From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/css/BasicShapeFunctions.cpp | 356 +- Source/WebCore/css/BasicShapeFunctions.h | 21 +- Source/WebCore/css/CSSAllInOne.cpp | 128 + .../WebCore/css/CSSAnimationTriggerScrollValue.cpp | 56 + .../WebCore/css/CSSAnimationTriggerScrollValue.h | 66 + Source/WebCore/css/CSSAspectRatioValue.cpp | 4 +- Source/WebCore/css/CSSAspectRatioValue.h | 16 +- Source/WebCore/css/CSSBasicShapes.cpp | 447 +- Source/WebCore/css/CSSBasicShapes.h | 284 +- Source/WebCore/css/CSSBorderImage.cpp | 25 +- Source/WebCore/css/CSSBorderImage.h | 14 +- Source/WebCore/css/CSSBorderImageSliceValue.cpp | 8 +- Source/WebCore/css/CSSBorderImageSliceValue.h | 22 +- Source/WebCore/css/CSSCalculationValue.cpp | 508 +- Source/WebCore/css/CSSCalculationValue.h | 90 +- Source/WebCore/css/CSSCanvasValue.cpp | 21 +- Source/WebCore/css/CSSCanvasValue.h | 32 +- Source/WebCore/css/CSSCharsetRule.cpp | 37 - Source/WebCore/css/CSSCharsetRule.h | 53 - Source/WebCore/css/CSSCharsetRule.idl | 29 - Source/WebCore/css/CSSComputedStyleDeclaration.cpp | 3857 +++--- Source/WebCore/css/CSSComputedStyleDeclaration.h | 107 +- Source/WebCore/css/CSSContentDistributionValue.cpp | 63 + Source/WebCore/css/CSSContentDistributionValue.h | 60 + Source/WebCore/css/CSSCrossfadeValue.cpp | 171 +- Source/WebCore/css/CSSCrossfadeValue.h | 81 +- Source/WebCore/css/CSSCursorImageValue.cpp | 193 +- Source/WebCore/css/CSSCursorImageValue.h | 41 +- Source/WebCore/css/CSSCustomIdentValue.cpp | 62 + Source/WebCore/css/CSSCustomIdentValue.h | 72 + Source/WebCore/css/CSSCustomPropertyValue.cpp | 55 + Source/WebCore/css/CSSCustomPropertyValue.h | 116 + Source/WebCore/css/CSSDefaultStyleSheets.cpp | 172 +- Source/WebCore/css/CSSDefaultStyleSheets.h | 13 +- Source/WebCore/css/CSSFilterImageValue.cpp | 95 +- Source/WebCore/css/CSSFilterImageValue.h | 40 +- Source/WebCore/css/CSSFontFace.cpp | 634 +- Source/WebCore/css/CSSFontFace.h | 185 +- Source/WebCore/css/CSSFontFaceLoadEvent.cpp | 10 +- Source/WebCore/css/CSSFontFaceLoadEvent.h | 42 +- Source/WebCore/css/CSSFontFaceLoadEvent.idl | 13 +- Source/WebCore/css/CSSFontFaceRule.cpp | 12 +- Source/WebCore/css/CSSFontFaceRule.h | 25 +- Source/WebCore/css/CSSFontFaceSet.cpp | 525 + Source/WebCore/css/CSSFontFaceSet.h | 109 + Source/WebCore/css/CSSFontFaceSource.cpp | 250 +- Source/WebCore/css/CSSFontFaceSource.h | 82 +- Source/WebCore/css/CSSFontFaceSrcValue.cpp | 39 +- Source/WebCore/css/CSSFontFaceSrcValue.h | 27 +- Source/WebCore/css/CSSFontFamily.h | 51 + Source/WebCore/css/CSSFontFeatureValue.cpp | 11 +- Source/WebCore/css/CSSFontFeatureValue.h | 27 +- Source/WebCore/css/CSSFontSelector.cpp | 678 +- Source/WebCore/css/CSSFontSelector.h | 77 +- Source/WebCore/css/CSSFontValue.cpp | 2 +- Source/WebCore/css/CSSFontValue.h | 14 +- Source/WebCore/css/CSSFontVariationValue.cpp | 61 + Source/WebCore/css/CSSFontVariationValue.h | 59 + Source/WebCore/css/CSSFunctionValue.cpp | 30 +- Source/WebCore/css/CSSFunctionValue.h | 42 +- Source/WebCore/css/CSSGradientValue.cpp | 407 +- Source/WebCore/css/CSSGradientValue.h | 79 +- Source/WebCore/css/CSSGrammar.y.in | 1688 --- Source/WebCore/css/CSSGrammar.y.includes | 61 - Source/WebCore/css/CSSGridAutoRepeatValue.cpp | 49 + Source/WebCore/css/CSSGridAutoRepeatValue.h | 72 + Source/WebCore/css/CSSGridLineNamesValue.cpp | 46 + Source/WebCore/css/CSSGridLineNamesValue.h | 52 + Source/WebCore/css/CSSGridTemplateAreasValue.cpp | 91 + Source/WebCore/css/CSSGridTemplateAreasValue.h | 66 + Source/WebCore/css/CSSGridTemplateValue.cpp | 86 - Source/WebCore/css/CSSGridTemplateValue.h | 67 - Source/WebCore/css/CSSGroupingRule.cpp | 42 +- Source/WebCore/css/CSSGroupingRule.h | 23 +- Source/WebCore/css/CSSHelper.h | 7 +- Source/WebCore/css/CSSHostRule.cpp | 48 - Source/WebCore/css/CSSHostRule.h | 47 - Source/WebCore/css/CSSHostRule.idl | 31 - Source/WebCore/css/CSSImageGeneratorValue.cpp | 174 +- Source/WebCore/css/CSSImageGeneratorValue.h | 56 +- Source/WebCore/css/CSSImageSetValue.cpp | 113 +- Source/WebCore/css/CSSImageSetValue.h | 45 +- Source/WebCore/css/CSSImageValue.cpp | 75 +- Source/WebCore/css/CSSImageValue.h | 43 +- Source/WebCore/css/CSSImportRule.cpp | 24 +- Source/WebCore/css/CSSImportRule.h | 31 +- Source/WebCore/css/CSSImportRule.idl | 2 +- Source/WebCore/css/CSSInheritedValue.h | 22 +- Source/WebCore/css/CSSInitialValue.h | 22 +- Source/WebCore/css/CSSKeyframeRule.cpp | 123 + Source/WebCore/css/CSSKeyframeRule.h | 99 + Source/WebCore/css/CSSKeyframeRule.idl | 36 + Source/WebCore/css/CSSKeyframesRule.cpp | 237 + Source/WebCore/css/CSSKeyframesRule.h | 115 + Source/WebCore/css/CSSKeyframesRule.idl | 40 + Source/WebCore/css/CSSLineBoxContainValue.cpp | 5 + Source/WebCore/css/CSSLineBoxContainValue.h | 16 +- Source/WebCore/css/CSSMarkup.cpp | 217 + Source/WebCore/css/CSSMarkup.h | 42 + Source/WebCore/css/CSSMediaRule.cpp | 14 +- Source/WebCore/css/CSSMediaRule.h | 24 +- Source/WebCore/css/CSSMediaRule.idl | 9 +- Source/WebCore/css/CSSNamedImageValue.cpp | 52 + Source/WebCore/css/CSSNamedImageValue.h | 61 + Source/WebCore/css/CSSNamespaceRule.cpp | 72 + Source/WebCore/css/CSSNamespaceRule.h | 55 + Source/WebCore/css/CSSNamespaceRule.idl | 33 + Source/WebCore/css/CSSOMUtils.cpp | 114 - Source/WebCore/css/CSSOMUtils.h | 52 - Source/WebCore/css/CSSPageRule.cpp | 15 +- Source/WebCore/css/CSSPageRule.h | 29 +- Source/WebCore/css/CSSPageRule.idl | 4 +- Source/WebCore/css/CSSParser.cpp | 12338 ------------------- Source/WebCore/css/CSSParser.h | 693 -- Source/WebCore/css/CSSParserMode.h | 83 - Source/WebCore/css/CSSParserValues.cpp | 231 - Source/WebCore/css/CSSParserValues.h | 214 - Source/WebCore/css/CSSPendingSubstitutionValue.cpp | 40 + Source/WebCore/css/CSSPendingSubstitutionValue.h | 73 + Source/WebCore/css/CSSPrimitiveValue.cpp | 1046 +- Source/WebCore/css/CSSPrimitiveValue.h | 380 +- Source/WebCore/css/CSSPrimitiveValue.idl | 68 - Source/WebCore/css/CSSPrimitiveValueMappings.h | 1611 ++- Source/WebCore/css/CSSProperties.json | 4200 +++++++ Source/WebCore/css/CSSProperty.cpp | 138 +- Source/WebCore/css/CSSProperty.h | 88 +- Source/WebCore/css/CSSPropertyNames.in | 464 - Source/WebCore/css/CSSPropertySourceData.cpp | 9 +- Source/WebCore/css/CSSPropertySourceData.h | 44 +- Source/WebCore/css/CSSReflectValue.cpp | 12 +- Source/WebCore/css/CSSReflectValue.h | 37 +- Source/WebCore/css/CSSReflectionDirection.h | 7 +- Source/WebCore/css/CSSRevertValue.cpp | 38 + Source/WebCore/css/CSSRevertValue.h | 54 + Source/WebCore/css/CSSRule.cpp | 5 +- Source/WebCore/css/CSSRule.h | 34 +- Source/WebCore/css/CSSRule.idl | 38 +- Source/WebCore/css/CSSRuleList.cpp | 2 +- Source/WebCore/css/CSSRuleList.h | 43 +- Source/WebCore/css/CSSRuleList.idl | 11 +- Source/WebCore/css/CSSSegmentedFontFace.cpp | 190 +- Source/WebCore/css/CSSSegmentedFontFace.h | 64 +- Source/WebCore/css/CSSSelector.cpp | 1074 +- Source/WebCore/css/CSSSelector.h | 559 +- Source/WebCore/css/CSSSelectorList.cpp | 62 +- Source/WebCore/css/CSSSelectorList.h | 17 +- Source/WebCore/css/CSSShadowValue.cpp | 21 +- Source/WebCore/css/CSSShadowValue.h | 38 +- Source/WebCore/css/CSSStyleDeclaration.h | 26 +- Source/WebCore/css/CSSStyleDeclaration.idl | 41 +- Source/WebCore/css/CSSStyleRule.cpp | 26 +- Source/WebCore/css/CSSStyleRule.h | 31 +- Source/WebCore/css/CSSStyleRule.idl | 4 +- Source/WebCore/css/CSSStyleSheet.cpp | 242 +- Source/WebCore/css/CSSStyleSheet.h | 93 +- Source/WebCore/css/CSSStyleSheet.idl | 23 +- Source/WebCore/css/CSSSupportsRule.cpp | 13 +- Source/WebCore/css/CSSSupportsRule.h | 22 +- Source/WebCore/css/CSSSupportsRule.idl | 11 +- Source/WebCore/css/CSSTimingFunctionValue.cpp | 55 +- Source/WebCore/css/CSSTimingFunctionValue.h | 58 +- Source/WebCore/css/CSSToLengthConversionData.cpp | 92 + Source/WebCore/css/CSSToLengthConversionData.h | 93 + Source/WebCore/css/CSSToStyleMap.cpp | 606 +- Source/WebCore/css/CSSToStyleMap.h | 74 +- Source/WebCore/css/CSSUnicodeRangeValue.cpp | 8 +- Source/WebCore/css/CSSUnicodeRangeValue.h | 17 +- Source/WebCore/css/CSSUnknownRule.h | 21 +- Source/WebCore/css/CSSUnknownRule.idl | 2 +- Source/WebCore/css/CSSUnsetValue.cpp | 38 + Source/WebCore/css/CSSUnsetValue.h | 54 + Source/WebCore/css/CSSValue.cpp | 423 +- Source/WebCore/css/CSSValue.h | 142 +- Source/WebCore/css/CSSValue.idl | 40 - Source/WebCore/css/CSSValueKeywords.in | 380 +- Source/WebCore/css/CSSValueList.cpp | 94 +- Source/WebCore/css/CSSValueList.h | 88 +- Source/WebCore/css/CSSValueList.idl | 33 - Source/WebCore/css/CSSValuePool.cpp | 110 +- Source/WebCore/css/CSSValuePool.h | 83 +- Source/WebCore/css/CSSVariableData.cpp | 182 + Source/WebCore/css/CSSVariableData.h | 94 + Source/WebCore/css/CSSVariableReferenceValue.cpp | 50 + Source/WebCore/css/CSSVariableReferenceValue.h | 69 + Source/WebCore/css/Counter.h | 50 +- Source/WebCore/css/Counter.idl | 28 - Source/WebCore/css/DOMCSSNamespace.cpp | 90 + Source/WebCore/css/DOMCSSNamespace.h | 46 + Source/WebCore/css/DOMCSSNamespace.idl | 37 + Source/WebCore/css/DOMWindowCSS.cpp | 89 - Source/WebCore/css/DOMWindowCSS.h | 58 - Source/WebCore/css/DOMWindowCSS.idl | 40 - Source/WebCore/css/DashboardRegion.h | 15 +- Source/WebCore/css/DeprecatedCSSOMCounter.h | 56 + Source/WebCore/css/DeprecatedCSSOMCounter.idl | 28 + .../WebCore/css/DeprecatedCSSOMPrimitiveValue.cpp | 90 + Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.h | 108 + .../WebCore/css/DeprecatedCSSOMPrimitiveValue.idl | 67 + Source/WebCore/css/DeprecatedCSSOMRGBColor.h | 73 + Source/WebCore/css/DeprecatedCSSOMRGBColor.idl | 31 + Source/WebCore/css/DeprecatedCSSOMRect.h | 63 + Source/WebCore/css/DeprecatedCSSOMRect.idl | 29 + Source/WebCore/css/DeprecatedCSSOMValue.cpp | 103 + Source/WebCore/css/DeprecatedCSSOMValue.h | 130 + Source/WebCore/css/DeprecatedCSSOMValue.idl | 38 + Source/WebCore/css/DeprecatedCSSOMValueList.cpp | 75 + Source/WebCore/css/DeprecatedCSSOMValueList.h | 64 + Source/WebCore/css/DeprecatedCSSOMValueList.idl | 34 + Source/WebCore/css/DeprecatedStyleBuilder.cpp | 2624 ---- Source/WebCore/css/DeprecatedStyleBuilder.h | 105 - Source/WebCore/css/DocumentRuleSets.cpp | 94 +- Source/WebCore/css/DocumentRuleSets.h | 68 +- Source/WebCore/css/ElementRuleCollector.cpp | 536 +- Source/WebCore/css/ElementRuleCollector.h | 85 +- Source/WebCore/css/FontFace.cpp | 427 + Source/WebCore/css/FontFace.h | 104 + Source/WebCore/css/FontFace.idl | 61 + Source/WebCore/css/FontFaceSet.cpp | 238 + Source/WebCore/css/FontFaceSet.h | 116 + Source/WebCore/css/FontFaceSet.idl | 55 + Source/WebCore/css/FontLoader.cpp | 317 - Source/WebCore/css/FontLoader.h | 108 - Source/WebCore/css/FontLoader.idl | 57 - Source/WebCore/css/FontVariantBuilder.cpp | 375 + Source/WebCore/css/FontVariantBuilder.h | 44 + Source/WebCore/css/InspectorCSSOMWrappers.cpp | 73 +- Source/WebCore/css/InspectorCSSOMWrappers.h | 19 +- Source/WebCore/css/LengthFunctions.cpp | 128 +- Source/WebCore/css/LengthFunctions.h | 60 +- Source/WebCore/css/MediaFeatureNames.cpp | 10 +- Source/WebCore/css/MediaFeatureNames.h | 95 +- Source/WebCore/css/MediaList.cpp | 263 +- Source/WebCore/css/MediaList.h | 97 +- Source/WebCore/css/MediaList.idl | 18 +- Source/WebCore/css/MediaQuery.cpp | 112 +- Source/WebCore/css/MediaQuery.h | 45 +- Source/WebCore/css/MediaQueryEvaluator.cpp | 735 +- Source/WebCore/css/MediaQueryEvaluator.h | 68 +- Source/WebCore/css/MediaQueryExp.cpp | 252 - Source/WebCore/css/MediaQueryExp.h | 86 - Source/WebCore/css/MediaQueryExpression.cpp | 237 + Source/WebCore/css/MediaQueryExpression.h | 78 + Source/WebCore/css/MediaQueryList.cpp | 30 +- Source/WebCore/css/MediaQueryList.h | 22 +- Source/WebCore/css/MediaQueryList.idl | 6 +- Source/WebCore/css/MediaQueryListListener.h | 7 +- Source/WebCore/css/MediaQueryListListener.idl | 7 +- Source/WebCore/css/MediaQueryMatcher.cpp | 103 +- Source/WebCore/css/MediaQueryMatcher.h | 47 +- Source/WebCore/css/PageRuleCollector.cpp | 25 +- Source/WebCore/css/PageRuleCollector.h | 6 +- Source/WebCore/css/Pair.h | 50 +- .../WebCore/css/PropertySetCSSStyleDeclaration.cpp | 180 +- .../WebCore/css/PropertySetCSSStyleDeclaration.h | 104 +- Source/WebCore/css/RGBColor.cpp | 40 +- Source/WebCore/css/RGBColor.h | 38 +- Source/WebCore/css/RGBColor.idl | 37 - Source/WebCore/css/Rect.h | 37 +- Source/WebCore/css/Rect.idl | 28 - Source/WebCore/css/RuleFeature.cpp | 148 +- Source/WebCore/css/RuleFeature.h | 50 +- Source/WebCore/css/RuleSet.cpp | 467 +- Source/WebCore/css/RuleSet.h | 126 +- .../WebCore/css/SVGCSSComputedStyleDeclaration.cpp | 92 +- Source/WebCore/css/SVGCSSParser.cpp | 369 - Source/WebCore/css/SVGCSSPropertyNames.in | 58 - Source/WebCore/css/SVGCSSStyleSelector.cpp | 617 - Source/WebCore/css/SVGCSSValueKeywords.in | 3 +- Source/WebCore/css/SelectorChecker.cpp | 1401 ++- Source/WebCore/css/SelectorChecker.h | 147 +- Source/WebCore/css/SelectorCheckerFastPath.cpp | 224 - Source/WebCore/css/SelectorCheckerFastPath.h | 64 - Source/WebCore/css/SelectorCheckerTestFunctions.h | 377 + Source/WebCore/css/SelectorFilter.cpp | 75 +- Source/WebCore/css/SelectorFilter.h | 15 +- ...electorPseudoClassAndCompatibilityElementMap.in | 80 + Source/WebCore/css/SelectorPseudoElementTypeMap.in | 17 + Source/WebCore/css/SelectorPseudoTypeMap.h | 40 + Source/WebCore/css/StyleBuilder.h | 41 + Source/WebCore/css/StyleBuilderConverter.h | 1455 +++ Source/WebCore/css/StyleBuilderCustom.h | 1830 +++ Source/WebCore/css/StyleColor.cpp | 61 + Source/WebCore/css/StyleColor.h | 75 + Source/WebCore/css/StyleInvalidationAnalysis.cpp | 221 +- Source/WebCore/css/StyleInvalidationAnalysis.h | 40 +- Source/WebCore/css/StyleMedia.cpp | 16 +- Source/WebCore/css/StyleMedia.h | 15 +- Source/WebCore/css/StyleMedia.idl | 8 +- Source/WebCore/css/StyleProperties.cpp | 814 +- Source/WebCore/css/StyleProperties.h | 259 +- Source/WebCore/css/StylePropertyShorthand.cpp | 794 +- Source/WebCore/css/StylePropertyShorthand.h | 97 +- Source/WebCore/css/StyleResolver.cpp | 3593 ++---- Source/WebCore/css/StyleResolver.h | 495 +- Source/WebCore/css/StyleRule.cpp | 282 +- Source/WebCore/css/StyleRule.h | 299 +- Source/WebCore/css/StyleRuleImport.cpp | 41 +- Source/WebCore/css/StyleRuleImport.h | 21 +- Source/WebCore/css/StyleScopeResolver.cpp | 228 - Source/WebCore/css/StyleScopeResolver.h | 125 - Source/WebCore/css/StyleSheet.cpp | 2 +- Source/WebCore/css/StyleSheet.h | 9 +- Source/WebCore/css/StyleSheet.idl | 28 +- Source/WebCore/css/StyleSheetContents.cpp | 298 +- Source/WebCore/css/StyleSheetContents.h | 73 +- Source/WebCore/css/StyleSheetList.cpp | 24 +- Source/WebCore/css/StyleSheetList.h | 20 +- Source/WebCore/css/StyleSheetList.idl | 10 +- Source/WebCore/css/TransformFunctions.cpp | 324 +- Source/WebCore/css/TransformFunctions.h | 14 +- Source/WebCore/css/ViewportStyleResolver.cpp | 23 +- Source/WebCore/css/ViewportStyleResolver.h | 11 +- Source/WebCore/css/WebKitCSSFilterValue.cpp | 105 - Source/WebCore/css/WebKitCSSFilterValue.h | 81 - Source/WebCore/css/WebKitCSSFilterValue.idl | 49 - Source/WebCore/css/WebKitCSSKeyframeRule.cpp | 121 - Source/WebCore/css/WebKitCSSKeyframeRule.h | 92 - Source/WebCore/css/WebKitCSSKeyframeRule.idl | 36 - Source/WebCore/css/WebKitCSSKeyframesRule.cpp | 202 - Source/WebCore/css/WebKitCSSKeyframesRule.h | 101 - Source/WebCore/css/WebKitCSSKeyframesRule.idl | 41 - Source/WebCore/css/WebKitCSSMatrix.cpp | 151 +- Source/WebCore/css/WebKitCSSMatrix.h | 47 +- Source/WebCore/css/WebKitCSSMatrix.idl | 91 +- Source/WebCore/css/WebKitCSSRegionRule.cpp | 4 +- Source/WebCore/css/WebKitCSSRegionRule.h | 19 +- Source/WebCore/css/WebKitCSSTransformValue.cpp | 92 - Source/WebCore/css/WebKitCSSTransformValue.h | 96 - Source/WebCore/css/WebKitCSSTransformValue.idl | 62 - Source/WebCore/css/WebKitCSSViewportRule.cpp | 12 +- Source/WebCore/css/WebKitCSSViewportRule.h | 26 +- Source/WebCore/css/fullscreen.css | 17 +- Source/WebCore/css/html.css | 512 +- Source/WebCore/css/make-css-file-arrays.pl | 5 +- ...electorPseudoClassAndCompatibilityElementMap.py | 217 + .../WebCore/css/makeSelectorPseudoElementsMap.py | 212 + Source/WebCore/css/makegrammar.pl | 95 - Source/WebCore/css/makeprop.pl | 958 +- Source/WebCore/css/makevalues.pl | 19 +- Source/WebCore/css/mathml.css | 253 +- Source/WebCore/css/mediaControls.css | 92 +- Source/WebCore/css/mediaControlsGtk.css | 222 +- Source/WebCore/css/mediaControlsiOS.css | 33 + Source/WebCore/css/parser/CSSAtRuleID.cpp | 67 + Source/WebCore/css/parser/CSSAtRuleID.h | 55 + Source/WebCore/css/parser/CSSDeferredParser.cpp | 57 + Source/WebCore/css/parser/CSSDeferredParser.h | 68 + Source/WebCore/css/parser/CSSParser.cpp | 303 + Source/WebCore/css/parser/CSSParser.h | 89 + Source/WebCore/css/parser/CSSParserFastPaths.cpp | 1258 ++ Source/WebCore/css/parser/CSSParserFastPaths.h | 55 + Source/WebCore/css/parser/CSSParserIdioms.cpp | 58 + Source/WebCore/css/parser/CSSParserIdioms.h | 67 + Source/WebCore/css/parser/CSSParserImpl.cpp | 910 ++ Source/WebCore/css/parser/CSSParserImpl.h | 176 + Source/WebCore/css/parser/CSSParserMode.h | 165 + Source/WebCore/css/parser/CSSParserObserver.h | 47 + .../css/parser/CSSParserObserverWrapper.cpp | 72 + .../WebCore/css/parser/CSSParserObserverWrapper.h | 77 + Source/WebCore/css/parser/CSSParserSelector.cpp | 245 + Source/WebCore/css/parser/CSSParserSelector.h | 135 + Source/WebCore/css/parser/CSSParserToken.cpp | 479 + Source/WebCore/css/parser/CSSParserToken.h | 178 + Source/WebCore/css/parser/CSSParserTokenRange.cpp | 119 + Source/WebCore/css/parser/CSSParserTokenRange.h | 104 + Source/WebCore/css/parser/CSSPropertyParser.cpp | 5445 ++++++++ Source/WebCore/css/parser/CSSPropertyParser.h | 117 + .../css/parser/CSSPropertyParserHelpers.cpp | 1348 ++ .../WebCore/css/parser/CSSPropertyParserHelpers.h | 122 + Source/WebCore/css/parser/CSSSelectorParser.cpp | 891 ++ Source/WebCore/css/parser/CSSSelectorParser.h | 108 + Source/WebCore/css/parser/CSSSupportsParser.cpp | 127 + Source/WebCore/css/parser/CSSSupportsParser.h | 61 + Source/WebCore/css/parser/CSSTokenizer.cpp | 879 ++ Source/WebCore/css/parser/CSSTokenizer.h | 128 + .../WebCore/css/parser/CSSTokenizerInputStream.cpp | 73 + .../WebCore/css/parser/CSSTokenizerInputStream.h | 107 + Source/WebCore/css/parser/CSSVariableParser.cpp | 166 + Source/WebCore/css/parser/CSSVariableParser.h | 50 + .../WebCore/css/parser/MediaQueryBlockWatcher.cpp | 51 + Source/WebCore/css/parser/MediaQueryBlockWatcher.h | 46 + Source/WebCore/css/parser/MediaQueryParser.cpp | 310 + Source/WebCore/css/parser/MediaQueryParser.h | 136 + Source/WebCore/css/parser/SizesAttributeParser.cpp | 166 + Source/WebCore/css/parser/SizesAttributeParser.h | 64 + Source/WebCore/css/parser/SizesCalcParser.cpp | 259 + Source/WebCore/css/parser/SizesCalcParser.h | 81 + Source/WebCore/css/plugIns.css | 6 +- Source/WebCore/css/svg.css | 11 +- Source/WebCore/css/themeWin.css | 125 + Source/WebCore/css/themeWinQuirks.css | 38 + Source/WebCore/css/view-source.css | 162 - 392 files changed, 48709 insertions(+), 40147 deletions(-) create mode 100644 Source/WebCore/css/CSSAllInOne.cpp create mode 100644 Source/WebCore/css/CSSAnimationTriggerScrollValue.cpp create mode 100644 Source/WebCore/css/CSSAnimationTriggerScrollValue.h delete mode 100644 Source/WebCore/css/CSSCharsetRule.cpp delete mode 100644 Source/WebCore/css/CSSCharsetRule.h delete mode 100644 Source/WebCore/css/CSSCharsetRule.idl create mode 100644 Source/WebCore/css/CSSContentDistributionValue.cpp create mode 100644 Source/WebCore/css/CSSContentDistributionValue.h create mode 100644 Source/WebCore/css/CSSCustomIdentValue.cpp create mode 100644 Source/WebCore/css/CSSCustomIdentValue.h create mode 100644 Source/WebCore/css/CSSCustomPropertyValue.cpp create mode 100644 Source/WebCore/css/CSSCustomPropertyValue.h create mode 100644 Source/WebCore/css/CSSFontFaceSet.cpp create mode 100644 Source/WebCore/css/CSSFontFaceSet.h create mode 100644 Source/WebCore/css/CSSFontFamily.h create mode 100644 Source/WebCore/css/CSSFontVariationValue.cpp create mode 100644 Source/WebCore/css/CSSFontVariationValue.h delete mode 100644 Source/WebCore/css/CSSGrammar.y.in delete mode 100644 Source/WebCore/css/CSSGrammar.y.includes create mode 100644 Source/WebCore/css/CSSGridAutoRepeatValue.cpp create mode 100644 Source/WebCore/css/CSSGridAutoRepeatValue.h create mode 100644 Source/WebCore/css/CSSGridLineNamesValue.cpp create mode 100644 Source/WebCore/css/CSSGridLineNamesValue.h create mode 100644 Source/WebCore/css/CSSGridTemplateAreasValue.cpp create mode 100644 Source/WebCore/css/CSSGridTemplateAreasValue.h delete mode 100644 Source/WebCore/css/CSSGridTemplateValue.cpp delete mode 100644 Source/WebCore/css/CSSGridTemplateValue.h delete mode 100644 Source/WebCore/css/CSSHostRule.cpp delete mode 100644 Source/WebCore/css/CSSHostRule.h delete mode 100644 Source/WebCore/css/CSSHostRule.idl create mode 100644 Source/WebCore/css/CSSKeyframeRule.cpp create mode 100644 Source/WebCore/css/CSSKeyframeRule.h create mode 100644 Source/WebCore/css/CSSKeyframeRule.idl create mode 100644 Source/WebCore/css/CSSKeyframesRule.cpp create mode 100644 Source/WebCore/css/CSSKeyframesRule.h create mode 100644 Source/WebCore/css/CSSKeyframesRule.idl create mode 100644 Source/WebCore/css/CSSMarkup.cpp create mode 100644 Source/WebCore/css/CSSMarkup.h create mode 100644 Source/WebCore/css/CSSNamedImageValue.cpp create mode 100644 Source/WebCore/css/CSSNamedImageValue.h create mode 100644 Source/WebCore/css/CSSNamespaceRule.cpp create mode 100644 Source/WebCore/css/CSSNamespaceRule.h create mode 100644 Source/WebCore/css/CSSNamespaceRule.idl delete mode 100644 Source/WebCore/css/CSSOMUtils.cpp delete mode 100644 Source/WebCore/css/CSSOMUtils.h delete mode 100644 Source/WebCore/css/CSSParser.cpp delete mode 100644 Source/WebCore/css/CSSParser.h delete mode 100644 Source/WebCore/css/CSSParserMode.h delete mode 100644 Source/WebCore/css/CSSParserValues.cpp delete mode 100644 Source/WebCore/css/CSSParserValues.h create mode 100644 Source/WebCore/css/CSSPendingSubstitutionValue.cpp create mode 100644 Source/WebCore/css/CSSPendingSubstitutionValue.h delete mode 100644 Source/WebCore/css/CSSPrimitiveValue.idl create mode 100644 Source/WebCore/css/CSSProperties.json delete mode 100644 Source/WebCore/css/CSSPropertyNames.in create mode 100644 Source/WebCore/css/CSSRevertValue.cpp create mode 100644 Source/WebCore/css/CSSRevertValue.h create mode 100644 Source/WebCore/css/CSSToLengthConversionData.cpp create mode 100644 Source/WebCore/css/CSSToLengthConversionData.h create mode 100644 Source/WebCore/css/CSSUnsetValue.cpp create mode 100644 Source/WebCore/css/CSSUnsetValue.h delete mode 100644 Source/WebCore/css/CSSValue.idl delete mode 100644 Source/WebCore/css/CSSValueList.idl create mode 100644 Source/WebCore/css/CSSVariableData.cpp create mode 100644 Source/WebCore/css/CSSVariableData.h create mode 100644 Source/WebCore/css/CSSVariableReferenceValue.cpp create mode 100644 Source/WebCore/css/CSSVariableReferenceValue.h delete mode 100644 Source/WebCore/css/Counter.idl create mode 100644 Source/WebCore/css/DOMCSSNamespace.cpp create mode 100644 Source/WebCore/css/DOMCSSNamespace.h create mode 100644 Source/WebCore/css/DOMCSSNamespace.idl delete mode 100644 Source/WebCore/css/DOMWindowCSS.cpp delete mode 100644 Source/WebCore/css/DOMWindowCSS.h delete mode 100644 Source/WebCore/css/DOMWindowCSS.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMCounter.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMCounter.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.cpp create mode 100644 Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMRGBColor.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMRGBColor.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMRect.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMRect.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMValue.cpp create mode 100644 Source/WebCore/css/DeprecatedCSSOMValue.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMValue.idl create mode 100644 Source/WebCore/css/DeprecatedCSSOMValueList.cpp create mode 100644 Source/WebCore/css/DeprecatedCSSOMValueList.h create mode 100644 Source/WebCore/css/DeprecatedCSSOMValueList.idl delete mode 100644 Source/WebCore/css/DeprecatedStyleBuilder.cpp delete mode 100644 Source/WebCore/css/DeprecatedStyleBuilder.h create mode 100644 Source/WebCore/css/FontFace.cpp create mode 100644 Source/WebCore/css/FontFace.h create mode 100644 Source/WebCore/css/FontFace.idl create mode 100644 Source/WebCore/css/FontFaceSet.cpp create mode 100644 Source/WebCore/css/FontFaceSet.h create mode 100644 Source/WebCore/css/FontFaceSet.idl delete mode 100644 Source/WebCore/css/FontLoader.cpp delete mode 100644 Source/WebCore/css/FontLoader.h delete mode 100644 Source/WebCore/css/FontLoader.idl create mode 100644 Source/WebCore/css/FontVariantBuilder.cpp create mode 100644 Source/WebCore/css/FontVariantBuilder.h delete mode 100644 Source/WebCore/css/MediaQueryExp.cpp delete mode 100644 Source/WebCore/css/MediaQueryExp.h create mode 100644 Source/WebCore/css/MediaQueryExpression.cpp create mode 100644 Source/WebCore/css/MediaQueryExpression.h delete mode 100644 Source/WebCore/css/RGBColor.idl delete mode 100644 Source/WebCore/css/Rect.idl delete mode 100644 Source/WebCore/css/SVGCSSParser.cpp delete mode 100644 Source/WebCore/css/SVGCSSPropertyNames.in delete mode 100644 Source/WebCore/css/SVGCSSStyleSelector.cpp delete mode 100644 Source/WebCore/css/SelectorCheckerFastPath.cpp delete mode 100644 Source/WebCore/css/SelectorCheckerFastPath.h create mode 100644 Source/WebCore/css/SelectorCheckerTestFunctions.h create mode 100644 Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in create mode 100644 Source/WebCore/css/SelectorPseudoElementTypeMap.in create mode 100644 Source/WebCore/css/SelectorPseudoTypeMap.h create mode 100644 Source/WebCore/css/StyleBuilder.h create mode 100644 Source/WebCore/css/StyleBuilderConverter.h create mode 100644 Source/WebCore/css/StyleBuilderCustom.h create mode 100644 Source/WebCore/css/StyleColor.cpp create mode 100644 Source/WebCore/css/StyleColor.h delete mode 100644 Source/WebCore/css/StyleScopeResolver.cpp delete mode 100644 Source/WebCore/css/StyleScopeResolver.h delete mode 100644 Source/WebCore/css/WebKitCSSFilterValue.cpp delete mode 100644 Source/WebCore/css/WebKitCSSFilterValue.h delete mode 100644 Source/WebCore/css/WebKitCSSFilterValue.idl delete mode 100644 Source/WebCore/css/WebKitCSSKeyframeRule.cpp delete mode 100644 Source/WebCore/css/WebKitCSSKeyframeRule.h delete mode 100644 Source/WebCore/css/WebKitCSSKeyframeRule.idl delete mode 100644 Source/WebCore/css/WebKitCSSKeyframesRule.cpp delete mode 100644 Source/WebCore/css/WebKitCSSKeyframesRule.h delete mode 100644 Source/WebCore/css/WebKitCSSKeyframesRule.idl delete mode 100644 Source/WebCore/css/WebKitCSSTransformValue.cpp delete mode 100644 Source/WebCore/css/WebKitCSSTransformValue.h delete mode 100644 Source/WebCore/css/WebKitCSSTransformValue.idl create mode 100644 Source/WebCore/css/makeSelectorPseudoClassAndCompatibilityElementMap.py create mode 100644 Source/WebCore/css/makeSelectorPseudoElementsMap.py delete mode 100644 Source/WebCore/css/makegrammar.pl create mode 100644 Source/WebCore/css/mediaControlsiOS.css create mode 100644 Source/WebCore/css/parser/CSSAtRuleID.cpp create mode 100644 Source/WebCore/css/parser/CSSAtRuleID.h create mode 100644 Source/WebCore/css/parser/CSSDeferredParser.cpp create mode 100644 Source/WebCore/css/parser/CSSDeferredParser.h create mode 100644 Source/WebCore/css/parser/CSSParser.cpp create mode 100644 Source/WebCore/css/parser/CSSParser.h create mode 100644 Source/WebCore/css/parser/CSSParserFastPaths.cpp create mode 100644 Source/WebCore/css/parser/CSSParserFastPaths.h create mode 100644 Source/WebCore/css/parser/CSSParserIdioms.cpp create mode 100644 Source/WebCore/css/parser/CSSParserIdioms.h create mode 100644 Source/WebCore/css/parser/CSSParserImpl.cpp create mode 100644 Source/WebCore/css/parser/CSSParserImpl.h create mode 100644 Source/WebCore/css/parser/CSSParserMode.h create mode 100644 Source/WebCore/css/parser/CSSParserObserver.h create mode 100644 Source/WebCore/css/parser/CSSParserObserverWrapper.cpp create mode 100644 Source/WebCore/css/parser/CSSParserObserverWrapper.h create mode 100644 Source/WebCore/css/parser/CSSParserSelector.cpp create mode 100644 Source/WebCore/css/parser/CSSParserSelector.h create mode 100644 Source/WebCore/css/parser/CSSParserToken.cpp create mode 100644 Source/WebCore/css/parser/CSSParserToken.h create mode 100644 Source/WebCore/css/parser/CSSParserTokenRange.cpp create mode 100644 Source/WebCore/css/parser/CSSParserTokenRange.h create mode 100644 Source/WebCore/css/parser/CSSPropertyParser.cpp create mode 100644 Source/WebCore/css/parser/CSSPropertyParser.h create mode 100644 Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp create mode 100644 Source/WebCore/css/parser/CSSPropertyParserHelpers.h create mode 100644 Source/WebCore/css/parser/CSSSelectorParser.cpp create mode 100644 Source/WebCore/css/parser/CSSSelectorParser.h create mode 100644 Source/WebCore/css/parser/CSSSupportsParser.cpp create mode 100644 Source/WebCore/css/parser/CSSSupportsParser.h create mode 100644 Source/WebCore/css/parser/CSSTokenizer.cpp create mode 100644 Source/WebCore/css/parser/CSSTokenizer.h create mode 100644 Source/WebCore/css/parser/CSSTokenizerInputStream.cpp create mode 100644 Source/WebCore/css/parser/CSSTokenizerInputStream.h create mode 100644 Source/WebCore/css/parser/CSSVariableParser.cpp create mode 100644 Source/WebCore/css/parser/CSSVariableParser.h create mode 100644 Source/WebCore/css/parser/MediaQueryBlockWatcher.cpp create mode 100644 Source/WebCore/css/parser/MediaQueryBlockWatcher.h create mode 100644 Source/WebCore/css/parser/MediaQueryParser.cpp create mode 100644 Source/WebCore/css/parser/MediaQueryParser.h create mode 100644 Source/WebCore/css/parser/SizesAttributeParser.cpp create mode 100644 Source/WebCore/css/parser/SizesAttributeParser.h create mode 100644 Source/WebCore/css/parser/SizesCalcParser.cpp create mode 100644 Source/WebCore/css/parser/SizesCalcParser.h create mode 100644 Source/WebCore/css/themeWin.css create mode 100644 Source/WebCore/css/themeWinQuirks.css delete mode 100644 Source/WebCore/css/view-source.css (limited to 'Source/WebCore/css') diff --git a/Source/WebCore/css/BasicShapeFunctions.cpp b/Source/WebCore/css/BasicShapeFunctions.cpp index 5b4ba1282..5f225f74a 100644 --- a/Source/WebCore/css/BasicShapeFunctions.cpp +++ b/Source/WebCore/css/BasicShapeFunctions.cpp @@ -36,10 +36,11 @@ #include "CSSValuePool.h" #include "Pair.h" #include "RenderStyle.h" +#include "SVGPathByteStream.h" namespace WebCore { -static PassRefPtr valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle* style, const BasicShapeCenterCoordinate& center, EBoxOrient orientation) +static Ref valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle& style, const BasicShapeCenterCoordinate& center, EBoxOrient orientation) { if (center.direction() == BasicShapeCenterCoordinate::TopLeft) return pool.createValue(center.length(), style); @@ -49,7 +50,7 @@ static PassRefPtr valueForCenterCoordinate(CSSValuePool& pool return pool.createValue(Pair::create(pool.createIdentifierValue(keyword), pool.createValue(center.length(), style))); } -static PassRefPtr basicShapeRadiusToCSSValue(const RenderStyle* style, CSSValuePool& pool, const BasicShapeRadius& radius) +static Ref basicShapeRadiusToCSSValue(const RenderStyle& style, CSSValuePool& pool, const BasicShapeRadius& radius) { switch (radius.type()) { case BasicShapeRadius::Value: @@ -61,147 +62,109 @@ static PassRefPtr basicShapeRadiusToCSSValue(const RenderStyl } ASSERT_NOT_REACHED(); - return 0; + return pool.createIdentifierValue(CSSValueClosestSide); } -PassRefPtr valueForBasicShape(const RenderStyle* style, const BasicShape* basicShape) +Ref valueForBasicShape(const RenderStyle& style, const BasicShape& basicShape) { - CSSValuePool& pool = cssValuePool(); + auto& cssValuePool = CSSValuePool::singleton(); RefPtr basicShapeValue; - switch (basicShape->type()) { - case BasicShape::BasicShapeRectangleType: { - const BasicShapeRectangle* rectangle = static_cast(basicShape); - RefPtr rectangleValue = CSSBasicShapeRectangle::create(); - - rectangleValue->setX(pool.createValue(rectangle->x(), style)); - rectangleValue->setY(pool.createValue(rectangle->y(), style)); - rectangleValue->setWidth(pool.createValue(rectangle->width(), style)); - rectangleValue->setHeight(pool.createValue(rectangle->height(), style)); - rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX(), style)); - rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY(), style)); - - basicShapeValue = rectangleValue.release(); - break; - } - case BasicShape::DeprecatedBasicShapeCircleType: { - const DeprecatedBasicShapeCircle* circle = static_cast(basicShape); - RefPtr circleValue = CSSDeprecatedBasicShapeCircle::create(); - - circleValue->setCenterX(pool.createValue(circle->centerX(), style)); - circleValue->setCenterY(pool.createValue(circle->centerY(), style)); - circleValue->setRadius(pool.createValue(circle->radius(), style)); - - basicShapeValue = circleValue.release(); - break; - } + switch (basicShape.type()) { case BasicShape::BasicShapeCircleType: { - const BasicShapeCircle* circle = static_cast(basicShape); - RefPtr circleValue = CSSBasicShapeCircle::create(); + auto& circle = downcast(basicShape); + auto circleValue = CSSBasicShapeCircle::create(); - circleValue->setCenterX(valueForCenterCoordinate(pool, style, circle->centerX(), HORIZONTAL)); - circleValue->setCenterY(valueForCenterCoordinate(pool, style, circle->centerY(), VERTICAL)); - circleValue->setRadius(basicShapeRadiusToCSSValue(style, pool, circle->radius())); - basicShapeValue = circleValue.release(); - break; - } - case BasicShape::DeprecatedBasicShapeEllipseType: { - const DeprecatedBasicShapeEllipse* ellipse = static_cast(basicShape); - RefPtr ellipseValue = CSSDeprecatedBasicShapeEllipse::create(); - - ellipseValue->setCenterX(pool.createValue(ellipse->centerX(), style)); - ellipseValue->setCenterY(pool.createValue(ellipse->centerY(), style)); - ellipseValue->setRadiusX(pool.createValue(ellipse->radiusX(), style)); - ellipseValue->setRadiusY(pool.createValue(ellipse->radiusY(), style)); + circleValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, circle.centerX(), HORIZONTAL)); + circleValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, circle.centerY(), VERTICAL)); + circleValue->setRadius(basicShapeRadiusToCSSValue(style, cssValuePool, circle.radius())); - basicShapeValue = ellipseValue.release(); + basicShapeValue = WTFMove(circleValue); break; } case BasicShape::BasicShapeEllipseType: { - const BasicShapeEllipse* ellipse = static_cast(basicShape); - RefPtr ellipseValue = CSSBasicShapeEllipse::create(); - - ellipseValue->setCenterX(valueForCenterCoordinate(pool, style, ellipse->centerX(), HORIZONTAL)); - ellipseValue->setCenterY(valueForCenterCoordinate(pool, style, ellipse->centerY(), VERTICAL)); - ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, pool, ellipse->radiusX())); - ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, pool, ellipse->radiusY())); - basicShapeValue = ellipseValue.release(); + auto& ellipse = downcast(basicShape); + auto ellipseValue = CSSBasicShapeEllipse::create(); + + ellipseValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, ellipse.centerX(), HORIZONTAL)); + ellipseValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, ellipse.centerY(), VERTICAL)); + ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusX())); + ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusY())); + + basicShapeValue = WTFMove(ellipseValue); break; } case BasicShape::BasicShapePolygonType: { - const BasicShapePolygon* polygon = static_cast(basicShape); - RefPtr polygonValue = CSSBasicShapePolygon::create(); + auto& polygon = downcast(basicShape); + auto polygonValue = CSSBasicShapePolygon::create(); - polygonValue->setWindRule(polygon->windRule()); - const Vector& values = polygon->values(); + polygonValue->setWindRule(polygon.windRule()); + const Vector& values = polygon.values(); for (unsigned i = 0; i < values.size(); i += 2) - polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style)); + polygonValue->appendPoint(cssValuePool.createValue(values.at(i), style), cssValuePool.createValue(values.at(i + 1), style)); - basicShapeValue = polygonValue.release(); + basicShapeValue = WTFMove(polygonValue); break; } - case BasicShape::BasicShapeInsetRectangleType: { - const BasicShapeInsetRectangle* rectangle = static_cast(basicShape); - RefPtr rectangleValue = CSSBasicShapeInsetRectangle::create(); - - rectangleValue->setTop(pool.createValue(rectangle->top(), style)); - rectangleValue->setRight(pool.createValue(rectangle->right(), style)); - rectangleValue->setBottom(pool.createValue(rectangle->bottom(), style)); - rectangleValue->setLeft(pool.createValue(rectangle->left(), style)); - rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX(), style)); - rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY(), style)); - - basicShapeValue = rectangleValue.release(); + case BasicShape::BasicShapePathType: { + auto& pathShape = downcast(basicShape); + auto pathShapeValue = CSSBasicShapePath::create(pathShape.pathData()->copy()); + pathShapeValue->setWindRule(pathShape.windRule()); + + basicShapeValue = WTFMove(pathShapeValue); break; } case BasicShape::BasicShapeInsetType: { - const BasicShapeInset* inset = static_cast(basicShape); - RefPtr insetValue = CSSBasicShapeInset::create(); + auto& inset = downcast(basicShape); + auto insetValue = CSSBasicShapeInset::create(); - insetValue->setTop(pool.createValue(inset->top())); - insetValue->setRight(pool.createValue(inset->right())); - insetValue->setBottom(pool.createValue(inset->bottom())); - insetValue->setLeft(pool.createValue(inset->left())); + insetValue->setTop(cssValuePool.createValue(inset.top(), style)); + insetValue->setRight(cssValuePool.createValue(inset.right(), style)); + insetValue->setBottom(cssValuePool.createValue(inset.bottom(), style)); + insetValue->setLeft(cssValuePool.createValue(inset.left(), style)); - insetValue->setTopLeftRadius(pool.createValue(inset->topLeftRadius())); - insetValue->setTopRightRadius(pool.createValue(inset->topRightRadius())); - insetValue->setBottomRightRadius(pool.createValue(inset->bottomRightRadius())); - insetValue->setBottomLeftRadius(pool.createValue(inset->bottomLeftRadius())); + insetValue->setTopLeftRadius(cssValuePool.createValue(inset.topLeftRadius(), style)); + insetValue->setTopRightRadius(cssValuePool.createValue(inset.topRightRadius(), style)); + insetValue->setBottomRightRadius(cssValuePool.createValue(inset.bottomRightRadius(), style)); + insetValue->setBottomLeftRadius(cssValuePool.createValue(inset.bottomLeftRadius(), style)); - basicShapeValue = insetValue.release(); + basicShapeValue = WTFMove(insetValue); break; } - default: - break; } - if (basicShape->layoutBox() != BoxMissing) - basicShapeValue->setLayoutBox(pool.createValue(basicShape->layoutBox())); - - return pool.createValue(basicShapeValue.release()); + return cssValuePool.createValue(basicShapeValue.releaseNonNull()); } -static Length convertToLength(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value) +static Length convertToLength(const CSSToLengthConversionData& conversionData, const CSSPrimitiveValue* value) { - return value->convertToLength(style, rootStyle, style->effectiveZoom()); + return value->convertToLength(conversionData); } -static BasicShapeCenterCoordinate convertToCenterCoordinate(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value) +static LengthSize convertToLengthSize(const CSSToLengthConversionData& conversionData, const CSSPrimitiveValue* value) { - BasicShapeCenterCoordinate::Direction direction; - Length offset = Length(0, Fixed); + if (!value) + return { { 0, Fixed }, { 0, Fixed } }; + auto& pair = *value->pairValue(); + return { convertToLength(conversionData, pair.first()), convertToLength(conversionData, pair.second()) }; +} + +static BasicShapeCenterCoordinate convertToCenterCoordinate(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* value) +{ CSSValueID keyword = CSSValueTop; + Length offset { 0, Fixed }; if (!value) keyword = CSSValueCenter; else if (value->isValueID()) - keyword = value->getValueID(); - else if (Pair* pair = value->getPairValue()) { - keyword = pair->first()->getValueID(); - offset = convertToLength(style, rootStyle, pair->second()); + keyword = value->valueID(); + else if (Pair* pair = value->pairValue()) { + keyword = pair->first()->valueID(); + offset = convertToLength(conversionData, pair->second()); } else - offset = convertToLength(style, rootStyle, value); + offset = convertToLength(conversionData, value); + BasicShapeCenterCoordinate::Direction direction; switch (keyword) { case CSSValueTop: case CSSValueLeft: @@ -224,13 +187,13 @@ static BasicShapeCenterCoordinate convertToCenterCoordinate(const RenderStyle* s return BasicShapeCenterCoordinate(direction, offset); } -static BasicShapeRadius cssValueToBasicShapeRadius(const RenderStyle* style, const RenderStyle* rootStyle, PassRefPtr radius) +static BasicShapeRadius cssValueToBasicShapeRadius(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* radius) { if (!radius) return BasicShapeRadius(BasicShapeRadius::ClosestSide); if (radius->isValueID()) { - switch (radius->getValueID()) { + switch (radius->valueID()) { case CSSValueClosestSide: return BasicShapeRadius(BasicShapeRadius::ClosestSide); case CSSValueFarthestSide: @@ -241,177 +204,78 @@ static BasicShapeRadius cssValueToBasicShapeRadius(const RenderStyle* style, con } } - return BasicShapeRadius(convertToLength(style, rootStyle, radius.get())); + return BasicShapeRadius(convertToLength(conversionData, radius)); } -PassRefPtr basicShapeForValue(const RenderStyle* style, const RenderStyle* rootStyle, const CSSBasicShape* basicShapeValue) +Ref basicShapeForValue(const CSSToLengthConversionData& conversionData, const CSSBasicShape& basicShapeValue) { RefPtr basicShape; - switch (basicShapeValue->type()) { - case CSSBasicShape::CSSBasicShapeRectangleType: { - const CSSBasicShapeRectangle* rectValue = static_cast(basicShapeValue); - RefPtr rect = BasicShapeRectangle::create(); - - rect->setX(convertToLength(style, rootStyle, rectValue->x())); - rect->setY(convertToLength(style, rootStyle, rectValue->y())); - rect->setWidth(convertToLength(style, rootStyle, rectValue->width())); - rect->setHeight(convertToLength(style, rootStyle, rectValue->height())); - if (rectValue->radiusX()) { - Length radiusX = convertToLength(style, rootStyle, rectValue->radiusX()); - rect->setCornerRadiusX(radiusX); - if (rectValue->radiusY()) - rect->setCornerRadiusY(convertToLength(style, rootStyle, rectValue->radiusY())); - else - rect->setCornerRadiusY(radiusX); - } else { - rect->setCornerRadiusX(Length(0, Fixed)); - rect->setCornerRadiusY(Length(0, Fixed)); - } - basicShape = rect.release(); - break; - } - case CSSBasicShape::CSSDeprecatedBasicShapeCircleType: { - const CSSDeprecatedBasicShapeCircle* circleValue = static_cast(basicShapeValue); - RefPtr circle = DeprecatedBasicShapeCircle::create(); - - circle->setCenterX(convertToLength(style, rootStyle, circleValue->centerX())); - circle->setCenterY(convertToLength(style, rootStyle, circleValue->centerY())); - circle->setRadius(convertToLength(style, rootStyle, circleValue->radius())); - - basicShape = circle.release(); - break; - } + switch (basicShapeValue.type()) { case CSSBasicShape::CSSBasicShapeCircleType: { - const CSSBasicShapeCircle* circleValue = static_cast(basicShapeValue); - RefPtr circle = BasicShapeCircle::create(); + auto& circleValue = downcast(basicShapeValue); + auto circle = BasicShapeCircle::create(); - circle->setCenterX(convertToCenterCoordinate(style, rootStyle, circleValue->centerX())); - circle->setCenterY(convertToCenterCoordinate(style, rootStyle, circleValue->centerY())); - circle->setRadius(cssValueToBasicShapeRadius(style, rootStyle, circleValue->radius())); + circle->setCenterX(convertToCenterCoordinate(conversionData, circleValue.centerX())); + circle->setCenterY(convertToCenterCoordinate(conversionData, circleValue.centerY())); + circle->setRadius(cssValueToBasicShapeRadius(conversionData, circleValue.radius())); - basicShape = circle.release(); - break; - } - case CSSBasicShape::CSSDeprecatedBasicShapeEllipseType: { - const CSSDeprecatedBasicShapeEllipse* ellipseValue = static_cast(basicShapeValue); - RefPtr ellipse = DeprecatedBasicShapeEllipse::create(); - - ellipse->setCenterX(convertToLength(style, rootStyle, ellipseValue->centerX())); - ellipse->setCenterY(convertToLength(style, rootStyle, ellipseValue->centerY())); - ellipse->setRadiusX(convertToLength(style, rootStyle, ellipseValue->radiusX())); - ellipse->setRadiusY(convertToLength(style, rootStyle, ellipseValue->radiusY())); - - basicShape = ellipse.release(); + basicShape = WTFMove(circle); break; } case CSSBasicShape::CSSBasicShapeEllipseType: { - const CSSBasicShapeEllipse* ellipseValue = static_cast(basicShapeValue); - RefPtr ellipse = BasicShapeEllipse::create(); + auto& ellipseValue = downcast(basicShapeValue); + auto ellipse = BasicShapeEllipse::create(); - ellipse->setCenterX(convertToCenterCoordinate(style, rootStyle, ellipseValue->centerX())); - ellipse->setCenterY(convertToCenterCoordinate(style, rootStyle, ellipseValue->centerY())); + ellipse->setCenterX(convertToCenterCoordinate(conversionData, ellipseValue.centerX())); + ellipse->setCenterY(convertToCenterCoordinate(conversionData, ellipseValue.centerY())); - ellipse->setRadiusX(cssValueToBasicShapeRadius(style, rootStyle, ellipseValue->radiusX())); - ellipse->setRadiusY(cssValueToBasicShapeRadius(style, rootStyle, ellipseValue->radiusY())); + ellipse->setRadiusX(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusX())); + ellipse->setRadiusY(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusY())); - basicShape = ellipse.release(); + basicShape = WTFMove(ellipse); break; } case CSSBasicShape::CSSBasicShapePolygonType: { - const CSSBasicShapePolygon* polygonValue = static_cast(basicShapeValue); - RefPtr polygon = BasicShapePolygon::create(); + auto& polygonValue = downcast(basicShapeValue); + auto polygon = BasicShapePolygon::create(); - polygon->setWindRule(polygonValue->windRule()); - const Vector>& values = polygonValue->values(); + polygon->setWindRule(polygonValue.windRule()); + auto& values = polygonValue.values(); for (unsigned i = 0; i < values.size(); i += 2) - polygon->appendPoint(convertToLength(style, rootStyle, values.at(i).get()), convertToLength(style, rootStyle, values.at(i + 1).get())); + polygon->appendPoint(convertToLength(conversionData, values[i].ptr()), convertToLength(conversionData, values[i + 1].ptr())); - basicShape = polygon.release(); - break; - } - case CSSBasicShape::CSSBasicShapeInsetRectangleType: { - const CSSBasicShapeInsetRectangle* rectValue = static_cast(basicShapeValue); - RefPtr rect = BasicShapeInsetRectangle::create(); - - rect->setTop(convertToLength(style, rootStyle, rectValue->top())); - rect->setRight(convertToLength(style, rootStyle, rectValue->right())); - rect->setBottom(convertToLength(style, rootStyle, rectValue->bottom())); - rect->setLeft(convertToLength(style, rootStyle, rectValue->left())); - if (rectValue->radiusX()) { - Length radiusX = convertToLength(style, rootStyle, rectValue->radiusX()); - rect->setCornerRadiusX(radiusX); - if (rectValue->radiusY()) - rect->setCornerRadiusY(convertToLength(style, rootStyle, rectValue->radiusY())); - else - rect->setCornerRadiusY(radiusX); - } else { - rect->setCornerRadiusX(Length(0, Fixed)); - rect->setCornerRadiusY(Length(0, Fixed)); - } - basicShape = rect.release(); + basicShape = WTFMove(polygon); break; } case CSSBasicShape::CSSBasicShapeInsetType: { - const CSSBasicShapeInset* rectValue = static_cast(basicShapeValue); - RefPtr rect = BasicShapeInset::create(); - - if (rectValue->top()) - rect->setTop(convertToLength(style, rootStyle, rectValue->top())); - else { - rect->setTop(Length(0, Fixed)); - return rect; - } - if (rectValue->right()) - rect->setRight(convertToLength(style, rootStyle, rectValue->right())); - else - rect->setRight(Length(0, Fixed)); - - if (rectValue->bottom()) - rect->setBottom(convertToLength(style, rootStyle, rectValue->bottom())); - else - rect->setBottom(Length(0, Fixed)); - - if (rectValue->left()) - rect->setLeft(convertToLength(style, rootStyle, rectValue->left())); - else - rect->setLeft(Length(0, Fixed)); - - if (rectValue->topLeftRadius()) { - Pair* topLeftRadius = rectValue->topLeftRadius()->getPairValue(); - rect->setTopLeftRadius(LengthSize(convertToLength(style, rootStyle, topLeftRadius->first()), convertToLength(style, rootStyle, topLeftRadius->second()))); - } else - rect->setTopLeftRadius(LengthSize(Length(0, Fixed), Length(0, Fixed))); - - if (rectValue->topRightRadius()) { - Pair* topRightRadius = rectValue->topRightRadius()->getPairValue(); - rect->setTopRightRadius(LengthSize(convertToLength(style, rootStyle, topRightRadius->first()), convertToLength(style, rootStyle, topRightRadius->second()))); - } else - rect->setTopRightRadius(LengthSize(Length(0, Fixed), Length(0, Fixed))); - - if (rectValue->bottomRightRadius()) { - Pair* bottomRightRadius = rectValue->bottomRightRadius()->getPairValue(); - rect->setBottomRightRadius(LengthSize(convertToLength(style, rootStyle, bottomRightRadius->first()), convertToLength(style, rootStyle, bottomRightRadius->second()))); - } else - rect->setBottomRightRadius(LengthSize(Length(0, Fixed), Length(0, Fixed))); - - if (rectValue->topLeftRadius()) { - Pair* bottomLeftRadius = rectValue->bottomLeftRadius()->getPairValue(); - rect->setBottomLeftRadius(LengthSize(convertToLength(style, rootStyle, bottomLeftRadius->first()), convertToLength(style, rootStyle, bottomLeftRadius->second()))); - } else - rect->setBottomLeftRadius(LengthSize(Length(0, Fixed), Length(0, Fixed))); - - basicShape = rect.release(); + auto& rectValue = downcast(basicShapeValue); + auto rect = BasicShapeInset::create(); + + rect->setTop(convertToLength(conversionData, rectValue.top())); + rect->setRight(convertToLength(conversionData, rectValue.right())); + rect->setBottom(convertToLength(conversionData, rectValue.bottom())); + rect->setLeft(convertToLength(conversionData, rectValue.left())); + + rect->setTopLeftRadius(convertToLengthSize(conversionData, rectValue.topLeftRadius())); + rect->setTopRightRadius(convertToLengthSize(conversionData, rectValue.topRightRadius())); + rect->setBottomRightRadius(convertToLengthSize(conversionData, rectValue.bottomRightRadius())); + rect->setBottomLeftRadius(convertToLengthSize(conversionData, rectValue.bottomLeftRadius())); + + basicShape = WTFMove(rect); break; } - default: + case CSSBasicShape::CSSBasicShapePathType: { + auto& pathValue = downcast(basicShapeValue); + auto path = BasicShapePath::create(pathValue.pathData().copy()); + path->setWindRule(pathValue.windRule()); + + basicShape = WTFMove(path); break; } + } - if (basicShapeValue->layoutBox()) - basicShape->setLayoutBox(LayoutBox(*basicShapeValue->layoutBox())); - - return basicShape.release(); + return basicShape.releaseNonNull(); } float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate& center, float boxDimension) diff --git a/Source/WebCore/css/BasicShapeFunctions.h b/Source/WebCore/css/BasicShapeFunctions.h index 94354a0b2..5252b7890 100644 --- a/Source/WebCore/css/BasicShapeFunctions.h +++ b/Source/WebCore/css/BasicShapeFunctions.h @@ -27,26 +27,21 @@ * SUCH DAMAGE. */ -#ifndef BasicShapeFunctions_h -#define BasicShapeFunctions_h +#pragma once -#include "BasicShapes.h" -#include +#include namespace WebCore { +class BasicShape; +class BasicShapeCenterCoordinate; class CSSBasicShape; +class CSSToLengthConversionData; class CSSPrimitiveValue; -class CSSValue; class RenderStyle; -PassRefPtr valueForBasicShape(const RenderStyle*, const BasicShape*); -PassRefPtr basicShapeForValue(const RenderStyle*, const RenderStyle* rootStyle, const CSSBasicShape*); - -PassRefPtr valueForBox(LayoutBox); -LayoutBox boxForValue(const CSSPrimitiveValue*); - +Ref valueForBasicShape(const RenderStyle&, const BasicShape&); +Ref basicShapeForValue(const CSSToLengthConversionData&, const CSSBasicShape&); float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate&, float); -} -#endif +} diff --git a/Source/WebCore/css/CSSAllInOne.cpp b/Source/WebCore/css/CSSAllInOne.cpp new file mode 100644 index 000000000..b116afa8d --- /dev/null +++ b/Source/WebCore/css/CSSAllInOne.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "BasicShapeFunctions.cpp" +#include "CSSAspectRatioValue.cpp" +#include "CSSBasicShapes.cpp" +#include "CSSBorderImage.cpp" +#include "CSSBorderImageSliceValue.cpp" +#include "CSSCalculationValue.cpp" +#include "CSSCanvasValue.cpp" +#include "CSSComputedStyleDeclaration.cpp" +#include "CSSContentDistributionValue.cpp" +#include "CSSCrossfadeValue.cpp" +#include "CSSCursorImageValue.cpp" +#include "CSSDefaultStyleSheets.cpp" +#include "CSSFilterImageValue.cpp" +#include "CSSFontFace.cpp" +#include "CSSFontFaceLoadEvent.cpp" +#include "CSSFontFaceRule.cpp" +#include "CSSFontFaceSet.cpp" +#include "CSSFontFaceSource.cpp" +#include "CSSFontFaceSrcValue.cpp" +#include "CSSFontFeatureValue.cpp" +#include "CSSFontSelector.cpp" +#include "CSSFontValue.cpp" +#include "CSSFontVariationValue.cpp" +#include "CSSFunctionValue.cpp" +#include "CSSGradientValue.cpp" +#include "CSSGridLineNamesValue.cpp" +#include "CSSGridTemplateAreasValue.cpp" +#include "CSSGroupingRule.cpp" +#include "CSSImageGeneratorValue.cpp" +#include "CSSImageSetValue.cpp" +#include "CSSImageValue.cpp" +#include "CSSImportRule.cpp" +#include "CSSInheritedValue.cpp" +#include "CSSInitialValue.cpp" +#include "CSSKeyframeRule.cpp" +#include "CSSKeyframesRule.cpp" +#include "CSSLineBoxContainValue.cpp" +#include "CSSMarkup.cpp" +#include "CSSMediaRule.cpp" +#include "CSSNamedImageValue.cpp" +#include "CSSPageRule.cpp" +#include "CSSParser.cpp" +#include "CSSParserSelector.cpp" +#include "CSSProperty.cpp" +#include "CSSPropertySourceData.cpp" +#include "CSSReflectValue.cpp" +#include "CSSRevertValue.cpp" +#include "CSSRule.cpp" +#include "CSSRuleList.cpp" +#include "CSSSegmentedFontFace.cpp" +#include "CSSSelector.cpp" +#include "CSSSelectorList.cpp" +#include "CSSShadowValue.cpp" +#include "CSSStyleRule.cpp" +#include "CSSStyleSheet.cpp" +#include "CSSSupportsRule.cpp" +#include "CSSTimingFunctionValue.cpp" +#include "CSSToLengthConversionData.cpp" +#include "CSSToStyleMap.cpp" +#include "CSSUnicodeRangeValue.cpp" +#include "CSSUnsetValue.cpp" +#include "CSSValue.cpp" +#include "CSSValueList.cpp" +#include "CSSValuePool.cpp" +#include "DOMCSSNamespace.cpp" +#include "DocumentRuleSets.cpp" +#include "ElementRuleCollector.cpp" +#include "FontFace.cpp" +#include "FontVariantBuilder.cpp" +#include "InspectorCSSOMWrappers.cpp" +#include "LengthFunctions.cpp" +#include "MediaList.cpp" +#include "MediaQuery.cpp" +#include "MediaQueryEvaluator.cpp" +#include "MediaQueryExpression.cpp" +#include "MediaQueryList.cpp" +#include "MediaQueryMatcher.cpp" +#include "PageRuleCollector.cpp" +#include "PropertySetCSSStyleDeclaration.cpp" +#include "RGBColor.cpp" +#include "RuleFeature.cpp" +#include "RuleSet.cpp" +#include "SVGCSSComputedStyleDeclaration.cpp" +#include "SelectorChecker.cpp" +#include "SelectorFilter.cpp" +#include "StyleInvalidationAnalysis.cpp" +#include "StyleMedia.cpp" +#include "StyleProperties.cpp" +#include "StylePropertyShorthand.cpp" +#include "StyleResolver.cpp" +#include "StyleRule.cpp" +#include "StyleRuleImport.cpp" +#include "StyleSheet.cpp" +#include "StyleSheetContents.cpp" +#include "StyleSheetList.cpp" +#include "TransformFunctions.cpp" +#include "ViewportStyleResolver.cpp" +#include "WebKitCSSMatrix.cpp" +#include "WebKitCSSRegionRule.cpp" +#include "WebKitCSSViewportRule.cpp" + diff --git a/Source/WebCore/css/CSSAnimationTriggerScrollValue.cpp b/Source/WebCore/css/CSSAnimationTriggerScrollValue.cpp new file mode 100644 index 000000000..a1a597b86 --- /dev/null +++ b/Source/WebCore/css/CSSAnimationTriggerScrollValue.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSAnimationTriggerScrollValue.h" +#include + +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + +#include + +namespace WebCore { + +String CSSAnimationTriggerScrollValue::customCSSText() const +{ + StringBuilder result; + result.appendLiteral("container-scroll("); + result.append(m_startValue->cssText()); + if (m_endValue) { + result.appendLiteral(", "); + result.append(m_endValue->cssText()); + } + result.append(')'); + return result.toString(); +} + +bool CSSAnimationTriggerScrollValue::equals(const CSSAnimationTriggerScrollValue& other) const +{ + return m_startValue->equals(other.m_startValue.get()) && arePointingToEqualData(m_endValue.get(), other.m_endValue.get()); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/css/CSSAnimationTriggerScrollValue.h b/Source/WebCore/css/CSSAnimationTriggerScrollValue.h new file mode 100644 index 000000000..e5e02740c --- /dev/null +++ b/Source/WebCore/css/CSSAnimationTriggerScrollValue.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + +#include "CSSValue.h" + +namespace WebCore { + +class CSSAnimationTriggerScrollValue final : public CSSValue { +public: + static Ref create(Ref&& startValue, RefPtr&& endValue = nullptr) + { + return adoptRef(*new CSSAnimationTriggerScrollValue(WTFMove(startValue), WTFMove(endValue))); + } + + const CSSValue& startValue() const { return m_startValue.get(); } + const CSSValue* endValue() const { return m_endValue.get(); } + bool hasEndValue() const { return m_endValue; } + + String customCSSText() const; + + bool equals(const CSSAnimationTriggerScrollValue&) const; + bool operator==(const CSSAnimationTriggerScrollValue& other) const { return equals(other); } + +private: + CSSAnimationTriggerScrollValue(Ref&& startValue, RefPtr&& endValue) + : CSSValue(AnimationTriggerScrollClass) + , m_startValue(WTFMove(startValue)) + , m_endValue(WTFMove(endValue)) + { + } + + Ref m_startValue; + RefPtr m_endValue; +}; + +} + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSAnimationTriggerScrollValue, isAnimationTriggerScrollValue()) + +#endif diff --git a/Source/WebCore/css/CSSAspectRatioValue.cpp b/Source/WebCore/css/CSSAspectRatioValue.cpp index 221fa63eb..5c414aba9 100644 --- a/Source/WebCore/css/CSSAspectRatioValue.cpp +++ b/Source/WebCore/css/CSSAspectRatioValue.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,8 +29,6 @@ #include "config.h" #include "CSSAspectRatioValue.h" -#include - namespace WebCore { String CSSAspectRatioValue::customCSSText() const diff --git a/Source/WebCore/css/CSSAspectRatioValue.h b/Source/WebCore/css/CSSAspectRatioValue.h index fb582e421..d8ca16f21 100644 --- a/Source/WebCore/css/CSSAspectRatioValue.h +++ b/Source/WebCore/css/CSSAspectRatioValue.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,17 +26,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSAspectRatioValue_h -#define CSSAspectRatioValue_h +#pragma once -#include "CSSPrimitiveValue.h" #include "CSSValue.h" namespace WebCore { -class CSSAspectRatioValue : public CSSValue { +class CSSAspectRatioValue final : public CSSValue { public: - static PassRef create(float numeratorValue, float denominatorValue) + static Ref create(float numeratorValue, float denominatorValue) { return adoptRef(*new CSSAspectRatioValue(numeratorValue, denominatorValue)); } @@ -60,8 +58,6 @@ private: float m_denominatorValue; }; -CSS_VALUE_TYPE_CASTS(CSSAspectRatioValue, isAspectRatioValue()) +} // namespace WebCore -} - -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSAspectRatioValue, isAspectRatioValue()) diff --git a/Source/WebCore/css/CSSBasicShapes.cpp b/Source/WebCore/css/CSSBasicShapes.cpp index c36f43e96..dd8f9c7b5 100644 --- a/Source/WebCore/css/CSSBasicShapes.cpp +++ b/Source/WebCore/css/CSSBasicShapes.cpp @@ -31,79 +31,70 @@ #include "CSSBasicShapes.h" +#include "CSSMarkup.h" #include "CSSPrimitiveValueMappings.h" +#include "CSSValuePool.h" #include "Pair.h" +#include "SVGPathByteStream.h" +#include "SVGPathUtilities.h" #include using namespace WTF; namespace WebCore { -static String buildRectangleString(const String& x, const String& y, const String& width, const String& height, const String& radiusX, const String& radiusY, const String& box) +static String serializePositionOffset(const Pair& offset, const Pair& other) { - char opening[] = "rectangle("; - char separator[] = ", "; - StringBuilder result; - // Compute the required capacity in advance to reduce allocations. - result.reserveCapacity((sizeof(opening) - 1) + (5 * (sizeof(separator) - 1)) + 1 + x.length() + y.length() + width.length() + height.length() + radiusX.length() + radiusY.length() + (box.length() ? box.length() + 1 : 0)); - result.appendLiteral(opening); - result.append(x); - result.appendLiteral(separator); - result.append(y); - result.appendLiteral(separator); - result.append(width); - result.appendLiteral(separator); - result.append(height); - if (!radiusX.isNull()) { - result.appendLiteral(separator); - result.append(radiusX); - if (!radiusY.isNull()) { - result.appendLiteral(separator); - result.append(radiusY); - } - } - result.append(')'); - if (box.length()) { - result.append(' '); - result.append(box); - } - return result.toString(); -} - -String CSSBasicShapeRectangle::cssText() const -{ - return buildRectangleString(m_x->cssText(), - m_y->cssText(), - m_width->cssText(), - m_height->cssText(), - m_radiusX.get() ? m_radiusX->cssText() : String(), - m_radiusY.get() ? m_radiusY->cssText() : String(), - m_layoutBox ? m_layoutBox->cssText() : String()); + if ((offset.first()->valueID() == CSSValueLeft && other.first()->valueID() == CSSValueTop) + || (offset.first()->valueID() == CSSValueTop && other.first()->valueID() == CSSValueLeft)) + return offset.second()->cssText(); + return offset.cssText(); } -bool CSSBasicShapeRectangle::equals(const CSSBasicShape& shape) const +static Ref buildSerializablePositionOffset(CSSPrimitiveValue* offset, CSSValueID defaultSide) { - if (shape.type() != CSSBasicShapeRectangleType) - return false; + CSSValueID side = defaultSide; + RefPtr amount; + + if (!offset) + side = CSSValueCenter; + else if (offset->isValueID()) + side = offset->valueID(); + else if (Pair* pair = offset->pairValue()) { + side = pair->first()->valueID(); + amount = pair->second(); + } else + amount = offset; + + auto& cssValuePool = CSSValuePool::singleton(); + if (!amount) + amount = cssValuePool.createValue(Length(side == CSSValueCenter ? 50 : 0, Percent)); + + if (side == CSSValueCenter) + side = defaultSide; + else if ((side == CSSValueRight || side == CSSValueBottom) + && amount->isPercentage()) { + side = defaultSide; + amount = cssValuePool.createValue(Length(100 - amount->floatValue(), Percent)); + } else if (amount->isLength() && !amount->floatValue()) { + if (side == CSSValueRight || side == CSSValueBottom) + amount = cssValuePool.createValue(Length(100, Percent)); + else + amount = cssValuePool.createValue(Length(0, Percent)); + side = defaultSide; + } - const CSSBasicShapeRectangle& other = static_cast(shape); - return compareCSSValuePtr(m_x, other.m_x) - && compareCSSValuePtr(m_y, other.m_y) - && compareCSSValuePtr(m_width, other.m_width) - && compareCSSValuePtr(m_height, other.m_height) - && compareCSSValuePtr(m_radiusX, other.m_radiusX) - && compareCSSValuePtr(m_radiusY, other.m_radiusY) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); + return cssValuePool.createValue(Pair::create(cssValuePool.createValue(side), WTFMove(amount))); } -static String buildCircleString(const String& radius, const String& centerX, const String& centerY, const String& box) +static String buildCircleString(const String& radius, const String& centerX, const String& centerY) { char opening[] = "circle("; char at[] = "at"; char separator[] = " "; StringBuilder result; result.appendLiteral(opening); - if (!radius.isNull()) + if (!radius.isNull()) result.append(radius); if (!centerX.isNull() || !centerY.isNull()) { @@ -116,70 +107,35 @@ static String buildCircleString(const String& radius, const String& centerX, con result.append(centerY); } result.appendLiteral(")"); - if (box.length()) { - result.appendLiteral(separator); - result.append(box); - } return result.toString(); } String CSSBasicShapeCircle::cssText() const { - return buildCircleString(m_radius ? m_radius->cssText() : String(), - m_centerX ? m_centerX->cssText() : String(), - m_centerY ? m_centerY->cssText() : String(), - m_layoutBox ? m_layoutBox->cssText() : String()); -} - -bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const -{ - if (shape.type() != CSSBasicShapeCircleType) - return false; - - const CSSBasicShapeCircle& other = static_cast(shape); - return compareCSSValuePtr(m_centerX, other.m_centerX) - && compareCSSValuePtr(m_centerY, other.m_centerY) - && compareCSSValuePtr(m_radius, other.m_radius) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); -} + Ref normalizedCX = buildSerializablePositionOffset(m_centerX.get(), CSSValueLeft); + Ref normalizedCY = buildSerializablePositionOffset(m_centerY.get(), CSSValueTop); -static String buildDeprecatedCircleString(const String& x, const String& y, const String& radius, const String& box) -{ - StringBuilder result; - char opening[] = "circle("; - char separator[] = ", "; - result.appendLiteral(opening); - result.append(x); - result.appendLiteral(separator); - result.append(y); - result.appendLiteral(separator); - result.append(radius); - result.append(')'); - if (box.length()) { - result.append(' '); - result.append(box); - } - return result.toString(); -} + String radius; + if (m_radius && m_radius->valueID() != CSSValueClosestSide) + radius = m_radius->cssText(); -String CSSDeprecatedBasicShapeCircle::cssText() const -{ - return buildDeprecatedCircleString(m_centerX->cssText(), m_centerY->cssText(), m_radius->cssText(), m_layoutBox ? m_layoutBox->cssText() : String()); + return buildCircleString(radius, + serializePositionOffset(*normalizedCX->pairValue(), *normalizedCY->pairValue()), + serializePositionOffset(*normalizedCY->pairValue(), *normalizedCX->pairValue())); } -bool CSSDeprecatedBasicShapeCircle::equals(const CSSBasicShape& shape) const +bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const { - if (shape.type() != CSSDeprecatedBasicShapeCircleType) + if (!is(shape)) return false; - const CSSDeprecatedBasicShapeCircle& other = static_cast(shape); + const CSSBasicShapeCircle& other = downcast(shape); return compareCSSValuePtr(m_centerX, other.m_centerX) && compareCSSValuePtr(m_centerY, other.m_centerY) - && compareCSSValuePtr(m_radius, other.m_radius) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); + && compareCSSValuePtr(m_radius, other.m_radius); } -static String buildEllipseString(const String& radiusX, const String& radiusY, const String& centerX, const String& centerY, const String& box) +static String buildEllipseString(const String& radiusX, const String& radiusY, const String& centerX, const String& centerY) { char opening[] = "ellipse("; char at[] = "at"; @@ -208,84 +164,96 @@ static String buildEllipseString(const String& radiusX, const String& radiusY, c result.append(centerY); } result.appendLiteral(")"); - if (box.length()) { - result.appendLiteral(separator); - result.append(box); - } return result.toString(); } String CSSBasicShapeEllipse::cssText() const { - return buildEllipseString(m_radiusX ? m_radiusX->cssText() : String(), - m_radiusY ? m_radiusY->cssText() : String(), - m_centerX ? m_centerX->cssText() : String(), - m_centerY ? m_centerY->cssText() : String(), - m_layoutBox ? m_layoutBox->cssText() : String()); + Ref normalizedCX = buildSerializablePositionOffset(m_centerX.get(), CSSValueLeft); + Ref normalizedCY = buildSerializablePositionOffset(m_centerY.get(), CSSValueTop); + + String radiusX; + String radiusY; + if (m_radiusX) { + bool shouldSerializeRadiusXValue = m_radiusX->valueID() != CSSValueClosestSide; + bool shouldSerializeRadiusYValue = false; + + if (m_radiusY) { + shouldSerializeRadiusYValue = m_radiusY->valueID() != CSSValueClosestSide; + if (shouldSerializeRadiusYValue) + radiusY = m_radiusY->cssText(); + } + if (shouldSerializeRadiusXValue || (!shouldSerializeRadiusXValue && shouldSerializeRadiusYValue)) + radiusX = m_radiusX->cssText(); + } + return buildEllipseString(radiusX, radiusY, + serializePositionOffset(*normalizedCX->pairValue(), *normalizedCY->pairValue()), + serializePositionOffset(*normalizedCY->pairValue(), *normalizedCX->pairValue())); } bool CSSBasicShapeEllipse::equals(const CSSBasicShape& shape) const { - if (shape.type() != CSSBasicShapeEllipseType) + if (!is(shape)) return false; - const CSSBasicShapeEllipse& other = static_cast(shape); + const CSSBasicShapeEllipse& other = downcast(shape); return compareCSSValuePtr(m_centerX, other.m_centerX) && compareCSSValuePtr(m_centerY, other.m_centerY) && compareCSSValuePtr(m_radiusX, other.m_radiusX) - && compareCSSValuePtr(m_radiusY, other.m_radiusY) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); + && compareCSSValuePtr(m_radiusY, other.m_radiusY); } -static String buildDeprecatedEllipseString(const String& x, const String& y, const String& radiusX, const String& radiusY, const String& box) +CSSBasicShapePath::CSSBasicShapePath(std::unique_ptr&& pathData) + : m_byteStream(WTFMove(pathData)) +{ +} + +static String buildPathString(const WindRule& windRule, const String& path, const String& box) { StringBuilder result; - char opening[] = "ellipse("; - char separator[] = ", "; - result.appendLiteral(opening); - result.append(x); - result.appendLiteral(separator); - result.append(y); - result.appendLiteral(separator); - result.append(radiusX); - result.appendLiteral(separator); - result.append(radiusY); + if (windRule == RULE_EVENODD) + result.appendLiteral("path(evenodd, "); + else + result.appendLiteral("path("); + + serializeString(path, result); result.append(')'); + if (box.length()) { result.append(' '); result.append(box); } + return result.toString(); } -String CSSDeprecatedBasicShapeEllipse::cssText() const +String CSSBasicShapePath::cssText() const { - return buildDeprecatedEllipseString(m_centerX->cssText(), m_centerY->cssText(), m_radiusX->cssText(), m_radiusY->cssText(), m_layoutBox ? m_layoutBox->cssText() : String()); + String pathString; + buildStringFromByteStream(*m_byteStream, pathString, UnalteredParsing); + + return buildPathString(m_windRule, pathString, m_referenceBox ? m_referenceBox->cssText() : String()); } -bool CSSDeprecatedBasicShapeEllipse::equals(const CSSBasicShape& shape) const +bool CSSBasicShapePath::equals(const CSSBasicShape& otherShape) const { - if (shape.type() != CSSDeprecatedBasicShapeEllipseType) + if (!is(otherShape)) return false; - const CSSDeprecatedBasicShapeEllipse& other = static_cast(shape); - return compareCSSValuePtr(m_centerX, other.m_centerX) - && compareCSSValuePtr(m_centerY, other.m_centerY) - && compareCSSValuePtr(m_radiusX, other.m_radiusX) - && compareCSSValuePtr(m_radiusY, other.m_radiusY) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); + auto& otherShapePath = downcast(otherShape); + return windRule() == otherShapePath.windRule() && pathData() == otherShapePath.pathData(); } -static String buildPolygonString(const WindRule& windRule, const Vector& points, const String& box) +static String buildPolygonString(const WindRule& windRule, const Vector& points) { ASSERT(!(points.size() % 2)); StringBuilder result; char evenOddOpening[] = "polygon(evenodd, "; - char nonZeroOpening[] = "polygon(nonzero, "; + char nonZeroOpening[] = "polygon("; char commaSeparator[] = ", "; - COMPILE_ASSERT(sizeof(evenOddOpening) == sizeof(nonZeroOpening), polygon_string_openings_have_same_length); - + COMPILE_ASSERT(sizeof(evenOddOpening) >= sizeof(nonZeroOpening), polygon_evenodd_is_longest_string_opening); + // Compute the required capacity in advance to reduce allocations. size_t length = sizeof(evenOddOpening) - 1; for (size_t i = 0; i < points.size(); i += 2) { @@ -295,9 +263,6 @@ static String buildPolygonString(const WindRule& windRule, const Vector& length += points[i].length() + 1 + points[i + 1].length(); } - if (box.length()) - length += box.length() + 1; - result.reserveCapacity(length); if (windRule == RULE_EVENODD) @@ -315,11 +280,6 @@ static String buildPolygonString(const WindRule& windRule, const Vector& result.append(')'); - if (box.length()) { - result.append(' '); - result.append(box); - } - return result.toString(); } @@ -328,85 +288,42 @@ String CSSBasicShapePolygon::cssText() const Vector points; points.reserveInitialCapacity(m_values.size()); - for (size_t i = 0; i < m_values.size(); ++i) - points.append(m_values.at(i)->cssText()); + for (auto& shapeValue : m_values) + points.uncheckedAppend(shapeValue->cssText()); - return buildPolygonString(m_windRule, points, m_layoutBox ? m_layoutBox->cssText() : String()); + return buildPolygonString(m_windRule, points); } bool CSSBasicShapePolygon::equals(const CSSBasicShape& shape) const { - if (shape.type() != CSSBasicShapePolygonType) + if (!is(shape)) return false; - const CSSBasicShapePolygon& rhs = static_cast(shape); - return compareCSSValuePtr(m_layoutBox, rhs.m_layoutBox) - && compareCSSValueVector(m_values, rhs.m_values); -} - -static String buildInsetRectangleString(const String& top, const String& right, const String& bottom, const String& left, const String& radiusX, const String& radiusY, const String& box) -{ - char opening[] = "inset-rectangle("; - char separator[] = ", "; - StringBuilder result; - // Compute the required capacity in advance to reduce allocations. - result.reserveCapacity((sizeof(opening) - 1) + (5 * (sizeof(separator) - 1)) + 1 + top.length() + right.length() + bottom.length() + left.length() + radiusX.length() + radiusY.length() + (box.length() ? box.length() + 1 : 0)); - result.appendLiteral(opening); - result.append(top); - result.appendLiteral(separator); - result.append(right); - result.appendLiteral(separator); - result.append(bottom); - result.appendLiteral(separator); - result.append(left); - if (!radiusX.isNull()) { - result.appendLiteral(separator); - result.append(radiusX); - if (!radiusY.isNull()) { - result.appendLiteral(separator); - result.append(radiusY); - } - } - result.append(')'); - if (box.length()) { - result.append(' '); - result.append(box); - } - return result.toString(); + return compareCSSValueVector(m_values, downcast(shape).m_values); } -String CSSBasicShapeInsetRectangle::cssText() const +static bool buildInsetRadii(Vector& radii, const String& topLeftRadius, const String& topRightRadius, const String& bottomRightRadius, const String& bottomLeftRadius) { - return buildInsetRectangleString(m_top->cssText(), - m_right->cssText(), - m_bottom->cssText(), - m_left->cssText(), - m_radiusX.get() ? m_radiusX->cssText() : String(), - m_radiusY.get() ? m_radiusY->cssText() : String(), - m_layoutBox ? m_layoutBox->cssText() : String()); -} - -bool CSSBasicShapeInsetRectangle::equals(const CSSBasicShape& shape) const -{ - if (shape.type() != CSSBasicShapeInsetRectangleType) - return false; - - const CSSBasicShapeInsetRectangle& other = static_cast(shape); - return compareCSSValuePtr(m_top, other.m_top) - && compareCSSValuePtr(m_right, other.m_right) - && compareCSSValuePtr(m_bottom, other.m_bottom) - && compareCSSValuePtr(m_left, other.m_left) - && compareCSSValuePtr(m_radiusX, other.m_radiusX) - && compareCSSValuePtr(m_radiusY, other.m_radiusY) - && compareCSSValuePtr(m_layoutBox, other.m_layoutBox); + bool showBottomLeft = topRightRadius != bottomLeftRadius; + bool showBottomRight = showBottomLeft || (bottomRightRadius != topLeftRadius); + bool showTopRight = showBottomRight || (topRightRadius != topLeftRadius); + + radii.append(topLeftRadius); + if (showTopRight) + radii.append(topRightRadius); + if (showBottomRight) + radii.append(bottomRightRadius); + if (showBottomLeft) + radii.append(bottomLeftRadius); + + return radii.size() == 1 && radii[0] == "0px"; } static String buildInsetString(const String& top, const String& right, const String& bottom, const String& left, const String& topLeftRadiusWidth, const String& topLeftRadiusHeight, const String& topRightRadiusWidth, const String& topRightRadiusHeight, const String& bottomRightRadiusWidth, const String& bottomRightRadiusHeight, - const String& bottomLeftRadiusWidth, const String& bottomLeftRadiusHeight, - const String& box) + const String& bottomLeftRadiusWidth, const String& bottomLeftRadiusHeight) { char opening[] = "inset("; char separator[] = " "; @@ -414,92 +331,81 @@ static String buildInsetString(const String& top, const String& right, const Str StringBuilder result; result.appendLiteral(opening); result.append(top); - if (!right.isNull()) { + + bool showLeftArg = !left.isNull() && left != right; + bool showBottomArg = !bottom.isNull() && (bottom != top || showLeftArg); + bool showRightArg = !right.isNull() && (right != top || showBottomArg); + if (showRightArg) { result.appendLiteral(separator); result.append(right); } - if (!bottom.isNull()) { + if (showBottomArg) { result.appendLiteral(separator); result.append(bottom); } - if (!left.isNull()) { + if (showLeftArg) { result.appendLiteral(separator); result.append(left); } if (!topLeftRadiusWidth.isNull() && !topLeftRadiusHeight.isNull()) { - result.appendLiteral(separator); - result.appendLiteral(cornersSeparator); - result.appendLiteral(separator); + Vector horizontalRadii; + bool areDefaultCornerRadii = buildInsetRadii(horizontalRadii, topLeftRadiusWidth, topRightRadiusWidth, bottomRightRadiusWidth, bottomLeftRadiusWidth); - result.append(topLeftRadiusWidth); - result.appendLiteral(separator); - result.append(topRightRadiusWidth); - result.appendLiteral(separator); - result.append(bottomRightRadiusWidth); - result.appendLiteral(separator); - result.append(bottomLeftRadiusWidth); + Vector verticalRadii; + areDefaultCornerRadii &= buildInsetRadii(verticalRadii, topLeftRadiusHeight, topRightRadiusHeight, bottomRightRadiusHeight, bottomLeftRadiusHeight); - result.appendLiteral(separator); - result.append('/'); - result.appendLiteral(separator); - - result.append(topLeftRadiusHeight); - result.appendLiteral(separator); - result.append(topRightRadiusHeight); - result.appendLiteral(separator); - result.append(bottomRightRadiusHeight); - result.appendLiteral(separator); - result.append(bottomLeftRadiusHeight); + if (!areDefaultCornerRadii) { + result.appendLiteral(separator); + result.appendLiteral(cornersSeparator); + + for (size_t i = 0; i < horizontalRadii.size(); ++i) { + result.appendLiteral(separator); + result.append(horizontalRadii[i]); + } + + if (verticalRadii.size() != horizontalRadii.size() + || !VectorComparer::compare(verticalRadii.data(), horizontalRadii.data(), verticalRadii.size())) { + result.appendLiteral(separator); + result.appendLiteral("/"); + + for (size_t i = 0; i < verticalRadii.size(); ++i) { + result.appendLiteral(separator); + result.append(verticalRadii[i]); + } + } + } } result.append(')'); - if (box.length()) { - result.append(' '); - result.append(box); - } return result.toString(); } +static inline void updateCornerRadiusWidthAndHeight(CSSPrimitiveValue* corner, String& width, String& height) +{ + if (!corner) + return; + + Pair* radius = corner->pairValue(); + width = radius->first() ? radius->first()->cssText() : String("0"); + if (radius->second()) + height = radius->second()->cssText(); +} + String CSSBasicShapeInset::cssText() const { String topLeftRadiusWidth; String topLeftRadiusHeight; - if (topLeftRadius()) { - Pair* topLeftRadius = m_topLeftRadius->getPairValue(); - topLeftRadiusWidth = topLeftRadius->first() ? topLeftRadius->first()->cssText() : String("0"); - if (topLeftRadius->second()) - topLeftRadiusHeight = topLeftRadius->second()->cssText(); - } - String topRightRadiusWidth; String topRightRadiusHeight; - if (topRightRadius()) { - Pair* topRightRadius = m_topRightRadius->getPairValue(); - if (topRightRadius->first()) - topRightRadiusWidth = topRightRadius->first()->cssText(); - if (topRightRadius->second()) - topRightRadiusHeight = topRightRadius->second()->cssText(); - } - String bottomRightRadiusWidth; String bottomRightRadiusHeight; - if (bottomRightRadius()) { - Pair* bottomRightRadius = m_bottomRightRadius->getPairValue(); - if (bottomRightRadius->first()) - bottomRightRadiusWidth = bottomRightRadius->first()->cssText(); - if (bottomRightRadius->second()) - bottomRightRadiusHeight = bottomRightRadius->second()->cssText(); - } - String bottomLeftRadiusWidth; String bottomLeftRadiusHeight; - if (bottomLeftRadius()) { - Pair* bottomLeftRadius = m_bottomLeftRadius->getPairValue(); - if (bottomLeftRadius->first()) - bottomLeftRadiusWidth = bottomLeftRadius->first()->cssText(); - if (bottomLeftRadius->second()) - bottomLeftRadiusHeight = bottomLeftRadius->second()->cssText(); - } + + updateCornerRadiusWidthAndHeight(topLeftRadius(), topLeftRadiusWidth, topLeftRadiusHeight); + updateCornerRadiusWidthAndHeight(topRightRadius(), topRightRadiusWidth, topRightRadiusHeight); + updateCornerRadiusWidthAndHeight(bottomRightRadius(), bottomRightRadiusWidth, bottomRightRadiusHeight); + updateCornerRadiusWidthAndHeight(bottomLeftRadius(), bottomLeftRadiusWidth, bottomLeftRadiusHeight); return buildInsetString(m_top ? m_top->cssText() : String(), m_right ? m_right->cssText() : String(), @@ -512,16 +418,15 @@ String CSSBasicShapeInset::cssText() const bottomRightRadiusWidth, bottomRightRadiusHeight, bottomLeftRadiusWidth, - bottomLeftRadiusHeight, - m_layoutBox ? m_layoutBox->cssText() : String()); + bottomLeftRadiusHeight); } bool CSSBasicShapeInset::equals(const CSSBasicShape& shape) const { - if (shape.type() != CSSBasicShapeInsetType) + if (!is(shape)) return false; - const CSSBasicShapeInset& other = static_cast(shape); + const CSSBasicShapeInset& other = downcast(shape); return compareCSSValuePtr(m_top, other.m_top) && compareCSSValuePtr(m_right, other.m_right) && compareCSSValuePtr(m_bottom, other.m_bottom) diff --git a/Source/WebCore/css/CSSBasicShapes.h b/Source/WebCore/css/CSSBasicShapes.h index 4d85bf42b..6f449cc70 100644 --- a/Source/WebCore/css/CSSBasicShapes.h +++ b/Source/WebCore/css/CSSBasicShapes.h @@ -27,115 +27,44 @@ * SUCH DAMAGE. */ -#ifndef CSSBasicShapes_h -#define CSSBasicShapes_h +#pragma once -#include "CSSPrimitiveValue.h" #include "WindRule.h" #include +#include #include #include namespace WebCore { +class CSSPrimitiveValue; +class SVGPathByteStream; + class CSSBasicShape : public RefCounted { public: enum Type { - CSSBasicShapeRectangleType, - CSSDeprecatedBasicShapeCircleType, - CSSDeprecatedBasicShapeEllipseType, CSSBasicShapePolygonType, - CSSBasicShapeInsetRectangleType, CSSBasicShapeCircleType, CSSBasicShapeEllipseType, - CSSBasicShapeInsetType + CSSBasicShapeInsetType, + CSSBasicShapePathType }; virtual Type type() const = 0; virtual String cssText() const = 0; virtual bool equals(const CSSBasicShape&) const = 0; - CSSPrimitiveValue* layoutBox() const { return m_layoutBox.get(); } - void setLayoutBox(PassRefPtr layoutBox) { m_layoutBox = layoutBox; } - public: virtual ~CSSBasicShape() { } protected: CSSBasicShape() { } - RefPtr m_layoutBox; + RefPtr m_referenceBox; }; -class CSSBasicShapeRectangle : public CSSBasicShape { +class CSSBasicShapeInset final : public CSSBasicShape { public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapeRectangle); } - - CSSPrimitiveValue* x() const { return m_x.get(); } - CSSPrimitiveValue* y() const { return m_y.get(); } - CSSPrimitiveValue* width() const { return m_width.get(); } - CSSPrimitiveValue* height() const { return m_height.get(); } - CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } - CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } - - void setX(PassRefPtr x) { m_x = x; } - void setY(PassRefPtr y) { m_y = y; } - void setWidth(PassRefPtr width) { m_width = width; } - void setHeight(PassRefPtr height) { m_height = height; } - void setRadiusX(PassRefPtr radiusX) { m_radiusX = radiusX; } - void setRadiusY(PassRefPtr radiusY) { m_radiusY = radiusY; } - - virtual Type type() const override { return CSSBasicShapeRectangleType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; - -private: - CSSBasicShapeRectangle() { } - - RefPtr m_y; - RefPtr m_x; - RefPtr m_width; - RefPtr m_height; - RefPtr m_radiusX; - RefPtr m_radiusY; -}; - -class CSSBasicShapeInsetRectangle : public CSSBasicShape { -public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapeInsetRectangle); } - - CSSPrimitiveValue* top() const { return m_top.get(); } - CSSPrimitiveValue* right() const { return m_right.get(); } - CSSPrimitiveValue* bottom() const { return m_bottom.get(); } - CSSPrimitiveValue* left() const { return m_left.get(); } - CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } - CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } - - void setTop(PassRefPtr top) { m_top = top; } - void setRight(PassRefPtr right) { m_right = right; } - void setBottom(PassRefPtr bottom) { m_bottom = bottom; } - void setLeft(PassRefPtr left) { m_left = left; } - void setRadiusX(PassRefPtr radiusX) { m_radiusX = radiusX; } - void setRadiusY(PassRefPtr radiusY) { m_radiusY = radiusY; } - - virtual Type type() const override { return CSSBasicShapeInsetRectangleType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; - -private: - CSSBasicShapeInsetRectangle() { } - - RefPtr m_right; - RefPtr m_top; - RefPtr m_bottom; - RefPtr m_left; - RefPtr m_radiusX; - RefPtr m_radiusY; -}; - - -class CSSBasicShapeInset : public CSSBasicShape { -public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapeInset); } + static Ref create() { return adoptRef(*new CSSBasicShapeInset); } CSSPrimitiveValue* top() const { return m_top.get(); } CSSPrimitiveValue* right() const { return m_right.get(); } @@ -147,23 +76,46 @@ public: CSSPrimitiveValue* bottomRightRadius() const { return m_bottomRightRadius.get(); } CSSPrimitiveValue* bottomLeftRadius() const { return m_bottomLeftRadius.get(); } - void setTop(PassRefPtr top) { m_top = top; } - void setRight(PassRefPtr right) { m_right = right; } - void setBottom(PassRefPtr bottom) { m_bottom = bottom; } - void setLeft(PassRefPtr left) { m_left = left; } + void setTop(Ref&& top) { m_top = WTFMove(top); } + void setRight(Ref&& right) { m_right = WTFMove(right); } + void setBottom(Ref&& bottom) { m_bottom = WTFMove(bottom); } + void setLeft(Ref&& left) { m_left = WTFMove(left); } - void setTopLeftRadius(PassRefPtr radius) { m_topLeftRadius = radius; } - void setTopRightRadius(PassRefPtr radius) { m_topRightRadius = radius; } - void setBottomRightRadius(PassRefPtr radius) { m_bottomRightRadius = radius; } - void setBottomLeftRadius(PassRefPtr radius) { m_bottomLeftRadius = radius; } + void updateShapeSize4Values(Ref&& top, Ref&& right, Ref&& bottom, Ref&& left) + { + setTop(WTFMove(top)); + setRight(WTFMove(right)); + setBottom(WTFMove(bottom)); + setLeft(WTFMove(left)); + } + + void updateShapeSize1Value(Ref&& value1) + { + updateShapeSize4Values(value1.copyRef(), value1.copyRef(), value1.copyRef(), value1.copyRef()); + } + + void updateShapeSize2Values(Ref&& value1, Ref&& value2) + { + updateShapeSize4Values(value1.copyRef(), value2.copyRef(), value1.copyRef(), value2.copyRef()); + } + + void updateShapeSize3Values(Ref&& value1, Ref&& value2, Ref&& value3) + { + updateShapeSize4Values(WTFMove(value1), value2.copyRef(), WTFMove(value3), value2.copyRef()); + } - virtual Type type() const override { return CSSBasicShapeInsetType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; + void setTopLeftRadius(RefPtr&& radius) { m_topLeftRadius = WTFMove(radius); } + void setTopRightRadius(RefPtr&& radius) { m_topRightRadius = WTFMove(radius); } + void setBottomRightRadius(RefPtr&& radius) { m_bottomRightRadius = WTFMove(radius); } + void setBottomLeftRadius(RefPtr&& radius) { m_bottomLeftRadius = WTFMove(radius); } private: CSSBasicShapeInset() { } + Type type() const final { return CSSBasicShapeInsetType; } + String cssText() const final; + bool equals(const CSSBasicShape&) const final; + RefPtr m_top; RefPtr m_right; RefPtr m_bottom; @@ -175,74 +127,50 @@ private: RefPtr m_bottomLeftRadius; }; -class CSSBasicShapeCircle : public CSSBasicShape { +class CSSBasicShapeCircle final : public CSSBasicShape { public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapeCircle); } - - virtual Type type() const override { return CSSBasicShapeCircleType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; + static Ref create() { return adoptRef(*new CSSBasicShapeCircle); } CSSPrimitiveValue* centerX() const { return m_centerX.get(); } CSSPrimitiveValue* centerY() const { return m_centerY.get(); } CSSPrimitiveValue* radius() const { return m_radius.get(); } - void setCenterX(PassRefPtr centerX) { m_centerX = centerX; } - void setCenterY(PassRefPtr centerY) { m_centerY = centerY; } - void setRadius(PassRefPtr radius) { m_radius = radius; } + void setCenterX(Ref&& centerX) { m_centerX = WTFMove(centerX); } + void setCenterY(Ref&& centerY) { m_centerY = WTFMove(centerY); } + void setRadius(Ref&& radius) { m_radius = WTFMove(radius); } private: CSSBasicShapeCircle() { } - RefPtr m_centerX; - RefPtr m_centerY; - RefPtr m_radius; -}; - -class CSSDeprecatedBasicShapeCircle : public CSSBasicShape { -public: - static PassRefPtr create() { return adoptRef(new CSSDeprecatedBasicShapeCircle); } - - CSSPrimitiveValue* centerX() const { return m_centerX.get(); } - CSSPrimitiveValue* centerY() const { return m_centerY.get(); } - CSSPrimitiveValue* radius() const { return m_radius.get(); } - - void setCenterX(PassRefPtr centerX) { m_centerX = centerX; } - void setCenterY(PassRefPtr centerY) { m_centerY = centerY; } - void setRadius(PassRefPtr radius) { m_radius = radius; } - - virtual Type type() const override { return CSSDeprecatedBasicShapeCircleType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; + Type type() const final { return CSSBasicShapeCircleType; } + String cssText() const final; + bool equals(const CSSBasicShape&) const final; -private: - CSSDeprecatedBasicShapeCircle() { } - - RefPtr m_centerY; RefPtr m_centerX; + RefPtr m_centerY; RefPtr m_radius; }; -class CSSDeprecatedBasicShapeEllipse : public CSSBasicShape { +class CSSBasicShapeEllipse final : public CSSBasicShape { public: - static PassRefPtr create() { return adoptRef(new CSSDeprecatedBasicShapeEllipse); } + static Ref create() { return adoptRef(*new CSSBasicShapeEllipse); } CSSPrimitiveValue* centerX() const { return m_centerX.get(); } CSSPrimitiveValue* centerY() const { return m_centerY.get(); } CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } - void setCenterX(PassRefPtr centerX) { m_centerX = centerX; } - void setCenterY(PassRefPtr centerY) { m_centerY = centerY; } - void setRadiusX(PassRefPtr radiusX) { m_radiusX = radiusX; } - void setRadiusY(PassRefPtr radiusY) { m_radiusY = radiusY; } - - virtual Type type() const override { return CSSDeprecatedBasicShapeEllipseType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; + void setCenterX(Ref&& centerX) { m_centerX = WTFMove(centerX); } + void setCenterY(Ref&& centerY) { m_centerY = WTFMove(centerY); } + void setRadiusX(Ref&& radiusX) { m_radiusX = WTFMove(radiusX); } + void setRadiusY(Ref&& radiusY) { m_radiusY = WTFMove(radiusY); } private: - CSSDeprecatedBasicShapeEllipse() { } + CSSBasicShapeEllipse() { } + + Type type() const final { return CSSBasicShapeEllipseType; } + String cssText() const final; + bool equals(const CSSBasicShape&) const final; RefPtr m_centerX; RefPtr m_centerY; @@ -250,64 +178,70 @@ private: RefPtr m_radiusY; }; -class CSSBasicShapeEllipse : public CSSBasicShape { +class CSSBasicShapePolygon final : public CSSBasicShape { public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapeEllipse); } + static Ref create() { return adoptRef(*new CSSBasicShapePolygon); } - CSSPrimitiveValue* centerX() const { return m_centerX.get(); } - CSSPrimitiveValue* centerY() const { return m_centerY.get(); } - CSSPrimitiveValue* radiusX() const { return m_radiusX.get(); } - CSSPrimitiveValue* radiusY() const { return m_radiusY.get(); } + void appendPoint(Ref&& x, Ref&& y) + { + m_values.append(WTFMove(x)); + m_values.append(WTFMove(y)); + } - void setCenterX(PassRefPtr centerX) { m_centerX = centerX; } - void setCenterY(PassRefPtr centerY) { m_centerY = centerY; } - void setRadiusX(PassRefPtr radiusX) { m_radiusX = radiusX; } - void setRadiusY(PassRefPtr radiusY) { m_radiusY = radiusY; } + const Vector>& values() const { return m_values; } - virtual Type type() const override { return CSSBasicShapeEllipseType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; + void setWindRule(WindRule rule) { m_windRule = rule; } + WindRule windRule() const { return m_windRule; } private: - CSSBasicShapeEllipse() { } + CSSBasicShapePolygon() + : m_windRule(RULE_NONZERO) + { + } - RefPtr m_centerX; - RefPtr m_centerY; - RefPtr m_radiusX; - RefPtr m_radiusY; + Type type() const final { return CSSBasicShapePolygonType; } + String cssText() const final; + bool equals(const CSSBasicShape&) const final; + + Vector> m_values; + WindRule m_windRule; }; -class CSSBasicShapePolygon : public CSSBasicShape { +class CSSBasicShapePath final : public CSSBasicShape { public: - static PassRefPtr create() { return adoptRef(new CSSBasicShapePolygon); } - - void appendPoint(PassRefPtr x, PassRefPtr y) + static Ref create(std::unique_ptr&& pathData) { - m_values.append(x); - m_values.append(y); + return adoptRef(*new CSSBasicShapePath(WTFMove(pathData))); } - PassRefPtr getXAt(unsigned i) const { return m_values.at(i * 2); } - PassRefPtr getYAt(unsigned i) const { return m_values.at(i * 2 + 1); } - const Vector>& values() const { return m_values; } + const SVGPathByteStream& pathData() const + { + return *m_byteStream; + } - void setWindRule(WindRule w) { m_windRule = w; } + void setWindRule(WindRule rule) { m_windRule = rule; } WindRule windRule() const { return m_windRule; } - virtual Type type() const override { return CSSBasicShapePolygonType; } - virtual String cssText() const override; - virtual bool equals(const CSSBasicShape&) const override; - private: - CSSBasicShapePolygon() - : m_windRule(RULE_NONZERO) - { - } + CSSBasicShapePath(std::unique_ptr&&); - Vector> m_values; - WindRule m_windRule; + Type type() const final { return CSSBasicShapePathType; } + String cssText() const final; + bool equals(const CSSBasicShape&) const final; + + std::unique_ptr m_byteStream; + WindRule m_windRule { RULE_NONZERO }; }; } // namespace WebCore -#endif // CSSBasicShapes_h +#define SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(ToValueTypeName) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ + static bool isType(const WebCore::CSSBasicShape& basicShape) { return basicShape.type() == WebCore::CSSBasicShape::ToValueTypeName##Type; } \ +SPECIALIZE_TYPE_TRAITS_END() + +SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapeInset) +SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapeCircle) +SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapeEllipse) +SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapePolygon) +SPECIALIZE_TYPE_TRAITS_CSS_BASIC_SHAPES(CSSBasicShapePath) diff --git a/Source/WebCore/css/CSSBorderImage.cpp b/Source/WebCore/css/CSSBorderImage.cpp index ac3e51ef1..e06dec870 100644 --- a/Source/WebCore/css/CSSBorderImage.cpp +++ b/Source/WebCore/css/CSSBorderImage.cpp @@ -20,32 +20,33 @@ #include "config.h" #include "CSSBorderImage.h" +#include "CSSValueList.h" + namespace WebCore { -PassRefPtr createBorderImageValue(PassRefPtr image, PassRefPtr imageSlice, PassRefPtr borderSlice, - PassRefPtr outset, PassRefPtr repeat) +Ref createBorderImageValue(RefPtr&& image, RefPtr&& imageSlice, RefPtr&& borderSlice, RefPtr&& outset, RefPtr&& repeat) { - RefPtr list = CSSValueList::createSpaceSeparated(); + auto list = CSSValueList::createSpaceSeparated(); if (image) - list->append(image); + list.get().append(*image); if (borderSlice || outset) { - RefPtr listSlash = CSSValueList::createSlashSeparated(); + auto listSlash = CSSValueList::createSlashSeparated(); if (imageSlice) - listSlash->append(imageSlice); + listSlash.get().append(imageSlice.releaseNonNull()); if (borderSlice) - listSlash->append(borderSlice); + listSlash.get().append(borderSlice.releaseNonNull()); if (outset) - listSlash->append(outset); + listSlash.get().append(outset.releaseNonNull()); - list->append(listSlash); + list.get().append(WTFMove(listSlash)); } else if (imageSlice) - list->append(imageSlice); + list.get().append(imageSlice.releaseNonNull()); if (repeat) - list->append(repeat); - return list.release(); + list.get().append(repeat.releaseNonNull()); + return list; } } // namespace WebCore diff --git a/Source/WebCore/css/CSSBorderImage.h b/Source/WebCore/css/CSSBorderImage.h index b0769f31d..45357abb8 100644 --- a/Source/WebCore/css/CSSBorderImage.h +++ b/Source/WebCore/css/CSSBorderImage.h @@ -17,19 +17,15 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSBorderImage_h -#define CSSBorderImage_h +#pragma once -#include "CSSBorderImageSliceValue.h" -#include "CSSValueList.h" -#include #include namespace WebCore { -PassRefPtr createBorderImageValue(PassRefPtr image, PassRefPtr imageSlice, PassRefPtr borderSlice, - PassRefPtr outset, PassRefPtr repeat); +class CSSValue; +class CSSValueList; -} // namespace WebCore +Ref createBorderImageValue(RefPtr&& image, RefPtr&& imageSlice, RefPtr&& borderSlice, RefPtr&& outset, RefPtr&& repeat); -#endif // CSSBorderImage_h +} // namespace WebCore diff --git a/Source/WebCore/css/CSSBorderImageSliceValue.cpp b/Source/WebCore/css/CSSBorderImageSliceValue.cpp index 6c19204f5..343ea9367 100644 --- a/Source/WebCore/css/CSSBorderImageSliceValue.cpp +++ b/Source/WebCore/css/CSSBorderImageSliceValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,9 +31,9 @@ namespace WebCore { -CSSBorderImageSliceValue::CSSBorderImageSliceValue(PassRefPtr slices, bool fill) +CSSBorderImageSliceValue::CSSBorderImageSliceValue(RefPtr&& slices, bool fill) : CSSValue(BorderImageSliceClass) - , m_slices(slices) + , m_slices(WTFMove(slices)) , m_fill(fill) { } diff --git a/Source/WebCore/css/CSSBorderImageSliceValue.h b/Source/WebCore/css/CSSBorderImageSliceValue.h index 7c0bdad71..2402f2c78 100644 --- a/Source/WebCore/css/CSSBorderImageSliceValue.h +++ b/Source/WebCore/css/CSSBorderImageSliceValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,27 +23,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSBorderImageSliceValue_h -#define CSSBorderImageSliceValue_h +#pragma once #include "CSSPrimitiveValue.h" -#include #include namespace WebCore { class Rect; -class CSSBorderImageSliceValue : public CSSValue { +class CSSBorderImageSliceValue final : public CSSValue { public: - static PassRef create(PassRefPtr slices, bool fill) + static Ref create(RefPtr&& slices, bool fill) { - return adoptRef(*new CSSBorderImageSliceValue(slices, fill)); + return adoptRef(*new CSSBorderImageSliceValue(WTFMove(slices), fill)); } String customCSSText() const; - Quad* slices() { return m_slices ? m_slices->getQuadValue() : 0; } + Quad* slices() const { return m_slices ? m_slices->quadValue() : nullptr; } bool equals(const CSSBorderImageSliceValue&) const; @@ -53,11 +51,9 @@ public: bool m_fill; private: - CSSBorderImageSliceValue(PassRefPtr slices, bool fill); + CSSBorderImageSliceValue(RefPtr&& slices, bool fill); }; -CSS_VALUE_TYPE_CASTS(CSSBorderImageSliceValue, isBorderImageSliceValue()) - } // namespace WebCore -#endif // CSSBorderImageSliceValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSBorderImageSliceValue, isBorderImageSliceValue()) diff --git a/Source/WebCore/css/CSSCalculationValue.cpp b/Source/WebCore/css/CSSCalculationValue.cpp index 02329cdd4..5976d7f01 100644 --- a/Source/WebCore/css/CSSCalculationValue.cpp +++ b/Source/WebCore/css/CSSCalculationValue.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2011, 2012 Google Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,14 +32,11 @@ #include "config.h" #include "CSSCalculationValue.h" +#include "CSSParser.h" +#include "CSSParserTokenRange.h" #include "CSSPrimitiveValueMappings.h" -#include "CSSValueList.h" -#include "Length.h" #include "StyleResolver.h" - #include -#include -#include #include static const int maxExpressionDepth = 100; @@ -51,14 +49,14 @@ enum ParseState { namespace WebCore { -static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) +static RefPtr createCSS(const CalcExpressionNode&, const RenderStyle&); +static RefPtr createCSS(const Length&, const RenderStyle&); + +static CalculationCategory unitCategory(CSSPrimitiveValue::UnitType type) { switch (type) { case CSSPrimitiveValue::CSS_NUMBER: - case CSSPrimitiveValue::CSS_PARSER_INTEGER: return CalcNumber; - case CSSPrimitiveValue::CSS_PERCENTAGE: - return CalcPercent; case CSSPrimitiveValue::CSS_EMS: case CSSPrimitiveValue::CSS_EXS: case CSSPrimitiveValue::CSS_PX: @@ -69,18 +67,34 @@ static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) case CSSPrimitiveValue::CSS_PC: case CSSPrimitiveValue::CSS_REMS: case CSSPrimitiveValue::CSS_CHS: + case CSSPrimitiveValue::CSS_VW: + case CSSPrimitiveValue::CSS_VH: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VMAX: return CalcLength; + case CSSPrimitiveValue::CSS_PERCENTAGE: + return CalcPercent; + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: + return CalcAngle; + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + return CalcTime; + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + return CalcFrequency; default: return CalcOther; } } -static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) +static bool hasDoubleValue(CSSPrimitiveValue::UnitType type) { switch (type) { case CSSPrimitiveValue::CSS_FR: case CSSPrimitiveValue::CSS_NUMBER: - case CSSPrimitiveValue::CSS_PARSER_INTEGER: case CSSPrimitiveValue::CSS_PERCENTAGE: case CSSPrimitiveValue::CSS_EMS: case CSSPrimitiveValue::CSS_EXS: @@ -95,6 +109,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) case CSSPrimitiveValue::CSS_DEG: case CSSPrimitiveValue::CSS_RAD: case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: case CSSPrimitiveValue::CSS_MS: case CSSPrimitiveValue::CSS_S: case CSSPrimitiveValue::CSS_HZ: @@ -110,6 +125,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) return true; case CSSPrimitiveValue::CSS_UNKNOWN: case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_FONT_FAMILY: case CSSPrimitiveValue::CSS_URI: case CSSPrimitiveValue::CSS_IDENT: case CSSPrimitiveValue::CSS_ATTR: @@ -118,13 +134,10 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) case CSSPrimitiveValue::CSS_RGBCOLOR: case CSSPrimitiveValue::CSS_PAIR: case CSSPrimitiveValue::CSS_UNICODE_RANGE: - case CSSPrimitiveValue::CSS_PARSER_OPERATOR: - case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: - case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: - case CSSPrimitiveValue::CSS_TURN: case CSSPrimitiveValue::CSS_COUNTER_NAME: case CSSPrimitiveValue::CSS_SHAPE: case CSSPrimitiveValue::CSS_QUAD: + case CSSPrimitiveValue::CSS_QUIRKY_EMS: case CSSPrimitiveValue::CSS_CALC: case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: @@ -142,7 +155,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) static String buildCssText(const String& expression) { StringBuilder result; - result.append("calc"); + result.appendLiteral("calc"); bool expressionHasSingleTerm = expression[0] != '('; if (expressionHasSingleTerm) result.append('('); @@ -159,12 +172,12 @@ String CSSCalcValue::customCSSText() const bool CSSCalcValue::equals(const CSSCalcValue& other) const { - return compareCSSValuePtr(m_expression, other.m_expression); + return compareCSSValue(m_expression, other.m_expression); } -double CSSCalcValue::clampToPermittedRange(double value) const +inline double CSSCalcValue::clampToPermittedRange(double value) const { - return m_nonNegative && value < 0 ? 0 : value; + return m_shouldClampToNonNegative && value < 0 ? 0 : value; } double CSSCalcValue::doubleValue() const @@ -172,82 +185,82 @@ double CSSCalcValue::doubleValue() const return clampToPermittedRange(m_expression->doubleValue()); } -double CSSCalcValue::computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const -{ - return clampToPermittedRange(m_expression->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize)); -} - -CSSCalcExpressionNode::~CSSCalcExpressionNode() +double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const { + return clampToPermittedRange(m_expression->computeLengthPx(conversionData)); } -class CSSCalcPrimitiveValue : public CSSCalcExpressionNode { +class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode { WTF_MAKE_FAST_ALLOCATED; public: - - static PassRefPtr create(PassRefPtr value, bool isInteger) + static Ref create(Ref&& value, bool isInteger) { - return adoptRef(new CSSCalcPrimitiveValue(value, isInteger)); + return adoptRef(*new CSSCalcPrimitiveValue(WTFMove(value), isInteger)); } - static PassRefPtr create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger) + static RefPtr create(double value, CSSPrimitiveValue::UnitType type, bool isInteger) { - if (std::isnan(value) || std::isinf(value)) - return 0; + if (!std::isfinite(value)) + return nullptr; return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger)); } - virtual bool isZero() const +private: + bool isZero() const final { - return !m_value->getDoubleValue(); + return !m_value->doubleValue(); } - virtual String customCSSText() const + String customCSSText() const final { return m_value->cssText(); } - virtual PassOwnPtr toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + std::unique_ptr createCalcExpression(const CSSToLengthConversionData& conversionData) const final { - switch (m_category) { + switch (category()) { case CalcNumber: - return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue())); + return std::make_unique(m_value->floatValue()); case CalcLength: - return adoptPtr(new CalcExpressionNumber(m_value->computeLength(style, rootStyle, zoom))); + return std::make_unique(Length(m_value->computeLength(conversionData), WebCore::Fixed)); case CalcPercent: case CalcPercentLength: { - CSSPrimitiveValue* primitiveValue = m_value.get(); - return adoptPtr(new CalcExpressionLength(primitiveValue - ? primitiveValue->convertToLength(style, rootStyle, zoom) - : Length(Undefined))); + return std::make_unique(m_value->convertToLength(conversionData)); } // Only types that could be part of a Length expression can be converted // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length. case CalcPercentNumber: + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); } + ASSERT_NOT_REACHED(); return nullptr; } - virtual double doubleValue() const + double doubleValue() const final { if (hasDoubleValue(primitiveType())) - return m_value->getDoubleValue(); + return m_value->doubleValue(); ASSERT_NOT_REACHED(); return 0; } - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + double computeLengthPx(const CSSToLengthConversionData& conversionData) const final { - switch (m_category) { + switch (category()) { case CalcLength: - return m_value->computeLength(currentStyle, rootStyle, multiplier, computingFontSize); + return m_value->computeLength(conversionData); case CalcPercent: case CalcNumber: - return m_value->getDoubleValue(); + return m_value->doubleValue(); case CalcPercentLength: case CalcPercentNumber: + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); break; @@ -256,31 +269,31 @@ public: return 0; } - virtual bool equals(const CSSCalcExpressionNode& other) const + bool equals(const CSSCalcExpressionNode& other) const final { if (type() != other.type()) return false; - return compareCSSValuePtr(m_value, static_cast(other).m_value); + return compareCSSValue(m_value, static_cast(other).m_value); } - virtual Type type() const { return CssCalcPrimitiveValue; } - virtual CSSPrimitiveValue::UnitTypes primitiveType() const + Type type() const final { return CssCalcPrimitiveValue; } + CSSPrimitiveValue::UnitType primitiveType() const final { - return CSSPrimitiveValue::UnitTypes(m_value->primitiveType()); + return CSSPrimitiveValue::UnitType(m_value->primitiveType()); } private: - explicit CSSCalcPrimitiveValue(PassRefPtr value, bool isInteger) - : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger) - , m_value(value) + explicit CSSCalcPrimitiveValue(Ref&& value, bool isInteger) + : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger) + , m_value(WTFMove(value)) { } - RefPtr m_value; + Ref m_value; }; -static const CalculationCategory addSubtractResult[CalcOther][CalcOther] = { +static const CalculationCategory addSubtractResult[CalcAngle][CalcAngle] = { // CalcNumber CalcLength CalcPercent CalcPercentNumber CalcPercentLength { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcNumber { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcLength @@ -293,14 +306,17 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi { CalculationCategory leftCategory = leftSide.category(); CalculationCategory rightCategory = rightSide.category(); - - if (leftCategory == CalcOther || rightCategory == CalcOther) - return CalcOther; + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); switch (op) { case CalcAdd: case CalcSubtract: - return addSubtractResult[leftCategory][rightCategory]; + if (leftCategory < CalcAngle && rightCategory < CalcAngle) + return addSubtractResult[leftCategory][rightCategory]; + if (leftCategory == rightCategory) + return leftCategory; + return CalcOther; case CalcMultiply: if (leftCategory != CalcNumber && rightCategory != CalcNumber) return CalcOther; @@ -315,57 +331,63 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi return CalcOther; } -static bool isIntegerResult(const CSSCalcExpressionNode* leftSide, const CSSCalcExpressionNode* rightSide, CalcOperator op) +static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide) { // Performs W3C spec's type checking for calc integers. // http://www.w3.org/TR/css3-values/#calc-type-checking - return op != CalcDivide && leftSide->isInteger() && rightSide->isInteger(); + return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger(); } -class CSSCalcBinaryOperation : public CSSCalcExpressionNode { - +class CSSCalcBinaryOperation final : public CSSCalcExpressionNode { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr create(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) + static RefPtr create(CalcOperator op, RefPtr&& leftSide, RefPtr&& rightSide) { - ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther); + if (!leftSide || !rightSide) + return nullptr; - CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op); + ASSERT(leftSide->category() < CalcOther); + ASSERT(rightSide->category() < CalcOther); + auto newCategory = determineCategory(*leftSide, *rightSide, op); if (newCategory == CalcOther) - return 0; - - return adoptRef(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory)); + return nullptr; + return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull())); } - static PassRefPtr createSimplified(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) + static RefPtr createSimplified(CalcOperator op, RefPtr&& leftSide, RefPtr&& rightSide) { - CalculationCategory leftCategory = leftSide->category(); - CalculationCategory rightCategory = rightSide->category(); - ASSERT(leftCategory != CalcOther && rightCategory != CalcOther); + if (!leftSide || !rightSide) + return nullptr; + + auto leftCategory = leftSide->category(); + auto rightCategory = rightSide->category(); + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); - bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op); + bool isInteger = isIntegerResult(op, *leftSide, *rightSide); // Simplify numbers. if (leftCategory == CalcNumber && rightCategory == CalcNumber) { - CSSPrimitiveValue::UnitTypes evaluationType = isInteger ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER; - return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), evaluationType, isInteger); + CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER; + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), evaluationType, isInteger); } // Simplify addition and subtraction between same types. if (op == CalcAdd || op == CalcSubtract) { if (leftCategory == rightSide->category()) { - CSSPrimitiveValue::UnitTypes leftType = leftSide->primitiveType(); + CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType(); if (hasDoubleValue(leftType)) { - CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType(); + CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType(); if (leftType == rightType) - return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), leftType, isInteger); CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType); if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) { - CSSPrimitiveValue::UnitTypes canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory); + CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory); if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) { double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType); double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType); - return CSSCalcPrimitiveValue::create(evaluateOperator(leftValue, rightValue, op), canonicalType, isInteger); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger); } } } @@ -373,52 +395,53 @@ public: } else { // Simplify multiplying or dividing by a number for simplifiable types. ASSERT(op == CalcMultiply || op == CalcDivide); - CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get()); + auto* numberSide = getNumberSide(*leftSide, *rightSide); if (!numberSide) - return create(leftSide, rightSide, op); + return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull()); if (numberSide == leftSide && op == CalcDivide) - return 0; - CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get(); + return nullptr; + auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide; double number = numberSide->doubleValue(); - if (std::isnan(number) || std::isinf(number)) - return 0; + if (!std::isfinite(number)) + return nullptr; if (op == CalcDivide && !number) - return 0; + return nullptr; - CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType(); + auto otherType = otherSide.primitiveType(); if (hasDoubleValue(otherType)) - return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide.doubleValue(), number), otherType, isInteger); } - return create(leftSide, rightSide, op); + return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull()); } - virtual bool isZero() const +private: + bool isZero() const final { return !doubleValue(); } - virtual PassOwnPtr toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + std::unique_ptr createCalcExpression(const CSSToLengthConversionData& conversionData) const final { - OwnPtr left(m_leftSide->toCalcValue(style, rootStyle, zoom)); + auto left = m_leftSide->createCalcExpression(conversionData); if (!left) return nullptr; - OwnPtr right(m_rightSide->toCalcValue(style, rootStyle, zoom)); + auto right = m_rightSide->createCalcExpression(conversionData); if (!right) return nullptr; - return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator)); + return std::make_unique(WTFMove(left), WTFMove(right), m_operator); } - virtual double doubleValue() const + double doubleValue() const final { return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue()); } - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + double computeLengthPx(const CSSToLengthConversionData& conversionData) const final { - const double leftValue = m_leftSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize); - const double rightValue = m_rightSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize); + const double leftValue = m_leftSide->computeLengthPx(conversionData); + const double rightValue = m_rightSide->computeLengthPx(conversionData); return evaluate(leftValue, rightValue); } @@ -436,13 +459,12 @@ public: return result.toString(); } - virtual String customCSSText() const + String customCSSText() const final { return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator); } - - virtual bool equals(const CSSCalcExpressionNode& exp) const + bool equals(const CSSCalcExpressionNode& exp) const final { if (type() != exp.type()) return false; @@ -453,15 +475,13 @@ public: && m_operator == other.m_operator; } - virtual Type type() const { return CssCalcBinaryOperation; } + Type type() const final { return CssCalcBinaryOperation; } - virtual CSSPrimitiveValue::UnitTypes primitiveType() const + CSSPrimitiveValue::UnitType primitiveType() const final { - switch (m_category) { + switch (category()) { case CalcNumber: ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber); - if (m_isInteger) - return CSSPrimitiveValue::CSS_PARSER_INTEGER; return CSSPrimitiveValue::CSS_NUMBER; case CalcLength: case CalcPercent: { @@ -469,11 +489,17 @@ public: return m_rightSide->primitiveType(); if (m_rightSide->category() == CalcNumber) return m_leftSide->primitiveType(); - CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType(); + CSSPrimitiveValue::UnitType leftType = m_leftSide->primitiveType(); if (leftType == m_rightSide->primitiveType()) return leftType; return CSSPrimitiveValue::CSS_UNKNOWN; } + case CalcAngle: + return CSSPrimitiveValue::CSS_DEG; + case CalcTime: + return CSSPrimitiveValue::CSS_MS; + case CalcFrequency: + return CSSPrimitiveValue::CSS_HZ; case CalcPercentLength: case CalcPercentNumber: case CalcOther: @@ -483,30 +509,29 @@ public: return CSSPrimitiveValue::CSS_UNKNOWN; } -private: - CSSCalcBinaryOperation(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op, CalculationCategory category) - : CSSCalcExpressionNode(category, isIntegerResult(leftSide.get(), rightSide.get(), op)) - , m_leftSide(leftSide) - , m_rightSide(rightSide) + CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, Ref&& leftSide, Ref&& rightSide) + : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get())) + , m_leftSide(WTFMove(leftSide)) + , m_rightSide(WTFMove(rightSide)) , m_operator(op) { } - static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode* leftSide, CSSCalcExpressionNode* rightSide) + static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide) { - if (leftSide->category() == CalcNumber) - return leftSide; - if (rightSide->category() == CalcNumber) - return rightSide; - return 0; + if (leftSide.category() == CalcNumber) + return &leftSide; + if (rightSide.category() == CalcNumber) + return &rightSide; + return nullptr; } double evaluate(double leftSide, double rightSide) const { - return evaluateOperator(leftSide, rightSide, m_operator); + return evaluateOperator(m_operator, leftSide, rightSide); } - static double evaluateOperator(double leftValue, double rightValue, CalcOperator op) + static double evaluateOperator(CalcOperator op, double leftValue, double rightValue) { switch (op) { case CalcAdd: @@ -520,6 +545,7 @@ private: return leftValue / rightValue; return std::numeric_limits::quiet_NaN(); } + ASSERT_NOT_REACHED(); return 0; } @@ -528,200 +554,174 @@ private: const CalcOperator m_operator; }; -static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueList* tokens) +static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens) { (*depth)++; + if (tokens.atEnd()) + return NoMoreTokens; if (*depth > maxExpressionDepth) return TooDeep; - if (index >= tokens->size()) - return NoMoreTokens; return OK; } class CSSCalcExpressionNodeParser { public: - PassRefPtr parseCalc(CSSParserValueList* tokens) + RefPtr parseCalc(CSSParserTokenRange tokens) { - unsigned index = 0; Value result; - bool ok = parseValueExpression(tokens, 0, &index, &result); - ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size()); - if (!ok || index != tokens->size()) - return 0; + tokens.consumeWhitespace(); + bool ok = parseValueExpression(tokens, 0, &result); + if (!ok || !tokens.atEnd()) + return nullptr; return result.value; } - + private: struct Value { RefPtr value; }; - - char operatorValue(CSSParserValueList* tokens, unsigned index) + + char operatorValue(const CSSParserToken& token) { - if (index >= tokens->size()) - return 0; - CSSParserValue* value = tokens->valueAt(index); - if (value->unit != CSSParserValue::Operator) - return 0; - - return value->iValue; + if (token.type() == DelimiterToken) + return token.delimiter(); + return 0; } - - bool parseValue(CSSParserValueList* tokens, unsigned* index, Value* result) + + bool parseValue(CSSParserTokenRange& tokens, Value* result) { - CSSParserValue* parserValue = tokens->valueAt(*index); - if (parserValue->unit == CSSParserValue::Operator || parserValue->unit == CSSParserValue::Function) + CSSParserToken token = tokens.consumeIncludingWhitespace(); + if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken)) return false; - - RefPtr value = parserValue->createCSSValue(); - if (!value || !value->isPrimitiveValue()) + + CSSPrimitiveValue::UnitType type = token.unitType(); + if (unitCategory(type) == CalcOther) return false; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get()); - result->value = CSSCalcPrimitiveValue::create(primitiveValue, parserValue->isInt); - - ++*index; + + bool isInteger = token.numericValueType() == IntegerValueType || (token.numericValueType() == NumberValueType && token.numericValue() == trunc(token.numericValue())); + result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), isInteger); + return true; } - - bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (operatorValue(tokens, *index) == '(') { - unsigned currentIndex = *index + 1; - if (!parseValueExpression(tokens, depth, ¤tIndex, result)) - return false; - - if (operatorValue(tokens, currentIndex) != ')') - return false; - *index = currentIndex + 1; - return true; + + if (tokens.peek().type() == LeftParenthesisToken || tokens.peek().functionId() == CSSValueCalc) { + CSSParserTokenRange innerRange = tokens.consumeBlock(); + tokens.consumeWhitespace(); + innerRange.consumeWhitespace(); + return parseValueExpression(innerRange, depth, result); } - - return parseValue(tokens, index, result); + + return parseValue(tokens, result); } - - bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (!parseValueTerm(tokens, depth, index, result)) + + if (!parseValueTerm(tokens, depth, result)) return false; - - while (*index < tokens->size() - 1) { - char operatorCharacter = operatorValue(tokens, *index); + + while (!tokens.atEnd()) { + char operatorCharacter = operatorValue(tokens.peek()); if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide) break; - ++*index; - + tokens.consumeIncludingWhitespace(); + Value rhs; - if (!parseValueTerm(tokens, depth, index, &rhs)) + if (!parseValueTerm(tokens, depth, &rhs)) return false; + + result->value = CSSCalcBinaryOperation::createSimplified(static_cast(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value)); - result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast(operatorCharacter)); if (!result->value) return false; } - - ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size()); + return true; } - - bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (!parseValueMultiplicativeExpression(tokens, depth, index, result)) + + if (!parseValueMultiplicativeExpression(tokens, depth, result)) return false; - - while (*index < tokens->size() - 1) { - char operatorCharacter = operatorValue(tokens, *index); + + while (!tokens.atEnd()) { + char operatorCharacter = operatorValue(tokens.peek()); if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract) break; - ++*index; - + if ((&tokens.peek() - 1)->type() != WhitespaceToken) + return false; // calc(1px+ 2px) is invalid + tokens.consume(); + if (tokens.peek().type() != WhitespaceToken) + return false; // calc(1px +2px) is invalid + tokens.consumeIncludingWhitespace(); + Value rhs; - if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs)) + if (!parseValueMultiplicativeExpression(tokens, depth, &rhs)) return false; - - result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast(operatorCharacter)); + + result->value = CSSCalcBinaryOperation::createSimplified(static_cast(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value)); if (!result->value) return false; } - - ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size()); + return true; } - - bool parseValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - return parseAdditiveValueExpression(tokens, depth, index, result); + return parseAdditiveValueExpression(tokens, depth, result); } }; -PassRefPtr CSSCalcValue::createExpressionNode(PassRefPtr value, bool isInteger) +static inline RefPtr createBlendHalf(const Length& length, const RenderStyle& style, float progress) { - return CSSCalcPrimitiveValue::create(value, isInteger); + return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style), + CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1)); } -PassRefPtr CSSCalcValue::createExpressionNode(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) +static RefPtr createCSS(const CalcExpressionNode& node, const RenderStyle& style) { - return CSSCalcBinaryOperation::create(leftSide, rightSide, op); -} - -PassRefPtr CSSCalcValue::createExpressionNode(const CalcExpressionNode* node, const RenderStyle* style) -{ - switch (node->type()) { + switch (node.type()) { case CalcExpressionNodeNumber: { - float value = toCalcExpressionNumber(node)->value(); - return createExpressionNode(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == trunc(value)); + float value = toCalcExpressionNumber(node).value(); + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == std::trunc(value)); } case CalcExpressionNodeLength: - return createExpressionNode(toCalcExpressionLength(node)->length(), style); + return createCSS(toCalcExpressionLength(node).length(), style); case CalcExpressionNodeBinaryOperation: { - const CalcExpressionBinaryOperation* binaryNode = toCalcExpressionBinaryOperation(node); - return createExpressionNode(createExpressionNode(binaryNode->leftSide(), style), createExpressionNode(binaryNode->rightSide(), style), binaryNode->getOperator()); + auto& binaryNode = toCalcExpressionBinaryOperation(node); + return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style)); } case CalcExpressionNodeBlendLength: { // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength. - const CalcExpressionBlendLength* blendNode = toCalcExpressionBlendLength(node); - const double progress = blendNode->progress(); - const bool isInteger = !progress || (progress == 1); - return createExpressionNode( - createExpressionNode( - createExpressionNode(blendNode->from(), style), - createExpressionNode(CSSPrimitiveValue::create(1 - progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), - CalcMultiply), - createExpressionNode( - createExpressionNode(blendNode->to(), style), - createExpressionNode(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), - CalcMultiply), - CalcAdd); + auto& blend = toCalcExpressionBlendLength(node); + float progress = blend.progress(); + return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress)); } case CalcExpressionNodeUndefined: ASSERT_NOT_REACHED(); - return 0; } - ASSERT_NOT_REACHED(); - return 0; + return nullptr; } -PassRefPtr CSSCalcValue::createExpressionNode(const Length& length, const RenderStyle* style) +static RefPtr createCSS(const Length& length, const RenderStyle& style) { switch (length.type()) { case Percent: - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: case Fixed: - return createExpressionNode(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); case Calculated: - return createExpressionNode(length.calculationValue()->expression(), style); + return createCSS(length.calculationValue().expression(), style); case Auto: case Intrinsic: case MinIntrinsic: @@ -732,27 +732,25 @@ PassRefPtr CSSCalcValue::createExpressionNode(const Lengt case Relative: case Undefined: ASSERT_NOT_REACHED(); - return 0; } - ASSERT_NOT_REACHED(); - return 0; + return nullptr; } -PassRefPtr CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range) +RefPtr CSSCalcValue::create(const CSSParserTokenRange& tokens, ValueRange range) { CSSCalcExpressionNodeParser parser; - RefPtr expression; - - if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc(")) - expression = parser.parseCalc(parserValueList); - // FIXME: calc (http://webkit.org/b/16662) Add parsing for min and max here - - return expression ? adoptRef(new CSSCalcValue(expression, range)) : 0; + auto expression = parser.parseCalc(tokens); + if (!expression) + return nullptr; + return adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != ValueRangeAll)); } - -PassRef CSSCalcValue::create(PassRefPtr expression, CalculationPermittedValueRange range) + +RefPtr CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style) { - return adoptRef(*new CSSCalcValue(expression, range)); + auto expression = createCSS(value.expression(), style); + if (!expression) + return nullptr; + return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative())); } } // namespace WebCore diff --git a/Source/WebCore/css/CSSCalculationValue.h b/Source/WebCore/css/CSSCalculationValue.h index e68a6e589..23f9fddba 100644 --- a/Source/WebCore/css/CSSCalculationValue.h +++ b/Source/WebCore/css/CSSCalculationValue.h @@ -28,25 +28,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSCalculationValue_h -#define CSSCalculationValue_h +#pragma once -#include "CSSParserValues.h" #include "CSSPrimitiveValue.h" -#include "CSSValue.h" #include "CalculationValue.h" -#include -#include -#include namespace WebCore { -class CSSParserValueList; -class CSSValueList; -class CalculationValue; -class CalcExpressionNode; +class CSSParserTokenRange; +class CSSToLengthConversionData; class RenderStyle; -struct Length; enum CalculationCategory { CalcNumber = 0, @@ -54,6 +45,9 @@ enum CalculationCategory { CalcPercent, CalcPercentNumber, CalcPercentLength, + CalcAngle, + CalcTime, + CalcFrequency, CalcOther }; @@ -64,17 +58,17 @@ public: CssCalcBinaryOperation }; - virtual ~CSSCalcExpressionNode() = 0; + virtual ~CSSCalcExpressionNode() { } virtual bool isZero() const = 0; - virtual PassOwnPtr toCalcValue(const RenderStyle*, const RenderStyle* rootStyle, double zoom = 1.0) const = 0; + virtual std::unique_ptr createCalcExpression(const CSSToLengthConversionData&) const = 0; virtual double doubleValue() const = 0; - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const = 0; + virtual double computeLengthPx(const CSSToLengthConversionData&) const = 0; virtual String customCSSText() const = 0; virtual bool equals(const CSSCalcExpressionNode& other) const { return m_category == other.m_category && m_isInteger == other.m_isInteger; } virtual Type type() const = 0; + virtual CSSPrimitiveValue::UnitType primitiveType() const = 0; CalculationCategory category() const { return m_category; } - virtual CSSPrimitiveValue::UnitTypes primitiveType() const = 0; bool isInteger() const { return m_isInteger; } protected: @@ -84,58 +78,58 @@ protected: { } +private: CalculationCategory m_category; bool m_isInteger; }; -class CSSCalcValue : public CSSValue { +class CSSCalcValue final : public CSSValue { public: - static PassRefPtr create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange); - static PassRef create(PassRefPtr, CalculationPermittedValueRange = CalculationRangeAll); - static PassRef create(const CalculationValue* value, const RenderStyle* style) { return adoptRef(*new CSSCalcValue(value, style)); } - - static PassRefPtr createExpressionNode(PassRefPtr, bool isInteger = false); - static PassRefPtr createExpressionNode(PassRefPtr, PassRefPtr, CalcOperator); - static PassRefPtr createExpressionNode(const CalcExpressionNode*, const RenderStyle*); - static PassRefPtr createExpressionNode(const Length&, const RenderStyle*); + static RefPtr create(const CSSParserTokenRange&, ValueRange); + + static RefPtr create(const CalculationValue&, const RenderStyle&); - PassRefPtr toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom = 1.0) const - { - return CalculationValue::create(m_expression->toCalcValue(style, rootStyle, zoom), m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll); - } CalculationCategory category() const { return m_expression->category(); } bool isInt() const { return m_expression->isInteger(); } double doubleValue() const; + bool isPositive() const { return m_expression->doubleValue() > 0; } bool isNegative() const { return m_expression->doubleValue() < 0; } - CalculationPermittedValueRange permittedValueRange() { return m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll; } - double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const; - CSSCalcExpressionNode* expressionNode() const { return m_expression.get(); } + double computeLengthPx(const CSSToLengthConversionData&) const; + unsigned short primitiveType() const { return m_expression->primitiveType(); } + + Ref createCalculationValue(const CSSToLengthConversionData&) const; + void setPermittedValueRange(ValueRange); String customCSSText() const; bool equals(const CSSCalcValue&) const; private: - CSSCalcValue(PassRefPtr expression, CalculationPermittedValueRange range) - : CSSValue(CalculationClass) - , m_expression(expression) - , m_nonNegative(range == CalculationRangeNonNegative) - { - } - CSSCalcValue(const CalculationValue* value, const RenderStyle* style) - : CSSValue(CalculationClass) - , m_expression(createExpressionNode(value->expression(), style)) - , m_nonNegative(value->isNonNegative()) - { - } + CSSCalcValue(Ref&&, bool shouldClampToNonNegative); double clampToPermittedRange(double) const; - const RefPtr m_expression; - const bool m_nonNegative; + const Ref m_expression; + bool m_shouldClampToNonNegative; }; -CSS_VALUE_TYPE_CASTS(CSSCalcValue, isCalcValue()) +inline CSSCalcValue::CSSCalcValue(Ref&& expression, bool shouldClampToNonNegative) + : CSSValue(CalculationClass) + , m_expression(WTFMove(expression)) + , m_shouldClampToNonNegative(shouldClampToNonNegative) +{ +} + +inline Ref CSSCalcValue::createCalculationValue(const CSSToLengthConversionData& conversionData) const +{ + return CalculationValue::create(m_expression->createCalcExpression(conversionData), + m_shouldClampToNonNegative ? ValueRangeNonNegative : ValueRangeAll); +} + +inline void CSSCalcValue::setPermittedValueRange(ValueRange range) +{ + m_shouldClampToNonNegative = range != ValueRangeAll; +} } // namespace WebCore -#endif // CSSCalculationValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCalcValue, isCalcValue()) diff --git a/Source/WebCore/css/CSSCanvasValue.cpp b/Source/WebCore/css/CSSCanvasValue.cpp index c965f2ed4..4b2019313 100644 --- a/Source/WebCore/css/CSSCanvasValue.cpp +++ b/Source/WebCore/css/CSSCanvasValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,7 +28,6 @@ #include "ImageBuffer.h" #include "RenderElement.h" -#include namespace WebCore { @@ -40,11 +39,7 @@ CSSCanvasValue::~CSSCanvasValue() String CSSCanvasValue::customCSSText() const { - StringBuilder result; - result.appendLiteral("-webkit-canvas("); - result.append(m_name); - result.append(')'); - return result.toString(); + return makeString("-webkit-canvas(", m_name, ')'); } void CSSCanvasValue::canvasChanged(HTMLCanvasElement&, const FloatRect& changedRect) @@ -66,11 +61,11 @@ void CSSCanvasValue::canvasDestroyed(HTMLCanvasElement& element) m_element = nullptr; } -IntSize CSSCanvasValue::fixedSize(const RenderElement* renderer) +FloatSize CSSCanvasValue::fixedSize(const RenderElement* renderer) { if (HTMLCanvasElement* elt = element(renderer->document())) - return IntSize(elt->width(), elt->height()); - return IntSize(); + return FloatSize(elt->width(), elt->height()); + return FloatSize(); } HTMLCanvasElement* CSSCanvasValue::element(Document& document) @@ -84,12 +79,12 @@ HTMLCanvasElement* CSSCanvasValue::element(Document& document) return m_element; } -PassRefPtr CSSCanvasValue::image(RenderElement* renderer, const IntSize& /*size*/) +RefPtr CSSCanvasValue::image(RenderElement* renderer, const FloatSize& /*size*/) { ASSERT(clients().contains(renderer)); HTMLCanvasElement* element = this->element(renderer->document()); if (!element || !element->buffer()) - return 0; + return nullptr; return element->copiedImage(); } diff --git a/Source/WebCore/css/CSSCanvasValue.h b/Source/WebCore/css/CSSCanvasValue.h index 3aaf6ae72..5c422ce4a 100644 --- a/Source/WebCore/css/CSSCanvasValue.h +++ b/Source/WebCore/css/CSSCanvasValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSCanvasValue_h -#define CSSCanvasValue_h +#pragma once #include "CSSImageGeneratorValue.h" #include "HTMLCanvasElement.h" @@ -32,20 +31,21 @@ namespace WebCore { class Document; +class HTMLCanvasElement; -class CSSCanvasValue : public CSSImageGeneratorValue { +class CSSCanvasValue final : public CSSImageGeneratorValue { public: - static PassRef create(const String& name) { return adoptRef(*new CSSCanvasValue(name)); } + static Ref create(const String& name) { return adoptRef(*new CSSCanvasValue(name)); } ~CSSCanvasValue(); String customCSSText() const; - PassRefPtr image(RenderElement*, const IntSize&); + RefPtr image(RenderElement*, const FloatSize&); bool isFixedSize() const { return true; } - IntSize fixedSize(const RenderElement*); + FloatSize fixedSize(const RenderElement*); bool isPending() const { return false; } - void loadSubimages(CachedResourceLoader*) { } + void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&) { } bool equals(const CSSCanvasValue&) const; @@ -54,7 +54,6 @@ private: : CSSImageGeneratorValue(CanvasClass) , m_canvasObserver(*this) , m_name(name) - , m_element(0) { } @@ -72,15 +71,15 @@ private: } private: - virtual void canvasChanged(HTMLCanvasElement& canvas, const FloatRect& changedRect) override + void canvasChanged(HTMLCanvasElement& canvas, const FloatRect& changedRect) final { m_ownerValue.canvasChanged(canvas, changedRect); } - virtual void canvasResized(HTMLCanvasElement& canvas) override + void canvasResized(HTMLCanvasElement& canvas) final { m_ownerValue.canvasResized(canvas); } - virtual void canvasDestroyed(HTMLCanvasElement& canvas) override + void canvasDestroyed(HTMLCanvasElement& canvas) final { m_ownerValue.canvasDestroyed(canvas); } @@ -99,11 +98,10 @@ private: // The name of the canvas. String m_name; // The document supplies the element and owns it. - HTMLCanvasElement* m_element; + HTMLCanvasElement* m_element { nullptr }; }; -CSS_VALUE_TYPE_CASTS(CSSCanvasValue, isCanvasValue()) - } // namespace WebCore -#endif // CSSCanvasValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCanvasValue, isCanvasValue()) + diff --git a/Source/WebCore/css/CSSCharsetRule.cpp b/Source/WebCore/css/CSSCharsetRule.cpp deleted file mode 100644 index 7bb2a4170..000000000 --- a/Source/WebCore/css/CSSCharsetRule.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2006, 2008, 2012 Apple Inc. All rights reserved. - * Copyright (C) 2006 Alexey Proskuryakov (ap@macrules.ru) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "CSSCharsetRule.h" - -namespace WebCore { - -CSSCharsetRule::CSSCharsetRule(CSSStyleSheet* parent, const String& encoding) - : CSSRule(parent) - , m_encoding(encoding) -{ -} - -String CSSCharsetRule::cssText() const -{ - return "@charset \"" + m_encoding + "\";"; -} - -} // namespace WebCore diff --git a/Source/WebCore/css/CSSCharsetRule.h b/Source/WebCore/css/CSSCharsetRule.h deleted file mode 100644 index 86ea3f3c9..000000000 --- a/Source/WebCore/css/CSSCharsetRule.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2006, 2008, 2012 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef CSSCharsetRule_h -#define CSSCharsetRule_h - -#include "CSSRule.h" - -namespace WebCore { - -class CSSCharsetRule : public CSSRule { -public: - static PassRefPtr create(CSSStyleSheet* parent, const String& encoding) - { - return adoptRef(new CSSCharsetRule(parent, encoding)); - } - - virtual ~CSSCharsetRule() { } - - virtual CSSRule::Type type() const override { return CHARSET_RULE; } - virtual String cssText() const override; - virtual void reattach(StyleRuleBase* rule) override { ASSERT_UNUSED(rule, !rule); } - - const String& encoding() const { return m_encoding; } - void setEncoding(const String& encoding, ExceptionCode&) { m_encoding = encoding; } - -private: - CSSCharsetRule(CSSStyleSheet* parent, const String& encoding); - - String m_encoding; -}; - -} // namespace WebCore - -#endif // CSSCharsetRule_h diff --git a/Source/WebCore/css/CSSCharsetRule.idl b/Source/WebCore/css/CSSCharsetRule.idl deleted file mode 100644 index 9d5071e7c..000000000 --- a/Source/WebCore/css/CSSCharsetRule.idl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -// Introduced in DOM Level 2: -interface CSSCharsetRule : CSSRule { -#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C - [TreatReturnedNullStringAs=Null] readonly attribute DOMString encoding; -#else - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString encoding; -#endif -}; - diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp index d2e055423..392072c5f 100644 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Zack Rusin - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov * Copyright (C) 2007 Nicholas Shanks * Copyright (C) 2011 Sencha, Inc. All rights reserved. @@ -25,66 +25,90 @@ #include "config.h" #include "CSSComputedStyleDeclaration.h" -#include "AnimationController.h" #include "BasicShapeFunctions.h" #include "BasicShapes.h" +#include "CSSAnimationController.h" +#include "CSSAnimationTriggerScrollValue.h" #include "CSSAspectRatioValue.h" #include "CSSBasicShapes.h" #include "CSSBorderImage.h" +#include "CSSBorderImageSliceValue.h" +#include "CSSCustomPropertyValue.h" #include "CSSFontFeatureValue.h" #include "CSSFontValue.h" +#include "CSSFontVariationValue.h" #include "CSSFunctionValue.h" -#include "CSSGridTemplateValue.h" #include "CSSLineBoxContainValue.h" -#include "CSSParser.h" #include "CSSPrimitiveValue.h" #include "CSSPrimitiveValueMappings.h" #include "CSSPropertyNames.h" +#include "CSSPropertyParser.h" #include "CSSReflectValue.h" #include "CSSSelector.h" #include "CSSShadowValue.h" #include "CSSTimingFunctionValue.h" #include "CSSValueList.h" #include "CSSValuePool.h" +#include "ComposedTreeAncestorIterator.h" #include "ContentData.h" #include "CounterContent.h" #include "CursorList.h" +#include "DeprecatedCSSOMValue.h" #include "Document.h" #include "ExceptionCode.h" -#include "FontFeatureSettings.h" +#include "FontTaggedSettings.h" #include "HTMLFrameOwnerElement.h" +#include "NodeRenderStyle.h" #include "Pair.h" #include "PseudoElement.h" #include "Rect.h" +#include "RenderBlock.h" #include "RenderBox.h" #include "RenderStyle.h" -#include "RenderView.h" +#include "RuntimeEnabledFeatures.h" #include "SVGElement.h" +#include "Settings.h" +#include "ShapeValue.h" #include "StyleInheritedData.h" #include "StyleProperties.h" #include "StylePropertyShorthand.h" +#include "StylePropertyShorthandFunctions.h" #include "StyleResolver.h" -#include "WebKitCSSTransformValue.h" +#include "StyleScope.h" +#include "StyleScrollSnapPoints.h" +#include "Text.h" #include "WebKitFontFamilyNames.h" +#include "WillChangeData.h" +#include #include -#if ENABLE(CSS_SHAPES) -#include "ShapeValue.h" -#endif - -#if ENABLE(CSS_FILTERS) -#include "WebKitCSSFilterValue.h" -#endif +#include "CSSGridLineNamesValue.h" +#include "CSSGridTemplateAreasValue.h" +#include "RenderGrid.h" #if ENABLE(DASHBOARD_SUPPORT) #include "DashboardRegion.h" #endif +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) +#include "AnimationTrigger.h" +#endif + namespace WebCore { // List of all properties we know how to compute, omitting shorthands. static const CSSPropertyID computedProperties[] = { + CSSPropertyAlt, + CSSPropertyAnimationDelay, + CSSPropertyAnimationDirection, + CSSPropertyAnimationDuration, + CSSPropertyAnimationFillMode, + CSSPropertyAnimationIterationCount, + CSSPropertyAnimationName, + CSSPropertyAnimationPlayState, + CSSPropertyAnimationTimingFunction, CSSPropertyBackgroundAttachment, + CSSPropertyBackgroundBlendMode, CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundImage, @@ -121,6 +145,9 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyClear, CSSPropertyClip, CSSPropertyColor, + CSSPropertyCounterIncrement, + CSSPropertyCounterReset, + CSSPropertyContent, CSSPropertyCursor, CSSPropertyDirection, CSSPropertyDisplay, @@ -129,8 +156,10 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyFontFamily, CSSPropertyFontSize, CSSPropertyFontStyle, + CSSPropertyFontSynthesis, CSSPropertyFontVariant, CSSPropertyFontWeight, + CSSPropertyHangingPunctuation, CSSPropertyHeight, #if ENABLE(CSS_IMAGE_ORIENTATION) CSSPropertyImageOrientation, @@ -153,6 +182,8 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyMaxWidth, CSSPropertyMinHeight, CSSPropertyMinWidth, + CSSPropertyObjectFit, + CSSPropertyObjectPosition, CSSPropertyOpacity, CSSPropertyOrphans, CSSPropertyOutlineColor, @@ -193,6 +224,9 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyTextOverflow, CSSPropertyTextTransform, CSSPropertyTop, + CSSPropertyTransform, + CSSPropertyTransformOrigin, + CSSPropertyTransformStyle, CSSPropertyTransitionDelay, CSSPropertyTransitionDuration, CSSPropertyTransitionProperty, @@ -203,30 +237,38 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyWhiteSpace, CSSPropertyWidows, CSSPropertyWidth, + CSSPropertyWillChange, CSSPropertyWordBreak, CSSPropertyWordSpacing, CSSPropertyWordWrap, +#if ENABLE(CSS_SCROLL_SNAP) + CSSPropertyScrollSnapMargin, + CSSPropertyScrollSnapMarginLeft, + CSSPropertyScrollSnapMarginTop, + CSSPropertyScrollSnapMarginRight, + CSSPropertyScrollSnapMarginBottom, + CSSPropertyScrollPadding, + CSSPropertyScrollPaddingLeft, + CSSPropertyScrollPaddingTop, + CSSPropertyScrollPaddingRight, + CSSPropertyScrollPaddingBottom, + CSSPropertyScrollSnapType, + CSSPropertyScrollSnapAlign, +#endif CSSPropertyZIndex, CSSPropertyZoom, - - CSSPropertyWebkitAlt, - CSSPropertyWebkitAnimationDelay, - CSSPropertyWebkitAnimationDirection, - CSSPropertyWebkitAnimationDuration, - CSSPropertyWebkitAnimationFillMode, - CSSPropertyWebkitAnimationIterationCount, - CSSPropertyWebkitAnimationName, - CSSPropertyWebkitAnimationPlayState, - CSSPropertyWebkitAnimationTimingFunction, +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + CSSPropertyWebkitAnimationTrigger, +#endif CSSPropertyWebkitAppearance, CSSPropertyWebkitBackfaceVisibility, - CSSPropertyWebkitBackgroundBlendMode, CSSPropertyWebkitBackgroundClip, CSSPropertyWebkitBackgroundComposite, CSSPropertyWebkitBackgroundOrigin, CSSPropertyWebkitBackgroundSize, #if ENABLE(CSS_COMPOSITING) - CSSPropertyWebkitBlendMode, + CSSPropertyMixBlendMode, + CSSPropertyIsolation, #endif CSSPropertyWebkitBorderFit, CSSPropertyWebkitBorderHorizontalSpacing, @@ -246,55 +288,70 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyWebkitBoxReflect, CSSPropertyWebkitBoxShadow, CSSPropertyWebkitClipPath, - CSSPropertyWebkitColorCorrection, CSSPropertyWebkitColumnBreakAfter, CSSPropertyWebkitColumnBreakBefore, CSSPropertyWebkitColumnBreakInside, CSSPropertyWebkitColumnAxis, - CSSPropertyWebkitColumnCount, - CSSPropertyWebkitColumnGap, + CSSPropertyColumnCount, + CSSPropertyColumnFill, + CSSPropertyColumnGap, CSSPropertyWebkitColumnProgression, - CSSPropertyWebkitColumnRuleColor, - CSSPropertyWebkitColumnRuleStyle, - CSSPropertyWebkitColumnRuleWidth, - CSSPropertyWebkitColumnSpan, - CSSPropertyWebkitColumnWidth, + CSSPropertyColumnRuleColor, + CSSPropertyColumnRuleStyle, + CSSPropertyColumnRuleWidth, + CSSPropertyColumnSpan, + CSSPropertyColumnWidth, #if ENABLE(CURSOR_VISIBILITY) CSSPropertyWebkitCursorVisibility, #endif #if ENABLE(DASHBOARD_SUPPORT) CSSPropertyWebkitDashboardRegion, #endif -#if ENABLE(CSS_FILTERS) - CSSPropertyWebkitFilter, + CSSPropertyAlignContent, + CSSPropertyAlignItems, + CSSPropertyAlignSelf, + CSSPropertyFilter, + CSSPropertyFlexBasis, + CSSPropertyFlexDirection, + CSSPropertyFlexFlow, + CSSPropertyFlexGrow, + CSSPropertyFlexShrink, + CSSPropertyFlexWrap, + CSSPropertyJustifyContent, + CSSPropertyJustifySelf, + CSSPropertyJustifyItems, +#if ENABLE(FILTERS_LEVEL_2) + CSSPropertyWebkitBackdropFilter, #endif - CSSPropertyWebkitAlignContent, - CSSPropertyWebkitAlignItems, - CSSPropertyWebkitAlignSelf, - CSSPropertyWebkitFlexBasis, - CSSPropertyWebkitFlexGrow, - CSSPropertyWebkitFlexShrink, - CSSPropertyWebkitFlexDirection, - CSSPropertyWebkitFlexWrap, - CSSPropertyWebkitJustifyContent, CSSPropertyWebkitFontKerning, CSSPropertyWebkitFontSmoothing, - CSSPropertyWebkitFontVariantLigatures, - CSSPropertyWebkitGridAutoColumns, - CSSPropertyWebkitGridAutoFlow, - CSSPropertyWebkitGridAutoRows, - CSSPropertyWebkitGridColumnEnd, - CSSPropertyWebkitGridColumnStart, - CSSPropertyWebkitGridDefinitionColumns, - CSSPropertyWebkitGridDefinitionRows, - CSSPropertyWebkitGridRowEnd, - CSSPropertyWebkitGridRowStart, - CSSPropertyWebkitHighlight, + CSSPropertyFontVariantLigatures, + CSSPropertyFontVariantPosition, + CSSPropertyFontVariantCaps, + CSSPropertyFontVariantNumeric, + CSSPropertyFontVariantAlternates, + CSSPropertyFontVariantEastAsian, +#if ENABLE(VARIATION_FONTS) + CSSPropertyFontVariationSettings, +#endif + CSSPropertyGridAutoColumns, + CSSPropertyGridAutoFlow, + CSSPropertyGridAutoRows, + CSSPropertyGridColumnEnd, + CSSPropertyGridColumnStart, + CSSPropertyGridTemplateAreas, + CSSPropertyGridTemplateColumns, + CSSPropertyGridTemplateRows, + CSSPropertyGridRowEnd, + CSSPropertyGridRowStart, + CSSPropertyGridColumnGap, + CSSPropertyGridRowGap, CSSPropertyWebkitHyphenateCharacter, CSSPropertyWebkitHyphenateLimitAfter, CSSPropertyWebkitHyphenateLimitBefore, CSSPropertyWebkitHyphenateLimitLines, CSSPropertyWebkitHyphens, + CSSPropertyWebkitInitialLetter, CSSPropertyWebkitLineAlign, CSSPropertyWebkitLineBoxContain, CSSPropertyWebkitLineBreak, @@ -323,25 +380,18 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyWebkitMaskSize, CSSPropertyWebkitMaskSourceType, CSSPropertyWebkitNbspMode, - CSSPropertyWebkitOrder, + CSSPropertyOrder, #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) CSSPropertyWebkitOverflowScrolling, #endif - CSSPropertyWebkitPerspective, - CSSPropertyWebkitPerspectiveOrigin, + CSSPropertyPerspective, + CSSPropertyPerspectiveOrigin, CSSPropertyWebkitPrintColorAdjust, CSSPropertyWebkitRtlOrdering, #if PLATFORM(IOS) CSSPropertyWebkitTouchCallout, - - // FIXME: This property shouldn't be iOS-specific. Once we fix up its usage in InlineTextBox::paintCompositionBackground() - // we should move it outside the PLATFORM(IOS)-guard. See . - CSSPropertyWebkitCompositionFillColor, -#endif -#if ENABLE(CSS_SHAPES) - CSSPropertyWebkitShapeInside, - CSSPropertyWebkitShapeOutside, #endif + CSSPropertyShapeOutside, #if ENABLE(TOUCH_EVENTS) CSSPropertyWebkitTapHighlightColor, #endif @@ -353,22 +403,16 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyWebkitTextFillColor, CSSPropertyWebkitTextOrientation, CSSPropertyWebkitTextSecurity, -#if ENABLE(IOS_TEXT_AUTOSIZING) +#if ENABLE(TEXT_AUTOSIZING) CSSPropertyWebkitTextSizeAdjust, #endif CSSPropertyWebkitTextStrokeColor, CSSPropertyWebkitTextStrokeWidth, - CSSPropertyWebkitTransform, - CSSPropertyWebkitTransformOrigin, + CSSPropertyWebkitTextZoom, CSSPropertyWebkitTransformStyle, - CSSPropertyWebkitTransitionDelay, - CSSPropertyWebkitTransitionDuration, - CSSPropertyWebkitTransitionProperty, - CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitUserDrag, CSSPropertyWebkitUserModify, CSSPropertyWebkitUserSelect, - CSSPropertyWebkitWritingMode, #if ENABLE(CSS_REGIONS) CSSPropertyWebkitFlowInto, CSSPropertyWebkitFlowFrom, @@ -377,20 +421,17 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyWebkitRegionBreakInside, CSSPropertyWebkitRegionFragment, #endif -#if ENABLE(CSS_EXCLUSIONS) - CSSPropertyWebkitWrapFlow, - CSSPropertyWebkitWrapThrough, -#endif -#if ENABLE(CSS_SHAPES) - CSSPropertyWebkitShapeMargin, - CSSPropertyWebkitShapePadding, - CSSPropertyWebkitShapeImageThreshold, -#endif -#if ENABLE(SVG) + CSSPropertyShapeImageThreshold, + CSSPropertyShapeMargin, + CSSPropertyShapeOutside, + CSSPropertyShapeRendering, CSSPropertyBufferedRendering, CSSPropertyClipPath, CSSPropertyClipRule, + CSSPropertyCx, + CSSPropertyCy, CSSPropertyMask, + CSSPropertyMaskType, CSSPropertyFilter, CSSPropertyFloodColor, CSSPropertyFloodOpacity, @@ -406,8 +447,10 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyMarkerEnd, CSSPropertyMarkerMid, CSSPropertyMarkerStart, - CSSPropertyMaskType, - CSSPropertyShapeRendering, + CSSPropertyPaintOrder, + CSSPropertyR, + CSSPropertyRx, + CSSPropertyRy, CSSPropertyStroke, CSSPropertyStrokeDasharray, CSSPropertyStrokeDashoffset, @@ -425,8 +468,9 @@ static const CSSPropertyID computedProperties[] = { CSSPropertyGlyphOrientationHorizontal, CSSPropertyGlyphOrientationVertical, CSSPropertyWebkitSvgShadow, - CSSPropertyVectorEffect -#endif + CSSPropertyVectorEffect, + CSSPropertyX, + CSSPropertyY }; const unsigned numComputedProperties = WTF_ARRAY_LENGTH(computedProperties); @@ -445,71 +489,74 @@ static CSSValueID valueForRepeatRule(int rule) } } -static PassRefPtr valueForNinePieceImageSlice(const NinePieceImage& image) +static Ref valueForImageSliceSide(const Length& length) { - // Create the slices. - RefPtr top; + // These values can be percentages, numbers, or while an animation of mixed types is in progress, + // a calculation that combines a percentage and a number. + if (length.isPercent()) + return CSSValuePool::singleton().createValue(length.percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + if (length.isFixed()) + return CSSValuePool::singleton().createValue(length.value(), CSSPrimitiveValue::CSS_NUMBER); + + // Calculating the actual length currently in use would require most of the code from RenderBoxModelObject::paintNinePieceImage. + // And even if we could do that, it's not clear if that's exactly what we'd want during animation. + // FIXME: For now, just return 0. + ASSERT(length.isCalculated()); + return CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::CSS_NUMBER); +} + +static Ref valueForNinePieceImageSlice(const NinePieceImage& image) +{ + auto& slices = image.imageSlices(); + + RefPtr top = valueForImageSliceSide(slices.top()); + RefPtr right; RefPtr bottom; RefPtr left; - if (image.imageSlices().top().isPercent()) - top = cssValuePool().createValue(image.imageSlices().top().value(), CSSPrimitiveValue::CSS_PERCENTAGE); - else - top = cssValuePool().createValue(image.imageSlices().top().value(), CSSPrimitiveValue::CSS_NUMBER); - - if (image.imageSlices().right() == image.imageSlices().top() && image.imageSlices().bottom() == image.imageSlices().top() - && image.imageSlices().left() == image.imageSlices().top()) { + if (slices.right() == slices.top() && slices.bottom() == slices.top() && slices.left() == slices.top()) { right = top; bottom = top; left = top; } else { - if (image.imageSlices().right().isPercent()) - right = cssValuePool().createValue(image.imageSlices().right().value(), CSSPrimitiveValue::CSS_PERCENTAGE); - else - right = cssValuePool().createValue(image.imageSlices().right().value(), CSSPrimitiveValue::CSS_NUMBER); + right = valueForImageSliceSide(slices.right()); - if (image.imageSlices().bottom() == image.imageSlices().top() && image.imageSlices().right() == image.imageSlices().left()) { + if (slices.bottom() == slices.top() && slices.right() == slices.left()) { bottom = top; left = right; } else { - if (image.imageSlices().bottom().isPercent()) - bottom = cssValuePool().createValue(image.imageSlices().bottom().value(), CSSPrimitiveValue::CSS_PERCENTAGE); - else - bottom = cssValuePool().createValue(image.imageSlices().bottom().value(), CSSPrimitiveValue::CSS_NUMBER); + bottom = valueForImageSliceSide(slices.bottom()); - if (image.imageSlices().left() == image.imageSlices().right()) + if (slices.left() == slices.right()) left = right; - else { - if (image.imageSlices().left().isPercent()) - left = cssValuePool().createValue(image.imageSlices().left().value(), CSSPrimitiveValue::CSS_PERCENTAGE); - else - left = cssValuePool().createValue(image.imageSlices().left().value(), CSSPrimitiveValue::CSS_NUMBER); - } + else + left = valueForImageSliceSide(slices.left()); } } - RefPtr quad = Quad::create(); - quad->setTop(top); - quad->setRight(right); - quad->setBottom(bottom); - quad->setLeft(left); + auto quad = Quad::create(); + quad->setTop(WTFMove(top)); + quad->setRight(WTFMove(right)); + quad->setBottom(WTFMove(bottom)); + quad->setLeft(WTFMove(left)); - return CSSBorderImageSliceValue::create(cssValuePool().createValue(quad.release()), image.fill()); + return CSSBorderImageSliceValue::create(CSSValuePool::singleton().createValue(WTFMove(quad)), image.fill()); } -static PassRefPtr valueForNinePieceImageQuad(const LengthBox& box) +static Ref valueForNinePieceImageQuad(const LengthBox& box) { - // Create the slices. RefPtr top; RefPtr right; RefPtr bottom; RefPtr left; + auto& cssValuePool = CSSValuePool::singleton(); + if (box.top().isRelative()) - top = cssValuePool().createValue(box.top().value(), CSSPrimitiveValue::CSS_NUMBER); + top = cssValuePool.createValue(box.top().value(), CSSPrimitiveValue::CSS_NUMBER); else - top = cssValuePool().createValue(box.top()); + top = cssValuePool.createValue(box.top()); if (box.right() == box.top() && box.bottom() == box.top() && box.left() == box.top()) { right = top; @@ -517,56 +564,55 @@ static PassRefPtr valueForNinePieceImageQuad(const LengthBox& left = top; } else { if (box.right().isRelative()) - right = cssValuePool().createValue(box.right().value(), CSSPrimitiveValue::CSS_NUMBER); + right = cssValuePool.createValue(box.right().value(), CSSPrimitiveValue::CSS_NUMBER); else - right = cssValuePool().createValue(box.right()); + right = cssValuePool.createValue(box.right()); if (box.bottom() == box.top() && box.right() == box.left()) { bottom = top; left = right; } else { if (box.bottom().isRelative()) - bottom = cssValuePool().createValue(box.bottom().value(), CSSPrimitiveValue::CSS_NUMBER); + bottom = cssValuePool.createValue(box.bottom().value(), CSSPrimitiveValue::CSS_NUMBER); else - bottom = cssValuePool().createValue(box.bottom()); + bottom = cssValuePool.createValue(box.bottom()); if (box.left() == box.right()) left = right; else { if (box.left().isRelative()) - left = cssValuePool().createValue(box.left().value(), CSSPrimitiveValue::CSS_NUMBER); + left = cssValuePool.createValue(box.left().value(), CSSPrimitiveValue::CSS_NUMBER); else - left = cssValuePool().createValue(box.left()); + left = cssValuePool.createValue(box.left()); } } } - RefPtr quad = Quad::create(); - quad->setTop(top); - quad->setRight(right); - quad->setBottom(bottom); - quad->setLeft(left); + auto quad = Quad::create(); + quad->setTop(WTFMove(top)); + quad->setRight(WTFMove(right)); + quad->setBottom(WTFMove(bottom)); + quad->setLeft(WTFMove(left)); - return cssValuePool().createValue(quad.release()); + return cssValuePool.createValue(WTFMove(quad)); } -static PassRef valueForNinePieceImageRepeat(const NinePieceImage& image) +static Ref valueForNinePieceImageRepeat(const NinePieceImage& image) { - RefPtr horizontalRepeat; + auto& cssValuePool = CSSValuePool::singleton(); + auto horizontalRepeat = cssValuePool.createIdentifierValue(valueForRepeatRule(image.horizontalRule())); RefPtr verticalRepeat; - - horizontalRepeat = cssValuePool().createIdentifierValue(valueForRepeatRule(image.horizontalRule())); if (image.horizontalRule() == image.verticalRule()) - verticalRepeat = horizontalRepeat; + verticalRepeat = horizontalRepeat.copyRef(); else - verticalRepeat = cssValuePool().createIdentifierValue(valueForRepeatRule(image.verticalRule())); - return cssValuePool().createValue(Pair::create(horizontalRepeat.release(), verticalRepeat.release())); + verticalRepeat = cssValuePool.createIdentifierValue(valueForRepeatRule(image.verticalRule())); + return cssValuePool.createValue(Pair::create(WTFMove(horizontalRepeat), WTFMove(verticalRepeat))); } -static PassRefPtr valueForNinePieceImage(const NinePieceImage& image) +static Ref valueForNinePieceImage(const NinePieceImage& image) { if (!image.hasImage()) - return cssValuePool().createIdentifierValue(CSSValueNone); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); // Image first. RefPtr imageValue; @@ -585,513 +631,864 @@ static PassRefPtr valueForNinePieceImage(const NinePieceImage& image) // Create the repeat rules. RefPtr repeat = valueForNinePieceImageRepeat(image); - return createBorderImageValue(imageValue.release(), imageSlices.release(), borderSlices.release(), outset.release(), repeat.release()); + return createBorderImageValue(WTFMove(imageValue), WTFMove(imageSlices), WTFMove(borderSlices), WTFMove(outset), WTFMove(repeat)); } -inline static PassRef zoomAdjustedPixelValue(double value, const RenderStyle* style) +inline static Ref zoomAdjustedPixelValue(double value, const RenderStyle& style) { - return cssValuePool().createValue(adjustFloatForAbsoluteZoom(value, style), CSSPrimitiveValue::CSS_PX); + return CSSValuePool::singleton().createValue(adjustFloatForAbsoluteZoom(value, style), CSSPrimitiveValue::CSS_PX); } -inline static PassRef zoomAdjustedNumberValue(double value, const RenderStyle* style) +inline static Ref zoomAdjustedNumberValue(double value, const RenderStyle& style) { - return cssValuePool().createValue(value / style->effectiveZoom(), CSSPrimitiveValue::CSS_NUMBER); + return CSSValuePool::singleton().createValue(value / style.effectiveZoom(), CSSPrimitiveValue::CSS_NUMBER); } -static PassRef zoomAdjustedPixelValueForLength(const Length& length, const RenderStyle* style) +static Ref zoomAdjustedPixelValueForLength(const Length& length, const RenderStyle& style) { if (length.isFixed()) return zoomAdjustedPixelValue(length.value(), style); - return cssValuePool().createValue(length); + return CSSValuePool::singleton().createValue(length, style); } -static PassRef valueForReflection(const StyleReflection* reflection, const RenderStyle* style) +static Ref valueForReflection(const StyleReflection* reflection, const RenderStyle& style) { if (!reflection) - return cssValuePool().createIdentifierValue(CSSValueNone); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); RefPtr offset; - if (reflection->offset().isPercent()) - offset = cssValuePool().createValue(reflection->offset().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + if (reflection->offset().isPercentOrCalculated()) + offset = CSSValuePool::singleton().createValue(reflection->offset().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); else offset = zoomAdjustedPixelValue(reflection->offset().value(), style); RefPtr direction; switch (reflection->direction()) { case ReflectionBelow: - direction = cssValuePool().createIdentifierValue(CSSValueBelow); + direction = CSSValuePool::singleton().createIdentifierValue(CSSValueBelow); break; case ReflectionAbove: - direction = cssValuePool().createIdentifierValue(CSSValueAbove); + direction = CSSValuePool::singleton().createIdentifierValue(CSSValueAbove); break; case ReflectionLeft: - direction = cssValuePool().createIdentifierValue(CSSValueLeft); + direction = CSSValuePool::singleton().createIdentifierValue(CSSValueLeft); break; case ReflectionRight: - direction = cssValuePool().createIdentifierValue(CSSValueRight); + direction = CSSValuePool::singleton().createIdentifierValue(CSSValueRight); break; } - return CSSReflectValue::create(direction.release(), offset.release(), valueForNinePieceImage(reflection->mask())); + return CSSReflectValue::create(direction.releaseNonNull(), offset.releaseNonNull(), valueForNinePieceImage(reflection->mask())); } -static PassRef createPositionListForLayer(CSSPropertyID propertyID, const FillLayer* layer, const RenderStyle* style) +static Ref createPositionListForLayer(CSSPropertyID propertyID, const FillLayer& layer, const RenderStyle& style) { - auto positionList = CSSValueList::createSpaceSeparated(); - if (layer->isBackgroundOriginSet()) { + auto list = CSSValueList::createSpaceSeparated(); + if (layer.isBackgroundXOriginSet()) { ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPosition || propertyID == CSSPropertyWebkitMaskPosition); - positionList.get().append(cssValuePool().createValue(layer->backgroundXOrigin())); + list->append(CSSValuePool::singleton().createValue(layer.backgroundXOrigin())); } - positionList.get().append(zoomAdjustedPixelValueForLength(layer->xPosition(), style)); - if (layer->isBackgroundOriginSet()) { + list->append(zoomAdjustedPixelValueForLength(layer.xPosition(), style)); + if (layer.isBackgroundYOriginSet()) { ASSERT(propertyID == CSSPropertyBackgroundPosition || propertyID == CSSPropertyWebkitMaskPosition); - positionList.get().append(cssValuePool().createValue(layer->backgroundYOrigin())); + list->append(CSSValuePool::singleton().createValue(layer.backgroundYOrigin())); } - positionList.get().append(zoomAdjustedPixelValueForLength(layer->yPosition(), style)); - return positionList; + list->append(zoomAdjustedPixelValueForLength(layer.yPosition(), style)); + return list; } -static PassRefPtr getPositionOffsetValue(RenderStyle* style, CSSPropertyID propertyID, RenderView* renderView) +static RefPtr positionOffsetValue(const RenderStyle& style, CSSPropertyID propertyID) { - if (!style) - return 0; - - Length l; + Length length; switch (propertyID) { case CSSPropertyLeft: - l = style->left(); + length = style.left(); break; case CSSPropertyRight: - l = style->right(); + length = style.right(); break; case CSSPropertyTop: - l = style->top(); + length = style.top(); break; case CSSPropertyBottom: - l = style->bottom(); + length = style.bottom(); break; default: - return 0; + return nullptr; } - if (style->hasOutOfFlowPosition()) { - if (l.type() == WebCore::Fixed) - return zoomAdjustedPixelValue(l.value(), style); - else if (l.isViewportPercentage()) - return zoomAdjustedPixelValue(valueForLength(l, 0, renderView), style); - return cssValuePool().createValue(l); + if (style.hasOutOfFlowPosition()) { + if (length.isFixed()) + return zoomAdjustedPixelValue(length.value(), style); + + return CSSValuePool::singleton().createValue(length); } - if (style->hasInFlowPosition()) { + if (style.hasInFlowPosition()) { // FIXME: It's not enough to simply return "auto" values for one offset if the other side is defined. // In other words if left is auto and right is not auto, then left's computed value is negative right(). // So we should get the opposite length unit and see if it is auto. - return cssValuePool().createValue(l); + return CSSValuePool::singleton().createValue(length); } - return cssValuePool().createIdentifierValue(CSSValueAuto); + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); } -PassRefPtr ComputedStyleExtractor::currentColorOrValidColor(RenderStyle* style, const Color& color) const +RefPtr ComputedStyleExtractor::currentColorOrValidColor(const RenderStyle* style, const Color& color) const { // This function does NOT look at visited information, so that computed style doesn't expose that. if (!color.isValid()) - return cssValuePool().createColorValue(style->color().rgb()); - return cssValuePool().createColorValue(color.rgb()); + return CSSValuePool::singleton().createColorValue(style->color()); + return CSSValuePool::singleton().createColorValue(color); +} + +static Ref percentageOrZoomAdjustedValue(Length length, const RenderStyle& style) +{ + if (length.isPercent()) + return CSSValuePool::singleton().createValue(length.percent(), CSSPrimitiveValue::CSS_PERCENTAGE); + + return zoomAdjustedPixelValue(valueForLength(length, 0), style); +} + +static Ref autoOrZoomAdjustedValue(Length length, const RenderStyle& style) +{ + if (length.isAuto()) + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); + + return zoomAdjustedPixelValue(valueForLength(length, 0), style); } -static PassRef getBorderRadiusCornerValues(const LengthSize& radius, const RenderStyle* style, RenderView* renderView) +static Ref borderRadiusCornerValues(const LengthSize& radius, const RenderStyle& style) { auto list = CSSValueList::createSpaceSeparated(); - if (radius.width().type() == Percent) - list.get().append(cssValuePool().createValue(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); - else - list.get().append(zoomAdjustedPixelValue(valueForLength(radius.width(), 0, renderView), style)); - if (radius.height().type() == Percent) - list.get().append(cssValuePool().createValue(radius.height().percent(), CSSPrimitiveValue::CSS_PERCENTAGE)); - else - list.get().append(zoomAdjustedPixelValue(valueForLength(radius.height(), 0, renderView), style)); + list->append(percentageOrZoomAdjustedValue(radius.width, style)); + list->append(percentageOrZoomAdjustedValue(radius.height, style)); return list; } -static PassRef getBorderRadiusCornerValue(const LengthSize& radius, const RenderStyle* style, RenderView* renderView) +static Ref borderRadiusCornerValue(const LengthSize& radius, const RenderStyle& style) { - if (radius.width() == radius.height()) { - if (radius.width().type() == Percent) - return cssValuePool().createValue(radius.width().percent(), CSSPrimitiveValue::CSS_PERCENTAGE); - return zoomAdjustedPixelValue(valueForLength(radius.width(), 0, renderView), style); - } - return getBorderRadiusCornerValues(radius, style, renderView); + if (radius.width == radius.height) + return percentageOrZoomAdjustedValue(radius.width, style); + return borderRadiusCornerValues(radius, style); } -static PassRef getBorderRadiusShorthandValue(const RenderStyle* style, RenderView* renderView) +static Ref borderRadiusShorthandValue(const RenderStyle& style) { auto list = CSSValueList::createSlashSeparated(); - bool showHorizontalBottomLeft = style->borderTopRightRadius().width() != style->borderBottomLeftRadius().width(); - bool showHorizontalBottomRight = showHorizontalBottomLeft || (style->borderBottomRightRadius().width() != style->borderTopLeftRadius().width()); - bool showHorizontalTopRight = showHorizontalBottomRight || (style->borderTopRightRadius().width() != style->borderTopLeftRadius().width()); + bool showHorizontalBottomLeft = style.borderTopRightRadius().width != style.borderBottomLeftRadius().width; + bool showHorizontalBottomRight = showHorizontalBottomLeft || (style.borderBottomRightRadius().width != style.borderTopLeftRadius().width); + bool showHorizontalTopRight = showHorizontalBottomRight || (style.borderTopRightRadius().width != style.borderTopLeftRadius().width); - bool showVerticalBottomLeft = style->borderTopRightRadius().height() != style->borderBottomLeftRadius().height(); - bool showVerticalBottomRight = showVerticalBottomLeft || (style->borderBottomRightRadius().height() != style->borderTopLeftRadius().height()); - bool showVerticalTopRight = showVerticalBottomRight || (style->borderTopRightRadius().height() != style->borderTopLeftRadius().height()); + bool showVerticalBottomLeft = style.borderTopRightRadius().height != style.borderBottomLeftRadius().height; + bool showVerticalBottomRight = showVerticalBottomLeft || (style.borderBottomRightRadius().height != style.borderTopLeftRadius().height); + bool showVerticalTopRight = showVerticalBottomRight || (style.borderTopRightRadius().height != style.borderTopLeftRadius().height); - RefPtr topLeftRadius = getBorderRadiusCornerValues(style->borderTopLeftRadius(), style, renderView); - RefPtr topRightRadius = getBorderRadiusCornerValues(style->borderTopRightRadius(), style, renderView); - RefPtr bottomRightRadius = getBorderRadiusCornerValues(style->borderBottomRightRadius(), style, renderView); - RefPtr bottomLeftRadius = getBorderRadiusCornerValues(style->borderBottomLeftRadius(), style, renderView); + auto topLeftRadius = borderRadiusCornerValues(style.borderTopLeftRadius(), style); + auto topRightRadius = borderRadiusCornerValues(style.borderTopRightRadius(), style); + auto bottomRightRadius = borderRadiusCornerValues(style.borderBottomRightRadius(), style); + auto bottomLeftRadius = borderRadiusCornerValues(style.borderBottomLeftRadius(), style); - RefPtr horizontalRadii = CSSValueList::createSpaceSeparated(); - horizontalRadii->append(topLeftRadius->item(0)); + auto horizontalRadii = CSSValueList::createSpaceSeparated(); + horizontalRadii->append(*topLeftRadius->item(0)); if (showHorizontalTopRight) - horizontalRadii->append(topRightRadius->item(0)); + horizontalRadii->append(*topRightRadius->item(0)); if (showHorizontalBottomRight) - horizontalRadii->append(bottomRightRadius->item(0)); + horizontalRadii->append(*bottomRightRadius->item(0)); if (showHorizontalBottomLeft) - horizontalRadii->append(bottomLeftRadius->item(0)); + horizontalRadii->append(*bottomLeftRadius->item(0)); - list.get().append(horizontalRadii.release()); + list->append(WTFMove(horizontalRadii)); - RefPtr verticalRadiiList = CSSValueList::createSpaceSeparated(); - verticalRadiiList->append(topLeftRadius->item(1)); + auto verticalRadiiList = CSSValueList::createSpaceSeparated(); + verticalRadiiList->append(*topLeftRadius->item(1)); if (showVerticalTopRight) - verticalRadiiList->append(topRightRadius->item(1)); + verticalRadiiList->append(*topRightRadius->item(1)); if (showVerticalBottomRight) - verticalRadiiList->append(bottomRightRadius->item(1)); + verticalRadiiList->append(*bottomRightRadius->item(1)); if (showVerticalBottomLeft) - verticalRadiiList->append(bottomLeftRadius->item(1)); + verticalRadiiList->append(*bottomLeftRadius->item(1)); - if (!verticalRadiiList->equals(*toCSSValueList(list.get().item(0)))) - list.get().append(verticalRadiiList.release()); + if (!verticalRadiiList->equals(downcast(*list->item(0)))) + list->append(WTFMove(verticalRadiiList)); return list; } -static LayoutRect sizingBox(RenderObject* renderer) +static LayoutRect sizingBox(RenderObject& renderer) { - if (!renderer->isBox()) + if (!is(renderer)) return LayoutRect(); - RenderBox* box = toRenderBox(renderer); - return box->style().boxSizing() == BORDER_BOX ? box->borderBoxRect() : box->computedCSSContentBoxRect(); + auto& box = downcast(renderer); + return box.style().boxSizing() == BORDER_BOX ? box.borderBoxRect() : box.computedCSSContentBoxRect(); } -static PassRef matrixTransformValue(const TransformationMatrix& transform, const RenderStyle* style) +static Ref matrixTransformValue(const TransformationMatrix& transform, const RenderStyle& style) { - RefPtr transformValue; + RefPtr transformValue; + auto& cssValuePool = CSSValuePool::singleton(); if (transform.isAffine()) { - transformValue = WebKitCSSTransformValue::create(WebKitCSSTransformValue::MatrixTransformOperation); + transformValue = CSSFunctionValue::create(CSSValueMatrix); - transformValue->append(cssValuePool().createValue(transform.a(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.b(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.c(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.d(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.a(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.b(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.c(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.d(), CSSPrimitiveValue::CSS_NUMBER)); transformValue->append(zoomAdjustedNumberValue(transform.e(), style)); transformValue->append(zoomAdjustedNumberValue(transform.f(), style)); } else { - transformValue = WebKitCSSTransformValue::create(WebKitCSSTransformValue::Matrix3DTransformOperation); + transformValue = CSSFunctionValue::create(CSSValueMatrix3d); - transformValue->append(cssValuePool().createValue(transform.m11(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m12(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m13(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m14(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m11(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m12(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m13(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m14(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m21(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m22(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m23(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m24(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m21(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m22(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m23(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m24(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m31(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m32(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m33(), CSSPrimitiveValue::CSS_NUMBER)); - transformValue->append(cssValuePool().createValue(transform.m34(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m31(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m32(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m33(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m34(), CSSPrimitiveValue::CSS_NUMBER)); transformValue->append(zoomAdjustedNumberValue(transform.m41(), style)); transformValue->append(zoomAdjustedNumberValue(transform.m42(), style)); transformValue->append(zoomAdjustedNumberValue(transform.m43(), style)); - transformValue->append(cssValuePool().createValue(transform.m44(), CSSPrimitiveValue::CSS_NUMBER)); + transformValue->append(cssValuePool.createValue(transform.m44(), CSSPrimitiveValue::CSS_NUMBER)); } return transformValue.releaseNonNull(); } -static PassRef computedTransform(RenderObject* renderer, const RenderStyle* style) +static Ref computedTransform(RenderObject* renderer, const RenderStyle& style) { - if (!renderer || !renderer->hasTransform() || !style->hasTransform()) - return cssValuePool().createIdentifierValue(CSSValueNone); + if (!renderer || !renderer->hasTransform()) + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); - IntRect box; - if (renderer->isBox()) - box = pixelSnappedIntRect(toRenderBox(renderer)->borderBoxRect()); + FloatRect pixelSnappedRect; + if (is(*renderer)) + pixelSnappedRect = snapRectToDevicePixels(downcast(*renderer).borderBoxRect(), renderer->document().deviceScaleFactor()); TransformationMatrix transform; - style->applyTransform(transform, box.size(), RenderStyle::ExcludeTransformOrigin); - // Note that this does not flatten to an affine transform if ENABLE(3D_RENDERING) is off, by design. + style.applyTransform(transform, pixelSnappedRect, RenderStyle::ExcludeTransformOrigin); + // Note that this does not flatten to an affine transform if ENABLE(3D_TRANSFORMS) is off, by design. // FIXME: Need to print out individual functions (https://bugs.webkit.org/show_bug.cgi?id=23924) auto list = CSSValueList::createSpaceSeparated(); - list.get().append(matrixTransformValue(transform, style)); - return std::move(list); + list->append(matrixTransformValue(transform, style)); + return WTFMove(list); } -static inline PassRef adjustLengthForZoom(double length, const RenderStyle* style, AdjustPixelValuesForComputedStyle adjust) +static inline Ref adjustLengthForZoom(double length, const RenderStyle& style, AdjustPixelValuesForComputedStyle adjust) { - return adjust == AdjustPixelValues ? zoomAdjustedPixelValue(length, style) : cssValuePool().createValue(length, CSSPrimitiveValue::CSS_PX); + return adjust == AdjustPixelValues ? zoomAdjustedPixelValue(length, style) : CSSValuePool::singleton().createValue(length, CSSPrimitiveValue::CSS_PX); } -static inline PassRef adjustLengthForZoom(const Length& length, const RenderStyle* style, AdjustPixelValuesForComputedStyle adjust) +static inline Ref adjustLengthForZoom(const Length& length, const RenderStyle& style, AdjustPixelValuesForComputedStyle adjust) { - return adjust == AdjustPixelValues ? zoomAdjustedPixelValue(length.value(), style) : cssValuePool().createValue(length); + return adjust == AdjustPixelValues ? zoomAdjustedPixelValue(length.value(), style) : CSSValuePool::singleton().createValue(length); } -PassRefPtr ComputedStyleExtractor::valueForShadow(const ShadowData* shadow, CSSPropertyID propertyID, const RenderStyle* style, AdjustPixelValuesForComputedStyle adjust) +Ref ComputedStyleExtractor::valueForShadow(const ShadowData* shadow, CSSPropertyID propertyID, const RenderStyle& style, AdjustPixelValuesForComputedStyle adjust) { + auto& cssValuePool = CSSValuePool::singleton(); if (!shadow) - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); - RefPtr list = CSSValueList::createCommaSeparated(); + auto list = CSSValueList::createCommaSeparated(); for (const ShadowData* currShadowData = shadow; currShadowData; currShadowData = currShadowData->next()) { - RefPtr x = adjustLengthForZoom(currShadowData->x(), style, adjust); - RefPtr y = adjustLengthForZoom(currShadowData->y(), style, adjust); - RefPtr blur = adjustLengthForZoom(currShadowData->radius(), style, adjust); - RefPtr spread = propertyID == CSSPropertyTextShadow ? PassRefPtr() : adjustLengthForZoom(currShadowData->spread(), style, adjust); - RefPtr style = propertyID == CSSPropertyTextShadow || currShadowData->style() == Normal ? PassRefPtr() : cssValuePool().createIdentifierValue(CSSValueInset); - RefPtr color = cssValuePool().createColorValue(currShadowData->color().rgb()); - list->prepend(CSSShadowValue::create(x.release(), y.release(), blur.release(), spread.release(), style.release(), color.release())); + auto x = adjustLengthForZoom(currShadowData->x(), style, adjust); + auto y = adjustLengthForZoom(currShadowData->y(), style, adjust); + auto blur = adjustLengthForZoom(currShadowData->radius(), style, adjust); + auto spread = propertyID == CSSPropertyTextShadow ? RefPtr() : adjustLengthForZoom(currShadowData->spread(), style, adjust); + auto style = propertyID == CSSPropertyTextShadow || currShadowData->style() == Normal ? RefPtr() : cssValuePool.createIdentifierValue(CSSValueInset); + auto color = cssValuePool.createColorValue(currShadowData->color()); + list->prepend(CSSShadowValue::create(WTFMove(x), WTFMove(y), WTFMove(blur), WTFMove(spread), WTFMove(style), WTFMove(color))); } - return list.release(); + return WTFMove(list); } -#if ENABLE(CSS_FILTERS) -PassRef ComputedStyleExtractor::valueForFilter(const RenderStyle* style, const FilterOperations& filterOperations, AdjustPixelValuesForComputedStyle adjust) +Ref ComputedStyleExtractor::valueForFilter(const RenderStyle& style, const FilterOperations& filterOperations, AdjustPixelValuesForComputedStyle adjust) { + auto& cssValuePool = CSSValuePool::singleton(); if (filterOperations.operations().isEmpty()) - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); auto list = CSSValueList::createSpaceSeparated(); - RefPtr filterValue; - Vector>::const_iterator end = filterOperations.operations().end(); for (Vector>::const_iterator it = filterOperations.operations().begin(); it != end; ++it) { - FilterOperation* filterOperation = (*it).get(); - switch (filterOperation->type()) { - case FilterOperation::REFERENCE: { - ReferenceFilterOperation* referenceOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation); - filterValue->append(cssValuePool().createValue(referenceOperation->url(), CSSPrimitiveValue::CSS_URI)); - break; - } - case FilterOperation::GRAYSCALE: { - BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::GrayscaleFilterOperation); - filterValue->append(cssValuePool().createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::SEPIA: { - BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::SepiaFilterOperation); - filterValue->append(cssValuePool().createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::SATURATE: { - BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::SaturateFilterOperation); - filterValue->append(cssValuePool().createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::HUE_ROTATE: { - BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::HueRotateFilterOperation); - filterValue->append(cssValuePool().createValue(colorMatrixOperation->amount(), CSSPrimitiveValue::CSS_DEG)); - break; - } - case FilterOperation::INVERT: { - BasicComponentTransferFilterOperation* componentTransferOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::InvertFilterOperation); - filterValue->append(cssValuePool().createValue(componentTransferOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::OPACITY: { - BasicComponentTransferFilterOperation* componentTransferOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::OpacityFilterOperation); - filterValue->append(cssValuePool().createValue(componentTransferOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::BRIGHTNESS: { - BasicComponentTransferFilterOperation* brightnessOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::BrightnessFilterOperation); - filterValue->append(cssValuePool().createValue(brightnessOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::CONTRAST: { - BasicComponentTransferFilterOperation* contrastOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ContrastFilterOperation); - filterValue->append(cssValuePool().createValue(contrastOperation->amount(), CSSPrimitiveValue::CSS_NUMBER)); - break; - } - case FilterOperation::BLUR: { - BlurFilterOperation* blurOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::BlurFilterOperation); - filterValue->append(adjustLengthForZoom(blurOperation->stdDeviation(), style, adjust)); - break; - } - case FilterOperation::DROP_SHADOW: { - DropShadowFilterOperation* dropShadowOperation = static_cast(filterOperation); - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::DropShadowFilterOperation); - // We want our computed style to look like that of a text shadow (has neither spread nor inset style). - ShadowData shadowData = ShadowData(dropShadowOperation->location(), dropShadowOperation->stdDeviation(), 0, Normal, false, dropShadowOperation->color()); - filterValue->append(valueForShadow(&shadowData, CSSPropertyTextShadow, style, adjust)); - break; - } - default: - filterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::UnknownFilterOperation); - break; + FilterOperation& filterOperation = **it; + + if (filterOperation.type() == FilterOperation::REFERENCE) { + ReferenceFilterOperation& referenceOperation = downcast(filterOperation); + list->append(cssValuePool.createValue(referenceOperation.url(), CSSPrimitiveValue::CSS_URI)); + } else { + RefPtr filterValue; + switch (filterOperation.type()) { + case FilterOperation::GRAYSCALE: { + filterValue = CSSFunctionValue::create(CSSValueGrayscale); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::SEPIA: { + filterValue = CSSFunctionValue::create(CSSValueSepia); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::SATURATE: { + filterValue = CSSFunctionValue::create(CSSValueSaturate); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::HUE_ROTATE: { + filterValue = CSSFunctionValue::create(CSSValueHueRotate); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_DEG)); + break; + } + case FilterOperation::INVERT: { + filterValue = CSSFunctionValue::create(CSSValueInvert); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::OPACITY: { + filterValue = CSSFunctionValue::create(CSSValueOpacity); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::BRIGHTNESS: { + filterValue = CSSFunctionValue::create(CSSValueBrightness); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::CONTRAST: { + filterValue = CSSFunctionValue::create(CSSValueContrast); + filterValue->append(cssValuePool.createValue(downcast(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER)); + break; + } + case FilterOperation::BLUR: { + filterValue = CSSFunctionValue::create(CSSValueBlur); + filterValue->append(adjustLengthForZoom(downcast(filterOperation).stdDeviation(), style, adjust)); + break; + } + case FilterOperation::DROP_SHADOW: { + DropShadowFilterOperation& dropShadowOperation = downcast(filterOperation); + filterValue = CSSFunctionValue::create(CSSValueDropShadow); + // We want our computed style to look like that of a text shadow (has neither spread nor inset style). + ShadowData shadowData = ShadowData(dropShadowOperation.location(), dropShadowOperation.stdDeviation(), 0, Normal, false, dropShadowOperation.color()); + filterValue->append(valueForShadow(&shadowData, CSSPropertyTextShadow, style, adjust)); + break; + } + default: + ASSERT_NOT_REACHED(); + filterValue = CSSFunctionValue::create(CSSValueInvalid); + break; + } + list->append(filterValue.releaseNonNull()); } - list.get().append(filterValue.release()); } - - return std::move(list); + return WTFMove(list); } -#endif -static PassRef valueForGridTrackBreadth(const GridLength& trackBreadth, const RenderStyle* style, RenderView* renderView) +static Ref specifiedValueForGridTrackBreadth(const GridLength& trackBreadth, const RenderStyle& style) { if (!trackBreadth.isLength()) - return cssValuePool().createValue(trackBreadth.flex(), CSSPrimitiveValue::CSS_FR); + return CSSValuePool::singleton().createValue(trackBreadth.flex(), CSSPrimitiveValue::CSS_FR); const Length& trackBreadthLength = trackBreadth.length(); if (trackBreadthLength.isAuto()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - if (trackBreadthLength.isViewportPercentage()) - return zoomAdjustedPixelValue(valueForLength(trackBreadthLength, 0, renderView), style); + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); return zoomAdjustedPixelValueForLength(trackBreadthLength, style); } -static PassRefPtr valueForGridTrackSize(const GridTrackSize& trackSize, const RenderStyle* style, RenderView* renderView) +static Ref specifiedValueForGridTrackSize(const GridTrackSize& trackSize, const RenderStyle& style) { switch (trackSize.type()) { case LengthTrackSizing: - return valueForGridTrackBreadth(trackSize.length(), style, renderView); - case MinMaxTrackSizing: - RefPtr minMaxTrackBreadths = CSSValueList::createCommaSeparated(); - minMaxTrackBreadths->append(valueForGridTrackBreadth(trackSize.minTrackBreadth(), style, renderView)); - minMaxTrackBreadths->append(valueForGridTrackBreadth(trackSize.maxTrackBreadth(), style, renderView)); - return CSSFunctionValue::create("minmax(", minMaxTrackBreadths); + return specifiedValueForGridTrackBreadth(trackSize.minTrackBreadth(), style); + case FitContentTrackSizing: { + auto fitContentTrackSize = CSSFunctionValue::create(CSSValueFitContent); + fitContentTrackSize->append(zoomAdjustedPixelValueForLength(trackSize.fitContentTrackBreadth().length(), style)); + return WTFMove(fitContentTrackSize); + } + default: + ASSERT(trackSize.type() == MinMaxTrackSizing); + if (trackSize.minTrackBreadth().isAuto() && trackSize.maxTrackBreadth().isFlex()) + return CSSValuePool::singleton().createValue(trackSize.maxTrackBreadth().flex(), CSSPrimitiveValue::CSS_FR); + + auto minMaxTrackBreadths = CSSFunctionValue::create(CSSValueMinmax); + minMaxTrackBreadths->append(specifiedValueForGridTrackBreadth(trackSize.minTrackBreadth(), style)); + minMaxTrackBreadths->append(specifiedValueForGridTrackBreadth(trackSize.maxTrackBreadth(), style)); + return WTFMove(minMaxTrackBreadths); } - ASSERT_NOT_REACHED(); - return 0; } -static void addValuesForNamedGridLinesAtIndex(const NamedGridLinesMap& namedGridLines, size_t i, CSSValueList& list) +class OrderedNamedLinesCollector { + WTF_MAKE_NONCOPYABLE(OrderedNamedLinesCollector); +public: + OrderedNamedLinesCollector(const RenderStyle& style, bool isRowAxis, unsigned autoRepeatTracksCount) + : m_orderedNamedGridLines(isRowAxis ? style.orderedNamedGridColumnLines() : style.orderedNamedGridRowLines()) + , m_orderedNamedAutoRepeatGridLines(isRowAxis ? style.autoRepeatOrderedNamedGridColumnLines() : style.autoRepeatOrderedNamedGridRowLines()) + , m_insertionPoint(isRowAxis ? style.gridAutoRepeatColumnsInsertionPoint() : style.gridAutoRepeatRowsInsertionPoint()) + , m_autoRepeatTotalTracks(autoRepeatTracksCount) + , m_autoRepeatTrackListLength(isRowAxis ? style.gridAutoRepeatColumns().size() : style.gridAutoRepeatRows().size()) + { + } + + bool isEmpty() const { return m_orderedNamedGridLines.isEmpty() && m_orderedNamedAutoRepeatGridLines.isEmpty(); } + void collectLineNamesForIndex(CSSGridLineNamesValue&, unsigned index) const; + +private: + + enum NamedLinesType { NamedLines, AutoRepeatNamedLines }; + void appendLines(CSSGridLineNamesValue&, unsigned index, NamedLinesType) const; + + const OrderedNamedGridLinesMap& m_orderedNamedGridLines; + const OrderedNamedGridLinesMap& m_orderedNamedAutoRepeatGridLines; + unsigned m_insertionPoint; + unsigned m_autoRepeatTotalTracks; + unsigned m_autoRepeatTrackListLength; +}; + +void OrderedNamedLinesCollector::appendLines(CSSGridLineNamesValue& lineNamesValue, unsigned index, NamedLinesType type) const { - // Note that this won't return the results in the order specified in the style sheet, - // which is probably fine as we still *do* return all the expected values. - NamedGridLinesMap::const_iterator it = namedGridLines.begin(); - NamedGridLinesMap::const_iterator end = namedGridLines.end(); - for (; it != end; ++it) { - const Vector& linesIndexes = it->value; - for (size_t j = 0; j < linesIndexes.size(); ++j) { - if (linesIndexes[j] != i) - continue; + auto iter = type == NamedLines ? m_orderedNamedGridLines.find(index) : m_orderedNamedAutoRepeatGridLines.find(index); + auto endIter = type == NamedLines ? m_orderedNamedGridLines.end() : m_orderedNamedAutoRepeatGridLines.end(); + if (iter == endIter) + return; - list.append(cssValuePool().createValue(it->key, CSSPrimitiveValue::CSS_STRING)); - break; - } + auto& cssValuePool = CSSValuePool::singleton(); + for (auto lineName : iter->value) + lineNamesValue.append(cssValuePool.createValue(lineName, CSSPrimitiveValue::CSS_STRING)); +} + +void OrderedNamedLinesCollector::collectLineNamesForIndex(CSSGridLineNamesValue& lineNamesValue, unsigned i) const +{ + ASSERT(!isEmpty()); + if (m_orderedNamedAutoRepeatGridLines.isEmpty() || i < m_insertionPoint) { + appendLines(lineNamesValue, i, NamedLines); + return; + } + + ASSERT(m_autoRepeatTotalTracks); + + if (i > m_insertionPoint + m_autoRepeatTotalTracks) { + appendLines(lineNamesValue, i - (m_autoRepeatTotalTracks - 1), NamedLines); + return; + } + + if (i == m_insertionPoint) { + appendLines(lineNamesValue, i, NamedLines); + appendLines(lineNamesValue, 0, AutoRepeatNamedLines); + return; + } + + if (i == m_insertionPoint + m_autoRepeatTotalTracks) { + appendLines(lineNamesValue, m_autoRepeatTrackListLength, AutoRepeatNamedLines); + appendLines(lineNamesValue, m_insertionPoint + 1, NamedLines); + return; } + + unsigned autoRepeatIndexInFirstRepetition = (i - m_insertionPoint) % m_autoRepeatTrackListLength; + if (!autoRepeatIndexInFirstRepetition && i > m_insertionPoint) + appendLines(lineNamesValue, m_autoRepeatTrackListLength, AutoRepeatNamedLines); + appendLines(lineNamesValue, autoRepeatIndexInFirstRepetition, AutoRepeatNamedLines); } -static PassRef valueForGridTrackList(const Vector& trackSizes, const NamedGridLinesMap& namedGridLines, const RenderStyle* style, RenderView* renderView) +static void addValuesForNamedGridLinesAtIndex(OrderedNamedLinesCollector& collector, unsigned i, CSSValueList& list) { - // Handle the 'none' case here. - if (!trackSizes.size()) { - ASSERT(namedGridLines.isEmpty()); - return cssValuePool().createIdentifierValue(CSSValueNone); + if (collector.isEmpty()) + return; + + auto lineNames = CSSGridLineNamesValue::create(); + collector.collectLineNamesForIndex(lineNames.get(), i); + if (lineNames->length()) + list.append(WTFMove(lineNames)); +} + +static Ref valueForGridTrackSizeList(GridTrackSizingDirection direction, const RenderStyle& style) +{ + auto& autoTrackSizes = direction == ForColumns ? style.gridAutoColumns() : style.gridAutoRows(); + + auto list = CSSValueList::createSpaceSeparated(); + for (auto& trackSize : autoTrackSizes) + list->append(specifiedValueForGridTrackSize(trackSize, style)); + return list; +} + +static Ref valueForGridTrackList(GridTrackSizingDirection direction, RenderObject* renderer, const RenderStyle& style) +{ + bool isRowAxis = direction == ForColumns; + bool isRenderGrid = is(renderer); + auto& trackSizes = isRowAxis ? style.gridColumns() : style.gridRows(); + auto& autoRepeatTrackSizes = isRowAxis ? style.gridAutoRepeatColumns() : style.gridAutoRepeatRows(); + + // Handle the 'none' case. + bool trackListIsEmpty = trackSizes.isEmpty() && autoRepeatTrackSizes.isEmpty(); + if (isRenderGrid && trackListIsEmpty) { + // For grids we should consider every listed track, whether implicitly or explicitly + // created. Empty grids have a sole grid line per axis. + auto& grid = downcast(*renderer); + auto& positions = isRowAxis ? grid.columnPositions() : grid.rowPositions(); + trackListIsEmpty = positions.size() == 1; } + if (trackListIsEmpty) + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + + unsigned autoRepeatTotalTracks = isRenderGrid ? downcast(renderer)->autoRepeatCountForDirection(direction) : 0; + OrderedNamedLinesCollector collector(style, isRowAxis, autoRepeatTotalTracks); auto list = CSSValueList::createSpaceSeparated(); - for (size_t i = 0; i < trackSizes.size(); ++i) { - addValuesForNamedGridLinesAtIndex(namedGridLines, i, list.get()); - list.get().append(valueForGridTrackSize(trackSizes[i], style, renderView)); + unsigned insertionIndex; + if (isRenderGrid) { + auto computedTrackSizes = downcast(*renderer).trackSizesForComputedStyle(direction); + unsigned numTracks = computedTrackSizes.size(); + + for (unsigned i = 0; i < numTracks; ++i) { + addValuesForNamedGridLinesAtIndex(collector, i, list.get()); + list->append(zoomAdjustedPixelValue(computedTrackSizes[i], style)); + } + addValuesForNamedGridLinesAtIndex(collector, numTracks + 1, list.get()); + insertionIndex = numTracks; + } else { + for (unsigned i = 0; i < trackSizes.size(); ++i) { + addValuesForNamedGridLinesAtIndex(collector, i, list.get()); + list->append(specifiedValueForGridTrackSize(trackSizes[i], style)); + } + insertionIndex = trackSizes.size(); } - // Those are the trailing * allowed in the syntax. - addValuesForNamedGridLinesAtIndex(namedGridLines, trackSizes.size(), list.get()); - return std::move(list); + + // Those are the trailing * allowed in the syntax. + addValuesForNamedGridLinesAtIndex(collector, insertionIndex, list.get()); + return WTFMove(list); } -static PassRef valueForGridPosition(const GridPosition& position) +static Ref valueForGridPosition(const GridPosition& position) { + auto& cssValuePool = CSSValuePool::singleton(); if (position.isAuto()) - return cssValuePool().createIdentifierValue(CSSValueAuto); + return cssValuePool.createIdentifierValue(CSSValueAuto); if (position.isNamedGridArea()) - return cssValuePool().createValue(position.namedGridLine(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createValue(position.namedGridLine(), CSSPrimitiveValue::CSS_STRING); auto list = CSSValueList::createSpaceSeparated(); if (position.isSpan()) { - list.get().append(cssValuePool().createIdentifierValue(CSSValueSpan)); - list.get().append(cssValuePool().createValue(position.spanPosition(), CSSPrimitiveValue::CSS_NUMBER)); + list->append(cssValuePool.createIdentifierValue(CSSValueSpan)); + list->append(cssValuePool.createValue(position.spanPosition(), CSSPrimitiveValue::CSS_NUMBER)); } else - list.get().append(cssValuePool().createValue(position.integerPosition(), CSSPrimitiveValue::CSS_NUMBER)); + list->append(cssValuePool.createValue(position.integerPosition(), CSSPrimitiveValue::CSS_NUMBER)); if (!position.namedGridLine().isNull()) - list.get().append(cssValuePool().createValue(position.namedGridLine(), CSSPrimitiveValue::CSS_STRING)); - return std::move(list); + list->append(cssValuePool.createValue(position.namedGridLine(), CSSPrimitiveValue::CSS_STRING)); + return WTFMove(list); } -static PassRef createTransitionPropertyValue(const Animation& animation) +static Ref createTransitionPropertyValue(const Animation& animation) { - if (animation.animationMode() == Animation::AnimateNone) - return cssValuePool().createIdentifierValue(CSSValueNone); - if (animation.animationMode() == Animation::AnimateAll) - return cssValuePool().createIdentifierValue(CSSValueAll); - return cssValuePool().createValue(getPropertyNameString(animation.property()), CSSPrimitiveValue::CSS_STRING); + switch (animation.animationMode()) { + case Animation::AnimateNone: + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + case Animation::AnimateAll: + return CSSValuePool::singleton().createIdentifierValue(CSSValueAll); + case Animation::AnimateSingleProperty: + return CSSValuePool::singleton().createValue(getPropertyNameString(animation.property()), CSSPrimitiveValue::CSS_STRING); + case Animation::AnimateUnknownProperty: + return CSSValuePool::singleton().createValue(animation.unknownProperty(), CSSPrimitiveValue::CSS_STRING); + } + ASSERT_NOT_REACHED(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); } -static PassRef getTransitionPropertyValue(const AnimationList* animList) +static Ref transitionPropertyValue(const AnimationList* animationList) { auto list = CSSValueList::createCommaSeparated(); - if (animList) { - for (size_t i = 0; i < animList->size(); ++i) - list.get().append(createTransitionPropertyValue(animList->animation(i))); + if (animationList) { + for (size_t i = 0; i < animationList->size(); ++i) + list->append(createTransitionPropertyValue(animationList->animation(i))); } else - list.get().append(cssValuePool().createIdentifierValue(CSSValueAll)); + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueAll)); return list; } -static PassRef getDelayValue(const AnimationList* animList) +#if ENABLE(CSS_SCROLL_SNAP) + +static Ref valueForScrollSnapType(const ScrollSnapType& type) +{ + auto value = CSSValueList::createSpaceSeparated(); + if (type.strictness == ScrollSnapStrictness::None) + value->append(CSSValuePool::singleton().createValue(CSSValueNone)); + else { + value->append(CSSPrimitiveValue::create(type.axis)); + value->append(CSSPrimitiveValue::create(type.strictness)); + } + return value; +} + +static Ref valueForScrollSnapAlignment(const ScrollSnapAlign& alignment) +{ + auto value = CSSValueList::createSpaceSeparated(); + value->append(CSSPrimitiveValue::create(alignment.x)); + value->append(CSSPrimitiveValue::create(alignment.y)); + return value; +} + +#endif + +static Ref willChangePropertyValue(const WillChangeData* willChangeData) +{ + auto& cssValuePool = CSSValuePool::singleton(); + if (!willChangeData || !willChangeData->numFeatures()) + return cssValuePool.createIdentifierValue(CSSValueAuto); + + auto list = CSSValueList::createCommaSeparated(); + for (size_t i = 0; i < willChangeData->numFeatures(); ++i) { + WillChangeData::FeaturePropertyPair feature = willChangeData->featureAt(i); + switch (feature.first) { + case WillChangeData::ScrollPosition: + list->append(cssValuePool.createIdentifierValue(CSSValueScrollPosition)); + break; + case WillChangeData::Contents: + list->append(cssValuePool.createIdentifierValue(CSSValueContents)); + break; + case WillChangeData::Property: + list->append(cssValuePool.createIdentifierValue(feature.second)); + break; + case WillChangeData::Invalid: + ASSERT_NOT_REACHED(); + break; + } + } + + return WTFMove(list); +} + +static inline void appendLigaturesValue(CSSValueList& list, FontVariantLigatures value, CSSValueID yesValue, CSSValueID noValue) +{ + switch (value) { + case FontVariantLigatures::Normal: + return; + case FontVariantLigatures::No: + list.append(CSSValuePool::singleton().createIdentifierValue(noValue)); + return; + case FontVariantLigatures::Yes: + list.append(CSSValuePool::singleton().createIdentifierValue(yesValue)); + return; + } + ASSERT_NOT_REACHED(); +} + +static Ref fontVariantLigaturesPropertyValue(FontVariantLigatures common, FontVariantLigatures discretionary, FontVariantLigatures historical, FontVariantLigatures contextualAlternates) +{ + auto& cssValuePool = CSSValuePool::singleton(); + if (common == FontVariantLigatures::No && discretionary == FontVariantLigatures::No && historical == FontVariantLigatures::No && contextualAlternates == FontVariantLigatures::No) + return cssValuePool.createIdentifierValue(CSSValueNone); + if (common == FontVariantLigatures::Normal && discretionary == FontVariantLigatures::Normal && historical == FontVariantLigatures::Normal && contextualAlternates == FontVariantLigatures::Normal) + return cssValuePool.createIdentifierValue(CSSValueNormal); + + auto valueList = CSSValueList::createSpaceSeparated(); + appendLigaturesValue(valueList, common, CSSValueCommonLigatures, CSSValueNoCommonLigatures); + appendLigaturesValue(valueList, discretionary, CSSValueDiscretionaryLigatures, CSSValueNoDiscretionaryLigatures); + appendLigaturesValue(valueList, historical, CSSValueHistoricalLigatures, CSSValueNoHistoricalLigatures); + appendLigaturesValue(valueList, contextualAlternates, CSSValueContextual, CSSValueNoContextual); + return WTFMove(valueList); +} + +static Ref fontVariantPositionPropertyValue(FontVariantPosition position) +{ + auto& cssValuePool = CSSValuePool::singleton(); + CSSValueID valueID = CSSValueNormal; + switch (position) { + case FontVariantPosition::Normal: + break; + case FontVariantPosition::Subscript: + valueID = CSSValueSub; + break; + case FontVariantPosition::Superscript: + valueID = CSSValueSuper; + break; + } + return cssValuePool.createIdentifierValue(valueID); +} + +static Ref fontVariantCapsPropertyValue(FontVariantCaps caps) +{ + auto& cssValuePool = CSSValuePool::singleton(); + CSSValueID valueID = CSSValueNormal; + switch (caps) { + case FontVariantCaps::Normal: + break; + case FontVariantCaps::Small: + valueID = CSSValueSmallCaps; + break; + case FontVariantCaps::AllSmall: + valueID = CSSValueAllSmallCaps; + break; + case FontVariantCaps::Petite: + valueID = CSSValuePetiteCaps; + break; + case FontVariantCaps::AllPetite: + valueID = CSSValueAllPetiteCaps; + break; + case FontVariantCaps::Unicase: + valueID = CSSValueUnicase; + break; + case FontVariantCaps::Titling: + valueID = CSSValueTitlingCaps; + break; + } + return cssValuePool.createIdentifierValue(valueID); +} + +static Ref fontVariantNumericPropertyValue(FontVariantNumericFigure figure, FontVariantNumericSpacing spacing, FontVariantNumericFraction fraction, FontVariantNumericOrdinal ordinal, FontVariantNumericSlashedZero slashedZero) +{ + auto& cssValuePool = CSSValuePool::singleton(); + if (figure == FontVariantNumericFigure::Normal && spacing == FontVariantNumericSpacing::Normal && fraction == FontVariantNumericFraction::Normal && ordinal == FontVariantNumericOrdinal::Normal && slashedZero == FontVariantNumericSlashedZero::Normal) + return cssValuePool.createIdentifierValue(CSSValueNormal); + + auto valueList = CSSValueList::createSpaceSeparated(); + switch (figure) { + case FontVariantNumericFigure::Normal: + break; + case FontVariantNumericFigure::LiningNumbers: + valueList->append(cssValuePool.createIdentifierValue(CSSValueLiningNums)); + break; + case FontVariantNumericFigure::OldStyleNumbers: + valueList->append(cssValuePool.createIdentifierValue(CSSValueOldstyleNums)); + break; + } + + switch (spacing) { + case FontVariantNumericSpacing::Normal: + break; + case FontVariantNumericSpacing::ProportionalNumbers: + valueList->append(cssValuePool.createIdentifierValue(CSSValueProportionalNums)); + break; + case FontVariantNumericSpacing::TabularNumbers: + valueList->append(cssValuePool.createIdentifierValue(CSSValueTabularNums)); + break; + } + + switch (fraction) { + case FontVariantNumericFraction::Normal: + break; + case FontVariantNumericFraction::DiagonalFractions: + valueList->append(cssValuePool.createIdentifierValue(CSSValueDiagonalFractions)); + break; + case FontVariantNumericFraction::StackedFractions: + valueList->append(cssValuePool.createIdentifierValue(CSSValueStackedFractions)); + break; + } + + if (ordinal == FontVariantNumericOrdinal::Yes) + valueList->append(cssValuePool.createIdentifierValue(CSSValueOrdinal)); + if (slashedZero == FontVariantNumericSlashedZero::Yes) + valueList->append(cssValuePool.createIdentifierValue(CSSValueSlashedZero)); + + return WTFMove(valueList); +} + +static Ref fontVariantAlternatesPropertyValue(FontVariantAlternates alternates) +{ + auto& cssValuePool = CSSValuePool::singleton(); + CSSValueID valueID = CSSValueNormal; + switch (alternates) { + case FontVariantAlternates::Normal: + break; + case FontVariantAlternates::HistoricalForms: + valueID = CSSValueHistoricalForms; + break; + } + return cssValuePool.createIdentifierValue(valueID); +} + +static Ref fontVariantEastAsianPropertyValue(FontVariantEastAsianVariant variant, FontVariantEastAsianWidth width, FontVariantEastAsianRuby ruby) +{ + auto& cssValuePool = CSSValuePool::singleton(); + if (variant == FontVariantEastAsianVariant::Normal && width == FontVariantEastAsianWidth::Normal && ruby == FontVariantEastAsianRuby::Normal) + return cssValuePool.createIdentifierValue(CSSValueNormal); + + auto valueList = CSSValueList::createSpaceSeparated(); + switch (variant) { + case FontVariantEastAsianVariant::Normal: + break; + case FontVariantEastAsianVariant::Jis78: + valueList->append(cssValuePool.createIdentifierValue(CSSValueJis78)); + break; + case FontVariantEastAsianVariant::Jis83: + valueList->append(cssValuePool.createIdentifierValue(CSSValueJis83)); + break; + case FontVariantEastAsianVariant::Jis90: + valueList->append(cssValuePool.createIdentifierValue(CSSValueJis90)); + break; + case FontVariantEastAsianVariant::Jis04: + valueList->append(cssValuePool.createIdentifierValue(CSSValueJis04)); + break; + case FontVariantEastAsianVariant::Simplified: + valueList->append(cssValuePool.createIdentifierValue(CSSValueSimplified)); + break; + case FontVariantEastAsianVariant::Traditional: + valueList->append(cssValuePool.createIdentifierValue(CSSValueTraditional)); + break; + } + + switch (width) { + case FontVariantEastAsianWidth::Normal: + break; + case FontVariantEastAsianWidth::Full: + valueList->append(cssValuePool.createIdentifierValue(CSSValueFullWidth)); + break; + case FontVariantEastAsianWidth::Proportional: + valueList->append(cssValuePool.createIdentifierValue(CSSValueProportionalWidth)); + break; + } + + if (ruby == FontVariantEastAsianRuby::Yes) + valueList->append(cssValuePool.createIdentifierValue(CSSValueRuby)); + + return WTFMove(valueList); +} + +static Ref delayValue(const AnimationList* animationList) { + auto& cssValuePool = CSSValuePool::singleton(); auto list = CSSValueList::createCommaSeparated(); - if (animList) { - for (size_t i = 0; i < animList->size(); ++i) - list.get().append(cssValuePool().createValue(animList->animation(i).delay(), CSSPrimitiveValue::CSS_S)); + if (animationList) { + for (size_t i = 0; i < animationList->size(); ++i) + list->append(cssValuePool.createValue(animationList->animation(i).delay(), CSSPrimitiveValue::CSS_S)); } else { // Note that initialAnimationDelay() is used for both transitions and animations - list.get().append(cssValuePool().createValue(Animation::initialAnimationDelay(), CSSPrimitiveValue::CSS_S)); + list->append(cssValuePool.createValue(Animation::initialDelay(), CSSPrimitiveValue::CSS_S)); } return list; } -static PassRef getDurationValue(const AnimationList* animList) +static Ref durationValue(const AnimationList* animationList) { + auto& cssValuePool = CSSValuePool::singleton(); auto list = CSSValueList::createCommaSeparated(); - if (animList) { - for (size_t i = 0; i < animList->size(); ++i) - list.get().append(cssValuePool().createValue(animList->animation(i).duration(), CSSPrimitiveValue::CSS_S)); + if (animationList) { + for (size_t i = 0; i < animationList->size(); ++i) + list->append(cssValuePool.createValue(animationList->animation(i).duration(), CSSPrimitiveValue::CSS_S)); } else { // Note that initialAnimationDuration() is used for both transitions and animations - list.get().append(cssValuePool().createValue(Animation::initialAnimationDuration(), CSSPrimitiveValue::CSS_S)); + list->append(cssValuePool.createValue(Animation::initialDuration(), CSSPrimitiveValue::CSS_S)); } return list; } -static PassRefPtr createTimingFunctionValue(const TimingFunction* timingFunction) +static Ref createTimingFunctionValue(const TimingFunction& timingFunction) { - switch (timingFunction->type()) { + switch (timingFunction.type()) { case TimingFunction::CubicBezierFunction: { - const CubicBezierTimingFunction* bezierTimingFunction = static_cast(timingFunction); - if (bezierTimingFunction->timingFunctionPreset() != CubicBezierTimingFunction::Custom) { + auto& function = static_cast(timingFunction); + if (function.timingFunctionPreset() != CubicBezierTimingFunction::Custom) { CSSValueID valueId = CSSValueInvalid; - switch (bezierTimingFunction->timingFunctionPreset()) { + switch (function.timingFunctionPreset()) { case CubicBezierTimingFunction::Ease: valueId = CSSValueEase; break; @@ -1101,63 +1498,110 @@ static PassRefPtr createTimingFunctionValue(const TimingFunction* timi case CubicBezierTimingFunction::EaseOut: valueId = CSSValueEaseOut; break; - case CubicBezierTimingFunction::EaseInOut: + default: + ASSERT(function.timingFunctionPreset() == CubicBezierTimingFunction::EaseInOut); valueId = CSSValueEaseInOut; break; - default: - ASSERT_NOT_REACHED(); - return 0; } - return cssValuePool().createIdentifierValue(valueId); + return CSSValuePool::singleton().createIdentifierValue(valueId); } - return CSSCubicBezierTimingFunctionValue::create(bezierTimingFunction->x1(), bezierTimingFunction->y1(), bezierTimingFunction->x2(), bezierTimingFunction->y2()); + return CSSCubicBezierTimingFunctionValue::create(function.x1(), function.y1(), function.x2(), function.y2()); } case TimingFunction::StepsFunction: { - const StepsTimingFunction* stepsTimingFunction = static_cast(timingFunction); - return CSSStepsTimingFunctionValue::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart()); + auto& function = static_cast(timingFunction); + return CSSStepsTimingFunctionValue::create(function.numberOfSteps(), function.stepAtStart()); } - case TimingFunction::LinearFunction: - return cssValuePool().createIdentifierValue(CSSValueLinear); + case TimingFunction::SpringFunction: { + auto& function = static_cast(timingFunction); + return CSSSpringTimingFunctionValue::create(function.mass(), function.stiffness(), function.damping(), function.initialVelocity()); + } + default: + ASSERT(timingFunction.type() == TimingFunction::LinearFunction); + return CSSValuePool::singleton().createIdentifierValue(CSSValueLinear); } - ASSERT_NOT_REACHED(); - return 0; } -static PassRef getTimingFunctionValue(const AnimationList* animList) +static Ref timingFunctionValue(const AnimationList* animationList) { auto list = CSSValueList::createCommaSeparated(); - if (animList) { - for (size_t i = 0; i < animList->size(); ++i) - list.get().append(createTimingFunctionValue(animList->animation(i).timingFunction().get())); + if (animationList) { + for (size_t i = 0; i < animationList->size(); ++i) + list->append(createTimingFunctionValue(*animationList->animation(i).timingFunction())); } else // Note that initialAnimationTimingFunction() is used for both transitions and animations - list.get().append(createTimingFunctionValue(Animation::initialAnimationTimingFunction().get())); + list->append(createTimingFunctionValue(Animation::initialTimingFunction())); return list; } -static PassRef createLineBoxContainValue(unsigned lineBoxContain) +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + +static Ref createAnimationTriggerValue(const AnimationTrigger& trigger, const RenderStyle& style) +{ + switch (trigger.type()) { + case AnimationTrigger::AnimationTriggerType::ScrollAnimationTriggerType: { + auto& scrollAnimationTrigger = downcast(trigger); + if (scrollAnimationTrigger.endValue().isAuto()) + return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger.startValue(), style)); + return CSSAnimationTriggerScrollValue::create(zoomAdjustedPixelValueForLength(scrollAnimationTrigger.startValue(), style), + zoomAdjustedPixelValueForLength(scrollAnimationTrigger.endValue(), style)); + } + default: + ASSERT(trigger.type() == AnimationTrigger::AnimationTriggerType::AutoAnimationTriggerType); + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); + } +} + +static Ref animationTriggerValue(const AnimationList* animationList, const RenderStyle& style) +{ + auto list = CSSValueList::createCommaSeparated(); + if (animationList) { + for (size_t i = 0; i < animationList->size(); ++i) + list->append(createAnimationTriggerValue(*animationList->animation(i).trigger(), style)); + } else + list->append(createAnimationTriggerValue(Animation::initialTrigger().get(), style)); + return list; +} + +#endif + +static Ref createLineBoxContainValue(unsigned lineBoxContain) { if (!lineBoxContain) - return cssValuePool().createIdentifierValue(CSSValueNone); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); return CSSLineBoxContainValue::create(lineBoxContain); } -ComputedStyleExtractor::ComputedStyleExtractor(PassRefPtr node, bool allowVisitedStyle, PseudoId pseudoElementSpecifier) - : m_node(node) +static Element* styleElementForNode(Node* node) +{ + if (!node) + return nullptr; + if (is(*node)) + return downcast(node); + return composedTreeAncestors(*node).first(); +} + +ComputedStyleExtractor::ComputedStyleExtractor(Node* node, bool allowVisitedStyle, PseudoId pseudoElementSpecifier) + : m_element(styleElementForNode(node)) , m_pseudoElementSpecifier(pseudoElementSpecifier) , m_allowVisitedStyle(allowVisitedStyle) { } +ComputedStyleExtractor::ComputedStyleExtractor(Element* element, bool allowVisitedStyle, PseudoId pseudoElementSpecifier) + : m_element(element) + , m_pseudoElementSpecifier(pseudoElementSpecifier) + , m_allowVisitedStyle(allowVisitedStyle) +{ +} -CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(PassRefPtr n, bool allowVisitedStyle, const String& pseudoElementName) - : m_node(n) +CSSComputedStyleDeclaration::CSSComputedStyleDeclaration(Element& element, bool allowVisitedStyle, const String& pseudoElementName) + : m_element(element) , m_allowVisitedStyle(allowVisitedStyle) , m_refCount(1) { unsigned nameWithoutColonsStart = pseudoElementName[0] == ':' ? (pseudoElementName[1] == ':' ? 2 : 1) : 0; - m_pseudoElementSpecifier = CSSSelector::pseudoId(CSSSelector::parsePseudoType( - AtomicString(pseudoElementName.substring(nameWithoutColonsStart)))); + m_pseudoElementSpecifier = CSSSelector::pseudoId(CSSSelector::parsePseudoElementType( + (pseudoElementName.substringSharingImpl(nameWithoutColonsStart)))); } CSSComputedStyleDeclaration::~CSSComputedStyleDeclaration() @@ -1184,7 +1628,7 @@ String CSSComputedStyleDeclaration::cssText() const if (i) result.append(' '); result.append(getPropertyName(computedProperties[i])); - result.append(": ", 2); + result.appendLiteral(": "); result.append(getPropertyValue(computedProperties[i])); result.append(';'); } @@ -1192,41 +1636,33 @@ String CSSComputedStyleDeclaration::cssText() const return result.toString(); } -void CSSComputedStyleDeclaration::setCssText(const String&, ExceptionCode& ec) -{ - ec = NO_MODIFICATION_ALLOWED_ERR; -} - -static CSSValueID cssIdentifierForFontSizeKeyword(int keywordSize) +ExceptionOr CSSComputedStyleDeclaration::setCssText(const String&) { - ASSERT_ARG(keywordSize, keywordSize); - ASSERT_ARG(keywordSize, keywordSize <= 8); - return static_cast(CSSValueXxSmall + keywordSize - 1); + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -PassRefPtr ComputedStyleExtractor::getFontSizeCSSValuePreferringKeyword() const +RefPtr ComputedStyleExtractor::getFontSizeCSSValuePreferringKeyword() { - if (!m_node) - return 0; + if (!m_element) + return nullptr; - m_node->document().updateLayoutIgnorePendingStylesheets(); + m_element->document().updateLayoutIgnorePendingStylesheets(); - RefPtr style = m_node->computedStyle(m_pseudoElementSpecifier); + auto* style = m_element->computedStyle(m_pseudoElementSpecifier); if (!style) - return 0; + return nullptr; - if (int keywordSize = style->fontDescription().keywordSize()) - return cssValuePool().createIdentifierValue(cssIdentifierForFontSizeKeyword(keywordSize)); + if (CSSValueID sizeIdentifier = style->fontDescription().keywordSizeAsIdentifier()) + return CSSValuePool::singleton().createIdentifierValue(sizeIdentifier); - return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style.get()); + return zoomAdjustedPixelValue(style->fontDescription().computedSize(), *style); } -bool ComputedStyleExtractor::useFixedFontDefaultSize() const +bool ComputedStyleExtractor::useFixedFontDefaultSize() { - if (!m_node) + if (!m_element) return false; - - RefPtr style = m_node->computedStyle(m_pseudoElementSpecifier); + auto* style = m_element->computedStyle(m_pseudoElementSpecifier); if (!style) return false; @@ -1251,277 +1687,549 @@ static CSSValueID identifierForFamily(const AtomicString& family) return CSSValueInvalid; } -static PassRef valueForFamily(const AtomicString& family) +static Ref valueForFamily(const AtomicString& family) { if (CSSValueID familyIdentifier = identifierForFamily(family)) - return cssValuePool().createIdentifierValue(familyIdentifier); - return cssValuePool().createValue(family.string(), CSSPrimitiveValue::CSS_STRING); + return CSSValuePool::singleton().createIdentifierValue(familyIdentifier); + return CSSValuePool::singleton().createFontFamilyValue(family); } -static PassRef renderTextDecorationFlagsToCSSValue(int textDecoration) +static Ref renderTextDecorationFlagsToCSSValue(int textDecoration) { + auto& cssValuePool = CSSValuePool::singleton(); // Blink value is ignored. - RefPtr list = CSSValueList::createSpaceSeparated(); + auto list = CSSValueList::createSpaceSeparated(); if (textDecoration & TextDecorationUnderline) - list->append(cssValuePool().createIdentifierValue(CSSValueUnderline)); + list->append(cssValuePool.createIdentifierValue(CSSValueUnderline)); if (textDecoration & TextDecorationOverline) - list->append(cssValuePool().createIdentifierValue(CSSValueOverline)); + list->append(cssValuePool.createIdentifierValue(CSSValueOverline)); if (textDecoration & TextDecorationLineThrough) - list->append(cssValuePool().createIdentifierValue(CSSValueLineThrough)); + list->append(cssValuePool.createIdentifierValue(CSSValueLineThrough)); #if ENABLE(LETTERPRESS) if (textDecoration & TextDecorationLetterpress) - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitLetterpress)); + list->append(cssValuePool.createIdentifierValue(CSSValueWebkitLetterpress)); #endif if (!list->length()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return list.releaseNonNull(); + return cssValuePool.createIdentifierValue(CSSValueNone); + return WTFMove(list); } -static PassRef renderTextDecorationStyleFlagsToCSSValue(TextDecorationStyle textDecorationStyle) +static Ref renderTextDecorationStyleFlagsToCSSValue(TextDecorationStyle textDecorationStyle) { switch (textDecorationStyle) { case TextDecorationStyleSolid: - return cssValuePool().createIdentifierValue(CSSValueSolid); + return CSSValuePool::singleton().createIdentifierValue(CSSValueSolid); case TextDecorationStyleDouble: - return cssValuePool().createIdentifierValue(CSSValueDouble); + return CSSValuePool::singleton().createIdentifierValue(CSSValueDouble); case TextDecorationStyleDotted: - return cssValuePool().createIdentifierValue(CSSValueDotted); + return CSSValuePool::singleton().createIdentifierValue(CSSValueDotted); case TextDecorationStyleDashed: - return cssValuePool().createIdentifierValue(CSSValueDashed); + return CSSValuePool::singleton().createIdentifierValue(CSSValueDashed); case TextDecorationStyleWavy: - return cssValuePool().createIdentifierValue(CSSValueWavy); + return CSSValuePool::singleton().createIdentifierValue(CSSValueWavy); } ASSERT_NOT_REACHED(); - return cssValuePool().createExplicitInitialValue(); + return CSSValuePool::singleton().createExplicitInitialValue(); } -static PassRef renderTextDecorationSkipFlagsToCSSValue(TextDecorationSkip textDecorationSkip) +static Ref renderTextDecorationSkipFlagsToCSSValue(TextDecorationSkip textDecorationSkip) { switch (textDecorationSkip) { + case TextDecorationSkipAuto: + return CSSValuePool::singleton().createIdentifierValue(CSSValueAuto); case TextDecorationSkipNone: - return cssValuePool().createExplicitInitialValue(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); case TextDecorationSkipInk: - return cssValuePool().createIdentifierValue(CSSValueInk); + return CSSValuePool::singleton().createIdentifierValue(CSSValueInk); + case TextDecorationSkipObjects: + return CSSValuePool::singleton().createIdentifierValue(CSSValueObjects); } ASSERT_NOT_REACHED(); - return cssValuePool().createExplicitInitialValue(); + return CSSValuePool::singleton().createExplicitInitialValue(); } -static PassRef renderEmphasisPositionFlagsToCSSValue(TextEmphasisPosition textEmphasisPosition) +static Ref renderEmphasisPositionFlagsToCSSValue(TextEmphasisPosition textEmphasisPosition) { ASSERT(!((textEmphasisPosition & TextEmphasisPositionOver) && (textEmphasisPosition & TextEmphasisPositionUnder))); ASSERT(!((textEmphasisPosition & TextEmphasisPositionLeft) && (textEmphasisPosition & TextEmphasisPositionRight))); - RefPtr list = CSSValueList::createSpaceSeparated(); + auto& cssValuePool = CSSValuePool::singleton(); + auto list = CSSValueList::createSpaceSeparated(); if (textEmphasisPosition & TextEmphasisPositionOver) - list->append(cssValuePool().createIdentifierValue(CSSValueOver)); + list->append(cssValuePool.createIdentifierValue(CSSValueOver)); if (textEmphasisPosition & TextEmphasisPositionUnder) - list->append(cssValuePool().createIdentifierValue(CSSValueUnder)); + list->append(cssValuePool.createIdentifierValue(CSSValueUnder)); if (textEmphasisPosition & TextEmphasisPositionLeft) - list->append(cssValuePool().createIdentifierValue(CSSValueLeft)); + list->append(cssValuePool.createIdentifierValue(CSSValueLeft)); if (textEmphasisPosition & TextEmphasisPositionRight) - list->append(cssValuePool().createIdentifierValue(CSSValueRight)); - + list->append(cssValuePool.createIdentifierValue(CSSValueRight)); if (!list->length()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return list.releaseNonNull(); + return cssValuePool.createIdentifierValue(CSSValueNone); + return WTFMove(list); } -static PassRef fillRepeatToCSSValue(EFillRepeat xRepeat, EFillRepeat yRepeat) +static Ref hangingPunctuationToCSSValue(HangingPunctuation hangingPunctuation) +{ + auto& cssValuePool = CSSValuePool::singleton(); + auto list = CSSValueList::createSpaceSeparated(); + if (hangingPunctuation & FirstHangingPunctuation) + list->append(cssValuePool.createIdentifierValue(CSSValueFirst)); + if (hangingPunctuation & AllowEndHangingPunctuation) + list->append(cssValuePool.createIdentifierValue(CSSValueAllowEnd)); + if (hangingPunctuation & ForceEndHangingPunctuation) + list->append(cssValuePool.createIdentifierValue(CSSValueForceEnd)); + if (hangingPunctuation & LastHangingPunctuation) + list->append(cssValuePool.createIdentifierValue(CSSValueLast)); + if (!list->length()) + return cssValuePool.createIdentifierValue(CSSValueNone); + return WTFMove(list); +} + +static Ref fillRepeatToCSSValue(EFillRepeat xRepeat, EFillRepeat yRepeat) { // For backwards compatibility, if both values are equal, just return one of them. And // if the two values are equivalent to repeat-x or repeat-y, just return the shorthand. + auto& cssValuePool = CSSValuePool::singleton(); if (xRepeat == yRepeat) - return cssValuePool().createValue(xRepeat); + return cssValuePool.createValue(xRepeat); if (xRepeat == RepeatFill && yRepeat == NoRepeatFill) - return cssValuePool().createIdentifierValue(CSSValueRepeatX); + return cssValuePool.createIdentifierValue(CSSValueRepeatX); if (xRepeat == NoRepeatFill && yRepeat == RepeatFill) - return cssValuePool().createIdentifierValue(CSSValueRepeatY); + return cssValuePool.createIdentifierValue(CSSValueRepeatY); auto list = CSSValueList::createSpaceSeparated(); - list.get().append(cssValuePool().createValue(xRepeat)); - list.get().append(cssValuePool().createValue(yRepeat)); - return std::move(list); + list->append(cssValuePool.createValue(xRepeat)); + list->append(cssValuePool.createValue(yRepeat)); + return WTFMove(list); } -static PassRefPtr fillSourceTypeToCSSValue(EMaskSourceType type) +static Ref fillSourceTypeToCSSValue(EMaskSourceType type) { switch (type) { case MaskAlpha: - return cssValuePool().createValue(CSSValueAlpha); - case MaskLuminance: - return cssValuePool().createValue(CSSValueLuminance); + return CSSValuePool::singleton().createValue(CSSValueAlpha); + default: + ASSERT(type == MaskLuminance); + return CSSValuePool::singleton().createValue(CSSValueLuminance); } - - ASSERT_NOT_REACHED(); - - return 0; } -static PassRef fillSizeToCSSValue(const FillSize& fillSize, const RenderStyle* style) + +static Ref fillSizeToCSSValue(const FillSize& fillSize, const RenderStyle& style) { if (fillSize.type == Contain) - return cssValuePool().createIdentifierValue(CSSValueContain); + return CSSValuePool::singleton().createIdentifierValue(CSSValueContain); if (fillSize.type == Cover) - return cssValuePool().createIdentifierValue(CSSValueCover); + return CSSValuePool::singleton().createIdentifierValue(CSSValueCover); - if (fillSize.size.height().isAuto()) - return zoomAdjustedPixelValueForLength(fillSize.size.width(), style); + if (fillSize.size.height.isAuto()) + return zoomAdjustedPixelValueForLength(fillSize.size.width, style); auto list = CSSValueList::createSpaceSeparated(); - list.get().append(zoomAdjustedPixelValueForLength(fillSize.size.width(), style)); - list.get().append(zoomAdjustedPixelValueForLength(fillSize.size.height(), style)); - return std::move(list); + list->append(zoomAdjustedPixelValueForLength(fillSize.size.width, style)); + list->append(zoomAdjustedPixelValueForLength(fillSize.size.height, style)); + return WTFMove(list); } -static PassRef altTextToCSSValue(const RenderStyle* style) +static Ref altTextToCSSValue(const RenderStyle& style) { - return cssValuePool().createValue(style->contentAltText(), CSSPrimitiveValue::CSS_STRING); + return CSSValuePool::singleton().createValue(style.contentAltText(), CSSPrimitiveValue::CSS_STRING); } -static PassRef contentToCSSValue(const RenderStyle* style) +static Ref contentToCSSValue(const RenderStyle& style) { + auto& cssValuePool = CSSValuePool::singleton(); auto list = CSSValueList::createSpaceSeparated(); - for (const ContentData* contentData = style->contentData(); contentData; contentData = contentData->next()) { - if (contentData->isCounter()) { - const CounterContent* counter = static_cast(contentData)->counter(); - ASSERT(counter); - list.get().append(cssValuePool().createValue(counter->identifier(), CSSPrimitiveValue::CSS_COUNTER_NAME)); - } else if (contentData->isImage()) { - const StyleImage* image = static_cast(contentData)->image(); - ASSERT(image); - list.get().append(image->cssValue()); - } else if (contentData->isText()) - list.get().append(cssValuePool().createValue(static_cast(contentData)->text(), CSSPrimitiveValue::CSS_STRING)); - } - if (style->hasFlowFrom()) - list.get().append(cssValuePool().createValue(style->regionThread(), CSSPrimitiveValue::CSS_STRING)); + for (auto* contentData = style.contentData(); contentData; contentData = contentData->next()) { + if (is(*contentData)) + list->append(cssValuePool.createValue(downcast(*contentData).counter().identifier(), CSSPrimitiveValue::CSS_COUNTER_NAME)); + else if (is(*contentData)) + list->append(downcast(*contentData).image().cssValue()); + else if (is(*contentData)) + list->append(cssValuePool.createValue(downcast(*contentData).text(), CSSPrimitiveValue::CSS_STRING)); + } + if (style.hasFlowFrom()) + list->append(cssValuePool.createValue(style.regionThread(), CSSPrimitiveValue::CSS_STRING)); return list; } -static PassRefPtr counterToCSSValue(const RenderStyle* style, CSSPropertyID propertyID) +static Ref counterToCSSValue(const RenderStyle& style, CSSPropertyID propertyID) { - const CounterDirectiveMap* map = style->counterDirectives(); + auto* map = style.counterDirectives(); if (!map) - return 0; + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); - RefPtr list = CSSValueList::createSpaceSeparated(); + auto& cssValuePool = CSSValuePool::singleton(); + auto list = CSSValueList::createSpaceSeparated(); for (CounterDirectiveMap::const_iterator it = map->begin(); it != map->end(); ++it) { - list->append(cssValuePool().createValue(it->key, CSSPrimitiveValue::CSS_STRING)); + list->append(cssValuePool.createValue(it->key, CSSPrimitiveValue::CSS_STRING)); short number = propertyID == CSSPropertyCounterIncrement ? it->value.incrementValue() : it->value.resetValue(); - list->append(cssValuePool().createValue((double)number, CSSPrimitiveValue::CSS_NUMBER)); + list->append(cssValuePool.createValue((double)number, CSSPrimitiveValue::CSS_NUMBER)); } - return list.release(); + return WTFMove(list); } static void logUnimplementedPropertyID(CSSPropertyID propertyID) { - DEFINE_STATIC_LOCAL(HashSet, propertyIDSet, ()); - if (!propertyIDSet.add(propertyID).isNewEntry) + static NeverDestroyed> propertyIDSet; + if (!propertyIDSet.get().add(propertyID).isNewEntry) return; LOG_ERROR("WebKit does not yet implement getComputedStyle for '%s'.", getPropertyName(propertyID)); } -static PassRef fontFamilyFromStyle(RenderStyle* style) -{ - auto list = CSSValueList::createCommaSeparated(); - for (unsigned i = 0; i < style->font().familyCount(); ++i) - list.get().append(valueForFamily(style->font().familyAt(i))); - return list; -} +static Ref fontFamilyListFromStyle(const RenderStyle& style) +{ + auto list = CSSValueList::createCommaSeparated(); + for (unsigned i = 0; i < style.fontCascade().familyCount(); ++i) + list->append(valueForFamily(style.fontCascade().familyAt(i))); + return list; +} + +static Ref fontFamilyFromStyle(const RenderStyle& style) +{ + if (style.fontCascade().familyCount() == 1) + return valueForFamily(style.fontCascade().familyAt(0)); + return fontFamilyListFromStyle(style); +} + +static Ref lineHeightFromStyle(const RenderStyle& style) +{ + Length length = style.lineHeight(); + if (length.isNegative()) // If true, line-height not set; use the font's line spacing. + return zoomAdjustedPixelValue(style.fontMetrics().floatLineSpacing(), style); + if (length.isPercent()) { + // This is imperfect, because it doesn't include the zoom factor and the real computation + // for how high to be in pixels does include things like minimum font size and the zoom factor. + // On the other hand, since font-size doesn't include the zoom factor, we really can't do + // that here either. + return zoomAdjustedPixelValue(static_cast(length.percent() * style.fontDescription().specifiedSize()) / 100, style); + } + return zoomAdjustedPixelValue(floatValueForLength(length, 0), style); +} + +static Ref fontSizeFromStyle(const RenderStyle& style) +{ + return zoomAdjustedPixelValue(style.fontDescription().computedSize(), style); +} + +static Ref fontStyleFromStyle(const RenderStyle& style) +{ + if (style.fontDescription().italic()) + return CSSValuePool::singleton().createIdentifierValue(CSSValueItalic); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); +} + +static Ref fontVariantFromStyle(const RenderStyle& style) +{ + if (style.fontDescription().variantSettings().isAllNormal()) + return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); + + auto list = CSSValueList::createSpaceSeparated(); + + switch (style.fontDescription().variantCommonLigatures()) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueCommonLigatures)); + break; + case FontVariantLigatures::No: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoCommonLigatures)); + break; + } + + switch (style.fontDescription().variantDiscretionaryLigatures()) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiscretionaryLigatures)); + break; + case FontVariantLigatures::No: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoDiscretionaryLigatures)); + break; + } + + switch (style.fontDescription().variantHistoricalLigatures()) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalLigatures)); + break; + case FontVariantLigatures::No: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoHistoricalLigatures)); + break; + } + + switch (style.fontDescription().variantContextualAlternates()) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueContextual)); + break; + case FontVariantLigatures::No: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoContextual)); + break; + } + + switch (style.fontDescription().variantPosition()) { + case FontVariantPosition::Normal: + break; + case FontVariantPosition::Subscript: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSub)); + break; + case FontVariantPosition::Superscript: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSuper)); + break; + } + + switch (style.fontDescription().variantCaps()) { + case FontVariantCaps::Normal: + break; + case FontVariantCaps::Small: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSmallCaps)); + break; + case FontVariantCaps::AllSmall: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueAllSmallCaps)); + break; + case FontVariantCaps::Petite: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValuePetiteCaps)); + break; + case FontVariantCaps::AllPetite: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueAllPetiteCaps)); + break; + case FontVariantCaps::Unicase: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueUnicase)); + break; + case FontVariantCaps::Titling: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueTitlingCaps)); + break; + } + + switch (style.fontDescription().variantNumericFigure()) { + case FontVariantNumericFigure::Normal: + break; + case FontVariantNumericFigure::LiningNumbers: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueLiningNums)); + break; + case FontVariantNumericFigure::OldStyleNumbers: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueOldstyleNums)); + break; + } + + switch (style.fontDescription().variantNumericSpacing()) { + case FontVariantNumericSpacing::Normal: + break; + case FontVariantNumericSpacing::ProportionalNumbers: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalNums)); + break; + case FontVariantNumericSpacing::TabularNumbers: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueTabularNums)); + break; + } + + switch (style.fontDescription().variantNumericFraction()) { + case FontVariantNumericFraction::Normal: + break; + case FontVariantNumericFraction::DiagonalFractions: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiagonalFractions)); + break; + case FontVariantNumericFraction::StackedFractions: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueStackedFractions)); + break; + } + + switch (style.fontDescription().variantNumericOrdinal()) { + case FontVariantNumericOrdinal::Normal: + break; + case FontVariantNumericOrdinal::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueOrdinal)); + break; + } + + switch (style.fontDescription().variantNumericSlashedZero()) { + case FontVariantNumericSlashedZero::Normal: + break; + case FontVariantNumericSlashedZero::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSlashedZero)); + break; + } + + switch (style.fontDescription().variantAlternates()) { + case FontVariantAlternates::Normal: + break; + case FontVariantAlternates::HistoricalForms: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalForms)); + break; + } -static PassRef lineHeightFromStyle(RenderStyle* style, RenderView* renderView) -{ - Length length = style->lineHeight(); - if (length.isNegative()) - return cssValuePool().createIdentifierValue(CSSValueNormal); - if (length.isPercent()) - // This is imperfect, because it doesn't include the zoom factor and the real computation - // for how high to be in pixels does include things like minimum font size and the zoom factor. - // On the other hand, since font-size doesn't include the zoom factor, we really can't do - // that here either. - return zoomAdjustedPixelValue(static_cast(length.percent() * style->fontDescription().specifiedSize()) / 100, style); - return zoomAdjustedPixelValue(floatValueForLength(length, 0, renderView), style); -} + switch (style.fontDescription().variantEastAsianVariant()) { + case FontVariantEastAsianVariant::Normal: + break; + case FontVariantEastAsianVariant::Jis78: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis78)); + break; + case FontVariantEastAsianVariant::Jis83: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis83)); + break; + case FontVariantEastAsianVariant::Jis90: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis90)); + break; + case FontVariantEastAsianVariant::Jis04: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis04)); + break; + case FontVariantEastAsianVariant::Simplified: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSimplified)); + break; + case FontVariantEastAsianVariant::Traditional: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueTraditional)); + break; + } -static PassRef fontSizeFromStyle(RenderStyle* style) -{ - return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), style); -} + switch (style.fontDescription().variantEastAsianWidth()) { + case FontVariantEastAsianWidth::Normal: + break; + case FontVariantEastAsianWidth::Full: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueFullWidth)); + break; + case FontVariantEastAsianWidth::Proportional: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalWidth)); + break; + } -static PassRef fontStyleFromStyle(RenderStyle* style) -{ - if (style->fontDescription().italic()) - return cssValuePool().createIdentifierValue(CSSValueItalic); - return cssValuePool().createIdentifierValue(CSSValueNormal); -} + switch (style.fontDescription().variantEastAsianRuby()) { + case FontVariantEastAsianRuby::Normal: + break; + case FontVariantEastAsianRuby::Yes: + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueRuby)); + break; + } -static PassRef fontVariantFromStyle(RenderStyle* style) -{ - if (style->fontDescription().smallCaps()) - return cssValuePool().createIdentifierValue(CSSValueSmallCaps); - return cssValuePool().createIdentifierValue(CSSValueNormal); + return WTFMove(list); } -static PassRef fontWeightFromStyle(RenderStyle* style) +static Ref fontWeightFromStyle(const RenderStyle& style) { - switch (style->fontDescription().weight()) { + switch (style.fontDescription().weight()) { case FontWeight100: - return cssValuePool().createIdentifierValue(CSSValue100); + return CSSValuePool::singleton().createIdentifierValue(CSSValue100); case FontWeight200: - return cssValuePool().createIdentifierValue(CSSValue200); + return CSSValuePool::singleton().createIdentifierValue(CSSValue200); case FontWeight300: - return cssValuePool().createIdentifierValue(CSSValue300); + return CSSValuePool::singleton().createIdentifierValue(CSSValue300); case FontWeightNormal: - return cssValuePool().createIdentifierValue(CSSValueNormal); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); case FontWeight500: - return cssValuePool().createIdentifierValue(CSSValue500); + return CSSValuePool::singleton().createIdentifierValue(CSSValue500); case FontWeight600: - return cssValuePool().createIdentifierValue(CSSValue600); + return CSSValuePool::singleton().createIdentifierValue(CSSValue600); case FontWeightBold: - return cssValuePool().createIdentifierValue(CSSValueBold); + return CSSValuePool::singleton().createIdentifierValue(CSSValueBold); case FontWeight800: - return cssValuePool().createIdentifierValue(CSSValue800); + return CSSValuePool::singleton().createIdentifierValue(CSSValue800); case FontWeight900: - return cssValuePool().createIdentifierValue(CSSValue900); + return CSSValuePool::singleton().createIdentifierValue(CSSValue900); } ASSERT_NOT_REACHED(); - return cssValuePool().createIdentifierValue(CSSValueNormal); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); +} + +static Ref fontSynthesisFromStyle(const RenderStyle& style) +{ + if (style.fontDescription().fontSynthesis() == FontSynthesisNone) + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + + auto list = CSSValueList::createSpaceSeparated(); + if (style.fontDescription().fontSynthesis() & FontSynthesisStyle) + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueStyle)); + if (style.fontDescription().fontSynthesis() & FontSynthesisWeight) + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueWeight)); + if (style.fontDescription().fontSynthesis() & FontSynthesisSmallCaps) + list->append(CSSValuePool::singleton().createIdentifierValue(CSSValueSmallCaps)); + return WTFMove(list); } typedef const Length& (RenderStyle::*RenderStyleLengthGetter)() const; typedef LayoutUnit (RenderBoxModelObject::*RenderBoxComputedCSSValueGetter)() const; template -inline PassRefPtr zoomAdjustedPaddingOrMarginPixelValue(RenderStyle* style, RenderObject* renderer) +static RefPtr zoomAdjustedPaddingOrMarginPixelValue(const RenderStyle& style, RenderObject* renderer) { - Length unzoomzedLength = (style->*lengthGetter)(); - if (!renderer || !renderer->isBox() || unzoomzedLength.isFixed()) + Length unzoomzedLength = (style.*lengthGetter)(); + if (!is(renderer) || unzoomzedLength.isFixed()) return zoomAdjustedPixelValueForLength(unzoomzedLength, style); - return zoomAdjustedPixelValue((toRenderBox(renderer)->*computedCSSValueGetter)(), style); + return zoomAdjustedPixelValue((downcast(*renderer).*computedCSSValueGetter)(), style); } template -inline bool paddingOrMarginIsRendererDependent(RenderStyle* style, RenderObject* renderer) +static bool paddingOrMarginIsRendererDependent(const RenderStyle* style, RenderObject* renderer) { - if (!renderer || !renderer->isBox()) - return false; - return !(style && (style->*lengthGetter)().isFixed()); + return renderer && style && renderer->isBox() && !(style->*lengthGetter)().isFixed(); +} + +static CSSValueID convertToPageBreak(BreakBetween value) +{ + if (value == PageBreakBetween || value == LeftPageBreakBetween || value == RightPageBreakBetween + || value == RectoPageBreakBetween || value == VersoPageBreakBetween) + return CSSValueAlways; // CSS 2.1 allows us to map these to always. + if (value == AvoidBreakBetween || value == AvoidPageBreakBetween) + return CSSValueAvoid; + return CSSValueAuto; +} + +static CSSValueID convertToColumnBreak(BreakBetween value) +{ + if (value == ColumnBreakBetween) + return CSSValueAlways; + if (value == AvoidBreakBetween || value == AvoidColumnBreakBetween) + return CSSValueAvoid; + return CSSValueAuto; +} + +static CSSValueID convertToPageBreak(BreakInside value) +{ + if (value == AvoidBreakInside || value == AvoidPageBreakInside) + return CSSValueAvoid; + return CSSValueAuto; +} + +static CSSValueID convertToColumnBreak(BreakInside value) +{ + if (value == AvoidBreakInside || value == AvoidColumnBreakInside) + return CSSValueAvoid; + return CSSValueAuto; } -static bool isLayoutDependent(CSSPropertyID propertyID, RenderStyle* style, RenderObject* renderer) +#if ENABLE(CSS_REGIONS) +static CSSValueID convertToRegionBreak(BreakBetween value) +{ + if (value == RegionBreakBetween) + return CSSValueAlways; + if (value == AvoidBreakBetween || value == AvoidRegionBreakBetween) + return CSSValueAvoid; + return CSSValueAuto; +} + +static CSSValueID convertToRegionBreak(BreakInside value) +{ + if (value == AvoidBreakInside || value == AvoidRegionBreakInside) + return CSSValueAvoid; + return CSSValueAuto; +} +#endif + +static bool isLayoutDependent(CSSPropertyID propertyID, const RenderStyle* style, RenderObject* renderer) { switch (propertyID) { case CSSPropertyWidth: case CSSPropertyHeight: - case CSSPropertyWebkitPerspectiveOrigin: - case CSSPropertyWebkitTransformOrigin: - case CSSPropertyWebkitTransform: -#if ENABLE(CSS_FILTERS) - case CSSPropertyWebkitFilter: + case CSSPropertyPerspectiveOrigin: + case CSSPropertyTransformOrigin: + case CSSPropertyTransform: + case CSSPropertyFilter: +#if ENABLE(FILTERS_LEVEL_2) + case CSSPropertyWebkitBackdropFilter: #endif return true; case CSSPropertyMargin: { @@ -1552,136 +2260,325 @@ static bool isLayoutDependent(CSSPropertyID propertyID, RenderStyle* style, Rend return paddingOrMarginIsRendererDependent<&RenderStyle::paddingBottom>(style, renderer); case CSSPropertyPaddingLeft: return paddingOrMarginIsRendererDependent<&RenderStyle::paddingLeft>(style, renderer); + case CSSPropertyGridTemplateColumns: + case CSSPropertyGridTemplateRows: + case CSSPropertyGridTemplate: + case CSSPropertyGrid: + return renderer && renderer->isRenderGrid(); default: return false; } } -Node* ComputedStyleExtractor::styledNode() const +Element* ComputedStyleExtractor::styledElement() { - if (!m_node) - return 0; - if (!m_node->isElementNode()) - return m_node.get(); - Element* element = toElement(m_node.get()); + if (!m_element) + return nullptr; PseudoElement* pseudoElement; - if (m_pseudoElementSpecifier == BEFORE && (pseudoElement = element->beforePseudoElement())) + if (m_pseudoElementSpecifier == BEFORE && (pseudoElement = m_element->beforePseudoElement())) return pseudoElement; - if (m_pseudoElementSpecifier == AFTER && (pseudoElement = element->afterPseudoElement())) + if (m_pseudoElementSpecifier == AFTER && (pseudoElement = m_element->afterPseudoElement())) return pseudoElement; - return element; + return m_element.get(); +} + +static StyleSelfAlignmentData resolveLegacyJustifyItems(const StyleSelfAlignmentData& data) +{ + if (data.positionType() == LegacyPosition) + return { data.position(), OverflowAlignmentDefault }; + return data; } -PassRefPtr CSSComputedStyleDeclaration::getPropertyCSSValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const +static StyleSelfAlignmentData resolveJustifyItemsAuto(const StyleSelfAlignmentData& data, Node* parent) { - return ComputedStyleExtractor(m_node, m_allowVisitedStyle, m_pseudoElementSpecifier).propertyValue(propertyID, updateLayout); + if (data.position() != ItemPositionAuto) + return data; + + // If the inherited value of justify-items includes the 'legacy' keyword, 'auto' computes to the inherited value. + const auto& inheritedValue = (!parent || !parent->computedStyle()) ? RenderStyle::initialDefaultAlignment() : parent->computedStyle()->justifyItems(); + if (inheritedValue.positionType() == LegacyPosition) + return inheritedValue; + if (inheritedValue.position() == ItemPositionAuto) + return resolveJustifyItemsAuto(inheritedValue, parent->parentNode()); + return { ItemPositionNormal, OverflowAlignmentDefault }; } -PassRef CSSComputedStyleDeclaration::copyProperties() const +static StyleSelfAlignmentData resolveJustifySelfAuto(const StyleSelfAlignmentData& data, Node* parent) { - return ComputedStyleExtractor(m_node, m_allowVisitedStyle, m_pseudoElementSpecifier).copyProperties(); + if (data.position() != ItemPositionAuto) + return data; + + // The 'auto' keyword computes to the computed value of justify-items on the parent or 'normal' if the box has no parent. + if (!parent || !parent->computedStyle()) + return { ItemPositionNormal, OverflowAlignmentDefault }; + return resolveLegacyJustifyItems(resolveJustifyItemsAuto(parent->computedStyle()->justifyItems(), parent->parentNode())); +} + +static StyleSelfAlignmentData resolveAlignSelfAuto(const StyleSelfAlignmentData& data, Node* parent) +{ + if (data.position() != ItemPositionAuto) + return data; + + // The 'auto' keyword computes to the computed value of align-items on the parent or 'normal' if the box has no parent. + if (!parent || !parent->computedStyle()) + return { ItemPositionNormal, OverflowAlignmentDefault }; + return parent->computedStyle()->alignItems(); } -static inline bool nodeOrItsAncestorNeedsStyleRecalc(Node* styledNode) +static bool isImplicitlyInheritedGridOrFlexProperty(CSSPropertyID propertyID) { - if (styledNode->document().hasPendingForcedStyleRecalc()) + // It would be nice if grid and flex worked within normal CSS mechanisms and not invented their own inheritance system. + switch (propertyID) { + case CSSPropertyAlignSelf: + case CSSPropertyJustifySelf: + case CSSPropertyJustifyItems: + // FIXME: In StyleResolver::adjustRenderStyle z-index is adjusted based on the parent display property for grid/flex. + case CSSPropertyZIndex: return true; - for (Node* n = styledNode; n; n = n->parentNode()) {// FIXME: Call parentOrShadowHostNode() instead - if (n->needsStyleRecalc()) - return true; + default: + return false; } - return false; } -static inline PassRefPtr computeRenderStyleForProperty(Node* styledNode, PseudoId pseudoElementSpecifier, CSSPropertyID propertyID) +RefPtr CSSComputedStyleDeclaration::getPropertyCSSValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const +{ + return ComputedStyleExtractor(m_element.ptr(), m_allowVisitedStyle, m_pseudoElementSpecifier).propertyValue(propertyID, updateLayout); +} + +Ref CSSComputedStyleDeclaration::copyProperties() const +{ + return ComputedStyleExtractor(m_element.ptr(), m_allowVisitedStyle, m_pseudoElementSpecifier).copyProperties(); +} + +static inline bool hasValidStyleForProperty(Element& element, CSSPropertyID propertyID) +{ + if (element.styleValidity() != Style::Validity::Valid) + return false; + if (element.document().hasPendingForcedStyleRecalc()) + return false; + if (!element.document().childNeedsStyleRecalc()) + return true; + + bool isInherited = CSSProperty::isInheritedProperty(propertyID) || isImplicitlyInheritedGridOrFlexProperty(propertyID); + bool maybeExplicitlyInherited = !isInherited; + + const auto* currentElement = &element; + for (auto& ancestor : composedTreeAncestors(element)) { + if (ancestor.styleValidity() >= Style::Validity::SubtreeInvalid) + return false; + + if (maybeExplicitlyInherited) { + auto* style = currentElement->renderStyle(); + maybeExplicitlyInherited = !style || style->hasExplicitlyInheritedProperties(); + } + + if ((isInherited || maybeExplicitlyInherited) && ancestor.styleValidity() == Style::Validity::ElementInvalid) + return false; + + if (ancestor.directChildNeedsStyleRecalc() && currentElement->styleIsAffectedByPreviousSibling()) + return false; + + currentElement = &ancestor; + } + + return true; +} + +static bool updateStyleIfNeededForProperty(Element& element, CSSPropertyID propertyID) +{ + auto& document = element.document(); + + document.styleScope().flushPendingUpdate(); + + if (hasValidStyleForProperty(element, propertyID)) + return false; + + document.updateStyleIfNeeded(); + return true; +} + +static inline const RenderStyle* computeRenderStyleForProperty(Element& element, PseudoId pseudoElementSpecifier, CSSPropertyID propertyID, std::unique_ptr& ownedStyle) { - RenderObject* renderer = styledNode->renderer(); + auto* renderer = element.renderer(); - if (renderer && renderer->isComposited() && AnimationController::supportsAcceleratedAnimationOfProperty(propertyID)) { - AnimationUpdateBlock animationUpdateBlock(&renderer->animation()); - RefPtr style = renderer->animation().getAnimatedStyleForRenderer(toRenderElement(renderer)); - if (pseudoElementSpecifier && !styledNode->isPseudoElement()) { + if (renderer && renderer->isComposited() && CSSAnimationController::supportsAcceleratedAnimationOfProperty(propertyID)) { + ownedStyle = renderer->animation().getAnimatedStyleForRenderer(*renderer); + if (pseudoElementSpecifier && !element.isPseudoElement()) { // FIXME: This cached pseudo style will only exist if the animation has been run at least once. - return style->getCachedPseudoStyle(pseudoElementSpecifier); + return ownedStyle->getCachedPseudoStyle(pseudoElementSpecifier); } - return style.release(); + return ownedStyle.get(); } - return styledNode->computedStyle(styledNode->isPseudoElement() ? NOPSEUDO : pseudoElementSpecifier); + return element.computedStyle(element.isPseudoElement() ? NOPSEUDO : pseudoElementSpecifier); } -#if ENABLE(CSS_SHAPES) -static PassRefPtr shapePropertyValue(const RenderStyle* style, const ShapeValue* shapeValue) +static Ref shapePropertyValue(const RenderStyle& style, const ShapeValue* shapeValue) { if (!shapeValue) - return cssValuePool().createIdentifierValue(CSSValueNone); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); - if (shapeValue->type() == ShapeValue::Outside) - return cssValuePool().createIdentifierValue(CSSValueOutsideShape); + if (shapeValue->type() == ShapeValue::Type::Box) + return CSSValuePool::singleton().createValue(shapeValue->cssBox()); - if (shapeValue->type() == ShapeValue::Box) - return cssValuePool().createValue(shapeValue->layoutBox()); + if (shapeValue->type() == ShapeValue::Type::Image) { + if (shapeValue->image()) + return shapeValue->image()->cssValue(); + return CSSValuePool::singleton().createIdentifierValue(CSSValueNone); + } - if (shapeValue->type() == ShapeValue::Image) - return shapeValue->image() ? shapeValue->image()->cssValue() : cssValuePool().createIdentifierValue(CSSValueNone); + ASSERT(shapeValue->type() == ShapeValue::Type::Shape); - ASSERT(shapeValue->type() == ShapeValue::Shape); + auto list = CSSValueList::createSpaceSeparated(); + list->append(valueForBasicShape(style, *shapeValue->shape())); + if (shapeValue->cssBox() != BoxMissing) + list->append(CSSValuePool::singleton().createValue(shapeValue->cssBox())); + return WTFMove(list); +} - RefPtr list = CSSValueList::createSpaceSeparated(); - list->append(valueForBasicShape(style, shapeValue->shape())); - if (shapeValue->layoutBox() != BoxMissing) - list->append(cssValuePool().createValue(shapeValue->layoutBox())); - return list.release(); +static Ref valueForItemPositionWithOverflowAlignment(const StyleSelfAlignmentData& data) +{ + auto& cssValuePool = CSSValuePool::singleton(); + auto result = CSSValueList::createSpaceSeparated(); + if (data.positionType() == LegacyPosition) + result->append(cssValuePool.createIdentifierValue(CSSValueLegacy)); + result->append(cssValuePool.createValue(data.position())); + if (data.position() >= ItemPositionCenter && data.overflow() != OverflowAlignmentDefault) + result->append(cssValuePool.createValue(data.overflow())); + ASSERT(result->length() <= 2); + return result; } -#endif -PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const +static Ref valueForContentPositionAndDistributionWithOverflowAlignment(const StyleContentAlignmentData& data, CSSValueID normalBehaviorValueID) { - Node* styledNode = this->styledNode(); - if (!styledNode) - return 0; + auto& cssValuePool = CSSValuePool::singleton(); + auto result = CSSValueList::createSpaceSeparated(); + if (data.distribution() != ContentDistributionDefault) + result->append(cssValuePool.createValue(data.distribution())); + if (data.distribution() == ContentDistributionDefault || data.position() != ContentPositionNormal) { + bool gridEnabled = false; + gridEnabled = RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled(); + if (data.position() != ContentPositionNormal || gridEnabled) + result->append(cssValuePool.createValue(data.position())); + else + result->append(cssValuePool.createIdentifierValue(normalBehaviorValueID)); + } + if ((data.position() >= ContentPositionCenter || data.distribution() != ContentDistributionDefault) && data.overflow() != OverflowAlignmentDefault) + result->append(cssValuePool.createValue(data.overflow())); + ASSERT(result->length() > 0); + ASSERT(result->length() <= 3); + return result; +} + +static Ref paintOrder(PaintOrder paintOrder) +{ + if (paintOrder == PaintOrderNormal) + return CSSPrimitiveValue::createIdentifier(CSSValueNormal); + + auto paintOrderList = CSSValueList::createSpaceSeparated(); + switch (paintOrder) { + case PaintOrderNormal: + ASSERT_NOT_REACHED(); + break; + case PaintOrderFill: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueFill)); + break; + case PaintOrderFillMarkers: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueFill)); + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers)); + break; + case PaintOrderStroke: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke)); + break; + case PaintOrderStrokeMarkers: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke)); + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers)); + break; + case PaintOrderMarkers: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers)); + break; + case PaintOrderMarkersStroke: + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers)); + paintOrderList->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke)); + break; + } + return WTFMove(paintOrderList); +} + +inline static bool isFlexOrGrid(ContainerNode* element) +{ + return element && element->computedStyle() && element->computedStyle()->isDisplayFlexibleOrGridBox(); +} - RefPtr style; - RenderObject* renderer = 0; +RefPtr ComputedStyleExtractor::customPropertyValue(const String& propertyName) +{ + Element* styledElement = this->styledElement(); + if (!styledElement) + return nullptr; + + if (updateStyleIfNeededForProperty(*styledElement, CSSPropertyCustom)) { + // Style update may change styledElement() to PseudoElement or back. + styledElement = this->styledElement(); + } + + std::unique_ptr ownedStyle; + auto* style = computeRenderStyleForProperty(*styledElement, m_pseudoElementSpecifier, CSSPropertyCustom, ownedStyle); + if (!style) + return nullptr; + + return style->customProperties().get(propertyName); +} + +String ComputedStyleExtractor::customPropertyText(const String& propertyName) +{ + RefPtr propertyValue = customPropertyValue(propertyName); + return propertyValue ? propertyValue->cssText() : emptyString(); +} + +RefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) +{ + auto* styledElement = this->styledElement(); + if (!styledElement) + return nullptr; + + std::unique_ptr ownedStyle; + const RenderStyle* style = nullptr; + RenderObject* renderer = nullptr; bool forceFullLayout = false; if (updateLayout) { - Document& document = styledNode->document(); + Document& document = m_element->document(); - if (nodeOrItsAncestorNeedsStyleRecalc(styledNode)) { - document.updateStyleIfNeeded(); - // The style recalc could have caused the styled node to be discarded or replaced - // if it was a PseudoElement so we need to update it. - styledNode = this->styledNode(); + if (updateStyleIfNeededForProperty(*styledElement, propertyID)) { + // Style update may change styledElement() to PseudoElement or back. + styledElement = this->styledElement(); } + renderer = styledElement->renderer(); - renderer = styledNode->renderer(); - -#if ENABLE(SVG) - if (propertyID == CSSPropertyDisplay && !renderer && isSVGElement(*styledNode) && !toSVGElement(*styledNode).isValid()) + if (propertyID == CSSPropertyDisplay && !renderer && is(*styledElement) && !downcast(*styledElement).isValid()) return nullptr; -#endif - style = computeRenderStyleForProperty(styledNode, m_pseudoElementSpecifier, propertyID); + + style = computeRenderStyleForProperty(*styledElement, m_pseudoElementSpecifier, propertyID, ownedStyle); // FIXME: Some of these cases could be narrowed down or optimized better. - forceFullLayout = isLayoutDependent(propertyID, style.get(), renderer) - || styledNode->isInShadowTree() - || (document.styleResolverIfExists() && document.styleResolverIfExists()->hasViewportDependentMediaQueries() && document.ownerElement()) - || document.seamlessParentIFrame(); + forceFullLayout = isLayoutDependent(propertyID, style, renderer) + || styledElement->isInShadowTree() + || (document.styleScope().resolverIfExists() && document.styleScope().resolverIfExists()->hasViewportDependentMediaQueries() && document.ownerElement()); if (forceFullLayout) { document.updateLayoutIgnorePendingStylesheets(); - styledNode = this->styledNode(); + styledElement = this->styledElement(); } } if (!updateLayout || forceFullLayout) { - style = computeRenderStyleForProperty(styledNode, m_pseudoElementSpecifier, propertyID); - renderer = styledNode->renderer(); + style = computeRenderStyleForProperty(*styledElement, m_pseudoElementSpecifier, propertyID, ownedStyle); + renderer = styledElement->renderer(); } if (!style) - return 0; + return nullptr; + auto& cssValuePool = CSSValuePool::singleton(); propertyID = CSSProperty::resolveDirectionAwareProperty(propertyID, style->direction(), style->writingMode()); switch (propertyID) { @@ -1689,91 +2586,72 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert break; case CSSPropertyBackgroundColor: - return cssValuePool().createColorValue(m_allowVisitedStyle? style->visitedDependentColor(CSSPropertyBackgroundColor).rgb() : style->backgroundColor().rgb()); + return cssValuePool.createColorValue(m_allowVisitedStyle? style->visitedDependentColor(CSSPropertyBackgroundColor) : style->backgroundColor()); case CSSPropertyBackgroundImage: case CSSPropertyWebkitMaskImage: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskImage ? style->maskLayers() : style->backgroundLayers(); - if (!layers) - return cssValuePool().createIdentifierValue(CSSValueNone); - - if (!layers->next()) { - if (layers->image()) - return layers->image()->cssValue(); - - return cssValuePool().createIdentifierValue(CSSValueNone); + auto& layers = propertyID == CSSPropertyWebkitMaskImage ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) { + if (layers.image()) + return layers.image()->cssValue(); + return cssValuePool.createIdentifierValue(CSSValueNone); } - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) { if (currLayer->image()) list->append(currLayer->image()->cssValue()); else - list->append(cssValuePool().createIdentifierValue(CSSValueNone)); + list->append(cssValuePool.createIdentifierValue(CSSValueNone)); } - return list.release(); + return WTFMove(list); } case CSSPropertyBackgroundSize: case CSSPropertyWebkitBackgroundSize: case CSSPropertyWebkitMaskSize: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskSize ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return fillSizeToCSSValue(layers->size(), style.get()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(fillSizeToCSSValue(currLayer->size(), style.get())); - - return list.release(); + auto& layers = propertyID == CSSPropertyWebkitMaskSize ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return fillSizeToCSSValue(layers.size(), *style); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(fillSizeToCSSValue(currLayer->size(), *style)); + return WTFMove(list); } case CSSPropertyBackgroundRepeat: case CSSPropertyWebkitMaskRepeat: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskRepeat ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return fillRepeatToCSSValue(layers->repeatX(), layers->repeatY()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + auto& layers = propertyID == CSSPropertyWebkitMaskRepeat ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return fillRepeatToCSSValue(layers.repeatX(), layers.repeatY()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) list->append(fillRepeatToCSSValue(currLayer->repeatX(), currLayer->repeatY())); - - return list.release(); + return WTFMove(list); } case CSSPropertyWebkitMaskSourceType: { - const FillLayer* layers = style->maskLayers(); - - if (!layers) - return cssValuePool().createIdentifierValue(CSSValueNone); - - if (!layers->next()) - return fillSourceTypeToCSSValue(layers->maskSourceType()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) + auto& layers = style->maskLayers(); + if (!layers.next()) + return fillSourceTypeToCSSValue(layers.maskSourceType()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) list->append(fillSourceTypeToCSSValue(currLayer->maskSourceType())); - - return list.release(); + return WTFMove(list); } case CSSPropertyWebkitBackgroundComposite: case CSSPropertyWebkitMaskComposite: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskComposite ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return cssValuePool().createValue(layers->composite()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(cssValuePool().createValue(currLayer->composite())); - - return list.release(); + auto& layers = propertyID == CSSPropertyWebkitMaskComposite ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return cssValuePool.createValue(layers.composite()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(currLayer->composite())); + return WTFMove(list); } case CSSPropertyBackgroundAttachment: { - const FillLayer* layers = style->backgroundLayers(); - if (!layers->next()) - return cssValuePool().createValue(layers->attachment()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(cssValuePool().createValue(currLayer->attachment())); - - return list.release(); + auto& layers = style->backgroundLayers(); + if (!layers.next()) + return cssValuePool.createValue(layers.attachment()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(currLayer->attachment())); + return WTFMove(list); } case CSSPropertyBackgroundClip: case CSSPropertyBackgroundOrigin: @@ -1781,327 +2659,348 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyWebkitBackgroundOrigin: case CSSPropertyWebkitMaskClip: case CSSPropertyWebkitMaskOrigin: { - const FillLayer* layers = (propertyID == CSSPropertyWebkitMaskClip || propertyID == CSSPropertyWebkitMaskOrigin) ? style->maskLayers() : style->backgroundLayers(); + auto& layers = (propertyID == CSSPropertyWebkitMaskClip || propertyID == CSSPropertyWebkitMaskOrigin) ? style->maskLayers() : style->backgroundLayers(); bool isClip = propertyID == CSSPropertyBackgroundClip || propertyID == CSSPropertyWebkitBackgroundClip || propertyID == CSSPropertyWebkitMaskClip; - if (!layers->next()) { - EFillBox box = isClip ? layers->clip() : layers->origin(); - return cssValuePool().createValue(box); - } - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) { - EFillBox box = isClip ? currLayer->clip() : currLayer->origin(); - list->append(cssValuePool().createValue(box)); - } - - return list.release(); + if (!layers.next()) + return cssValuePool.createValue(isClip ? layers.clip() : layers.origin()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(isClip ? currLayer->clip() : currLayer->origin())); + return WTFMove(list); } case CSSPropertyBackgroundPosition: case CSSPropertyWebkitMaskPosition: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPosition ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return createPositionListForLayer(propertyID, layers, style.get()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(createPositionListForLayer(propertyID, currLayer, style.get())); - return list.release(); + auto& layers = propertyID == CSSPropertyWebkitMaskPosition ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return createPositionListForLayer(propertyID, layers, *style); + + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(createPositionListForLayer(propertyID, *currLayer, *style)); + return WTFMove(list); } case CSSPropertyBackgroundPositionX: case CSSPropertyWebkitMaskPositionX: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPositionX ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return cssValuePool().createValue(layers->xPosition()); + auto& layers = propertyID == CSSPropertyWebkitMaskPositionX ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return cssValuePool.createValue(layers.xPosition()); - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(cssValuePool().createValue(currLayer->xPosition())); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(currLayer->xPosition())); - return list.release(); + return WTFMove(list); } case CSSPropertyBackgroundPositionY: case CSSPropertyWebkitMaskPositionY: { - const FillLayer* layers = propertyID == CSSPropertyWebkitMaskPositionY ? style->maskLayers() : style->backgroundLayers(); - if (!layers->next()) - return cssValuePool().createValue(layers->yPosition()); + auto& layers = propertyID == CSSPropertyWebkitMaskPositionY ? style->maskLayers() : style->backgroundLayers(); + if (!layers.next()) + return cssValuePool.createValue(layers.yPosition()); - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(cssValuePool().createValue(currLayer->yPosition())); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(currLayer->yPosition())); - return list.release(); + return WTFMove(list); } case CSSPropertyBorderCollapse: if (style->borderCollapse()) - return cssValuePool().createIdentifierValue(CSSValueCollapse); - return cssValuePool().createIdentifierValue(CSSValueSeparate); + return cssValuePool.createIdentifierValue(CSSValueCollapse); + return cssValuePool.createIdentifierValue(CSSValueSeparate); case CSSPropertyBorderSpacing: { - RefPtr list = CSSValueList::createSpaceSeparated(); - list->append(zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get())); - list->append(zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get())); - return list.release(); + auto list = CSSValueList::createSpaceSeparated(); + list->append(zoomAdjustedPixelValue(style->horizontalBorderSpacing(), *style)); + list->append(zoomAdjustedPixelValue(style->verticalBorderSpacing(), *style)); + return WTFMove(list); } case CSSPropertyWebkitBorderHorizontalSpacing: - return zoomAdjustedPixelValue(style->horizontalBorderSpacing(), style.get()); + return zoomAdjustedPixelValue(style->horizontalBorderSpacing(), *style); case CSSPropertyWebkitBorderVerticalSpacing: - return zoomAdjustedPixelValue(style->verticalBorderSpacing(), style.get()); + return zoomAdjustedPixelValue(style->verticalBorderSpacing(), *style); case CSSPropertyBorderImageSource: if (style->borderImageSource()) return style->borderImageSource()->cssValue(); - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); case CSSPropertyBorderTopColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyBorderTopColor).rgb()) : currentColorOrValidColor(style.get(), style->borderTopColor()); + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyBorderTopColor)) : currentColorOrValidColor(style, style->borderTopColor()); case CSSPropertyBorderRightColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyBorderRightColor).rgb()) : currentColorOrValidColor(style.get(), style->borderRightColor()); + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyBorderRightColor)) : currentColorOrValidColor(style, style->borderRightColor()); case CSSPropertyBorderBottomColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyBorderBottomColor).rgb()) : currentColorOrValidColor(style.get(), style->borderBottomColor()); + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyBorderBottomColor)) : currentColorOrValidColor(style, style->borderBottomColor()); case CSSPropertyBorderLeftColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyBorderLeftColor).rgb()) : currentColorOrValidColor(style.get(), style->borderLeftColor()); + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyBorderLeftColor)) : currentColorOrValidColor(style, style->borderLeftColor()); case CSSPropertyBorderTopStyle: - return cssValuePool().createValue(style->borderTopStyle()); + return cssValuePool.createValue(style->borderTopStyle()); case CSSPropertyBorderRightStyle: - return cssValuePool().createValue(style->borderRightStyle()); + return cssValuePool.createValue(style->borderRightStyle()); case CSSPropertyBorderBottomStyle: - return cssValuePool().createValue(style->borderBottomStyle()); + return cssValuePool.createValue(style->borderBottomStyle()); case CSSPropertyBorderLeftStyle: - return cssValuePool().createValue(style->borderLeftStyle()); + return cssValuePool.createValue(style->borderLeftStyle()); case CSSPropertyBorderTopWidth: - return zoomAdjustedPixelValue(style->borderTopWidth(), style.get()); + return zoomAdjustedPixelValue(style->borderTopWidth(), *style); case CSSPropertyBorderRightWidth: - return zoomAdjustedPixelValue(style->borderRightWidth(), style.get()); + return zoomAdjustedPixelValue(style->borderRightWidth(), *style); case CSSPropertyBorderBottomWidth: - return zoomAdjustedPixelValue(style->borderBottomWidth(), style.get()); + return zoomAdjustedPixelValue(style->borderBottomWidth(), *style); case CSSPropertyBorderLeftWidth: - return zoomAdjustedPixelValue(style->borderLeftWidth(), style.get()); + return zoomAdjustedPixelValue(style->borderLeftWidth(), *style); case CSSPropertyBottom: - return getPositionOffsetValue(style.get(), CSSPropertyBottom, m_node->document().renderView()); + return positionOffsetValue(*style, CSSPropertyBottom); case CSSPropertyWebkitBoxAlign: - return cssValuePool().createValue(style->boxAlign()); + return cssValuePool.createValue(style->boxAlign()); #if ENABLE(CSS_BOX_DECORATION_BREAK) case CSSPropertyWebkitBoxDecorationBreak: if (style->boxDecorationBreak() == DSLICE) - return cssValuePool().createIdentifierValue(CSSValueSlice); - return cssValuePool().createIdentifierValue(CSSValueClone); + return cssValuePool.createIdentifierValue(CSSValueSlice); + return cssValuePool.createIdentifierValue(CSSValueClone); #endif case CSSPropertyWebkitBoxDirection: - return cssValuePool().createValue(style->boxDirection()); + return cssValuePool.createValue(style->boxDirection()); case CSSPropertyWebkitBoxFlex: - return cssValuePool().createValue(style->boxFlex(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->boxFlex(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWebkitBoxFlexGroup: - return cssValuePool().createValue(style->boxFlexGroup(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->boxFlexGroup(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWebkitBoxLines: - return cssValuePool().createValue(style->boxLines()); + return cssValuePool.createValue(style->boxLines()); case CSSPropertyWebkitBoxOrdinalGroup: - return cssValuePool().createValue(style->boxOrdinalGroup(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->boxOrdinalGroup(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWebkitBoxOrient: - return cssValuePool().createValue(style->boxOrient()); + return cssValuePool.createValue(style->boxOrient()); case CSSPropertyWebkitBoxPack: - return cssValuePool().createValue(style->boxPack()); + return cssValuePool.createValue(style->boxPack()); case CSSPropertyWebkitBoxReflect: - return valueForReflection(style->boxReflect(), style.get()); + return valueForReflection(style->boxReflect(), *style); case CSSPropertyBoxShadow: case CSSPropertyWebkitBoxShadow: - return valueForShadow(style->boxShadow(), propertyID, style.get()); + return valueForShadow(style->boxShadow(), propertyID, *style); case CSSPropertyCaptionSide: - return cssValuePool().createValue(style->captionSide()); + return cssValuePool.createValue(style->captionSide()); case CSSPropertyClear: - return cssValuePool().createValue(style->clear()); + return cssValuePool.createValue(style->clear()); case CSSPropertyColor: - return cssValuePool().createColorValue(m_allowVisitedStyle ? style->visitedDependentColor(CSSPropertyColor).rgb() : style->color().rgb()); + return cssValuePool.createColorValue(m_allowVisitedStyle ? style->visitedDependentColor(CSSPropertyColor) : style->color()); case CSSPropertyWebkitPrintColorAdjust: - return cssValuePool().createValue(style->printColorAdjust()); + return cssValuePool.createValue(style->printColorAdjust()); case CSSPropertyWebkitColumnAxis: - return cssValuePool().createValue(style->columnAxis()); - case CSSPropertyWebkitColumnCount: + return cssValuePool.createValue(style->columnAxis()); + case CSSPropertyColumnCount: if (style->hasAutoColumnCount()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->columnCount(), CSSPrimitiveValue::CSS_NUMBER); - case CSSPropertyWebkitColumnFill: - return cssValuePool().createValue(style->columnFill()); - case CSSPropertyWebkitColumnGap: + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->columnCount(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyColumnFill: + return cssValuePool.createValue(style->columnFill()); + case CSSPropertyColumnGap: if (style->hasNormalColumnGap()) - return cssValuePool().createIdentifierValue(CSSValueNormal); - return zoomAdjustedPixelValue(style->columnGap(), style.get()); + return cssValuePool.createIdentifierValue(CSSValueNormal); + return zoomAdjustedPixelValue(style->columnGap(), *style); case CSSPropertyWebkitColumnProgression: - return cssValuePool().createValue(style->columnProgression()); - case CSSPropertyWebkitColumnRuleColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->columnRuleColor()); - case CSSPropertyWebkitColumnRuleStyle: - return cssValuePool().createValue(style->columnRuleStyle()); - case CSSPropertyWebkitColumnRuleWidth: - return zoomAdjustedPixelValue(style->columnRuleWidth(), style.get()); - case CSSPropertyWebkitColumnSpan: - return cssValuePool().createIdentifierValue(style->columnSpan() ? CSSValueAll : CSSValueNone); + return cssValuePool.createValue(style->columnProgression()); + case CSSPropertyColumnRuleColor: + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor)) : currentColorOrValidColor(style, style->columnRuleColor()); + case CSSPropertyColumnRuleStyle: + return cssValuePool.createValue(style->columnRuleStyle()); + case CSSPropertyColumnRuleWidth: + return zoomAdjustedPixelValue(style->columnRuleWidth(), *style); + case CSSPropertyColumnSpan: + return cssValuePool.createIdentifierValue(style->columnSpan() ? CSSValueAll : CSSValueNone); case CSSPropertyWebkitColumnBreakAfter: - return cssValuePool().createValue(style->columnBreakAfter()); + return cssValuePool.createValue(convertToColumnBreak(style->breakAfter())); case CSSPropertyWebkitColumnBreakBefore: - return cssValuePool().createValue(style->columnBreakBefore()); + return cssValuePool.createValue(convertToColumnBreak(style->breakBefore())); case CSSPropertyWebkitColumnBreakInside: - return cssValuePool().createValue(style->columnBreakInside()); - case CSSPropertyWebkitColumnWidth: + return cssValuePool.createValue(convertToColumnBreak(style->breakInside())); + case CSSPropertyColumnWidth: if (style->hasAutoColumnWidth()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return zoomAdjustedPixelValue(style->columnWidth(), style.get()); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(style->columnWidth(), *style); case CSSPropertyTabSize: - return cssValuePool().createValue(style->tabSize(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->tabSize(), CSSPrimitiveValue::CSS_NUMBER); #if ENABLE(CSS_REGIONS) case CSSPropertyWebkitRegionBreakAfter: - return cssValuePool().createValue(style->regionBreakAfter()); + return cssValuePool.createValue(convertToRegionBreak(style->breakAfter())); case CSSPropertyWebkitRegionBreakBefore: - return cssValuePool().createValue(style->regionBreakBefore()); + return cssValuePool.createValue(convertToRegionBreak(style->breakBefore())); case CSSPropertyWebkitRegionBreakInside: - return cssValuePool().createValue(style->regionBreakInside()); + return cssValuePool.createValue(convertToRegionBreak(style->breakInside())); #endif case CSSPropertyCursor: { RefPtr list; - CursorList* cursors = style->cursors(); + auto* cursors = style->cursors(); if (cursors && cursors->size() > 0) { list = CSSValueList::createCommaSeparated(); for (unsigned i = 0; i < cursors->size(); ++i) if (StyleImage* image = cursors->at(i).image()) list->append(image->cssValue()); } - RefPtr value = cssValuePool().createValue(style->cursor()); + auto value = cssValuePool.createValue(style->cursor()); if (list) { - list->append(value.release()); - return list.release(); + list->append(WTFMove(value)); + return list; } - return value.release(); + return WTFMove(value); } #if ENABLE(CURSOR_VISIBILITY) case CSSPropertyWebkitCursorVisibility: - return cssValuePool().createValue(style->cursorVisibility()); + return cssValuePool.createValue(style->cursorVisibility()); #endif case CSSPropertyDirection: - return cssValuePool().createValue(style->direction()); + return cssValuePool.createValue(style->direction()); case CSSPropertyDisplay: - return cssValuePool().createValue(style->display()); + return cssValuePool.createValue(style->display()); case CSSPropertyEmptyCells: - return cssValuePool().createValue(style->emptyCells()); - case CSSPropertyWebkitAlignContent: - return cssValuePool().createValue(style->alignContent()); - case CSSPropertyWebkitAlignItems: - return cssValuePool().createValue(style->alignItems()); - case CSSPropertyWebkitAlignSelf: - if (style->alignSelf() == AlignAuto) { - Node* parent = styledNode->parentNode(); - if (parent && parent->computedStyle()) - return cssValuePool().createValue(parent->computedStyle()->alignItems()); - return cssValuePool().createValue(AlignStretch); - } - return cssValuePool().createValue(style->alignSelf()); - case CSSPropertyWebkitFlex: - return getCSSPropertyValuesForShorthandProperties(webkitFlexShorthand()); - case CSSPropertyWebkitFlexBasis: - return cssValuePool().createValue(style->flexBasis()); - case CSSPropertyWebkitFlexDirection: - return cssValuePool().createValue(style->flexDirection()); - case CSSPropertyWebkitFlexFlow: - return getCSSPropertyValuesForShorthandProperties(webkitFlexFlowShorthand()); - case CSSPropertyWebkitFlexGrow: - return cssValuePool().createValue(style->flexGrow()); - case CSSPropertyWebkitFlexShrink: - return cssValuePool().createValue(style->flexShrink()); - case CSSPropertyWebkitFlexWrap: - return cssValuePool().createValue(style->flexWrap()); - case CSSPropertyWebkitJustifyContent: - return cssValuePool().createValue(style->justifyContent()); - case CSSPropertyWebkitOrder: - return cssValuePool().createValue(style->order(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->emptyCells()); + case CSSPropertyAlignContent: + return valueForContentPositionAndDistributionWithOverflowAlignment(style->alignContent(), CSSValueStretch); + case CSSPropertyAlignItems: + return valueForItemPositionWithOverflowAlignment(style->alignItems()); + case CSSPropertyAlignSelf: + return valueForItemPositionWithOverflowAlignment(resolveAlignSelfAuto(style->alignSelf(), styledElement->parentNode())); + case CSSPropertyFlex: + return getCSSPropertyValuesForShorthandProperties(flexShorthand()); + case CSSPropertyFlexBasis: + return cssValuePool.createValue(style->flexBasis()); + case CSSPropertyFlexDirection: + return cssValuePool.createValue(style->flexDirection()); + case CSSPropertyFlexFlow: + return getCSSPropertyValuesForShorthandProperties(flexFlowShorthand()); + case CSSPropertyFlexGrow: + return cssValuePool.createValue(style->flexGrow()); + case CSSPropertyFlexShrink: + return cssValuePool.createValue(style->flexShrink()); + case CSSPropertyFlexWrap: + return cssValuePool.createValue(style->flexWrap()); + case CSSPropertyJustifyContent: + return valueForContentPositionAndDistributionWithOverflowAlignment(style->justifyContent(), CSSValueFlexStart); + case CSSPropertyJustifyItems: + return valueForItemPositionWithOverflowAlignment(resolveJustifyItemsAuto(style->justifyItems(), styledElement->parentNode())); + case CSSPropertyJustifySelf: + return valueForItemPositionWithOverflowAlignment(resolveJustifySelfAuto(style->justifySelf(), styledElement->parentNode())); + case CSSPropertyOrder: + return cssValuePool.createValue(style->order(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyFloat: if (style->display() != NONE && style->hasOutOfFlowPosition()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->floating()); + return cssValuePool.createIdentifierValue(CSSValueNone); + return cssValuePool.createValue(style->floating()); case CSSPropertyFont: { - RefPtr computedFont = CSSFontValue::create(); - computedFont->style = fontStyleFromStyle(style.get()); - computedFont->variant = fontVariantFromStyle(style.get()); - computedFont->weight = fontWeightFromStyle(style.get()); - computedFont->size = fontSizeFromStyle(style.get()); - computedFont->lineHeight = lineHeightFromStyle(style.get(), m_node->document().renderView()); - computedFont->family = fontFamilyFromStyle(style.get()); - return computedFont.release(); - } - case CSSPropertyFontFamily: { - RefPtr fontFamilyList = fontFamilyFromStyle(style.get()); - // If there's only a single family, return that as a CSSPrimitiveValue. - // NOTE: Gecko always returns this as a comma-separated CSSPrimitiveValue string. - if (fontFamilyList->length() == 1) - return fontFamilyList->item(0); - return fontFamilyList.release(); + auto computedFont = CSSFontValue::create(); + computedFont->style = fontStyleFromStyle(*style); + if (style->fontDescription().variantCaps() == FontVariantCaps::Small) + computedFont->variant = CSSValuePool::singleton().createIdentifierValue(CSSValueSmallCaps); + else + computedFont->variant = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); + computedFont->weight = fontWeightFromStyle(*style); + computedFont->size = fontSizeFromStyle(*style); + computedFont->lineHeight = lineHeightFromStyle(*style); + computedFont->family = fontFamilyListFromStyle(*style); + return WTFMove(computedFont); } + case CSSPropertyFontFamily: + return fontFamilyFromStyle(*style); case CSSPropertyFontSize: - return fontSizeFromStyle(style.get()); + return fontSizeFromStyle(*style); case CSSPropertyFontStyle: - return fontStyleFromStyle(style.get()); + return fontStyleFromStyle(*style); case CSSPropertyFontVariant: - return fontVariantFromStyle(style.get()); + return fontVariantFromStyle(*style); case CSSPropertyFontWeight: - return fontWeightFromStyle(style.get()); - case CSSPropertyWebkitFontFeatureSettings: { - const FontFeatureSettings* featureSettings = style->fontDescription().featureSettings(); - if (!featureSettings || !featureSettings->size()) - return cssValuePool().createIdentifierValue(CSSValueNormal); - RefPtr list = CSSValueList::createCommaSeparated(); - for (unsigned i = 0; i < featureSettings->size(); ++i) { - const FontFeature& feature = featureSettings->at(i); - list->append(CSSFontFeatureValue::create(feature.tag(), feature.value())); - } - return list.release(); + return fontWeightFromStyle(*style); + case CSSPropertyFontSynthesis: + return fontSynthesisFromStyle(*style); + case CSSPropertyFontFeatureSettings: { + const FontFeatureSettings& featureSettings = style->fontDescription().featureSettings(); + if (!featureSettings.size()) + return cssValuePool.createIdentifierValue(CSSValueNormal); + auto list = CSSValueList::createCommaSeparated(); + for (auto& feature : featureSettings) + list->append(CSSFontFeatureValue::create(FontTag(feature.tag()), feature.value())); + return WTFMove(list); } - case CSSPropertyWebkitGridAutoColumns: - return valueForGridTrackSize(style->gridAutoColumns(), style.get(), m_node->document().renderView()); - case CSSPropertyWebkitGridAutoFlow: - return cssValuePool().createValue(style->gridAutoFlow()); - case CSSPropertyWebkitGridAutoRows: - return valueForGridTrackSize(style->gridAutoRows(), style.get(), m_node->document().renderView()); - case CSSPropertyWebkitGridDefinitionColumns: - return valueForGridTrackList(style->gridColumns(), style->namedGridColumnLines(), style.get(), m_node->document().renderView()); - case CSSPropertyWebkitGridDefinitionRows: - return valueForGridTrackList(style->gridRows(), style->namedGridRowLines(), style.get(), m_node->document().renderView()); - - case CSSPropertyWebkitGridColumnStart: +#if ENABLE(VARIATION_FONTS) + case CSSPropertyFontVariationSettings: { + const FontVariationSettings& variationSettings = style->fontDescription().variationSettings(); + if (variationSettings.isEmpty()) + return cssValuePool.createIdentifierValue(CSSValueNormal); + auto list = CSSValueList::createCommaSeparated(); + for (auto& feature : variationSettings) + list->append(CSSFontVariationValue::create(feature.tag(), feature.value())); + return WTFMove(list); + } +#endif + case CSSPropertyGridAutoFlow: { + auto list = CSSValueList::createSpaceSeparated(); + ASSERT(style->isGridAutoFlowDirectionRow() || style->isGridAutoFlowDirectionColumn()); + if (style->isGridAutoFlowDirectionRow()) + list->append(cssValuePool.createIdentifierValue(CSSValueRow)); + else + list->append(cssValuePool.createIdentifierValue(CSSValueColumn)); + + if (style->isGridAutoFlowAlgorithmDense()) + list->append(cssValuePool.createIdentifierValue(CSSValueDense)); + + return WTFMove(list); + } + + // Specs mention that getComputedStyle() should return the used value of the property instead of the computed + // one for grid-template-{rows|columns} but not for the grid-auto-{rows|columns} as things like + // grid-auto-columns: 2fr; cannot be resolved to a value in pixels as the '2fr' means very different things + // depending on the size of the explicit grid or the number of implicit tracks added to the grid. See + // http://lists.w3.org/Archives/Public/www-style/2013Nov/0014.html + case CSSPropertyGridAutoColumns: + return valueForGridTrackSizeList(ForColumns, *style); + case CSSPropertyGridAutoRows: + return valueForGridTrackSizeList(ForRows, *style); + + case CSSPropertyGridTemplateColumns: + return valueForGridTrackList(ForColumns, renderer, *style); + case CSSPropertyGridTemplateRows: + return valueForGridTrackList(ForRows, renderer, *style); + + case CSSPropertyGridColumnStart: return valueForGridPosition(style->gridItemColumnStart()); - case CSSPropertyWebkitGridColumnEnd: + case CSSPropertyGridColumnEnd: return valueForGridPosition(style->gridItemColumnEnd()); - case CSSPropertyWebkitGridRowStart: + case CSSPropertyGridRowStart: return valueForGridPosition(style->gridItemRowStart()); - case CSSPropertyWebkitGridRowEnd: + case CSSPropertyGridRowEnd: return valueForGridPosition(style->gridItemRowEnd()); - case CSSPropertyWebkitGridArea: - return getCSSPropertyValuesForGridShorthand(webkitGridAreaShorthand()); - case CSSPropertyWebkitGridColumn: - return getCSSPropertyValuesForGridShorthand(webkitGridColumnShorthand()); - case CSSPropertyWebkitGridRow: - return getCSSPropertyValuesForGridShorthand(webkitGridRowShorthand()); - - case CSSPropertyWebkitGridTemplate: + case CSSPropertyGridArea: + return getCSSPropertyValuesForGridShorthand(gridAreaShorthand()); + case CSSPropertyGridTemplate: + return getCSSPropertyValuesForGridShorthand(gridTemplateShorthand()); + case CSSPropertyGrid: + return getCSSPropertyValuesForGridShorthand(gridShorthand()); + case CSSPropertyGridColumn: + return getCSSPropertyValuesForGridShorthand(gridColumnShorthand()); + case CSSPropertyGridRow: + return getCSSPropertyValuesForGridShorthand(gridRowShorthand()); + case CSSPropertyGridTemplateAreas: if (!style->namedGridAreaRowCount()) { ASSERT(!style->namedGridAreaColumnCount()); - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); } - - return CSSGridTemplateValue::create(style->namedGridArea(), style->namedGridAreaRowCount(), style->namedGridAreaColumnCount()); - + return CSSGridTemplateAreasValue::create(style->namedGridArea(), style->namedGridAreaRowCount(), style->namedGridAreaColumnCount()); + case CSSPropertyGridColumnGap: + return zoomAdjustedPixelValueForLength(style->gridColumnGap(), *style); + case CSSPropertyGridRowGap: + return zoomAdjustedPixelValueForLength(style->gridRowGap(), *style); + case CSSPropertyGridGap: + return getCSSPropertyValuesForGridShorthand(gridGapShorthand()); case CSSPropertyHeight: - if (renderer) { + if (renderer && !renderer->isRenderSVGModelObject()) { // According to http://www.w3.org/TR/CSS2/visudet.html#the-height-property, // the "height" property does not apply for non-replaced inline elements. if (!renderer->isReplaced() && renderer->isInline()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return zoomAdjustedPixelValue(sizingBox(renderer).height(), style.get()); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(sizingBox(*renderer).height(), *style); } - return zoomAdjustedPixelValueForLength(style->height(), style.get()); - case CSSPropertyWebkitHighlight: - if (style->highlight() == nullAtom) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->highlight(), CSSPrimitiveValue::CSS_STRING); + return zoomAdjustedPixelValueForLength(style->height(), *style); case CSSPropertyWebkitHyphens: - return cssValuePool().createValue(style->hyphens()); + return cssValuePool.createValue(style->hyphens()); case CSSPropertyWebkitHyphenateCharacter: if (style->hyphenationString().isNull()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->hyphenationString(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->hyphenationString(), CSSPrimitiveValue::CSS_STRING); case CSSPropertyWebkitHyphenateLimitAfter: if (style->hyphenationLimitAfter() < 0) return CSSPrimitiveValue::createIdentifier(CSSValueAuto); @@ -2116,158 +3015,171 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert return CSSPrimitiveValue::create(style->hyphenationLimitLines(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWebkitBorderFit: if (style->borderFit() == BorderFitBorder) - return cssValuePool().createIdentifierValue(CSSValueBorder); - return cssValuePool().createIdentifierValue(CSSValueLines); + return cssValuePool.createIdentifierValue(CSSValueBorder); + return cssValuePool.createIdentifierValue(CSSValueLines); #if ENABLE(CSS_IMAGE_ORIENTATION) case CSSPropertyImageOrientation: - return cssValuePool().createValue(style->imageOrientation()); + return cssValuePool.createValue(style->imageOrientation()); #endif case CSSPropertyImageRendering: return CSSPrimitiveValue::create(style->imageRendering()); #if ENABLE(CSS_IMAGE_RESOLUTION) case CSSPropertyImageResolution: - return cssValuePool().createValue(style->imageResolution(), CSSPrimitiveValue::CSS_DPPX); + return cssValuePool.createValue(style->imageResolution(), CSSPrimitiveValue::CSS_DPPX); #endif case CSSPropertyLeft: - return getPositionOffsetValue(style.get(), CSSPropertyLeft, m_node->document().renderView()); + return positionOffsetValue(*style, CSSPropertyLeft); case CSSPropertyLetterSpacing: if (!style->letterSpacing()) - return cssValuePool().createIdentifierValue(CSSValueNormal); - return zoomAdjustedPixelValue(style->letterSpacing(), style.get()); + return cssValuePool.createIdentifierValue(CSSValueNormal); + return zoomAdjustedPixelValue(style->letterSpacing(), *style); case CSSPropertyWebkitLineClamp: if (style->lineClamp().isNone()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->lineClamp().value(), style->lineClamp().isPercentage() ? CSSPrimitiveValue::CSS_PERCENTAGE : CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createIdentifierValue(CSSValueNone); + return cssValuePool.createValue(style->lineClamp().value(), style->lineClamp().isPercentage() ? CSSPrimitiveValue::CSS_PERCENTAGE : CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyLineHeight: - return lineHeightFromStyle(style.get(), m_node->document().renderView()); + return lineHeightFromStyle(*style); case CSSPropertyListStyleImage: if (style->listStyleImage()) return style->listStyleImage()->cssValue(); - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); case CSSPropertyListStylePosition: - return cssValuePool().createValue(style->listStylePosition()); + return cssValuePool.createValue(style->listStylePosition()); case CSSPropertyListStyleType: - return cssValuePool().createValue(style->listStyleType()); + return cssValuePool.createValue(style->listStyleType()); case CSSPropertyWebkitLocale: if (style->locale().isNull()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->locale(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->locale(), CSSPrimitiveValue::CSS_STRING); case CSSPropertyMarginTop: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginTop, &RenderBoxModelObject::marginTop>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginTop, &RenderBoxModelObject::marginTop>(*style, renderer); case CSSPropertyMarginRight: { Length marginRight = style->marginRight(); - if (marginRight.isFixed() || !renderer || !renderer->isBox()) - return zoomAdjustedPixelValueForLength(marginRight, style.get()); + if (marginRight.isFixed() || !is(renderer)) + return zoomAdjustedPixelValueForLength(marginRight, *style); float value; - if (marginRight.isPercent() || marginRight.isViewportPercentage()) + if (marginRight.isPercentOrCalculated()) { // RenderBox gives a marginRight() that is the distance between the right-edge of the child box // and the right-edge of the containing box, when display == BLOCK. Let's calculate the absolute // value of the specified margin-right % instead of relying on RenderBox's marginRight() value. - value = minimumValueForLength(marginRight, toRenderBox(renderer)->containingBlockLogicalWidthForContent(), m_node->document().renderView()); - else - value = toRenderBox(renderer)->marginRight(); - return zoomAdjustedPixelValue(value, style.get()); + value = minimumValueForLength(marginRight, downcast(*renderer).containingBlockLogicalWidthForContent()); + } else + value = downcast(*renderer).marginRight(); + return zoomAdjustedPixelValue(value, *style); } case CSSPropertyMarginBottom: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginBottom, &RenderBoxModelObject::marginBottom>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginBottom, &RenderBoxModelObject::marginBottom>(*style, renderer); case CSSPropertyMarginLeft: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginLeft, &RenderBoxModelObject::marginLeft>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginLeft, &RenderBoxModelObject::marginLeft>(*style, renderer); case CSSPropertyWebkitMarqueeDirection: - return cssValuePool().createValue(style->marqueeDirection()); + return cssValuePool.createValue(style->marqueeDirection()); case CSSPropertyWebkitMarqueeIncrement: - return cssValuePool().createValue(style->marqueeIncrement()); + return cssValuePool.createValue(style->marqueeIncrement()); case CSSPropertyWebkitMarqueeRepetition: if (style->marqueeLoopCount() < 0) - return cssValuePool().createIdentifierValue(CSSValueInfinite); - return cssValuePool().createValue(style->marqueeLoopCount(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createIdentifierValue(CSSValueInfinite); + return cssValuePool.createValue(style->marqueeLoopCount(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWebkitMarqueeStyle: - return cssValuePool().createValue(style->marqueeBehavior()); + return cssValuePool.createValue(style->marqueeBehavior()); case CSSPropertyWebkitUserModify: - return cssValuePool().createValue(style->userModify()); + return cssValuePool.createValue(style->userModify()); case CSSPropertyMaxHeight: { const Length& maxHeight = style->maxHeight(); if (maxHeight.isUndefined()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return zoomAdjustedPixelValueForLength(maxHeight, style.get()); + return cssValuePool.createIdentifierValue(CSSValueNone); + return zoomAdjustedPixelValueForLength(maxHeight, *style); } case CSSPropertyMaxWidth: { const Length& maxWidth = style->maxWidth(); if (maxWidth.isUndefined()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return zoomAdjustedPixelValueForLength(maxWidth, style.get()); + return cssValuePool.createIdentifierValue(CSSValueNone); + return zoomAdjustedPixelValueForLength(maxWidth, *style); } case CSSPropertyMinHeight: - // FIXME: For flex-items, min-height:auto should compute to min-content. - if (style->minHeight().isAuto()) - return zoomAdjustedPixelValue(0, style.get()); - return zoomAdjustedPixelValueForLength(style->minHeight(), style.get()); + if (style->minHeight().isAuto()) { + if (isFlexOrGrid(styledElement->parentNode())) + return cssValuePool.createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(0, *style); + } + return zoomAdjustedPixelValueForLength(style->minHeight(), *style); case CSSPropertyMinWidth: - // FIXME: For flex-items, min-width:auto should compute to min-content. - if (style->minWidth().isAuto()) - return zoomAdjustedPixelValue(0, style.get()); - return zoomAdjustedPixelValueForLength(style->minWidth(), style.get()); + if (style->minWidth().isAuto()) { + if (isFlexOrGrid(styledElement->parentNode())) + return cssValuePool.createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(0, *style); + } + return zoomAdjustedPixelValueForLength(style->minWidth(), *style); case CSSPropertyObjectFit: - return cssValuePool().createValue(style->objectFit()); + return cssValuePool.createValue(style->objectFit()); + case CSSPropertyObjectPosition: { + auto list = CSSValueList::createSpaceSeparated(); + list->append(zoomAdjustedPixelValueForLength(style->objectPosition().x(), *style)); + list->append(zoomAdjustedPixelValueForLength(style->objectPosition().y(), *style)); + return WTFMove(list); + } case CSSPropertyOpacity: - return cssValuePool().createValue(style->opacity(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->opacity(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyOrphans: if (style->hasAutoOrphans()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->orphans(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->orphans(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyOutlineColor: - return m_allowVisitedStyle ? cssValuePool().createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor).rgb()) : currentColorOrValidColor(style.get(), style->outlineColor()); + return m_allowVisitedStyle ? cssValuePool.createColorValue(style->visitedDependentColor(CSSPropertyOutlineColor)) : currentColorOrValidColor(style, style->outlineColor()); case CSSPropertyOutlineOffset: - return zoomAdjustedPixelValue(style->outlineOffset(), style.get()); + return zoomAdjustedPixelValue(style->outlineOffset(), *style); case CSSPropertyOutlineStyle: if (style->outlineStyleIsAuto()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->outlineStyle()); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->outlineStyle()); case CSSPropertyOutlineWidth: - return zoomAdjustedPixelValue(style->outlineWidth(), style.get()); + return zoomAdjustedPixelValue(style->outlineWidth(), *style); case CSSPropertyOverflow: - return cssValuePool().createValue(std::max(style->overflowX(), style->overflowY())); + return cssValuePool.createValue(std::max(style->overflowX(), style->overflowY())); case CSSPropertyOverflowWrap: - return cssValuePool().createValue(style->overflowWrap()); + return cssValuePool.createValue(style->overflowWrap()); case CSSPropertyOverflowX: - return cssValuePool().createValue(style->overflowX()); + return cssValuePool.createValue(style->overflowX()); case CSSPropertyOverflowY: - return cssValuePool().createValue(style->overflowY()); + return cssValuePool.createValue(style->overflowY()); case CSSPropertyPaddingTop: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingTop, &RenderBoxModelObject::computedCSSPaddingTop>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingTop, &RenderBoxModelObject::computedCSSPaddingTop>(*style, renderer); case CSSPropertyPaddingRight: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingRight, &RenderBoxModelObject::computedCSSPaddingRight>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingRight, &RenderBoxModelObject::computedCSSPaddingRight>(*style, renderer); case CSSPropertyPaddingBottom: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingBottom, &RenderBoxModelObject::computedCSSPaddingBottom>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingBottom, &RenderBoxModelObject::computedCSSPaddingBottom>(*style, renderer); case CSSPropertyPaddingLeft: - return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingLeft, &RenderBoxModelObject::computedCSSPaddingLeft>(style.get(), renderer); + return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::paddingLeft, &RenderBoxModelObject::computedCSSPaddingLeft>(*style, renderer); case CSSPropertyPageBreakAfter: - return cssValuePool().createValue(style->pageBreakAfter()); + return cssValuePool.createValue(convertToPageBreak(style->breakAfter())); case CSSPropertyPageBreakBefore: - return cssValuePool().createValue(style->pageBreakBefore()); - case CSSPropertyPageBreakInside: { - EPageBreak pageBreak = style->pageBreakInside(); - ASSERT(pageBreak != PBALWAYS); - if (pageBreak == PBALWAYS) - return 0; - return cssValuePool().createValue(style->pageBreakInside()); - } + return cssValuePool.createValue(convertToPageBreak(style->breakBefore())); + case CSSPropertyPageBreakInside: + return cssValuePool.createValue(convertToPageBreak(style->breakInside())); + case CSSPropertyBreakAfter: + return cssValuePool.createValue(style->breakAfter()); + case CSSPropertyBreakBefore: + return cssValuePool.createValue(style->breakBefore()); + case CSSPropertyBreakInside: + return cssValuePool.createValue(style->breakInside()); + case CSSPropertyHangingPunctuation: + return hangingPunctuationToCSSValue(style->hangingPunctuation()); case CSSPropertyPosition: - return cssValuePool().createValue(style->position()); + return cssValuePool.createValue(style->position()); case CSSPropertyRight: - return getPositionOffsetValue(style.get(), CSSPropertyRight, m_node->document().renderView()); + return positionOffsetValue(*style, CSSPropertyRight); case CSSPropertyWebkitRubyPosition: - return cssValuePool().createValue(style->rubyPosition()); + return cssValuePool.createValue(style->rubyPosition()); case CSSPropertyTableLayout: - return cssValuePool().createValue(style->tableLayout()); + return cssValuePool.createValue(style->tableLayout()); case CSSPropertyTextAlign: - return cssValuePool().createValue(style->textAlign()); + return cssValuePool.createValue(style->textAlign()); case CSSPropertyTextDecoration: return renderTextDecorationFlagsToCSSValue(style->textDecoration()); #if ENABLE(CSS3_TEXT) case CSSPropertyWebkitTextAlignLast: - return cssValuePool().createValue(style->textAlignLast()); + return cssValuePool.createValue(style->textAlignLast()); case CSSPropertyWebkitTextJustify: - return cssValuePool().createValue(style->textJustify()); + return cssValuePool.createValue(style->textJustify()); #endif // CSS3_TEXT case CSSPropertyWebkitTextDecoration: return getCSSPropertyValuesForShorthandProperties(webkitTextDecorationShorthand()); @@ -2276,25 +3188,25 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyWebkitTextDecorationStyle: return renderTextDecorationStyleFlagsToCSSValue(style->textDecorationStyle()); case CSSPropertyWebkitTextDecorationColor: - return currentColorOrValidColor(style.get(), style->textDecorationColor()); + return currentColorOrValidColor(style, style->textDecorationColor()); case CSSPropertyWebkitTextDecorationSkip: return renderTextDecorationSkipFlagsToCSSValue(style->textDecorationSkip()); case CSSPropertyWebkitTextUnderlinePosition: - return cssValuePool().createValue(style->textUnderlinePosition()); + return cssValuePool.createValue(style->textUnderlinePosition()); case CSSPropertyWebkitTextDecorationsInEffect: return renderTextDecorationFlagsToCSSValue(style->textDecorationsInEffect()); case CSSPropertyWebkitTextFillColor: - return currentColorOrValidColor(style.get(), style->textFillColor()); + return currentColorOrValidColor(style, style->textFillColor()); case CSSPropertyWebkitTextEmphasisColor: - return currentColorOrValidColor(style.get(), style->textEmphasisColor()); + return currentColorOrValidColor(style, style->textEmphasisColor()); case CSSPropertyWebkitTextEmphasisPosition: return renderEmphasisPositionFlagsToCSSValue(style->textEmphasisPosition()); case CSSPropertyWebkitTextEmphasisStyle: switch (style->textEmphasisMark()) { case TextEmphasisMarkNone: - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); case TextEmphasisMarkCustom: - return cssValuePool().createValue(style->textEmphasisCustomMark(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createValue(style->textEmphasisCustomMark(), CSSPrimitiveValue::CSS_STRING); case TextEmphasisMarkAuto: ASSERT_NOT_REACHED(); #if ASSERT_DISABLED @@ -2304,269 +3216,283 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case TextEmphasisMarkCircle: case TextEmphasisMarkDoubleCircle: case TextEmphasisMarkTriangle: - case TextEmphasisMarkSesame: { - RefPtr list = CSSValueList::createSpaceSeparated(); - list->append(cssValuePool().createValue(style->textEmphasisFill())); - list->append(cssValuePool().createValue(style->textEmphasisMark())); - return list.release(); - } + case TextEmphasisMarkSesame: + auto list = CSSValueList::createSpaceSeparated(); + list->append(cssValuePool.createValue(style->textEmphasisFill())); + list->append(cssValuePool.createValue(style->textEmphasisMark())); + return WTFMove(list); } case CSSPropertyTextIndent: { // If CSS3_TEXT is disabled or text-indent has only one value( | ), // getPropertyCSSValue() returns CSSValue. - RefPtr textIndent = zoomAdjustedPixelValueForLength(style->textIndent(), style.get()); + auto textIndent = zoomAdjustedPixelValueForLength(style->textIndent(), *style); #if ENABLE(CSS3_TEXT) // If CSS3_TEXT is enabled and text-indent has -webkit-each-line or -webkit-hanging, // getPropertyCSSValue() returns CSSValueList. if (style->textIndentLine() == TextIndentEachLine || style->textIndentType() == TextIndentHanging) { - RefPtr list = CSSValueList::createSpaceSeparated(); - list->append(textIndent.release()); + auto list = CSSValueList::createSpaceSeparated(); + list->append(WTFMove(textIndent)); if (style->textIndentLine() == TextIndentEachLine) - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine)); + list->append(cssValuePool.createIdentifierValue(CSSValueWebkitEachLine)); if (style->textIndentType() == TextIndentHanging) - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitHanging)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueWebkitHanging)); + return WTFMove(list); } #endif - return textIndent.release(); + return WTFMove(textIndent); } case CSSPropertyTextShadow: - return valueForShadow(style->textShadow(), propertyID, style.get()); + return valueForShadow(style->textShadow(), propertyID, *style); case CSSPropertyTextRendering: - return cssValuePool().createValue(style->fontDescription().textRenderingMode()); + return cssValuePool.createValue(style->fontDescription().textRenderingMode()); case CSSPropertyTextOverflow: if (style->textOverflow()) - return cssValuePool().createIdentifierValue(CSSValueEllipsis); - return cssValuePool().createIdentifierValue(CSSValueClip); + return cssValuePool.createIdentifierValue(CSSValueEllipsis); + return cssValuePool.createIdentifierValue(CSSValueClip); case CSSPropertyWebkitTextSecurity: - return cssValuePool().createValue(style->textSecurity()); -#if ENABLE(IOS_TEXT_AUTOSIZING) + return cssValuePool.createValue(style->textSecurity()); +#if ENABLE(TEXT_AUTOSIZING) case CSSPropertyWebkitTextSizeAdjust: if (style->textSizeAdjust().isAuto()) - return cssValuePool().createIdentifierValue(CSSValueAuto); + return cssValuePool.createIdentifierValue(CSSValueAuto); if (style->textSizeAdjust().isNone()) - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); return CSSPrimitiveValue::create(style->textSizeAdjust().percentage(), CSSPrimitiveValue::CSS_PERCENTAGE); #endif case CSSPropertyWebkitTextStrokeColor: - return currentColorOrValidColor(style.get(), style->textStrokeColor()); + return currentColorOrValidColor(style, style->textStrokeColor()); case CSSPropertyWebkitTextStrokeWidth: - return zoomAdjustedPixelValue(style->textStrokeWidth(), style.get()); + return zoomAdjustedPixelValue(style->textStrokeWidth(), *style); case CSSPropertyTextTransform: - return cssValuePool().createValue(style->textTransform()); + return cssValuePool.createValue(style->textTransform()); case CSSPropertyTop: - return getPositionOffsetValue(style.get(), CSSPropertyTop, m_node->document().renderView()); + return positionOffsetValue(*style, CSSPropertyTop); case CSSPropertyUnicodeBidi: - return cssValuePool().createValue(style->unicodeBidi()); + return cssValuePool.createValue(style->unicodeBidi()); case CSSPropertyVerticalAlign: switch (style->verticalAlign()) { case BASELINE: - return cssValuePool().createIdentifierValue(CSSValueBaseline); + return cssValuePool.createIdentifierValue(CSSValueBaseline); case MIDDLE: - return cssValuePool().createIdentifierValue(CSSValueMiddle); + return cssValuePool.createIdentifierValue(CSSValueMiddle); case SUB: - return cssValuePool().createIdentifierValue(CSSValueSub); + return cssValuePool.createIdentifierValue(CSSValueSub); case SUPER: - return cssValuePool().createIdentifierValue(CSSValueSuper); + return cssValuePool.createIdentifierValue(CSSValueSuper); case TEXT_TOP: - return cssValuePool().createIdentifierValue(CSSValueTextTop); + return cssValuePool.createIdentifierValue(CSSValueTextTop); case TEXT_BOTTOM: - return cssValuePool().createIdentifierValue(CSSValueTextBottom); + return cssValuePool.createIdentifierValue(CSSValueTextBottom); case TOP: - return cssValuePool().createIdentifierValue(CSSValueTop); + return cssValuePool.createIdentifierValue(CSSValueTop); case BOTTOM: - return cssValuePool().createIdentifierValue(CSSValueBottom); + return cssValuePool.createIdentifierValue(CSSValueBottom); case BASELINE_MIDDLE: - return cssValuePool().createIdentifierValue(CSSValueWebkitBaselineMiddle); + return cssValuePool.createIdentifierValue(CSSValueWebkitBaselineMiddle); case LENGTH: - return cssValuePool().createValue(style->verticalAlignLength()); + return cssValuePool.createValue(style->verticalAlignLength()); } ASSERT_NOT_REACHED(); - return 0; + return nullptr; case CSSPropertyVisibility: - return cssValuePool().createValue(style->visibility()); + return cssValuePool.createValue(style->visibility()); case CSSPropertyWhiteSpace: - return cssValuePool().createValue(style->whiteSpace()); + return cssValuePool.createValue(style->whiteSpace()); case CSSPropertyWidows: if (style->hasAutoWidows()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->widows(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->widows(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyWidth: - if (renderer) { + if (renderer && !renderer->isRenderSVGModelObject()) { // According to http://www.w3.org/TR/CSS2/visudet.html#the-width-property, // the "width" property does not apply for non-replaced inline elements. if (!renderer->isReplaced() && renderer->isInline()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return zoomAdjustedPixelValue(sizingBox(renderer).width(), style.get()); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return zoomAdjustedPixelValue(sizingBox(*renderer).width(), *style); } - return zoomAdjustedPixelValueForLength(style->width(), style.get()); + return zoomAdjustedPixelValueForLength(style->width(), *style); + case CSSPropertyWillChange: + return willChangePropertyValue(style->willChange()); case CSSPropertyWordBreak: - return cssValuePool().createValue(style->wordBreak()); + return cssValuePool.createValue(style->wordBreak()); case CSSPropertyWordSpacing: - return zoomAdjustedPixelValue(style->font().wordSpacing(), style.get()); + return zoomAdjustedPixelValue(style->fontCascade().wordSpacing(), *style); case CSSPropertyWordWrap: - return cssValuePool().createValue(style->overflowWrap()); + return cssValuePool.createValue(style->overflowWrap()); case CSSPropertyWebkitLineBreak: - return cssValuePool().createValue(style->lineBreak()); + return cssValuePool.createValue(style->lineBreak()); case CSSPropertyWebkitNbspMode: - return cssValuePool().createValue(style->nbspMode()); + return cssValuePool.createValue(style->nbspMode()); case CSSPropertyResize: - return cssValuePool().createValue(style->resize()); + return cssValuePool.createValue(style->resize()); case CSSPropertyWebkitFontKerning: - return cssValuePool().createValue(style->fontDescription().kerning()); + return cssValuePool.createValue(style->fontDescription().kerning()); case CSSPropertyWebkitFontSmoothing: - return cssValuePool().createValue(style->fontDescription().fontSmoothing()); - case CSSPropertyWebkitFontVariantLigatures: { - FontDescription::LigaturesState commonLigaturesState = style->fontDescription().commonLigaturesState(); - FontDescription::LigaturesState discretionaryLigaturesState = style->fontDescription().discretionaryLigaturesState(); - FontDescription::LigaturesState historicalLigaturesState = style->fontDescription().historicalLigaturesState(); - if (commonLigaturesState == FontDescription::NormalLigaturesState && discretionaryLigaturesState == FontDescription::NormalLigaturesState - && historicalLigaturesState == FontDescription::NormalLigaturesState) - return cssValuePool().createIdentifierValue(CSSValueNormal); - - RefPtr valueList = CSSValueList::createSpaceSeparated(); - if (commonLigaturesState != FontDescription::NormalLigaturesState) - valueList->append(cssValuePool().createIdentifierValue(commonLigaturesState == FontDescription::DisabledLigaturesState ? CSSValueNoCommonLigatures : CSSValueCommonLigatures)); - if (discretionaryLigaturesState != FontDescription::NormalLigaturesState) - valueList->append(cssValuePool().createIdentifierValue(discretionaryLigaturesState == FontDescription::DisabledLigaturesState ? CSSValueNoDiscretionaryLigatures : CSSValueDiscretionaryLigatures)); - if (historicalLigaturesState != FontDescription::NormalLigaturesState) - valueList->append(cssValuePool().createIdentifierValue(historicalLigaturesState == FontDescription::DisabledLigaturesState ? CSSValueNoHistoricalLigatures : CSSValueHistoricalLigatures)); - return valueList; - } + return cssValuePool.createValue(style->fontDescription().fontSmoothing()); + case CSSPropertyFontVariantLigatures: + return fontVariantLigaturesPropertyValue(style->fontDescription().variantCommonLigatures(), style->fontDescription().variantDiscretionaryLigatures(), style->fontDescription().variantHistoricalLigatures(), style->fontDescription().variantContextualAlternates()); + case CSSPropertyFontVariantPosition: + return fontVariantPositionPropertyValue(style->fontDescription().variantPosition()); + case CSSPropertyFontVariantCaps: + return fontVariantCapsPropertyValue(style->fontDescription().variantCaps()); + case CSSPropertyFontVariantNumeric: + return fontVariantNumericPropertyValue(style->fontDescription().variantNumericFigure(), style->fontDescription().variantNumericSpacing(), style->fontDescription().variantNumericFraction(), style->fontDescription().variantNumericOrdinal(), style->fontDescription().variantNumericSlashedZero()); + case CSSPropertyFontVariantAlternates: + return fontVariantAlternatesPropertyValue(style->fontDescription().variantAlternates()); + case CSSPropertyFontVariantEastAsian: + return fontVariantEastAsianPropertyValue(style->fontDescription().variantEastAsianVariant(), style->fontDescription().variantEastAsianWidth(), style->fontDescription().variantEastAsianRuby()); case CSSPropertyZIndex: if (style->hasAutoZIndex()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createValue(style->zIndex(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createValue(style->zIndex(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyZoom: - return cssValuePool().createValue(style->zoom(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(style->zoom(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyBoxSizing: if (style->boxSizing() == CONTENT_BOX) - return cssValuePool().createIdentifierValue(CSSValueContentBox); - return cssValuePool().createIdentifierValue(CSSValueBorderBox); + return cssValuePool.createIdentifierValue(CSSValueContentBox); + return cssValuePool.createIdentifierValue(CSSValueBorderBox); #if ENABLE(DASHBOARD_SUPPORT) case CSSPropertyWebkitDashboardRegion: { const Vector& regions = style->dashboardRegions(); unsigned count = regions.size(); if (count == 1 && regions[0].type == StyleDashboardRegion::None) - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); RefPtr firstRegion; - DashboardRegion* previousRegion = 0; + DashboardRegion* previousRegion = nullptr; for (unsigned i = 0; i < count; i++) { - RefPtr region = DashboardRegion::create(); + auto region = DashboardRegion::create(); StyleDashboardRegion styleRegion = regions[i]; region->m_label = styleRegion.label; LengthBox offset = styleRegion.offset; - region->setTop(zoomAdjustedPixelValue(offset.top().value(), style.get())); - region->setRight(zoomAdjustedPixelValue(offset.right().value(), style.get())); - region->setBottom(zoomAdjustedPixelValue(offset.bottom().value(), style.get())); - region->setLeft(zoomAdjustedPixelValue(offset.left().value(), style.get())); + region->setTop(zoomAdjustedPixelValue(offset.top().value(), *style)); + region->setRight(zoomAdjustedPixelValue(offset.right().value(), *style)); + region->setBottom(zoomAdjustedPixelValue(offset.bottom().value(), *style)); + region->setLeft(zoomAdjustedPixelValue(offset.left().value(), *style)); region->m_isRectangle = (styleRegion.type == StyleDashboardRegion::Rectangle); region->m_isCircle = (styleRegion.type == StyleDashboardRegion::Circle); if (previousRegion) - previousRegion->m_next = region; + previousRegion->m_next = region.copyRef(); else - firstRegion = region; - previousRegion = region.get(); + firstRegion = region.copyRef(); + previousRegion = region.ptr(); } - return cssValuePool().createValue(firstRegion.release()); + return cssValuePool.createValue(WTFMove(firstRegion)); } #endif - case CSSPropertyWebkitAnimationDelay: - return getDelayValue(style->animations()); - case CSSPropertyWebkitAnimationDirection: { - RefPtr list = CSSValueList::createCommaSeparated(); + case CSSPropertyAnimationDelay: + return delayValue(style->animations()); + case CSSPropertyAnimationDirection: { + auto list = CSSValueList::createCommaSeparated(); const AnimationList* t = style->animations(); if (t) { for (size_t i = 0; i < t->size(); ++i) { - if (t->animation(i).direction()) - list->append(cssValuePool().createIdentifierValue(CSSValueAlternate)); - else - list->append(cssValuePool().createIdentifierValue(CSSValueNormal)); + switch (t->animation(i).direction()) { + case Animation::AnimationDirectionNormal: + list->append(cssValuePool.createIdentifierValue(CSSValueNormal)); + break; + case Animation::AnimationDirectionAlternate: + list->append(cssValuePool.createIdentifierValue(CSSValueAlternate)); + break; + case Animation::AnimationDirectionReverse: + list->append(cssValuePool.createIdentifierValue(CSSValueReverse)); + break; + case Animation::AnimationDirectionAlternateReverse: + list->append(cssValuePool.createIdentifierValue(CSSValueAlternateReverse)); + break; + } } } else - list->append(cssValuePool().createIdentifierValue(CSSValueNormal)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueNormal)); + return WTFMove(list); } - case CSSPropertyWebkitAnimationDuration: - return getDurationValue(style->animations()); - case CSSPropertyWebkitAnimationFillMode: { - RefPtr list = CSSValueList::createCommaSeparated(); + case CSSPropertyAnimationDuration: + return durationValue(style->animations()); + case CSSPropertyAnimationFillMode: { + auto list = CSSValueList::createCommaSeparated(); const AnimationList* t = style->animations(); if (t) { for (size_t i = 0; i < t->size(); ++i) { switch (t->animation(i).fillMode()) { case AnimationFillModeNone: - list->append(cssValuePool().createIdentifierValue(CSSValueNone)); + list->append(cssValuePool.createIdentifierValue(CSSValueNone)); break; case AnimationFillModeForwards: - list->append(cssValuePool().createIdentifierValue(CSSValueForwards)); + list->append(cssValuePool.createIdentifierValue(CSSValueForwards)); break; case AnimationFillModeBackwards: - list->append(cssValuePool().createIdentifierValue(CSSValueBackwards)); + list->append(cssValuePool.createIdentifierValue(CSSValueBackwards)); break; case AnimationFillModeBoth: - list->append(cssValuePool().createIdentifierValue(CSSValueBoth)); + list->append(cssValuePool.createIdentifierValue(CSSValueBoth)); break; } } } else - list->append(cssValuePool().createIdentifierValue(CSSValueNone)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueNone)); + return WTFMove(list); } - case CSSPropertyWebkitAnimationIterationCount: { - RefPtr list = CSSValueList::createCommaSeparated(); + case CSSPropertyAnimationIterationCount: { + auto list = CSSValueList::createCommaSeparated(); const AnimationList* t = style->animations(); if (t) { for (size_t i = 0; i < t->size(); ++i) { double iterationCount = t->animation(i).iterationCount(); if (iterationCount == Animation::IterationCountInfinite) - list->append(cssValuePool().createIdentifierValue(CSSValueInfinite)); + list->append(cssValuePool.createIdentifierValue(CSSValueInfinite)); else - list->append(cssValuePool().createValue(iterationCount, CSSPrimitiveValue::CSS_NUMBER)); + list->append(cssValuePool.createValue(iterationCount, CSSPrimitiveValue::CSS_NUMBER)); } } else - list->append(cssValuePool().createValue(Animation::initialAnimationIterationCount(), CSSPrimitiveValue::CSS_NUMBER)); - return list.release(); + list->append(cssValuePool.createValue(Animation::initialIterationCount(), CSSPrimitiveValue::CSS_NUMBER)); + return WTFMove(list); } - case CSSPropertyWebkitAnimationName: { - RefPtr list = CSSValueList::createCommaSeparated(); + case CSSPropertyAnimationName: { + auto list = CSSValueList::createCommaSeparated(); const AnimationList* t = style->animations(); if (t) { for (size_t i = 0; i < t->size(); ++i) - list->append(cssValuePool().createValue(t->animation(i).name(), CSSPrimitiveValue::CSS_STRING)); + list->append(cssValuePool.createValue(t->animation(i).name(), CSSPrimitiveValue::CSS_STRING)); } else - list->append(cssValuePool().createIdentifierValue(CSSValueNone)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueNone)); + return WTFMove(list); } - case CSSPropertyWebkitAnimationPlayState: { - RefPtr list = CSSValueList::createCommaSeparated(); + case CSSPropertyAnimationPlayState: { + auto list = CSSValueList::createCommaSeparated(); const AnimationList* t = style->animations(); if (t) { for (size_t i = 0; i < t->size(); ++i) { int prop = t->animation(i).playState(); if (prop == AnimPlayStatePlaying) - list->append(cssValuePool().createIdentifierValue(CSSValueRunning)); + list->append(cssValuePool.createIdentifierValue(CSSValueRunning)); else - list->append(cssValuePool().createIdentifierValue(CSSValuePaused)); + list->append(cssValuePool.createIdentifierValue(CSSValuePaused)); } } else - list->append(cssValuePool().createIdentifierValue(CSSValueRunning)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueRunning)); + return WTFMove(list); } - case CSSPropertyWebkitAnimationTimingFunction: - return getTimingFunctionValue(style->animations()); + case CSSPropertyAnimationTimingFunction: + return timingFunctionValue(style->animations()); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case CSSPropertyWebkitAnimationTrigger: + return animationTriggerValue(style->animations(), *style); +#endif case CSSPropertyWebkitAppearance: - return cssValuePool().createValue(style->appearance()); + return cssValuePool.createValue(style->appearance()); case CSSPropertyWebkitAspectRatio: - if (!style->hasAspectRatio()) - return cssValuePool().createIdentifierValue(CSSValueNone); + if (style->aspectRatioType() == AspectRatioAuto) + return cssValuePool.createIdentifierValue(CSSValueAuto); + if (style->aspectRatioType() == AspectRatioFromDimensions) + return cssValuePool.createIdentifierValue(CSSValueFromDimensions); + if (style->aspectRatioType() == AspectRatioFromIntrinsic) + return cssValuePool.createIdentifierValue(CSSValueFromIntrinsic); return CSSAspectRatioValue::create(style->aspectRatioNumerator(), style->aspectRatioDenominator()); case CSSPropertyWebkitBackfaceVisibility: - return cssValuePool().createIdentifierValue((style->backfaceVisibility() == BackfaceVisibilityHidden) ? CSSValueHidden : CSSValueVisible); + return cssValuePool.createIdentifierValue((style->backfaceVisibility() == BackfaceVisibilityHidden) ? CSSValueHidden : CSSValueVisible); case CSSPropertyWebkitBorderImage: return valueForNinePieceImage(style->borderImage()); case CSSPropertyBorderImageOutset: @@ -2590,256 +3516,231 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyWebkitMaskBoxImageSource: if (style->maskBoxImageSource()) return style->maskBoxImageSource()->cssValue(); - return cssValuePool().createIdentifierValue(CSSValueNone); + return cssValuePool.createIdentifierValue(CSSValueNone); case CSSPropertyWebkitFontSizeDelta: // Not a real style property -- used by the editing engine -- so has no computed value. break; + case CSSPropertyWebkitInitialLetter: { + auto drop = !style->initialLetterDrop() ? cssValuePool.createIdentifierValue(CSSValueNormal) : cssValuePool.createValue(style->initialLetterDrop(), CSSPrimitiveValue::CSS_NUMBER); + auto size = !style->initialLetterHeight() ? cssValuePool.createIdentifierValue(CSSValueNormal) : cssValuePool.createValue(style->initialLetterHeight(), CSSPrimitiveValue::CSS_NUMBER); + return cssValuePool.createValue(Pair::create(WTFMove(drop), WTFMove(size))); + } case CSSPropertyWebkitMarginBottomCollapse: case CSSPropertyWebkitMarginAfterCollapse: - return cssValuePool().createValue(style->marginAfterCollapse()); + return cssValuePool.createValue(style->marginAfterCollapse()); case CSSPropertyWebkitMarginTopCollapse: case CSSPropertyWebkitMarginBeforeCollapse: - return cssValuePool().createValue(style->marginBeforeCollapse()); + return cssValuePool.createValue(style->marginBeforeCollapse()); #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) case CSSPropertyWebkitOverflowScrolling: if (!style->useTouchOverflowScrolling()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - return cssValuePool().createIdentifierValue(CSSValueTouch); + return cssValuePool.createIdentifierValue(CSSValueAuto); + return cssValuePool.createIdentifierValue(CSSValueTouch); #endif - case CSSPropertyWebkitPerspective: + case CSSPropertyPerspective: if (!style->hasPerspective()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return zoomAdjustedPixelValue(style->perspective(), style.get()); - case CSSPropertyWebkitPerspectiveOrigin: { - RefPtr list = CSSValueList::createSpaceSeparated(); + return cssValuePool.createIdentifierValue(CSSValueNone); + return zoomAdjustedPixelValue(style->perspective(), *style); + case CSSPropertyPerspectiveOrigin: { + auto list = CSSValueList::createSpaceSeparated(); if (renderer) { LayoutRect box; - if (renderer->isBox()) - box = toRenderBox(renderer)->borderBoxRect(); + if (is(*renderer)) + box = downcast(*renderer).borderBoxRect(); - RenderView* renderView = m_node->document().renderView(); - list->append(zoomAdjustedPixelValue(minimumValueForLength(style->perspectiveOriginX(), box.width(), renderView), style.get())); - list->append(zoomAdjustedPixelValue(minimumValueForLength(style->perspectiveOriginY(), box.height(), renderView), style.get())); + list->append(zoomAdjustedPixelValue(minimumValueForLength(style->perspectiveOriginX(), box.width()), *style)); + list->append(zoomAdjustedPixelValue(minimumValueForLength(style->perspectiveOriginY(), box.height()), *style)); } else { - list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginX(), style.get())); - list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginY(), style.get())); + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginX(), *style)); + list->append(zoomAdjustedPixelValueForLength(style->perspectiveOriginY(), *style)); } - return list.release(); + return WTFMove(list); } case CSSPropertyWebkitRtlOrdering: - return cssValuePool().createIdentifierValue(style->rtlOrdering() ? CSSValueVisual : CSSValueLogical); -#if PLATFORM(IOS) - // FIXME: This property shouldn't be iOS-specific. Once we fix up its usage in InlineTextBox::paintCompositionBackground() - // we should remove the PLATFORM(IOS)-guard. See . - case CSSPropertyWebkitCompositionFillColor: - return currentColorOrValidColor(style.get(), style->compositionFillColor()); -#endif + return cssValuePool.createIdentifierValue(style->rtlOrdering() ? CSSValueVisual : CSSValueLogical); #if ENABLE(TOUCH_EVENTS) case CSSPropertyWebkitTapHighlightColor: - return currentColorOrValidColor(style.get(), style->tapHighlightColor()); + return currentColorOrValidColor(style, style->tapHighlightColor()); + case CSSPropertyTouchAction: + return cssValuePool.createValue(style->touchAction()); #endif #if PLATFORM(IOS) case CSSPropertyWebkitTouchCallout: - return cssValuePool().createIdentifierValue(style->touchCalloutEnabled() ? CSSValueDefault : CSSValueNone); + return cssValuePool.createIdentifierValue(style->touchCalloutEnabled() ? CSSValueDefault : CSSValueNone); #endif case CSSPropertyWebkitUserDrag: - return cssValuePool().createValue(style->userDrag()); + return cssValuePool.createValue(style->userDrag()); case CSSPropertyWebkitUserSelect: - return cssValuePool().createValue(style->userSelect()); + return cssValuePool.createValue(style->userSelect()); case CSSPropertyBorderBottomLeftRadius: - return getBorderRadiusCornerValue(style->borderBottomLeftRadius(), style.get(), m_node->document().renderView()); + return borderRadiusCornerValue(style->borderBottomLeftRadius(), *style); case CSSPropertyBorderBottomRightRadius: - return getBorderRadiusCornerValue(style->borderBottomRightRadius(), style.get(), m_node->document().renderView()); + return borderRadiusCornerValue(style->borderBottomRightRadius(), *style); case CSSPropertyBorderTopLeftRadius: - return getBorderRadiusCornerValue(style->borderTopLeftRadius(), style.get(), m_node->document().renderView()); + return borderRadiusCornerValue(style->borderTopLeftRadius(), *style); case CSSPropertyBorderTopRightRadius: - return getBorderRadiusCornerValue(style->borderTopRightRadius(), style.get(), m_node->document().renderView()); + return borderRadiusCornerValue(style->borderTopRightRadius(), *style); case CSSPropertyClip: { if (!style->hasClip()) - return cssValuePool().createIdentifierValue(CSSValueAuto); - RefPtr rect = Rect::create(); - rect->setTop(zoomAdjustedPixelValue(style->clip().top().value(), style.get())); - rect->setRight(zoomAdjustedPixelValue(style->clip().right().value(), style.get())); - rect->setBottom(zoomAdjustedPixelValue(style->clip().bottom().value(), style.get())); - rect->setLeft(zoomAdjustedPixelValue(style->clip().left().value(), style.get())); - return cssValuePool().createValue(rect.release()); + return cssValuePool.createIdentifierValue(CSSValueAuto); + auto rect = Rect::create(); + rect->setTop(autoOrZoomAdjustedValue(style->clip().top(), *style)); + rect->setRight(autoOrZoomAdjustedValue(style->clip().right(), *style)); + rect->setBottom(autoOrZoomAdjustedValue(style->clip().bottom(), *style)); + rect->setLeft(autoOrZoomAdjustedValue(style->clip().left(), *style)); + return cssValuePool.createValue(WTFMove(rect)); } case CSSPropertySpeak: - return cssValuePool().createValue(style->speak()); - case CSSPropertyWebkitTransform: - return computedTransform(renderer, style.get()); - case CSSPropertyWebkitTransformOrigin: { - RefPtr list = CSSValueList::createSpaceSeparated(); + return cssValuePool.createValue(style->speak()); + case CSSPropertyTransform: + return computedTransform(renderer, *style); + case CSSPropertyTransformOrigin: { + auto list = CSSValueList::createSpaceSeparated(); if (renderer) { LayoutRect box; - if (renderer->isBox()) - box = toRenderBox(renderer)->borderBoxRect(); + if (is(*renderer)) + box = downcast(*renderer).borderBoxRect(); - RenderView* renderView = m_node->document().renderView(); - list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginX(), box.width(), renderView), style.get())); - list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginY(), box.height(), renderView), style.get())); + list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginX(), box.width()), *style)); + list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginY(), box.height()), *style)); if (style->transformOriginZ() != 0) - list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get())); + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), *style)); } else { - list->append(zoomAdjustedPixelValueForLength(style->transformOriginX(), style.get())); - list->append(zoomAdjustedPixelValueForLength(style->transformOriginY(), style.get())); + list->append(zoomAdjustedPixelValueForLength(style->transformOriginX(), *style)); + list->append(zoomAdjustedPixelValueForLength(style->transformOriginY(), *style)); if (style->transformOriginZ() != 0) - list->append(zoomAdjustedPixelValue(style->transformOriginZ(), style.get())); + list->append(zoomAdjustedPixelValue(style->transformOriginZ(), *style)); } - return list.release(); + return WTFMove(list); } + case CSSPropertyTransformStyle: case CSSPropertyWebkitTransformStyle: - return cssValuePool().createIdentifierValue((style->transformStyle3D() == TransformStyle3DPreserve3D) ? CSSValuePreserve3d : CSSValueFlat); + return cssValuePool.createIdentifierValue((style->transformStyle3D() == TransformStyle3DPreserve3D) ? CSSValuePreserve3d : CSSValueFlat); case CSSPropertyTransitionDelay: - case CSSPropertyWebkitTransitionDelay: - return getDelayValue(style->transitions()); + return delayValue(style->transitions()); case CSSPropertyTransitionDuration: - case CSSPropertyWebkitTransitionDuration: - return getDurationValue(style->transitions()); + return durationValue(style->transitions()); case CSSPropertyTransitionProperty: - case CSSPropertyWebkitTransitionProperty: - return getTransitionPropertyValue(style->transitions()); + return transitionPropertyValue(style->transitions()); case CSSPropertyTransitionTimingFunction: - case CSSPropertyWebkitTransitionTimingFunction: - return getTimingFunctionValue(style->transitions()); - case CSSPropertyTransition: - case CSSPropertyWebkitTransition: { - const AnimationList* animList = style->transitions(); - if (animList) { - RefPtr transitionsList = CSSValueList::createCommaSeparated(); - for (size_t i = 0; i < animList->size(); ++i) { - RefPtr list = CSSValueList::createSpaceSeparated(); - const Animation& animation = animList->animation(i); + return timingFunctionValue(style->transitions()); + case CSSPropertyTransition: { + if (auto* animationList = style->transitions()) { + auto transitionsList = CSSValueList::createCommaSeparated(); + for (size_t i = 0; i < animationList->size(); ++i) { + auto list = CSSValueList::createSpaceSeparated(); + auto& animation = animationList->animation(i); list->append(createTransitionPropertyValue(animation)); - list->append(cssValuePool().createValue(animation.duration(), CSSPrimitiveValue::CSS_S)); - list->append(createTimingFunctionValue(animation.timingFunction().get())); - list->append(cssValuePool().createValue(animation.delay(), CSSPrimitiveValue::CSS_S)); - transitionsList->append(list); + list->append(cssValuePool.createValue(animation.duration(), CSSPrimitiveValue::CSS_S)); + list->append(createTimingFunctionValue(*animation.timingFunction())); + list->append(cssValuePool.createValue(animation.delay(), CSSPrimitiveValue::CSS_S)); + transitionsList->append(WTFMove(list)); } - return transitionsList.release(); + return WTFMove(transitionsList); } - RefPtr list = CSSValueList::createSpaceSeparated(); + auto list = CSSValueList::createSpaceSeparated(); // transition-property default value. - list->append(cssValuePool().createIdentifierValue(CSSValueAll)); - list->append(cssValuePool().createValue(Animation::initialAnimationDuration(), CSSPrimitiveValue::CSS_S)); - list->append(createTimingFunctionValue(Animation::initialAnimationTimingFunction().get())); - list->append(cssValuePool().createValue(Animation::initialAnimationDelay(), CSSPrimitiveValue::CSS_S)); - return list.release(); + list->append(cssValuePool.createIdentifierValue(CSSValueAll)); + list->append(cssValuePool.createValue(Animation::initialDuration(), CSSPrimitiveValue::CSS_S)); + list->append(createTimingFunctionValue(Animation::initialTimingFunction())); + list->append(cssValuePool.createValue(Animation::initialDelay(), CSSPrimitiveValue::CSS_S)); + return WTFMove(list); } case CSSPropertyPointerEvents: - return cssValuePool().createValue(style->pointerEvents()); - case CSSPropertyWebkitColorCorrection: - return cssValuePool().createValue(style->colorSpace()); + return cssValuePool.createValue(style->pointerEvents()); case CSSPropertyWebkitLineGrid: if (style->lineGrid().isNull()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->lineGrid(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createIdentifierValue(CSSValueNone); + return cssValuePool.createValue(style->lineGrid(), CSSPrimitiveValue::CSS_STRING); case CSSPropertyWebkitLineSnap: return CSSPrimitiveValue::create(style->lineSnap()); case CSSPropertyWebkitLineAlign: return CSSPrimitiveValue::create(style->lineAlign()); - case CSSPropertyWebkitWritingMode: - return cssValuePool().createValue(style->writingMode()); + case CSSPropertyWritingMode: + return cssValuePool.createValue(style->writingMode()); case CSSPropertyWebkitTextCombine: - return cssValuePool().createValue(style->textCombine()); + return cssValuePool.createValue(style->textCombine()); case CSSPropertyWebkitTextOrientation: return CSSPrimitiveValue::create(style->textOrientation()); case CSSPropertyWebkitLineBoxContain: return createLineBoxContainValue(style->lineBoxContain()); - case CSSPropertyWebkitAlt: - return altTextToCSSValue(style.get()); + case CSSPropertyAlt: + return altTextToCSSValue(*style); case CSSPropertyContent: - return contentToCSSValue(style.get()); + return contentToCSSValue(*style); case CSSPropertyCounterIncrement: - return counterToCSSValue(style.get(), propertyID); + return counterToCSSValue(*style, propertyID); case CSSPropertyCounterReset: - return counterToCSSValue(style.get(), propertyID); + return counterToCSSValue(*style, propertyID); case CSSPropertyWebkitClipPath: { - ClipPathOperation* operation = style->clipPath(); + auto* operation = style->clipPath(); if (!operation) - return cssValuePool().createIdentifierValue(CSSValueNone); -#if ENABLE(SVG) - if (operation->type() == ClipPathOperation::Reference) { - ReferenceClipPathOperation& referenceOperation = toReferenceClipPathOperation(*operation); - return CSSPrimitiveValue::create(referenceOperation.url(), CSSPrimitiveValue::CSS_URI); - } -#endif - RefPtr list = CSSValueList::createSpaceSeparated(); - if (operation->type() == ClipPathOperation::Shape) { - ShapeClipPathOperation& shapeOperation = toShapeClipPathOperation(*operation); - list->append(valueForBasicShape(style.get(), shapeOperation.basicShape())); + return cssValuePool.createIdentifierValue(CSSValueNone); + if (is(*operation)) + return CSSPrimitiveValue::create(downcast(*operation).url(), CSSPrimitiveValue::CSS_URI); + auto list = CSSValueList::createSpaceSeparated(); + if (is(*operation)) { + auto& shapeOperation = downcast(*operation); + list->append(valueForBasicShape(*style, shapeOperation.basicShape())); if (shapeOperation.referenceBox() != BoxMissing) - list->append(cssValuePool().createValue(shapeOperation.referenceBox())); - } - if (operation->type() == ClipPathOperation::Box) { - BoxClipPathOperation& boxOperation = toBoxClipPathOperation(*operation); - list->append(cssValuePool().createValue(boxOperation.referenceBox())); + list->append(cssValuePool.createValue(shapeOperation.referenceBox())); } - return list.release(); + if (is(*operation)) + list->append(cssValuePool.createValue(downcast(*operation).referenceBox())); + return WTFMove(list); } #if ENABLE(CSS_REGIONS) case CSSPropertyWebkitFlowInto: - if (style->flowThread().isNull()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->flowThread(), CSSPrimitiveValue::CSS_STRING); + if (!style->hasFlowInto()) + return cssValuePool.createIdentifierValue(CSSValueNone); + return cssValuePool.createValue(style->flowThread(), CSSPrimitiveValue::CSS_STRING); case CSSPropertyWebkitFlowFrom: if (!style->hasFlowFrom()) - return cssValuePool().createIdentifierValue(CSSValueNone); - return cssValuePool().createValue(style->regionThread(), CSSPrimitiveValue::CSS_STRING); + return cssValuePool.createIdentifierValue(CSSValueNone); + return cssValuePool.createValue(style->regionThread(), CSSPrimitiveValue::CSS_STRING); case CSSPropertyWebkitRegionFragment: - return cssValuePool().createValue(style->regionFragment()); -#endif -#if ENABLE(CSS_EXCLUSIONS) - case CSSPropertyWebkitWrapFlow: - return cssValuePool().createValue(style->wrapFlow()); - case CSSPropertyWebkitWrapThrough: - return cssValuePool().createValue(style->wrapThrough()); -#endif -#if ENABLE(CSS_SHAPES) - case CSSPropertyWebkitShapeMargin: - return cssValuePool().createValue(style->shapeMargin()); - case CSSPropertyWebkitShapePadding: - return cssValuePool().createValue(style->shapePadding()); - case CSSPropertyWebkitShapeImageThreshold: - return cssValuePool().createValue(style->shapeImageThreshold(), CSSPrimitiveValue::CSS_NUMBER); - case CSSPropertyWebkitShapeInside: - return shapePropertyValue(style.get(), style->shapeInside()); - case CSSPropertyWebkitShapeOutside: - return shapePropertyValue(style.get(), style->shapeOutside()); + return cssValuePool.createValue(style->regionFragment()); #endif -#if ENABLE(CSS_FILTERS) - case CSSPropertyWebkitFilter: - return valueForFilter(style.get(), style->filter()); + case CSSPropertyShapeMargin: + return cssValuePool.createValue(style->shapeMargin(), *style); + case CSSPropertyShapeImageThreshold: + return cssValuePool.createValue(style->shapeImageThreshold(), CSSPrimitiveValue::CSS_NUMBER); + case CSSPropertyShapeOutside: + return shapePropertyValue(*style, style->shapeOutside()); + case CSSPropertyFilter: + return valueForFilter(*style, style->filter()); +#if ENABLE(FILTERS_LEVEL_2) + case CSSPropertyWebkitBackdropFilter: + return valueForFilter(*style, style->backdropFilter()); #endif #if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: - return cssValuePool().createValue(style->blendMode()); + case CSSPropertyMixBlendMode: + return cssValuePool.createValue(style->blendMode()); + case CSSPropertyIsolation: + return cssValuePool.createValue(style->isolation()); #endif - case CSSPropertyWebkitBackgroundBlendMode: { - const FillLayer* layers = style->backgroundLayers(); - if (!layers->next()) - return cssValuePool().createValue(layers->blendMode()); - - RefPtr list = CSSValueList::createCommaSeparated(); - for (const FillLayer* currLayer = layers; currLayer; currLayer = currLayer->next()) - list->append(cssValuePool().createValue(currLayer->blendMode())); - - return list.release(); + case CSSPropertyBackgroundBlendMode: { + auto& layers = style->backgroundLayers(); + if (!layers.next()) + return cssValuePool.createValue(layers.blendMode()); + auto list = CSSValueList::createCommaSeparated(); + for (auto* currLayer = &layers; currLayer; currLayer = currLayer->next()) + list->append(cssValuePool.createValue(currLayer->blendMode())); + return WTFMove(list); } case CSSPropertyBackground: return getBackgroundShorthandValue(); case CSSPropertyBorder: { - RefPtr value = propertyValue(CSSPropertyBorderTop, DoNotUpdateLayout); - const CSSPropertyID properties[3] = { CSSPropertyBorderRight, CSSPropertyBorderBottom, - CSSPropertyBorderLeft }; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { - if (!compareCSSValuePtr(value, propertyValue(properties[i], DoNotUpdateLayout))) - return 0; + auto value = propertyValue(CSSPropertyBorderTop, DoNotUpdateLayout); + const CSSPropertyID properties[3] = { CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; + for (auto& property : properties) { + if (!compareCSSValuePtr(value, propertyValue(property, DoNotUpdateLayout))) + return nullptr; } - return value.release(); + return value; } case CSSPropertyBorderBottom: return getCSSPropertyValuesForShorthandProperties(borderBottomShorthand()); @@ -2850,7 +3751,7 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyBorderImage: return valueForNinePieceImage(style->borderImage()); case CSSPropertyBorderRadius: - return getBorderRadiusShorthandValue(style.get(), m_node->document().renderView()); + return borderRadiusShorthandValue(*style); case CSSPropertyBorderRight: return getCSSPropertyValuesForShorthandProperties(borderRightShorthand()); case CSSPropertyBorderStyle: @@ -2859,10 +3760,10 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert return getCSSPropertyValuesForShorthandProperties(borderTopShorthand()); case CSSPropertyBorderWidth: return getCSSPropertyValuesForSidesShorthand(borderWidthShorthand()); - case CSSPropertyWebkitColumnRule: - return getCSSPropertyValuesForShorthandProperties(webkitColumnRuleShorthand()); - case CSSPropertyWebkitColumns: - return getCSSPropertyValuesForShorthandProperties(webkitColumnsShorthand()); + case CSSPropertyColumnRule: + return getCSSPropertyValuesForShorthandProperties(columnRuleShorthand()); + case CSSPropertyColumns: + return getCSSPropertyValuesForShorthandProperties(columnsShorthand()); case CSSPropertyListStyle: return getCSSPropertyValuesForShorthandProperties(listStyleShorthand()); case CSSPropertyMargin: @@ -2871,12 +3772,83 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert return getCSSPropertyValuesForShorthandProperties(outlineShorthand()); case CSSPropertyPadding: return getCSSPropertyValuesForSidesShorthand(paddingShorthand()); + +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPropertyScrollSnapMargin: + return getCSSPropertyValuesForSidesShorthand(scrollSnapMarginShorthand()); + case CSSPropertyScrollSnapMarginBottom: + return zoomAdjustedPixelValueForLength(style->scrollSnapMarginBottom(), *style); + case CSSPropertyScrollSnapMarginTop: + return zoomAdjustedPixelValueForLength(style->scrollSnapMarginTop(), *style); + case CSSPropertyScrollSnapMarginRight: + return zoomAdjustedPixelValueForLength(style->scrollSnapMarginRight(), *style); + case CSSPropertyScrollSnapMarginLeft: + return zoomAdjustedPixelValueForLength(style->scrollSnapMarginLeft(), *style); + case CSSPropertyScrollPadding: + return getCSSPropertyValuesForSidesShorthand(scrollPaddingShorthand()); + case CSSPropertyScrollPaddingBottom: + return zoomAdjustedPixelValueForLength(style->scrollPaddingBottom(), *style); + case CSSPropertyScrollPaddingTop: + return zoomAdjustedPixelValueForLength(style->scrollPaddingTop(), *style); + case CSSPropertyScrollPaddingRight: + return zoomAdjustedPixelValueForLength(style->scrollPaddingRight(), *style); + case CSSPropertyScrollPaddingLeft: + return zoomAdjustedPixelValueForLength(style->scrollPaddingLeft(), *style); + case CSSPropertyScrollSnapType: + return valueForScrollSnapType(style->scrollSnapType()); + case CSSPropertyScrollSnapAlign: + return valueForScrollSnapAlignment(style->scrollSnapAlign()); +#endif + +#if ENABLE(CSS_TRAILING_WORD) + case CSSPropertyAppleTrailingWord: + return cssValuePool.createValue(style->trailingWord()); +#endif + +#if ENABLE(APPLE_PAY) + case CSSPropertyApplePayButtonStyle: + return cssValuePool.createValue(style->applePayButtonStyle()); + case CSSPropertyApplePayButtonType: + return cssValuePool.createValue(style->applePayButtonType()); +#endif + /* Individual properties not part of the spec */ case CSSPropertyBackgroundRepeatX: case CSSPropertyBackgroundRepeatY: break; + // Length properties for SVG. + case CSSPropertyCx: + return zoomAdjustedPixelValueForLength(style->svgStyle().cx(), *style); + case CSSPropertyCy: + return zoomAdjustedPixelValueForLength(style->svgStyle().cy(), *style); + case CSSPropertyR: + return zoomAdjustedPixelValueForLength(style->svgStyle().r(), *style); + case CSSPropertyRx: + return zoomAdjustedPixelValueForLength(style->svgStyle().rx(), *style); + case CSSPropertyRy: + return zoomAdjustedPixelValueForLength(style->svgStyle().ry(), *style); + case CSSPropertyStrokeDashoffset: + return zoomAdjustedPixelValueForLength(style->svgStyle().strokeDashOffset(), *style); + case CSSPropertyX: + return zoomAdjustedPixelValueForLength(style->svgStyle().x(), *style); + case CSSPropertyY: + return zoomAdjustedPixelValueForLength(style->svgStyle().y(), *style); + case CSSPropertyWebkitTextZoom: + return cssValuePool.createValue(style->textZoom()); + + case CSSPropertyPaintOrder: + return paintOrder(style->paintOrder()); + case CSSPropertyStrokeLinecap: + return CSSPrimitiveValue::create(style->capStyle()); + case CSSPropertyStrokeLinejoin: + return CSSPrimitiveValue::create(style->joinStyle()); + case CSSPropertyStrokeWidth: + return zoomAdjustedPixelValueForLength(style->strokeWidth(), *style); + /* Unimplemented CSS 3 properties (including CSS3 shorthand properties) */ + case CSSPropertyAll: + case CSSPropertyAnimation: case CSSPropertyWebkitTextEmphasis: case CSSPropertyTextLineThrough: case CSSPropertyTextLineThroughColor: @@ -2942,7 +3914,6 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert break; /* Unimplemented -webkit- properties */ - case CSSPropertyWebkitAnimation: case CSSPropertyWebkitBorderRadius: case CSSPropertyWebkitMarginCollapse: case CSSPropertyWebkitMarquee: @@ -2950,12 +3921,12 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyWebkitMask: case CSSPropertyWebkitMaskRepeatX: case CSSPropertyWebkitMaskRepeatY: - case CSSPropertyWebkitPerspectiveOriginX: - case CSSPropertyWebkitPerspectiveOriginY: + case CSSPropertyPerspectiveOriginX: + case CSSPropertyPerspectiveOriginY: case CSSPropertyWebkitTextStroke: - case CSSPropertyWebkitTransformOriginX: - case CSSPropertyWebkitTransformOriginY: - case CSSPropertyWebkitTransformOriginZ: + case CSSPropertyTransformOriginX: + case CSSPropertyTransformOriginY: + case CSSPropertyTransformOriginZ: break; #if ENABLE(CSS_DEVICE_ADAPTATION) @@ -2966,13 +3937,11 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert break; #endif -#if ENABLE(SVG) case CSSPropertyBufferedRendering: case CSSPropertyClipPath: case CSSPropertyClipRule: case CSSPropertyMask: case CSSPropertyEnableBackground: - case CSSPropertyFilter: case CSSPropertyFloodColor: case CSSPropertyFloodOpacity: case CSSPropertyLightingColor: @@ -2993,12 +3962,8 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyShapeRendering: case CSSPropertyStroke: case CSSPropertyStrokeDasharray: - case CSSPropertyStrokeDashoffset: - case CSSPropertyStrokeLinecap: - case CSSPropertyStrokeLinejoin: case CSSPropertyStrokeMiterlimit: case CSSPropertyStrokeOpacity: - case CSSPropertyStrokeWidth: case CSSPropertyAlignmentBaseline: case CSSPropertyBaselineShift: case CSSPropertyDominantBaseline: @@ -3007,142 +3972,166 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyKerning: case CSSPropertyTextAnchor: case CSSPropertyVectorEffect: - case CSSPropertyWritingMode: case CSSPropertyWebkitSvgShadow: return svgPropertyValue(propertyID, DoNotUpdateLayout); -#endif + case CSSPropertyCustom: + ASSERT_NOT_REACHED(); + return nullptr; } logUnimplementedPropertyID(propertyID); - return 0; + return nullptr; } String CSSComputedStyleDeclaration::getPropertyValue(CSSPropertyID propertyID) const { - RefPtr value = getPropertyCSSValue(propertyID); - if (value) - return value->cssText(); - return ""; + auto value = getPropertyCSSValue(propertyID); + if (!value) + return emptyString(); // FIXME: Should this be null instead, as it is in StyleProperties::getPropertyValue? + return value->cssText(); } unsigned CSSComputedStyleDeclaration::length() const { - Node* node = m_node.get(); - if (!node) - return 0; + updateStyleIfNeededForProperty(m_element.get(), CSSPropertyCustom); - RenderStyle* style = node->computedStyle(m_pseudoElementSpecifier); + auto* style = m_element->computedStyle(m_pseudoElementSpecifier); if (!style) return 0; - return numComputedProperties; + return numComputedProperties + style->customProperties().size(); } String CSSComputedStyleDeclaration::item(unsigned i) const { if (i >= length()) - return ""; - - return getPropertyNameString(computedProperties[i]); + return String(); + + if (i < numComputedProperties) + return getPropertyNameString(computedProperties[i]); + + auto* style = m_element->computedStyle(m_pseudoElementSpecifier); + if (!style) + return String(); + + unsigned index = i - numComputedProperties; + + const auto& customProperties = style->customProperties(); + if (index >= customProperties.size()) + return String(); + + Vector results; + copyKeysToVector(customProperties, results); + return results.at(index); } -bool ComputedStyleExtractor::propertyMatches(CSSPropertyID propertyID, const CSSValue* value) const +bool ComputedStyleExtractor::propertyMatches(CSSPropertyID propertyID, const CSSValue* value) { - if (propertyID == CSSPropertyFontSize && value->isPrimitiveValue() && m_node) { - m_node->document().updateLayoutIgnorePendingStylesheets(); - RenderStyle* style = m_node->computedStyle(m_pseudoElementSpecifier); - if (style && style->fontDescription().keywordSize()) { - CSSValueID sizeValue = cssIdentifierForFontSizeKeyword(style->fontDescription().keywordSize()); - const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->isValueID() && primitiveValue->getValueID() == sizeValue) - return true; + if (!m_element) + return false; + if (propertyID == CSSPropertyFontSize && is(*value)) { + m_element->document().updateLayoutIgnorePendingStylesheets(); + if (auto* style = m_element->computedStyle(m_pseudoElementSpecifier)) { + if (CSSValueID sizeIdentifier = style->fontDescription().keywordSizeAsIdentifier()) { + auto& primitiveValue = downcast(*value); + if (primitiveValue.isValueID() && primitiveValue.valueID() == sizeIdentifier) + return true; + } } } RefPtr computedValue = propertyValue(propertyID); return computedValue && value && computedValue->equals(*value); } -PassRef ComputedStyleExtractor::copyProperties() const +Ref ComputedStyleExtractor::copyProperties() { return copyPropertiesInSet(computedProperties, numComputedProperties); } -PassRefPtr ComputedStyleExtractor::getCSSPropertyValuesForShorthandProperties(const StylePropertyShorthand& shorthand) const +RefPtr ComputedStyleExtractor::getCSSPropertyValuesForShorthandProperties(const StylePropertyShorthand& shorthand) { - RefPtr list = CSSValueList::createSpaceSeparated(); - for (size_t i = 0; i < shorthand.length(); ++i) { - RefPtr value = propertyValue(shorthand.properties()[i], DoNotUpdateLayout); - list->append(value); - } - return list.release(); + auto list = CSSValueList::createSpaceSeparated(); + for (size_t i = 0; i < shorthand.length(); ++i) + list->append(propertyValue(shorthand.properties()[i], DoNotUpdateLayout).releaseNonNull()); + return WTFMove(list); } -PassRefPtr ComputedStyleExtractor::getCSSPropertyValuesForSidesShorthand(const StylePropertyShorthand& shorthand) const +RefPtr ComputedStyleExtractor::getCSSPropertyValuesForSidesShorthand(const StylePropertyShorthand& shorthand) { - RefPtr list = CSSValueList::createSpaceSeparated(); + auto list = CSSValueList::createSpaceSeparated(); + // Assume the properties are in the usual order top, right, bottom, left. - RefPtr topValue = propertyValue(shorthand.properties()[0], DoNotUpdateLayout); - RefPtr rightValue = propertyValue(shorthand.properties()[1], DoNotUpdateLayout); - RefPtr bottomValue = propertyValue(shorthand.properties()[2], DoNotUpdateLayout); - RefPtr leftValue = propertyValue(shorthand.properties()[3], DoNotUpdateLayout); + auto topValue = propertyValue(shorthand.properties()[0], DoNotUpdateLayout); + auto rightValue = propertyValue(shorthand.properties()[1], DoNotUpdateLayout); + auto bottomValue = propertyValue(shorthand.properties()[2], DoNotUpdateLayout); + auto leftValue = propertyValue(shorthand.properties()[3], DoNotUpdateLayout); // All 4 properties must be specified. if (!topValue || !rightValue || !bottomValue || !leftValue) - return 0; + return nullptr; bool showLeft = !compareCSSValuePtr(rightValue, leftValue); bool showBottom = !compareCSSValuePtr(topValue, bottomValue) || showLeft; bool showRight = !compareCSSValuePtr(topValue, rightValue) || showBottom; - list->append(topValue.release()); + list->append(topValue.releaseNonNull()); if (showRight) - list->append(rightValue.release()); + list->append(rightValue.releaseNonNull()); if (showBottom) - list->append(bottomValue.release()); + list->append(bottomValue.releaseNonNull()); if (showLeft) - list->append(leftValue.release()); + list->append(leftValue.releaseNonNull()); - return list.release(); + return WTFMove(list); } -PassRefPtr ComputedStyleExtractor::getCSSPropertyValuesForGridShorthand(const StylePropertyShorthand& shorthand) const +RefPtr ComputedStyleExtractor::getCSSPropertyValuesForGridShorthand(const StylePropertyShorthand& shorthand) { - RefPtr list = CSSValueList::createSlashSeparated(); - for (size_t i = 0; i < shorthand.length(); ++i) { - RefPtr value = propertyValue(shorthand.properties()[i], DoNotUpdateLayout); - list->append(value.release()); - } - return list.release(); + auto list = CSSValueList::createSlashSeparated(); + for (size_t i = 0; i < shorthand.length(); ++i) + list->append(propertyValue(shorthand.properties()[i], DoNotUpdateLayout).releaseNonNull()); + return WTFMove(list); } -PassRef ComputedStyleExtractor::copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const +Ref ComputedStyleExtractor::copyPropertiesInSet(const CSSPropertyID* set, unsigned length) { Vector list; list.reserveInitialCapacity(length); for (unsigned i = 0; i < length; ++i) { - RefPtr value = propertyValue(set[i]); - if (value) - list.append(CSSProperty(set[i], value.release(), false)); + if (auto value = propertyValue(set[i])) + list.append(CSSProperty(set[i], WTFMove(value), false)); } return MutableStyleProperties::create(list.data(), list.size()); } CSSRule* CSSComputedStyleDeclaration::parentRule() const { - return 0; + return nullptr; } -PassRefPtr CSSComputedStyleDeclaration::getPropertyCSSValue(const String& propertyName) +RefPtr CSSComputedStyleDeclaration::getPropertyCSSValue(const String& propertyName) { + if (isCustomPropertyName(propertyName)) { + auto value = ComputedStyleExtractor(m_element.ptr(), m_allowVisitedStyle, m_pseudoElementSpecifier).customPropertyValue(propertyName); + if (!value) + return nullptr; + return value->createDeprecatedCSSOMWrapper(); + } + CSSPropertyID propertyID = cssPropertyID(propertyName); if (!propertyID) - return 0; - RefPtr value = getPropertyCSSValue(propertyID); - return value ? value->cloneForCSSOM() : 0; + return nullptr; + auto value = getPropertyCSSValue(propertyID); + if (!value) + return nullptr; + return value->createDeprecatedCSSOMWrapper(); } String CSSComputedStyleDeclaration::getPropertyValue(const String &propertyName) { + if (isCustomPropertyName(propertyName)) + return ComputedStyleExtractor(m_element.ptr(), m_allowVisitedStyle, m_pseudoElementSpecifier).customPropertyText(propertyName); + CSSPropertyID propertyID = cssPropertyID(propertyName); if (!propertyID) return String(); @@ -3152,12 +4141,12 @@ String CSSComputedStyleDeclaration::getPropertyValue(const String &propertyName) String CSSComputedStyleDeclaration::getPropertyPriority(const String&) { // All computed styles have a priority of not "important". - return ""; + return emptyString(); // FIXME: Should this sometimes be null instead of empty, to match a normal style declaration? } String CSSComputedStyleDeclaration::getPropertyShorthand(const String&) { - return ""; + return emptyString(); // FIXME: Should this sometimes be null instead of empty, to match a normal style declaration? } bool CSSComputedStyleDeclaration::isPropertyImplicit(const String&) @@ -3165,18 +4154,17 @@ bool CSSComputedStyleDeclaration::isPropertyImplicit(const String&) return false; } -void CSSComputedStyleDeclaration::setProperty(const String&, const String&, const String&, ExceptionCode& ec) +ExceptionOr CSSComputedStyleDeclaration::setProperty(const String&, const String&, const String&) { - ec = NO_MODIFICATION_ALLOWED_ERR; + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -String CSSComputedStyleDeclaration::removeProperty(const String&, ExceptionCode& ec) +ExceptionOr CSSComputedStyleDeclaration::removeProperty(const String&) { - ec = NO_MODIFICATION_ALLOWED_ERR; - return String(); + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -PassRefPtr CSSComputedStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID) +RefPtr CSSComputedStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID) { return getPropertyCSSValue(propertyID); } @@ -3186,23 +4174,20 @@ String CSSComputedStyleDeclaration::getPropertyValueInternal(CSSPropertyID prope return getPropertyValue(propertyID); } -void CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool, ExceptionCode& ec) +ExceptionOr CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool) { - ec = NO_MODIFICATION_ALLOWED_ERR; + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -PassRefPtr ComputedStyleExtractor::getBackgroundShorthandValue() const +Ref ComputedStyleExtractor::getBackgroundShorthandValue() { - static const CSSPropertyID propertiesBeforeSlashSeperator[5] = { CSSPropertyBackgroundColor, CSSPropertyBackgroundImage, - CSSPropertyBackgroundRepeat, CSSPropertyBackgroundAttachment, - CSSPropertyBackgroundPosition }; - static const CSSPropertyID propertiesAfterSlashSeperator[3] = { CSSPropertyBackgroundSize, CSSPropertyBackgroundOrigin, - CSSPropertyBackgroundClip }; + static const CSSPropertyID propertiesBeforeSlashSeperator[5] = { CSSPropertyBackgroundColor, CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition }; + static const CSSPropertyID propertiesAfterSlashSeperator[3] = { CSSPropertyBackgroundSize, CSSPropertyBackgroundOrigin, CSSPropertyBackgroundClip }; - RefPtr list = CSSValueList::createSlashSeparated(); - list->append(getCSSPropertyValuesForShorthandProperties(StylePropertyShorthand(CSSPropertyBackground, propertiesBeforeSlashSeperator, WTF_ARRAY_LENGTH(propertiesBeforeSlashSeperator)))); - list->append(getCSSPropertyValuesForShorthandProperties(StylePropertyShorthand(CSSPropertyBackground, propertiesAfterSlashSeperator, WTF_ARRAY_LENGTH(propertiesAfterSlashSeperator)))); - return list.release(); + auto list = CSSValueList::createSlashSeparated(); + list->append(*getCSSPropertyValuesForShorthandProperties(StylePropertyShorthand(CSSPropertyBackground, propertiesBeforeSlashSeperator))); + list->append(*getCSSPropertyValuesForShorthandProperties(StylePropertyShorthand(CSSPropertyBackground, propertiesAfterSlashSeperator))); + return list; } } // namespace WebCore diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.h b/Source/WebCore/css/CSSComputedStyleDeclaration.h index 9981cf257..67a8e70f2 100644 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.h +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.h @@ -18,11 +18,11 @@ * 02110-1301 USA */ -#ifndef CSSComputedStyleDeclaration_h -#define CSSComputedStyleDeclaration_h +#pragma once #include "CSSStyleDeclaration.h" #include "RenderStyleConstants.h" +#include "SVGRenderStyleDefs.h" #include #include @@ -31,6 +31,7 @@ namespace WebCore { class CSSPrimitiveValue; class CSSValueList; class Color; +class Element; class FilterOperations; class MutableStyleProperties; class Node; @@ -47,88 +48,82 @@ enum AdjustPixelValuesForComputedStyle { AdjustPixelValues, DoNotAdjustPixelValu class ComputedStyleExtractor { public: - ComputedStyleExtractor(PassRefPtr, bool allowVisitedStyle = false, PseudoId = NOPSEUDO); + ComputedStyleExtractor(Node*, bool allowVisitedStyle = false, PseudoId = NOPSEUDO); + ComputedStyleExtractor(Element*, bool allowVisitedStyle = false, PseudoId = NOPSEUDO); - PassRefPtr propertyValue(CSSPropertyID, EUpdateLayout = UpdateLayout) const; + RefPtr propertyValue(CSSPropertyID, EUpdateLayout = UpdateLayout); + String customPropertyText(const String& propertyName); + RefPtr customPropertyValue(const String& propertyName); // Helper methods for HTML editing. - PassRef copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const; - PassRef copyProperties() const; - PassRefPtr getFontSizeCSSValuePreferringKeyword() const; - bool useFixedFontDefaultSize() const; - bool propertyMatches(CSSPropertyID, const CSSValue*) const; + Ref copyPropertiesInSet(const CSSPropertyID* set, unsigned length); + Ref copyProperties(); + RefPtr getFontSizeCSSValuePreferringKeyword(); + bool useFixedFontDefaultSize(); + bool propertyMatches(CSSPropertyID, const CSSValue*); -#if ENABLE(CSS_FILTERS) - static PassRef valueForFilter(const RenderStyle*, const FilterOperations&, AdjustPixelValuesForComputedStyle = AdjustPixelValues); -#endif + static Ref valueForFilter(const RenderStyle&, const FilterOperations&, AdjustPixelValuesForComputedStyle = AdjustPixelValues); private: - // The styled node is either the node passed into computedPropertyValue, or the + // The styled element is either the element passed into computedPropertyValue, or the // PseudoElement for :before and :after if they exist. - // FIXME: This should be styledElement since in JS getComputedStyle only works - // on Elements, but right now editing creates these for text nodes. We should fix that. - Node* styledNode() const; + Element* styledElement(); -#if ENABLE(SVG) - PassRefPtr svgPropertyValue(CSSPropertyID, EUpdateLayout) const; - PassRefPtr adjustSVGPaintForCurrentColor(PassRefPtr, RenderStyle*) const; -#endif + RefPtr svgPropertyValue(CSSPropertyID, EUpdateLayout); + RefPtr adjustSVGPaintForCurrentColor(SVGPaintType, const String& url, const Color&, const Color& currentColor) const; + static Ref valueForShadow(const ShadowData*, CSSPropertyID, const RenderStyle&, AdjustPixelValuesForComputedStyle = AdjustPixelValues); + RefPtr currentColorOrValidColor(const RenderStyle*, const Color&) const; - static PassRefPtr valueForShadow(const ShadowData*, CSSPropertyID, const RenderStyle*, AdjustPixelValuesForComputedStyle = AdjustPixelValues); - PassRefPtr currentColorOrValidColor(RenderStyle*, const Color&) const; + RefPtr getCSSPropertyValuesForShorthandProperties(const StylePropertyShorthand&); + RefPtr getCSSPropertyValuesForSidesShorthand(const StylePropertyShorthand&); + Ref getBackgroundShorthandValue(); + RefPtr getCSSPropertyValuesForGridShorthand(const StylePropertyShorthand&); - PassRefPtr getCSSPropertyValuesForShorthandProperties(const StylePropertyShorthand&) const; - PassRefPtr getCSSPropertyValuesForSidesShorthand(const StylePropertyShorthand&) const; - PassRefPtr getBackgroundShorthandValue() const; - PassRefPtr getCSSPropertyValuesForGridShorthand(const StylePropertyShorthand&) const; - - RefPtr m_node; + RefPtr m_element; PseudoId m_pseudoElementSpecifier; bool m_allowVisitedStyle; }; -class CSSComputedStyleDeclaration : public CSSStyleDeclaration { +class CSSComputedStyleDeclaration final : public CSSStyleDeclaration { public: - static PassRefPtr create(PassRefPtr node, bool allowVisitedStyle = false, const String& pseudoElementName = String()) + static Ref create(Element& element, bool allowVisitedStyle = false, const String& pseudoElementName = String()) { - return adoptRef(new CSSComputedStyleDeclaration(node, allowVisitedStyle, pseudoElementName)); + return adoptRef(*new CSSComputedStyleDeclaration(element, allowVisitedStyle, pseudoElementName)); } virtual ~CSSComputedStyleDeclaration(); - virtual void ref() override; - virtual void deref() override; + WEBCORE_EXPORT void ref() final; + WEBCORE_EXPORT void deref() final; String getPropertyValue(CSSPropertyID) const; private: - CSSComputedStyleDeclaration(PassRefPtr, bool allowVisitedStyle, const String&); + WEBCORE_EXPORT CSSComputedStyleDeclaration(Element&, bool allowVisitedStyle, const String&); // CSSOM functions. Don't make these public. - virtual CSSRule* parentRule() const override; - virtual unsigned length() const override; - virtual String item(unsigned index) const override; - virtual PassRefPtr getPropertyCSSValue(const String& propertyName) override; - virtual String getPropertyValue(const String& propertyName) override; - virtual String getPropertyPriority(const String& propertyName) override; - virtual String getPropertyShorthand(const String& propertyName) override; - virtual bool isPropertyImplicit(const String& propertyName) override; - virtual void setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode&) override; - virtual String removeProperty(const String& propertyName, ExceptionCode&) override; - virtual String cssText() const override; - virtual void setCssText(const String&, ExceptionCode&) override; - virtual PassRefPtr getPropertyCSSValueInternal(CSSPropertyID) override; - virtual String getPropertyValueInternal(CSSPropertyID) override; - virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override; - virtual PassRef copyProperties() const override; - - PassRefPtr getPropertyCSSValue(CSSPropertyID, EUpdateLayout = UpdateLayout) const; - - RefPtr m_node; + CSSRule* parentRule() const final; + unsigned length() const final; + String item(unsigned index) const final; + RefPtr getPropertyCSSValue(const String& propertyName) final; + String getPropertyValue(const String& propertyName) final; + String getPropertyPriority(const String& propertyName) final; + String getPropertyShorthand(const String& propertyName) final; + bool isPropertyImplicit(const String& propertyName) final; + ExceptionOr setProperty(const String& propertyName, const String& value, const String& priority) final; + ExceptionOr removeProperty(const String& propertyName) final; + String cssText() const final; + ExceptionOr setCssText(const String&) final; + RefPtr getPropertyCSSValueInternal(CSSPropertyID) final; + String getPropertyValueInternal(CSSPropertyID) final; + ExceptionOr setPropertyInternal(CSSPropertyID, const String& value, bool important) final; + Ref copyProperties() const final; + + RefPtr getPropertyCSSValue(CSSPropertyID, EUpdateLayout = UpdateLayout) const; + + mutable Ref m_element; PseudoId m_pseudoElementSpecifier; bool m_allowVisitedStyle; unsigned m_refCount; }; } // namespace WebCore - -#endif // CSSComputedStyleDeclaration_h diff --git a/Source/WebCore/css/CSSContentDistributionValue.cpp b/Source/WebCore/css/CSSContentDistributionValue.cpp new file mode 100644 index 000000000..0349ede80 --- /dev/null +++ b/Source/WebCore/css/CSSContentDistributionValue.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Igalia S.L. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSContentDistributionValue.h" + +#include "CSSValueList.h" +#include + +namespace WebCore { + +CSSContentDistributionValue::CSSContentDistributionValue(CSSValueID distribution, CSSValueID position, CSSValueID overflow) + : CSSValue(CSSContentDistributionClass) + , m_distribution(distribution) + , m_position(position) + , m_overflow(overflow) +{ +} + +CSSContentDistributionValue::~CSSContentDistributionValue() +{ +} + +String CSSContentDistributionValue::customCSSText() const +{ + auto list = CSSValueList::createSpaceSeparated(); + if (m_distribution != CSSValueInvalid) + list->append(distribution()); + if (m_position != CSSValueInvalid) + list->append(position()); + if (m_overflow != CSSValueInvalid) + list->append(overflow()); + return list->customCSSText(); +} + +bool CSSContentDistributionValue::equals(const CSSContentDistributionValue& other) const +{ + return m_distribution == other.m_distribution && m_position == other.m_position && m_overflow == other.m_overflow; +} + +} diff --git a/Source/WebCore/css/CSSContentDistributionValue.h b/Source/WebCore/css/CSSContentDistributionValue.h new file mode 100644 index 000000000..7d9a285b3 --- /dev/null +++ b/Source/WebCore/css/CSSContentDistributionValue.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Igalia S.L. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include "CSSValuePool.h" +#include + +namespace WebCore { + +class CSSContentDistributionValue final : public CSSValue { +public: + static Ref create(CSSValueID distribution, CSSValueID position, CSSValueID overflow) + { + return adoptRef(*new CSSContentDistributionValue(distribution, position, overflow)); + } + ~CSSContentDistributionValue(); + + Ref distribution() const { return CSSValuePool::singleton().createIdentifierValue(m_distribution); } + Ref position() const { return CSSValuePool::singleton().createIdentifierValue(m_position); } + Ref overflow() const { return CSSValuePool::singleton().createIdentifierValue(m_overflow); } + + String customCSSText() const; + + bool equals(const CSSContentDistributionValue&) const; + +private: + CSSContentDistributionValue(CSSValueID distribution, CSSValueID position, CSSValueID overflow); + + CSSValueID m_distribution; + CSSValueID m_position; + CSSValueID m_overflow; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSContentDistributionValue, isContentDistributionValue()) diff --git a/Source/WebCore/css/CSSCrossfadeValue.cpp b/Source/WebCore/css/CSSCrossfadeValue.cpp index 26472263a..c324dc112 100644 --- a/Source/WebCore/css/CSSCrossfadeValue.cpp +++ b/Source/WebCore/css/CSSCrossfadeValue.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,6 +29,7 @@ #include "AnimationUtilities.h" #include "CSSImageValue.h" +#include "CachedImage.h" #include "CachedResourceLoader.h" #include "CrossfadeGeneratedImage.h" #include "ImageBuffer.h" @@ -44,31 +45,59 @@ static inline double blendFunc(double from, double to, double progress) return blend(from, to, progress); } -static bool subimageKnownToBeOpaque(CSSValue& value, const RenderElement* renderer) +static bool subimageKnownToBeOpaque(const CSSValue& value, const RenderElement& renderer) { - if (value.isImageValue()) - return toCSSImageValue(value).knownToBeOpaque(renderer); + if (is(value)) + return downcast(value).knownToBeOpaque(&renderer); - if (value.isImageGeneratorValue()) - return toCSSImageGeneratorValue(value).knownToBeOpaque(renderer); + if (is(value)) + return downcast(value).knownToBeOpaque(renderer); ASSERT_NOT_REACHED(); return false; } +inline CSSCrossfadeValue::SubimageObserver::SubimageObserver(CSSCrossfadeValue& owner) + : m_owner(owner) +{ +} + +void CSSCrossfadeValue::SubimageObserver::imageChanged(CachedImage*, const IntRect*) +{ + m_owner.crossfadeChanged(); +} + +inline CSSCrossfadeValue::CSSCrossfadeValue(Ref&& fromValue, Ref&& toValue, Ref&& percentageValue, bool prefixed) + : CSSImageGeneratorValue(CrossfadeClass) + , m_fromValue(WTFMove(fromValue)) + , m_toValue(WTFMove(toValue)) + , m_percentageValue(WTFMove(percentageValue)) + , m_subimageObserver(*this) + , m_isPrefixed(prefixed) +{ +} + +Ref CSSCrossfadeValue::create(Ref&& fromValue, Ref&& toValue, Ref&& percentageValue, bool prefixed) +{ + return adoptRef(*new CSSCrossfadeValue(WTFMove(fromValue), WTFMove(toValue), WTFMove(percentageValue), prefixed)); +} + CSSCrossfadeValue::~CSSCrossfadeValue() { if (m_cachedFromImage) - m_cachedFromImage->removeClient(&m_crossfadeSubimageObserver); + m_cachedFromImage->removeClient(m_subimageObserver); if (m_cachedToImage) - m_cachedToImage->removeClient(&m_crossfadeSubimageObserver); + m_cachedToImage->removeClient(m_subimageObserver); } String CSSCrossfadeValue::customCSSText() const { StringBuilder result; - result.appendLiteral("-webkit-cross-fade("); + if (m_isPrefixed) + result.appendLiteral("-webkit-cross-fade("); + else + result.appendLiteral("cross-fade("); result.append(m_fromValue->cssText()); result.appendLiteral(", "); result.append(m_toValue->cssText()); @@ -78,142 +107,144 @@ String CSSCrossfadeValue::customCSSText() const return result.toString(); } -IntSize CSSCrossfadeValue::fixedSize(const RenderElement* renderer) +FloatSize CSSCrossfadeValue::fixedSize(const RenderElement& renderer) { - float percentage = m_percentageValue->getFloatValue(); + float percentage = m_percentageValue->floatValue(); float inversePercentage = 1 - percentage; - CachedResourceLoader* cachedResourceLoader = renderer->document().cachedResourceLoader(); - CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); - CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + // FIXME: Skip Content Security Policy check when cross fade is applied to an element in a user agent shadow tree. + // See . + auto options = CachedResourceLoader::defaultCachedResourceOptions(); + + auto& cachedResourceLoader = renderer.document().cachedResourceLoader(); + auto* cachedFromImage = cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options); + auto* cachedToImage = cachedImageForCSSValue(m_toValue, cachedResourceLoader, options); if (!cachedFromImage || !cachedToImage) - return IntSize(); + return FloatSize(); - IntSize fromImageSize = cachedFromImage->imageForRenderer(renderer)->size(); - IntSize toImageSize = cachedToImage->imageForRenderer(renderer)->size(); + FloatSize fromImageSize = cachedFromImage->imageForRenderer(&renderer)->size(); + FloatSize toImageSize = cachedToImage->imageForRenderer(&renderer)->size(); // Rounding issues can cause transitions between images of equal size to return // a different fixed size; avoid performing the interpolation if the images are the same size. if (fromImageSize == toImageSize) return fromImageSize; - return IntSize(fromImageSize.width() * inversePercentage + toImageSize.width() * percentage, - fromImageSize.height() * inversePercentage + toImageSize.height() * percentage); + return fromImageSize * inversePercentage + toImageSize * percentage; } bool CSSCrossfadeValue::isPending() const { - return CSSImageGeneratorValue::subimageIsPending(m_fromValue.get()) - || CSSImageGeneratorValue::subimageIsPending(m_toValue.get()); + return CSSImageGeneratorValue::subimageIsPending(m_fromValue) + || CSSImageGeneratorValue::subimageIsPending(m_toValue); } -bool CSSCrossfadeValue::knownToBeOpaque(const RenderElement* renderer) const +bool CSSCrossfadeValue::knownToBeOpaque(const RenderElement& renderer) const { - return subimageKnownToBeOpaque(*m_fromValue, renderer) && subimageKnownToBeOpaque(*m_toValue, renderer); + return subimageKnownToBeOpaque(m_fromValue, renderer) + && subimageKnownToBeOpaque(m_toValue, renderer); } -void CSSCrossfadeValue::loadSubimages(CachedResourceLoader* cachedResourceLoader) +void CSSCrossfadeValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { - CachedResourceHandle oldCachedFromImage = m_cachedFromImage; - CachedResourceHandle oldCachedToImage = m_cachedToImage; + auto oldCachedFromImage = m_cachedFromImage; + auto oldCachedToImage = m_cachedToImage; - m_cachedFromImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); - m_cachedToImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + m_cachedFromImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options); + m_cachedToImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_toValue, cachedResourceLoader, options); if (m_cachedFromImage != oldCachedFromImage) { if (oldCachedFromImage) - oldCachedFromImage->removeClient(&m_crossfadeSubimageObserver); + oldCachedFromImage->removeClient(m_subimageObserver); if (m_cachedFromImage) - m_cachedFromImage->addClient(&m_crossfadeSubimageObserver); + m_cachedFromImage->addClient(m_subimageObserver); } if (m_cachedToImage != oldCachedToImage) { if (oldCachedToImage) - oldCachedToImage->removeClient(&m_crossfadeSubimageObserver); + oldCachedToImage->removeClient(m_subimageObserver); if (m_cachedToImage) - m_cachedToImage->addClient(&m_crossfadeSubimageObserver); + m_cachedToImage->addClient(m_subimageObserver); } - m_crossfadeSubimageObserver.setReady(true); + // FIXME: Unclear why this boolean adds any value; for now keeping it around to avoid changing semantics. + m_subimagesAreReady = true; } -PassRefPtr CSSCrossfadeValue::image(RenderElement* renderer, const IntSize& size) +Image* CSSCrossfadeValue::image(RenderElement& renderer, const FloatSize& size) { if (size.isEmpty()) - return 0; + return nullptr; - CachedResourceLoader* cachedResourceLoader = renderer->document().cachedResourceLoader(); - CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); - CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); + // FIXME: Skip Content Security Policy check when cross fade is applied to an element in a user agent shadow tree. + // See . + auto options = CachedResourceLoader::defaultCachedResourceOptions(); + + auto& cachedResourceLoader = renderer.document().cachedResourceLoader(); + auto* cachedFromImage = cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options); + auto* cachedToImage = cachedImageForCSSValue(m_toValue, cachedResourceLoader, options); if (!cachedFromImage || !cachedToImage) return Image::nullImage(); - Image* fromImage = cachedFromImage->imageForRenderer(renderer); - Image* toImage = cachedToImage->imageForRenderer(renderer); + auto* fromImage = cachedFromImage->imageForRenderer(&renderer); + auto* toImage = cachedToImage->imageForRenderer(&renderer); if (!fromImage || !toImage) return Image::nullImage(); - m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); - - return m_generatedImage.release(); + m_generatedImage = CrossfadeGeneratedImage::create(*fromImage, *toImage, m_percentageValue->floatValue(), fixedSize(renderer), size); + return m_generatedImage.get(); } -void CSSCrossfadeValue::crossfadeChanged(const IntRect&) +inline void CSSCrossfadeValue::crossfadeChanged() { - for (auto it = clients().begin(), end = clients().end(); it != end; ++it) - it->key->imageChanged(static_cast(this)); + if (!m_subimagesAreReady) + return; + for (auto& client : clients()) + client.key->imageChanged(this); } -void CSSCrossfadeValue::CrossfadeSubimageObserverProxy::imageChanged(CachedImage*, const IntRect* rect) +bool CSSCrossfadeValue::traverseSubresources(const std::function& handler) const { - if (m_ready) - m_ownerValue->crossfadeChanged(*rect); -} - -bool CSSCrossfadeValue::hasFailedOrCanceledSubresources() const -{ - if (m_cachedFromImage && m_cachedFromImage->loadFailedOrCanceled()) + if (m_cachedFromImage && handler(*m_cachedFromImage)) return true; - if (m_cachedToImage && m_cachedToImage->loadFailedOrCanceled()) + if (m_cachedToImage && handler(*m_cachedToImage)) return true; return false; } -PassRefPtr CSSCrossfadeValue::blend(const CSSCrossfadeValue& from, double progress) const +RefPtr CSSCrossfadeValue::blend(const CSSCrossfadeValue& from, double progress) const { ASSERT(equalInputImages(from)); - RefPtr toStyledImage = StyleCachedImage::create(m_cachedToImage.get()); - RefPtr fromStyledImage = StyleCachedImage::create(m_cachedFromImage.get()); - auto fromImageValue = CSSImageValue::create(m_cachedFromImage->url(), fromStyledImage.get()); - auto toImageValue = CSSImageValue::create(m_cachedToImage->url(), toStyledImage.get()); + if (!m_cachedToImage || !m_cachedFromImage) + return nullptr; - RefPtr crossfadeValue = CSSCrossfadeValue::create(std::move(fromImageValue), std::move(toImageValue)); + auto fromImageValue = CSSImageValue::create(*m_cachedFromImage); + auto toImageValue = CSSImageValue::create(*m_cachedToImage); - double fromPercentage = from.m_percentageValue->getDoubleValue(); + double fromPercentage = from.m_percentageValue->doubleValue(); if (from.m_percentageValue->isPercentage()) fromPercentage /= 100.0; - double toPercentage = m_percentageValue->getDoubleValue(); + double toPercentage = m_percentageValue->doubleValue(); if (m_percentageValue->isPercentage()) toPercentage /= 100.0; - crossfadeValue->setPercentage(CSSPrimitiveValue::create(blendFunc(fromPercentage, toPercentage, progress), CSSPrimitiveValue::CSS_NUMBER)); - return crossfadeValue.release(); + auto percentageValue = CSSPrimitiveValue::create(blendFunc(fromPercentage, toPercentage, progress), CSSPrimitiveValue::CSS_NUMBER); + + return CSSCrossfadeValue::create(WTFMove(fromImageValue), WTFMove(toImageValue), WTFMove(percentageValue), from.isPrefixed() && isPrefixed()); } bool CSSCrossfadeValue::equals(const CSSCrossfadeValue& other) const { - return equalInputImages(other) - && compareCSSValuePtr(m_percentageValue, other.m_percentageValue); + return equalInputImages(other) && compareCSSValue(m_percentageValue, other.m_percentageValue); } bool CSSCrossfadeValue::equalInputImages(const CSSCrossfadeValue& other) const { - return compareCSSValuePtr(m_fromValue, other.m_fromValue) - && compareCSSValuePtr(m_toValue, other.m_toValue); + return compareCSSValue(m_fromValue, other.m_fromValue) && compareCSSValue(m_toValue, other.m_toValue); } } // namespace WebCore diff --git a/Source/WebCore/css/CSSCrossfadeValue.h b/Source/WebCore/css/CSSCrossfadeValue.h index 53bd05983..a3500b44e 100644 --- a/Source/WebCore/css/CSSCrossfadeValue.h +++ b/Source/WebCore/css/CSSCrossfadeValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,95 +23,68 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSCrossfadeValue_h -#define CSSCrossfadeValue_h +#pragma once #include "CachedImageClient.h" #include "CachedResourceHandle.h" #include "CSSImageGeneratorValue.h" -#include "CSSPrimitiveValue.h" -#include "Image.h" -#include "ImageObserver.h" namespace WebCore { -class CachedImage; -class CrossfadeSubimageObserverProxy; -class RenderElement; -class Document; +class CSSPrimitiveValue; -class CSSCrossfadeValue : public CSSImageGeneratorValue { - friend class CrossfadeSubimageObserverProxy; +class CSSCrossfadeValue final : public CSSImageGeneratorValue { public: - static PassRef create(PassRefPtr fromValue, PassRefPtr toValue) - { - return adoptRef(*new CSSCrossfadeValue(fromValue, toValue)); - } + static Ref create(Ref&& fromValue, Ref&& toValue, Ref&& percentageValue, bool prefixed = false); ~CSSCrossfadeValue(); String customCSSText() const; - PassRefPtr image(RenderElement*, const IntSize&); + Image* image(RenderElement&, const FloatSize&); bool isFixedSize() const { return true; } - IntSize fixedSize(const RenderElement*); + FloatSize fixedSize(const RenderElement&); + bool isPrefixed() const { return m_isPrefixed; } bool isPending() const; - bool knownToBeOpaque(const RenderElement*) const; + bool knownToBeOpaque(const RenderElement&) const; - void loadSubimages(CachedResourceLoader*); + void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&); - void setPercentage(PassRefPtr percentageValue) { m_percentageValue = percentageValue; } + bool traverseSubresources(const std::function& handler) const; - bool hasFailedOrCanceledSubresources() const; - - PassRefPtr blend(const CSSCrossfadeValue&, double) const; + RefPtr blend(const CSSCrossfadeValue&, double) const; bool equals(const CSSCrossfadeValue&) const; - bool equalInputImages(const CSSCrossfadeValue&) const; private: - CSSCrossfadeValue(PassRefPtr fromValue, PassRefPtr toValue) - : CSSImageGeneratorValue(CrossfadeClass) - , m_fromValue(fromValue) - , m_toValue(toValue) - , m_crossfadeSubimageObserver(this) - { - } - - class CrossfadeSubimageObserverProxy : public CachedImageClient { + CSSCrossfadeValue(Ref&& fromValue, Ref&& toValue, Ref&& percentageValue, bool prefixed); + + class SubimageObserver final : public CachedImageClient { public: - CrossfadeSubimageObserverProxy(CSSCrossfadeValue* ownerValue) - : m_ownerValue(ownerValue) - , m_ready(false) - { - } - - virtual ~CrossfadeSubimageObserverProxy() { } - virtual void imageChanged(CachedImage*, const IntRect* = 0) override; - void setReady(bool ready) { m_ready = ready; } + SubimageObserver(CSSCrossfadeValue&); private: - CSSCrossfadeValue* m_ownerValue; - bool m_ready; + void imageChanged(CachedImage*, const IntRect*) final; + CSSCrossfadeValue& m_owner; }; - void crossfadeChanged(const IntRect&); + void crossfadeChanged(); - RefPtr m_fromValue; - RefPtr m_toValue; - RefPtr m_percentageValue; + Ref m_fromValue; + Ref m_toValue; + Ref m_percentageValue; CachedResourceHandle m_cachedFromImage; CachedResourceHandle m_cachedToImage; RefPtr m_generatedImage; - CrossfadeSubimageObserverProxy m_crossfadeSubimageObserver; + SubimageObserver m_subimageObserver; + bool m_isPrefixed { false }; + bool m_subimagesAreReady { false }; }; -CSS_VALUE_TYPE_CASTS(CSSCrossfadeValue, isCrossfadeValue()) - } // namespace WebCore -#endif // CSSCrossfadeValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCrossfadeValue, isCrossfadeValue()) diff --git a/Source/WebCore/css/CSSCursorImageValue.cpp b/Source/WebCore/css/CSSCursorImageValue.cpp index 6d0806407..c9f0a7660 100644 --- a/Source/WebCore/css/CSSCursorImageValue.cpp +++ b/Source/WebCore/css/CSSCursorImageValue.cpp @@ -22,75 +22,34 @@ #include "config.h" #include "CSSCursorImageValue.h" +#include "CSSImageSetValue.h" #include "CSSImageValue.h" #include "CachedImage.h" #include "CachedResourceLoader.h" -#include "StyleCachedImage.h" -#include "StyleImage.h" -#include "StylePendingImage.h" +#include "SVGCursorElement.h" +#include "SVGLengthContext.h" +#include "SVGURIReference.h" #include "TreeScope.h" #include #include #include -#if ENABLE(SVG) -#include "SVGCursorElement.h" -#include "SVGLengthContext.h" -#include "SVGNames.h" -#include "SVGURIReference.h" -#endif - -#if ENABLE(CSS_IMAGE_SET) -#include "CSSImageSetValue.h" -#include "StyleCachedImageSet.h" -#endif - namespace WebCore { -#if ENABLE(SVG) -static inline SVGCursorElement* resourceReferencedByCursorElement(const String& url, Document& document) -{ - Element* element = SVGURIReference::targetElementFromIRIString(url, document); - if (element && isSVGCursorElement(element)) - return toSVGCursorElement(element); - - return 0; -} -#endif - -CSSCursorImageValue::CSSCursorImageValue(PassRef imageValue, bool hasHotSpot, const IntPoint& hotSpot) +CSSCursorImageValue::CSSCursorImageValue(Ref&& imageValue, bool hasHotSpot, const IntPoint& hotSpot) : CSSValue(CursorImageClass) - , m_imageValue(std::move(imageValue)) + , m_imageValue(WTFMove(imageValue)) , m_hasHotSpot(hasHotSpot) , m_hotSpot(hotSpot) - , m_accessedImage(false) -{ -} - -inline void CSSCursorImageValue::detachPendingImage() { - if (m_image && m_image->isPendingImage()) - static_cast(*m_image).detachFromCSSValue(); + if (is(m_imageValue.get())) + m_originalURL = downcast(m_imageValue.get()).url(); } CSSCursorImageValue::~CSSCursorImageValue() { - detachPendingImage(); - -#if ENABLE(SVG) - if (!isSVGCursor()) - return; - - HashSet::const_iterator it = m_referencedElements.begin(); - HashSet::const_iterator end = m_referencedElements.end(); - - for (; it != end; ++it) { - SVGElement* referencedElement = *it; - referencedElement->cursorImageValueRemoved(); - if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(toCSSImageValue(m_imageValue.get()).url(), referencedElement->document())) - cursorElement->removeClient(referencedElement); - } -#endif + for (auto* element : m_cursorElements) + element->removeClient(*this); } String CSSCursorImageValue::customCSSText() const @@ -106,124 +65,52 @@ String CSSCursorImageValue::customCSSText() const return result.toString(); } -bool CSSCursorImageValue::updateIfSVGCursorIsUsed(Element* element) +SVGCursorElement* CSSCursorImageValue::updateCursorElement(const Document& document) { -#if !ENABLE(SVG) - UNUSED_PARAM(element); -#else - if (!element || !element->isSVGElement()) - return false; - - if (!isSVGCursor()) - return false; - - if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(toCSSImageValue(m_imageValue.get()).url(), element->document())) { - // FIXME: This will override hot spot specified in CSS, which is probably incorrect. - SVGLengthContext lengthContext(0); - m_hasHotSpot = true; - float x = roundf(cursorElement->x().value(lengthContext)); - m_hotSpot.setX(static_cast(x)); - - float y = roundf(cursorElement->y().value(lengthContext)); - m_hotSpot.setY(static_cast(y)); - - if (cachedImageURL() != element->document().completeURL(cursorElement->href())) - clearCachedImage(); - - SVGElement* svgElement = toSVGElement(element); - m_referencedElements.add(svgElement); - svgElement->setCursorImageValue(this); - cursorElement->addClient(svgElement); - return true; - } -#endif + if (!m_originalURL.hasFragmentIdentifier()) + return nullptr; - return false; -} + auto* element = SVGURIReference::targetElementFromIRIString(m_originalURL, document); + if (!is(element)) + return nullptr; -StyleImage* CSSCursorImageValue::cachedImage(CachedResourceLoader* loader) -{ -#if ENABLE(CSS_IMAGE_SET) - if (m_imageValue.get().isImageSetValue()) - return toCSSImageSetValue(m_imageValue.get()).cachedImageSet(loader); -#endif - - if (!m_accessedImage) { - m_accessedImage = true; - -#if ENABLE(SVG) - // For SVG images we need to lazily substitute in the correct URL. Rather than attempt - // to change the URL of the CSSImageValue (which would then change behavior like cssText), - // we create an alternate CSSImageValue to use. - if (isSVGCursor() && loader && loader->document()) { - // FIXME: This will fail if the element is in a shadow DOM (bug 59827) - if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(toCSSImageValue(m_imageValue.get()).url(), *loader->document())) { - detachPendingImage(); - Ref svgImageValue(CSSImageValue::create(cursorElement->href())); - StyleCachedImage* cachedImage = svgImageValue->cachedImage(loader); - m_image = cachedImage; - return cachedImage; - } - } -#endif - - if (m_imageValue.get().isImageValue()) { - detachPendingImage(); - m_image = toCSSImageValue(m_imageValue.get()).cachedImage(loader); - } + auto& cursorElement = downcast(*element); + if (m_cursorElements.add(&cursorElement).isNewEntry) { + cursorElementChanged(cursorElement); + cursorElement.addClient(*this); } - - if (m_image && m_image->isCachedImage()) - return static_cast(m_image.get()); - - return 0; + return &cursorElement; } -StyleImage* CSSCursorImageValue::cachedOrPendingImage(Document& document) +void CSSCursorImageValue::cursorElementRemoved(SVGCursorElement& cursorElement) { -#if ENABLE(CSS_IMAGE_SET) - // Need to delegate completely so that changes in device scale factor can be handled appropriately. - if (m_imageValue.get().isImageSetValue()) - return toCSSImageSetValue(m_imageValue.get()).cachedOrPendingImageSet(document); -#else - UNUSED_PARAM(document); -#endif - - if (!m_image) - m_image = StylePendingImage::create(this); - - return m_image.get(); + m_cursorElements.remove(&cursorElement); } -#if ENABLE(SVG) -bool CSSCursorImageValue::isSVGCursor() const +void CSSCursorImageValue::cursorElementChanged(SVGCursorElement& cursorElement) { - if (m_imageValue.get().isImageValue()) { - URL kurl(ParsedURLString, toCSSImageValue(m_imageValue.get()).url()); - return kurl.hasFragmentIdentifier(); - } - return false; + // FIXME: This will override hot spot specified in CSS, which is probably incorrect. + SVGLengthContext lengthContext(nullptr); + m_hasHotSpot = true; + float x = std::round(cursorElement.x().value(lengthContext)); + m_hotSpot.setX(static_cast(x)); + + float y = std::round(cursorElement.y().value(lengthContext)); + m_hotSpot.setY(static_cast(y)); } -String CSSCursorImageValue::cachedImageURL() +std::pair CSSCursorImageValue::loadImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options) { - if (!m_image || !m_image->isCachedImage()) - return String(); - return static_cast(m_image.get())->cachedImage()->url(); -} + if (is(m_imageValue.get())) + return downcast(m_imageValue.get()).loadBestFitImage(loader, options); -void CSSCursorImageValue::clearCachedImage() -{ - detachPendingImage(); - m_image = nullptr; - m_accessedImage = false; -} + if (auto* cursorElement = updateCursorElement(*loader.document())) { + if (cursorElement->href() != downcast(m_imageValue.get()).url()) + m_imageValue = CSSImageValue::create(loader.document()->completeURL(cursorElement->href())); + } -void CSSCursorImageValue::removeReferencedElement(SVGElement* element) -{ - m_referencedElements.remove(element); + return { downcast(m_imageValue.get()).loadImage(loader, options), 1 }; } -#endif bool CSSCursorImageValue::equals(const CSSCursorImageValue& other) const { diff --git a/Source/WebCore/css/CSSCursorImageValue.h b/Source/WebCore/css/CSSCursorImageValue.h index b1c6d1dee..d2da62df2 100644 --- a/Source/WebCore/css/CSSCursorImageValue.h +++ b/Source/WebCore/css/CSSCursorImageValue.h @@ -18,8 +18,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSCursorImageValue_h -#define CSSCursorImageValue_h +#pragma once #include "CSSImageValue.h" #include "IntPoint.h" @@ -29,13 +28,14 @@ namespace WebCore { class Document; class Element; +class SVGCursorElement; class SVGElement; -class CSSCursorImageValue : public CSSValue { +class CSSCursorImageValue final : public CSSValue { public: - static PassRef create(PassRef imageValue, bool hasHotSpot, const IntPoint& hotSpot) + static Ref create(Ref&& imageValue, bool hasHotSpot, const IntPoint& hotSpot) { - return adoptRef(*new CSSCursorImageValue(std::move(imageValue), hasHotSpot, hotSpot)); + return adoptRef(*new CSSCursorImageValue(WTFMove(imageValue), hasHotSpot, hotSpot)); } ~CSSCursorImageValue(); @@ -51,41 +51,28 @@ public: String customCSSText() const; - bool updateIfSVGCursorIsUsed(Element*); - StyleImage* cachedImage(CachedResourceLoader*); - StyleImage* cachedOrPendingImage(Document&); + std::pair loadImage(CachedResourceLoader&, const ResourceLoaderOptions&); -#if ENABLE(SVG) void removeReferencedElement(SVGElement*); -#endif bool equals(const CSSCursorImageValue&) const; -private: - CSSCursorImageValue(PassRef imageValue, bool hasHotSpot, const IntPoint& hotSpot); + void cursorElementRemoved(SVGCursorElement&); + void cursorElementChanged(SVGCursorElement&); - void detachPendingImage(); +private: + CSSCursorImageValue(Ref&& imageValue, bool hasHotSpot, const IntPoint& hotSpot); -#if ENABLE(SVG) - bool isSVGCursor() const; - String cachedImageURL(); - void clearCachedImage(); -#endif + SVGCursorElement* updateCursorElement(const Document&); + URL m_originalURL; Ref m_imageValue; bool m_hasHotSpot; IntPoint m_hotSpot; - RefPtr m_image; - bool m_accessedImage; - -#if ENABLE(SVG) - HashSet m_referencedElements; -#endif + HashSet m_cursorElements; }; -CSS_VALUE_TYPE_CASTS(CSSCursorImageValue, isCursorImageValue()) - } // namespace WebCore -#endif // CSSCursorImageValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCursorImageValue, isCursorImageValue()) diff --git a/Source/WebCore/css/CSSCustomIdentValue.cpp b/Source/WebCore/css/CSSCustomIdentValue.cpp new file mode 100644 index 000000000..26d6e3bb0 --- /dev/null +++ b/Source/WebCore/css/CSSCustomIdentValue.cpp @@ -0,0 +1,62 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "CSSCustomIdentValue.h" + +#include "CSSMarkup.h" +#include +#include + +namespace WebCore { + +CSSCustomIdentValue::CSSCustomIdentValue(const String& str) + : CSSValue(CustomIdentClass) + , m_string(str) + , m_propertyId(CSSPropertyInvalid) { } + +CSSCustomIdentValue::CSSCustomIdentValue(CSSPropertyID id) + : CSSValue(CustomIdentClass) + , m_string() + , m_propertyId(id) +{ + ASSERT(isKnownPropertyID()); +} + + +String CSSCustomIdentValue::customCSSText() const +{ + if (isKnownPropertyID()) + return getPropertyNameAtomicString(m_propertyId); + StringBuilder builder; + serializeIdentifier(m_string, builder); + return builder.toString(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSCustomIdentValue.h b/Source/WebCore/css/CSSCustomIdentValue.h new file mode 100644 index 000000000..a562aed2d --- /dev/null +++ b/Source/WebCore/css/CSSCustomIdentValue.h @@ -0,0 +1,72 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "CSSPropertyNames.h" +#include "CSSValue.h" + +namespace WebCore { + +class CSSCustomIdentValue : public CSSValue { +public: + static Ref create(const String& str) + { + return adoptRef(*new CSSCustomIdentValue(str)); + } + + // FIXME: Remove this and lazily parse the CSSPropertyID in isKnownPropertyID(). + static Ref create(CSSPropertyID id) + { + return adoptRef(*new CSSCustomIdentValue(id)); + } + + String value() const { ASSERT(!isKnownPropertyID()); return m_string; } + bool isKnownPropertyID() const { return m_propertyId != CSSPropertyInvalid; } + CSSPropertyID valueAsPropertyID() const { ASSERT(isKnownPropertyID()); return m_propertyId; } + + String customCSSText() const; + + bool equals(const CSSCustomIdentValue& other) const + { + return isKnownPropertyID() ? m_propertyId == other.m_propertyId : m_string == other.m_string; + } + +private: + CSSCustomIdentValue(const String&); + CSSCustomIdentValue(CSSPropertyID); + + // FIXME: Change this to an AtomicString. + String m_string; + CSSPropertyID m_propertyId; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCustomIdentValue, isCustomIdentValue()) diff --git a/Source/WebCore/css/CSSCustomPropertyValue.cpp b/Source/WebCore/css/CSSCustomPropertyValue.cpp new file mode 100644 index 000000000..b8808ce8e --- /dev/null +++ b/Source/WebCore/css/CSSCustomPropertyValue.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSCustomPropertyValue.h" + +#include "CSSParserSelector.h" + +namespace WebCore { + +bool CSSCustomPropertyValue::checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap& customProperties, HashSet& seenProperties, HashSet& invalidProperties) const +{ + ASSERT(containsVariables()); + if (m_value) + return m_value->checkVariablesForCycles(name, customProperties, seenProperties, invalidProperties); + return true; +} + +void CSSCustomPropertyValue::resolveVariableReferences(const CustomPropertyValueMap& customProperties, Vector>& resolvedValues) const +{ + ASSERT(containsVariables()); + if (!m_value) + return; + + ASSERT(m_value->needsVariableResolution()); + RefPtr resolvedData = m_value->resolveVariableReferences(customProperties); + if (resolvedData) + resolvedValues.append(CSSCustomPropertyValue::createWithVariableData(m_name, resolvedData.releaseNonNull())); + else + resolvedValues.append(CSSCustomPropertyValue::createWithID(m_name, CSSValueInvalid)); +} + +} diff --git a/Source/WebCore/css/CSSCustomPropertyValue.h b/Source/WebCore/css/CSSCustomPropertyValue.h new file mode 100644 index 000000000..31958b215 --- /dev/null +++ b/Source/WebCore/css/CSSCustomPropertyValue.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include "CSSVariableData.h" +#include +#include + +namespace WebCore { + +class CSSCustomPropertyValue final : public CSSValue { +public: + static Ref createWithVariableData(const AtomicString& name, Ref&& value) + { + return adoptRef(*new CSSCustomPropertyValue(name, WTFMove(value))); + } + + static Ref createWithID(const AtomicString& name, CSSValueID value) + { + return adoptRef(*new CSSCustomPropertyValue(name, value)); + } + + static Ref createInvalid() + { + return adoptRef(*new CSSCustomPropertyValue(emptyString(), emptyString())); + } + + String customCSSText() const + { + if (!m_serialized) { + m_serialized = true; + if (m_value) + m_stringValue = m_value->tokenRange().serialize(); + else if (m_valueId != CSSValueInvalid) + m_stringValue = getValueName(m_valueId); + else + m_stringValue = emptyString(); + } + return m_stringValue; + } + + const AtomicString& name() const { return m_name; } + + bool equals(const CSSCustomPropertyValue& other) const { return m_name == other.m_name && m_value == other.m_value && m_valueId == other.m_valueId; } + + bool containsVariables() const { return m_containsVariables; } + bool checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap&, HashSet& seenProperties, HashSet& invalidProperties) const; + + void resolveVariableReferences(const CustomPropertyValueMap&, Vector>&) const; + + CSSValueID valueID() const { return m_valueId; } + CSSVariableData* value() const { return m_value.get(); } + +private: + CSSCustomPropertyValue(const AtomicString& name, const String& serializedValue) + : CSSValue(CustomPropertyClass) + , m_name(name) + , m_stringValue(serializedValue) + , m_serialized(true) + { + } + + CSSCustomPropertyValue(const AtomicString& name, CSSValueID id) + : CSSValue(CustomPropertyClass) + , m_name(name) + , m_valueId(id) + { + ASSERT(id == CSSValueInherit || id == CSSValueInitial || id == CSSValueUnset || id == CSSValueRevert || id == CSSValueInvalid); + } + + CSSCustomPropertyValue(const AtomicString& name, Ref&& value) + : CSSValue(CustomPropertyClass) + , m_name(name) + , m_value(WTFMove(value)) + , m_valueId(CSSValueInternalVariableValue) + , m_containsVariables(m_value->needsVariableResolution()) + { + } + + const AtomicString m_name; + + RefPtr m_value; + CSSValueID m_valueId { CSSValueInvalid }; + + mutable String m_stringValue; + bool m_containsVariables { false }; + mutable bool m_serialized { false }; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCustomPropertyValue, isCustomPropertyValue()) diff --git a/Source/WebCore/css/CSSDefaultStyleSheets.cpp b/Source/WebCore/css/CSSDefaultStyleSheets.cpp index e70024313..b9b40dd8a 100644 --- a/Source/WebCore/css/CSSDefaultStyleSheets.cpp +++ b/Source/WebCore/css/CSSDefaultStyleSheets.cpp @@ -33,12 +33,24 @@ #include "ChromeClient.h" #include "HTMLAnchorElement.h" #include "HTMLAudioElement.h" +#include "HTMLBRElement.h" +#include "HTMLBodyElement.h" +#include "HTMLDivElement.h" +#include "HTMLEmbedElement.h" +#include "HTMLHeadElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLObjectElement.h" +#include "HTMLSpanElement.h" +#include "MathMLElement.h" #include "MediaQueryEvaluator.h" #include "Page.h" #include "RenderTheme.h" #include "RuleSet.h" +#include "RuntimeEnabledFeatures.h" +#include "SVGElement.h" #include "StyleSheetContents.h" #include "UserAgentStyleSheets.h" +#include namespace WebCore { @@ -47,7 +59,7 @@ using namespace HTMLNames; RuleSet* CSSDefaultStyleSheets::defaultStyle; RuleSet* CSSDefaultStyleSheets::defaultQuirksStyle; RuleSet* CSSDefaultStyleSheets::defaultPrintStyle; -RuleSet* CSSDefaultStyleSheets::defaultViewSourceStyle; +unsigned CSSDefaultStyleSheets::defaultStyleVersion; StyleSheetContents* CSSDefaultStyleSheets::simpleDefaultStyleSheet; StyleSheetContents* CSSDefaultStyleSheets::defaultStyleSheet; @@ -57,30 +69,34 @@ StyleSheetContents* CSSDefaultStyleSheets::mathMLStyleSheet; StyleSheetContents* CSSDefaultStyleSheets::mediaControlsStyleSheet; StyleSheetContents* CSSDefaultStyleSheets::fullscreenStyleSheet; StyleSheetContents* CSSDefaultStyleSheets::plugInsStyleSheet; +StyleSheetContents* CSSDefaultStyleSheets::imageControlsStyleSheet; // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet. -static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}head{display:none}body{margin:8px}div:focus,span:focus,a:focus{outline:auto 5px -webkit-focus-ring-color}a:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}"; +static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}head{display:none}body{margin:8px}div:focus,span:focus,a:focus{outline:auto 5px -webkit-focus-ring-color}a:any-link{color:-webkit-link;text-decoration:underline}a:any-link:active{color:-webkit-activelink}"; -static inline bool elementCanUseSimpleDefaultStyle(Element* e) +static inline bool elementCanUseSimpleDefaultStyle(const Element& element) { - return e->hasTagName(htmlTag) || e->hasTagName(headTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || isHTMLAnchorElement(e); + return is(element) || is(element) + || is(element) || is(element) + || is(element) || is(element) + || is(element); } static const MediaQueryEvaluator& screenEval() { - DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen")); + static NeverDestroyed staticScreenEval(String(ASCIILiteral("screen"))); return staticScreenEval; } static const MediaQueryEvaluator& printEval() { - DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print")); + static NeverDestroyed staticPrintEval(String(ASCIILiteral("print"))); return staticPrintEval; } static StyleSheetContents* parseUASheet(const String& str) { - StyleSheetContents& sheet = StyleSheetContents::create().leakRef(); // leak the sheet on purpose + StyleSheetContents& sheet = StyleSheetContents::create(CSSParserContext(UASheetMode)).leakRef(); // leak the sheet on purpose sheet.parseString(str); return &sheet; } @@ -90,10 +106,10 @@ static StyleSheetContents* parseUASheet(const char* characters, unsigned size) return parseUASheet(String(characters, size)); } -void CSSDefaultStyleSheets::initDefaultStyle(Element* root) +void CSSDefaultStyleSheets::initDefaultStyle(const Element* root) { if (!defaultStyle) { - if (!root || elementCanUseSimpleDefaultStyle(root)) + if (!root || elementCanUseSimpleDefaultStyle(*root)) loadSimpleDefaultStyle(); else loadFullDefaultStyle(); @@ -107,26 +123,26 @@ void CSSDefaultStyleSheets::loadFullDefaultStyle() ASSERT(defaultPrintStyle == defaultStyle); delete defaultStyle; simpleDefaultStyleSheet->deref(); - defaultStyle = RuleSet::create().leakPtr(); - defaultPrintStyle = RuleSet::create().leakPtr(); + defaultStyle = std::make_unique().release(); + defaultPrintStyle = std::make_unique().release(); simpleDefaultStyleSheet = 0; } else { ASSERT(!defaultStyle); - defaultStyle = RuleSet::create().leakPtr(); - defaultPrintStyle = RuleSet::create().leakPtr(); - defaultQuirksStyle = RuleSet::create().leakPtr(); + defaultStyle = std::make_unique().release(); + defaultPrintStyle = std::make_unique().release(); + defaultQuirksStyle = std::make_unique().release(); } // Strict-mode rules. String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet(); defaultStyleSheet = parseUASheet(defaultRules); - defaultStyle->addRulesFromSheet(defaultStyleSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(defaultStyleSheet, printEval()); + defaultStyle->addRulesFromSheet(*defaultStyleSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(*defaultStyleSheet, printEval()); // Quirks-mode rules. String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet(); quirksStyleSheet = parseUASheet(quirksRules); - defaultQuirksStyle->addRulesFromSheet(quirksStyleSheet, screenEval()); + defaultQuirksStyle->addRulesFromSheet(*quirksStyleSheet, screenEval()); } void CSSDefaultStyleSheets::loadSimpleDefaultStyle() @@ -134,85 +150,89 @@ void CSSDefaultStyleSheets::loadSimpleDefaultStyle() ASSERT(!defaultStyle); ASSERT(!simpleDefaultStyleSheet); - defaultStyle = RuleSet::create().leakPtr(); + defaultStyle = std::make_unique().release(); // There are no media-specific rules in the simple default style. defaultPrintStyle = defaultStyle; - defaultQuirksStyle = RuleSet::create().leakPtr(); + defaultQuirksStyle = std::make_unique().release(); simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet)); - defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval()); - + defaultStyle->addRulesFromSheet(*simpleDefaultStyleSheet, screenEval()); + ++defaultStyleVersion; // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style. } -RuleSet* CSSDefaultStyleSheets::viewSourceStyle() -{ - if (!defaultViewSourceStyle) { - static StyleSheetContents* viewSourceStyleSheet = parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)); - defaultViewSourceStyle = RuleSet::create().leakPtr(); - defaultViewSourceStyle->addRulesFromSheet(viewSourceStyleSheet, screenEval()); - } - return defaultViewSourceStyle; -} - - -void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(Element* element, bool& changedDefaultStyle) +void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(const Element& element) { if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(element)) { loadFullDefaultStyle(); - changedDefaultStyle = true; + ++defaultStyleVersion; } -#if ENABLE(SVG) - if (element->isSVGElement() && !svgStyleSheet) { - // SVG rules. - svgStyleSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); - defaultStyle->addRulesFromSheet(svgStyleSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(svgStyleSheet, printEval()); - changedDefaultStyle = true; + if (is(element)) { + if (is(element) || is(element)) { + if (!plugInsStyleSheet) { + String plugInsRules = RenderTheme::themeForPage(element.document().page())->extraPlugInsStyleSheet() + element.document().page()->chrome().client().plugInExtraStyleSheet(); + if (plugInsRules.isEmpty()) + plugInsRules = String(plugInsUserAgentStyleSheet, sizeof(plugInsUserAgentStyleSheet)); + plugInsStyleSheet = parseUASheet(plugInsRules); + defaultStyle->addRulesFromSheet(*plugInsStyleSheet, screenEval()); + ++defaultStyleVersion; + } + } +#if ENABLE(VIDEO) + else if (is(element)) { + if (!mediaControlsStyleSheet) { + String mediaRules = RenderTheme::themeForPage(element.document().page())->mediaControlsStyleSheet(); + if (mediaRules.isEmpty()) + mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(element.document().page())->extraMediaControlsStyleSheet(); + mediaControlsStyleSheet = parseUASheet(mediaRules); + defaultStyle->addRulesFromSheet(*mediaControlsStyleSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(*mediaControlsStyleSheet, printEval()); + ++defaultStyleVersion; + } + } +#endif // ENABLE(VIDEO) +#if ENABLE(SERVICE_CONTROLS) + else if (is(element) && element.isImageControlsRootElement()) { + if (!imageControlsStyleSheet) { + String imageControlsRules = RenderTheme::themeForPage(element.document().page())->imageControlsStyleSheet(); + imageControlsStyleSheet = parseUASheet(imageControlsRules); + defaultStyle->addRulesFromSheet(*imageControlsStyleSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(*imageControlsStyleSheet, printEval()); + ++defaultStyleVersion; + } + } +#endif // ENABLE(SERVICE_CONTROLS) + } else if (is(element)) { + if (!svgStyleSheet) { + // SVG rules. + svgStyleSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(*svgStyleSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(*svgStyleSheet, printEval()); + ++defaultStyleVersion; + } } -#endif - #if ENABLE(MATHML) - if (element->isMathMLElement() && !mathMLStyleSheet) { - // MathML rules. - mathMLStyleSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet)); - defaultStyle->addRulesFromSheet(mathMLStyleSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(mathMLStyleSheet, printEval()); - changedDefaultStyle = true; - } -#endif - -#if ENABLE(VIDEO) - if (!mediaControlsStyleSheet && (element->hasTagName(videoTag) || isHTMLAudioElement(element))) { - String mediaRules = RenderTheme::themeForPage(element->document().page())->mediaControlsStyleSheet(); - if (mediaRules.isEmpty()) - mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(element->document().page())->extraMediaControlsStyleSheet(); - mediaControlsStyleSheet = parseUASheet(mediaRules); - defaultStyle->addRulesFromSheet(mediaControlsStyleSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(mediaControlsStyleSheet, printEval()); - changedDefaultStyle = true; + else if (is(element)) { + if (!mathMLStyleSheet) { + // MathML rules. + mathMLStyleSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet)); + defaultStyle->addRulesFromSheet(*mathMLStyleSheet, screenEval()); + defaultPrintStyle->addRulesFromSheet(*mathMLStyleSheet, printEval()); + ++defaultStyleVersion; + } } -#endif +#endif // ENABLE(MATHML) #if ENABLE(FULLSCREEN_API) - if (!fullscreenStyleSheet && element->document().webkitIsFullScreen()) { + if (!fullscreenStyleSheet && element.document().webkitIsFullScreen()) { String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraFullScreenStyleSheet(); fullscreenStyleSheet = parseUASheet(fullscreenRules); - defaultStyle->addRulesFromSheet(fullscreenStyleSheet, screenEval()); - defaultQuirksStyle->addRulesFromSheet(fullscreenStyleSheet, screenEval()); - changedDefaultStyle = true; - } -#endif - - if (!plugInsStyleSheet && (element->hasTagName(objectTag) || element->hasTagName(embedTag))) { - String plugInsRules = RenderTheme::themeForPage(element->document().page())->extraPlugInsStyleSheet() + element->document().page()->chrome().client().plugInExtraStyleSheet(); - if (plugInsRules.isEmpty()) - plugInsRules = String(plugInsUserAgentStyleSheet, sizeof(plugInsUserAgentStyleSheet)); - plugInsStyleSheet = parseUASheet(plugInsRules); - defaultStyle->addRulesFromSheet(plugInsStyleSheet, screenEval()); - changedDefaultStyle = true; + defaultStyle->addRulesFromSheet(*fullscreenStyleSheet, screenEval()); + defaultQuirksStyle->addRulesFromSheet(*fullscreenStyleSheet, screenEval()); + ++defaultStyleVersion; } +#endif // ENABLE(FULLSCREEN_API) ASSERT(defaultStyle->features().idsInRules.isEmpty()); ASSERT(mathMLStyleSheet || defaultStyle->features().siblingRules.isEmpty()); diff --git a/Source/WebCore/css/CSSDefaultStyleSheets.h b/Source/WebCore/css/CSSDefaultStyleSheets.h index ccdb1965d..3672ca1af 100644 --- a/Source/WebCore/css/CSSDefaultStyleSheets.h +++ b/Source/WebCore/css/CSSDefaultStyleSheets.h @@ -20,8 +20,7 @@ * */ -#ifndef CSSDefaultStyleSheets_h -#define CSSDefaultStyleSheets_h +#pragma once namespace WebCore { @@ -34,7 +33,7 @@ public: static RuleSet* defaultStyle; static RuleSet* defaultQuirksStyle; static RuleSet* defaultPrintStyle; - static RuleSet* defaultViewSourceStyle; + static unsigned defaultStyleVersion; static StyleSheetContents* simpleDefaultStyleSheet; static StyleSheetContents* defaultStyleSheet; @@ -44,14 +43,12 @@ public: static StyleSheetContents* mediaControlsStyleSheet; static StyleSheetContents* fullscreenStyleSheet; static StyleSheetContents* plugInsStyleSheet; + static StyleSheetContents* imageControlsStyleSheet; - static void ensureDefaultStyleSheetsForElement(Element*, bool& changedDefaultStyle); + static void ensureDefaultStyleSheetsForElement(const Element&); static void loadFullDefaultStyle(); static void loadSimpleDefaultStyle(); - static void initDefaultStyle(Element*); - static RuleSet* viewSourceStyle(); + static void initDefaultStyle(const Element*); }; } // namespace WebCore - -#endif // CSSDefaultStyleSheets_h diff --git a/Source/WebCore/css/CSSFilterImageValue.cpp b/Source/WebCore/css/CSSFilterImageValue.cpp index f217a8a69..15c3caf86 100644 --- a/Source/WebCore/css/CSSFilterImageValue.cpp +++ b/Source/WebCore/css/CSSFilterImageValue.cpp @@ -27,12 +27,13 @@ #include "config.h" #include "CSSFilterImageValue.h" -#if ENABLE(CSS_FILTERS) - #include "CSSImageValue.h" +#include "CachedImage.h" #include "CachedResourceLoader.h" +#include "CachedSVGDocumentReference.h" #include "CrossfadeGeneratedImage.h" #include "FilterEffectRenderer.h" +#include "GraphicsContext.h" #include "ImageBuffer.h" #include "RenderElement.h" #include "StyleCachedImage.h" @@ -45,13 +46,13 @@ namespace WebCore { CSSFilterImageValue::~CSSFilterImageValue() { if (m_cachedImage) - m_cachedImage->removeClient(&m_filterSubimageObserver); + m_cachedImage->removeClient(m_filterSubimageObserver); } String CSSFilterImageValue::customCSSText() const { StringBuilder result; - result.appendLiteral("-webkit-filter("); + result.appendLiteral("filter("); result.append(m_imageValue->cssText()); result.appendLiteral(", "); result.append(m_filterValue->cssText()); @@ -59,20 +60,24 @@ String CSSFilterImageValue::customCSSText() const return result.toString(); } -IntSize CSSFilterImageValue::fixedSize(const RenderElement* renderer) +FloatSize CSSFilterImageValue::fixedSize(const RenderElement* renderer) { - CachedResourceLoader* cachedResourceLoader = renderer->document().cachedResourceLoader(); - CachedImage* cachedImage = cachedImageForCSSValue(m_imageValue.get(), cachedResourceLoader); + // FIXME: Skip Content Security Policy check when filter is applied to an element in a user agent shadow tree. + // See . + ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); + + CachedResourceLoader& cachedResourceLoader = renderer->document().cachedResourceLoader(); + CachedImage* cachedImage = cachedImageForCSSValue(m_imageValue, cachedResourceLoader, options); if (!cachedImage) - return IntSize(); + return FloatSize(); return cachedImage->imageForRenderer(renderer)->size(); } bool CSSFilterImageValue::isPending() const { - return CSSImageGeneratorValue::subimageIsPending(m_imageValue.get()); + return CSSImageGeneratorValue::subimageIsPending(m_imageValue); } bool CSSFilterImageValue::knownToBeOpaque(const RenderElement*) const @@ -80,67 +85,77 @@ bool CSSFilterImageValue::knownToBeOpaque(const RenderElement*) const return false; } -void CSSFilterImageValue::loadSubimages(CachedResourceLoader* cachedResourceLoader) +void CSSFilterImageValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { CachedResourceHandle oldCachedImage = m_cachedImage; - m_cachedImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_imageValue.get(), cachedResourceLoader); + m_cachedImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_imageValue, cachedResourceLoader, options); if (m_cachedImage != oldCachedImage) { if (oldCachedImage) - oldCachedImage->removeClient(&m_filterSubimageObserver); + oldCachedImage->removeClient(m_filterSubimageObserver); if (m_cachedImage) - m_cachedImage->addClient(&m_filterSubimageObserver); + m_cachedImage->addClient(m_filterSubimageObserver); + } + + for (auto& filterOperation : m_filterOperations.operations()) { + if (!is(filterOperation.get())) + continue; + auto& referenceFilterOperation = downcast(*filterOperation); + referenceFilterOperation.loadExternalDocumentIfNeeded(cachedResourceLoader, options); } m_filterSubimageObserver.setReady(true); } -PassRefPtr CSSFilterImageValue::image(RenderElement* renderer, const IntSize& size) +RefPtr CSSFilterImageValue::image(RenderElement* renderer, const FloatSize& size) { - if (size.isEmpty()) - return 0; + ASSERT(renderer); - CachedResourceLoader* cachedResourceLoader = renderer->document().cachedResourceLoader(); - CachedImage* cachedImage = cachedImageForCSSValue(m_imageValue.get(), cachedResourceLoader); + if (size.isEmpty()) + return nullptr; + // FIXME: Skip Content Security Policy check when filter is applied to an element in a user agent shadow tree. + // See . + ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); + auto* cachedImage = cachedImageForCSSValue(m_imageValue, renderer->document().cachedResourceLoader(), options); if (!cachedImage) return Image::nullImage(); - Image* image = cachedImage->imageForRenderer(renderer); - + auto* image = cachedImage->imageForRenderer(renderer); if (!image) return Image::nullImage(); // Transform Image into ImageBuffer. - std::unique_ptr texture = ImageBuffer::create(size); + // FIXME (149424): This buffer should not be unconditionally unaccelerated. + auto texture = ImageBuffer::create(size, Unaccelerated); if (!texture) return Image::nullImage(); - texture->context()->drawImage(image, ColorSpaceDeviceRGB, IntPoint()); - RefPtr filterRenderer = FilterEffectRenderer::create(); - filterRenderer->setSourceImage(std::move(texture)); - filterRenderer->setSourceImageRect(FloatRect(FloatPoint(), size)); - filterRenderer->setFilterRegion(FloatRect(FloatPoint(), size)); - if (!filterRenderer->build(renderer, m_filterOperations, FilterFunction)) + auto imageRect = FloatRect { { }, size }; + texture->context().drawImage(*image, imageRect); + + auto filterRenderer = FilterEffectRenderer::create(); + filterRenderer->setSourceImage(WTFMove(texture)); + filterRenderer->setSourceImageRect(imageRect); + filterRenderer->setFilterRegion(imageRect); + if (!filterRenderer->build(*renderer, m_filterOperations, FilterFunction)) return Image::nullImage(); filterRenderer->apply(); - m_generatedImage = filterRenderer->output()->copyImage(); - - return m_generatedImage.release(); + return filterRenderer->output()->copyImage(); } void CSSFilterImageValue::filterImageChanged(const IntRect&) { - for (auto it = clients().begin(), end = clients().end(); it != end; ++it) - it->key->imageChanged(static_cast(this)); + for (auto& client : clients()) + client.key->imageChanged(static_cast(this)); } void CSSFilterImageValue::createFilterOperations(StyleResolver* resolver) { m_filterOperations.clear(); - resolver->createFilterOperations(m_filterValue.get(), m_filterOperations); + resolver->createFilterOperations(m_filterValue, m_filterOperations); } void CSSFilterImageValue::FilterSubimageObserverProxy::imageChanged(CachedImage*, const IntRect* rect) @@ -149,23 +164,21 @@ void CSSFilterImageValue::FilterSubimageObserverProxy::imageChanged(CachedImage* m_ownerValue->filterImageChanged(*rect); } -bool CSSFilterImageValue::hasFailedOrCanceledSubresources() const +bool CSSFilterImageValue::traverseSubresources(const std::function& handler) const { - if (m_cachedImage && m_cachedImage->loadFailedOrCanceled()) - return true; - return false; + if (!m_cachedImage) + return false; + return handler(*m_cachedImage); } bool CSSFilterImageValue::equals(const CSSFilterImageValue& other) const { - return equalInputImages(other) && compareCSSValuePtr(m_filterValue, other.m_filterValue); + return equalInputImages(other) && compareCSSValue(m_filterValue, other.m_filterValue); } bool CSSFilterImageValue::equalInputImages(const CSSFilterImageValue& other) const { - return compareCSSValuePtr(m_imageValue, other.m_imageValue); + return compareCSSValue(m_imageValue, other.m_imageValue); } } // namespace WebCore - -#endif // ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/css/CSSFilterImageValue.h b/Source/WebCore/css/CSSFilterImageValue.h index f212f51c7..cc59d6f82 100644 --- a/Source/WebCore/css/CSSFilterImageValue.h +++ b/Source/WebCore/css/CSSFilterImageValue.h @@ -24,10 +24,7 @@ * SUCH DAMAGE. */ -#ifndef CSSFilterImageValue_h -#define CSSFilterImageValue_h - -#if ENABLE(CSS_FILTERS) +#pragma once #include "CSSImageGeneratorValue.h" #include "CSSPrimitiveValue.h" @@ -45,28 +42,28 @@ class RenderElement; class Document; class StyleResolver; -class CSSFilterImageValue : public CSSImageGeneratorValue { +class CSSFilterImageValue final : public CSSImageGeneratorValue { friend class FilterSubimageObserverProxy; public: - static PassRef create(PassRef imageValue, PassRef filterValue) + static Ref create(Ref&& imageValue, Ref&& filterValue) { - return adoptRef(*new CSSFilterImageValue(std::move(imageValue), std::move(filterValue))); + return adoptRef(*new CSSFilterImageValue(WTFMove(imageValue), WTFMove(filterValue))); } ~CSSFilterImageValue(); String customCSSText() const; - PassRefPtr image(RenderElement*, const IntSize&); + RefPtr image(RenderElement*, const FloatSize&); bool isFixedSize() const { return true; } - IntSize fixedSize(const RenderElement*); + FloatSize fixedSize(const RenderElement*); bool isPending() const; bool knownToBeOpaque(const RenderElement*) const; - void loadSubimages(CachedResourceLoader*); + void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&); - bool hasFailedOrCanceledSubresources() const; + bool traverseSubresources(const std::function& handler) const; bool equals(const CSSFilterImageValue&) const; @@ -82,15 +79,15 @@ public: CachedImage* cachedImage() const { return m_cachedImage.get(); } private: - CSSFilterImageValue(PassRefPtr imageValue, PassRefPtr filterValue) + CSSFilterImageValue(Ref&& imageValue, Ref&& filterValue) : CSSImageGeneratorValue(FilterImageClass) - , m_imageValue(imageValue) - , m_filterValue(filterValue) + , m_imageValue(WTFMove(imageValue)) + , m_filterValue(WTFMove(filterValue)) , m_filterSubimageObserver(this) { } - class FilterSubimageObserverProxy : public CachedImageClient { + class FilterSubimageObserverProxy final : public CachedImageClient { public: FilterSubimageObserverProxy(CSSFilterImageValue* ownerValue) : m_ownerValue(ownerValue) @@ -99,7 +96,7 @@ private: } virtual ~FilterSubimageObserverProxy() { } - virtual void imageChanged(CachedImage*, const IntRect* = 0) override; + void imageChanged(CachedImage*, const IntRect* = nullptr) final; void setReady(bool ready) { m_ready = ready; } private: CSSFilterImageValue* m_ownerValue; @@ -108,21 +105,16 @@ private: void filterImageChanged(const IntRect&); - RefPtr m_imageValue; - RefPtr m_filterValue; + Ref m_imageValue; + Ref m_filterValue; FilterOperations m_filterOperations; CachedResourceHandle m_cachedImage; - RefPtr m_generatedImage; FilterSubimageObserverProxy m_filterSubimageObserver; }; -CSS_VALUE_TYPE_CASTS(CSSFilterImageValue, isFilterImageValue()) - } // namespace WebCore -#endif // ENABLE(CSS_FILTERS) - -#endif // CSSFilterImageValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFilterImageValue, isFilterImageValue()) diff --git a/Source/WebCore/css/CSSFontFace.cpp b/Source/WebCore/css/CSSFontFace.cpp index f8eab28e0..9bae31cdd 100644 --- a/Source/WebCore/css/CSSFontFace.cpp +++ b/Source/WebCore/css/CSSFontFace.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,155 +27,599 @@ #include "CSSFontFace.h" #include "CSSFontFaceSource.h" +#include "CSSFontFaceSrcValue.h" +#include "CSSFontFamily.h" +#include "CSSFontFeatureValue.h" #include "CSSFontSelector.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSSegmentedFontFace.h" +#include "CSSUnicodeRangeValue.h" +#include "CSSValue.h" +#include "CSSValueList.h" #include "Document.h" +#include "Font.h" #include "FontDescription.h" -#include "FontLoader.h" +#include "FontFace.h" +#include "FontVariantBuilder.h" #include "RuntimeEnabledFeatures.h" -#include "SimpleFontData.h" +#include "Settings.h" +#include "StyleProperties.h" +#include "StyleRule.h" namespace WebCore { -bool CSSFontFace::isLoaded() const +template void iterateClients(HashSet& clients, T callback) { - size_t size = m_sources.size(); - for (size_t i = 0; i < size; i++) { - if (!m_sources[i]->isLoaded()) - return false; + Vector> clientsCopy; + clientsCopy.reserveInitialCapacity(clients.size()); + for (auto* client : clients) + clientsCopy.uncheckedAppend(*client); + + for (auto* client : clients) + callback(*client); +} + +void CSSFontFace::appendSources(CSSFontFace& fontFace, CSSValueList& srcList, Document* document, bool isInitiatingElementInUserAgentShadowTree) +{ + for (auto& src : srcList) { + // An item in the list either specifies a string (local font name) or a URL (remote font to download). + CSSFontFaceSrcValue& item = downcast(src.get()); + std::unique_ptr source; + SVGFontFaceElement* fontFaceElement = nullptr; + bool foundSVGFont = false; + +#if ENABLE(SVG_FONTS) + foundSVGFont = item.isSVGFontFaceSrc() || item.svgFontFaceElement(); + fontFaceElement = item.svgFontFaceElement(); +#endif + if (!item.isLocal()) { + const Settings* settings = document ? &document->settings() : nullptr; + bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled()); + if (allowDownloading && item.isSupportedFormat() && document) { + if (CachedFont* cachedFont = item.cachedFont(document, foundSVGFont, isInitiatingElementInUserAgentShadowTree)) + source = std::make_unique(fontFace, item.resource(), cachedFont); + } + } else + source = std::make_unique(fontFace, item.resource(), nullptr, fontFaceElement); + + if (source) + fontFace.adoptSource(WTFMove(source)); } + fontFace.sourcesPopulated(); +} + +CSSFontFace::CSSFontFace(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection, FontFace* wrapper, bool isLocalFallback) + : m_timeoutTimer(*this, &CSSFontFace::timeoutFired) + , m_fontSelector(fontSelector) + , m_cssConnection(cssConnection) + , m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr()) + , m_isLocalFallback(isLocalFallback) + , m_mayBePurged(!wrapper) +{ +} + +CSSFontFace::~CSSFontFace() +{ +} + +bool CSSFontFace::setFamilies(CSSValue& family) +{ + if (!is(family)) + return false; + + CSSValueList& familyList = downcast(family); + if (!familyList.length()) + return false; + + RefPtr oldFamilies = m_families; + m_families = &familyList; + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFamily, &family); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this, oldFamilies.get()); + }); + return true; } -bool CSSFontFace::isValid() const +std::optional CSSFontFace::calculateStyleMask(CSSValue& style) { - size_t size = m_sources.size(); - for (size_t i = 0; i < size; i++) { - if (m_sources[i]->isValid()) - return true; + if (!is(style)) + return std::nullopt; + + switch (downcast(style).valueID()) { + case CSSValueNormal: + return FontStyleNormalMask; + case CSSValueItalic: + case CSSValueOblique: + return FontStyleItalicMask; + default: + return FontStyleNormalMask; + } + + return FontStyleNormalMask; +} + +bool CSSFontFace::setStyle(CSSValue& style) +{ + if (auto mask = calculateStyleMask(style)) { + m_traitsMask = static_cast((static_cast(m_traitsMask) & (~FontStyleMask)) | mask.value()); + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStyle, &style); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; + } + return false; +} + +std::optional CSSFontFace::calculateWeightMask(CSSValue& weight) +{ + if (!is(weight)) + return std::nullopt; + + switch (downcast(weight).valueID()) { + case CSSValueBold: + case CSSValueBolder: + case CSSValue700: + return FontWeight700Mask; + case CSSValueNormal: + case CSSValue400: + return FontWeight400Mask; + case CSSValue900: + return FontWeight900Mask; + case CSSValue800: + return FontWeight800Mask; + case CSSValue600: + return FontWeight600Mask; + case CSSValue500: + return FontWeight500Mask; + case CSSValue300: + return FontWeight300Mask; + case CSSValueLighter: + case CSSValue200: + return FontWeight200Mask; + case CSSValue100: + return FontWeight100Mask; + default: + return FontWeight400Mask; + } + + return FontWeight400Mask; +} + +bool CSSFontFace::setWeight(CSSValue& weight) +{ + if (auto mask = calculateWeightMask(weight)) { + m_traitsMask = static_cast((static_cast(m_traitsMask) & (~FontWeightMask)) | mask.value()); + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; } + return false; } -void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace) +bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange) { - m_segmentedFontFaces.add(segmentedFontFace); + if (!is(unicodeRange)) + return false; + + m_ranges.clear(); + auto& list = downcast(unicodeRange); + for (auto& rangeValue : list) { + auto& range = downcast(rangeValue.get()); + m_ranges.append({ range.from(), range.to() }); + } + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; } -void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace) +bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures) { - m_segmentedFontFaces.remove(segmentedFontFace); + auto ligatures = extractFontVariantLigatures(variantLigatures); + + m_variantSettings.commonLigatures = ligatures.commonLigatures; + m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures; + m_variantSettings.historicalLigatures = ligatures.historicalLigatures; + m_variantSettings.contextualAlternates = ligatures.contextualAlternates; + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantLigatures, &variantLigatures); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; } -void CSSFontFace::addSource(std::unique_ptr source) +bool CSSFontFace::setVariantPosition(CSSValue& variantPosition) { - source->setFontFace(this); - m_sources.append(std::move(source)); + if (!is(variantPosition)) + return false; + + m_variantSettings.position = downcast(variantPosition); + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; } -void CSSFontFace::fontLoaded(CSSFontFaceSource* source) +bool CSSFontFace::setVariantCaps(CSSValue& variantCaps) { - if (source != m_activeSource) - return; + if (!is(variantCaps)) + return false; - // FIXME: Can we assert that m_segmentedFontFaces is not empty? That may - // require stopping in-progress font loading when the last - // CSSSegmentedFontFace is removed. - if (m_segmentedFontFaces.isEmpty()) - return; + m_variantSettings.caps = downcast(variantCaps); - // Use one of the CSSSegmentedFontFaces' font selector. They all have - // the same font selector, so it's wasteful to store it in the CSSFontFace. - CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector(); - fontSelector->fontLoaded(); - -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading) { - if (source->ensureFontData()) - notifyFontLoader(Loaded); - else if (!isValid()) - notifyFontLoader(Error); - } -#endif + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps); - HashSet::iterator end = m_segmentedFontFaces.end(); - for (HashSet::iterator it = m_segmentedFontFaces.begin(); it != end; ++it) - (*it)->fontLoaded(this); + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled()) - notifyLoadingDone(); -#endif + return true; } -PassRefPtr CSSFontFace::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) +bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric) { - m_activeSource = 0; - if (!isValid()) - return 0; + auto numeric = extractFontVariantNumeric(variantNumeric); - ASSERT(!m_segmentedFontFaces.isEmpty()); - CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector(); + m_variantSettings.numericFigure = numeric.figure; + m_variantSettings.numericSpacing = numeric.spacing; + m_variantSettings.numericFraction = numeric.fraction; + m_variantSettings.numericOrdinal = numeric.ordinal; + m_variantSettings.numericSlashedZero = numeric.slashedZero; -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == NotLoaded) - notifyFontLoader(Loading); -#endif + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric); - size_t size = m_sources.size(); - for (size_t i = 0; i < size; ++i) { - if (RefPtr result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector)) { - m_activeSource = m_sources[i].get(); -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading && m_sources[i]->isLoaded()) { - notifyFontLoader(Loaded); - notifyLoadingDone(); - } -#endif - return result.release(); + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; +} + +bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates) +{ + if (!is(variantAlternates)) + return false; + + m_variantSettings.alternates = downcast(variantAlternates); + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; +} + +bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian) +{ + auto eastAsian = extractFontVariantEastAsian(variantEastAsian); + + m_variantSettings.eastAsianVariant = eastAsian.variant; + m_variantSettings.eastAsianWidth = eastAsian.width; + m_variantSettings.eastAsianRuby = eastAsian.ruby; + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantEastAsian, &variantEastAsian); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); + + return true; +} + +void CSSFontFace::setFeatureSettings(CSSValue& featureSettings) +{ + // Can only call this with a primitive value of normal, or a value list containing font feature values. + ASSERT(is(featureSettings) || is(featureSettings)); + + FontFeatureSettings settings; + + if (is(featureSettings)) { + auto& list = downcast(featureSettings); + for (auto& rangeValue : list) { + auto& feature = downcast(rangeValue.get()); + settings.insert({ feature.tag(), feature.value() }); } } -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading) { - notifyFontLoader(Error); - notifyLoadingDone(); + if (m_featureSettings == settings) + return; + + m_featureSettings = WTFMove(settings); + + if (m_cssConnection) + m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings); + + iterateClients(m_clients, [&](Client& client) { + client.fontPropertyChanged(*this); + }); +} + +bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const +{ + if (m_ranges.isEmpty()) + return true; + + for (auto& range : m_ranges) { + if (range.from <= character && character <= range.to) + return true; } -#endif - return 0; + return false; } -#if ENABLE(FONT_LOAD_EVENTS) -void CSSFontFace::notifyFontLoader(LoadState newState) +void CSSFontFace::fontLoadEventOccurred() { - m_loadState = newState; + Ref protectedThis(*this); - Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document(); - if (!document) - return; + // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source. + // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly + // when a source is failed or succeeded before we have asked it to load. + if (m_sourcesPopulated) + pump(); + + ASSERT(m_fontSelector); + m_fontSelector->fontLoaded(); + + iterateClients(m_clients, [&](Client& client) { + client.fontLoaded(*this); + }); +} + +void CSSFontFace::timeoutFired() +{ + setStatus(Status::TimedOut); + + fontLoadEventOccurred(); +} + +bool CSSFontFace::allSourcesFailed() const +{ + for (auto& source : m_sources) { + if (source->status() != CSSFontFaceSource::Status::Failure) + return false; + } + return true; +} + +void CSSFontFace::addClient(Client& client) +{ + m_clients.add(&client); +} - switch (newState) { - case Loading: - document->fontloader()->beginFontLoading(m_rule.get()); +void CSSFontFace::removeClient(Client& client) +{ + ASSERT(m_clients.contains(&client)); + m_clients.remove(&client); +} + +void CSSFontFace::initializeWrapper() +{ + switch (m_status) { + case Status::Pending: break; - case Loaded: - document->fontloader()->fontLoaded(m_rule.get()); + case Status::Loading: + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading); break; - case Error: - document->fontloader()->loadError(m_rule.get(), m_activeSource); + case Status::TimedOut: + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading); + m_wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut); break; - default: + case Status::Success: + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading); + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Success); + break; + case Status::Failure: + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading); + m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure); break; } + m_mayBePurged = false; } -void CSSFontFace::notifyLoadingDone() +Ref CSSFontFace::wrapper() { - Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document(); - if (document) - document->fontloader()->loadingDone(); + if (m_wrapper) + return *m_wrapper.get(); + + auto wrapper = FontFace::create(*this); + m_wrapper = wrapper->createWeakPtr(); + initializeWrapper(); + return wrapper; +} + +void CSSFontFace::setWrapper(FontFace& newWrapper) +{ + m_wrapper = newWrapper.createWeakPtr(); + initializeWrapper(); +} + +void CSSFontFace::adoptSource(std::unique_ptr&& source) +{ + m_sources.append(WTFMove(source)); + + // We should never add sources in the middle of loading. + ASSERT(!m_sourcesPopulated); +} + +void CSSFontFace::setStatus(Status newStatus) +{ + switch (newStatus) { + case Status::Pending: + ASSERT_NOT_REACHED(); + break; + case Status::Loading: + ASSERT(m_status == Status::Pending); + break; + case Status::TimedOut: + ASSERT(m_status == Status::Loading); + break; + case Status::Success: + ASSERT(m_status == Status::Loading || m_status == Status::TimedOut); + break; + case Status::Failure: + ASSERT(m_status == Status::Loading || m_status == Status::TimedOut); + break; + } + + if (newStatus == Status::Loading) + m_timeoutTimer.startOneShot(webFontsShouldAlwaysFallBack() ? 0 : 3); + else if (newStatus == Status::Success || newStatus == Status::Failure) + m_timeoutTimer.stop(); + + iterateClients(m_clients, [&](Client& client) { + client.fontStateChanged(*this, m_status, newStatus); + }); + + m_status = newStatus; +} + +void CSSFontFace::fontLoaded(CSSFontFaceSource&) +{ + ASSERT(!webFontsShouldAlwaysFallBack()); + + fontLoadEventOccurred(); +} + +bool CSSFontFace::webFontsShouldAlwaysFallBack() const +{ + return m_fontSelector && m_fontSelector->document() && m_fontSelector->document()->settings().webFontsAlwaysFallBack(); +} + +size_t CSSFontFace::pump() +{ + size_t i; + for (i = 0; i < m_sources.size(); ++i) { + auto& source = m_sources[i]; + + if (source->status() == CSSFontFaceSource::Status::Pending) { + ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut); + ASSERT(m_fontSelector); + if (m_status == Status::Pending) + setStatus(Status::Loading); + source->load(*m_fontSelector); + } + + switch (source->status()) { + case CSSFontFaceSource::Status::Pending: + ASSERT_NOT_REACHED(); + break; + case CSSFontFaceSource::Status::Loading: + ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut); + if (m_status == Status::Pending) + setStatus(Status::Loading); + return i; + case CSSFontFaceSource::Status::Success: + ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success); + if (m_status == Status::Pending) + setStatus(Status::Loading); + if (m_status == Status::Loading || m_status == Status::TimedOut) + setStatus(Status::Success); + return i; + case CSSFontFaceSource::Status::Failure: + if (m_status == Status::Pending) + setStatus(Status::Loading); + break; + } + } + if (m_sources.isEmpty() && m_status == Status::Pending) + setStatus(Status::Loading); + if (m_status == Status::Loading || m_status == Status::TimedOut) + setStatus(Status::Failure); + return m_sources.size(); +} + +void CSSFontFace::load() +{ + pump(); +} + +RefPtr CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) +{ + if (allSourcesFailed()) + return nullptr; + + // Our status is derived from the first non-failed source. However, this source may + // return null from font(), which means we need to continue looping through the remainder + // of the sources to try to find a font to use. These subsequent tries should not affect + // our own state, though. + size_t startIndex = pump(); + bool fontIsLoading = false; + for (size_t i = startIndex; i < m_sources.size(); ++i) { + auto& source = m_sources[i]; + if (source->status() == CSSFontFaceSource::Status::Pending) { + ASSERT(m_fontSelector); + if (fontIsLoading) + continue; + source->load(*m_fontSelector); + } + + switch (source->status()) { + case CSSFontFaceSource::Status::Pending: + ASSERT_NOT_REACHED(); + break; + case CSSFontFaceSource::Status::Loading: + ASSERT(!fontIsLoading); + fontIsLoading = true; + if (status() == Status::TimedOut) + continue; + return Font::create(FontCache::singleton().lastResortFallbackFontForEveryCharacter(fontDescription)->platformData(), true, true); + case CSSFontFaceSource::Status::Success: + if (RefPtr result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings)) + return result; + break; + case CSSFontFaceSource::Status::Failure: + break; + } + } + + return nullptr; +} + +bool CSSFontFace::purgeable() const +{ + return cssConnection() && m_mayBePurged; +} + +void CSSFontFace::updateStyleIfNeeded() +{ + if (m_fontSelector && m_fontSelector->document()) + m_fontSelector->document()->updateStyleIfNeeded(); } -#endif #if ENABLE(SVG_FONTS) bool CSSFontFace::hasSVGFontFaceSource() const diff --git a/Source/WebCore/css/CSSFontFace.h b/Source/WebCore/css/CSSFontFace.h index b8f561e54..b11dfd015 100644 --- a/Source/WebCore/css/CSSFontFace.h +++ b/Source/WebCore/css/CSSFontFace.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,102 +23,159 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFontFace_h -#define CSSFontFace_h +#pragma once #include "CSSFontFaceRule.h" -#include "CSSFontFaceSource.h" -#include "FontTraitsMask.h" +#include "FontTaggedSettings.h" +#include "TextFlags.h" +#include "Timer.h" #include #include #include -#include #include #include -#include +#include + +namespace JSC { +class ExecState; +} namespace WebCore { +class CSSFontFaceSource; +class CSSFontSelector; class CSSSegmentedFontFace; +class CSSValue; +class CSSValueList; +class Document; class FontDescription; -class SimpleFontData; +class Font; +class FontFace; -class CSSFontFace : public RefCounted { +class CSSFontFace final : public RefCounted { public: - static PassRefPtr create(FontTraitsMask traitsMask, PassRefPtr rule, bool isLocalFallback = false) { return adoptRef(new CSSFontFace(traitsMask, rule, isLocalFallback)); } - + static Ref create(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection = nullptr, FontFace* wrapper = nullptr, bool isLocalFallback = false) + { + return adoptRef(*new CSSFontFace(fontSelector, cssConnection, wrapper, isLocalFallback)); + } + virtual ~CSSFontFace(); + + // FIXME: These functions don't need to have boolean return values. + // Callers only call this with known-valid CSS values. + bool setFamilies(CSSValue&); + bool setStyle(CSSValue&); + bool setWeight(CSSValue&); + bool setUnicodeRange(CSSValue&); + bool setVariantLigatures(CSSValue&); + bool setVariantPosition(CSSValue&); + bool setVariantCaps(CSSValue&); + bool setVariantNumeric(CSSValue&); + bool setVariantAlternates(CSSValue&); + bool setVariantEastAsian(CSSValue&); + void setFeatureSettings(CSSValue&); + + enum class Status; + struct UnicodeRange; + const CSSValueList* families() const { return m_families.get(); } FontTraitsMask traitsMask() const { return m_traitsMask; } + const Vector& ranges() const { return m_ranges; } + const FontFeatureSettings& featureSettings() const { return m_featureSettings; } + const FontVariantSettings& variantSettings() const { return m_variantSettings; } + void setVariantSettings(const FontVariantSettings& variantSettings) { m_variantSettings = variantSettings; } + void setTraitsMask(FontTraitsMask traitsMask) { m_traitsMask = traitsMask; } + bool isLocalFallback() const { return m_isLocalFallback; } + Status status() const { return m_status; } + StyleRuleFontFace* cssConnection() const { return m_cssConnection.get(); } - struct UnicodeRange; + static std::optional calculateStyleMask(CSSValue& style); + static std::optional calculateWeightMask(CSSValue& weight); - void addRange(UChar32 from, UChar32 to) { m_ranges.append(UnicodeRange(from, to)); } - const Vector& ranges() const { return m_ranges; } + class Client; + void addClient(Client&); + void removeClient(Client&); - void addedToSegmentedFontFace(CSSSegmentedFontFace*); - void removedFromSegmentedFontFace(CSSSegmentedFontFace*); + bool allSourcesFailed() const; - bool isLoaded() const; - bool isValid() const; + void adoptSource(std::unique_ptr&&); + void sourcesPopulated() { m_sourcesPopulated = true; } - bool isLocalFallback() const { return m_isLocalFallback; } + void fontLoaded(CSSFontFaceSource&); - void addSource(std::unique_ptr); + void load(); + RefPtr font(const FontDescription&, bool syntheticBold, bool syntheticItalic); - void fontLoaded(CSSFontFaceSource*); + static void appendSources(CSSFontFace&, CSSValueList&, Document*, bool isInitiatingElementInUserAgentShadowTree); - PassRefPtr getFontData(const FontDescription&, bool syntheticBold, bool syntheticItalic); + class Client { + public: + virtual ~Client() { } + virtual void fontLoaded(CSSFontFace&) { } + virtual void fontStateChanged(CSSFontFace&, Status /*oldState*/, Status /*newState*/) { } + virtual void fontPropertyChanged(CSSFontFace&, CSSValueList* /*oldFamilies*/ = nullptr) { } + virtual void ref() = 0; + virtual void deref() = 0; + }; + + // Pending => Loading => TimedOut + // || \\ // || + // || \\ // || + // || \\// || + // || // || + // || //\\ || + // || // \\ || + // \/ \/ \/ \/ + // Success Failure + enum class Status { Pending, Loading, TimedOut, Success, Failure }; struct UnicodeRange { - UnicodeRange(UChar32 from, UChar32 to) - : m_from(from) - , m_to(to) - { - } - - UChar32 from() const { return m_from; } - UChar32 to() const { return m_to; } - - private: - UChar32 m_from; - UChar32 m_to; + UChar32 from; + UChar32 to; }; + bool rangesMatchCodePoint(UChar32) const; + + // We don't guarantee that the FontFace wrapper will be the same every time you ask for it. + Ref wrapper(); + void setWrapper(FontFace&); + FontFace* existingWrapper() { return m_wrapper.get(); } + + bool webFontsShouldAlwaysFallBack() const; + + bool purgeable() const; + + void updateStyleIfNeeded(); + #if ENABLE(SVG_FONTS) bool hasSVGFontFaceSource() const; #endif -#if ENABLE(FONT_LOAD_EVENTS) - enum LoadState { NotLoaded, Loading, Loaded, Error }; - LoadState loadState() const { return m_loadState; } -#endif - private: - CSSFontFace(FontTraitsMask traitsMask, PassRefPtr rule, bool isLocalFallback) - : m_traitsMask(traitsMask) - , m_activeSource(0) - , m_isLocalFallback(isLocalFallback) -#if ENABLE(FONT_LOAD_EVENTS) - , m_loadState(isLocalFallback ? Loaded : NotLoaded) - , m_rule(rule) -#endif - { - UNUSED_PARAM(rule); - } + CSSFontFace(CSSFontSelector*, StyleRuleFontFace*, FontFace*, bool isLocalFallback); + + size_t pump(); + void setStatus(Status); + void notifyClientsOfFontPropertyChange(); + + void initializeWrapper(); + + void fontLoadEventOccurred(); + void timeoutFired(); - FontTraitsMask m_traitsMask; + RefPtr m_families; + FontTraitsMask m_traitsMask { static_cast(FontStyleNormalMask | FontWeight400Mask) }; Vector m_ranges; - HashSet m_segmentedFontFaces; + FontFeatureSettings m_featureSettings; + FontVariantSettings m_variantSettings; + Timer m_timeoutTimer; Vector> m_sources; - CSSFontFaceSource* m_activeSource; - bool m_isLocalFallback; -#if ENABLE(FONT_LOAD_EVENTS) - LoadState m_loadState; - RefPtr m_rule; - void notifyFontLoader(LoadState); - void notifyLoadingDone(); -#endif + RefPtr m_fontSelector; + RefPtr m_cssConnection; + HashSet m_clients; + WeakPtr m_wrapper; + Status m_status { Status::Pending }; + bool m_isLocalFallback { false }; + bool m_sourcesPopulated { false }; + bool m_mayBePurged { true }; }; } - -#endif diff --git a/Source/WebCore/css/CSSFontFaceLoadEvent.cpp b/Source/WebCore/css/CSSFontFaceLoadEvent.cpp index c1801be80..017d4de46 100644 --- a/Source/WebCore/css/CSSFontFaceLoadEvent.cpp +++ b/Source/WebCore/css/CSSFontFaceLoadEvent.cpp @@ -39,15 +39,15 @@ CSSFontFaceLoadEvent::CSSFontFaceLoadEvent() { } -CSSFontFaceLoadEvent::CSSFontFaceLoadEvent(const AtomicString& type, PassRefPtr fontface, PassRefPtr error) +CSSFontFaceLoadEvent::CSSFontFaceLoadEvent(const AtomicString& type, RefPtr&& fontface, RefPtr&& error) : Event(type, false, false) - , m_fontface(fontface) - , m_error(error) + , m_fontface(WTFMove(fontface)) + , m_error(WTFMove(error)) { } -CSSFontFaceLoadEvent::CSSFontFaceLoadEvent(const AtomicString& type, const CSSFontFaceLoadEventInit& initializer) - : Event(type, initializer) +CSSFontFaceLoadEvent::CSSFontFaceLoadEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) , m_fontface(initializer.fontface) , m_error(initializer.error) { diff --git a/Source/WebCore/css/CSSFontFaceLoadEvent.h b/Source/WebCore/css/CSSFontFaceLoadEvent.h index c0f29c01f..93a613bc6 100644 --- a/Source/WebCore/css/CSSFontFaceLoadEvent.h +++ b/Source/WebCore/css/CSSFontFaceLoadEvent.h @@ -28,46 +28,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if ENABLE(FONT_LOAD_EVENTS) +#pragma once -#ifndef CSSFontFaceLoadEvent_h -#define CSSFontFaceLoadEvent_h +#if ENABLE(FONT_LOAD_EVENTS) #include "CSSFontFaceRule.h" #include "CSSValue.h" -#include "DOMError.h" #include "Event.h" #include "EventNames.h" -#include #include namespace WebCore { -struct CSSFontFaceLoadEventInit : public EventInit { - RefPtr fontface; - RefPtr error; -}; +class DOMError; -class CSSFontFaceLoadEvent : public Event { +class CSSFontFaceLoadEvent final : public Event { public: - static PassRefPtr create() + static Ref create() { - return adoptRef(new CSSFontFaceLoadEvent()); + return adoptRef(*new CSSFontFaceLoadEvent); } - static PassRefPtr create(const AtomicString& type, const CSSFontFaceLoadEventInit& initializer) + struct Init : EventInit { + RefPtr fontface; + RefPtr error; + }; + + static Ref create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) { - return adoptRef(new CSSFontFaceLoadEvent(type, initializer)); + return adoptRef(*new CSSFontFaceLoadEvent(type, initializer, isTrusted)); } - static PassRefPtr createForFontFaceRule(const AtomicString& type, PassRefPtr rule) + static Ref createForFontFaceRule(const AtomicString& type, RefPtr&& rule) { - return adoptRef(new CSSFontFaceLoadEvent(type, rule, 0)); + return adoptRef(*new CSSFontFaceLoadEvent(type, WTFMove(rule), nullptr)); } - static PassRefPtr createForError(PassRefPtr rule, PassRefPtr error) + static Ref createForError(RefPtr&& rule, RefPtr&& error) { - return adoptRef(new CSSFontFaceLoadEvent(eventNames().errorEvent, rule, error)); + return adoptRef(*new CSSFontFaceLoadEvent(eventNames().errorEvent, WTFMove(rule), WTFMove(error))); } virtual ~CSSFontFaceLoadEvent(); @@ -75,12 +74,12 @@ public: CSSFontFaceRule* fontface() const { return m_fontface.get(); } DOMError* error() const { return m_error.get(); } - virtual EventInterface eventInterface() const; + EventInterface eventInterface() const final; private: CSSFontFaceLoadEvent(); - CSSFontFaceLoadEvent(const AtomicString&, PassRefPtr, PassRefPtr); - CSSFontFaceLoadEvent(const AtomicString&, const CSSFontFaceLoadEventInit&); + CSSFontFaceLoadEvent(const AtomicString&, RefPtr&&, RefPtr&&); + CSSFontFaceLoadEvent(const AtomicString&, const Init&, IsTrusted); RefPtr m_fontface; RefPtr m_error; @@ -88,5 +87,4 @@ private: } // namespace WebCore -#endif // CSSFontFaceLoadEvent_h #endif // ENABLE(FONT_LOAD_EVENTS) diff --git a/Source/WebCore/css/CSSFontFaceLoadEvent.idl b/Source/WebCore/css/CSSFontFaceLoadEvent.idl index 148ea1fe1..0ab6f2083 100644 --- a/Source/WebCore/css/CSSFontFaceLoadEvent.idl +++ b/Source/WebCore/css/CSSFontFaceLoadEvent.idl @@ -29,11 +29,14 @@ */ [ - NoInterfaceObject, Conditional=FONT_LOAD_EVENTS, - JSNoStaticTables, - ConstructorTemplate=Event + Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInit), ] interface CSSFontFaceLoadEvent : Event { - [InitializedByEventConstructor] readonly attribute CSSFontFaceRule fontface; - [InitializedByEventConstructor] readonly attribute DOMError error; + readonly attribute CSSFontFaceRule? fontface; + readonly attribute DOMError? error; +}; + +dictionary CSSFontFaceLoadEventInit : EventInit { + CSSFontFaceRule? fontface = null; + DOMError? error = null; }; diff --git a/Source/WebCore/css/CSSFontFaceRule.cpp b/Source/WebCore/css/CSSFontFaceRule.cpp index e5c2a5556..0dda1b2c5 100644 --- a/Source/WebCore/css/CSSFontFaceRule.cpp +++ b/Source/WebCore/css/CSSFontFaceRule.cpp @@ -29,7 +29,7 @@ namespace WebCore { -CSSFontFaceRule::CSSFontFaceRule(StyleRuleFontFace* fontFaceRule, CSSStyleSheet* parent) +CSSFontFaceRule::CSSFontFaceRule(StyleRuleFontFace& fontFaceRule, CSSStyleSheet* parent) : CSSRule(parent) , m_fontFaceRule(fontFaceRule) { @@ -41,11 +41,11 @@ CSSFontFaceRule::~CSSFontFaceRule() m_propertiesCSSOMWrapper->clearParentRule(); } -CSSStyleDeclaration* CSSFontFaceRule::style() +CSSStyleDeclaration& CSSFontFaceRule::style() { if (!m_propertiesCSSOMWrapper) m_propertiesCSSOMWrapper = StyleRuleCSSStyleDeclaration::create(m_fontFaceRule->mutableProperties(), *this); - return m_propertiesCSSOMWrapper.get(); + return *m_propertiesCSSOMWrapper; } String CSSFontFaceRule::cssText() const @@ -60,11 +60,9 @@ String CSSFontFaceRule::cssText() const return result.toString(); } -void CSSFontFaceRule::reattach(StyleRuleBase* rule) +void CSSFontFaceRule::reattach(StyleRuleBase& rule) { - ASSERT(rule); - ASSERT_WITH_SECURITY_IMPLICATION(rule->isFontFaceRule()); - m_fontFaceRule = static_cast(rule); + m_fontFaceRule = downcast(rule); if (m_propertiesCSSOMWrapper) m_propertiesCSSOMWrapper->reattach(m_fontFaceRule->mutableProperties()); } diff --git a/Source/WebCore/css/CSSFontFaceRule.h b/Source/WebCore/css/CSSFontFaceRule.h index 32c8da977..e331c15db 100644 --- a/Source/WebCore/css/CSSFontFaceRule.h +++ b/Source/WebCore/css/CSSFontFaceRule.h @@ -19,8 +19,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSFontFaceRule_h -#define CSSFontFaceRule_h +#pragma once #include "CSSRule.h" @@ -30,25 +29,25 @@ class CSSStyleDeclaration; class StyleRuleFontFace; class StyleRuleCSSStyleDeclaration; -class CSSFontFaceRule : public CSSRule { +class CSSFontFaceRule final : public CSSRule { public: - static PassRefPtr create(StyleRuleFontFace* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSFontFaceRule(rule, sheet)); } + static Ref create(StyleRuleFontFace& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSFontFaceRule(rule, sheet)); } virtual ~CSSFontFaceRule(); - virtual CSSRule::Type type() const override { return FONT_FACE_RULE; } - virtual String cssText() const override; - virtual void reattach(StyleRuleBase*) override; - - CSSStyleDeclaration* style(); + WEBCORE_EXPORT CSSStyleDeclaration& style(); private: - CSSFontFaceRule(StyleRuleFontFace*, CSSStyleSheet* parent); + CSSFontFaceRule(StyleRuleFontFace&, CSSStyleSheet* parent); + + CSSRule::Type type() const final { return FONT_FACE_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; - RefPtr m_fontFaceRule; - mutable RefPtr m_propertiesCSSOMWrapper; + Ref m_fontFaceRule; + RefPtr m_propertiesCSSOMWrapper; }; } // namespace WebCore -#endif // CSSFontFaceRule_h +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSFontFaceRule, CSSRule::FONT_FACE_RULE) diff --git a/Source/WebCore/css/CSSFontFaceSet.cpp b/Source/WebCore/css/CSSFontFaceSet.cpp new file mode 100644 index 000000000..4507bfd3d --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSet.cpp @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSFontFaceSet.h" + +#include "CSSFontFaceSource.h" +#include "CSSFontFamily.h" +#include "CSSFontSelector.h" +#include "CSSParser.h" +#include "CSSPrimitiveValue.h" +#include "CSSSegmentedFontFace.h" +#include "CSSValueList.h" +#include "CSSValuePool.h" +#include "ExceptionCode.h" +#include "FontCache.h" +#include "StyleProperties.h" + +namespace WebCore { + +CSSFontFaceSet::CSSFontFaceSet() +{ +} + +CSSFontFaceSet::~CSSFontFaceSet() +{ + for (auto& face : m_faces) + face->removeClient(*this); + + for (auto& pair : m_locallyInstalledFacesLookupTable) { + for (auto& face : pair.value) + face->removeClient(*this); + } +} + +void CSSFontFaceSet::addClient(CSSFontFaceSetClient& client) +{ + m_clients.add(&client); +} + +void CSSFontFaceSet::removeClient(CSSFontFaceSetClient& client) +{ + ASSERT(m_clients.contains(&client)); + m_clients.remove(&client); +} + +void CSSFontFaceSet::incrementActiveCount() +{ + ++m_activeCount; + if (m_activeCount == 1) { + m_status = Status::Loading; + for (auto* client : m_clients) + client->startedLoading(); + } +} + +void CSSFontFaceSet::decrementActiveCount() +{ + --m_activeCount; + if (!m_activeCount) { + m_status = Status::Loaded; + for (auto* client : m_clients) + client->completedLoading(); + } +} + +bool CSSFontFaceSet::hasFace(const CSSFontFace& face) const +{ + for (auto& myFace : m_faces) { + if (myFace.ptr() == &face) + return true; + } + + return false; +} + +void CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered(const String& familyName) +{ + if (m_locallyInstalledFacesLookupTable.contains(familyName)) + return; + + Vector traitsMasks = FontCache::singleton().getTraitsInFamily(familyName); + if (traitsMasks.isEmpty()) + return; + + Vector> faces; + for (auto mask : traitsMasks) { + Ref face = CSSFontFace::create(nullptr, nullptr, nullptr, true); + + Ref familyList = CSSValueList::createCommaSeparated(); + familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName)); + face->setFamilies(familyList.get()); + face->setTraitsMask(mask); + face->adoptSource(std::make_unique(face.get(), familyName)); + ASSERT(!face->allSourcesFailed()); + faces.append(WTFMove(face)); + } + m_locallyInstalledFacesLookupTable.add(familyName, WTFMove(faces)); +} + +String CSSFontFaceSet::familyNameFromPrimitive(const CSSPrimitiveValue& value) +{ + if (value.isFontFamily()) + return value.fontFamily().familyName; + if (!value.isValueID()) + return { }; + + // We need to use the raw text for all the generic family types, since @font-face is a way of actually + // defining what font to use for those types. + switch (value.valueID()) { + case CSSValueSerif: + return serifFamily; + case CSSValueSansSerif: + return sansSerifFamily; + case CSSValueCursive: + return cursiveFamily; + case CSSValueFantasy: + return fantasyFamily; + case CSSValueMonospace: + return monospaceFamily; + case CSSValueWebkitPictograph: + return pictographFamily; + default: + return { }; + } +} + +void CSSFontFaceSet::addToFacesLookupTable(CSSFontFace& face) +{ + if (!face.families()) + return; + + for (auto& item : *face.families()) { + String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast(item.get())); + if (familyName.isEmpty()) + continue; + + auto addResult = m_facesLookupTable.add(familyName, Vector>()); + auto& familyFontFaces = addResult.iterator->value; + if (addResult.isNewEntry) { + // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system. + // This is by design. + ensureLocalFontFacesForFamilyRegistered(familyName); + familyFontFaces = { }; + } + + familyFontFaces.append(face); + } +} + +void CSSFontFaceSet::add(CSSFontFace& face) +{ + ASSERT(!hasFace(face)); + + for (auto* client : m_clients) + client->fontModified(); + + face.addClient(*this); + m_cache.clear(); + + if (face.cssConnection()) + m_faces.insert(m_facesPartitionIndex++, face); + else + m_faces.append(face); + + addToFacesLookupTable(face); + + if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut) + incrementActiveCount(); + + if (face.cssConnection()) { + ASSERT(!m_constituentCSSConnections.contains(face.cssConnection())); + m_constituentCSSConnections.add(face.cssConnection(), &face); + } +} + +void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor) +{ + for (auto& item : familiesToSearchFor) { + String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast(item.get())); + if (familyName.isEmpty()) + continue; + + auto iterator = m_facesLookupTable.find(familyName); + ASSERT(iterator != m_facesLookupTable.end()); + bool found = false; + for (size_t i = 0; i < iterator->value.size(); ++i) { + if (iterator->value[i].ptr() == &face) { + found = true; + iterator->value.remove(i); + break; + } + } + ASSERT_UNUSED(found, found); + if (!iterator->value.size()) + m_facesLookupTable.remove(iterator); + } +} + +void CSSFontFaceSet::remove(const CSSFontFace& face) +{ + m_cache.clear(); + + for (auto* client : m_clients) + client->fontModified(); + + if (face.families()) + removeFromFacesLookupTable(face, *face.families()); + + if (face.cssConnection()) { + ASSERT(m_constituentCSSConnections.get(face.cssConnection()) == &face); + m_constituentCSSConnections.remove(face.cssConnection()); + } + + for (size_t i = 0; i < m_faces.size(); ++i) { + if (m_faces[i].ptr() == &face) { + if (i < m_facesPartitionIndex) + --m_facesPartitionIndex; + m_faces[i]->removeClient(*this); + m_faces.remove(i); + if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut) + decrementActiveCount(); + return; + } + } + ASSERT_NOT_REACHED(); +} + +CSSFontFace* CSSFontFaceSet::lookUpByCSSConnection(StyleRuleFontFace& target) +{ + return m_constituentCSSConnections.get(&target); +} + +void CSSFontFaceSet::purge() +{ + Vector> toRemove; + for (auto& face : m_faces) { + if (face->purgeable()) + toRemove.append(face.copyRef()); + } + + for (auto& item : toRemove) + remove(item.get()); +} + +void CSSFontFaceSet::clear() +{ + for (auto& face : m_faces) + face->removeClient(*this); + m_faces.clear(); + m_facesLookupTable.clear(); + m_locallyInstalledFacesLookupTable.clear(); + m_cache.clear(); + m_constituentCSSConnections.clear(); + m_facesPartitionIndex = 0; + m_status = Status::Loaded; +} + +CSSFontFace& CSSFontFaceSet::operator[](size_t i) +{ + ASSERT(i < faceCount()); + return m_faces[i]; +} + +static std::optional computeFontTraitsMask(MutableStyleProperties& style) +{ + RefPtr styleValue = style.getPropertyCSSValue(CSSPropertyFontStyle).get(); + if (!styleValue) + styleValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr(); + + FontTraitsMask styleMask; + if (auto styleMaskOptional = CSSFontFace::calculateStyleMask(*styleValue)) + styleMask = styleMaskOptional.value(); + else + return std::nullopt; + + RefPtr weightValue = style.getPropertyCSSValue(CSSPropertyFontWeight).get(); + if (!weightValue) + weightValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr(); + + FontTraitsMask weightMask; + if (auto weightMaskOptional = CSSFontFace::calculateWeightMask(*weightValue)) + weightMask = weightMaskOptional.value(); + else + return std::nullopt; + + return static_cast(static_cast(styleMask) | static_cast(weightMask)); +} + +static HashSet codePointsFromString(StringView stringView) +{ + HashSet result; + auto graphemeClusters = stringView.graphemeClusters(); + for (auto cluster : graphemeClusters) { + ASSERT(cluster.length() > 0); + UChar32 character = 0; + if (cluster.is8Bit()) + character = cluster[0]; + else + U16_GET(cluster.characters16(), 0, 0, cluster.length(), character); + result.add(character); + } + return result; +} + +ExceptionOr>> CSSFontFaceSet::matchingFaces(const String& font, const String& string) +{ + auto style = MutableStyleProperties::create(); + auto parseResult = CSSParser::parseValue(style, CSSPropertyFont, font, true, HTMLStandardMode); + if (parseResult == CSSParser::ParseResult::Error) + return Exception { SYNTAX_ERR }; + + FontTraitsMask fontTraitsMask; + if (auto maskOptional = computeFontTraitsMask(style.get())) + fontTraitsMask = maskOptional.value(); + else + return Exception { SYNTAX_ERR }; + + auto family = style->getPropertyCSSValue(CSSPropertyFontFamily); + if (!is(family.get())) + return Exception { SYNTAX_ERR }; + CSSValueList& familyList = downcast(*family); + + HashSet uniqueFamilies; + Vector familyOrder; + for (auto& family : familyList) { + auto& primitive = downcast(family.get()); + if (!primitive.isFontFamily()) + continue; + if (uniqueFamilies.add(primitive.fontFamily().familyName).isNewEntry) + familyOrder.append(primitive.fontFamily().familyName); + } + + HashSet resultConstituents; + for (auto codePoint : codePointsFromString(string)) { + bool found = false; + for (auto& family : familyOrder) { + auto* faces = fontFace(fontTraitsMask, family); + if (!faces) + continue; + for (auto& constituentFace : faces->constituentFaces()) { + if (constituentFace->rangesMatchCodePoint(codePoint)) { + resultConstituents.add(constituentFace.ptr()); + found = true; + break; + } + } + if (found) + break; + } + } + + Vector> result; + result.reserveInitialCapacity(resultConstituents.size()); + for (auto* constituent : resultConstituents) + result.uncheckedAppend(*constituent); + return WTFMove(result); +} + +ExceptionOr CSSFontFaceSet::check(const String& font, const String& text) +{ + auto matchingFaces = this->matchingFaces(font, text); + if (matchingFaces.hasException()) + return matchingFaces.releaseException(); + + for (auto& face : matchingFaces.releaseReturnValue()) { + if (face.get().status() == CSSFontFace::Status::Pending) + return false; + } + return true; +} + +static bool fontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison, const CSSFontFace& first, const CSSFontFace& second) +{ + FontTraitsMask firstTraitsMask = first.traitsMask(); + FontTraitsMask secondTraitsMask = second.traitsMask(); + + bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; + bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; + + if (firstHasDesiredStyle != secondHasDesiredStyle) + return firstHasDesiredStyle; + + if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) { + // Prefer a font that has indicated that it can only support italics to a font that claims to support + // all styles. The specialized font is more likely to be the one the author wants used. + bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); + bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); + if (firstRequiresItalics != secondRequiresItalics) + return firstRequiresItalics; + } + + if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) + return false; + if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) + return true; + + // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says : + // - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found. + // - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found. + // - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used. + // - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used. + + static const unsigned fallbackRuleSets = 9; + static const unsigned rulesPerSet = 8; + static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { + { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, + { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, + { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } + }; + + unsigned ruleSetIndex = 0; + for (; !(desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { } + + const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; + for (unsigned i = 0; i < rulesPerSet; ++i) { + if (secondTraitsMask & weightFallbackRule[i]) + return false; + if (firstTraitsMask & weightFallbackRule[i]) + return true; + } + + return false; +} + +CSSSegmentedFontFace* CSSFontFaceSet::fontFace(FontTraitsMask traitsMask, const AtomicString& family) +{ + auto iterator = m_facesLookupTable.find(family); + if (iterator == m_facesLookupTable.end()) + return nullptr; + auto& familyFontFaces = iterator->value; + + auto& segmentedFontFaceCache = m_cache.add(family, HashMap>()).iterator->value; + + auto& face = segmentedFontFaceCache.add(traitsMask, nullptr).iterator->value; + if (face) + return face.get(); + + face = CSSSegmentedFontFace::create(); + + Vector, 32> candidateFontFaces; + for (int i = familyFontFaces.size() - 1; i >= 0; --i) { + CSSFontFace& candidate = familyFontFaces[i]; + unsigned candidateTraitsMask = candidate.traitsMask(); + if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) + continue; + candidateFontFaces.append(candidate); + } + + auto localIterator = m_locallyInstalledFacesLookupTable.find(family); + if (localIterator != m_locallyInstalledFacesLookupTable.end()) { + for (auto& candidate : localIterator->value) { + unsigned candidateTraitsMask = candidate->traitsMask(); + if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) + continue; + candidateFontFaces.append(candidate); + } + } + + std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [traitsMask](const CSSFontFace& first, const CSSFontFace& second) { + return fontFaceComparator(traitsMask, first, second); + }); + for (auto& candidate : candidateFontFaces) + face->appendFontFace(candidate.get()); + + return face.get(); +} + +void CSSFontFaceSet::fontStateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState) +{ + ASSERT(hasFace(face)); + if (oldState == CSSFontFace::Status::Pending) { + ASSERT(newState == CSSFontFace::Status::Loading); + incrementActiveCount(); + } + if (newState == CSSFontFace::Status::Success || newState == CSSFontFace::Status::Failure) { + ASSERT(oldState == CSSFontFace::Status::Loading || oldState == CSSFontFace::Status::TimedOut); + for (auto* client : m_clients) + client->faceFinished(face, newState); + decrementActiveCount(); + } +} + +void CSSFontFaceSet::fontPropertyChanged(CSSFontFace& face, CSSValueList* oldFamilies) +{ + m_cache.clear(); + + if (oldFamilies) { + removeFromFacesLookupTable(face, *oldFamilies); + addToFacesLookupTable(face); + } + + for (auto* client : m_clients) + client->fontModified(); +} + +} diff --git a/Source/WebCore/css/CSSFontFaceSet.h b/Source/WebCore/css/CSSFontFaceSet.h new file mode 100644 index 000000000..7913402fd --- /dev/null +++ b/Source/WebCore/css/CSSFontFaceSet.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSFontFace.h" +#include +#include +#include + +namespace WebCore { + +class CSSPrimitiveValue; +class FontFaceSet; + +class CSSFontFaceSetClient { +public: + virtual ~CSSFontFaceSetClient() { } + virtual void faceFinished(CSSFontFace&, CSSFontFace::Status) { }; + virtual void fontModified() { }; + virtual void startedLoading() { }; + virtual void completedLoading() { }; +}; + +class CSSFontFaceSet final : public RefCounted, public CSSFontFace::Client { +public: + static Ref create() + { + return adoptRef(*new CSSFontFaceSet()); + } + ~CSSFontFaceSet(); + + void addClient(CSSFontFaceSetClient&); + void removeClient(CSSFontFaceSetClient&); + + bool hasFace(const CSSFontFace&) const; + size_t faceCount() const { return m_faces.size(); } + void add(CSSFontFace&); + void remove(const CSSFontFace&); + void purge(); + void clear(); + CSSFontFace& operator[](size_t i); + + CSSFontFace* lookUpByCSSConnection(StyleRuleFontFace&); + + ExceptionOr check(const String& font, const String& text); + + CSSSegmentedFontFace* fontFace(FontTraitsMask, const AtomicString& family); + + enum class Status { Loading, Loaded }; + Status status() const { return m_status; } + + ExceptionOr>> matchingFaces(const String& font, const String& text); + + // CSSFontFace::Client needs to be able to be held in a RefPtr. + void ref() final { RefCounted::ref(); } + void deref() final { RefCounted::deref(); } + +private: + CSSFontFaceSet(); + + void removeFromFacesLookupTable(const CSSFontFace&, const CSSValueList& familiesToSearchFor); + void addToFacesLookupTable(CSSFontFace&); + + void incrementActiveCount(); + void decrementActiveCount(); + + void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) final; + void fontPropertyChanged(CSSFontFace&, CSSValueList* oldFamilies = nullptr) final; + + void ensureLocalFontFacesForFamilyRegistered(const String&); + + static String familyNameFromPrimitive(const CSSPrimitiveValue&); + + // m_faces should hold all the same fonts as the ones inside inside m_facesLookupTable. + Vector> m_faces; // We should investigate moving m_faces to FontFaceSet and making it reference FontFaces. This may clean up the font loading design. + HashMap>, ASCIICaseInsensitiveHash> m_facesLookupTable; + HashMap>, ASCIICaseInsensitiveHash> m_locallyInstalledFacesLookupTable; + HashMap>, ASCIICaseInsensitiveHash> m_cache; + HashMap m_constituentCSSConnections; + size_t m_facesPartitionIndex { 0 }; // All entries in m_faces before this index are CSS-connected. + Status m_status { Status::Loaded }; + HashSet m_clients; + unsigned m_activeCount { 0 }; +}; + +} diff --git a/Source/WebCore/css/CSSFontFaceSource.cpp b/Source/WebCore/css/CSSFontFaceSource.cpp index 23ee019b6..293f8f7fd 100644 --- a/Source/WebCore/css/CSSFontFaceSource.cpp +++ b/Source/WebCore/css/CSSFontFaceSource.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,187 +32,175 @@ #include "CachedResourceLoader.h" #include "Document.h" #include "ElementIterator.h" +#include "Font.h" #include "FontCache.h" +#include "FontCustomPlatformData.h" #include "FontDescription.h" -#include "SimpleFontData.h" +#include "SVGToOTFFontConversion.h" #if ENABLE(SVG_FONTS) +#include "CachedSVGFont.h" #include "FontCustomPlatformData.h" -#include "SVGFontData.h" #include "SVGFontElement.h" #include "SVGFontFaceElement.h" -#include "SVGNames.h" #include "SVGURIReference.h" #endif +#if USE(DIRECT2D) +#include +#endif + namespace WebCore { -CSSFontFaceSource::CSSFontFaceSource(const String& str, CachedFont* font) - : m_string(str) +inline void CSSFontFaceSource::setStatus(Status newStatus) +{ + switch (newStatus) { + case Status::Pending: + ASSERT_NOT_REACHED(); + break; + case Status::Loading: + ASSERT(status() == Status::Pending); + break; + case Status::Success: + ASSERT(status() == Status::Loading); + break; + case Status::Failure: + ASSERT(status() == Status::Loading); + break; + } + + m_status = newStatus; +} + +CSSFontFaceSource::CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CachedFont* font, SVGFontFaceElement* fontFace, RefPtr&& arrayBufferView) + : m_familyNameOrURI(familyNameOrURI) , m_font(font) - , m_face(0) + , m_face(owner) + , m_immediateSource(WTFMove(arrayBufferView)) #if ENABLE(SVG_FONTS) - , m_hasExternalSVGFont(false) + , m_svgFontFaceElement(fontFace) #endif { +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(fontFace); +#endif + + // This may synchronously call fontLoaded(). if (m_font) - m_font->addClient(this); + m_font->addClient(*this); + + if (status() == Status::Pending && (!m_font || m_font->isLoaded())) { + setStatus(Status::Loading); + if (m_font && m_font->errorOccurred()) + setStatus(Status::Failure); + else + setStatus(Status::Success); + } } CSSFontFaceSource::~CSSFontFaceSource() { if (m_font) - m_font->removeClient(this); - pruneTable(); + m_font->removeClient(*this); } -void CSSFontFaceSource::pruneTable() +void CSSFontFaceSource::fontLoaded(CachedFont& loadedFont) { - if (m_fontDataTable.isEmpty()) + ASSERT_UNUSED(loadedFont, &loadedFont == m_font.get()); + + // If the font is in the cache, this will be synchronously called from CachedFont::addClient(). + if (m_status == Status::Pending) + setStatus(Status::Loading); + else if (m_status == Status::Failure) { + // This function may be called twice if loading was cancelled. + ASSERT(m_font->errorOccurred()); return; + } - m_fontDataTable.clear(); -} + if (m_face.webFontsShouldAlwaysFallBack()) + return; -bool CSSFontFaceSource::isLoaded() const -{ - if (m_font) - return m_font->isLoaded(); - return true; -} + if (m_font->errorOccurred()) + setStatus(Status::Failure); + else + setStatus(Status::Success); -bool CSSFontFaceSource::isValid() const -{ - if (m_font) - return !m_font->errorOccurred(); - return true; + m_face.fontLoaded(*this); } -void CSSFontFaceSource::fontLoaded(CachedFont*) +void CSSFontFaceSource::load(CSSFontSelector& fontSelector) { - pruneTable(); - if (m_face) - m_face->fontLoaded(this); + setStatus(Status::Loading); + + ASSERT(m_font); + fontSelector.beginLoadingFontSoon(*m_font); } -PassRefPtr CSSFontFaceSource::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector* fontSelector) +RefPtr CSSFontFaceSource::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings) { - // If the font hasn't loaded or an error occurred, then we've got nothing. - if (!isValid()) - return 0; + ASSERT(status() == Status::Success); - if (!m_font + SVGFontFaceElement* fontFaceElement = nullptr; #if ENABLE(SVG_FONTS) - && !m_svgFontFaceElement + fontFaceElement = m_svgFontFaceElement.get(); #endif - ) { - // We're local. Just return a SimpleFontData from the normal cache. + + if (!m_font && !fontFaceElement) { + if (m_immediateSource) { + if (!m_immediateFontCustomPlatformData) { + bool wrapping; + RefPtr buffer = SharedBuffer::create(static_cast(m_immediateSource->baseAddress()), m_immediateSource->byteLength()); + ASSERT(buffer); + m_immediateFontCustomPlatformData = CachedFont::createCustomFontData(*buffer, wrapping); + } if (!m_immediateFontCustomPlatformData) + return nullptr; + return Font::create(CachedFont::platformDataFromCustomData(*m_immediateFontCustomPlatformData, fontDescription, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings), true); + } + + // We're local. Just return a Font from the normal cache. // We don't want to check alternate font family names here, so pass true as the checkingAlternateName parameter. - return fontCache()->getCachedFontData(fontDescription, m_string, true); + return FontCache::singleton().fontForFamily(fontDescription, m_familyNameOrURI, &fontFaceFeatures, &fontFaceVariantSettings, true); } - // See if we have a mapping in our FontData cache. - unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 5 | fontDescription.widthVariant() << 3 - | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); + if (m_font) { + if (!m_font->ensureCustomFontData(m_familyNameOrURI)) + return nullptr; - RefPtr fontData = m_fontDataTable.add(hashKey, nullptr).iterator->value; - if (fontData) - return fontData.release(); + return m_font->createFont(fontDescription, m_familyNameOrURI, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings); + } + + // In-Document SVG Fonts + if (!fontFaceElement) + return nullptr; - // If we are still loading, then we let the system pick a font. - if (isLoaded()) { - if (m_font) { #if ENABLE(SVG_FONTS) - if (m_hasExternalSVGFont) { - // For SVG fonts parse the external SVG document, and extract the element. - if (!m_font->ensureSVGFontData()) - return 0; - - if (!m_externalSVGFontElement) { - String fragmentIdentifier; - size_t start = m_string.find('#'); - if (start != notFound) - fragmentIdentifier = m_string.string().substring(start + 1); - m_externalSVGFontElement = m_font->getSVGFontById(fragmentIdentifier); - } - - if (!m_externalSVGFontElement) - return 0; - - if (auto firstFontFace = childrenOfType(*m_externalSVGFontElement).first()) { - if (!m_svgFontFaceElement) { - // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement. - // Use the imported tag as referencing font-face element for these cases. - m_svgFontFaceElement = firstFontFace; - } - - fontData = SimpleFontData::create(std::make_unique(firstFontFace), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic); - } - } else + if (!is(m_svgFontFaceElement->parentNode())) + return nullptr; + if (!m_inDocumentCustomPlatformData) { + SVGFontElement& fontElement = downcast(*m_svgFontFaceElement->parentNode()); + if (auto otfFont = convertSVGToOTFFont(fontElement)) + m_generatedOTFBuffer = SharedBuffer::adoptVector(otfFont.value()); + if (!m_generatedOTFBuffer) + return nullptr; + m_inDocumentCustomPlatformData = createFontCustomPlatformData(*m_generatedOTFBuffer); + } + if (!m_inDocumentCustomPlatformData) + return nullptr; +#if PLATFORM(COCOA) + return Font::create(m_inDocumentCustomPlatformData->fontPlatformData(fontDescription, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings), true, false); +#else + return Font::create(m_inDocumentCustomPlatformData->fontPlatformData(fontDescription, syntheticBold, syntheticItalic), true, false); #endif - { - // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef. - if (!m_font->ensureCustomFontData()) - return 0; - - fontData = SimpleFontData::create(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, - fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.renderingMode()), true, false); - } - } else { -#if ENABLE(SVG_FONTS) - // In-Document SVG Fonts - if (m_svgFontFaceElement) - fontData = SimpleFontData::create(std::make_unique(m_svgFontFaceElement.get()), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic); #endif - } - } else { - // Kick off the load. Do it soon rather than now, because we may be in the middle of layout, - // and the loader may invoke arbitrary delegate or event handler code. - fontSelector->beginLoadingFontSoon(m_font.get()); - - // This temporary font is not retained and should not be returned. - FontCachePurgePreventer fontCachePurgePreventer; - SimpleFontData* temporaryFont = fontCache()->getNonRetainedLastResortFallbackFont(fontDescription); - fontData = SimpleFontData::create(temporaryFont->platformData(), true, true); - } - return fontData.release(); + ASSERT_NOT_REACHED(); + return nullptr; } #if ENABLE(SVG_FONTS) -SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const -{ - return m_svgFontFaceElement.get(); -} - -void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr element) -{ - m_svgFontFaceElement = element; -} - bool CSSFontFaceSource::isSVGFontFaceSource() const { - return m_svgFontFaceElement || m_hasExternalSVGFont; -} -#endif - -#if ENABLE(FONT_LOAD_EVENTS) -bool CSSFontFaceSource::isDecodeError() const -{ - if (m_font) - return m_font->status() == CachedResource::DecodeError; - return false; -} - -bool CSSFontFaceSource::ensureFontData() -{ - if (!m_font) - return false; -#if ENABLE(SVG_FONTS) - if (m_hasExternalSVGFont) - return m_font->ensureSVGFontData(); -#endif - return m_font->ensureCustomFontData(); + return m_svgFontFaceElement || is(m_font.get()); } #endif diff --git a/Source/WebCore/css/CSSFontFaceSource.h b/Source/WebCore/css/CSSFontFaceSource.h index 818a3269c..4d0065219 100644 --- a/Source/WebCore/css/CSSFontFaceSource.h +++ b/Source/WebCore/css/CSSFontFaceSource.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,72 +23,74 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFontFaceSource_h -#define CSSFontFaceSource_h +#pragma once #include "CachedFontClient.h" #include "CachedResourceHandle.h" -#include "Timer.h" -#include +#include #include namespace WebCore { -class CachedFont; class CSSFontFace; class CSSFontSelector; +class Font; +struct FontCustomPlatformData; class FontDescription; -class SimpleFontData; -#if ENABLE(SVG_FONTS) -class SVGFontElement; +struct FontVariantSettings; class SVGFontFaceElement; -#endif +class SharedBuffer; -class CSSFontFaceSource : public CachedFontClient { +template class FontTaggedSettings; +typedef FontTaggedSettings FontFeatureSettings; + +class CSSFontFaceSource final : public CachedFontClient { + WTF_MAKE_FAST_ALLOCATED; public: - CSSFontFaceSource(const String&, CachedFont* = 0); + CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CachedFont* = nullptr, SVGFontFaceElement* = nullptr, RefPtr&& = nullptr); virtual ~CSSFontFaceSource(); - bool isLoaded() const; - bool isValid() const; - - const AtomicString& string() const { return m_string; } + // => Success + // // + // Pending => Loading + // \\. + // => Failure + enum class Status { + Pending, + Loading, + Success, + Failure + }; + Status status() const { return m_status; } - void setFontFace(CSSFontFace* face) { m_face = face; } + const AtomicString& familyNameOrURI() const { return m_familyNameOrURI; } - virtual void fontLoaded(CachedFont*); - - PassRefPtr getFontData(const FontDescription&, bool syntheticBold, bool syntheticItalic, CSSFontSelector*); - - void pruneTable(); + void load(CSSFontSelector&); + RefPtr font(const FontDescription&, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings&, const FontVariantSettings&); #if ENABLE(SVG_FONTS) - SVGFontFaceElement* svgFontFaceElement() const; - void setSVGFontFaceElement(PassRefPtr); bool isSVGFontFaceSource() const; - void setHasExternalSVGFont(bool value) { m_hasExternalSVGFont = value; } -#endif - -#if ENABLE(FONT_LOAD_EVENTS) - bool isDecodeError() const; - bool ensureFontData(); #endif private: - void startLoadingTimerFired(Timer*); + void fontLoaded(CachedFont&) override; + + void setStatus(Status); - AtomicString m_string; // URI for remote, built-in font name for local. + AtomicString m_familyNameOrURI; // URI for remote, built-in font name for local. CachedResourceHandle m_font; // For remote fonts, a pointer to our cached resource. - CSSFontFace* m_face; // Our owning font face. - HashMap> m_fontDataTable; // The hash key is composed of size synthetic styles. + CSSFontFace& m_face; // Our owning font face. + + RefPtr m_generatedOTFBuffer; + RefPtr m_immediateSource; + std::unique_ptr m_immediateFontCustomPlatformData; #if ENABLE(SVG_FONTS) RefPtr m_svgFontFaceElement; - RefPtr m_externalSVGFontElement; - bool m_hasExternalSVGFont; #endif -}; + std::unique_ptr m_inDocumentCustomPlatformData; -} + Status m_status { Status::Pending }; +}; -#endif +} // namespace WebCore diff --git a/Source/WebCore/css/CSSFontFaceSrcValue.cpp b/Source/WebCore/css/CSSFontFaceSrcValue.cpp index 6e653567a..8c4be4f20 100644 --- a/Source/WebCore/css/CSSFontFaceSrcValue.cpp +++ b/Source/WebCore/css/CSSFontFaceSrcValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,14 +41,19 @@ namespace WebCore { #if ENABLE(SVG_FONTS) bool CSSFontFaceSrcValue::isSVGFontFaceSrc() const { - return equalIgnoringCase(m_format, "svg"); + return equalLettersIgnoringASCIICase(m_format, "svg"); +} + +bool CSSFontFaceSrcValue::isSVGFontTarget() const +{ + return isSVGFontFaceSrc() || svgFontFaceElement(); } #endif bool CSSFontFaceSrcValue::isSupportedFormat() const { // Normally we would just check the format, but in order to avoid conflicts with the old WinIE style of font-face, - // we will also check to see if the URL ends with .eot. If so, we'll go ahead and assume that we shouldn't load it. + // we will also check to see if the URL ends with .eot. If so, we'll assume that we shouldn't load it. if (m_format.isEmpty()) { // Check for .eot. if (!m_resource.startsWith("data:", false) && m_resource.endsWith(".eot", false)) @@ -80,26 +85,24 @@ String CSSFontFaceSrcValue::customCSSText() const return result.toString(); } -void CSSFontFaceSrcValue::addSubresourceStyleURLs(ListHashSet& urls, const StyleSheetContents* styleSheet) const -{ - if (!isLocal()) - addSubresourceURL(urls, styleSheet->completeURL(m_resource)); -} - -bool CSSFontFaceSrcValue::hasFailedOrCanceledSubresources() const +bool CSSFontFaceSrcValue::traverseSubresources(const std::function& handler) const { if (!m_cachedFont) return false; - return m_cachedFont->loadFailedOrCanceled(); + return handler(*m_cachedFont); } -CachedFont* CSSFontFaceSrcValue::cachedFont(Document* document) +CachedFont* CSSFontFaceSrcValue::cachedFont(Document* document, bool isSVG, bool isInitiatingElementInUserAgentShadowTree) { - if (!m_cachedFont) { - CachedResourceRequest request(ResourceRequest(document->completeURL(m_resource))); - request.setInitiator(cachedResourceRequestInitiators().css); - m_cachedFont = document->cachedResourceLoader()->requestFont(request); - } + if (m_cachedFont) + return m_cachedFont.get(); + + ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); + options.contentSecurityPolicyImposition = isInitiatingElementInUserAgentShadowTree ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck; + + CachedResourceRequest request(ResourceRequest(document->completeURL(m_resource)), options); + request.setInitiator(cachedResourceRequestInitiators().css); + m_cachedFont = document->cachedResourceLoader().requestFont(WTFMove(request), isSVG); return m_cachedFont.get(); } diff --git a/Source/WebCore/css/CSSFontFaceSrcValue.h b/Source/WebCore/css/CSSFontFaceSrcValue.h index f2855ae41..4cca8da3e 100644 --- a/Source/WebCore/css/CSSFontFaceSrcValue.h +++ b/Source/WebCore/css/CSSFontFaceSrcValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,12 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFontFaceSrcValue_h -#define CSSFontFaceSrcValue_h +#pragma once #include "CSSValue.h" #include "CachedResourceHandle.h" -#include #include namespace WebCore { @@ -37,13 +35,13 @@ class CachedFont; class Document; class SVGFontFaceElement; -class CSSFontFaceSrcValue : public CSSValue { +class CSSFontFaceSrcValue final : public CSSValue { public: - static PassRef create(const String& resource) + static Ref create(const String& resource) { return adoptRef(*new CSSFontFaceSrcValue(resource, false)); } - static PassRef createLocal(const String& resource) + static Ref createLocal(const String& resource) { return adoptRef(*new CSSFontFaceSrcValue(resource, true)); } @@ -58,6 +56,7 @@ public: #if ENABLE(SVG_FONTS) bool isSVGFontFaceSrc() const; + bool isSVGFontTarget() const; SVGFontFaceElement* svgFontFaceElement() const { return m_svgFontFaceElement; } void setSVGFontFaceElement(SVGFontFaceElement* element) { m_svgFontFaceElement = element; } @@ -65,11 +64,9 @@ public: String customCSSText() const; - void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; + bool traverseSubresources(const std::function& handler) const; - bool hasFailedOrCanceledSubresources() const; - - CachedFont* cachedFont(Document*); + CachedFont* cachedFont(Document*, bool isSVG, bool isInitiatingElementInUserAgentShadowTree); bool equals(const CSSFontFaceSrcValue&) const; @@ -95,8 +92,6 @@ private: #endif }; -CSS_VALUE_TYPE_CASTS(CSSFontFaceSrcValue, isFontFaceSrcValue()) - -} +} // namespace WebCore -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFontFaceSrcValue, isFontFaceSrcValue()) diff --git a/Source/WebCore/css/CSSFontFamily.h b/Source/WebCore/css/CSSFontFamily.h new file mode 100644 index 000000000..87a647d46 --- /dev/null +++ b/Source/WebCore/css/CSSFontFamily.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace WebCore { + +// We use a CSSFontFamily instead of a String to store the font family inside CSSPrimitiveValue. +// This is because require an extra bit to determine if the font family was resolved by the CSS +// parser from a system font ID (caption | icon | menu | message-box | small-caption | +// status-bar). +// +// This is needed by the StyleBuilder to correctly set the "isSpecifiedFont" flag on the +// FontDescription. This flag is used to determine if we should do the "use backslash as Yen +// sign" hack. + +struct CSSFontFamily { + String familyName; + bool fromSystemFontID; +}; + +inline bool operator==(const CSSFontFamily& a, const CSSFontFamily& b) +{ + return a.familyName == b.familyName && a.fromSystemFontID == b.fromSystemFontID; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSFontFeatureValue.cpp b/Source/WebCore/css/CSSFontFeatureValue.cpp index 33ae13281..bdd3e9c80 100644 --- a/Source/WebCore/css/CSSFontFeatureValue.cpp +++ b/Source/WebCore/css/CSSFontFeatureValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,9 +32,9 @@ namespace WebCore { -CSSFontFeatureValue::CSSFontFeatureValue(const String& tag, int value) +CSSFontFeatureValue::CSSFontFeatureValue(FontTag&& tag, int value) : CSSValue(FontFeatureClass) - , m_tag(tag) + , m_tag(WTFMove(tag)) , m_value(value) { } @@ -43,7 +43,8 @@ String CSSFontFeatureValue::customCSSText() const { StringBuilder builder; builder.append('\''); - builder.append(m_tag); + for (char c : m_tag) + builder.append(c); builder.appendLiteral("' "); builder.appendNumber(m_value); return builder.toString(); diff --git a/Source/WebCore/css/CSSFontFeatureValue.h b/Source/WebCore/css/CSSFontFeatureValue.h index 94b2c64ec..f444fe36d 100644 --- a/Source/WebCore/css/CSSFontFeatureValue.h +++ b/Source/WebCore/css/CSSFontFeatureValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,36 +23,33 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFontFeatureValue_h -#define CSSFontFeatureValue_h +#pragma once #include "CSSValue.h" -#include +#include "FontTaggedSettings.h" namespace WebCore { -class CSSFontFeatureValue : public CSSValue { +class CSSFontFeatureValue final : public CSSValue { public: - static PassRef create(const String& tag, int value) + static Ref create(FontTag&& tag, int value) { - return adoptRef(*new CSSFontFeatureValue(tag, value)); + return adoptRef(*new CSSFontFeatureValue(WTFMove(tag), value)); } - const String& tag() const { return m_tag; } + const FontTag& tag() const { return m_tag; } int value() const { return m_value; } String customCSSText() const; bool equals(const CSSFontFeatureValue&) const; private: - CSSFontFeatureValue(const String&, int); + CSSFontFeatureValue(FontTag&&, int); - String m_tag; + FontTag m_tag; const int m_value; }; -CSS_VALUE_TYPE_CASTS(CSSFontFeatureValue, isFontFeatureValue()) +} // namespace WebCore -} // namespace - -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFontFeatureValue, isFontFeatureValue()) diff --git a/Source/WebCore/css/CSSFontSelector.cpp b/Source/WebCore/css/CSSFontSelector.cpp index e88567deb..44d84b04d 100644 --- a/Source/WebCore/css/CSSFontSelector.cpp +++ b/Source/WebCore/css/CSSFontSelector.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,20 +31,27 @@ #include "CSSFontFace.h" #include "CSSFontFaceRule.h" #include "CSSFontFaceSource.h" -#include "CSSFontFaceSrcValue.h" +#include "CSSFontFamily.h" +#include "CSSFontFeatureValue.h" #include "CSSPrimitiveValue.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSPropertyNames.h" #include "CSSSegmentedFontFace.h" #include "CSSUnicodeRangeValue.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" +#include "CSSValuePool.h" #include "CachedResourceLoader.h" #include "Document.h" +#include "Font.h" #include "FontCache.h" +#include "FontFace.h" +#include "FontFaceSet.h" +#include "FontSelectorClient.h" +#include "FontVariantBuilder.h" #include "Frame.h" #include "FrameLoader.h" #include "Settings.h" -#include "SimpleFontData.h" #include "StyleProperties.h" #include "StyleResolver.h" #include "StyleRule.h" @@ -52,286 +59,179 @@ #include #include -#if ENABLE(SVG) -#include "SVGFontFaceElement.h" -#include "SVGNames.h" -#endif - namespace WebCore { static unsigned fontSelectorId; -CSSFontSelector::CSSFontSelector(Document* document) - : m_document(document) - , m_beginLoadingTimer(this, &CSSFontSelector::beginLoadTimerFired) +CSSFontSelector::CSSFontSelector(Document& document) + : m_document(&document) + , m_cssFontFaceSet(CSSFontFaceSet::create()) + , m_beginLoadingTimer(*this, &CSSFontSelector::beginLoadTimerFired) , m_uniqueId(++fontSelectorId) , m_version(0) - { - // FIXME: An old comment used to say there was no need to hold a reference to m_document - // because "we are guaranteed to be destroyed before the document". But there does not - // seem to be any such guarantee. - ASSERT(m_document); - fontCache()->addClient(this); + FontCache::singleton().addClient(*this); + m_cssFontFaceSet->addClient(*this); } CSSFontSelector::~CSSFontSelector() { clearDocument(); - fontCache()->removeClient(this); + m_cssFontFaceSet->removeClient(*this); + FontCache::singleton().removeClient(*this); +} + +FontFaceSet& CSSFontSelector::fontFaceSet() +{ + if (!m_fontFaceSet) { + ASSERT(m_document); + m_fontFaceSet = FontFaceSet::create(*m_document, m_cssFontFaceSet.get()); + } + + return *m_fontFaceSet; } bool CSSFontSelector::isEmpty() const { - return m_fonts.isEmpty(); + return !m_cssFontFaceSet->faceCount(); +} + +void CSSFontSelector::buildStarted() +{ + m_buildIsUnderway = true; + m_stagingArea.clear(); + m_cssFontFaceSet->purge(); + ++m_version; + + m_cssConnectionsPossiblyToRemove.clear(); + m_cssConnectionsEncounteredDuringBuild.clear(); + for (size_t i = 0; i < m_cssFontFaceSet->faceCount(); ++i) { + CSSFontFace& face = m_cssFontFaceSet.get()[i]; + if (face.cssConnection()) + m_cssConnectionsPossiblyToRemove.add(&face); + } +} + +void CSSFontSelector::buildCompleted() +{ + if (!m_buildIsUnderway) + return; + + m_buildIsUnderway = false; + + // Some font faces weren't re-added during the build process. + for (auto& face : m_cssConnectionsPossiblyToRemove) { + auto* connection = face->cssConnection(); + ASSERT(connection); + if (!m_cssConnectionsEncounteredDuringBuild.contains(connection)) + m_cssFontFaceSet->remove(*face); + } + + for (auto& item : m_stagingArea) + addFontFaceRule(item.styleRuleFontFace, item.isInitiatingElementInUserAgentShadowTree); + m_stagingArea.clear(); } -void CSSFontSelector::addFontFaceRule(const StyleRuleFontFace* fontFaceRule) +void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree) { - // Obtain the font-family property and the src property. Both must be defined. - const StyleProperties& style = fontFaceRule->properties(); + if (m_buildIsUnderway) { + m_cssConnectionsEncounteredDuringBuild.add(&fontFaceRule); + m_stagingArea.append({fontFaceRule, isInitiatingElementInUserAgentShadowTree}); + return; + } + + const StyleProperties& style = fontFaceRule.properties(); RefPtr fontFamily = style.getPropertyCSSValue(CSSPropertyFontFamily); + RefPtr fontStyle = style.getPropertyCSSValue(CSSPropertyFontStyle); + RefPtr fontWeight = style.getPropertyCSSValue(CSSPropertyFontWeight); RefPtr src = style.getPropertyCSSValue(CSSPropertySrc); RefPtr unicodeRange = style.getPropertyCSSValue(CSSPropertyUnicodeRange); - if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList())) + RefPtr featureSettings = style.getPropertyCSSValue(CSSPropertyFontFeatureSettings); + RefPtr variantLigatures = style.getPropertyCSSValue(CSSPropertyFontVariantLigatures); + RefPtr variantPosition = style.getPropertyCSSValue(CSSPropertyFontVariantPosition); + RefPtr variantCaps = style.getPropertyCSSValue(CSSPropertyFontVariantCaps); + RefPtr variantNumeric = style.getPropertyCSSValue(CSSPropertyFontVariantNumeric); + RefPtr variantAlternates = style.getPropertyCSSValue(CSSPropertyFontVariantAlternates); + RefPtr variantEastAsian = style.getPropertyCSSValue(CSSPropertyFontVariantEastAsian); + if (!is(fontFamily.get()) || !is(src.get()) || (unicodeRange && !is(*unicodeRange))) return; - CSSValueList* familyList = toCSSValueList(fontFamily.get()); - if (!familyList->length()) + CSSValueList& familyList = downcast(*fontFamily); + if (!familyList.length()) return; - CSSValueList* srcList = toCSSValueList(src.get()); - if (!srcList->length()) + if (!fontStyle) + fontStyle = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr(); + + if (!fontWeight) + fontWeight = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); + + CSSValueList* rangeList = downcast(unicodeRange.get()); + + CSSValueList& srcList = downcast(*src); + if (!srcList.length()) return; - CSSValueList* rangeList = toCSSValueList(unicodeRange.get()); - - unsigned traitsMask = 0; - - if (RefPtr fontStyle = style.getPropertyCSSValue(CSSPropertyFontStyle)) { - if (!fontStyle->isPrimitiveValue()) - return; - - switch (toCSSPrimitiveValue(fontStyle.get())->getValueID()) { - case CSSValueNormal: - traitsMask |= FontStyleNormalMask; - break; - case CSSValueItalic: - case CSSValueOblique: - traitsMask |= FontStyleItalicMask; - break; - default: - break; - } - } else - traitsMask |= FontStyleNormalMask; - - if (RefPtr fontWeight = style.getPropertyCSSValue(CSSPropertyFontWeight)) { - if (!fontWeight->isPrimitiveValue()) - return; - - switch (toCSSPrimitiveValue(fontWeight.get())->getValueID()) { - case CSSValueBold: - case CSSValue700: - traitsMask |= FontWeight700Mask; - break; - case CSSValueNormal: - case CSSValue400: - traitsMask |= FontWeight400Mask; - break; - case CSSValue900: - traitsMask |= FontWeight900Mask; - break; - case CSSValue800: - traitsMask |= FontWeight800Mask; - break; - case CSSValue600: - traitsMask |= FontWeight600Mask; - break; - case CSSValue500: - traitsMask |= FontWeight500Mask; - break; - case CSSValue300: - traitsMask |= FontWeight300Mask; - break; - case CSSValue200: - traitsMask |= FontWeight200Mask; - break; - case CSSValue100: - traitsMask |= FontWeight100Mask; - break; - default: - break; - } - } else - traitsMask |= FontWeight400Mask; - - if (RefPtr fontVariant = style.getPropertyCSSValue(CSSPropertyFontVariant)) { - // font-variant descriptor can be a value list. - if (fontVariant->isPrimitiveValue()) { - RefPtr list = CSSValueList::createCommaSeparated(); - list->append(fontVariant); - fontVariant = list; - } else if (!fontVariant->isValueList()) - return; - - CSSValueList* variantList = toCSSValueList(fontVariant.get()); - unsigned numVariants = variantList->length(); - if (!numVariants) - return; - - for (unsigned i = 0; i < numVariants; ++i) { - switch (toCSSPrimitiveValue(variantList->itemWithoutBoundsCheck(i))->getValueID()) { - case CSSValueNormal: - traitsMask |= FontVariantNormalMask; - break; - case CSSValueSmallCaps: - traitsMask |= FontVariantSmallCapsMask; - break; - default: - break; - } - } - } else - traitsMask |= FontVariantMask; - - // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace. - RefPtr fontFace; - - int srcLength = srcList->length(); - - bool foundSVGFont = false; - - for (int i = 0; i < srcLength; i++) { - // An item in the list either specifies a string (local font name) or a URL (remote font to download). - CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i)); - std::unique_ptr source; - -#if ENABLE(SVG_FONTS) - foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement(); -#endif - if (!item->isLocal()) { - Settings* settings = m_document ? m_document->frame() ? &m_document->frame()->settings() : 0 : 0; - bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled()); - if (allowDownloading && item->isSupportedFormat() && m_document) { - CachedFont* cachedFont = item->cachedFont(m_document); - if (cachedFont) { - source = std::make_unique(item->resource(), cachedFont); -#if ENABLE(SVG_FONTS) - if (foundSVGFont) - source->setHasExternalSVGFont(true); -#endif - } - } - } else { - source = std::make_unique(item->resource()); - } - - if (!fontFace) { - RefPtr rule; -#if ENABLE(FONT_LOAD_EVENTS) - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=112116 - This CSSFontFaceRule has no parent. - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled()) - rule = static_pointer_cast(fontFaceRule->createCSSOMWrapper()); -#endif - fontFace = CSSFontFace::create(static_cast(traitsMask), rule); - } - - if (source) { -#if ENABLE(SVG_FONTS) - source->setSVGFontFaceElement(item->svgFontFaceElement()); -#endif - fontFace->addSource(std::move(source)); - } - } + m_creatingFont = true; + Ref fontFace = CSSFontFace::create(this, &fontFaceRule); - ASSERT(fontFace); + if (!fontFace->setFamilies(*fontFamily)) + return; + if (!fontFace->setStyle(*fontStyle)) + return; + if (!fontFace->setWeight(*fontWeight)) + return; + if (rangeList && !fontFace->setUnicodeRange(*rangeList)) + return; + if (variantLigatures && !fontFace->setVariantLigatures(*variantLigatures)) + return; + if (variantPosition && !fontFace->setVariantPosition(*variantPosition)) + return; + if (variantCaps && !fontFace->setVariantCaps(*variantCaps)) + return; + if (variantNumeric && !fontFace->setVariantNumeric(*variantNumeric)) + return; + if (variantAlternates && !fontFace->setVariantAlternates(*variantAlternates)) + return; + if (variantEastAsian && !fontFace->setVariantEastAsian(*variantEastAsian)) + return; + if (featureSettings) + fontFace->setFeatureSettings(*featureSettings); - if (fontFace && !fontFace->isValid()) + CSSFontFace::appendSources(fontFace, srcList, m_document, isInitiatingElementInUserAgentShadowTree); + if (fontFace->allSourcesFailed()) return; - if (rangeList) { - unsigned numRanges = rangeList->length(); - for (unsigned i = 0; i < numRanges; i++) { - CSSUnicodeRangeValue* range = static_cast(rangeList->itemWithoutBoundsCheck(i)); - fontFace->addRange(range->from(), range->to()); - } + if (RefPtr existingFace = m_cssFontFaceSet->lookUpByCSSConnection(fontFaceRule)) { + // This adoption is fairly subtle. Script can trigger a purge of m_cssFontFaceSet at any time, + // which will cause us to just rely on the memory cache to retain the bytes of the file the next + // time we build up the CSSFontFaceSet. However, when the CSS Font Loading API is involved, + // the FontFace and FontFaceSet objects need to retain state. We create the new CSSFontFace object + // while the old one is still in scope so that the memory cache will be forced to retain the bytes + // of the resource. This means that the CachedFont will temporarily have two clients (until the + // old CSSFontFace goes out of scope, which should happen at the end of this "if" block). Because + // the CSSFontFaceSource objects will inspect their CachedFonts, the new CSSFontFace is smart enough + // to enter the correct state() during the next pump(). This approach of making a new CSSFontFace is + // simpler than computing and applying a diff of the StyleProperties. + m_cssFontFaceSet->remove(*existingFace); + if (auto* existingWrapper = existingFace->existingWrapper()) + existingWrapper->adopt(fontFace.get()); } - // Hash under every single family name. - int familyLength = familyList->length(); - for (int i = 0; i < familyLength; i++) { - CSSPrimitiveValue* item = toCSSPrimitiveValue(familyList->itemWithoutBoundsCheck(i)); - String familyName; - if (item->isString()) { - familyName = item->getStringValue(); - } else if (item->isValueID()) { - // We need to use the raw text for all the generic family types, since @font-face is a way of actually - // defining what font to use for those types. - switch (item->getValueID()) { - case CSSValueSerif: - familyName = serifFamily; - break; - case CSSValueSansSerif: - familyName = sansSerifFamily; - break; - case CSSValueCursive: - familyName = cursiveFamily; - break; - case CSSValueFantasy: - familyName = fantasyFamily; - break; - case CSSValueMonospace: - familyName = monospaceFamily; - break; - case CSSValueWebkitPictograph: - familyName = pictographFamily; - break; - default: - break; - } - } - - if (familyName.isEmpty()) - continue; - - std::unique_ptr>>& familyFontFaces = m_fontFaces.add(familyName, nullptr).iterator->value; - if (!familyFontFaces) { - familyFontFaces = std::make_unique>>(); - - ASSERT(!m_locallyInstalledFontFaces.contains(familyName)); - - Vector locallyInstalledFontsTraitsMasks; - fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks); - if (unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size()) { - auto familyLocallyInstalledFaces = std::make_unique>>(); - - for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) { - RefPtr locallyInstalledFontFace = CSSFontFace::create(static_cast(locallyInstalledFontsTraitsMasks[i]), 0, true); - locallyInstalledFontFace->addSource(std::make_unique(familyName)); - ASSERT(locallyInstalledFontFace->isValid()); - familyLocallyInstalledFaces->append(locallyInstalledFontFace); - } - - m_locallyInstalledFontFaces.set(familyName, std::move(familyLocallyInstalledFaces)); - } - } - - familyFontFaces->append(fontFace); - - ++m_version; - } + m_cssFontFaceSet->add(fontFace.get()); + m_creatingFont = false; + ++m_version; } -void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client) +void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient& client) { - m_clients.add(client); + m_clients.add(&client); } -void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client) +void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient& client) { - m_clients.remove(client); + m_clients.remove(&client); } void CSSFontSelector::dispatchInvalidationCallbacks() @@ -341,16 +241,7 @@ void CSSFontSelector::dispatchInvalidationCallbacks() Vector clients; copyToVector(m_clients, clients); for (size_t i = 0; i < clients.size(); ++i) - clients[i]->fontsNeedUpdate(this); - - // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks. - if (!m_document) - return; - if (StyleResolver* styleResolver = m_document->styleResolverIfExists()) - styleResolver->invalidateMatchedPropertiesCache(); - if (m_document->inPageCache() || !m_document->renderView()) - return; - m_document->scheduleForcedStyleRecalc(); + clients[i]->fontsNeedUpdate(*this); } void CSSFontSelector::fontLoaded() @@ -358,202 +249,60 @@ void CSSFontSelector::fontLoaded() dispatchInvalidationCallbacks(); } +void CSSFontSelector::fontModified() +{ + if (!m_creatingFont) + dispatchInvalidationCallbacks(); +} + void CSSFontSelector::fontCacheInvalidated() { dispatchInvalidationCallbacks(); } -static PassRefPtr fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName) +static const AtomicString& resolveGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName) { - if (!document || !document->frame()) - return 0; + if (!document) + return familyName; - const Settings& settings = document->frame()->settings(); + const Settings& settings = document->settings(); - AtomicString genericFamily; UScriptCode script = fontDescription.script(); - if (familyName == serifFamily) - genericFamily = settings.serifFontFamily(script); - else if (familyName == sansSerifFamily) - genericFamily = settings.sansSerifFontFamily(script); - else if (familyName == cursiveFamily) - genericFamily = settings.cursiveFontFamily(script); - else if (familyName == fantasyFamily) - genericFamily = settings.fantasyFontFamily(script); - else if (familyName == monospaceFamily) - genericFamily = settings.fixedFontFamily(script); - else if (familyName == pictographFamily) - genericFamily = settings.pictographFontFamily(script); - else if (familyName == standardFamily) - genericFamily = settings.standardFontFamily(script); - - if (!genericFamily.isEmpty()) - return fontCache()->getCachedFontData(fontDescription, genericFamily); - - return nullptr; + return settings.serifFontFamily(script); + if (familyName == sansSerifFamily) + return settings.sansSerifFontFamily(script); + if (familyName == cursiveFamily) + return settings.cursiveFontFamily(script); + if (familyName == fantasyFamily) + return settings.fantasyFontFamily(script); + if (familyName == monospaceFamily) + return settings.fixedFontFamily(script); + if (familyName == pictographFamily) + return settings.pictographFontFamily(script); + if (familyName == standardFamily) + return settings.standardFontFamily(script); + + return familyName; } -static FontTraitsMask desiredTraitsMaskForComparison; - -static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second) +FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescription, const AtomicString& familyName) { - FontTraitsMask firstTraitsMask = first->traitsMask(); - FontTraitsMask secondTraitsMask = second->traitsMask(); - - bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; - bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; - - if (firstHasDesiredVariant != secondHasDesiredVariant) - return firstHasDesiredVariant; - - // We need to check font-variant css property for CSS2.1 compatibility. - if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) { - // Prefer a font that has indicated that it can only support small-caps to a font that claims to support - // all variants. The specialized font is more likely to be true small-caps and not require synthesis. - bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask); - bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask); - if (firstRequiresSmallCaps != secondRequiresSmallCaps) - return firstRequiresSmallCaps; - } - - bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; - bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; - - if (firstHasDesiredStyle != secondHasDesiredStyle) - return firstHasDesiredStyle; - - if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) { - // Prefer a font that has indicated that it can only support italics to a font that claims to support - // all styles. The specialized font is more likely to be the one the author wants used. - bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); - bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); - if (firstRequiresItalics != secondRequiresItalics) - return firstRequiresItalics; - } - - if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) - return false; - if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) - return true; - - // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says : - // - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found. - // - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found. - // - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used. - // - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used. - - static const unsigned fallbackRuleSets = 9; - static const unsigned rulesPerSet = 8; - static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { - { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, - { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, - { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, - { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, - { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, - { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, - { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, - { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, - { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } - }; - - unsigned ruleSetIndex = 0; - unsigned w = FontWeight100Bit; - while (!(desiredTraitsMaskForComparison & (1 << w))) { - w++; - ruleSetIndex++; - } - - ASSERT_WITH_SECURITY_IMPLICATION(ruleSetIndex < fallbackRuleSets); - const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; - for (unsigned i = 0; i < rulesPerSet; ++i) { - if (secondTraitsMask & weightFallbackRule[i]) - return false; - if (firstTraitsMask & weightFallbackRule[i]) - return true; - } - - return false; -} + // If this ASSERT() fires, it usually means you forgot a document.updateStyleIfNeeded() somewhere. + ASSERT(!m_buildIsUnderway || m_isComputingRootStyleFont); -PassRefPtr CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName) -{ - if (m_fontFaces.isEmpty()) { - if (familyName.startsWith("-webkit-")) - return fontDataForGenericFamily(m_document, fontDescription, familyName); - if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) - return fontDataForGenericFamily(m_document, fontDescription, standardFamily); - return 0; - } + // FIXME: The spec (and Firefox) says user specified generic families (sans-serif etc.) should be resolved before the @font-face lookup too. + bool resolveGenericFamilyFirst = familyName == standardFamily; - CSSSegmentedFontFace* face = getFontFace(fontDescription, familyName); - // If no face was found, then return 0 and let the OS come up with its best match for the name. + AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName; + auto* face = m_cssFontFaceSet->fontFace(fontDescription.traitsMask(), familyForLookup); if (!face) { - // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our - // settings. - if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) - return fontDataForGenericFamily(m_document, fontDescription, standardFamily); - return fontDataForGenericFamily(m_document, fontDescription, familyName); + if (!resolveGenericFamilyFirst) + familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName); + return FontRanges(FontCache::singleton().fontForFamily(fontDescription, familyForLookup)); } - // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over. - return face->getFontData(fontDescription); -} - -CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family) -{ - Vector>* familyFontFaces = m_fontFaces.get(family); - if (!familyFontFaces || familyFontFaces->isEmpty()) - return 0; - - std::unique_ptr>>& segmentedFontFaceCache = m_fonts.add(family, nullptr).iterator->value; - if (!segmentedFontFaceCache) - segmentedFontFaceCache = std::make_unique>>(); - - FontTraitsMask traitsMask = fontDescription.traitsMask(); - - RefPtr& face = segmentedFontFaceCache->add(traitsMask, nullptr).iterator->value; - if (!face) { - face = CSSSegmentedFontFace::create(this); - - // Collect all matching faces and sort them in order of preference. - Vector candidateFontFaces; - for (int i = familyFontFaces->size() - 1; i >= 0; --i) { - CSSFontFace* candidate = familyFontFaces->at(i).get(); - unsigned candidateTraitsMask = candidate->traitsMask(); - if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) - continue; - if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) - continue; -#if ENABLE(SVG_FONTS) - // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable - // of small-caps synthesis and just ignore the font face as a candidate. - if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask)) - continue; -#endif - candidateFontFaces.append(candidate); - } - - if (Vector>* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { - unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); - for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { - CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); - unsigned candidateTraitsMask = candidate->traitsMask(); - if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) - continue; - if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) - continue; - candidateFontFaces.append(candidate); - } - } - - desiredTraitsMaskForComparison = traitsMask; - std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces); - unsigned numCandidates = candidateFontFaces.size(); - for (unsigned i = 0; i < numCandidates; ++i) - face->appendFontFace(candidateFontFaces[i]); - } - return face.get(); + return face->fontRanges(fontDescription); } void CSSFontSelector::clearDocument() @@ -566,93 +315,74 @@ void CSSFontSelector::clearDocument() m_beginLoadingTimer.stop(); - CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader(); - for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) { + CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader(); + for (auto& fontHandle : m_fontsToBeginLoading) { // Balances incrementRequestCount() in beginLoadingFontSoon(). - cachedResourceLoader->decrementRequestCount(m_fontsToBeginLoading[i].get()); + cachedResourceLoader.decrementRequestCount(*fontHandle); } - m_fontsToBeginLoading.clear(); - m_document = 0; + m_document = nullptr; + + m_cssFontFaceSet->clear(); + m_clients.clear(); } -void CSSFontSelector::beginLoadingFontSoon(CachedFont* font) +void CSSFontSelector::beginLoadingFontSoon(CachedFont& font) { if (!m_document) return; - m_fontsToBeginLoading.append(font); + m_fontsToBeginLoading.append(&font); // Increment the request count now, in order to prevent didFinishLoad from being dispatched // after this font has been requested but before it began loading. Balanced by // decrementRequestCount() in beginLoadTimerFired() and in clearDocument(). - m_document->cachedResourceLoader()->incrementRequestCount(font); + m_document->cachedResourceLoader().incrementRequestCount(font); m_beginLoadingTimer.startOneShot(0); } -void CSSFontSelector::beginLoadTimerFired(Timer&) +void CSSFontSelector::beginLoadTimerFired() { Vector> fontsToBeginLoading; fontsToBeginLoading.swap(m_fontsToBeginLoading); // CSSFontSelector could get deleted via beginLoadIfNeeded() or loadDone() unless protected. - Ref protect(*this); + Ref protectedThis(*this); - CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader(); - for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) { - fontsToBeginLoading[i]->beginLoadIfNeeded(cachedResourceLoader); + CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader(); + for (auto& fontHandle : fontsToBeginLoading) { + fontHandle->beginLoadIfNeeded(cachedResourceLoader); // Balances incrementRequestCount() in beginLoadingFontSoon(). - cachedResourceLoader->decrementRequestCount(fontsToBeginLoading[i].get()); + cachedResourceLoader.decrementRequestCount(*fontHandle); } // Ensure that if the request count reaches zero, the frame loader will know about it. - cachedResourceLoader->loadDone(0); + cachedResourceLoader.loadDone(); // New font loads may be triggered by layout after the document load is complete but before we have dispatched // didFinishLoading for the frame. Make sure the delegate is always dispatched by checking explicitly. if (m_document && m_document->frame()) m_document->frame()->loader().checkLoadComplete(); } -bool CSSFontSelector::resolvesFamilyFor(const FontDescription& description) const -{ - for (unsigned i = 0; i < description.familyCount(); ++i) { - const AtomicString& familyName = description.familyAt(i); - if (description.genericFamily() == FontDescription::StandardFamily && !description.isSpecifiedFont()) - return true; - if (familyName.isEmpty()) - continue; - if (m_fontFaces.contains(familyName)) - return true; - DEFINE_STATIC_LOCAL(String, webkitPrefix, ("-webkit-")); - if (familyName.startsWith(webkitPrefix)) - return true; - - } - return false; -} -size_t CSSFontSelector::fallbackFontDataCount() +size_t CSSFontSelector::fallbackFontCount() { if (!m_document) return 0; - if (Settings* settings = m_document->settings()) - return settings->fontFallbackPrefersPictographs() ? 1 : 0; - - return 0; + return m_document->settings().fontFallbackPrefersPictographs() ? 1 : 0; } -PassRefPtr CSSFontSelector::getFallbackFontData(const FontDescription& fontDescription, size_t index) +RefPtr CSSFontSelector::fallbackFontAt(const FontDescription& fontDescription, size_t index) { ASSERT_UNUSED(index, !index); if (!m_document) - return 0; + return nullptr; - Settings* settings = m_document->settings(); - if (!settings || !settings->fontFallbackPrefersPictographs()) - return 0; + if (!m_document->settings().fontFallbackPrefersPictographs()) + return nullptr; - return fontCache()->getCachedFontData(fontDescription, settings->pictographFontFamily()); + return FontCache::singleton().fontForFamily(fontDescription, m_document->settings().pictographFontFamily()); } } diff --git a/Source/WebCore/css/CSSFontSelector.h b/Source/WebCore/css/CSSFontSelector.h index 8ad74cd77..623f2486a 100644 --- a/Source/WebCore/css/CSSFontSelector.h +++ b/Source/WebCore/css/CSSFontSelector.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,84 +23,97 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFontSelector_h -#define CSSFontSelector_h +#pragma once +#include "CSSFontFace.h" +#include "CSSFontFaceSet.h" #include "CachedResourceHandle.h" +#include "Font.h" #include "FontSelector.h" -#include "SimpleFontData.h" #include "Timer.h" #include #include -#include #include #include #include namespace WebCore { -class CSSFontFace; class CSSFontFaceRule; +class CSSPrimitiveValue; class CSSSegmentedFontFace; +class CSSValueList; class CachedFont; class Document; -class FontDescription; class StyleRuleFontFace; -class CSSFontSelector final : public FontSelector { +class CSSFontSelector final : public FontSelector, public CSSFontFaceSetClient { public: - static PassRefPtr create(Document* document) + static Ref create(Document& document) { - return adoptRef(new CSSFontSelector(document)); + return adoptRef(*new CSSFontSelector(document)); } virtual ~CSSFontSelector(); - virtual unsigned version() const override { return m_version; } - virtual unsigned uniqueId() const override { return m_uniqueId; } + unsigned version() const final { return m_version; } + unsigned uniqueId() const final { return m_uniqueId; } - virtual PassRefPtr getFontData(const FontDescription&, const AtomicString&) override; - virtual size_t fallbackFontDataCount() override; - virtual PassRefPtr getFallbackFontData(const FontDescription&, size_t) override; - CSSSegmentedFontFace* getFontFace(const FontDescription&, const AtomicString& family); - - virtual bool resolvesFamilyFor(const FontDescription&) const override; + FontRanges fontRangesForFamily(const FontDescription&, const AtomicString&) final; + size_t fallbackFontCount() final; + RefPtr fallbackFontAt(const FontDescription&, size_t) final; void clearDocument(); + void buildStarted(); + void buildCompleted(); - void addFontFaceRule(const StyleRuleFontFace*); + void addFontFaceRule(StyleRuleFontFace&, bool isInitiatingElementInUserAgentShadowTree); void fontLoaded(); - virtual void fontCacheInvalidated() override; + void fontCacheInvalidated() final; bool isEmpty() const; - virtual void registerForInvalidationCallbacks(FontSelectorClient*) override; - virtual void unregisterForInvalidationCallbacks(FontSelectorClient*) override; + void registerForInvalidationCallbacks(FontSelectorClient&) final; + void unregisterForInvalidationCallbacks(FontSelectorClient&) final; Document* document() const { return m_document; } - void beginLoadingFontSoon(CachedFont*); + void beginLoadingFontSoon(CachedFont&); + + FontFaceSet& fontFaceSet(); + + void setIsComputingRootStyleFont(bool value) { m_isComputingRootStyleFont = value; } private: - CSSFontSelector(Document*); + explicit CSSFontSelector(Document&); void dispatchInvalidationCallbacks(); - void beginLoadTimerFired(Timer&); + void fontModified() final; + + void beginLoadTimerFired(); + + struct PendingFontFaceRule { + StyleRuleFontFace& styleRuleFontFace; + bool isInitiatingElementInUserAgentShadowTree; + }; + Vector m_stagingArea; Document* m_document; - HashMap>>, CaseFoldingHash> m_fontFaces; - HashMap>>, CaseFoldingHash> m_locallyInstalledFontFaces; - HashMap>>, CaseFoldingHash> m_fonts; + RefPtr m_fontFaceSet; + Ref m_cssFontFaceSet; HashSet m_clients; Vector> m_fontsToBeginLoading; - Timer m_beginLoadingTimer; + HashSet> m_cssConnectionsPossiblyToRemove; + HashSet> m_cssConnectionsEncounteredDuringBuild; + Timer m_beginLoadingTimer; unsigned m_uniqueId; unsigned m_version; + bool m_creatingFont { false }; + bool m_buildIsUnderway { false }; + bool m_isComputingRootStyleFont { false }; }; } // namespace WebCore - -#endif // CSSFontSelector_h diff --git a/Source/WebCore/css/CSSFontValue.cpp b/Source/WebCore/css/CSSFontValue.cpp index 5197c9bf0..f80d43d55 100644 --- a/Source/WebCore/css/CSSFontValue.cpp +++ b/Source/WebCore/css/CSSFontValue.cpp @@ -1,6 +1,6 @@ /** * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/Source/WebCore/css/CSSFontValue.h b/Source/WebCore/css/CSSFontValue.h index 81ac41a7a..79d548d24 100644 --- a/Source/WebCore/css/CSSFontValue.h +++ b/Source/WebCore/css/CSSFontValue.h @@ -18,11 +18,9 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSFontValue_h -#define CSSFontValue_h +#pragma once #include "CSSValue.h" -#include #include namespace WebCore { @@ -30,9 +28,9 @@ namespace WebCore { class CSSPrimitiveValue; class CSSValueList; -class CSSFontValue : public CSSValue { +class CSSFontValue final : public CSSValue { public: - static PassRef create() + static Ref create() { return adoptRef(*new CSSFontValue); } @@ -55,8 +53,6 @@ private: } }; -CSS_VALUE_TYPE_CASTS(CSSFontValue, isFontValue()) +} // namespace WebCore -} // namespace - -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFontValue, isFontValue()) diff --git a/Source/WebCore/css/CSSFontVariationValue.cpp b/Source/WebCore/css/CSSFontVariationValue.cpp new file mode 100644 index 000000000..a20826129 --- /dev/null +++ b/Source/WebCore/css/CSSFontVariationValue.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VARIATION_FONTS) + +#include "CSSFontVariationValue.h" + +#include + +namespace WebCore { + +CSSFontVariationValue::CSSFontVariationValue(FontTag tag, float value) + : CSSValue(FontVariationClass) + , m_tag(tag) + , m_value(value) +{ +} + +String CSSFontVariationValue::customCSSText() const +{ + StringBuilder builder; + builder.append('\''); + for (char c : m_tag) + builder.append(c); + builder.appendLiteral("' "); + builder.appendNumber(m_value); + return builder.toString(); +} + +bool CSSFontVariationValue::equals(const CSSFontVariationValue& other) const +{ + return m_tag == other.m_tag && m_value == other.m_value; +} + +} + +#endif // ENABLE(VARIATION_FONTS) diff --git a/Source/WebCore/css/CSSFontVariationValue.h b/Source/WebCore/css/CSSFontVariationValue.h new file mode 100644 index 000000000..faf34b57b --- /dev/null +++ b/Source/WebCore/css/CSSFontVariationValue.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(VARIATION_FONTS) + +#include "CSSValue.h" +#include "FontTaggedSettings.h" + +namespace WebCore { + +class CSSFontVariationValue final : public CSSValue { +public: + static Ref create(FontTag tag, float value) + { + return adoptRef(*new CSSFontVariationValue(tag, value)); + } + + const FontTag& tag() const { return m_tag; } + float value() const { return m_value; } + String customCSSText() const; + + bool equals(const CSSFontVariationValue&) const; + +private: + CSSFontVariationValue(FontTag, float); + + FontTag m_tag; + const float m_value; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFontVariationValue, isFontVariationValue()) + +#endif // ENABLE(VARIATION_FONTS) diff --git a/Source/WebCore/css/CSSFunctionValue.cpp b/Source/WebCore/css/CSSFunctionValue.cpp index 3877f6da9..75ef0c1ed 100644 --- a/Source/WebCore/css/CSSFunctionValue.cpp +++ b/Source/WebCore/css/CSSFunctionValue.cpp @@ -26,40 +26,18 @@ #include "config.h" #include "CSSFunctionValue.h" -#include "CSSParserValues.h" -#include "CSSValueList.h" #include namespace WebCore { - -CSSFunctionValue::CSSFunctionValue(CSSParserFunction* function) - : CSSValue(FunctionClass) - , m_name(function->name) -{ - if (function->args) - m_args = CSSValueList::createFromParserValueList(*function->args); -} - -CSSFunctionValue::CSSFunctionValue(String name, PassRefPtr args) - : CSSValue(FunctionClass) - , m_name(name) - , m_args(args) -{ -} - + String CSSFunctionValue::customCSSText() const { StringBuilder result; - result.append(m_name); // Includes the '(' - if (m_args) - result.append(m_args->cssText()); + result.append(getValueName(m_name)); + result.append('('); + result.append(CSSValueList::customCSSText()); result.append(')'); return result.toString(); } -bool CSSFunctionValue::equals(const CSSFunctionValue& other) const -{ - return m_name == other.m_name && compareCSSValuePtr(m_args, other.m_args); -} - } diff --git a/Source/WebCore/css/CSSFunctionValue.h b/Source/WebCore/css/CSSFunctionValue.h index 511123b87..ebb3d5bab 100644 --- a/Source/WebCore/css/CSSFunctionValue.h +++ b/Source/WebCore/css/CSSFunctionValue.h @@ -23,44 +23,36 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSFunctionValue_h -#define CSSFunctionValue_h +#pragma once -#include "CSSValue.h" +#include "CSSValueKeywords.h" +#include "CSSValueList.h" namespace WebCore { -class CSSValueList; -struct CSSParserFunction; - -class CSSFunctionValue : public CSSValue { +class CSSFunctionValue final : public CSSValueList { public: - static PassRef create(CSSParserFunction* function) - { - return adoptRef(*new CSSFunctionValue(function)); - } - - static PassRef create(String name, PassRefPtr args) + static Ref create(CSSValueID name) { - return adoptRef(*new CSSFunctionValue(name, args)); + return adoptRef(*new CSSFunctionValue(name)); } - + String customCSSText() const; - bool equals(const CSSFunctionValue&) const; + CSSValueID name() const { return m_name; } - CSSValueList* arguments() const { return m_args.get(); } + bool equals(const CSSFunctionValue& other) const { return m_name == other.m_name && CSSValueList::equals(other); } private: - explicit CSSFunctionValue(CSSParserFunction*); - CSSFunctionValue(String, PassRefPtr); + CSSFunctionValue(CSSValueID name) + : CSSValueList(FunctionClass, CommaSeparator) + , m_name(name) + { + } - String m_name; - RefPtr m_args; + CSSValueID m_name { CSSValueInvalid }; }; -CSS_VALUE_TYPE_CASTS(CSSFunctionValue, isFunctionValue()) - -} -#endif +} // namespace WebCore +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSFunctionValue, isFunctionValue()) diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp index 151740fba..95b2047c0 100644 --- a/Source/WebCore/css/CSSGradientValue.cpp +++ b/Source/WebCore/css/CSSGradientValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,54 +27,49 @@ #include "CSSGradientValue.h" #include "CSSCalculationValue.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" +#include "FloatSize.h" #include "Gradient.h" #include "GradientImage.h" -#include "Image.h" -#include "IntSize.h" -#include "IntSizeHash.h" #include "NodeRenderStyle.h" +#include "Pair.h" #include "RenderElement.h" +#include "RenderView.h" #include "StyleResolver.h" #include -#include namespace WebCore { -PassRefPtr CSSGradientValue::image(RenderElement* renderer, const IntSize& size) +static inline Ref createGradient(CSSGradientValue& value, RenderElement& renderer, FloatSize size) { - if (size.isEmpty()) - return 0; + if (is(value)) + return downcast(value).createGradient(renderer, size); + return downcast(value).createGradient(renderer, size); +} +RefPtr CSSGradientValue::image(RenderElement& renderer, const FloatSize& size) +{ + if (size.isEmpty()) + return nullptr; bool cacheable = isCacheable(); if (cacheable) { - if (!clients().contains(renderer)) - return 0; - - Image* result = cachedImageForSize(size); - if (result) + if (!clients().contains(&renderer)) + return nullptr; + if (auto* result = cachedImageForSize(size)) return result; } - - RefPtr gradient; - - if (isLinearGradientValue()) - gradient = toCSSLinearGradientValue(this)->createGradient(renderer, size); - else - gradient = toCSSRadialGradientValue(this)->createGradient(renderer, size); - - RefPtr newImage = GradientImage::create(gradient, size); + auto newImage = GradientImage::create(createGradient(*this, renderer, size), size); if (cacheable) - saveCachedImageForSize(size, newImage); - - return newImage.release(); + saveCachedImageForSize(size, newImage.get()); + return WTFMove(newImage); } // Should only ever be called for deprecated gradients. static inline bool compareStops(const CSSGradientColorStop& a, const CSSGradientColorStop& b) { - double aVal = a.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); - double bVal = b.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); + double aVal = a.m_position->doubleValue(CSSPrimitiveValue::CSS_NUMBER); + double bVal = b.m_position->doubleValue(CSSPrimitiveValue::CSS_NUMBER); return aVal < bVal; } @@ -91,47 +86,55 @@ void CSSGradientValue::sortStopsIfNeeded() struct GradientStop { Color color; - float offset; - bool specified; - - GradientStop() - : offset(0) - , specified(false) - { } + float offset { 0 }; + bool specified { false }; + bool isMidpoint { false }; }; -PassRefPtr CSSGradientValue::gradientWithStylesResolved(StyleResolver* styleResolver) +static inline Ref clone(CSSGradientValue& value) { - bool derived = false; - for (unsigned i = 0; i < m_stops.size(); i++) - if (styleResolver->colorFromPrimitiveValueIsDerivedFromElement(m_stops[i].m_color.get())) { - m_stops[i].m_colorIsDerivedFromElement = true; - derived = true; + if (is(value)) + return downcast(value).clone(); + ASSERT(is(value)); + return downcast(value).clone(); +} + +Ref CSSGradientValue::gradientWithStylesResolved(const StyleResolver& styleResolver) +{ + bool colorIsDerivedFromElement = false; + for (auto& stop : m_stops) { + if (!stop.isMidpoint && styleResolver.colorFromPrimitiveValueIsDerivedFromElement(*stop.m_color)) { + stop.m_colorIsDerivedFromElement = true; + colorIsDerivedFromElement = true; break; } - - RefPtr result; - if (!derived) - result = this; - else if (isLinearGradientValue()) - result = toCSSLinearGradientValue(this)->clone(); - else if (isRadialGradientValue()) - result = toCSSRadialGradientValue(this)->clone(); - else { - ASSERT_NOT_REACHED(); - return 0; } + auto result = colorIsDerivedFromElement ? clone(*this) : makeRef(*this); + for (auto& stop : result->m_stops) { + if (!stop.isMidpoint) + stop.m_resolvedColor = styleResolver.colorFromPrimitiveValue(*stop.m_color); + } + return result; +} - for (unsigned i = 0; i < result->m_stops.size(); i++) - result->m_stops[i].m_resolvedColor = styleResolver->colorFromPrimitiveValue(result->m_stops[i].m_color.get()); - - return result.release(); +static inline int interpolate(int min, int max, float position) +{ + return min + static_cast(position * (max - min)); } -void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, const RenderStyle& rootStyle, float maxLengthForRepeat) +static inline Color interpolate(const Color& color1, const Color& color2, float position) { - RenderStyle& style = renderer->style(); + // FIXME: ExtendedColor - Doesn't work with extended colors, and really should be a helper in Color.h, not here. + int red = interpolate(color1.red(), color2.red(), position); + int green = interpolate(color1.green(), color2.green(), position); + int blue = interpolate(color1.blue(), color2.blue(), position); + int alpha = interpolate(color1.alpha(), color2.alpha(), position); + + return Color(red, green, blue, alpha); +} +void CSSGradientValue::addStops(Gradient& gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat) +{ if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) { sortStopsIfNeeded(); @@ -140,15 +143,15 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con float offset; if (stop.m_position->isPercentage()) - offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; + offset = stop.m_position->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; else - offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); + offset = stop.m_position->floatValue(CSSPrimitiveValue::CSS_NUMBER); - gradient->addColorStop(offset, stop.m_resolvedColor); + gradient.addColorStop(offset, stop.m_resolvedColor); } // The back end already sorted the stops. - gradient->setStopsSorted(true); + gradient.setStopsSorted(true); return; } @@ -159,31 +162,35 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con float gradientLength = 0; bool computedGradientLength = false; - FloatPoint gradientStart = gradient->p0(); + FloatPoint gradientStart = gradient.p0(); FloatPoint gradientEnd; if (isLinearGradientValue()) - gradientEnd = gradient->p1(); + gradientEnd = gradient.p1(); else if (isRadialGradientValue()) - gradientEnd = gradientStart + FloatSize(gradient->endRadius(), 0); + gradientEnd = gradientStart + FloatSize(gradient.endRadius(), 0); for (size_t i = 0; i < numStops; ++i) { const CSSGradientColorStop& stop = m_stops[i]; + stops[i].isMidpoint = stop.isMidpoint; stops[i].color = stop.m_resolvedColor; if (stop.m_position) { - if (stop.m_position->isPercentage()) - stops[i].offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; - else if (stop.m_position->isLength() || stop.m_position->isCalculatedPercentageWithLength()) { + const CSSPrimitiveValue& positionValue = *stop.m_position; + if (positionValue.isPercentage()) + stops[i].offset = positionValue.floatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; + else if (positionValue.isLength() || positionValue.isViewportPercentageLength() || positionValue.isCalculatedPercentageWithLength()) { if (!computedGradientLength) { FloatSize gradientSize(gradientStart - gradientEnd); gradientLength = gradientSize.diagonalLength(); } float length; - if (stop.m_position->isLength()) - length = stop.m_position->computeLength(&style, &rootStyle, style.effectiveZoom()); - else - length = stop.m_position->cssCalcValue()->toCalcValue(&style, &rootStyle, style.effectiveZoom())->evaluate(gradientLength); + if (positionValue.isLength()) + length = positionValue.computeLength(conversionData); + else { + Ref calculationValue { positionValue.cssCalcValue()->createCalculationValue(conversionData) }; + length = calculationValue->evaluate(gradientLength); + } stops[i].offset = (gradientLength > 0) ? length / gradientLength : 0; } else { ASSERT_NOT_REACHED(); @@ -247,6 +254,86 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con } } + // Walk over the color stops, look for midpoints and add stops as needed. + // If mid < 50%, add 2 stops to the left and 6 to the right + // else add 6 stops to the left and 2 to the right. + // Stops on the side with the most stops start midway because the curve approximates + // a line in that region. We then add 5 more color stops on that side to minimize the change + // how the luminance changes at each of the color stops. We don't have to add as many on the other side + // since it becomes small which increases the differentation of luminance which hides the color stops. + // Even with 4 extra color stops, it *is* possible to discern the steps when the gradient is large and has + // large luminance differences between midpoint and color stop. If this becomes an issue, we can consider + // making this algorithm a bit smarter. + + // Midpoints that coincide with color stops are treated specially since they don't require + // extra stops and generate hard lines. + for (size_t x = 1; x < stops.size() - 1;) { + if (!stops[x].isMidpoint) { + ++x; + continue; + } + + // Find previous and next color so we know what to interpolate between. + // We already know they have a color since we checked for that earlier. + Color color1 = stops[x - 1].color; + Color color2 = stops[x + 1].color; + // Likewise find the position of previous and next color stop. + float offset1 = stops[x - 1].offset; + float offset2 = stops[x + 1].offset; + float offset = stops[x].offset; + + // Check if everything coincides or the midpoint is exactly in the middle. + // If so, ignore the midpoint. + if (offset - offset1 == offset2 - offset) { + stops.remove(x); + continue; + } + + // Check if we coincide with the left color stop. + if (offset1 == offset) { + // Morph the midpoint to a regular stop with the color of the next color stop. + stops[x].color = color2; + stops[x].isMidpoint = false; + continue; + } + + // Check if we coincide with the right color stop. + if (offset2 == offset) { + // Morph the midpoint to a regular stop with the color of the previous color stop. + stops[x].color = color1; + stops[x].isMidpoint = false; + continue; + } + + float midpoint = (offset - offset1) / (offset2 - offset1); + GradientStop newStops[9]; + if (midpoint > .5f) { + for (size_t y = 0; y < 7; ++y) + newStops[y].offset = offset1 + (offset - offset1) * (7 + y) / 13; + + newStops[7].offset = offset + (offset2 - offset) / 3; + newStops[8].offset = offset + (offset2 - offset) * 2 / 3; + } else { + newStops[0].offset = offset1 + (offset - offset1) / 3; + newStops[1].offset = offset1 + (offset - offset1) * 2 / 3; + + for (size_t y = 0; y < 7; ++y) + newStops[y + 2].offset = offset + (offset2 - offset) * y / 13; + } + // calculate colors + for (size_t y = 0; y < 9; ++y) { + float relativeOffset = (newStops[y].offset - offset1) / (offset2 - offset1); + float multiplier = powf(relativeOffset, logf(.5f) / logf(midpoint)); + newStops[y].color = interpolate(color1, color2, multiplier); + } + + stops.remove(x); + stops.insert(x, newStops, 9); + x += 9; + } + + numStops = stops.size(); + // If the gradient is repeating, repeat the color stops. // We can't just push this logic down into the platform-specific Gradient code, // because we have to know the extent of the gradient, and possible move the end points. @@ -271,7 +358,7 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con } if (maxLengthForRepeat > gradientLength) - maxExtent = maxLengthForRepeat / gradientLength; + maxExtent = gradientLength > 0 ? maxLengthForRepeat / gradientLength : 0; } size_t originalNumStops = numStops; @@ -331,10 +418,10 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con for (size_t i = 0; i < numStops; ++i) stops[i].offset = (stops[i].offset - firstOffset) / scale; - FloatPoint p0 = gradient->p0(); - FloatPoint p1 = gradient->p1(); - gradient->setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()))); - gradient->setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()))); + FloatPoint p0 = gradient.p0(); + FloatPoint p1 = gradient.p1(); + gradient.setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()))); + gradient.setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()))); } else { // There's a single position that is outside the scale, clamp the positions to 1. for (size_t i = 0; i < numStops; ++i) @@ -379,32 +466,48 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con for (size_t i = 0; i < numStops; ++i) stops[i].offset /= scale; - gradient->setStartRadius(gradient->startRadius() * scale); - gradient->setEndRadius(gradient->endRadius() * scale); + gradient.setStartRadius(gradient.startRadius() * scale); + gradient.setEndRadius(gradient.endRadius() * scale); } } for (unsigned i = 0; i < numStops; i++) - gradient->addColorStop(stops[i].offset, stops[i].color); + gradient.addColorStop(stops[i].offset, stops[i].color); - gradient->setStopsSorted(true); + gradient.setStopsSorted(true); } -static float positionFromValue(CSSPrimitiveValue* value, const RenderStyle& style, const RenderStyle& rootStyle, const IntSize& size, bool isHorizontal) +static float positionFromValue(const CSSPrimitiveValue* value, const CSSToLengthConversionData& conversionData, const FloatSize& size, bool isHorizontal) { - float zoomFactor = style.effectiveZoom(); - - if (value->isNumber()) - return value->getFloatValue() * zoomFactor; - + int origin = 0; + int sign = 1; int edgeDistance = isHorizontal ? size.width() : size.height(); + + // In this case the center of the gradient is given relative to an edge in the + // form of: [ top | bottom | right | left ] [ | ]. + if (value->isPair()) { + CSSValueID originID = value->pairValue()->first()->valueID(); + value = value->pairValue()->second(); + + if (originID == CSSValueRight || originID == CSSValueBottom) { + // For right/bottom, the offset is relative to the far edge. + origin = edgeDistance; + sign = -1; + } + } + + if (value->isNumber()) + return origin + sign * value->floatValue() * conversionData.zoom(); + if (value->isPercentage()) - return value->getFloatValue() / 100.f * edgeDistance; - - if (value->isCalculatedPercentageWithLength()) - return value->cssCalcValue()->toCalcValue(&style, &rootStyle, style.effectiveZoom())->evaluate(edgeDistance); + return origin + sign * value->floatValue() / 100.f * edgeDistance; - switch (value->getValueID()) { + if (value->isCalculatedPercentageWithLength()) { + Ref calculationValue { value->cssCalcValue()->createCalculationValue(conversionData) }; + return origin + sign * calculationValue->evaluate(edgeDistance); + } + + switch (value->valueID()) { case CSSValueTop: ASSERT(!isHorizontal); return 0; @@ -417,22 +520,24 @@ static float positionFromValue(CSSPrimitiveValue* value, const RenderStyle& styl case CSSValueRight: ASSERT(isHorizontal); return size.width(); + case CSSValueCenter: + return origin + sign * .5f * edgeDistance; default: break; } - return value->computeLength(&style, &rootStyle, zoomFactor); + return origin + sign * value->computeLength(conversionData); } -FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* horizontal, CSSPrimitiveValue* vertical, const RenderStyle& style, const RenderStyle& rootStyle, const IntSize& size) +FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* horizontal, CSSPrimitiveValue* vertical, const CSSToLengthConversionData& conversionData, const FloatSize& size) { FloatPoint result; if (horizontal) - result.setX(positionFromValue(horizontal, style, rootStyle, size, true)); + result.setX(positionFromValue(horizontal, conversionData, size, true)); if (vertical) - result.setY(positionFromValue(vertical, style, rootStyle, size, false)); + result.setY(positionFromValue(vertical, conversionData, size, false)); return result; } @@ -455,10 +560,10 @@ bool CSSGradientValue::isCacheable() const return true; } -bool CSSGradientValue::knownToBeOpaque(const RenderElement*) const +bool CSSGradientValue::knownToBeOpaque() const { - for (size_t i = 0; i < m_stops.size(); ++i) { - if (m_stops[i].m_resolvedColor.hasAlpha()) + for (auto& stop : m_stops) { + if (!stop.m_resolvedColor.isOpaque()) return false; } return true; @@ -477,20 +582,20 @@ String CSSLinearGradientValue::customCSSText() const result.append(' '); result.append(m_secondY->cssText()); - for (unsigned i = 0; i < m_stops.size(); i++) { - const CSSGradientColorStop& stop = m_stops[i]; + for (auto& stop : m_stops) { result.appendLiteral(", "); - if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) { + auto position = stop.m_position->doubleValue(CSSPrimitiveValue::CSS_NUMBER); + if (!position) { result.appendLiteral("from("); result.append(stop.m_color->cssText()); result.append(')'); - } else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) { + } else if (position == 1) { result.appendLiteral("to("); result.append(stop.m_color->cssText()); result.append(')'); } else { result.appendLiteral("color-stop("); - result.appendNumber(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)); + result.appendNumber(position); result.appendLiteral(", "); result.append(stop.m_color->cssText()); result.append(')'); @@ -538,7 +643,7 @@ String CSSLinearGradientValue::customCSSText() const if (m_angle && m_angle->computeDegrees() != 180) { result.append(m_angle->cssText()); wroteSomething = true; - } else if ((m_firstX || m_firstY) && !(!m_firstX && m_firstY && m_firstY->getValueID() == CSSValueBottom)) { + } else if ((m_firstX || m_firstY) && !(!m_firstX && m_firstY && m_firstY->valueID() == CSSValueBottom)) { result.appendLiteral("to "); if (m_firstX && m_firstY) { result.append(m_firstX->cssText()); @@ -558,9 +663,11 @@ String CSSLinearGradientValue::customCSSText() const const CSSGradientColorStop& stop = m_stops[i]; if (i) result.appendLiteral(", "); - result.append(stop.m_color->cssText()); + if (!stop.isMidpoint) + result.append(stop.m_color->cssText()); if (stop.m_position) { - result.append(' '); + if (!stop.isMidpoint) + result.append(' '); result.append(stop.m_position->cssText()); } } @@ -572,7 +679,7 @@ String CSSLinearGradientValue::customCSSText() const } // Compute the endpoints so that a gradient of the given angle covers a box of the given size. -static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint, CSSGradientType type) +static void endPointsFromAngle(float angleDeg, const FloatSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint, CSSGradientType type) { // Prefixed gradients use "polar coordinate" angles, rather than "bearing" angles. if (type == CSSPrefixedLinearGradient) @@ -639,23 +746,23 @@ static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint.set(halfWidth - endX, halfHeight + endY); } -PassRefPtr CSSLinearGradientValue::createGradient(RenderElement* renderer, const IntSize& size) +Ref CSSLinearGradientValue::createGradient(RenderElement& renderer, const FloatSize& size) { ASSERT(!size.isEmpty()); - RenderStyle& rootStyle = *renderer->document().documentElement()->renderStyle(); + CSSToLengthConversionData conversionData(&renderer.style(), renderer.document().documentElement()->renderStyle(), &renderer.view()); FloatPoint firstPoint; FloatPoint secondPoint; if (m_angle) { - float angle = m_angle->getFloatValue(CSSPrimitiveValue::CSS_DEG); + float angle = m_angle->floatValue(CSSPrimitiveValue::CSS_DEG); endPointsFromAngle(angle, size, firstPoint, secondPoint, m_gradientType); } else { switch (m_gradientType) { case CSSDeprecatedLinearGradient: - firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_secondX || m_secondY) - secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), conversionData, size); else { if (m_firstX) secondPoint.setX(size.width() - firstPoint.x()); @@ -664,7 +771,7 @@ PassRefPtr CSSLinearGradientValue::createGradient(RenderElement* rende } break; case CSSPrefixedLinearGradient: - firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_firstX) secondPoint.setX(size.width() - firstPoint.x()); if (m_firstY) @@ -675,15 +782,15 @@ PassRefPtr CSSLinearGradientValue::createGradient(RenderElement* rende // "Magic" corners, so the 50% line touches two corners. float rise = size.width(); float run = size.height(); - if (m_firstX && m_firstX->getValueID() == CSSValueLeft) + if (m_firstX && m_firstX->valueID() == CSSValueLeft) run *= -1; - if (m_firstY && m_firstY->getValueID() == CSSValueBottom) + if (m_firstY && m_firstY->valueID() == CSSValueBottom) rise *= -1; // Compute angle, and flip it back to "bearing angle" degrees. float angle = 90 - rad2deg(atan2(rise, run)); endPointsFromAngle(angle, size, firstPoint, secondPoint, m_gradientType); } else if (m_firstX || m_firstY) { - secondPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + secondPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_firstX) firstPoint.setX(size.width() - secondPoint.x()); if (m_firstY) @@ -697,12 +804,12 @@ PassRefPtr CSSLinearGradientValue::createGradient(RenderElement* rende } - RefPtr gradient = Gradient::create(firstPoint, secondPoint); + Ref gradient = Gradient::create(firstPoint, secondPoint); // Now add the stops. - addStops(gradient.get(), renderer, rootStyle, 1); + addStops(gradient, conversionData, 1); - return gradient.release(); + return gradient; } bool CSSLinearGradientValue::equals(const CSSLinearGradientValue& other) const @@ -756,20 +863,20 @@ String CSSRadialGradientValue::customCSSText() const result.append(m_secondRadius->cssText()); // FIXME: share? - for (unsigned i = 0; i < m_stops.size(); i++) { - const CSSGradientColorStop& stop = m_stops[i]; + for (auto& stop : m_stops) { result.appendLiteral(", "); - if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) { + auto position = stop.m_position->doubleValue(CSSPrimitiveValue::CSS_NUMBER); + if (!position) { result.appendLiteral("from("); result.append(stop.m_color->cssText()); result.append(')'); - } else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) { + } else if (position == 1) { result.appendLiteral("to("); result.append(stop.m_color->cssText()); result.append(')'); } else { result.appendLiteral("color-stop("); - result.appendNumber(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)); + result.appendNumber(position); result.appendLiteral(", "); result.append(stop.m_color->cssText()); result.append(')'); @@ -831,12 +938,12 @@ String CSSRadialGradientValue::customCSSText() const // The only ambiguous case that needs an explicit shape to be provided // is when a sizing keyword is used (or all sizing is omitted). - if (m_shape && m_shape->getValueID() != CSSValueEllipse && (m_sizingBehavior || (!m_sizingBehavior && !m_endHorizontalSize))) { + if (m_shape && m_shape->valueID() != CSSValueEllipse && (m_sizingBehavior || (!m_sizingBehavior && !m_endHorizontalSize))) { result.appendLiteral("circle"); wroteSomething = true; } - if (m_sizingBehavior && m_sizingBehavior->getValueID() != CSSValueFarthestCorner) { + if (m_sizingBehavior && m_sizingBehavior->valueID() != CSSValueFarthestCorner) { if (wroteSomething) result.append(' '); result.append(m_sizingBehavior->cssText()); @@ -874,9 +981,11 @@ String CSSRadialGradientValue::customCSSText() const const CSSGradientColorStop& stop = m_stops[i]; if (i) result.appendLiteral(", "); - result.append(stop.m_color->cssText()); + if (!stop.isMidpoint) + result.append(stop.m_color->cssText()); if (stop.m_position) { - result.append(' '); + if (!stop.isMidpoint) + result.append(' '); result.append(stop.m_position->cssText()); } } @@ -887,17 +996,15 @@ String CSSRadialGradientValue::customCSSText() const return result.toString(); } -float CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue* radius, const RenderStyle& style, const RenderStyle& rootStyle, float* widthOrHeight) +float CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue& radius, const CSSToLengthConversionData& conversionData, float* widthOrHeight) { - float zoomFactor = style.effectiveZoom(); - float result = 0; - if (radius->isNumber()) // Can the radius be a percentage? - result = radius->getFloatValue() * zoomFactor; - else if (widthOrHeight && radius->isPercentage()) - result = *widthOrHeight * radius->getFloatValue() / 100; + if (radius.isNumber()) // Can the radius be a percentage? + result = radius.floatValue() * conversionData.zoom(); + else if (widthOrHeight && radius.isPercentage()) + result = *widthOrHeight * radius.floatValue() / 100; else - result = radius->computeLength(&style, &rootStyle, zoomFactor); + result = radius.computeLength(conversionData); return result; } @@ -979,19 +1086,19 @@ static inline float horizontalEllipseRadius(const FloatSize& p, float aspectRati } // FIXME: share code with the linear version -PassRefPtr CSSRadialGradientValue::createGradient(RenderElement* renderer, const IntSize& size) +Ref CSSRadialGradientValue::createGradient(RenderElement& renderer, const FloatSize& size) { ASSERT(!size.isEmpty()); - RenderStyle& rootStyle = *renderer->document().documentElement()->renderStyle(); + CSSToLengthConversionData conversionData(&renderer.style(), renderer.document().documentElement()->renderStyle(), &renderer.view()); - FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (!m_firstX) firstPoint.setX(size.width() / 2); if (!m_firstY) firstPoint.setY(size.height() / 2); - FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), conversionData, size); if (!m_secondX) secondPoint.setX(size.width() / 2); if (!m_secondY) @@ -999,31 +1106,31 @@ PassRefPtr CSSRadialGradientValue::createGradient(RenderElement* rende float firstRadius = 0; if (m_firstRadius) - firstRadius = resolveRadius(m_firstRadius.get(), renderer->style(), rootStyle); + firstRadius = resolveRadius(*m_firstRadius, conversionData); float secondRadius = 0; float aspectRatio = 1; // width / height. if (m_secondRadius) - secondRadius = resolveRadius(m_secondRadius.get(), renderer->style(), rootStyle); + secondRadius = resolveRadius(*m_secondRadius, conversionData); else if (m_endHorizontalSize) { float width = size.width(); float height = size.height(); - secondRadius = resolveRadius(m_endHorizontalSize.get(), renderer->style(), rootStyle, &width); + secondRadius = resolveRadius(*m_endHorizontalSize, conversionData, &width); if (m_endVerticalSize) - aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height); + aspectRatio = secondRadius / resolveRadius(*m_endVerticalSize, conversionData, &height); else aspectRatio = 1; } else { enum GradientShape { Circle, Ellipse }; GradientShape shape = Ellipse; - if ((m_shape && m_shape->getValueID() == CSSValueCircle) + if ((m_shape && m_shape->valueID() == CSSValueCircle) || (!m_shape && !m_sizingBehavior && m_endHorizontalSize && !m_endVerticalSize)) shape = Circle; enum GradientFill { ClosestSide, ClosestCorner, FarthestSide, FarthestCorner }; GradientFill fill = FarthestCorner; - switch (m_sizingBehavior ? m_sizingBehavior->getValueID() : 0) { + switch (m_sizingBehavior ? m_sizingBehavior->valueID() : 0) { case CSSValueContain: case CSSValueClosestSide: fill = ClosestSide; @@ -1106,7 +1213,7 @@ PassRefPtr CSSRadialGradientValue::createGradient(RenderElement* rende } } - RefPtr gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); + Ref gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); // addStops() only uses maxExtent for repeating gradients. float maxExtent = 0; @@ -1116,9 +1223,9 @@ PassRefPtr CSSRadialGradientValue::createGradient(RenderElement* rende } // Now add the stops. - addStops(gradient.get(), renderer, rootStyle, maxExtent); + addStops(gradient, conversionData, maxExtent); - return gradient.release(); + return gradient; } bool CSSRadialGradientValue::equals(const CSSRadialGradientValue& other) const diff --git a/Source/WebCore/css/CSSGradientValue.h b/Source/WebCore/css/CSSGradientValue.h index 24bfe9001..a8e66c4d7 100644 --- a/Source/WebCore/css/CSSGradientValue.h +++ b/Source/WebCore/css/CSSGradientValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,18 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSGradientValue_h -#define CSSGradientValue_h +#pragma once #include "CSSImageGeneratorValue.h" #include "CSSPrimitiveValue.h" -#include #include namespace WebCore { class FloatPoint; class Gradient; +class StyleResolver; enum CSSGradientType { CSSDeprecatedLinearGradient, @@ -47,11 +46,11 @@ enum CSSGradientType { enum CSSGradientRepeat { NonRepeating, Repeating }; struct CSSGradientColorStop { - CSSGradientColorStop() : m_colorIsDerivedFromElement(false) { }; RefPtr m_position; // percentage or length RefPtr m_color; Color m_resolvedColor; - bool m_colorIsDerivedFromElement; + bool m_colorIsDerivedFromElement = false; + bool isMidpoint = false; bool operator==(const CSSGradientColorStop& other) const { return compareCSSValuePtr(m_color, other.m_color) @@ -61,12 +60,12 @@ struct CSSGradientColorStop { class CSSGradientValue : public CSSImageGeneratorValue { public: - PassRefPtr image(RenderElement*, const IntSize&); + RefPtr image(RenderElement&, const FloatSize&); - void setFirstX(PassRefPtr val) { m_firstX = val; } - void setFirstY(PassRefPtr val) { m_firstY = val; } - void setSecondX(PassRefPtr val) { m_secondX = val; } - void setSecondY(PassRefPtr val) { m_secondY = val; } + void setFirstX(RefPtr&& val) { m_firstX = WTFMove(val); } + void setFirstY(RefPtr&& val) { m_firstY = WTFMove(val); } + void setSecondX(RefPtr&& val) { m_secondX = WTFMove(val); } + void setSecondY(RefPtr&& val) { m_secondY = WTFMove(val); } void addStop(const CSSGradientColorStop& stop) { m_stops.append(stop); } @@ -79,13 +78,13 @@ public: CSSGradientType gradientType() const { return m_gradientType; } bool isFixedSize() const { return false; } - IntSize fixedSize(const RenderElement*) const { return IntSize(); } + FloatSize fixedSize(const RenderElement&) const { return FloatSize(); } bool isPending() const { return false; } - bool knownToBeOpaque(const RenderElement*) const; + bool knownToBeOpaque() const; - void loadSubimages(CachedResourceLoader*) { } - PassRefPtr gradientWithStylesResolved(StyleResolver*); + void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&) { } + Ref gradientWithStylesResolved(const StyleResolver&); protected: CSSGradientValue(ClassType classType, CSSGradientRepeat repeat, CSSGradientType gradientType) @@ -109,10 +108,10 @@ protected: { } - void addStops(Gradient*, RenderElement*, const RenderStyle& rootStyle, float maxLengthForRepeat = 0); + void addStops(Gradient&, const CSSToLengthConversionData&, float maxLengthForRepeat = 0); // Resolve points/radii to front end values. - FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, const RenderStyle&, const RenderStyle& rootStyle, const IntSize&); + FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, const CSSToLengthConversionData&, const FloatSize&); bool isCacheable() const; @@ -130,24 +129,21 @@ protected: bool m_repeating; }; -CSS_VALUE_TYPE_CASTS(CSSGradientValue, isGradientValue()) - -class CSSLinearGradientValue : public CSSGradientValue { +class CSSLinearGradientValue final : public CSSGradientValue { public: - - static PassRef create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSLinearGradient) + static Ref create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSLinearGradient) { return adoptRef(*new CSSLinearGradientValue(repeat, gradientType)); } - void setAngle(PassRefPtr val) { m_angle = val; } + void setAngle(Ref&& val) { m_angle = WTFMove(val); } String customCSSText() const; // Create the gradient for a given size. - PassRefPtr createGradient(RenderElement*, const IntSize&); + Ref createGradient(RenderElement&, const FloatSize&); - PassRef clone() const + Ref clone() const { return adoptRef(*new CSSLinearGradientValue(*this)); } @@ -169,33 +165,31 @@ private: RefPtr m_angle; // may be null. }; -CSS_VALUE_TYPE_CASTS(CSSLinearGradientValue, isLinearGradientValue()) - -class CSSRadialGradientValue : public CSSGradientValue { +class CSSRadialGradientValue final : public CSSGradientValue { public: - static PassRef create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSRadialGradient) + static Ref create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSRadialGradient) { return adoptRef(*new CSSRadialGradientValue(repeat, gradientType)); } - PassRef clone() const + Ref clone() const { return adoptRef(*new CSSRadialGradientValue(*this)); } String customCSSText() const; - void setFirstRadius(PassRefPtr val) { m_firstRadius = val; } - void setSecondRadius(PassRefPtr val) { m_secondRadius = val; } + void setFirstRadius(RefPtr&& val) { m_firstRadius = WTFMove(val); } + void setSecondRadius(RefPtr&& val) { m_secondRadius = WTFMove(val); } - void setShape(PassRefPtr val) { m_shape = val; } - void setSizingBehavior(PassRefPtr val) { m_sizingBehavior = val; } + void setShape(RefPtr&& val) { m_shape = WTFMove(val); } + void setSizingBehavior(RefPtr&& val) { m_sizingBehavior = WTFMove(val); } - void setEndHorizontalSize(PassRefPtr val) { m_endHorizontalSize = val; } - void setEndVerticalSize(PassRefPtr val) { m_endVerticalSize = val; } + void setEndHorizontalSize(RefPtr&& val) { m_endHorizontalSize = WTFMove(val); } + void setEndVerticalSize(RefPtr&& val) { m_endVerticalSize = WTFMove(val); } // Create the gradient for a given size. - PassRefPtr createGradient(RenderElement*, const IntSize&); + Ref createGradient(RenderElement&, const FloatSize&); bool equals(const CSSRadialGradientValue&) const; @@ -216,9 +210,8 @@ private: { } - // Resolve points/radii to front end values. - float resolveRadius(CSSPrimitiveValue*, const RenderStyle&, const RenderStyle& rootStyle, float* widthOrHeight = 0); + float resolveRadius(CSSPrimitiveValue&, const CSSToLengthConversionData&, float* widthOrHeight = 0); // These may be null for non-deprecated gradients. RefPtr m_firstRadius; @@ -232,8 +225,8 @@ private: RefPtr m_endVerticalSize; }; -CSS_VALUE_TYPE_CASTS(CSSRadialGradientValue, isRadialGradientValue()) - } // namespace WebCore -#endif // CSSGradientValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSGradientValue, isGradientValue()) +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSLinearGradientValue, isLinearGradientValue()) +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSRadialGradientValue, isRadialGradientValue()) diff --git a/Source/WebCore/css/CSSGrammar.y.in b/Source/WebCore/css/CSSGrammar.y.in deleted file mode 100644 index eb11be3a8..000000000 --- a/Source/WebCore/css/CSSGrammar.y.in +++ /dev/null @@ -1,1688 +0,0 @@ -/* - * Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) - * Copyright (C) 2008 Eric Seidel - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -%pure_parser - -%parse-param { CSSParser* parser } -%lex-param { CSSParser* parser } - -%union { - double number; - CSSParserString string; - CSSSelector::MarginBoxType marginBox; - CSSParserValue value; -} - -%{ - -static inline int cssyyerror(void*, const char*) -{ - return 1; -} - -#if YYDEBUG > 0 - -static inline bool isCSSTokenAString(int yytype) -{ - switch (yytype) { - case IDENT: - case STRING: - case NTH: - case HEX: - case IDSEL: - case DIMEN: - case INVALIDDIMEN: - case URI: - case FUNCTION: - case ANYFUNCTION: - case NOTFUNCTION: - case CALCFUNCTION: - case MINFUNCTION: - case MAXFUNCTION: - case UNICODERANGE: - return true; - default: - return false; - } -} - -#endif - -%} - -#if ENABLE_SHADOW_DOM -%expect 30 -#else -%expect 29 -#endif - -%nonassoc LOWEST_PREC - -%left UNIMPORTANT_TOK - -%token WHITESPACE SGML_CD -%token TOKEN_EOF 0 - -%token INCLUDES -%token DASHMATCH -%token BEGINSWITH -%token ENDSWITH -%token CONTAINS - -%token STRING -%right IDENT -%token NTH - -%nonassoc HEX -%nonassoc IDSEL -%nonassoc ':' -%nonassoc '.' -%nonassoc '[' -%nonassoc '*' -%nonassoc error -%left '|' - -%token IMPORT_SYM -%token PAGE_SYM -%token MEDIA_SYM -%token FONT_FACE_SYM -%token CHARSET_SYM -%token NAMESPACE_SYM -%token WEBKIT_RULE_SYM -%token WEBKIT_DECLS_SYM -%token WEBKIT_KEYFRAME_RULE_SYM -%token WEBKIT_KEYFRAMES_SYM -%token WEBKIT_VALUE_SYM -%token WEBKIT_MEDIAQUERY_SYM -%token WEBKIT_SELECTOR_SYM -%token WEBKIT_REGION_RULE_SYM -%token WEBKIT_VIEWPORT_RULE_SYM -%token TOPLEFTCORNER_SYM -%token TOPLEFT_SYM -%token TOPCENTER_SYM -%token TOPRIGHT_SYM -%token TOPRIGHTCORNER_SYM -%token BOTTOMLEFTCORNER_SYM -%token BOTTOMLEFT_SYM -%token BOTTOMCENTER_SYM -%token BOTTOMRIGHT_SYM -%token BOTTOMRIGHTCORNER_SYM -%token LEFTTOP_SYM -%token LEFTMIDDLE_SYM -%token LEFTBOTTOM_SYM -%token RIGHTTOP_SYM -%token RIGHTMIDDLE_SYM -%token RIGHTBOTTOM_SYM - -%token ATKEYWORD - -%token IMPORTANT_SYM -%token MEDIA_ONLY -%token MEDIA_NOT -%token MEDIA_AND - -%token REMS -%token CHS -%token QEMS -%token EMS -%token EXS -%token PXS -%token CMS -%token MMS -%token INS -%token PTS -%token PCS -%token DEGS -%token RADS -%token GRADS -%token TURNS -%token MSECS -%token SECS -%token HERTZ -%token KHERTZ -%token DIMEN -%token INVALIDDIMEN -%token PERCENTAGE -%token FLOATTOKEN -%token INTEGER -%token VW -%token VH -%token VMIN -%token VMAX -%token DPPX -%token DPI -%token DPCM -%token FR - -%token URI -%token FUNCTION -%token ANYFUNCTION -%token NOTFUNCTION -%token CALCFUNCTION -%token MINFUNCTION -%token MAXFUNCTION - -%token UNICODERANGE - -%union { CSSSelector::Relation relation; } -%type combinator - -%union { StyleRuleBase* rule; } -%type block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule -%destructor { if ($$) $$->deref(); } block_rule block_valid_rule font_face import keyframes media page region rule ruleset valid_rule - -%union { Vector>* ruleList; } -%type block_rule_list block_valid_rule_list -%destructor { delete $$; } block_rule_list block_valid_rule_list - -%type ident_or_string maybe_ns_prefix namespace_selector string_or_uri - -%type margin_sym - -%union { MediaQuerySet* mediaList; } -%type media_list maybe_media_list -%destructor { if ($$) $$->deref(); } media_list maybe_media_list - -%union { MediaQuery* mediaQuery; } -%type media_query -%destructor { delete $$; } media_query - -%union { MediaQuery::Restrictor mediaQueryRestrictor; } -%type maybe_media_restrictor - -%union { MediaQueryExp* mediaQueryExp; } -%type media_query_exp -%destructor { delete $$; } media_query_exp - -%union { Vector>* mediaQueryExpList; } -%type media_query_exp_list maybe_and_media_query_exp_list -%destructor { delete $$; } media_query_exp_list maybe_and_media_query_exp_list - -%type keyframe_name - -%union { StyleKeyframe* keyframe; } -%type keyframe_rule -%destructor { if ($$) $$->deref(); } keyframe_rule - -%union { Vector>* keyframeRuleList; } -%type keyframes_rule -%destructor { delete $$; } keyframes_rule - -// These two parser values never need to be destroyed because they are never functions. -%type key unary_term - -// These parser values need to be destroyed because they might be functions. -%type calc_func_term calc_function function min_or_max_function term -%destructor { destroy($$); } calc_func_term calc_function function min_or_max_function term - -%union { CSSPropertyID id; } -%type property - -%union { CSSParserSelector* selector; } -%type attrib class page_selector pseudo pseudo_page selector selector_with_trailing_whitespace simple_selector specifier specifier_list -%destructor { delete $$; } attrib class page_selector pseudo pseudo_page selector selector_with_trailing_whitespace simple_selector specifier specifier_list - -%union { Vector>* selectorList; } -%type selector_list simple_selector_list -%destructor { delete $$; } selector_list simple_selector_list - -%union { bool boolean; } -%type declaration declaration_list decl_list priority - -%union { CSSSelector::Match match; } -%type match - -%union { int integer; } -%type unary_operator maybe_unary_operator - -%union { char character; } -%type operator calc_func_operator - -%union { CSSParserValueList* valueList; } -%type calc_func_expr calc_func_expr_list calc_func_paren_expr expr key_list maybe_media_value valid_calc_func_expr valid_expr -%destructor { delete $$; } calc_func_expr calc_func_expr_list calc_func_paren_expr expr key_list maybe_media_value valid_calc_func_expr valid_expr - -%type min_or_max - -%type element_name - -%union { CSSParser::Location location; } -%type error_location - -#if ENABLE_CSS3_CONDITIONAL_RULES - -%token SUPPORTS_AND -%token SUPPORTS_NOT -%token SUPPORTS_OR -%token SUPPORTS_SYM -%token WEBKIT_SUPPORTS_CONDITION_SYM - -%type supports -%destructor { if ($$) $$->deref(); } supports - -%type supports_condition supports_condition_in_parens supports_conjunction supports_declaration_condition supports_disjunction supports_error supports_negation - -#endif - -#if ENABLE_CSS_DEVICE_ADAPTATION - -%type viewport -%destructor { if ($$) $$->deref(); } viewport - -#endif - -#if ENABLE_SHADOW_DOM - -%token HOST_SYM - -%type host -%destructor { if ($$) $$->deref(); } host - -#endif - -#if ENABLE_VIDEO_TRACK - -%token CUEFUNCTION - -#endif - -%% - -stylesheet: - maybe_space maybe_charset maybe_sgml rule_list - | webkit_rule maybe_space - | webkit_decls maybe_space - | webkit_value maybe_space - | webkit_mediaquery maybe_space - | webkit_selector maybe_space - | webkit_keyframe_rule maybe_space -#if ENABLE_CSS3_CONDITIONAL_RULES - | webkit_supports_condition maybe_space -#endif - ; - -webkit_rule: WEBKIT_RULE_SYM '{' maybe_space valid_rule maybe_space '}' { parser->m_rule = adoptRef($4); } ; - -webkit_keyframe_rule: WEBKIT_KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' { parser->m_keyframe = adoptRef($4); } ; - -webkit_decls: WEBKIT_DECLS_SYM '{' maybe_space_before_declaration declaration_list '}' ; - -webkit_value: - WEBKIT_VALUE_SYM '{' maybe_space expr '}' { - if ($4) { - parser->m_valueList = adoptPtr($4); - int oldParsedProperties = parser->m_parsedProperties.size(); - if (!parser->parseValue(parser->m_id, parser->m_important)) - parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties); - parser->m_valueList = nullptr; - } - } -; - -webkit_mediaquery: WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' { parser->m_mediaQuery = adoptPtr($4); } ; - -webkit_selector: - WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' { - if ($4) { - if (parser->m_selectorListForParseSelector) - parser->m_selectorListForParseSelector->adoptSelectorVector(*$4); - parser->recycleSelectorVector(adoptPtr($4)); - } - } -; - -#if ENABLE_CSS3_CONDITIONAL_RULES - -webkit_supports_condition: WEBKIT_SUPPORTS_CONDITION_SYM '{' maybe_space supports_condition '}' { parser->m_supportsCondition = $4; } ; - -#endif - -/* for expressions that require at least one whitespace to be present, like the + and - operators in calc expressions */ -space: WHITESPACE | space WHITESPACE ; - -maybe_space: /* empty */ %prec UNIMPORTANT_TOK | maybe_space WHITESPACE ; - -maybe_sgml: /* empty */ | maybe_sgml SGML_CD | maybe_sgml WHITESPACE ; - -maybe_charset: /* empty */ | charset ; - -closing_brace: '}' | %prec LOWEST_PREC TOKEN_EOF ; - -closing_parenthesis: ')' | %prec LOWEST_PREC TOKEN_EOF ; - -charset: - CHARSET_SYM maybe_space STRING maybe_space ';' { - if (parser->m_styleSheet) - parser->m_styleSheet->parserSetEncodingFromCharsetRule($3); - if (parser->isExtractingSourceData() && parser->m_currentRuleDataStack->isEmpty() && parser->m_ruleSourceDataResult) - parser->addNewRuleToSourceTree(CSSRuleSourceData::createUnknown()); - } - | CHARSET_SYM error invalid_block - | CHARSET_SYM error ';' -; - -// Ignore any @charset rule not at the beginning of the style sheet. -ignored_charset: CHARSET_SYM maybe_space STRING maybe_space ';' | CHARSET_SYM maybe_space ';' ; - -rule_list: - /* empty */ - | rule_list rule maybe_sgml { - if (RefPtr rule = adoptRef($2)) { - if (parser->m_styleSheet) - parser->m_styleSheet->parserAppendRule(rule.releaseNonNull()); - } - } - ; - -valid_rule: - ruleset - | media - | page - | font_face - | keyframes - | namespace { $$ = nullptr; } - | import - | region -#if ENABLE_CSS3_CONDITIONAL_RULES - | supports -#endif -#if ENABLE_SHADOW_DOM - | host -#endif -#if ENABLE_CSS_DEVICE_ADAPTATION - | viewport -#endif - ; - -rule: - valid_rule { - $$ = $1; - parser->m_hadSyntacticallyValidCSSRule = true; - } - | ignored_charset { $$ = nullptr; } - | invalid_rule { $$ = nullptr; } - | invalid_at { $$ = nullptr; } - ; - -block_rule_list: - /* empty */ { $$ = nullptr; } - | block_rule_list block_rule maybe_sgml { - $$ = $1; - if (RefPtr rule = adoptRef($2)) { - if (!$$) - $$ = new Vector>; - $$->append(rule.release()); - } - } - ; - -block_valid_rule_list: - /* empty */ { $$ = nullptr; } - | block_valid_rule_list block_valid_rule maybe_sgml { - $$ = $1; - if (RefPtr rule = adoptRef($2)) { - if (!$$) - $$ = new Vector>; - $$->append(rule.release()); - } - } - ; - -block_valid_rule: - ruleset - | page - | font_face - | media - | keyframes -#if ENABLE_CSS3_CONDITIONAL_RULES - | supports -#endif -#if ENABLE_CSS_DEVICE_ADAPTATION - | viewport -#endif - ; - -block_rule: block_valid_rule | invalid_rule { $$ = nullptr; } | invalid_at { $$ = nullptr; } | namespace { $$ = nullptr; } | import | region ; - -at_import_header_end_maybe_space: - maybe_space { - parser->markRuleHeaderEnd(); - parser->markRuleBodyStart(); - } - ; - -before_import_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::IMPORT_RULE); - } - ; - -import: - before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list ';' { - $$ = parser->createImportRule($4, adoptRef($6)).leakRef(); - } - | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list TOKEN_EOF { - $$ = parser->createImportRule($4, adoptRef($6)).leakRef(); - } - | before_import_rule IMPORT_SYM at_import_header_end_maybe_space string_or_uri maybe_space maybe_media_list invalid_block { - $$ = nullptr; - parser->popRuleData(); - if ($6) - $6->deref(); - } - | before_import_rule IMPORT_SYM error ';' { - $$ = nullptr; - parser->popRuleData(); - } - | before_import_rule IMPORT_SYM error invalid_block { - $$ = nullptr; - parser->popRuleData(); - } - ; - -namespace: - NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' { parser->addNamespace($3, $4); } - | NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space invalid_block - | NAMESPACE_SYM error invalid_block - | NAMESPACE_SYM error ';' - ; - -maybe_ns_prefix: /* empty */ { $$.clear(); } | IDENT maybe_space; - -string_or_uri: STRING | URI ; - -maybe_media_value: /*empty*/ { $$ = nullptr; } | ':' maybe_space expr maybe_space { $$ = $3; } ; - -media_query_exp: - maybe_media_restrictor maybe_space '(' maybe_space IDENT maybe_space maybe_media_value ')' maybe_space { - // If restrictor is specified, media query expression is invalid. - // Create empty media query expression and continue parsing media query. - OwnPtr mediaValue = adoptPtr($7); - if ($1 != MediaQuery::None) - $$ = MediaQueryExp::create(emptyString(), nullptr).leakPtr(); - else { - $5.lower(); - $$ = MediaQueryExp::create($5, mediaValue.get()).leakPtr(); - } - } - ; - -media_query_exp_list: - media_query_exp { - $$ = new Vector>; - $$->append(adoptPtr($1)); - } - | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp { - $$ = $1; - $$->append(adoptPtr($5)); - } - ; - -maybe_and_media_query_exp_list: - /*empty*/ { - $$ = new Vector>; - } - | MEDIA_AND maybe_space media_query_exp_list { - $$ = $3; - } - ; - -maybe_media_restrictor: - /*empty*/ { - $$ = MediaQuery::None; - } - | MEDIA_ONLY { - $$ = MediaQuery::Only; - } - | MEDIA_NOT { - $$ = MediaQuery::Not; - } - ; - -media_query: - media_query_exp_list { - $$ = new MediaQuery(MediaQuery::None, "all", adoptPtr($1)); - } - | - maybe_media_restrictor maybe_space IDENT maybe_space maybe_and_media_query_exp_list { - $3.lower(); - $$ = new MediaQuery($1, $3, adoptPtr($5)); - } - ; - -maybe_media_list: /* empty */ { $$ = MediaQuerySet::create().leakRef(); } | media_list ; - -media_list: - media_query { - $$ = MediaQuerySet::create().leakRef(); - $$->addMediaQuery(adoptPtr($1)); - parser->updateLastMediaLine($$); - } - | media_list ',' maybe_space media_query { - $$ = $1; - OwnPtr mediaQuery = adoptPtr($4); - if ($$) { - $$->addMediaQuery(mediaQuery.release()); - parser->updateLastMediaLine($$); - } - } - | media_list error { - $$ = nullptr; - if ($1) - $1->deref(); - } - ; - -at_rule_body_start: - /* empty */ { - parser->markRuleBodyStart(); - } - ; - -before_media_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::MEDIA_RULE); - } - ; - -at_rule_header_end_maybe_space: - maybe_space { - parser->markRuleHeaderEnd(); - } - ; - -media: - before_media_rule MEDIA_SYM maybe_space media_list at_rule_header_end '{' at_rule_body_start maybe_space block_rule_list save_block { - $$ = parser->createMediaRule(adoptRef($4), adoptPtr($9).get()).leakRef(); - } - | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space block_rule_list save_block { - $$ = parser->createEmptyMediaRule(adoptPtr($7).get()).leakRef(); - } - | before_media_rule MEDIA_SYM at_rule_header_end_maybe_space ';' { - $$ = nullptr; - parser->popRuleData(); - } - ; - -#if ENABLE_CSS3_CONDITIONAL_RULES - -supports: - before_supports_rule SUPPORTS_SYM maybe_space supports_condition at_supports_rule_header_end '{' at_rule_body_start maybe_space block_rule_list save_block { - $$ = parser->createSupportsRule($4, adoptPtr($9).get()).leakRef(); - } - | before_supports_rule SUPPORTS_SYM supports_error { - $$ = nullptr; - parser->popRuleData(); - parser->popSupportsRuleData(); - } - ; - -supports_error: error ';' | error invalid_block ; - -before_supports_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::SUPPORTS_RULE); - parser->markSupportsRuleHeaderStart(); - } - ; - -at_supports_rule_header_end: - /* empty */ { - parser->markRuleHeaderEnd(); - parser->markSupportsRuleHeaderEnd(); - } - ; - -supports_condition: supports_condition_in_parens | supports_negation | supports_conjunction | supports_disjunction ; - -supports_negation: SUPPORTS_NOT maybe_space supports_condition_in_parens { $$ = !$3; } ; - -supports_conjunction: - supports_condition_in_parens SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; } - | supports_conjunction SUPPORTS_AND maybe_space supports_condition_in_parens { $$ = $1 && $4; } - ; - -supports_disjunction: - supports_condition_in_parens SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; } - | supports_disjunction SUPPORTS_OR maybe_space supports_condition_in_parens { $$ = $1 || $4; } - ; - -supports_condition_in_parens: - '(' maybe_space supports_condition ')' maybe_space { $$ = $3; } - | supports_declaration_condition - | '(' error ')' - ; - -supports_declaration_condition: - '(' maybe_space property ':' maybe_space expr priority ')' maybe_space { - $$ = false; - CSSParser* p = static_cast(parser); - OwnPtr propertyValue = adoptPtr($6); - if ($3 && propertyValue) { - p->m_valueList = propertyValue.release(); - int oldParsedProperties = p->m_parsedProperties.size(); - $$ = p->parseValue($3, $7); - // We just need to know if the declaration is supported as it is written. Rollback any additions. - if ($$) - p->rollbackLastProperties(p->m_parsedProperties.size() - oldParsedProperties); - p->m_valueList = nullptr; - } - p->markPropertyEnd($7, false); - } - ; - -#endif - -before_keyframes_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::KEYFRAMES_RULE); - } - ; - -keyframes: - before_keyframes_rule WEBKIT_KEYFRAMES_SYM maybe_space keyframe_name at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space keyframes_rule closing_brace { - $$ = parser->createKeyframesRule($4, adoptPtr($9)).leakRef(); - } - ; - -keyframe_name: IDENT | STRING ; - -keyframes_rule: - /* empty */ { $$ = new Vector>; } - | keyframes_rule keyframe_rule maybe_space { - $$ = $1; - if (RefPtr keyframe = adoptRef($2)) - $$->append(keyframe.release()); - } - ; - -keyframe_rule: key_list maybe_space '{' maybe_space declaration_list closing_brace { $$ = parser->createKeyframe(*adoptPtr($1)).leakRef(); } ; - -key_list: - key { - $$ = new CSSParserValueList; - $$->addValue($1); - } - | key_list maybe_space ',' maybe_space key { - $$ = $1; - ASSERT($5.unit != CSSParserValue::Function); // No need to call destroy. - if ($$) - $$->addValue($5); - } - ; - -key: - maybe_unary_operator PERCENTAGE { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1 * $2; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } - | IDENT { - $$.id = CSSValueInvalid; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER; - CSSParserString& str = $1; - if (str.equalIgnoringCase("from")) - $$.fValue = 0; - else if (str.equalIgnoringCase("to")) - $$.fValue = 100; - else { - $$.unit = 0; - YYERROR; - } - } - | error { - $$.unit = 0; - } - ; - -before_page_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::PAGE_RULE); - } - ; - -page: - before_page_rule PAGE_SYM maybe_space page_selector at_rule_header_end_maybe_space - '{' at_rule_body_start maybe_space_before_declaration declarations_and_margins closing_brace { - if ($4) - $$ = parser->createPageRule(adoptPtr($4)).leakRef(); - else { - // Clear properties in the invalid @page rule. - parser->clearProperties(); - // Also clear margin at-rules here once we fully implement margin at-rules parsing. - $$ = nullptr; - parser->popRuleData(); - } - } - | before_page_rule PAGE_SYM error invalid_block { - parser->popRuleData(); - $$ = nullptr; - } - | before_page_rule PAGE_SYM error ';' { - parser->popRuleData(); - $$ = nullptr; - } - ; - -page_selector: - IDENT { - $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace)); - $$->setForPage(); - } - | IDENT pseudo_page { - $$ = $2; - if ($$) { - $$->prependTagSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace)); - $$->setForPage(); - } - } - | pseudo_page { - $$ = $1; - if ($$) - $$->setForPage(); - } - | /* empty */ { - $$ = new CSSParserSelector; - $$->setForPage(); - } - ; - -declarations_and_margins: declaration_list | declarations_and_margins margin_box maybe_space declaration_list ; - -margin_box: - margin_sym { - parser->startDeclarationsForMarginBox(); - } maybe_space '{' maybe_space declaration_list closing_brace { - parser->createMarginAtRule($1); - } - ; - -margin_sym: - TOPLEFTCORNER_SYM { - $$ = CSSSelector::TopLeftCornerMarginBox; - } - | TOPLEFT_SYM { - $$ = CSSSelector::TopLeftMarginBox; - } - | TOPCENTER_SYM { - $$ = CSSSelector::TopCenterMarginBox; - } - | TOPRIGHT_SYM { - $$ = CSSSelector::TopRightMarginBox; - } - | TOPRIGHTCORNER_SYM { - $$ = CSSSelector::TopRightCornerMarginBox; - } - | BOTTOMLEFTCORNER_SYM { - $$ = CSSSelector::BottomLeftCornerMarginBox; - } - | BOTTOMLEFT_SYM { - $$ = CSSSelector::BottomLeftMarginBox; - } - | BOTTOMCENTER_SYM { - $$ = CSSSelector::BottomCenterMarginBox; - } - | BOTTOMRIGHT_SYM { - $$ = CSSSelector::BottomRightMarginBox; - } - | BOTTOMRIGHTCORNER_SYM { - $$ = CSSSelector::BottomRightCornerMarginBox; - } - | LEFTTOP_SYM { - $$ = CSSSelector::LeftTopMarginBox; - } - | LEFTMIDDLE_SYM { - $$ = CSSSelector::LeftMiddleMarginBox; - } - | LEFTBOTTOM_SYM { - $$ = CSSSelector::LeftBottomMarginBox; - } - | RIGHTTOP_SYM { - $$ = CSSSelector::RightTopMarginBox; - } - | RIGHTMIDDLE_SYM { - $$ = CSSSelector::RightMiddleMarginBox; - } - | RIGHTBOTTOM_SYM { - $$ = CSSSelector::RightBottomMarginBox; - } - ; - -before_font_face_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::FONT_FACE_RULE); - } - ; - -font_face: - before_font_face_rule FONT_FACE_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace { - $$ = parser->createFontFaceRule().leakRef(); - } - | before_font_face_rule FONT_FACE_SYM error invalid_block { - $$ = nullptr; - parser->popRuleData(); - } - | before_font_face_rule FONT_FACE_SYM error ';' { - $$ = nullptr; - parser->popRuleData(); - } -; - -#if ENABLE_SHADOW_DOM - -before_host_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::HOST_RULE); - } - ; - -host: - before_host_rule HOST_SYM at_rule_header_end_maybe_space '{' at_rule_body_start maybe_space block_rule_list save_block { - $$ = parser->createHostRule(adoptPtr($7).get()).leakRef(); - } - | before_host_rule HOST_SYM at_rule_header_end_maybe_space ';' { - $$ = nullptr; - parser->popRuleData(); - } - ; - -#endif - -#if ENABLE_CSS_DEVICE_ADAPTATION - -before_viewport_rule: - /* empty */ { - parser->markViewportRuleBodyStart(); - parser->markRuleHeaderStart(CSSRuleSourceData::VIEWPORT_RULE); - } - ; - -viewport: - before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM at_rule_header_end_maybe_space - '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace { - $$ = parser->createViewportRule().leakRef(); - parser->markViewportRuleBodyEnd(); - } - | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error invalid_block { - $$ = nullptr; - parser->popRuleData(); - parser->markViewportRuleBodyEnd(); - } - | before_viewport_rule WEBKIT_VIEWPORT_RULE_SYM error ';' { - $$ = nullptr; - parser->popRuleData(); - parser->markViewportRuleBodyEnd(); - } -; - -#endif - -before_region_rule: - /* empty */ { - parser->markRuleHeaderStart(CSSRuleSourceData::REGION_RULE); - } - ; - -region: - before_region_rule WEBKIT_REGION_RULE_SYM maybe_space selector_list at_rule_header_end '{' at_rule_body_start maybe_space block_valid_rule_list save_block { - OwnPtr>> ruleList = adoptPtr($9); - if ($4) - $$ = parser->createRegionRule(adoptPtr($4).get(), ruleList.get()).leakRef(); - else { - $$ = nullptr; - parser->popRuleData(); - } - } -; - -combinator: - '+' maybe_space { $$ = CSSSelector::DirectAdjacent; } - | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; } - | '>' maybe_space { $$ = CSSSelector::Child; } - ; - -maybe_unary_operator: unary_operator | { $$ = 1; } ; - -unary_operator: '-' { $$ = -1; } | '+' { $$ = 1; } ; - -maybe_space_before_declaration: maybe_space { parser->markPropertyStart(); } ; - -before_selector_list: - { - parser->markRuleHeaderStart(CSSRuleSourceData::STYLE_RULE); - parser->markSelectorStart(); - } - ; - -at_rule_header_end: { parser->markRuleHeaderEnd(); } ; - -at_selector_end: { parser->markSelectorEnd(); } ; - -ruleset: - before_selector_list selector_list at_selector_end at_rule_header_end '{' at_rule_body_start maybe_space_before_declaration declaration_list closing_brace { - $$ = parser->createStyleRule($2).leakRef(); - parser->recycleSelectorVector(adoptPtr($2)); - } - ; - -before_selector_group_item: { parser->markSelectorStart(); } ; - -selector_list: - selector %prec UNIMPORTANT_TOK { - $$ = nullptr; - if ($1) { - $$ = parser->createSelectorVector().leakPtr(); - $$->append(adoptPtr($1)); - parser->updateLastSelectorLineAndPosition(); - } - } - | selector_list at_selector_end ',' maybe_space before_selector_group_item selector %prec UNIMPORTANT_TOK { - OwnPtr>> selectorList = adoptPtr($1); - OwnPtr selector = adoptPtr($6); - $$ = nullptr; - if (selectorList && selector) { - $$ = selectorList.leakPtr(); - $$->append(selector.release()); - parser->updateLastSelectorLineAndPosition(); - } - } - | selector_list error { - $$ = nullptr; - delete $1; - } - ; - -selector_with_trailing_whitespace: - selector WHITESPACE; - -selector: - simple_selector - | selector_with_trailing_whitespace - | selector_with_trailing_whitespace simple_selector { - OwnPtr left = adoptPtr($1); - OwnPtr right = adoptPtr($2); - $$ = nullptr; - if (left && right) { - right->appendTagHistory(CSSSelector::Descendant, left.release()); - $$ = right.leakPtr(); - } - } - | selector combinator simple_selector { - OwnPtr left = adoptPtr($1); - OwnPtr right = adoptPtr($3); - $$ = nullptr; - if (left && right) { - right->appendTagHistory($2, left.release()); - $$ = right.leakPtr(); - } - } - | selector error { - $$ = nullptr; - delete $1; - } - ; - -namespace_selector: - '|' { $$.clear(); } - | '*' '|' { static LChar star = '*'; $$.init(&star, 1); } - | IDENT '|' -; - -simple_selector: - element_name { - $$ = new CSSParserSelector(QualifiedName(nullAtom, $1, parser->m_defaultNamespace)); - } - | element_name specifier_list { - $$ = $2; - if ($$) - parser->rewriteSpecifiersWithElementName(nullAtom, $1, *$$); - } - | specifier_list { - $$ = $1; - if ($$) - parser->rewriteSpecifiersWithNamespaceIfNeeded(*$$); - } - | namespace_selector element_name { - $$ = new CSSParserSelector(parser->determineNameInNamespace($1, $2)); - } - | namespace_selector element_name specifier_list { - $$ = $3; - if ($$) - parser->rewriteSpecifiersWithElementName($1, $2, *$$); - } - | namespace_selector specifier_list { - $$ = $2; - if ($$) - parser->rewriteSpecifiersWithElementName($1, starAtom, *$$); - } - ; - -simple_selector_list: - simple_selector %prec UNIMPORTANT_TOK { - $$ = nullptr; - if ($1) { - $$ = parser->createSelectorVector().leakPtr(); - $$->append(adoptPtr($1)); - } - } - | simple_selector_list maybe_space ',' maybe_space simple_selector %prec UNIMPORTANT_TOK { - OwnPtr>> list = adoptPtr($1); - OwnPtr selector = adoptPtr($5); - $$ = nullptr; - if (list && selector) { - $$ = list.leakPtr(); - $$->append(selector.release()); - } - } - | simple_selector_list error { - $$ = nullptr; - delete $1; - } - ; - -element_name: - IDENT { - if (parser->m_context.isHTMLDocument) - $1.lower(); - $$ = $1; - } - | '*' { - static LChar star = '*'; - $$.init(&star, 1); - } - ; - -specifier_list: - specifier - | specifier_list specifier { - OwnPtr list = adoptPtr($1); - OwnPtr specifier = adoptPtr($2); - $$ = nullptr; - if (list && specifier) - $$ = parser->rewriteSpecifiers(list.release(), specifier.release()).leakPtr(); - } - | specifier_list error { - $$ = nullptr; - delete $1; - } -; - -specifier: - IDSEL { - $$ = new CSSParserSelector; - $$->setMatch(CSSSelector::Id); - if (parser->m_context.mode == CSSQuirksMode) - $1.lower(); - $$->setValue($1); - } - | HEX { - if ($1[0] >= '0' && $1[0] <= '9') - $$ = nullptr; - else { - $$ = new CSSParserSelector; - $$->setMatch(CSSSelector::Id); - if (parser->m_context.mode == CSSQuirksMode) - $1.lower(); - $$->setValue($1); - } - } - | class - | attrib - | pseudo - ; - -class: - '.' IDENT { - $$ = new CSSParserSelector; - $$->setMatch(CSSSelector::Class); - if (parser->m_context.mode == CSSQuirksMode) - $2.lower(); - $$->setValue($2); - } - ; - -attrib: - '[' maybe_space IDENT maybe_space ']' { - $$ = new CSSParserSelector; - $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument); - $$->setMatch(CSSSelector::Set); - } - | '[' maybe_space IDENT maybe_space match maybe_space ident_or_string maybe_space ']' { - $$ = new CSSParserSelector; - $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom), parser->m_context.isHTMLDocument); - $$->setMatch($5); - $$->setValue($7); - } - | '[' maybe_space namespace_selector IDENT maybe_space ']' { - $$ = new CSSParserSelector; - $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument); - $$->setMatch(CSSSelector::Set); - } - | '[' maybe_space namespace_selector IDENT maybe_space match maybe_space ident_or_string maybe_space ']' { - $$ = new CSSParserSelector; - $$->setAttribute(parser->determineNameInNamespace($3, $4), parser->m_context.isHTMLDocument); - $$->setMatch($6); - $$->setValue($8); - } - ; - -match: - '=' { - $$ = CSSSelector::Exact; - } - | INCLUDES { - $$ = CSSSelector::List; - } - | DASHMATCH { - $$ = CSSSelector::Hyphen; - } - | BEGINSWITH { - $$ = CSSSelector::Begin; - } - | ENDSWITH { - $$ = CSSSelector::End; - } - | CONTAINS { - $$ = CSSSelector::Contain; - } - ; - -ident_or_string: IDENT | STRING ; - -pseudo_page: - ':' IDENT { - $$ = nullptr; - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PagePseudoClass); - $2.lower(); - selector->setValue($2); - if (selector->pseudoType() != CSSSelector::PseudoUnknown) - $$ = selector.release(); - } - -pseudo: - ':' IDENT { - $$ = nullptr; - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - $2.lower(); - selector->setValue($2); - if (selector->pseudoType() != CSSSelector::PseudoUnknown) - $$ = selector.release(); - } - | ':' ':' IDENT { - $$ = nullptr; - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoElement); - $3.lower(); - selector->setValue($3); - if (selector->pseudoType() != CSSSelector::PseudoUnknown) - $$ = selector.release(); - } -#if ENABLE_VIDEO_TRACK - // used by ::cue(:past/:future) - | ':' ':' CUEFUNCTION maybe_space simple_selector_list maybe_space ')' { - $$ = nullptr; - if ($5) { - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - selector->adoptSelectorVector(*adoptPtr($5)); - selector->setValue($3); - if (selector->pseudoType() == CSSSelector::PseudoCue) - $$ = selector.release(); - } - } -#endif - // use by :-webkit-any. - // FIXME: should we support generic selectors here or just simple_selectors? - // Use simple_selector_list for now to match -moz-any. - // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0566.html for some - // related discussion with respect to :not. - | ':' ANYFUNCTION maybe_space simple_selector_list maybe_space ')' { - $$ = nullptr; - if ($4) { - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - selector->adoptSelectorVector(*adoptPtr($4)); - $2.lower(); - selector->setValue($2); - if (selector->pseudoType() == CSSSelector::PseudoAny) - $$ = selector.release(); - } - } - // used by :nth-*(ax+b) - | ':' FUNCTION maybe_space NTH maybe_space ')' { - $$ = nullptr; - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - selector->setArgument($4); - selector->setValue($2); - if (selector->pseudoType() != CSSSelector::PseudoUnknown) - $$ = selector.release(); - } - // used by :nth-* - | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' { - $$ = nullptr; - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - selector->setArgument(AtomicString::number($4 * $5)); - selector->setValue($2); - if (selector->pseudoType() != CSSSelector::PseudoUnknown) - $$ = selector.release(); - } - // used by :nth-*(odd/even) and :lang - | ':' FUNCTION maybe_space IDENT maybe_space ')' { - auto selector = std::make_unique(); - selector->setMatch(CSSSelector::PseudoClass); - selector->setArgument($4); - $2.lower(); - selector->setValue($2); - CSSSelector::PseudoType type = selector->pseudoType(); - if (type == CSSSelector::PseudoUnknown) - selector = nullptr; - else if (type == CSSSelector::PseudoNthChild || - type == CSSSelector::PseudoNthOfType || - type == CSSSelector::PseudoNthLastChild || - type == CSSSelector::PseudoNthLastOfType) { - if (!isValidNthToken($4)) - selector = nullptr; - } - $$ = selector.release(); - } - // used by :not - | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' { - OwnPtr selector = adoptPtr($4); - $$ = nullptr; - if (selector && selector->isSimple()) { - $$ = new CSSParserSelector; - $$->setMatch(CSSSelector::PseudoClass); - - Vector> selectorVector; - selectorVector.append(selector.release()); - $$->adoptSelectorVector(selectorVector); - - $2.lower(); - $$->setValue($2); - } - } - ; - -declaration_list: - /* empty */ { $$ = false; } - | declaration - | decl_list declaration { $$ = $1 || $2; } - | decl_list - | decl_list_recovery { $$ = false; } - | decl_list decl_list_recovery - ; - -decl_list: - declaration ';' maybe_space { - parser->markPropertyStart(); - $$ = $1; - } - | decl_list_recovery ';' maybe_space { - parser->markPropertyStart(); - $$ = false; - } - | decl_list declaration ';' maybe_space { - parser->markPropertyStart(); - $$ = $1; - if ($2) - $$ = $2; - } - | decl_list decl_list_recovery ';' maybe_space { - parser->markPropertyStart(); - $$ = $1; - } - ; - -decl_list_recovery: - error error_location error_recovery { - parser->syntaxError($2, CSSParser::PropertyDeclarationError); - } - ; - -declaration: - property ':' maybe_space expr priority { - $$ = false; - bool isPropertyParsed = false; - OwnPtr propertyValue = adoptPtr($4); - if ($1 && propertyValue) { - parser->m_valueList = propertyValue.release(); - int oldParsedProperties = parser->m_parsedProperties.size(); - $$ = parser->parseValue($1, $5); - if (!$$) - parser->rollbackLastProperties(parser->m_parsedProperties.size() - oldParsedProperties); - else - isPropertyParsed = true; - parser->m_valueList = nullptr; - } - parser->markPropertyEnd($5, isPropertyParsed); - } - | property declaration_recovery { $$ = false; } - | property ':' maybe_space expr priority declaration_recovery { - // When we encounter something like p {color: red !important fail;} we should drop the declaration. - parser->markPropertyEnd(false, false); - delete $4; - $$ = false; - } - | IMPORTANT_SYM maybe_space declaration_recovery { - // Handle this case -- div { text-align: center; !important } -- by just reducing away the stray !important. - $$ = false; - } - | property ':' maybe_space declaration_recovery { - // If we come across rules with invalid values like this case: p { weight: *; }, just discard the rule. - parser->markPropertyEnd(false, false); - $$ = false; - } - ; - -declaration_recovery: error error_location error_recovery { parser->syntaxError($2); } ; - -property: IDENT maybe_space { $$ = cssPropertyID($1); } ; - -priority: IMPORTANT_SYM maybe_space { $$ = true; } | /* empty */ { $$ = false; } ; - -expr: valid_expr | valid_expr expr_recovery { $$ = nullptr; delete $1; } ; - -valid_expr: - term { - $$ = new CSSParserValueList; - $$->addValue($1); - } - | valid_expr operator term { - $$ = $1; - if (!$$) - destroy($3); - else { - if ($2) { - CSSParserValue v; - v.id = CSSValueInvalid; - v.unit = CSSParserValue::Operator; - v.iValue = $2; - $$->addValue(v); - } - $$->addValue($3); - } - } - ; - -expr_recovery: error error_location error_recovery ; - -operator: '/' maybe_space { $$ = '/'; } | ',' maybe_space { $$ = ','; } | /* empty */ { $$ = 0; } ; - -term: - unary_term maybe_space - | unary_operator unary_term maybe_space { $$ = $2; $$.fValue *= $1; } - | STRING maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; } - | IDENT maybe_space { - $$.id = cssValueKeywordID($1); - $$.unit = CSSPrimitiveValue::CSS_IDENT; - $$.string = $1; - } - /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */ - | DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } - | unary_operator DIMEN maybe_space { $$.id = CSSValueInvalid; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } - | URI maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; } - | UNICODERANGE maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; } - | HEX maybe_space { $$.id = CSSValueInvalid; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } - | '#' maybe_space { $$.id = CSSValueInvalid; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */ - /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */ - | function maybe_space - | calc_function maybe_space - | min_or_max_function maybe_space - | '%' maybe_space { /* Handle width: %; */ - $$.id = CSSValueInvalid; $$.unit = 0; - } - ; - -unary_term: - INTEGER { $$.id = CSSValueInvalid; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } - | FLOATTOKEN { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } - | PERCENTAGE { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; } - | PXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; } - | CMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; } - | MMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; } - | INS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; } - | PTS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; } - | PCS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; } - | DEGS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; } - | RADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; } - | GRADS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; } - | TURNS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; } - | MSECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; } - | SECS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; } - | HERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; } - | KHERTZ { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; } - | EMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; } - | QEMS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; } - | EXS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; } - | REMS { - $$.id = CSSValueInvalid; - $$.fValue = $1; - $$.unit = CSSPrimitiveValue::CSS_REMS; - if (parser->m_styleSheet) - parser->m_styleSheet->parserSetUsesRemUnits(true); - } - | CHS { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CHS; } - | VW { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VW; } - | VH { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VH; } - | VMIN { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMIN; } - | VMAX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_VMAX; } - | DPPX { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPPX; } - | DPI { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPI; } - | DPCM { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPCM; } - | FR { $$.id = CSSValueInvalid; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_FR; } - ; - -function: - FUNCTION maybe_space expr closing_parenthesis { - CSSParserFunction* f = new CSSParserFunction; - f->name = $1; - f->args = adoptPtr($3); - $$.id = CSSValueInvalid; - $$.unit = CSSParserValue::Function; - $$.function = f; - } | - FUNCTION maybe_space closing_parenthesis { - CSSParserFunction* f = new CSSParserFunction; - f->name = $1; - f->args = adoptPtr(new CSSParserValueList); - $$.id = CSSValueInvalid; - $$.unit = CSSParserValue::Function; - $$.function = f; - } | - FUNCTION maybe_space expr_recovery closing_parenthesis { - CSSParserFunction* f = new CSSParserFunction; - f->name = $1; - f->args = nullptr; - $$.id = CSSValueInvalid; - $$.unit = CSSParserValue::Function; - $$.function = f; - } - ; - -calc_func_term: - unary_term - | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } - ; - -/* - * The grammar requires spaces around binary ‘+’ and ‘-’ operators. - * The '*' and '/' operators do not require spaces. - * http://www.w3.org/TR/css3-values/#calc-syntax - */ -calc_func_operator: - space '+' space { - $$ = '+'; - } - | space '-' space { - $$ = '-'; - } - | calc_maybe_space '*' maybe_space { - $$ = '*'; - } - | calc_maybe_space '/' maybe_space { - $$ = '/'; - } - ; - -calc_maybe_space: /* empty */ | WHITESPACE ; - -calc_func_paren_expr: - '(' maybe_space calc_func_expr calc_maybe_space closing_parenthesis { - $$ = nullptr; - if ($3) { - $$ = $3; - CSSParserValue v; - v.id = CSSValueInvalid; - v.unit = CSSParserValue::Operator; - v.iValue = '('; - $$->insertValueAt(0, v); - v.iValue = ')'; - $$->addValue(v); - } - } - ; - -calc_func_expr: valid_calc_func_expr | valid_calc_func_expr expr_recovery { $$ = nullptr; delete $1; } ; - -valid_calc_func_expr: - calc_func_term { - $$ = new CSSParserValueList; - $$->addValue($1); - } - | calc_func_expr calc_func_operator calc_func_term { - OwnPtr expression = adoptPtr($1); - $$ = nullptr; - if (expression && $2) { - $$ = expression.leakPtr(); - CSSParserValue v; - v.id = CSSValueInvalid; - v.unit = CSSParserValue::Operator; - v.iValue = $2; - $$->addValue(v); - $$->addValue($3); - } else { - destroy($3); - } - - } - | calc_func_expr calc_func_operator calc_func_paren_expr { - OwnPtr left = adoptPtr($1); - OwnPtr right = adoptPtr($3); - $$ = nullptr; - if (left && $2 && right) { - CSSParserValue v; - v.id = CSSValueInvalid; - v.unit = CSSParserValue::Operator; - v.iValue = $2; - left->addValue(v); - left->extend(*right); - $$ = left.leakPtr(); - } - } - | calc_func_paren_expr - ; - -calc_func_expr_list: - calc_func_expr calc_maybe_space - | calc_func_expr_list ',' maybe_space calc_func_expr calc_maybe_space { - OwnPtr list = adoptPtr($1); - OwnPtr expression = adoptPtr($4); - $$ = nullptr; - if (list && expression) { - $$ = list.leakPtr(); - CSSParserValue v; - v.id = CSSValueInvalid; - v.unit = CSSParserValue::Operator; - v.iValue = ','; - $$->addValue(v); - $$->extend(*expression); - } - } - ; - -calc_function: - CALCFUNCTION maybe_space calc_func_expr calc_maybe_space closing_parenthesis { - CSSParserFunction* f = new CSSParserFunction; - f->name = $1; - f->args = adoptPtr($3); - $$.id = CSSValueInvalid; - $$.unit = CSSParserValue::Function; - $$.function = f; - } - | CALCFUNCTION maybe_space expr_recovery closing_parenthesis { - $$.id = CSSValueInvalid; - $$.unit = 0; - YYERROR; - } - ; - - -min_or_max: MINFUNCTION | MAXFUNCTION ; - -min_or_max_function: - min_or_max maybe_space calc_func_expr_list closing_parenthesis { - CSSParserFunction* f = new CSSParserFunction; - f->name = $1; - f->args = adoptPtr($3); - $$.id = CSSValueInvalid; - $$.unit = CSSParserValue::Function; - $$.function = f; - } - | min_or_max maybe_space expr_recovery closing_parenthesis { - $$.id = CSSValueInvalid; - $$.unit = 0; - YYERROR; - } - ; - -/* error handling rules */ - -save_block: closing_brace | error closing_brace ; - -invalid_at: ATKEYWORD error invalid_block | ATKEYWORD error ';' ; - -invalid_rule: error invalid_block ; - -invalid_block: '{' error_recovery closing_brace { parser->invalidBlockHit(); } ; - -invalid_square_brackets_block: '[' error_recovery ']' | '[' error_recovery TOKEN_EOF ; - -invalid_parentheses_block: opening_parenthesis error_recovery closing_parenthesis; - -opening_parenthesis: - '(' | FUNCTION | CALCFUNCTION | MINFUNCTION | MAXFUNCTION | ANYFUNCTION | NOTFUNCTION -#if ENABLE_VIDEO_TRACK - | CUEFUNCTION -#endif - ; - -error_location: { $$ = parser->currentLocation(); } ; - -error_recovery: - /* empty */ - | error_recovery error - | error_recovery invalid_block - | error_recovery invalid_square_brackets_block - | error_recovery invalid_parentheses_block - ; - -%% diff --git a/Source/WebCore/css/CSSGrammar.y.includes b/Source/WebCore/css/CSSGrammar.y.includes deleted file mode 100644 index 44e45fc75..000000000 --- a/Source/WebCore/css/CSSGrammar.y.includes +++ /dev/null @@ -1,61 +0,0 @@ -%{ - -/* - * Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) - * Copyright (C) 2008 Eric Seidel - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" - -#include "CSSParser.h" -#include "CSSParserMode.h" -#include "CSSPrimitiveValue.h" -#include "CSSPropertyNames.h" -#include "CSSSelector.h" -#include "CSSSelectorList.h" -#include "Document.h" -#include "HTMLNames.h" -#include "MediaList.h" -#include "MediaQueryExp.h" -#include "StyleRule.h" -#include "StyleSheetContents.h" -#include "WebKitCSSKeyframeRule.h" -#include "WebKitCSSKeyframesRule.h" -#include -#include -#include - -using namespace WebCore; -using namespace HTMLNames; - -#define YYMALLOC fastMalloc -#define YYFREE fastFree - -#define YYENABLE_NLS 0 -#define YYLTYPE_IS_TRIVIAL 1 -#define YYMAXDEPTH 10000 -#define YYDEBUG 0 - -#if YYDEBUG > 0 -#include -#define YYPRINT(File,Type,Value) if (isCSSTokenAString(Type)) YYFPRINTF(File, "%s", String((Value).string).utf8().data()) -#endif - -%} diff --git a/Source/WebCore/css/CSSGridAutoRepeatValue.cpp b/Source/WebCore/css/CSSGridAutoRepeatValue.cpp new file mode 100644 index 000000000..1b5fc1a4a --- /dev/null +++ b/Source/WebCore/css/CSSGridAutoRepeatValue.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSGridAutoRepeatValue.h" + +#include + +namespace WebCore { + +String CSSGridAutoRepeatValue::customCSSText() const +{ + StringBuilder result; + result.append("repeat("); + result.append(getValueName(autoRepeatID())); + result.append(", "); + result.append(CSSValueList::customCSSText()); + result.append(")"); + return result.toString(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSGridAutoRepeatValue.h b/Source/WebCore/css/CSSGridAutoRepeatValue.h new file mode 100644 index 000000000..774c81f57 --- /dev/null +++ b/Source/WebCore/css/CSSGridAutoRepeatValue.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValueKeywords.h" +#include "CSSValueList.h" + +namespace WebCore { + +// CSSGridAutoRepeatValue stores the track sizes and line numbers when the auto-repeat +// syntax is used +// +// Right now the auto-repeat syntax is as follows: +// = repeat( [ auto-fill | auto-fit ], ? ? ) +// +// meaning that only one fixed size track is allowed. It could be argued that a different +// class storing two CSSGridLineNamesValue and one CSSValue (for the track size) fits +// better but the CSSWG has left the door open to allow more than one track in the +// future. That's why we're using a list, it's prepared for future changes and it also +// allows us to keep the parsing algorithm almost intact. +class CSSGridAutoRepeatValue final : public CSSValueList { +public: + static Ref create(CSSValueID id) + { + return adoptRef(*new CSSGridAutoRepeatValue(id)); + } + + String customCSSText() const; + CSSValueID autoRepeatID() const { return m_autoRepeatID; } + +private: + CSSGridAutoRepeatValue(CSSValueID id) + : CSSValueList(GridAutoRepeatClass, SpaceSeparator) + , m_autoRepeatID(id) + { + ASSERT(id == CSSValueAutoFill || id == CSSValueAutoFit); + } + + const CSSValueID m_autoRepeatID; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSGridAutoRepeatValue, isGridAutoRepeatValue()); diff --git a/Source/WebCore/css/CSSGridLineNamesValue.cpp b/Source/WebCore/css/CSSGridLineNamesValue.cpp new file mode 100644 index 000000000..217051dfb --- /dev/null +++ b/Source/WebCore/css/CSSGridLineNamesValue.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013, 2014 Igalia, S.L. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSGridLineNamesValue.h" + +namespace WebCore { + +String CSSGridLineNamesValue::customCSSText() const +{ + return "[" + CSSValueList::customCSSText() + "]"; +} + +CSSGridLineNamesValue::CSSGridLineNamesValue() + : CSSValueList(GridLineNamesClass, SpaceSeparator) +{ +} + +} diff --git a/Source/WebCore/css/CSSGridLineNamesValue.h b/Source/WebCore/css/CSSGridLineNamesValue.h new file mode 100644 index 000000000..be1630103 --- /dev/null +++ b/Source/WebCore/css/CSSGridLineNamesValue.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013, 2014 Igalia, S.L. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValueList.h" + +namespace WebCore { + +class CSSGridLineNamesValue final : public CSSValueList { +public: + static Ref create() + { + return adoptRef(*new CSSGridLineNamesValue); + } + + String customCSSText() const; + +private: + CSSGridLineNamesValue(); +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSGridLineNamesValue, isGridLineNamesValue()); diff --git a/Source/WebCore/css/CSSGridTemplateAreasValue.cpp b/Source/WebCore/css/CSSGridTemplateAreasValue.cpp new file mode 100644 index 000000000..e0b78659a --- /dev/null +++ b/Source/WebCore/css/CSSGridTemplateAreasValue.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSGridTemplateAreasValue.h" + +#include "GridArea.h" +#include + +namespace WebCore { + +CSSGridTemplateAreasValue::CSSGridTemplateAreasValue(const NamedGridAreaMap& gridAreaMap, size_t rowCount, size_t columnCount) + : CSSValue(GridTemplateAreasClass) + , m_gridAreaMap(gridAreaMap) + , m_rowCount(rowCount) + , m_columnCount(columnCount) +{ + ASSERT(m_rowCount); + ASSERT(m_columnCount); +} + +static String stringForPosition(const NamedGridAreaMap& gridAreaMap, size_t row, size_t column) +{ + Vector candidates; + + for (const auto& it : gridAreaMap) { + const GridArea& area = it.value; + if (row >= area.rows.startLine() && row < area.rows.endLine()) + candidates.append(it.key); + } + + for (const auto& it : gridAreaMap) { + const GridArea& area = it.value; + if (column >= area.columns.startLine() && column < area.columns.endLine() && candidates.contains(it.key)) + return it.key; + } + + return "."; +} + +String CSSGridTemplateAreasValue::customCSSText() const +{ + StringBuilder builder; + for (size_t row = 0; row < m_rowCount; ++row) { + builder.append('\"'); + for (size_t column = 0; column < m_columnCount; ++column) { + builder.append(stringForPosition(m_gridAreaMap, row, column)); + if (column != m_columnCount - 1) + builder.append(' '); + } + builder.append('\"'); + if (row != m_rowCount - 1) + builder.append(' '); + } + return builder.toString(); +} + +bool CSSGridTemplateAreasValue::equals(const CSSGridTemplateAreasValue& other) const +{ + return m_gridAreaMap == other.m_gridAreaMap && m_rowCount == other.m_rowCount && m_columnCount == other.m_columnCount; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSGridTemplateAreasValue.h b/Source/WebCore/css/CSSGridTemplateAreasValue.h new file mode 100644 index 000000000..d4b986829 --- /dev/null +++ b/Source/WebCore/css/CSSGridTemplateAreasValue.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include "GridArea.h" + +namespace WebCore { + +class CSSGridTemplateAreasValue final : public CSSValue { +public: + static Ref create(const NamedGridAreaMap& gridAreaMap, size_t rowCount, size_t columnCount) + { + return adoptRef(*new CSSGridTemplateAreasValue(gridAreaMap, rowCount, columnCount)); + } + + ~CSSGridTemplateAreasValue() { } + + String customCSSText() const; + + const NamedGridAreaMap& gridAreaMap() const { return m_gridAreaMap; } + size_t rowCount() const { return m_rowCount; } + size_t columnCount() const { return m_columnCount; } + + bool equals(const CSSGridTemplateAreasValue&) const; + +private: + CSSGridTemplateAreasValue(const NamedGridAreaMap&, size_t rowCount, size_t columnCount); + + NamedGridAreaMap m_gridAreaMap; + size_t m_rowCount; + size_t m_columnCount; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSGridTemplateAreasValue, isGridTemplateAreasValue()) diff --git a/Source/WebCore/css/CSSGridTemplateValue.cpp b/Source/WebCore/css/CSSGridTemplateValue.cpp deleted file mode 100644 index 5fa8ef523..000000000 --- a/Source/WebCore/css/CSSGridTemplateValue.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * Copyright (C) 2013 Igalia S.L. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "CSSGridTemplateValue.h" - -#include "GridCoordinate.h" -#include - -namespace WebCore { - -CSSGridTemplateValue::CSSGridTemplateValue(const NamedGridAreaMap& gridAreaMap, size_t rowCount, size_t columnCount) - : CSSValue(GridTemplateClass) - , m_gridAreaMap(gridAreaMap) - , m_rowCount(rowCount) - , m_columnCount(columnCount) -{ - ASSERT(m_rowCount); - ASSERT(m_columnCount); -} - -static String stringForPosition(const NamedGridAreaMap& gridAreaMap, size_t row, size_t column) -{ - Vector candidates; - - for (auto it = gridAreaMap.begin(), end = gridAreaMap.end(); it != end; ++it) { - const GridCoordinate& coordinate = it->value; - if (row >= coordinate.rows.initialPositionIndex && row <= coordinate.rows.finalPositionIndex) - candidates.append(it->key); - } - - for (auto it = gridAreaMap.begin(), end = gridAreaMap.end(); it != end; ++it) { - const GridCoordinate& coordinate = it->value; - if (column >= coordinate.columns.initialPositionIndex && column <= coordinate.columns.finalPositionIndex && candidates.contains(it->key)) - return it->key; - } - - return "."; -} - -String CSSGridTemplateValue::customCSSText() const -{ - StringBuilder builder; - for (size_t row = 0; row < m_rowCount; ++row) { - builder.append('\"'); - for (size_t column = 0; column < m_columnCount; ++column) { - builder.append(stringForPosition(m_gridAreaMap, row, column)); - if (column != m_columnCount - 1) - builder.append(' '); - } - builder.append('\"'); - if (row != m_rowCount - 1) - builder.append(' '); - } - return builder.toString(); -} - -} // namespace WebCore diff --git a/Source/WebCore/css/CSSGridTemplateValue.h b/Source/WebCore/css/CSSGridTemplateValue.h deleted file mode 100644 index efae01c48..000000000 --- a/Source/WebCore/css/CSSGridTemplateValue.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * Copyright (C) 2013 Igalia S.L. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CSSGridTemplateValue_h -#define CSSGridTemplateValue_h - -#include "CSSValue.h" -#include "GridCoordinate.h" - -namespace WebCore { - -class CSSGridTemplateValue : public CSSValue { -public: - static PassRef create(const NamedGridAreaMap& gridAreaMap, size_t rowCount, size_t columnCount) - { - return adoptRef(*new CSSGridTemplateValue(gridAreaMap, rowCount, columnCount)); - } - - ~CSSGridTemplateValue() { } - - String customCSSText() const; - - const NamedGridAreaMap& gridAreaMap() const { return m_gridAreaMap; } - size_t rowCount() const { return m_rowCount; } - size_t columnCount() const { return m_columnCount; } - -private: - CSSGridTemplateValue(const NamedGridAreaMap&, size_t rowCount, size_t columnCount); - - NamedGridAreaMap m_gridAreaMap; - size_t m_rowCount; - size_t m_columnCount; -}; - -CSS_VALUE_TYPE_CASTS(CSSGridTemplateValue, isGridTemplateValue()) - -} // namespace WebCore - -#endif // CSSGridTemplateValue_h diff --git a/Source/WebCore/css/CSSGroupingRule.cpp b/Source/WebCore/css/CSSGroupingRule.cpp index 664c9b9a1..42bb83bd1 100644 --- a/Source/WebCore/css/CSSGroupingRule.cpp +++ b/Source/WebCore/css/CSSGroupingRule.cpp @@ -41,10 +41,10 @@ namespace WebCore { -CSSGroupingRule::CSSGroupingRule(StyleRuleGroup* groupRule, CSSStyleSheet* parent) +CSSGroupingRule::CSSGroupingRule(StyleRuleGroup& groupRule, CSSStyleSheet* parent) : CSSRule(parent) , m_groupRule(groupRule) - , m_childRuleCSSOMWrappers(groupRule->childRules().size()) + , m_childRuleCSSOMWrappers(groupRule.childRules().size()) { } @@ -57,26 +57,23 @@ CSSGroupingRule::~CSSGroupingRule() } } -unsigned CSSGroupingRule::insertRule(const String& ruleString, unsigned index, ExceptionCode& ec) +ExceptionOr CSSGroupingRule::insertRule(const String& ruleString, unsigned index) { ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); if (index > m_groupRule->childRules().size()) { // INDEX_SIZE_ERR: Raised if the specified index is not a valid insertion point. - ec = INDEX_SIZE_ERR; - return 0; + return Exception { INDEX_SIZE_ERR }; } - CSSParser parser(parserContext()); CSSStyleSheet* styleSheet = parentStyleSheet(); - RefPtr newRule = parser.parseRule(styleSheet ? &styleSheet->contents() : nullptr, ruleString); + RefPtr newRule = CSSParser::parseRule(parserContext(), styleSheet ? &styleSheet->contents() : nullptr, ruleString); if (!newRule) { // SYNTAX_ERR: Raised if the specified rule has a syntax error and is unparsable. - ec = SYNTAX_ERR; - return 0; + return Exception { SYNTAX_ERR }; } - if (newRule->isImportRule()) { + if (newRule->isImportRule() || newRule->isNamespaceRule()) { // FIXME: an HIERARCHY_REQUEST_ERR should also be thrown for a @charset or a nested // @media rule. They are currently not getting parsed, resulting in a SYNTAX_ERR // to get raised above. @@ -84,8 +81,7 @@ unsigned CSSGroupingRule::insertRule(const String& ruleString, unsigned index, E // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified // index, e.g., if an @import rule is inserted after a standard rule set or other // at-rule. - ec = HIERARCHY_REQUEST_ERR; - return 0; + return Exception { HIERARCHY_REQUEST_ERR }; } CSSStyleSheet::RuleMutationScope mutationScope(this); @@ -95,15 +91,14 @@ unsigned CSSGroupingRule::insertRule(const String& ruleString, unsigned index, E return index; } -void CSSGroupingRule::deleteRule(unsigned index, ExceptionCode& ec) +ExceptionOr CSSGroupingRule::deleteRule(unsigned index) { ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); if (index >= m_groupRule->childRules().size()) { // INDEX_SIZE_ERR: Raised if the specified index does not correspond to a // rule in the media rule list. - ec = INDEX_SIZE_ERR; - return; + return Exception { INDEX_SIZE_ERR }; } CSSStyleSheet::RuleMutationScope mutationScope(this); @@ -113,6 +108,8 @@ void CSSGroupingRule::deleteRule(unsigned index, ExceptionCode& ec) if (m_childRuleCSSOMWrappers[index]) m_childRuleCSSOMWrappers[index]->setParentRule(0); m_childRuleCSSOMWrappers.remove(index); + + return { }; } void CSSGroupingRule::appendCssTextForItems(StringBuilder& result) const @@ -133,7 +130,7 @@ unsigned CSSGroupingRule::length() const CSSRule* CSSGroupingRule::item(unsigned index) const { if (index >= length()) - return 0; + return nullptr; ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); RefPtr& rule = m_childRuleCSSOMWrappers[index]; if (!rule) @@ -141,20 +138,19 @@ CSSRule* CSSGroupingRule::item(unsigned index) const return rule.get(); } -CSSRuleList* CSSGroupingRule::cssRules() const +CSSRuleList& CSSGroupingRule::cssRules() const { if (!m_ruleListCSSOMWrapper) - m_ruleListCSSOMWrapper = std::make_unique>(const_cast(this)); - return m_ruleListCSSOMWrapper.get(); + m_ruleListCSSOMWrapper = std::make_unique>(const_cast(*this)); + return *m_ruleListCSSOMWrapper; } -void CSSGroupingRule::reattach(StyleRuleBase* rule) +void CSSGroupingRule::reattach(StyleRuleBase& rule) { - ASSERT(rule); - m_groupRule = static_cast(rule); + m_groupRule = static_cast(rule); for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) { if (m_childRuleCSSOMWrappers[i]) - m_childRuleCSSOMWrappers[i]->reattach(m_groupRule->childRules()[i].get()); + m_childRuleCSSOMWrappers[i]->reattach(*m_groupRule.get().childRules()[i]); } } diff --git a/Source/WebCore/css/CSSGroupingRule.h b/Source/WebCore/css/CSSGroupingRule.h index f14ee2ce1..f54a39719 100644 --- a/Source/WebCore/css/CSSGroupingRule.h +++ b/Source/WebCore/css/CSSGroupingRule.h @@ -20,43 +20,42 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSGroupingRule_h -#define CSSGroupingRule_h +#pragma once #include "CSSRule.h" -#include "StyleRule.h" #include #include namespace WebCore { class CSSRuleList; +class StyleRuleGroup; class CSSGroupingRule : public CSSRule { public: virtual ~CSSGroupingRule(); - virtual void reattach(StyleRuleBase*) override; + WEBCORE_EXPORT CSSRuleList& cssRules() const; - CSSRuleList* cssRules() const; - - unsigned insertRule(const String& rule, unsigned index, ExceptionCode&); - void deleteRule(unsigned index, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr insertRule(const String& rule, unsigned index); + WEBCORE_EXPORT ExceptionOr deleteRule(unsigned index); // For CSSRuleList unsigned length() const; CSSRule* item(unsigned index) const; protected: - CSSGroupingRule(StyleRuleGroup* groupRule, CSSStyleSheet* parent); + CSSGroupingRule(StyleRuleGroup& groupRule, CSSStyleSheet* parent); + void reattach(StyleRuleBase&) override; + void appendCssTextForItems(StringBuilder&) const; - RefPtr m_groupRule; + Ref m_groupRule; + +private: mutable Vector> m_childRuleCSSOMWrappers; mutable std::unique_ptr m_ruleListCSSOMWrapper; }; } // namespace WebCore - -#endif // CSSGroupingRule_h diff --git a/Source/WebCore/css/CSSHelper.h b/Source/WebCore/css/CSSHelper.h index 6f2ffca9b..576112ffe 100644 --- a/Source/WebCore/css/CSSHelper.h +++ b/Source/WebCore/css/CSSHelper.h @@ -19,10 +19,7 @@ * */ -#ifndef CSSHelper_h -#define CSSHelper_h - -#include +#pragma once namespace WebCore { @@ -32,5 +29,3 @@ namespace WebCore { const float cssPixelsPerInch = 96; } // namespace WebCore - -#endif // CSSHelper_h diff --git a/Source/WebCore/css/CSSHostRule.cpp b/Source/WebCore/css/CSSHostRule.cpp deleted file mode 100644 index 86bebc9f3..000000000 --- a/Source/WebCore/css/CSSHostRule.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2005, 2006, 2012 Apple Computer, Inc. - * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "CSSHostRule.h" - -#if ENABLE(SHADOW_DOM) - -#include - -namespace WebCore { - -CSSHostRule::CSSHostRule(StyleRuleHost* hostRule, CSSStyleSheet* parent) - : CSSGroupingRule(hostRule, parent) -{ -} - -String CSSHostRule::cssText() const -{ - StringBuilder result; - result.appendLiteral("@host { \n"); - appendCssTextForItems(result); - result.append('}'); - return result.toString(); -} - -} // namespace WebCore - -#endif // ENABLE(SHADOW_DOM) diff --git a/Source/WebCore/css/CSSHostRule.h b/Source/WebCore/css/CSSHostRule.h deleted file mode 100644 index f3e7dcac7..000000000 --- a/Source/WebCore/css/CSSHostRule.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2006, 2008, 2012 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef CSSHostRule_h -#define CSSHostRule_h - -#include "CSSGroupingRule.h" - -namespace WebCore { - -#if ENABLE(SHADOW_DOM) - -class CSSHostRule : public CSSGroupingRule { -public: - static PassRefPtr create(StyleRuleHost* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSHostRule(rule, sheet)); } - - virtual CSSRule::Type type() const override { return CSSRule::HOST_RULE; } - virtual String cssText() const override; - -private: - CSSHostRule(StyleRuleHost*, CSSStyleSheet*); -}; - -#endif // ENABLE(SHADOW_DOM) - -} // namespace WebCore - -#endif // CSSHostRule_h diff --git a/Source/WebCore/css/CSSHostRule.idl b/Source/WebCore/css/CSSHostRule.idl deleted file mode 100644 index edac345a5..000000000 --- a/Source/WebCore/css/CSSHostRule.idl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -// Introduced in Shadow DOM spec: -[ - Conditional=SHADOW_DOM, -] interface CSSHostRule : CSSRule { - readonly attribute CSSRuleList cssRules; - - [RaisesException] unsigned long insertRule([Default=Undefined] optional DOMString rule, - [Default=Undefined] optional unsigned long index); - [RaisesException] void deleteRule([Default=Undefined] optional unsigned long index); -}; - diff --git a/Source/WebCore/css/CSSImageGeneratorValue.cpp b/Source/WebCore/css/CSSImageGeneratorValue.cpp index 30ca59c3d..3c7c29956 100644 --- a/Source/WebCore/css/CSSImageGeneratorValue.cpp +++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,13 +32,30 @@ #include "CSSFilterImageValue.h" #include "CSSGradientValue.h" #include "CSSImageValue.h" +#include "CSSNamedImageValue.h" #include "GeneratedImage.h" #include "RenderElement.h" #include "StyleCachedImage.h" namespace WebCore { -static const double timeToKeepCachedGeneratedImagesInSeconds = 3; +static const auto timeToKeepCachedGeneratedImages = std::chrono::seconds { 3 }; + +class CSSImageGeneratorValue::CachedGeneratedImage { + WTF_MAKE_FAST_ALLOCATED; +public: + CachedGeneratedImage(CSSImageGeneratorValue&, FloatSize, GeneratedImage&); + GeneratedImage& image() const { return m_image; } + void puntEvictionTimer() { m_evictionTimer.restart(); } + +private: + void evictionTimerFired(); + + CSSImageGeneratorValue& m_owner; + const FloatSize m_size; + const Ref m_image; + DeferrableOneShotTimer m_evictionTimer; +}; CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType classType) : CSSValue(classType) @@ -49,77 +66,75 @@ CSSImageGeneratorValue::~CSSImageGeneratorValue() { } -void CSSImageGeneratorValue::addClient(RenderElement* renderer) +void CSSImageGeneratorValue::addClient(RenderElement& renderer) { - ASSERT(renderer); if (m_clients.isEmpty()) ref(); - m_clients.add(renderer); + m_clients.add(&renderer); } -void CSSImageGeneratorValue::removeClient(RenderElement* renderer) +void CSSImageGeneratorValue::removeClient(RenderElement& renderer) { - ASSERT(renderer); - ASSERT(m_clients.contains(renderer)); - if (m_clients.remove(renderer) && m_clients.isEmpty()) + ASSERT(m_clients.contains(&renderer)); + if (m_clients.remove(&renderer) && m_clients.isEmpty()) deref(); } -GeneratedImage* CSSImageGeneratorValue::cachedImageForSize(IntSize size) +GeneratedImage* CSSImageGeneratorValue::cachedImageForSize(FloatSize size) { if (size.isEmpty()) return nullptr; - CachedGeneratedImage* cachedGeneratedImage = m_images.get(size); + auto* cachedGeneratedImage = m_images.get(size); if (!cachedGeneratedImage) return nullptr; cachedGeneratedImage->puntEvictionTimer(); - return cachedGeneratedImage->image(); + return &cachedGeneratedImage->image(); } -void CSSImageGeneratorValue::saveCachedImageForSize(IntSize size, PassRefPtr image) +void CSSImageGeneratorValue::saveCachedImageForSize(FloatSize size, GeneratedImage& image) { ASSERT(!m_images.contains(size)); m_images.add(size, std::make_unique(*this, size, image)); } -void CSSImageGeneratorValue::evictCachedGeneratedImage(IntSize size) +void CSSImageGeneratorValue::evictCachedGeneratedImage(FloatSize size) { ASSERT(m_images.contains(size)); m_images.remove(size); } -CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage(CSSImageGeneratorValue& owner, IntSize size, PassRefPtr image) +inline CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage(CSSImageGeneratorValue& owner, FloatSize size, GeneratedImage& image) : m_owner(owner) , m_size(size) , m_image(image) - , m_evictionTimer(this, &CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired, timeToKeepCachedGeneratedImagesInSeconds) + , m_evictionTimer(*this, &CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired, timeToKeepCachedGeneratedImages) { m_evictionTimer.restart(); } -void CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired(DeferrableOneShotTimer&) +void CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired() { // NOTE: This is essentially a "delete this", the object is no longer valid after this line. m_owner.evictCachedGeneratedImage(m_size); } -PassRefPtr CSSImageGeneratorValue::image(RenderElement* renderer, const IntSize& size) +RefPtr CSSImageGeneratorValue::image(RenderElement& renderer, const FloatSize& size) { switch (classType()) { case CanvasClass: - return toCSSCanvasValue(this)->image(renderer, size); + return downcast(*this).image(&renderer, size); + case NamedImageClass: + return downcast(*this).image(&renderer, size); case CrossfadeClass: - return toCSSCrossfadeValue(this)->image(renderer, size); -#if ENABLE(CSS_FILTERS) + return downcast(*this).image(renderer, size); case FilterImageClass: - return toCSSFilterImageValue(this)->image(renderer, size); -#endif + return downcast(*this).image(&renderer, size); case LinearGradientClass: - return toCSSLinearGradientValue(this)->image(renderer, size); + return downcast(*this).image(renderer, size); case RadialGradientClass: - return toCSSRadialGradientValue(this)->image(renderer, size); + return downcast(*this).image(renderer, size); default: ASSERT_NOT_REACHED(); } @@ -130,151 +145,140 @@ bool CSSImageGeneratorValue::isFixedSize() const { switch (classType()) { case CanvasClass: - return toCSSCanvasValue(this)->isFixedSize(); + return downcast(*this).isFixedSize(); + case NamedImageClass: + return downcast(*this).isFixedSize(); case CrossfadeClass: - return toCSSCrossfadeValue(this)->isFixedSize(); -#if ENABLE(CSS_FILTERS) + return downcast(*this).isFixedSize(); case FilterImageClass: - return toCSSFilterImageValue(this)->isFixedSize(); -#endif + return downcast(*this).isFixedSize(); case LinearGradientClass: - return toCSSLinearGradientValue(this)->isFixedSize(); + return downcast(*this).isFixedSize(); case RadialGradientClass: - return toCSSRadialGradientValue(this)->isFixedSize(); + return downcast(*this).isFixedSize(); default: ASSERT_NOT_REACHED(); } return false; } -IntSize CSSImageGeneratorValue::fixedSize(const RenderElement* renderer) +FloatSize CSSImageGeneratorValue::fixedSize(const RenderElement& renderer) { switch (classType()) { case CanvasClass: - return toCSSCanvasValue(this)->fixedSize(renderer); + return downcast(*this).fixedSize(&renderer); case CrossfadeClass: - return toCSSCrossfadeValue(this)->fixedSize(renderer); -#if ENABLE(CSS_FILTERS) + return downcast(*this).fixedSize(renderer); case FilterImageClass: - return toCSSFilterImageValue(this)->fixedSize(renderer); -#endif + return downcast(*this).fixedSize(&renderer); case LinearGradientClass: - return toCSSLinearGradientValue(this)->fixedSize(renderer); + return downcast(*this).fixedSize(renderer); case RadialGradientClass: - return toCSSRadialGradientValue(this)->fixedSize(renderer); + return downcast(*this).fixedSize(renderer); default: ASSERT_NOT_REACHED(); } - return IntSize(); + return FloatSize(); } bool CSSImageGeneratorValue::isPending() const { switch (classType()) { case CrossfadeClass: - return toCSSCrossfadeValue(this)->isPending(); + return downcast(*this).isPending(); case CanvasClass: - return toCSSCanvasValue(this)->isPending(); -#if ENABLE(CSS_FILTERS) + return downcast(*this).isPending(); + case NamedImageClass: + return downcast(*this).isPending(); case FilterImageClass: - return toCSSFilterImageValue(this)->isPending(); -#endif + return downcast(*this).isPending(); case LinearGradientClass: - return toCSSLinearGradientValue(this)->isPending(); + return downcast(*this).isPending(); case RadialGradientClass: - return toCSSRadialGradientValue(this)->isPending(); + return downcast(*this).isPending(); default: ASSERT_NOT_REACHED(); } return false; } -bool CSSImageGeneratorValue::knownToBeOpaque(const RenderElement* renderer) const +bool CSSImageGeneratorValue::knownToBeOpaque(const RenderElement& renderer) const { switch (classType()) { case CrossfadeClass: - return toCSSCrossfadeValue(this)->knownToBeOpaque(renderer); + return downcast(*this).knownToBeOpaque(renderer); case CanvasClass: return false; -#if ENABLE(CSS_FILTERS) + case NamedImageClass: + return false; case FilterImageClass: - return toCSSFilterImageValue(this)->knownToBeOpaque(renderer); -#endif + return downcast(*this).knownToBeOpaque(&renderer); case LinearGradientClass: - return toCSSLinearGradientValue(this)->knownToBeOpaque(renderer); + return downcast(*this).knownToBeOpaque(); case RadialGradientClass: - return toCSSRadialGradientValue(this)->knownToBeOpaque(renderer); + return downcast(*this).knownToBeOpaque(); default: ASSERT_NOT_REACHED(); } return false; } -void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader* cachedResourceLoader) +void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { switch (classType()) { case CrossfadeClass: - toCSSCrossfadeValue(this)->loadSubimages(cachedResourceLoader); + downcast(*this).loadSubimages(cachedResourceLoader, options); break; case CanvasClass: - toCSSCanvasValue(this)->loadSubimages(cachedResourceLoader); + downcast(*this).loadSubimages(cachedResourceLoader, options); break; -#if ENABLE(CSS_FILTERS) case FilterImageClass: - toCSSFilterImageValue(this)->loadSubimages(cachedResourceLoader); + downcast(*this).loadSubimages(cachedResourceLoader, options); break; -#endif case LinearGradientClass: - toCSSLinearGradientValue(this)->loadSubimages(cachedResourceLoader); + downcast(*this).loadSubimages(cachedResourceLoader, options); break; case RadialGradientClass: - toCSSRadialGradientValue(this)->loadSubimages(cachedResourceLoader); + downcast(*this).loadSubimages(cachedResourceLoader, options); break; default: ASSERT_NOT_REACHED(); } } -bool CSSImageGeneratorValue::subimageIsPending(CSSValue* value) +bool CSSImageGeneratorValue::subimageIsPending(const CSSValue& value) { - if (value->isImageValue()) - return toCSSImageValue(value)->cachedOrPendingImage()->isPendingImage(); + if (is(value)) + return downcast(value).isPending(); - if (value->isImageGeneratorValue()) - return toCSSImageGeneratorValue(value)->isPending(); + if (is(value)) + return downcast(value).isPending(); - if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNone) + if (is(value) && downcast(value).valueID() == CSSValueNone) return false; ASSERT_NOT_REACHED(); - return false; } -CachedImage* CSSImageGeneratorValue::cachedImageForCSSValue(CSSValue* value, CachedResourceLoader* cachedResourceLoader) +CachedImage* CSSImageGeneratorValue::cachedImageForCSSValue(CSSValue& value, CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options) { - if (!value) - return nullptr; - - if (value->isImageValue()) { - StyleCachedImage* styleCachedImage = toCSSImageValue(value)->cachedImage(cachedResourceLoader); - if (!styleCachedImage) - return nullptr; - - return styleCachedImage->cachedImage(); + if (is(value)) { + auto& imageValue = downcast(value); + return imageValue.loadImage(cachedResourceLoader, options); } - if (value->isImageGeneratorValue()) { - toCSSImageGeneratorValue(value)->loadSubimages(cachedResourceLoader); + if (is(value)) { + downcast(value).loadSubimages(cachedResourceLoader, options); // FIXME: Handle CSSImageGeneratorValue (and thus cross-fades with gradients and canvas). return nullptr; } - if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNone) + if (is(value) && downcast(value).valueID() == CSSValueNone) return nullptr; ASSERT_NOT_REACHED(); - return nullptr; } + } // namespace WebCore diff --git a/Source/WebCore/css/CSSImageGeneratorValue.h b/Source/WebCore/css/CSSImageGeneratorValue.h index 0a6a1b6fd..dc57ea453 100644 --- a/Source/WebCore/css/CSSImageGeneratorValue.h +++ b/Source/WebCore/css/CSSImageGeneratorValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,11 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSImageGeneratorValue_h -#define CSSImageGeneratorValue_h +#pragma once #include "CSSValue.h" -#include "IntSizeHash.h" +#include "FloatSizeHash.h" #include "Timer.h" #include @@ -38,61 +37,46 @@ class CachedResourceLoader; class GeneratedImage; class Image; class RenderElement; -class StyleResolver; + +struct ResourceLoaderOptions; class CSSImageGeneratorValue : public CSSValue { public: ~CSSImageGeneratorValue(); - void addClient(RenderElement*); - void removeClient(RenderElement*); + void addClient(RenderElement&); + void removeClient(RenderElement&); - PassRefPtr image(RenderElement*, const IntSize&); + RefPtr image(RenderElement&, const FloatSize&); bool isFixedSize() const; - IntSize fixedSize(const RenderElement*); + FloatSize fixedSize(const RenderElement&); bool isPending() const; - bool knownToBeOpaque(const RenderElement*) const; + bool knownToBeOpaque(const RenderElement&) const; - void loadSubimages(CachedResourceLoader*); + void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&); protected: CSSImageGeneratorValue(ClassType); - GeneratedImage* cachedImageForSize(IntSize); - void saveCachedImageForSize(IntSize, PassRefPtr); + GeneratedImage* cachedImageForSize(FloatSize); + void saveCachedImageForSize(FloatSize, GeneratedImage&); const HashCountedSet& clients() const { return m_clients; } // Helper functions for Crossfade and Filter. - static CachedImage* cachedImageForCSSValue(CSSValue*, CachedResourceLoader*); - static bool subimageIsPending(CSSValue*); + static CachedImage* cachedImageForCSSValue(CSSValue&, CachedResourceLoader&, const ResourceLoaderOptions&); + static bool subimageIsPending(const CSSValue&); private: - class CachedGeneratedImage { - public: - CachedGeneratedImage(CSSImageGeneratorValue&, IntSize, PassRefPtr); - GeneratedImage* image() { return m_image.get(); } - void puntEvictionTimer() { m_evictionTimer.restart(); } - - private: - void evictionTimerFired(DeferrableOneShotTimer&); + class CachedGeneratedImage; - CSSImageGeneratorValue& m_owner; - IntSize m_size; - RefPtr m_image; - DeferrableOneShotTimer m_evictionTimer; - }; - - friend class CachedGeneratedImage; - void evictCachedGeneratedImage(IntSize); + void evictCachedGeneratedImage(FloatSize); HashCountedSet m_clients; - HashMap> m_images; + HashMap> m_images; }; -CSS_VALUE_TYPE_CASTS(CSSImageGeneratorValue, isImageGeneratorValue()) - } // namespace WebCore -#endif // CSSImageGeneratorValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSImageGeneratorValue, isImageGeneratorValue()) diff --git a/Source/WebCore/css/CSSImageSetValue.cpp b/Source/WebCore/css/CSSImageSetValue.cpp index b031cc2ee..db7c3d726 100644 --- a/Source/WebCore/css/CSSImageSetValue.cpp +++ b/Source/WebCore/css/CSSImageSetValue.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "CSSImageSetValue.h" -#if ENABLE(CSS_IMAGE_SET) - #include "CSSImageValue.h" #include "CSSPrimitiveValue.h" #include "CachedImage.h" @@ -37,31 +35,17 @@ #include "CrossOriginAccessControl.h" #include "Document.h" #include "Page.h" -#include "StyleCachedImageSet.h" -#include "StylePendingImage.h" #include namespace WebCore { CSSImageSetValue::CSSImageSetValue() : CSSValueList(ImageSetClass, CommaSeparator) - , m_accessedBestFitImage(false) - , m_scaleFactor(1) -{ -} - -inline void CSSImageSetValue::detachPendingImage() { - if (m_imageSet && m_imageSet->isPendingImage()) - static_cast(*m_imageSet).detachFromCSSValue(); } CSSImageSetValue::~CSSImageSetValue() { - detachPendingImage(); - - if (m_imageSet && m_imageSet->isCachedImageSet()) - static_cast(m_imageSet.get())->clearImageSetValue(); } void CSSImageSetValue::fillImageSet() @@ -70,13 +54,12 @@ void CSSImageSetValue::fillImageSet() size_t i = 0; while (i < length) { CSSValue* imageValue = item(i); - String imageURL = toCSSImageValue(imageValue)->url(); + String imageURL = downcast(*imageValue).url(); ++i; ASSERT_WITH_SECURITY_IMPLICATION(i < length); CSSValue* scaleFactorValue = item(i); - ASSERT_WITH_SECURITY_IMPLICATION(scaleFactorValue->isPrimitiveValue()); - float scaleFactor = toCSSPrimitiveValue(scaleFactorValue)->getFloatValue(); + float scaleFactor = downcast(*scaleFactorValue).floatValue(); ImageWithScale image; image.imageURL = imageURL; @@ -91,76 +74,58 @@ void CSSImageSetValue::fillImageSet() CSSImageSetValue::ImageWithScale CSSImageSetValue::bestImageForScaleFactor() { + if (!m_imagesInSet.size()) + fillImageSet(); + ImageWithScale image; size_t numberOfImages = m_imagesInSet.size(); for (size_t i = 0; i < numberOfImages; ++i) { image = m_imagesInSet.at(i); - if (image.scaleFactor >= m_scaleFactor) + if (image.scaleFactor >= m_deviceScaleFactor) return image; } return image; } -StyleCachedImageSet* CSSImageSetValue::cachedImageSet(CachedResourceLoader* loader, const ResourceLoaderOptions& options) +std::pair CSSImageSetValue::loadBestFitImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options) { - ASSERT(loader); - - Document* document = loader->document(); - if (Page* page = document->page()) - m_scaleFactor = page->deviceScaleFactor(); - else - m_scaleFactor = 1; + Document* document = loader.document(); + ASSERT(document); - if (!m_imagesInSet.size()) - fillImageSet(); + updateDeviceScaleFactor(*document); if (!m_accessedBestFitImage) { - // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here. + m_accessedBestFitImage = true; + + // FIXME: In the future, we want to take much more than deviceScaleFactor into acount here. // All forms of scale should be included: Page::pageScaleFactor(), Frame::pageZoomFactor(), // and any CSS transforms. https://bugs.webkit.org/show_bug.cgi?id=81698 ImageWithScale image = bestImageForScaleFactor(); CachedResourceRequest request(ResourceRequest(document->completeURL(image.imageURL)), options); request.setInitiator(cachedResourceRequestInitiators().css); - if (options.requestOriginPolicy == PotentiallyCrossOriginEnabled) - updateRequestForAccessControl(request.mutableResourceRequest(), document->securityOrigin(), options.allowCredentials); - if (CachedResourceHandle cachedImage = loader->requestImage(request)) { - detachPendingImage(); - m_imageSet = StyleCachedImageSet::create(cachedImage.get(), image.scaleFactor, this); - m_accessedBestFitImage = true; - } - } + if (options.mode == FetchOptions::Mode::Cors) + request.updateForAccessControl(*document); - return (m_imageSet && m_imageSet->isCachedImageSet()) ? static_cast(m_imageSet.get()) : 0; + m_cachedImage = loader.requestImage(WTFMove(request)); + m_bestFitImageScaleFactor = image.scaleFactor; + } + return { m_cachedImage.get(), m_bestFitImageScaleFactor }; } -StyleCachedImageSet* CSSImageSetValue::cachedImageSet(CachedResourceLoader* loader) +void CSSImageSetValue::updateDeviceScaleFactor(const Document& document) { - return cachedImageSet(loader, CachedResourceLoader::defaultCachedResourceOptions()); -} - -StyleImage* CSSImageSetValue::cachedOrPendingImageSet(Document& document) -{ - if (!m_imageSet) - m_imageSet = StylePendingImage::create(this); - else if (!m_imageSet->isPendingImage()) { - float deviceScaleFactor = 1; - if (Page* page = document.page()) - deviceScaleFactor = page->deviceScaleFactor(); - - // If the deviceScaleFactor has changed, we may not have the best image loaded, so we have to re-assess. - if (deviceScaleFactor != m_scaleFactor) { - m_accessedBestFitImage = false; - m_imageSet = StylePendingImage::create(this); - } - } - - return m_imageSet.get(); + float deviceScaleFactor = document.page() ? document.page()->deviceScaleFactor() : 1; + if (deviceScaleFactor == m_deviceScaleFactor) + return; + m_deviceScaleFactor = deviceScaleFactor; + m_accessedBestFitImage = false; + m_cachedImage = nullptr; } String CSSImageSetValue::customCSSText() const { StringBuilder result; - result.appendLiteral("-webkit-image-set("); + result.appendLiteral("image-set("); size_t length = this->length(); size_t i = 0; @@ -187,29 +152,11 @@ String CSSImageSetValue::customCSSText() const return result.toString(); } -bool CSSImageSetValue::hasFailedOrCanceledSubresources() const +bool CSSImageSetValue::traverseSubresources(const std::function& handler) const { - if (!m_imageSet || !m_imageSet->isCachedImageSet()) + if (!m_cachedImage) return false; - CachedResource* cachedResource = static_cast(m_imageSet.get())->cachedImage(); - if (!cachedResource) - return true; - return cachedResource->loadFailedOrCanceled(); -} - -CSSImageSetValue::CSSImageSetValue(const CSSImageSetValue& cloneFrom) - : CSSValueList(cloneFrom) - , m_accessedBestFitImage(false) - , m_scaleFactor(1) -{ - // Non-CSSValueList data is not accessible through CSS OM, no need to clone. -} - -PassRefPtr CSSImageSetValue::cloneForCSSOM() const -{ - return adoptRef(new CSSImageSetValue(*this)); + return handler(*m_cachedImage); } } // namespace WebCore - -#endif // ENABLE(CSS_IMAGE_SET) diff --git a/Source/WebCore/css/CSSImageSetValue.h b/Source/WebCore/css/CSSImageSetValue.h index c1899f3ab..d6f09b171 100644 --- a/Source/WebCore/css/CSSImageSetValue.h +++ b/Source/WebCore/css/CSSImageSetValue.h @@ -23,74 +23,57 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSImageSetValue_h -#define CSSImageSetValue_h - -#if ENABLE(CSS_IMAGE_SET) +#pragma once #include "CSSValueList.h" +#include "CachedImageClient.h" +#include "CachedResourceHandle.h" namespace WebCore { class CachedResourceLoader; class Document; -class StyleCachedImageSet; -class StyleImage; struct ResourceLoaderOptions; -class CSSImageSetValue : public CSSValueList { +class CSSImageSetValue final : public CSSValueList { public: - - static PassRef create() + static Ref create() { return adoptRef(*new CSSImageSetValue()); } ~CSSImageSetValue(); - StyleCachedImageSet* cachedImageSet(CachedResourceLoader*, const ResourceLoaderOptions&); - StyleCachedImageSet* cachedImageSet(CachedResourceLoader*); - - // Returns a StyleCachedImageSet if the best fit image has been cached already, otherwise a StylePendingImage. - StyleImage* cachedOrPendingImageSet(Document&); + std::pair loadBestFitImage(CachedResourceLoader&, const ResourceLoaderOptions&); + CachedImage* cachedImage() const { return m_cachedImage.get(); } String customCSSText() const; - bool isPending() const { return !m_accessedBestFitImage; } - struct ImageWithScale { String imageURL; float scaleFactor; }; - bool hasFailedOrCanceledSubresources() const; + bool traverseSubresources(const std::function& handler) const; - PassRefPtr cloneForCSSOM() const; + void updateDeviceScaleFactor(const Document&); protected: ImageWithScale bestImageForScaleFactor(); private: CSSImageSetValue(); - CSSImageSetValue(const CSSImageSetValue& cloneFrom); - void detachPendingImage(); void fillImageSet(); static inline bool compareByScaleFactor(ImageWithScale first, ImageWithScale second) { return first.scaleFactor < second.scaleFactor; } - RefPtr m_imageSet; - bool m_accessedBestFitImage; - - // This represents the scale factor that we used to find the best fit image. It does not necessarily - // correspond to the scale factor of the best fit image. - float m_scaleFactor; + CachedResourceHandle m_cachedImage; + bool m_accessedBestFitImage { false }; + float m_bestFitImageScaleFactor { 1 }; + float m_deviceScaleFactor { 1 }; Vector m_imagesInSet; }; -CSS_VALUE_TYPE_CASTS(CSSImageSetValue, isImageSetValue()) - } // namespace WebCore -#endif // ENABLE(CSS_IMAGE_SET) - -#endif // CSSImageSetValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSImageSetValue, isImageSetValue()) diff --git a/Source/WebCore/css/CSSImageValue.cpp b/Source/WebCore/css/CSSImageValue.cpp index 544025719..1430c89b0 100644 --- a/Source/WebCore/css/CSSImageValue.cpp +++ b/Source/WebCore/css/CSSImageValue.cpp @@ -22,93 +22,70 @@ #include "CSSImageValue.h" #include "CSSCursorImageValue.h" -#include "CSSParser.h" +#include "CSSMarkup.h" +#include "CSSPrimitiveValue.h" #include "CSSValueKeywords.h" #include "CachedImage.h" #include "CachedResourceLoader.h" #include "CachedResourceRequest.h" #include "CachedResourceRequestInitiators.h" #include "CrossOriginAccessControl.h" +#include "DeprecatedCSSOMPrimitiveValue.h" #include "Document.h" #include "Element.h" -#include "MemoryCache.h" -#include "StyleCachedImage.h" -#include "StylePendingImage.h" namespace WebCore { -CSSImageValue::CSSImageValue(const String& url) +CSSImageValue::CSSImageValue(URL&& url) : CSSValue(ImageClass) - , m_url(url) + , m_url(WTFMove(url)) , m_accessedImage(false) { } -CSSImageValue::CSSImageValue(const String& url, StyleImage* image) +CSSImageValue::CSSImageValue(CachedImage& image) : CSSValue(ImageClass) - , m_url(url) - , m_image(image) + , m_url(image.url()) + , m_cachedImage(&image) , m_accessedImage(true) { } -inline void CSSImageValue::detachPendingImage() -{ - if (m_image && m_image->isPendingImage()) - static_cast(*m_image).detachFromCSSValue(); -} CSSImageValue::~CSSImageValue() { - detachPendingImage(); } -StyleImage* CSSImageValue::cachedOrPendingImage() +bool CSSImageValue::isPending() const { - if (!m_image) - m_image = StylePendingImage::create(this); - - return m_image.get(); + return !m_accessedImage; } -StyleCachedImage* CSSImageValue::cachedImage(CachedResourceLoader* loader, const ResourceLoaderOptions& options) +CachedImage* CSSImageValue::loadImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options) { - ASSERT(loader); - if (!m_accessedImage) { m_accessedImage = true; - CachedResourceRequest request(ResourceRequest(loader->document()->completeURL(m_url)), options); + CachedResourceRequest request(ResourceRequest(loader.document()->completeURL(m_url.string())), options); if (m_initiatorName.isEmpty()) request.setInitiator(cachedResourceRequestInitiators().css); else request.setInitiator(m_initiatorName); - if (options.requestOriginPolicy == PotentiallyCrossOriginEnabled) - updateRequestForAccessControl(request.mutableResourceRequest(), loader->document()->securityOrigin(), options.allowCredentials); - - if (CachedResourceHandle cachedImage = loader->requestImage(request)) { - detachPendingImage(); - m_image = StyleCachedImage::create(cachedImage.get()); + if (options.mode == FetchOptions::Mode::Cors) { + ASSERT(loader.document()); + request.updateForAccessControl(*loader.document()); } + m_cachedImage = loader.requestImage(WTFMove(request)); } - - return (m_image && m_image->isCachedImage()) ? static_cast(m_image.get()) : 0; + return m_cachedImage.get(); } -StyleCachedImage* CSSImageValue::cachedImage(CachedResourceLoader* loader) +bool CSSImageValue::traverseSubresources(const std::function& handler) const { - return cachedImage(loader, CachedResourceLoader::defaultCachedResourceOptions()); -} - -bool CSSImageValue::hasFailedOrCanceledSubresources() const -{ - if (!m_image || !m_image->isCachedImage()) + if (!m_cachedImage) return false; - CachedResource* cachedResource = static_cast(m_image.get())->cachedImage(); - if (!cachedResource) - return true; - return cachedResource->loadFailedOrCanceled(); + return handler(*m_cachedImage); } bool CSSImageValue::equals(const CSSImageValue& other) const @@ -118,20 +95,20 @@ bool CSSImageValue::equals(const CSSImageValue& other) const String CSSImageValue::customCSSText() const { - return "url(" + quoteCSSURLIfNeeded(m_url) + ')'; + return serializeURL(m_url); } -PassRefPtr CSSImageValue::cloneForCSSOM() const +Ref CSSImageValue::createDeprecatedCSSOMWrapper() const { // NOTE: We expose CSSImageValues as URI primitive values in CSSOM to maintain old behavior. - RefPtr uriValue = CSSPrimitiveValue::create(m_url, CSSPrimitiveValue::CSS_URI); - uriValue->setCSSOMSafe(); - return uriValue.release(); + return DeprecatedCSSOMPrimitiveValue::create(CSSPrimitiveValue::create(m_url, CSSPrimitiveValue::CSS_URI)); } bool CSSImageValue::knownToBeOpaque(const RenderElement* renderer) const { - return m_image ? m_image->knownToBeOpaque(renderer) : false; + if (!m_cachedImage) + return false; + return m_cachedImage->currentFrameKnownToBeOpaque(renderer); } } // namespace WebCore diff --git a/Source/WebCore/css/CSSImageValue.h b/Source/WebCore/css/CSSImageValue.h index 9cc8bc3e4..48581945b 100644 --- a/Source/WebCore/css/CSSImageValue.h +++ b/Source/WebCore/css/CSSImageValue.h @@ -18,39 +18,37 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSImageValue_h -#define CSSImageValue_h +#pragma once #include "CSSValue.h" -#include +#include "CachedResourceHandle.h" +#include namespace WebCore { +class CachedImage; class CachedResourceLoader; -class Element; -class StyleCachedImage; -class StyleImage; +class DeprecatedCSSOMValue; class RenderElement; struct ResourceLoaderOptions; -class CSSImageValue : public CSSValue { +class CSSImageValue final : public CSSValue { public: - static PassRef create(const String& url) { return adoptRef(*new CSSImageValue(url)); } - static PassRef create(const String& url, StyleImage* image) { return adoptRef(*new CSSImageValue(url, image)); } + static Ref create(URL&& url) { return adoptRef(*new CSSImageValue(WTFMove(url))); } + static Ref create(CachedImage& image) { return adoptRef(*new CSSImageValue(image)); } ~CSSImageValue(); - StyleCachedImage* cachedImage(CachedResourceLoader*, const ResourceLoaderOptions&); - StyleCachedImage* cachedImage(CachedResourceLoader*); - // Returns a StyleCachedImage if the image is cached already, otherwise a StylePendingImage. - StyleImage* cachedOrPendingImage(); + bool isPending() const; + CachedImage* loadImage(CachedResourceLoader&, const ResourceLoaderOptions&); + CachedImage* cachedImage() const { return m_cachedImage.get(); } - const String& url() const { return m_url; } + const URL& url() const { return m_url; } String customCSSText() const; - PassRefPtr cloneForCSSOM() const; + Ref createDeprecatedCSSOMWrapper() const; - bool hasFailedOrCanceledSubresources() const; + bool traverseSubresources(const std::function& handler) const; bool equals(const CSSImageValue&) const; @@ -59,18 +57,15 @@ public: void setInitiator(const AtomicString& name) { m_initiatorName = name; } private: - explicit CSSImageValue(const String& url); - CSSImageValue(const String& url, StyleImage*); - void detachPendingImage(); + explicit CSSImageValue(URL&&); + explicit CSSImageValue(CachedImage&); - String m_url; - RefPtr m_image; + URL m_url; + CachedResourceHandle m_cachedImage; bool m_accessedImage; AtomicString m_initiatorName; }; -CSS_VALUE_TYPE_CASTS(CSSImageValue, isImageValue()) - } // namespace WebCore -#endif // CSSImageValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSImageValue, isImageValue()) diff --git a/Source/WebCore/css/CSSImportRule.cpp b/Source/WebCore/css/CSSImportRule.cpp index 5e68cc72f..af6856574 100644 --- a/Source/WebCore/css/CSSImportRule.cpp +++ b/Source/WebCore/css/CSSImportRule.cpp @@ -25,16 +25,14 @@ #include "CSSStyleSheet.h" #include "CachedCSSStyleSheet.h" #include "CachedResourceLoader.h" -#include "Document.h" #include "MediaList.h" -#include "SecurityOrigin.h" #include "StyleRuleImport.h" #include "StyleSheetContents.h" #include namespace WebCore { -CSSImportRule::CSSImportRule(StyleRuleImport* importRule, CSSStyleSheet* parent) +CSSImportRule::CSSImportRule(StyleRuleImport& importRule, CSSStyleSheet* parent) : CSSRule(parent) , m_importRule(importRule) { @@ -50,25 +48,25 @@ CSSImportRule::~CSSImportRule() String CSSImportRule::href() const { - return m_importRule->href(); + return m_importRule.get().href(); } -MediaList* CSSImportRule::media() const +MediaList& CSSImportRule::media() const { if (!m_mediaCSSOMWrapper) - m_mediaCSSOMWrapper = MediaList::create(m_importRule->mediaQueries(), const_cast(this)); - return m_mediaCSSOMWrapper.get(); + m_mediaCSSOMWrapper = MediaList::create(m_importRule.get().mediaQueries(), const_cast(this)); + return *m_mediaCSSOMWrapper; } String CSSImportRule::cssText() const { StringBuilder result; result.appendLiteral("@import url(\""); - result.append(m_importRule->href()); + result.append(m_importRule.get().href()); result.appendLiteral("\")"); - if (m_importRule->mediaQueries()) { - String mediaText = m_importRule->mediaQueries()->mediaText(); + if (m_importRule.get().mediaQueries()) { + String mediaText = m_importRule.get().mediaQueries()->mediaText(); if (!mediaText.isEmpty()) { result.append(' '); result.append(mediaText); @@ -81,15 +79,15 @@ String CSSImportRule::cssText() const CSSStyleSheet* CSSImportRule::styleSheet() const { - if (!m_importRule->styleSheet()) + if (!m_importRule.get().styleSheet()) return 0; if (!m_styleSheetCSSOMWrapper) - m_styleSheetCSSOMWrapper = CSSStyleSheet::create(*m_importRule->styleSheet(), const_cast(this)); + m_styleSheetCSSOMWrapper = CSSStyleSheet::create(*m_importRule.get().styleSheet(), const_cast(this)); return m_styleSheetCSSOMWrapper.get(); } -void CSSImportRule::reattach(StyleRuleBase*) +void CSSImportRule::reattach(StyleRuleBase&) { // FIXME: Implement when enabling caching for stylesheets with import rules. ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/css/CSSImportRule.h b/Source/WebCore/css/CSSImportRule.h index 83122b34a..2b1f66d31 100644 --- a/Source/WebCore/css/CSSImportRule.h +++ b/Source/WebCore/css/CSSImportRule.h @@ -19,40 +19,37 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSImportRule_h -#define CSSImportRule_h +#pragma once #include "CSSRule.h" namespace WebCore { -class CachedCSSStyleSheet; class MediaList; -class MediaQuerySet; class StyleRuleImport; -class CSSImportRule : public CSSRule { +class CSSImportRule final : public CSSRule { public: - static PassRefPtr create(StyleRuleImport* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSImportRule(rule, sheet)); } - - virtual ~CSSImportRule(); + static Ref create(StyleRuleImport& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSImportRule(rule, sheet)); } - virtual CSSRule::Type type() const override { return IMPORT_RULE; } - virtual String cssText() const override; - virtual void reattach(StyleRuleBase*) override; + virtual ~CSSImportRule(); - String href() const; - MediaList* media() const; - CSSStyleSheet* styleSheet() const; + WEBCORE_EXPORT String href() const; + WEBCORE_EXPORT MediaList& media() const; + WEBCORE_EXPORT CSSStyleSheet* styleSheet() const; private: - CSSImportRule(StyleRuleImport*, CSSStyleSheet*); + CSSImportRule(StyleRuleImport&, CSSStyleSheet*); + + CSSRule::Type type() const final { return IMPORT_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; - RefPtr m_importRule; + Ref m_importRule; mutable RefPtr m_mediaCSSOMWrapper; mutable RefPtr m_styleSheetCSSOMWrapper; }; } // namespace WebCore -#endif // CSSImportRule_h +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSImportRule, CSSRule::IMPORT_RULE) diff --git a/Source/WebCore/css/CSSImportRule.idl b/Source/WebCore/css/CSSImportRule.idl index d1d76abca..f56ef9fc0 100644 --- a/Source/WebCore/css/CSSImportRule.idl +++ b/Source/WebCore/css/CSSImportRule.idl @@ -20,7 +20,7 @@ // Introduced in DOM Level 2: interface CSSImportRule : CSSRule { - [TreatReturnedNullStringAs=Null] readonly attribute DOMString href; + readonly attribute DOMString? href; readonly attribute MediaList media; readonly attribute CSSStyleSheet styleSheet; }; diff --git a/Source/WebCore/css/CSSInheritedValue.h b/Source/WebCore/css/CSSInheritedValue.h index f6d168eea..8f9253de7 100644 --- a/Source/WebCore/css/CSSInheritedValue.h +++ b/Source/WebCore/css/CSSInheritedValue.h @@ -18,34 +18,32 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSInheritedValue_h -#define CSSInheritedValue_h +#pragma once #include "CSSValue.h" -#include +#include namespace WebCore { -class CSSInheritedValue : public CSSValue { +class CSSInheritedValue final : public CSSValue { public: - static PassRef create() - { - return adoptRef(*new CSSInheritedValue); - } - String customCSSText() const; bool equals(const CSSInheritedValue&) const { return true; } +#if COMPILER(MSVC) + // FIXME: This should be private, but for some reason MSVC then fails to invoke it from LazyNeverDestroyed::construct. +public: +#else private: + friend class LazyNeverDestroyed; +#endif CSSInheritedValue() : CSSValue(InheritedClass) { } }; -CSS_VALUE_TYPE_CASTS(CSSInheritedValue, isInheritedValue()) - } // namespace WebCore -#endif // CSSInheritedValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSInheritedValue, isInheritedValue()) diff --git a/Source/WebCore/css/CSSInitialValue.h b/Source/WebCore/css/CSSInitialValue.h index a0a6e5548..c4161515e 100644 --- a/Source/WebCore/css/CSSInitialValue.h +++ b/Source/WebCore/css/CSSInitialValue.h @@ -18,21 +18,20 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSInitialValue_h -#define CSSInitialValue_h +#pragma once #include "CSSValue.h" -#include +#include namespace WebCore { -class CSSInitialValue : public CSSValue { +class CSSInitialValue final : public CSSValue { public: - static PassRef createExplicit() + static Ref createExplicit() { return adoptRef(*new CSSInitialValue(/* implicit */ false)); } - static PassRef createImplicit() + static Ref createImplicit() { return adoptRef(*new CSSInitialValue(/* implicit */ true)); } @@ -43,18 +42,23 @@ public: bool equals(const CSSInitialValue&) const { return true; } +#if COMPILER(MSVC) + // FIXME: This should be private, but for some reason MSVC then fails to invoke it from LazyNeverDestroyed::construct. +public: +#else private: + friend class LazyNeverDestroyed; +#endif CSSInitialValue(bool implicit) : CSSValue(InitialClass) , m_isImplicit(implicit) { } +private: bool m_isImplicit; }; -CSS_VALUE_TYPE_CASTS(CSSInitialValue, isInitialValue()) - } // namespace WebCore -#endif // CSSInitialValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSInitialValue, isInitialValue()) diff --git a/Source/WebCore/css/CSSKeyframeRule.cpp b/Source/WebCore/css/CSSKeyframeRule.cpp new file mode 100644 index 000000000..c3f9a2263 --- /dev/null +++ b/Source/WebCore/css/CSSKeyframeRule.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007, 2008, 2012, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSKeyframeRule.h" + +#include "CSSKeyframesRule.h" +#include "PropertySetCSSStyleDeclaration.h" +#include "StyleProperties.h" +#include + +namespace WebCore { + +StyleRuleKeyframe::StyleRuleKeyframe(Ref&& properties) + : StyleRuleBase(Keyframe) + , m_properties(WTFMove(properties)) +{ +} + +StyleRuleKeyframe::StyleRuleKeyframe(std::unique_ptr> keys, Ref&& properties) + : StyleRuleBase(Keyframe) + , m_properties(WTFMove(properties)) + , m_keys(*keys) +{ +} + +StyleRuleKeyframe::~StyleRuleKeyframe() +{ +} + +MutableStyleProperties& StyleRuleKeyframe::mutableProperties() +{ + if (!is(m_properties.get())) + m_properties = m_properties->mutableCopy(); + return downcast(m_properties.get()); +} + +String StyleRuleKeyframe::keyText() const +{ + StringBuilder keyText; + + for (size_t i = 0; i < m_keys.size(); ++i) { + if (i) + keyText.append(','); + keyText.appendNumber(m_keys.at(i) * 100); + keyText.append('%'); + } + + return keyText.toString(); +} + +bool StyleRuleKeyframe::setKeyText(const String& keyText) +{ + ASSERT(!keyText.isNull()); + auto keys = CSSParser::parseKeyframeKeyList(keyText); + if (!keys || keys->isEmpty()) + return false; + m_keys = *keys; + return true; +} + +String StyleRuleKeyframe::cssText() const +{ + StringBuilder result; + result.append(keyText()); + result.appendLiteral(" { "); + String decls = m_properties->asText(); + result.append(decls); + if (!decls.isEmpty()) + result.append(' '); + result.append('}'); + return result.toString(); +} + +CSSKeyframeRule::CSSKeyframeRule(StyleRuleKeyframe& keyframe, CSSKeyframesRule* parent) + : CSSRule(0) + , m_keyframe(keyframe) +{ + setParentRule(parent); +} + +CSSKeyframeRule::~CSSKeyframeRule() +{ + if (m_propertiesCSSOMWrapper) + m_propertiesCSSOMWrapper->clearParentRule(); +} + +CSSStyleDeclaration& CSSKeyframeRule::style() +{ + if (!m_propertiesCSSOMWrapper) + m_propertiesCSSOMWrapper = StyleRuleCSSStyleDeclaration::create(m_keyframe->mutableProperties(), *this); + return *m_propertiesCSSOMWrapper; +} + +void CSSKeyframeRule::reattach(StyleRuleBase&) +{ + // No need to reattach, the underlying data is shareable on mutation. + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSKeyframeRule.h b/Source/WebCore/css/CSSKeyframeRule.h new file mode 100644 index 000000000..866c6c48c --- /dev/null +++ b/Source/WebCore/css/CSSKeyframeRule.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2007, 2008, 2012, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSParser.h" +#include "CSSRule.h" +#include "StyleProperties.h" +#include "StyleRule.h" + +namespace WebCore { + +class CSSStyleDeclaration; +class StyleRuleCSSStyleDeclaration; +class CSSKeyframesRule; + +class StyleRuleKeyframe final : public StyleRuleBase { +public: + static Ref create(Ref&& properties) + { + return adoptRef(*new StyleRuleKeyframe(WTFMove(properties))); + } + + static Ref create(std::unique_ptr> keys, Ref&& properties) + { + return adoptRef(*new StyleRuleKeyframe(WTFMove(keys), WTFMove(properties))); + } + ~StyleRuleKeyframe(); + + String keyText() const; + bool setKeyText(const String&); + void setKey(double key) + { + ASSERT(m_keys.isEmpty()); + m_keys.clear(); + m_keys.append(key); + } + + const Vector& keys() const { return m_keys; }; + + const StyleProperties& properties() const { return m_properties; } + MutableStyleProperties& mutableProperties(); + + String cssText() const; + +private: + explicit StyleRuleKeyframe(Ref&&); + StyleRuleKeyframe(std::unique_ptr>, Ref&&); + + Ref m_properties; + Vector m_keys; +}; + +class CSSKeyframeRule final : public CSSRule { +public: + virtual ~CSSKeyframeRule(); + + String cssText() const final { return m_keyframe->cssText(); } + void reattach(StyleRuleBase&) final; + + String keyText() const { return m_keyframe->keyText(); } + void setKeyText(const String& text) { m_keyframe->setKeyText(text); } + + CSSStyleDeclaration& style(); + +private: + CSSKeyframeRule(StyleRuleKeyframe&, CSSKeyframesRule* parent); + + CSSRule::Type type() const final { return KEYFRAME_RULE; } + + Ref m_keyframe; + mutable RefPtr m_propertiesCSSOMWrapper; + + friend class CSSKeyframesRule; +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSKeyframeRule.idl b/Source/WebCore/css/CSSKeyframeRule.idl new file mode 100644 index 000000000..e3b8b861f --- /dev/null +++ b/Source/WebCore/css/CSSKeyframeRule.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Introduced in DOM Level ?: +interface CSSKeyframeRule : CSSRule { + + attribute DOMString keyText; + readonly attribute CSSStyleDeclaration style; + +}; + diff --git a/Source/WebCore/css/CSSKeyframesRule.cpp b/Source/WebCore/css/CSSKeyframesRule.cpp new file mode 100644 index 000000000..51ad8b8f0 --- /dev/null +++ b/Source/WebCore/css/CSSKeyframesRule.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2007, 2008, 2012, 2013, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSKeyframesRule.h" + +#include "CSSDeferredParser.h" +#include "CSSKeyframeRule.h" +#include "CSSParser.h" +#include "CSSRuleList.h" +#include "CSSStyleSheet.h" +#include "Document.h" +#include "StyleProperties.h" +#include "StyleSheet.h" +#include + +namespace WebCore { + +StyleRuleKeyframes::StyleRuleKeyframes(const AtomicString& name) + : StyleRuleBase(Keyframes) + , m_name(name) +{ +} + +StyleRuleKeyframes::StyleRuleKeyframes(const AtomicString& name, std::unique_ptr&& deferredRules) + : StyleRuleBase(Keyframes) + , m_name(name) + , m_deferredRules(WTFMove(deferredRules)) +{ + +} + +StyleRuleKeyframes::StyleRuleKeyframes(const StyleRuleKeyframes& o) + : StyleRuleBase(o) + , m_name(o.m_name) +{ + m_keyframes.reserveInitialCapacity(o.keyframes().size()); + for (auto& keyframe : o.keyframes()) + m_keyframes.uncheckedAppend(keyframe.copyRef()); +} + +StyleRuleKeyframes::~StyleRuleKeyframes() +{ +} + +void StyleRuleKeyframes::parseDeferredRulesIfNeeded() const +{ + if (!m_deferredRules) + return; + + m_deferredRules->parseDeferredKeyframes(const_cast(*this)); + m_deferredRules = nullptr; +} + +const Vector>& StyleRuleKeyframes::keyframes() const +{ + parseDeferredRulesIfNeeded(); + return m_keyframes; +} + +void StyleRuleKeyframes::parserAppendKeyframe(RefPtr&& keyframe) +{ + if (!keyframe) + return; + m_keyframes.append(keyframe.releaseNonNull()); +} + +void StyleRuleKeyframes::wrapperAppendKeyframe(Ref&& keyframe) +{ + parseDeferredRulesIfNeeded(); + m_keyframes.append(WTFMove(keyframe)); +} + +void StyleRuleKeyframes::wrapperRemoveKeyframe(unsigned index) +{ + parseDeferredRulesIfNeeded(); + m_keyframes.remove(index); +} + +size_t StyleRuleKeyframes::findKeyframeIndex(const String& key) const +{ + parseDeferredRulesIfNeeded(); + + auto keys = CSSParser::parseKeyframeKeyList(key); + + if (!keys) + return notFound; + + for (size_t i = m_keyframes.size(); i--; ) { + if (m_keyframes[i]->keys() == *keys) + return i; + } + + return notFound; +} + +CSSKeyframesRule::CSSKeyframesRule(StyleRuleKeyframes& keyframesRule, CSSStyleSheet* parent) + : CSSRule(parent) + , m_keyframesRule(keyframesRule) + , m_childRuleCSSOMWrappers(keyframesRule.keyframes().size()) +{ +} + +CSSKeyframesRule::~CSSKeyframesRule() +{ + ASSERT(m_childRuleCSSOMWrappers.size() == m_keyframesRule->keyframes().size()); + + for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) { + if (m_childRuleCSSOMWrappers[i]) + m_childRuleCSSOMWrappers[i]->setParentRule(0); + } +} + +void CSSKeyframesRule::setName(const String& name) +{ + CSSStyleSheet::RuleMutationScope mutationScope(this); + + m_keyframesRule->setName(name); +} + +void CSSKeyframesRule::appendRule(const String& ruleText) +{ + ASSERT(m_childRuleCSSOMWrappers.size() == m_keyframesRule->keyframes().size()); + + CSSParser parser(parserContext()); + RefPtr keyframe = parser.parseKeyframeRule(ruleText); + if (!keyframe) + return; + + CSSStyleSheet::RuleMutationScope mutationScope(this); + + m_keyframesRule->wrapperAppendKeyframe(keyframe.releaseNonNull()); + + m_childRuleCSSOMWrappers.grow(length()); +} + +void CSSKeyframesRule::insertRule(const String& ruleText) +{ + if (CSSStyleSheet* parent = parentStyleSheet()) { + if (Document* ownerDocument = parent->ownerDocument()) + ownerDocument->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("CSSKeyframesRule 'insertRule' function is deprecated. Use 'appendRule' instead.")); + } + appendRule(ruleText); +} + +void CSSKeyframesRule::deleteRule(const String& s) +{ + ASSERT(m_childRuleCSSOMWrappers.size() == m_keyframesRule->keyframes().size()); + + size_t i = m_keyframesRule->findKeyframeIndex(s); + if (i == notFound) + return; + + CSSStyleSheet::RuleMutationScope mutationScope(this); + + m_keyframesRule->wrapperRemoveKeyframe(i); + + if (m_childRuleCSSOMWrappers[i]) + m_childRuleCSSOMWrappers[i]->setParentRule(0); + m_childRuleCSSOMWrappers.remove(i); +} + +CSSKeyframeRule* CSSKeyframesRule::findRule(const String& s) +{ + size_t i = m_keyframesRule->findKeyframeIndex(s); + return i != notFound ? item(i) : nullptr; +} + +String CSSKeyframesRule::cssText() const +{ + StringBuilder result; + result.appendLiteral("@-webkit-keyframes "); + result.append(name()); + result.appendLiteral(" { \n"); + + unsigned size = length(); + for (unsigned i = 0; i < size; ++i) { + result.appendLiteral(" "); + result.append(m_keyframesRule->keyframes()[i]->cssText()); + result.append('\n'); + } + result.append('}'); + return result.toString(); +} + +unsigned CSSKeyframesRule::length() const +{ + return m_keyframesRule->keyframes().size(); +} + +CSSKeyframeRule* CSSKeyframesRule::item(unsigned index) const +{ + if (index >= length()) + return nullptr; + ASSERT(m_childRuleCSSOMWrappers.size() == m_keyframesRule->keyframes().size()); + auto& rule = m_childRuleCSSOMWrappers[index]; + if (!rule) + rule = adoptRef(*new CSSKeyframeRule(m_keyframesRule->keyframes()[index], const_cast(this))); + return rule.get(); +} + +CSSRuleList& CSSKeyframesRule::cssRules() +{ + if (!m_ruleListCSSOMWrapper) + m_ruleListCSSOMWrapper = std::make_unique>(*this); + return *m_ruleListCSSOMWrapper; +} + +void CSSKeyframesRule::reattach(StyleRuleBase& rule) +{ + ASSERT_WITH_SECURITY_IMPLICATION(rule.isKeyframesRule()); + m_keyframesRule = static_cast(rule); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSKeyframesRule.h b/Source/WebCore/css/CSSKeyframesRule.h new file mode 100644 index 000000000..dd075957e --- /dev/null +++ b/Source/WebCore/css/CSSKeyframesRule.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2007, 2008, 2012, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSRule.h" +#include "StyleRule.h" +#include +#include +#include + +namespace WebCore { + +class CSSRuleList; +class StyleRuleKeyframe; +class CSSKeyframeRule; + +class StyleRuleKeyframes final : public StyleRuleBase { +public: + static Ref create(const AtomicString& name) { return adoptRef(*new StyleRuleKeyframes(name)); } + static Ref create(const AtomicString& name, std::unique_ptr&& deferredRules) { return adoptRef(*new StyleRuleKeyframes(name, WTFMove(deferredRules))); } + + ~StyleRuleKeyframes(); + + const Vector>& keyframes() const; + const Vector>* keyframesWithoutDeferredParsing() const + { + return !m_deferredRules ? &m_keyframes : nullptr; + } + + void parserAppendKeyframe(RefPtr&&); + void wrapperAppendKeyframe(Ref&&); + void wrapperRemoveKeyframe(unsigned); + + const AtomicString& name() const { return m_name; } + void setName(const AtomicString& name) { m_name = name; } + + size_t findKeyframeIndex(const String& key) const; + + Ref copy() const { return adoptRef(*new StyleRuleKeyframes(*this)); } + +private: + StyleRuleKeyframes(const AtomicString&); + StyleRuleKeyframes(const AtomicString&, std::unique_ptr&&); + StyleRuleKeyframes(const StyleRuleKeyframes&); + + void parseDeferredRulesIfNeeded() const; + + mutable Vector> m_keyframes; + AtomicString m_name; + + mutable std::unique_ptr m_deferredRules; +}; + +class CSSKeyframesRule final : public CSSRule { +public: + static Ref create(StyleRuleKeyframes& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSKeyframesRule(rule, sheet)); } + + virtual ~CSSKeyframesRule(); + + CSSRule::Type type() const final { return KEYFRAMES_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; + + String name() const { return m_keyframesRule->name(); } + void setName(const String&); + + CSSRuleList& cssRules(); + + void insertRule(const String& rule); + void appendRule(const String& rule); + void deleteRule(const String& key); + CSSKeyframeRule* findRule(const String& key); + + // For IndexedGetter and CSSRuleList. + unsigned length() const; + CSSKeyframeRule* item(unsigned index) const; + +private: + CSSKeyframesRule(StyleRuleKeyframes&, CSSStyleSheet* parent); + + Ref m_keyframesRule; + mutable Vector> m_childRuleCSSOMWrappers; + mutable std::unique_ptr m_ruleListCSSOMWrapper; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSKeyframesRule, CSSRule::KEYFRAMES_RULE) + +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::StyleRuleKeyframes) + static bool isType(const WebCore::StyleRuleBase& rule) { return rule.isKeyframesRule(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/css/CSSKeyframesRule.idl b/Source/WebCore/css/CSSKeyframesRule.idl new file mode 100644 index 000000000..1a2f547e3 --- /dev/null +++ b/Source/WebCore/css/CSSKeyframesRule.idl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +interface CSSKeyframesRule : CSSRule { + attribute DOMString name; + readonly attribute CSSRuleList cssRules; + + void insertRule(DOMString rule); + void appendRule(DOMString rule); + void deleteRule(DOMString key); + CSSKeyframeRule? findRule(DOMString key); + + getter CSSKeyframeRule (unsigned long index); +}; + diff --git a/Source/WebCore/css/CSSLineBoxContainValue.cpp b/Source/WebCore/css/CSSLineBoxContainValue.cpp index 07fb17a3f..19fdf8b97 100644 --- a/Source/WebCore/css/CSSLineBoxContainValue.cpp +++ b/Source/WebCore/css/CSSLineBoxContainValue.cpp @@ -67,6 +67,11 @@ String CSSLineBoxContainValue::customCSSText() const text.append(' '); text.appendLiteral("inline-box"); } + if (m_value & LineBoxContainInitialLetter) { + if (!text.isEmpty()) + text.append(' '); + text.appendLiteral("initial-letter"); + } return text.toString(); } diff --git a/Source/WebCore/css/CSSLineBoxContainValue.h b/Source/WebCore/css/CSSLineBoxContainValue.h index fa3aefd50..248b2337e 100644 --- a/Source/WebCore/css/CSSLineBoxContainValue.h +++ b/Source/WebCore/css/CSSLineBoxContainValue.h @@ -23,11 +23,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSLineBoxContainValue_h -#define CSSLineBoxContainValue_h +#pragma once #include "CSSValue.h" -#include #include namespace WebCore { @@ -35,13 +33,13 @@ namespace WebCore { class CSSPrimitiveValue; enum LineBoxContainFlags { LineBoxContainNone = 0x0, LineBoxContainBlock = 0x1, LineBoxContainInline = 0x2, LineBoxContainFont = 0x4, LineBoxContainGlyphs = 0x8, - LineBoxContainReplaced = 0x10, LineBoxContainInlineBox = 0x20 }; + LineBoxContainReplaced = 0x10, LineBoxContainInlineBox = 0x20, LineBoxContainInitialLetter = 0x40 }; typedef unsigned LineBoxContain; // Used for text-CSSLineBoxContain and box-CSSLineBoxContain -class CSSLineBoxContainValue : public CSSValue { +class CSSLineBoxContainValue final : public CSSValue { public: - static PassRef create(LineBoxContain value) + static Ref create(LineBoxContain value) { return adoptRef(*new CSSLineBoxContainValue(value)); } @@ -56,8 +54,6 @@ private: LineBoxContain m_value; }; -CSS_VALUE_TYPE_CASTS(CSSLineBoxContainValue, isLineBoxContainValue()) +} // namespace WebCore -} // namespace - -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSLineBoxContainValue, isLineBoxContainValue()) diff --git a/Source/WebCore/css/CSSMarkup.cpp b/Source/WebCore/css/CSSMarkup.cpp new file mode 100644 index 000000000..81fe8886b --- /dev/null +++ b/Source/WebCore/css/CSSMarkup.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) + * Copyright (C) 2004-2012, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Nicholas Shanks + * Copyright (C) 2008 Eric Seidel + * 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 Intel Corporation. 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "CSSMarkup.h" + +#include "CSSParserIdioms.h" +#include +#include +#include + +namespace WebCore { + +template +static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length) +{ + const CharacterType* end = characters + length; + + // -? + if (characters != end && characters[0] == '-') + ++characters; + + // {nmstart} + if (characters == end || !isNameStartCodePoint(characters[0])) + return false; + ++characters; + + // {nmchar}* + for (; characters != end; ++characters) { + if (!isNameCodePoint(characters[0])) + return false; + } + + return true; +} + +// "ident" from the CSS tokenizer, minus backslash-escape sequences +static bool isCSSTokenizerIdentifier(const String& string) +{ + unsigned length = string.length(); + + if (!length) + return false; + + if (string.is8Bit()) + return isCSSTokenizerIdentifier(string.characters8(), length); + return isCSSTokenizerIdentifier(string.characters16(), length); +} + +static void serializeCharacter(UChar32 c, StringBuilder& appendTo) +{ + appendTo.append('\\'); + appendTo.append(c); +} + +static void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo) +{ + appendTo.append('\\'); + appendUnsignedAsHex(c, appendTo, Lowercase); + appendTo.append(' '); +} + +void serializeIdentifier(const String& identifier, StringBuilder& appendTo, bool skipStartChecks) +{ + bool isFirst = !skipStartChecks; + bool isSecond = false; + bool isFirstCharHyphen = false; + unsigned index = 0; + while (index < identifier.length()) { + UChar32 c = identifier.characterStartingAt(index); + if (!c) { + // Check for lone surrogate which characterStartingAt does not return. + c = identifier[index]; + } + + index += U16_LENGTH(c); + + if (!c) + appendTo.append(0xfffd); + else if (c <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen)))) + serializeCharacterAsCodePoint(c, appendTo); + else if (c == 0x2d && isFirst && index == identifier.length()) + serializeCharacter(c, appendTo); + else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a)) + appendTo.append(c); + else + serializeCharacter(c, appendTo); + + if (isFirst) { + isFirst = false; + isSecond = true; + isFirstCharHyphen = (c == 0x2d); + } else if (isSecond) + isSecond = false; + } +} + +template +static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length) +{ + const CharacterType* end = characters + length; + + for (; characters != end; ++characters) { + CharacterType c = characters[0]; + switch (c) { + case '!': + case '#': + case '$': + case '%': + case '&': + break; + default: + if (c < '*') + return false; + if (c <= '~') + break; + if (c < 128) + return false; + } + } + + return true; +} + +// "url" from the CSS tokenizer, minus backslash-escape sequences +static bool isCSSTokenizerURL(const String& string) +{ + unsigned length = string.length(); + + if (!length) + return true; + + if (string.is8Bit()) + return isCSSTokenizerURL(string.characters8(), length); + return isCSSTokenizerURL(string.characters16(), length); +} + +void serializeString(const String& string, StringBuilder& appendTo) +{ + // FIXME: From the CSS OM draft: + // To serialize a string means to create a string represented by '"' (U+0022). + // We need to switch to using " instead of ', but this involves patching a large + // number of tests and changing editing code to not get confused by double quotes. + appendTo.append('"'); + + unsigned index = 0; + while (index < string.length()) { + UChar32 c = string.characterStartingAt(index); + index += U16_LENGTH(c); + + if (c <= 0x1f || c == 0x7f) + serializeCharacterAsCodePoint(c, appendTo); + else if (c == 0x22 || c == 0x5c) + serializeCharacter(c, appendTo); + else + appendTo.append(c); + } + + appendTo.append('"'); +} + +String serializeString(const String& string) +{ + StringBuilder builder; + serializeString(string, builder); + return builder.toString(); +} + +String serializeURL(const String& string) +{ + // FIXME: URLS must always be double quoted. From the CSS OM draft: + // To serialize a URL means to create a string represented by "url(", followed by + // the serialization of the URL as a string, followed by ")". + // To keep backwards compatibility with existing tests, for now we only quote if needed and + // we use a single quote. + return "url(" + (isCSSTokenizerURL(string) ? string : serializeString(string)) + ")"; +} + +String serializeAsStringOrCustomIdent(const String& string) +{ + if (isCSSTokenizerIdentifier(string)) { + StringBuilder builder; + serializeIdentifier(string, builder); + return builder.toString(); + } + return serializeString(string); +} + +String serializeFontFamily(const String& string) +{ + return isCSSTokenizerIdentifier(string) ? string : serializeString(string); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSMarkup.h b/Source/WebCore/css/CSSMarkup.h new file mode 100644 index 000000000..9873b40ea --- /dev/null +++ b/Source/WebCore/css/CSSMarkup.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004-2008, 2009-2010, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2008 Eric Seidel + * Copyright (C) 2009 - 2010 Torch Mobile (Beijing) Co. Ltd. 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +// Helper functions for converting from CSSValues to text. + +namespace WebCore { + +// Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms +void serializeIdentifier(const String& identifier, StringBuilder& appendTo, bool skipStartChecks = false); +void serializeString(const String&, StringBuilder& appendTo); +String serializeString(const String&); +String serializeURL(const String&); +String serializeFontFamily(const String&); + +// FIXME-NEWPARSER: This hybrid "check for both string or ident" function can be removed +// once we have enabled CSSCustomIdentValue and CSSStringValue. +String serializeAsStringOrCustomIdent(const String&); + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSMediaRule.cpp b/Source/WebCore/css/CSSMediaRule.cpp index 13fdd6cf8..3954df041 100644 --- a/Source/WebCore/css/CSSMediaRule.cpp +++ b/Source/WebCore/css/CSSMediaRule.cpp @@ -1,7 +1,7 @@ /** * (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2005, 2006, 2012 Apple Computer, Inc. + * Copyright (C) 2002, 2005, 2006, 2012 Apple Inc. * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) * * This library is free software; you can redistribute it and/or @@ -26,13 +26,13 @@ #include "CSSParser.h" #include "CSSRuleList.h" #include "CSSStyleSheet.h" -#include "ExceptionCode.h" +#include "MediaList.h" #include "StyleRule.h" #include namespace WebCore { -CSSMediaRule::CSSMediaRule(StyleRuleMedia* mediaRule, CSSStyleSheet* parent) +CSSMediaRule::CSSMediaRule(StyleRuleMedia& mediaRule, CSSStyleSheet* parent) : CSSGroupingRule(mediaRule, parent) { } @@ -45,13 +45,13 @@ CSSMediaRule::~CSSMediaRule() MediaQuerySet* CSSMediaRule::mediaQueries() const { - return toStyleRuleMedia(m_groupRule.get())->mediaQueries(); + return downcast(m_groupRule.get()).mediaQueries(); } String CSSMediaRule::cssText() const { StringBuilder result; - result.append("@media "); + result.appendLiteral("@media "); if (mediaQueries()) { result.append(mediaQueries()->mediaText()); result.append(' '); @@ -65,13 +65,13 @@ String CSSMediaRule::cssText() const MediaList* CSSMediaRule::media() const { if (!mediaQueries()) - return 0; + return nullptr; if (!m_mediaCSSOMWrapper) m_mediaCSSOMWrapper = MediaList::create(mediaQueries(), const_cast(this)); return m_mediaCSSOMWrapper.get(); } -void CSSMediaRule::reattach(StyleRuleBase* rule) +void CSSMediaRule::reattach(StyleRuleBase& rule) { CSSGroupingRule::reattach(rule); if (m_mediaCSSOMWrapper && mediaQueries()) diff --git a/Source/WebCore/css/CSSMediaRule.h b/Source/WebCore/css/CSSMediaRule.h index aeea9d29d..2160faca9 100644 --- a/Source/WebCore/css/CSSMediaRule.h +++ b/Source/WebCore/css/CSSMediaRule.h @@ -20,30 +20,30 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSMediaRule_h -#define CSSMediaRule_h +#pragma once #include "CSSGroupingRule.h" -#include "MediaList.h" namespace WebCore { +class MediaList; +class MediaQuerySet; class StyleRuleMedia; -class CSSMediaRule : public CSSGroupingRule { +class CSSMediaRule final : public CSSGroupingRule { public: - static PassRefPtr create(StyleRuleMedia* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSMediaRule(rule, sheet)); } + static Ref create(StyleRuleMedia& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSMediaRule(rule, sheet)); } virtual ~CSSMediaRule(); - virtual CSSRule::Type type() const override { return MEDIA_RULE; } - virtual void reattach(StyleRuleBase*) override; - virtual String cssText() const override; - - MediaList* media() const; + WEBCORE_EXPORT MediaList* media() const; private: - CSSMediaRule(StyleRuleMedia*, CSSStyleSheet*); + CSSMediaRule(StyleRuleMedia&, CSSStyleSheet*); + + CSSRule::Type type() const final { return MEDIA_RULE; } + void reattach(StyleRuleBase&) final; + String cssText() const final; MediaQuerySet* mediaQueries() const; @@ -52,4 +52,4 @@ private: } // namespace WebCore -#endif // CSSMediaRule_h +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSMediaRule, CSSRule::MEDIA_RULE) diff --git a/Source/WebCore/css/CSSMediaRule.idl b/Source/WebCore/css/CSSMediaRule.idl index 38aeef293..cf2155511 100644 --- a/Source/WebCore/css/CSSMediaRule.idl +++ b/Source/WebCore/css/CSSMediaRule.idl @@ -18,13 +18,10 @@ * Boston, MA 02110-1301, USA. */ -// Introduced in DOM Level 2: interface CSSMediaRule : CSSRule { readonly attribute MediaList media; readonly attribute CSSRuleList cssRules; - - [ObjCLegacyUnnamedParameters, RaisesException] unsigned long insertRule([Default=Undefined] optional DOMString rule, - [Default=Undefined] optional unsigned long index); - [RaisesException] void deleteRule([Default=Undefined] optional unsigned long index); -}; + [MayThrowException] unsigned long insertRule(optional DOMString rule = "undefined", optional unsigned long index = 0); + [MayThrowException] void deleteRule(optional unsigned long index = 0); +}; diff --git a/Source/WebCore/css/CSSNamedImageValue.cpp b/Source/WebCore/css/CSSNamedImageValue.cpp new file mode 100644 index 000000000..870012d0d --- /dev/null +++ b/Source/WebCore/css/CSSNamedImageValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSNamedImageValue.h" + +#include "ImageBuffer.h" +#include "NamedImageGeneratedImage.h" + +namespace WebCore { + +String CSSNamedImageValue::customCSSText() const +{ + return makeString("-webkit-named-image(", m_name, ')'); +} + +RefPtr CSSNamedImageValue::image(RenderElement*, const FloatSize& size) +{ + if (size.isEmpty()) + return nullptr; + + return NamedImageGeneratedImage::create(m_name, size); +} + +bool CSSNamedImageValue::equals(const CSSNamedImageValue& other) const +{ + return m_name == other.m_name; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSNamedImageValue.h b/Source/WebCore/css/CSSNamedImageValue.h new file mode 100644 index 000000000..2bc28bad1 --- /dev/null +++ b/Source/WebCore/css/CSSNamedImageValue.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSImageGeneratorValue.h" +#include "Image.h" + +namespace WebCore { + +class CSSNamedImageValue final : public CSSImageGeneratorValue { +public: + static Ref create(const String& name) + { + return adoptRef(*new CSSNamedImageValue(name)); + } + + String customCSSText() const; + + bool isFixedSize() const { return false; } + bool isPending() const { return false; } + + RefPtr image(RenderElement*, const FloatSize&); + + bool equals(const CSSNamedImageValue&) const; + +private: + explicit CSSNamedImageValue(const String& name) + : CSSImageGeneratorValue(NamedImageClass) + , m_name(name) + { + } + + String m_name; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSNamedImageValue, isNamedImageValue()) diff --git a/Source/WebCore/css/CSSNamespaceRule.cpp b/Source/WebCore/css/CSSNamespaceRule.cpp new file mode 100644 index 000000000..4a88ee9c5 --- /dev/null +++ b/Source/WebCore/css/CSSNamespaceRule.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSNamespaceRule.h" + +#include "CSSMarkup.h" +#include "StyleRule.h" +#include + +namespace WebCore { + +CSSNamespaceRule::CSSNamespaceRule(StyleRuleNamespace& namespaceRule, CSSStyleSheet* parent) + : CSSRule(parent) + , m_namespaceRule(namespaceRule) +{ +} + +CSSNamespaceRule::~CSSNamespaceRule() +{ +} + +AtomicString CSSNamespaceRule::namespaceURI() const +{ + return m_namespaceRule->uri(); +} + +AtomicString CSSNamespaceRule::prefix() const +{ + return m_namespaceRule->prefix(); +} + +String CSSNamespaceRule::cssText() const +{ + StringBuilder result; + result.appendLiteral("@namespace "); + serializeIdentifier(prefix(), result); + if (!prefix().isEmpty()) + result.append(' '); + result.append("url("); + result.append(serializeString(namespaceURI())); + result.append(");"); + return result.toString(); +} + +void CSSNamespaceRule::reattach(StyleRuleBase&) +{ +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSNamespaceRule.h b/Source/WebCore/css/CSSNamespaceRule.h new file mode 100644 index 000000000..cd7004321 --- /dev/null +++ b/Source/WebCore/css/CSSNamespaceRule.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSRule.h" + +namespace WebCore { + +class StyleRuleNamespace; + +class CSSNamespaceRule final : public CSSRule { +public: + static Ref create(StyleRuleNamespace& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSNamespaceRule(rule, sheet)); } + + virtual ~CSSNamespaceRule(); + + AtomicString namespaceURI() const; + AtomicString prefix() const; + +private: + CSSNamespaceRule(StyleRuleNamespace&, CSSStyleSheet*); + + CSSRule::Type type() const final { return NAMESPACE_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; + + Ref m_namespaceRule; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSNamespaceRule, CSSRule::NAMESPACE_RULE) diff --git a/Source/WebCore/css/CSSNamespaceRule.idl b/Source/WebCore/css/CSSNamespaceRule.idl new file mode 100644 index 000000000..83b2ac9cf --- /dev/null +++ b/Source/WebCore/css/CSSNamespaceRule.idl @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2016 Apple Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface + +interface CSSNamespaceRule : CSSRule { + + readonly attribute DOMString namespaceURI; + readonly attribute DOMString prefix; + +}; diff --git a/Source/WebCore/css/CSSOMUtils.cpp b/Source/WebCore/css/CSSOMUtils.cpp deleted file mode 100644 index e763bfe67..000000000 --- a/Source/WebCore/css/CSSOMUtils.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "CSSOMUtils.h" - -#include -#include - -namespace WebCore { - -void serializeCharacter(UChar32 c, StringBuilder& appendTo) -{ - appendTo.append('\\'); - appendTo.append(c); -} - -void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo) -{ - appendTo.append('\\'); - appendUnsignedAsHex(c, appendTo, Lowercase); - appendTo.append(' '); -} - -void serializeIdentifier(const String& identifier, String& appendTo) -{ - StringBuilder addend; - serializeIdentifier(identifier, addend); - appendTo.append(addend.toString()); -} - -void serializeIdentifier(const String& identifier, StringBuilder& appendTo) -{ - bool isFirst = true; - bool isSecond = false; - bool isFirstCharHyphen = false; - unsigned index = 0; - while (index < identifier.length()) { - UChar32 c = identifier.characterStartingAt(index); - index += U16_LENGTH(c); - - if (c <= 0x1f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen)))) - serializeCharacterAsCodePoint(c, appendTo); - else if (c == 0x2d && isSecond && isFirstCharHyphen) - serializeCharacter(c, appendTo); - else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a)) - appendTo.append(c); - else - serializeCharacter(c, appendTo); - - if (isFirst) { - isFirst = false; - isSecond = true; - isFirstCharHyphen = (c == 0x2d); - } else if (isSecond) { - isSecond = false; - } - } -} - -void serializeString(const String& string, String& appendTo) -{ - StringBuilder addend; - serializeString(string, addend); - appendTo.append(addend.toString()); -} - -void serializeString(const String& string, StringBuilder& appendTo) -{ - appendTo.append('\"'); - - unsigned index = 0; - while (index < string.length()) { - UChar32 c = string.characterStartingAt(index); - index += U16_LENGTH(c); - if (c <= 0x1f) - serializeCharacterAsCodePoint(c, appendTo); - else if (c == 0x22 || c == 0x5c) - serializeCharacter(c, appendTo); - else - appendTo.append(c); - } - - appendTo.append('\"'); -} - -} // namespace WebCore diff --git a/Source/WebCore/css/CSSOMUtils.h b/Source/WebCore/css/CSSOMUtils.h deleted file mode 100644 index 878669c37..000000000 --- a/Source/WebCore/css/CSSOMUtils.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CSSOMUtils_h -#define CSSOMUtils_h - -#include -#include -#include - -// Utilities for CSSOM http://dev.w3.org/csswg/cssom/ - -namespace WebCore { - -// Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms -void serializeCharacter(UChar32, StringBuilder& appendTo); -void serializeCharacterAsCodePoint(UChar32, StringBuilder& appendTo); -void serializeIdentifier(const String& identifier, String& appendTo); -void serializeIdentifier(const String& identifier, StringBuilder& appendTo); -void serializeString(const String&, String& appendTo); -void serializeString(const String&, StringBuilder& appendTo); - -} // namespace WebCore - -#endif // CSSOMUtils_h diff --git a/Source/WebCore/css/CSSPageRule.cpp b/Source/WebCore/css/CSSPageRule.cpp index 4895e8b20..e1012b04c 100644 --- a/Source/WebCore/css/CSSPageRule.cpp +++ b/Source/WebCore/css/CSSPageRule.cpp @@ -29,12 +29,11 @@ #include "PropertySetCSSStyleDeclaration.h" #include "StyleProperties.h" #include "StyleRule.h" -#include #include namespace WebCore { -CSSPageRule::CSSPageRule(StyleRulePage* pageRule, CSSStyleSheet* parent) +CSSPageRule::CSSPageRule(StyleRulePage& pageRule, CSSStyleSheet* parent) : CSSRule(parent) , m_pageRule(pageRule) { @@ -46,11 +45,11 @@ CSSPageRule::~CSSPageRule() m_propertiesCSSOMWrapper->clearParentRule(); } -CSSStyleDeclaration* CSSPageRule::style() +CSSStyleDeclaration& CSSPageRule::style() { if (!m_propertiesCSSOMWrapper) m_propertiesCSSOMWrapper = StyleRuleCSSStyleDeclaration::create(m_pageRule->mutableProperties(), *this); - return m_propertiesCSSOMWrapper.get(); + return *m_propertiesCSSOMWrapper; } String CSSPageRule::selectorText() const @@ -94,13 +93,11 @@ String CSSPageRule::cssText() const return result.toString(); } -void CSSPageRule::reattach(StyleRuleBase* rule) +void CSSPageRule::reattach(StyleRuleBase& rule) { - ASSERT(rule); - ASSERT_WITH_SECURITY_IMPLICATION(rule->isPageRule()); - m_pageRule = static_cast(rule); + m_pageRule = downcast(rule); if (m_propertiesCSSOMWrapper) - m_propertiesCSSOMWrapper->reattach(m_pageRule->mutableProperties()); + m_propertiesCSSOMWrapper->reattach(m_pageRule.get().mutableProperties()); } } // namespace WebCore diff --git a/Source/WebCore/css/CSSPageRule.h b/Source/WebCore/css/CSSPageRule.h index a4439b646..442bcd79d 100644 --- a/Source/WebCore/css/CSSPageRule.h +++ b/Source/WebCore/css/CSSPageRule.h @@ -19,8 +19,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSPageRule_h -#define CSSPageRule_h +#pragma once #include "CSSRule.h" @@ -31,28 +30,26 @@ class CSSStyleSheet; class StyleRulePage; class StyleRuleCSSStyleDeclaration; -class CSSPageRule : public CSSRule { +class CSSPageRule final : public CSSRule { public: - static PassRefPtr create(StyleRulePage* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSPageRule(rule, sheet)); } + static Ref create(StyleRulePage& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSPageRule(rule, sheet)); } virtual ~CSSPageRule(); - virtual CSSRule::Type type() const override { return PAGE_RULE; } - virtual String cssText() const override; - virtual void reattach(StyleRuleBase*) override; + WEBCORE_EXPORT CSSStyleDeclaration& style(); - CSSStyleDeclaration* style(); - - String selectorText() const; - void setSelectorText(const String&); + WEBCORE_EXPORT String selectorText() const; + WEBCORE_EXPORT void setSelectorText(const String&); private: - CSSPageRule(StyleRulePage*, CSSStyleSheet*); - - RefPtr m_pageRule; + CSSPageRule(StyleRulePage&, CSSStyleSheet*); + + CSSRule::Type type() const final { return PAGE_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; + + Ref m_pageRule; mutable RefPtr m_propertiesCSSOMWrapper; }; } // namespace WebCore - -#endif // CSSPageRule_h diff --git a/Source/WebCore/css/CSSPageRule.idl b/Source/WebCore/css/CSSPageRule.idl index e9e49d096..0132df0d5 100644 --- a/Source/WebCore/css/CSSPageRule.idl +++ b/Source/WebCore/css/CSSPageRule.idl @@ -20,10 +20,8 @@ // Introduced in DOM Level 2: interface CSSPageRule : CSSRule { - - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString] attribute DOMString selectorText; + attribute DOMString? selectorText; readonly attribute CSSStyleDeclaration style; - }; diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp deleted file mode 100644 index 837d0a2e0..000000000 --- a/Source/WebCore/css/CSSParser.cpp +++ /dev/null @@ -1,12338 +0,0 @@ -/* - * 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, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2007 Nicholas Shanks - * Copyright (C) 2008 Eric Seidel - * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) - * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2012 Intel Corporation. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "CSSParser.h" - -#include "CSSAspectRatioValue.h" -#include "CSSBasicShapes.h" -#include "CSSBorderImage.h" -#include "CSSCanvasValue.h" -#include "CSSCrossfadeValue.h" -#include "CSSCursorImageValue.h" -#include "CSSFilterImageValue.h" -#include "CSSFontFaceRule.h" -#include "CSSFontFaceSrcValue.h" -#include "CSSFontFeatureValue.h" -#include "CSSFontValue.h" -#include "CSSFunctionValue.h" -#include "CSSGradientValue.h" -#include "CSSGridTemplateValue.h" -#include "CSSImageValue.h" -#include "CSSInheritedValue.h" -#include "CSSInitialValue.h" -#include "CSSLineBoxContainValue.h" -#include "CSSMediaRule.h" -#include "CSSPageRule.h" -#include "CSSPrimitiveValue.h" -#include "CSSPropertySourceData.h" -#include "CSSReflectValue.h" -#include "CSSSelector.h" -#include "CSSShadowValue.h" -#include "CSSStyleSheet.h" -#include "CSSTimingFunctionValue.h" -#include "CSSUnicodeRangeValue.h" -#include "CSSValueKeywords.h" -#include "CSSValueList.h" -#include "CSSValuePool.h" -#include "Counter.h" -#include "Document.h" -#include "FloatConversion.h" -#include "HTMLParserIdioms.h" -#include "HashTools.h" -#include "HistogramSupport.h" -#include "MediaList.h" -#include "MediaQueryExp.h" -#include "Page.h" -#include "PageConsole.h" -#include "Pair.h" -#include "Rect.h" -#include "RenderTheme.h" -#include "RuntimeEnabledFeatures.h" -#include "SVGParserUtilities.h" -#include "Settings.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 "WebKitCSSRegionRule.h" -#include "WebKitCSSTransformValue.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#if ENABLE(CSS_IMAGE_SET) -#include "CSSImageSetValue.h" -#endif - -#if ENABLE(CSS_FILTERS) -#include "WebKitCSSFilterValue.h" -#endif - -#if ENABLE(DASHBOARD_SUPPORT) -#include "DashboardRegion.h" -#endif - -#define YYDEBUG 0 - -#if YYDEBUG > 0 -extern int cssyydebug; -#endif - -extern int cssyyparse(WebCore::CSSParser*); - -using namespace WTF; - -namespace { - -enum PropertyType { - PropertyExplicit, - PropertyImplicit -}; - -class ImplicitScope { - WTF_MAKE_NONCOPYABLE(ImplicitScope); -public: - ImplicitScope(WebCore::CSSParser* parser, PropertyType propertyType) - : m_parser(parser) - { - m_parser->m_implicitShorthand = propertyType == PropertyImplicit; - } - - ~ImplicitScope() - { - m_parser->m_implicitShorthand = false; - } - -private: - WebCore::CSSParser* m_parser; -}; - -} // namespace - -namespace WebCore { - -static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; -static const double MAX_SCALE = 1000000; - -template -static bool equal(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::equal(a.characters8(), reinterpret_cast(b), length) : WTF::equal(a.characters16(), reinterpret_cast(b), length); -} - -template -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 -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); -} - -static bool hasPrefix(const char* string, unsigned length, const char* prefix) -{ - for (unsigned i = 0; i < length; ++i) { - if (!prefix[i]) - return true; - if (string[i] != prefix[i]) - return false; - } - return false; -} - -static PassRefPtr createPrimitiveValuePair(PassRefPtr first, PassRefPtr second) -{ - return cssValuePool().createValue(Pair::create(first, second)); -} - -class AnimationParseContext { -public: - AnimationParseContext() - : m_animationPropertyKeywordAllowed(true) - , m_firstAnimationCommitted(false) - , m_hasSeenAnimationPropertyKeyword(false) - { - } - - void commitFirstAnimation() - { - m_firstAnimationCommitted = true; - } - - bool hasCommittedFirstAnimation() const - { - return m_firstAnimationCommitted; - } - - void commitAnimationPropertyKeyword() - { - m_animationPropertyKeywordAllowed = false; - } - - bool animationPropertyKeywordAllowed() const - { - return m_animationPropertyKeywordAllowed; - } - - bool hasSeenAnimationPropertyKeyword() const - { - return m_hasSeenAnimationPropertyKeyword; - } - - void sawAnimationPropertyKeyword() - { - m_hasSeenAnimationPropertyKeyword = true; - } - -private: - bool m_animationPropertyKeywordAllowed; - bool m_firstAnimationCommitted; - bool m_hasSeenAnimationPropertyKeyword; -}; - -const CSSParserContext& strictCSSParserContext() -{ - DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (CSSStrictMode)); - return strictContext; -} - -CSSParserContext::CSSParserContext(CSSParserMode mode, const URL& baseURL) - : baseURL(baseURL) - , mode(mode) - , isHTMLDocument(false) - , isCSSStickyPositionEnabled(false) - , isCSSRegionsEnabled(false) - , isCSSCompositingEnabled(false) - , isCSSGridLayoutEnabled(false) - , 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: - // Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView - needsSiteSpecificQuirks = true; -#endif -} - -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()) - , isCSSStickyPositionEnabled(document.cssStickyPositionEnabled()) - , isCSSRegionsEnabled(document.cssRegionsEnabled()) - , isCSSCompositingEnabled(document.cssCompositingEnabled()) - , isCSSGridLayoutEnabled(document.cssGridLayoutEnabled()) - , 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: - // Investigate Enabling Site Specific Quirks in MobileSafari and UIWebView - needsSiteSpecificQuirks = true; -#endif -} - -bool operator==(const CSSParserContext& a, const CSSParserContext& b) -{ - return a.baseURL == b.baseURL - && a.charset == b.charset - && a.mode == b.mode - && a.isHTMLDocument == b.isHTMLDocument - && a.isCSSStickyPositionEnabled == b.isCSSStickyPositionEnabled - && a.isCSSRegionsEnabled == b.isCSSRegionsEnabled - && a.isCSSCompositingEnabled == b.isCSSCompositingEnabled - && a.isCSSGridLayoutEnabled == b.isCSSGridLayoutEnabled - && a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks - && a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode - && a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior; -} - -CSSParser::CSSParser(const CSSParserContext& context) - : m_context(context) - , m_important(false) - , m_id(CSSPropertyInvalid) - , m_styleSheet(0) -#if ENABLE(CSS3_CONDITIONAL_RULES) - , m_supportsCondition(false) -#endif - , m_selectorListForParseSelector(0) - , 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) - , m_defaultNamespace(starAtom) - , m_parsedTextPrefixLength(0) - , m_propertyRange(UINT_MAX, UINT_MAX) - , m_ruleSourceDataResult(0) - , m_parsingMode(NormalMode) - , m_is8BitSource(false) - , m_currentCharacter8(0) - , m_currentCharacter16(0) - , m_length(0) - , m_token(0) - , m_lineNumber(0) - , m_tokenStartLineNumber(0) - , m_lastSelectorLineNumber(0) - , m_allowImportRules(true) - , m_allowNamespaceDeclarations(true) -#if ENABLE(CSS_DEVICE_ADAPTATION) - , m_inViewport(false) -#endif -{ -#if YYDEBUG > 0 - cssyydebug = 1; -#endif - m_tokenStart.ptr8 = 0; -} - -CSSParser::~CSSParser() -{ - clearProperties(); -} - -template -ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, 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++) { - ASSERT(u_tolower(input[i]) <= 0xFFFF); - output[i] = u_tolower(input[i]); - } - } -} - -void CSSParserString::lower() -{ - if (is8Bit()) { - makeLower(characters8(), characters8(), length()); - return; - } - - makeLower(characters16(), characters16(), length()); -} - -void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength) -{ - m_parsedTextPrefixLength = prefixLength; - unsigned stringLength = string.length(); - unsigned length = stringLength + m_parsedTextPrefixLength + suffixLength + 1; - m_length = length; - - if (!stringLength || string.is8Bit()) { - m_dataStart8 = std::make_unique(length); - for (unsigned i = 0; i < m_parsedTextPrefixLength; i++) - m_dataStart8[i] = prefix[i]; - - if (stringLength) - memcpy(m_dataStart8.get() + m_parsedTextPrefixLength, string.characters8(), stringLength * sizeof(LChar)); - - unsigned start = m_parsedTextPrefixLength + stringLength; - unsigned end = start + suffixLength; - for (unsigned i = start; i < end; i++) - m_dataStart8[i] = suffix[i - start]; - - m_dataStart8[length - 1] = 0; - - m_is8BitSource = true; - m_currentCharacter8 = m_dataStart8.get(); - m_currentCharacter16 = 0; - setTokenStart(m_currentCharacter8); - m_lexFunc = &CSSParser::realLex; - return; - } - - m_dataStart16 = std::make_unique(length); - for (unsigned i = 0; i < m_parsedTextPrefixLength; i++) - m_dataStart16[i] = prefix[i]; - - ASSERT(stringLength); - memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters16(), stringLength * sizeof(UChar)); - - unsigned start = m_parsedTextPrefixLength + stringLength; - unsigned end = start + suffixLength; - for (unsigned i = start; i < end; i++) - m_dataStart16[i] = suffix[i - start]; - - m_dataStart16[length - 1] = 0; - - m_is8BitSource = false; - m_currentCharacter8 = 0; - m_currentCharacter16 = m_dataStart16.get(); - setTokenStart(m_currentCharacter16); - m_lexFunc = &CSSParser::realLex; -} - -void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult, bool logErrors) -{ - setStyleSheet(sheet); - m_defaultNamespace = starAtom; // Reset the default namespace. - if (ruleSourceDataResult) - m_currentRuleDataStack = adoptPtr(new RuleSourceDataList()); - m_ruleSourceDataResult = ruleSourceDataResult; - - m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page(); - m_ignoreErrorsInDeclaration = false; - m_lineNumber = startLineNumber; - setupParser("", string, ""); - cssyyparse(this); - sheet->shrinkToFit(); - m_currentRuleDataStack.clear(); - m_ruleSourceDataResult = 0; - m_rule = 0; - m_ignoreErrorsInDeclaration = false; - m_logErrors = false; -} - -PassRefPtr CSSParser::parseRule(StyleSheetContents* sheet, const String& string) -{ - setStyleSheet(sheet); - m_allowNamespaceDeclarations = false; - setupParser("@-webkit-rule{", string, "} "); - cssyyparse(this); - return m_rule.release(); -} - -PassRefPtr CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string) -{ - setStyleSheet(sheet); - setupParser("@-webkit-keyframe-rule{ ", string, "} "); - cssyyparse(this); - return m_keyframe.release(); -} - -#if ENABLE(CSS3_CONDITIONAL_RULES) -bool CSSParser::parseSupportsCondition(const String& string) -{ - m_supportsCondition = false; - setupParser("@-webkit-supports-condition{ ", string, "} "); - cssyyparse(this); - return m_supportsCondition; -} -#endif - -static inline bool isColorPropertyID(CSSPropertyID propertyId) -{ - switch (propertyId) { - case CSSPropertyColor: - case CSSPropertyBackgroundColor: - case CSSPropertyBorderBottomColor: - case CSSPropertyBorderLeftColor: - case CSSPropertyBorderRightColor: - case CSSPropertyBorderTopColor: - case CSSPropertyOutlineColor: - case CSSPropertyTextLineThroughColor: - case CSSPropertyTextOverlineColor: - case CSSPropertyTextUnderlineColor: - case CSSPropertyWebkitBorderAfterColor: - case CSSPropertyWebkitBorderBeforeColor: - case CSSPropertyWebkitBorderEndColor: - case CSSPropertyWebkitBorderStartColor: - case CSSPropertyWebkitColumnRuleColor: - case CSSPropertyWebkitTextDecorationColor: - case CSSPropertyWebkitTextEmphasisColor: - case CSSPropertyWebkitTextFillColor: - case CSSPropertyWebkitTextStrokeColor: - return true; - default: - return false; - } -} - -static bool parseColorValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) -{ - ASSERT(!string.isEmpty()); - bool strict = isStrictParserMode(cssParserMode); - if (!isColorPropertyID(propertyId)) - return false; - 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 value = cssValuePool().createIdentifierValue(valueID); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; - } - RGBA32 color; - if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#')) - return false; - RefPtr value = cssValuePool().createColorValue(color); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; -} - -static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers) -{ - switch (propertyId) { - case CSSPropertyFontSize: - case CSSPropertyHeight: - case CSSPropertyWidth: - case CSSPropertyMinHeight: - case CSSPropertyMinWidth: - case CSSPropertyPaddingBottom: - case CSSPropertyPaddingLeft: - case CSSPropertyPaddingRight: - case CSSPropertyPaddingTop: - case CSSPropertyWebkitLogicalWidth: - case CSSPropertyWebkitLogicalHeight: - case CSSPropertyWebkitMinLogicalWidth: - case CSSPropertyWebkitMinLogicalHeight: - case CSSPropertyWebkitPaddingAfter: - case CSSPropertyWebkitPaddingBefore: - case CSSPropertyWebkitPaddingEnd: - case CSSPropertyWebkitPaddingStart: - acceptsNegativeNumbers = false; - return true; -#if ENABLE(CSS_SHAPES) - case CSSPropertyWebkitShapeMargin: - case CSSPropertyWebkitShapePadding: - acceptsNegativeNumbers = false; - return RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled(); -#endif - case CSSPropertyBottom: - case CSSPropertyLeft: - case CSSPropertyMarginBottom: - case CSSPropertyMarginLeft: - case CSSPropertyMarginRight: - case CSSPropertyMarginTop: - case CSSPropertyRight: - case CSSPropertyTop: - case CSSPropertyWebkitMarginAfter: - case CSSPropertyWebkitMarginBefore: - case CSSPropertyWebkitMarginEnd: - case CSSPropertyWebkitMarginStart: - acceptsNegativeNumbers = true; - return true; - default: - return false; - } -} - -template -static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number) -{ - if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') { - length -= 2; - unit = CSSPrimitiveValue::CSS_PX; - } else if (length > 1 && characters[length - 1] == '%') { - length -= 1; - unit = CSSPrimitiveValue::CSS_PERCENTAGE; - } - - // We rely on charactersToDouble for validation as well. The function - // will set "ok" to "false" if the entire passed-in character range does - // not represent a double. - bool ok; - number = charactersToDouble(characters, length, &ok); - return ok; -} - -static bool parseSimpleLengthValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode) -{ - ASSERT(!string.isEmpty()); - bool acceptsNegativeNumbers; - if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers)) - return false; - - unsigned length = string.length(); - double number; - CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER; - - if (string.is8Bit()) { - if (!parseSimpleLength(string.characters8(), length, unit, number)) - return false; - } else { - if (!parseSimpleLength(string.characters16(), length, unit, number)) - return false; - } - - if (unit == CSSPrimitiveValue::CSS_NUMBER) { - if (number && isStrictParserMode(cssParserMode)) - return false; - unit = CSSPrimitiveValue::CSS_PX; - } - if (number < 0 && !acceptsNegativeNumbers) - return false; - - RefPtr value = cssValuePool().createValue(number, unit); - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; -} - -static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext) -{ - if (!valueID) - return false; - - switch (propertyId) { - case CSSPropertyBorderCollapse: // collapse | separate | inherit - if (valueID == CSSValueCollapse || valueID == CSSValueSeparate) - return true; - break; - case CSSPropertyBorderTopStyle: // | inherit - case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed | - case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset - case CSSPropertyBorderLeftStyle: - case CSSPropertyWebkitBorderAfterStyle: - case CSSPropertyWebkitBorderBeforeStyle: - case CSSPropertyWebkitBorderEndStyle: - case CSSPropertyWebkitBorderStartStyle: - case CSSPropertyWebkitColumnRuleStyle: - if (valueID >= CSSValueNone && valueID <= CSSValueDouble) - return true; - break; - case CSSPropertyBoxSizing: - if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox) - return true; - break; - case CSSPropertyCaptionSide: // top | bottom | left | right | inherit - if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom) - return true; - break; - case CSSPropertyClear: // none | left | right | both | inherit - if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth) - return true; - break; - case CSSPropertyDirection: // ltr | rtl | inherit - if (valueID == CSSValueLtr || valueID == CSSValueRtl) - return true; - break; - case CSSPropertyDisplay: - // inline | block | list-item | run-in | 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 - if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineFlex) || valueID == CSSValueNone) - return true; - if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid)) - return true; - break; - - case CSSPropertyEmptyCells: // show | hide | inherit - if (valueID == CSSValueShow || valueID == CSSValueHide) - return true; - break; - case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none) - if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter) - return true; - break; - case CSSPropertyFontStyle: // normal | italic | oblique | inherit - if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique) - return true; - break; - case CSSPropertyImageRendering: // auto | optimizeSpeed | optimizeQuality | -webkit-crisp-edges | -webkit-optimize-contrast - if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality - || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast) - return true; - break; - case CSSPropertyListStylePosition: // inside | outside | inherit - if (valueID == CSSValueInside || valueID == CSSValueOutside) - return true; - break; - case CSSPropertyListStyleType: - // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in - // for the list of supported list-style-types. - 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: // ( except hidden) | auto | inherit - if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble)) - return true; - break; - case CSSPropertyOverflowWrap: // normal | break-word - case CSSPropertyWordWrap: - if (valueID == CSSValueNormal || valueID == CSSValueBreakWord) - return true; - break; - case CSSPropertyOverflowX: // visible | hidden | scroll | auto | marquee | overlay | inherit - if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee) - return true; - break; - case CSSPropertyOverflowY: // visible | hidden | scroll | auto | marquee | overlay | inherit | -webkit-paged-x | -webkit-paged-y - if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY) - return true; - break; - case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit - case CSSPropertyPageBreakBefore: - case CSSPropertyWebkitColumnBreakAfter: - case CSSPropertyWebkitColumnBreakBefore: - if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight) - return true; - break; - case CSSPropertyPageBreakInside: // avoid | auto | inherit - case CSSPropertyWebkitColumnBreakInside: - if (valueID == CSSValueAuto || valueID == CSSValueAvoid) - return true; - break; - case CSSPropertyPointerEvents: - // none | visiblePainted | visibleFill | visibleStroke | visible | - // painted | fill | stroke | auto | all | inherit - if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke)) - 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 - ) - return true; - break; - case CSSPropertyResize: // none | both | horizontal | vertical | auto - if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto) - return true; - break; - case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit - if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation) - return true; - break; - case CSSPropertyTableLayout: // auto | fixed | inherit - if (valueID == CSSValueAuto || valueID == CSSValueFixed) - return true; - break; - case CSSPropertyTextLineThroughMode: - case CSSPropertyTextOverlineMode: - case CSSPropertyTextUnderlineMode: - if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace) - return true; - break; - case CSSPropertyTextLineThroughStyle: - case CSSPropertyTextOverlineStyle: - case CSSPropertyTextUnderlineStyle: - if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave) - return true; - break; - case CSSPropertyTextOverflow: // clip | ellipsis - if (valueID == CSSValueClip || valueID == CSSValueEllipsis) - return true; - break; - case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision - if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision) - return true; - break; - case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit - if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone) - return true; - break; - case CSSPropertyVisibility: // visible | hidden | collapse | inherit - if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse) - return true; - break; - case CSSPropertyWebkitAppearance: - if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone) - return true; - break; - case CSSPropertyWebkitBackfaceVisibility: - if (valueID == CSSValueVisible || valueID == CSSValueHidden) - return true; - break; -#if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: - 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)) - return true; - break; -#endif - case CSSPropertyWebkitBorderFit: - if (valueID == CSSValueBorder || valueID == CSSValueLines) - return true; - break; - case CSSPropertyWebkitBoxAlign: - if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline) - return true; - break; -#if ENABLE(CSS_BOX_DECORATION_BREAK) - case CSSPropertyWebkitBoxDecorationBreak: - if (valueID == CSSValueClone || valueID == CSSValueSlice) - return true; - break; -#endif - case CSSPropertyWebkitBoxDirection: - if (valueID == CSSValueNormal || valueID == CSSValueReverse) - return true; - break; - case CSSPropertyWebkitBoxLines: - if (valueID == CSSValueSingle || valueID == CSSValueMultiple) - return true; - break; - case CSSPropertyWebkitBoxOrient: - if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis) - return true; - break; - case CSSPropertyWebkitBoxPack: - if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify) - return true; - break; - case CSSPropertyWebkitColorCorrection: - if (valueID == CSSValueSrgb || valueID == CSSValueDefault) - return true; - break; - case CSSPropertyWebkitColumnFill: - 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: - if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse) - return true; - break; - case CSSPropertyWebkitFlexWrap: - 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; - break; - case CSSPropertyWebkitFontSmoothing: - if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased) - return true; - break; - case CSSPropertyWebkitHyphens: - 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; - break; - case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space - if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace) - return true; - break; - case CSSPropertyWebkitLineSnap: - if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain) - return true; - break; - case CSSPropertyWebkitMarginAfterCollapse: - case CSSPropertyWebkitMarginBeforeCollapse: - case CSSPropertyWebkitMarginBottomCollapse: - case CSSPropertyWebkitMarginTopCollapse: - if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard) - return true; - break; - case CSSPropertyWebkitMarqueeDirection: - if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown - || valueID == CSSValueUp || valueID == CSSValueAuto) - return true; - break; - case CSSPropertyWebkitMarqueeStyle: - if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate) - return true; - break; - case CSSPropertyWebkitNbspMode: // normal | space - if (valueID == CSSValueNormal || valueID == CSSValueSpace) - return true; - break; -#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) - case CSSPropertyWebkitOverflowScrolling: - if (valueID == CSSValueAuto || valueID == CSSValueTouch) - return true; - break; -#endif - case CSSPropertyWebkitPrintColorAdjust: - if (valueID == CSSValueExact || valueID == CSSValueEconomy) - return true; - break; -#if ENABLE(CSS_REGIONS) - case CSSPropertyWebkitRegionBreakAfter: - case CSSPropertyWebkitRegionBreakBefore: - if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)) - return true; - break; - case CSSPropertyWebkitRegionBreakInside: - if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueAvoid)) - return true; - break; - case CSSPropertyWebkitRegionFragment: - if (parserContext.isCSSRegionsEnabled && (valueID == CSSValueAuto || valueID == CSSValueBreak)) - return true; - break; -#endif - case CSSPropertyWebkitRtlOrdering: - if (valueID == CSSValueLogical || valueID == CSSValueVisual) - return true; - break; - - case CSSPropertyWebkitRubyPosition: - if (valueID == CSSValueBefore || valueID == CSSValueAfter) - return true; - break; - -#if ENABLE(CSS3_TEXT) - case CSSPropertyWebkitTextAlignLast: - // auto | start | end | left | right | center | justify - if ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto) - return true; - break; -#endif // CSS3_TEXT - case CSSPropertyWebkitTextCombine: - if (valueID == CSSValueNone || valueID == CSSValueHorizontal) - 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) - return true; - break; -#endif // CSS3_TEXT - case CSSPropertyWebkitTextSecurity: - // disc | circle | square | none | inherit - 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 CSSPropertyWebkitTransformStyle: - if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d) - return true; - break; - case CSSPropertyWebkitUserDrag: // auto | none | element - if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement) - return true; - break; - case CSSPropertyWebkitUserModify: // read-only | read-write - if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly) - 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::sharedFeatures().cssExclusionsEnabled()) - return false; - if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear) - return true; - break; - case CSSPropertyWebkitWrapThrough: - if (!RuntimeEnabledFeatures::sharedFeatures().cssExclusionsEnabled()) - return false; - if (valueID == CSSValueWrap || valueID == CSSValueNone) - return true; - break; -#endif - case CSSPropertyWebkitWritingMode: - if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt) - return true; - break; - case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit - 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) - return true; - break; - default: - ASSERT_NOT_REACHED(); - return false; - } - return false; -} - -static inline bool isKeywordPropertyID(CSSPropertyID propertyId) -{ - switch (propertyId) { - case CSSPropertyBorderBottomStyle: - case CSSPropertyBorderCollapse: - case CSSPropertyBorderLeftStyle: - case CSSPropertyBorderRightStyle: - case CSSPropertyBorderTopStyle: - case CSSPropertyBoxSizing: - case CSSPropertyCaptionSide: - case CSSPropertyClear: - case CSSPropertyDirection: - case CSSPropertyDisplay: - case CSSPropertyEmptyCells: - case CSSPropertyFloat: - case CSSPropertyFontStyle: - case CSSPropertyImageRendering: - case CSSPropertyListStylePosition: - case CSSPropertyListStyleType: - case CSSPropertyObjectFit: - case CSSPropertyOutlineStyle: - case CSSPropertyOverflowWrap: - case CSSPropertyOverflowX: - case CSSPropertyOverflowY: - case CSSPropertyPageBreakAfter: - case CSSPropertyPageBreakBefore: - case CSSPropertyPageBreakInside: - case CSSPropertyPointerEvents: - case CSSPropertyPosition: - case CSSPropertyResize: - case CSSPropertySpeak: - case CSSPropertyTableLayout: - case CSSPropertyTextLineThroughMode: - case CSSPropertyTextLineThroughStyle: - case CSSPropertyTextOverflow: - case CSSPropertyTextOverlineMode: - case CSSPropertyTextOverlineStyle: - case CSSPropertyTextRendering: - case CSSPropertyTextTransform: - case CSSPropertyTextUnderlineMode: - case CSSPropertyTextUnderlineStyle: - case CSSPropertyVisibility: - case CSSPropertyWebkitAppearance: -#if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: -#endif - case CSSPropertyWebkitBackfaceVisibility: - case CSSPropertyWebkitBorderAfterStyle: - case CSSPropertyWebkitBorderBeforeStyle: - case CSSPropertyWebkitBorderEndStyle: - case CSSPropertyWebkitBorderFit: - case CSSPropertyWebkitBorderStartStyle: - case CSSPropertyWebkitBoxAlign: -#if ENABLE(CSS_BOX_DECORATION_BREAK) - case CSSPropertyWebkitBoxDecorationBreak: -#endif - case CSSPropertyWebkitBoxDirection: - case CSSPropertyWebkitBoxLines: - case CSSPropertyWebkitBoxOrient: - case CSSPropertyWebkitBoxPack: - case CSSPropertyWebkitColorCorrection: - case CSSPropertyWebkitColumnBreakAfter: - case CSSPropertyWebkitColumnBreakBefore: - case CSSPropertyWebkitColumnBreakInside: - case CSSPropertyWebkitColumnFill: - case CSSPropertyWebkitColumnRuleStyle: - case CSSPropertyWebkitAlignContent: - case CSSPropertyWebkitAlignItems: - case CSSPropertyWebkitAlignSelf: - case CSSPropertyWebkitFlexDirection: - case CSSPropertyWebkitFlexWrap: - case CSSPropertyWebkitJustifyContent: - case CSSPropertyWebkitFontKerning: - case CSSPropertyWebkitFontSmoothing: - case CSSPropertyWebkitHyphens: - case CSSPropertyWebkitGridAutoFlow: - case CSSPropertyWebkitLineAlign: - case CSSPropertyWebkitLineBreak: - case CSSPropertyWebkitLineSnap: - case CSSPropertyWebkitMarginAfterCollapse: - case CSSPropertyWebkitMarginBeforeCollapse: - case CSSPropertyWebkitMarginBottomCollapse: - case CSSPropertyWebkitMarginTopCollapse: - case CSSPropertyWebkitMarqueeDirection: - case CSSPropertyWebkitMarqueeStyle: - case CSSPropertyWebkitNbspMode: -#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) - case CSSPropertyWebkitOverflowScrolling: -#endif - case CSSPropertyWebkitPrintColorAdjust: -#if ENABLE(CSS_REGIONS) - case CSSPropertyWebkitRegionBreakAfter: - case CSSPropertyWebkitRegionBreakBefore: - case CSSPropertyWebkitRegionBreakInside: - case CSSPropertyWebkitRegionFragment: -#endif - case CSSPropertyWebkitRtlOrdering: - case CSSPropertyWebkitRubyPosition: -#if ENABLE(CSS3_TEXT) - case CSSPropertyWebkitTextAlignLast: -#endif // CSS3_TEXT - case CSSPropertyWebkitTextCombine: -#if ENABLE(CSS3_TEXT) - case CSSPropertyWebkitTextJustify: -#endif // CSS3_TEXT - case CSSPropertyWebkitTextSecurity: - 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: - return true; - default: - return false; - } -} - -static bool parseKeywordValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext) -{ - 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; - - // Parse initial/inherit shorthands using the CSSParser. - if (shorthandForProperty(propertyId).length()) - return false; - } - - CSSParserString cssString; - cssString.init(string); - CSSValueID valueID = cssValueKeywordID(cssString); - - if (!valueID) - return false; - - RefPtr value; - if (valueID == CSSValueInherit) - value = cssValuePool().createInheritedValue(); - else if (valueID == CSSValueInitial) - value = cssValuePool().createExplicitInitialValue(); - else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext)) - value = cssValuePool().createIdentifierValue(valueID); - else - return false; - - declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)); - return true; -} - -template -static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount) -{ - while (expectedCount) { - size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start); - if (end == notFound || (expectedCount == 1 && end != length - 1)) - return false; - unsigned argumentLength = end - start; - CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER; - double number; - if (!parseSimpleLength(characters + start, argumentLength, unit, number)) - return false; - if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER)) - return false; - transformValue->append(cssValuePool().createValue(number, unit)); - start = end + 1; - --expectedCount; - } - return true; -} - -static bool parseTranslateTransformValue(MutableStyleProperties* properties, CSSPropertyID propertyID, const String& string, bool important) -{ - if (propertyID != CSSPropertyWebkitTransform) - return false; - static const unsigned shortestValidTransformStringLength = 12; - static const unsigned likelyMultipartTransformStringLengthCutoff = 32; - if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff) - return false; - if (!string.startsWith("translate", false)) - return false; - UChar c9 = toASCIILower(string[9]); - UChar c10 = toASCIILower(string[10]); - - WebKitCSSTransformValue::TransformOperationType transformType; - unsigned expectedArgumentCount = 1; - unsigned argumentStart = 11; - if (c9 == 'x' && c10 == '(') - transformType = WebKitCSSTransformValue::TranslateXTransformOperation; - else if (c9 == 'y' && c10 == '(') - transformType = WebKitCSSTransformValue::TranslateYTransformOperation; - else if (c9 == 'z' && c10 == '(') - transformType = WebKitCSSTransformValue::TranslateZTransformOperation; - else if (c9 == '(') { - transformType = WebKitCSSTransformValue::TranslateTransformOperation; - expectedArgumentCount = 2; - argumentStart = 10; - } else if (c9 == '3' && c10 == 'd' && string[11] == '(') { - transformType = WebKitCSSTransformValue::Translate3DTransformOperation; - expectedArgumentCount = 3; - argumentStart = 12; - } else - return false; - - RefPtr transformValue = WebKitCSSTransformValue::create(transformType); - bool success; - if (string.is8Bit()) - success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount); - else - success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount); - if (!success) - return false; - RefPtr result = CSSValueList::createSpaceSeparated(); - result->append(transformValue.release()); - properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important)); - return true; -} - -PassRefPtr CSSParser::parseFontFaceValue(const AtomicString& string) -{ - if (string.isEmpty()) - return 0; - RefPtr dummyStyle = MutableStyleProperties::create(); - if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, 0)) - return 0; - - RefPtr 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(fontFamily.release()); -} - -bool 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; - - CSSParserContext context(cssParserMode); - if (contextStyleSheet) { - context = contextStyleSheet->parserContext(); - context.mode = cssParserMode; - } - - if (parseKeywordValue(declaration, propertyID, string, important, context)) - return true; - if (parseTranslateTransformValue(declaration, propertyID, string, important)) - return true; - - CSSParser parser(context); - return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet); -} - -bool CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet) -{ - setStyleSheet(contextStyleSheet); - - setupParser("@-webkit-value{", string, "} "); - - m_id = propertyID; - m_important = important; - - cssyyparse(this); - - m_rule = 0; - - bool ok = false; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - if (!m_parsedProperties.isEmpty()) { - ok = true; - declaration->addParsedProperties(m_parsedProperties); - clearProperties(); - } - - return ok; -} - -// 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) -{ - // First try creating a color specified by name, rgba(), rgb() or "#" syntax. - if (fastParseColor(color, string, strict)) - return true; - - CSSParser parser(CSSStrictMode); - - // In case the fast-path parser didn't understand the color, try the full parser. - if (!parser.parseColor(string)) - return false; - - CSSValue* value = parser.m_parsedProperties.first().value(); - if (!value->isPrimitiveValue()) - return false; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (!primitiveValue->isRGBColor()) - return false; - - color = primitiveValue->getRGBA32Value(); - return true; -} - -bool CSSParser::parseColor(const String& string) -{ - setupParser("@-webkit-decls{color:", string, "} "); - cssyyparse(this); - m_rule = 0; - - return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor; -} - -bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document) -{ - if (!document || !document->page()) - return false; - - CSSParserString cssColor; - cssColor.init(string); - CSSValueID id = cssValueKeywordID(cssColor); - if (id <= 0) - return false; - - color = document->page()->theme().systemColor(id).rgb(); - return true; -} - -void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList) -{ - m_selectorListForParseSelector = &selectorList; - - setupParser("@-webkit-selector{", string, "}"); - - cssyyparse(this); - - m_selectorListForParseSelector = 0; -} - -PassRef 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()); -} - -PassRef CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet) -{ - setStyleSheet(contextStyleSheet); - - setupParser("@-webkit-decls{", string, "} "); - cssyyparse(this); - m_rule = 0; - - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - - PassRef style = createStyleProperties(); - clearProperties(); - return style; -} - - -bool CSSParser::parseDeclaration(MutableStyleProperties* declaration, const String& string, PassRefPtr prpRuleSourceData, StyleSheetContents* contextStyleSheet) -{ - // Length of the "@-webkit-decls{" prefix. - static const unsigned prefixLength = 15; - - setStyleSheet(contextStyleSheet); - - RefPtr ruleSourceData = prpRuleSourceData; - if (ruleSourceData) { - m_currentRuleDataStack = adoptPtr(new RuleSourceDataList()); - m_currentRuleDataStack->append(ruleSourceData); - } - - setupParser("@-webkit-decls{", string, "} "); - cssyyparse(this); - m_rule = 0; - - bool ok = false; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - if (!m_parsedProperties.isEmpty()) { - ok = true; - declaration->addParsedProperties(m_parsedProperties); - clearProperties(); - } - - if (ruleSourceData) { - ASSERT(m_currentRuleDataStack->size() == 1); - ruleSourceData->ruleBodyRange.start = 0; - ruleSourceData->ruleBodyRange.end = string.length(); - for (size_t i = 0, size = ruleSourceData->styleSourceData->propertyData.size(); i < size; ++i) { - CSSPropertySourceData& propertyData = ruleSourceData->styleSourceData->propertyData.at(i); - propertyData.range.start -= prefixLength; - propertyData.range.end -= prefixLength; - } - - fixUnparsedPropertyRanges(ruleSourceData.get()); - m_currentRuleDataStack.clear(); - } - - return ok; -} - -PassOwnPtr CSSParser::parseMediaQuery(const String& string) -{ - if (string.isEmpty()) - return nullptr; - - ASSERT(!m_mediaQuery); - - // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token. - // instead insert one " " (which is WHITESPACE in CSSGrammar.y) - setupParser("@-webkit-mediaquery ", string, "} "); - cssyyparse(this); - - return m_mediaQuery.release(); -} - -static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector& output, size_t& unusedEntries, std::bitset& seenProperties) -{ - // 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; - const unsigned propertyIDIndex = property.id() - firstCSSProperty; - if (seenProperties.test(propertyIDIndex)) - continue; - seenProperties.set(propertyIDIndex); - output[--unusedEntries] = property; - } -} - -PassRef CSSParser::createStyleProperties() -{ - std::bitset seenProperties; - size_t unusedEntries = m_parsedProperties.size(); - Vector results(unusedEntries); - - // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found. - filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties); - filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties); - if (unusedEntries) - results.remove(0, unusedEntries); - - return ImmutableStyleProperties::create(results.data(), results.size(), m_context.mode); -} - -void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr value, bool important, bool implicit) -{ - RefPtr val = value.get(); - addProperty(propId, value, important, implicit); - - CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId); - if (prefixingVariant == propId) - return; - - 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 value, bool important, bool 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 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) -{ - ASSERT(num >= 0); - ASSERT(m_parsedProperties.size() >= static_cast(num)); - m_parsedProperties.shrink(m_parsedProperties.size() - num); -} - -void CSSParser::clearProperties() -{ - m_parsedProperties.clear(); - m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES; - m_hasFontFaceOnlyValues = false; -} - -URL CSSParser::completeURL(const CSSParserContext& context, const String& url) -{ - if (url.isNull()) - return URL(); - if (context.charset.isEmpty()) - return URL(context.baseURL, url); - return URL(context.baseURL, url, context.charset); -} - -URL CSSParser::completeURL(const String& url) const -{ - return completeURL(m_context, url); -} - -bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc) -{ - bool mustBeNonNegative = unitflags & FNonNeg; - - if (!parseCalculation(value, mustBeNonNegative ? CalculationRangeNonNegative : CalculationRangeAll)) - return false; - - bool b = false; - switch (m_parsedCalculation->category()) { - case CalcLength: - b = (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; - break; - case CalcPercentLength: - b = (unitflags & FPercent) && (unitflags & FLength); - break; - case CalcPercentNumber: - b = (unitflags & FPercent) && (unitflags & FNumber); - break; - case CalcOther: - break; - } - if (!b || releaseCalc == ReleaseParsedCalcValue) - m_parsedCalculation.release(); - return b; -} - -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); -} - -bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc) -{ - if (isCalculation(value)) - return validCalculationUnit(value, unitflags, releaseCalc); - - bool b = false; - switch (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 = true; - } - if (!b && (unitflags & FInteger) && value->isInt) - b = true; - if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0) - b = true; - break; - case CSSPrimitiveValue::CSS_PERCENTAGE: - b = (unitflags & FPercent); - break; - case CSSParserValue::Q_EMS: - case CSSPrimitiveValue::CSS_EMS: - case CSSPrimitiveValue::CSS_REMS: - case CSSPrimitiveValue::CSS_CHS: - case CSSPrimitiveValue::CSS_EXS: - case CSSPrimitiveValue::CSS_PX: - case CSSPrimitiveValue::CSS_CM: - case CSSPrimitiveValue::CSS_MM: - case CSSPrimitiveValue::CSS_IN: - case CSSPrimitiveValue::CSS_PT: - case CSSPrimitiveValue::CSS_PC: - case CSSPrimitiveValue::CSS_VW: - case CSSPrimitiveValue::CSS_VH: - case CSSPrimitiveValue::CSS_VMIN: - case CSSPrimitiveValue::CSS_VMAX: - b = (unitflags & FLength); - break; - case CSSPrimitiveValue::CSS_MS: - case CSSPrimitiveValue::CSS_S: - b = (unitflags & FTime); - break; - case CSSPrimitiveValue::CSS_DEG: - case CSSPrimitiveValue::CSS_RAD: - case CSSPrimitiveValue::CSS_GRAD: - case CSSPrimitiveValue::CSS_TURN: - 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); - break; -#endif - case CSSPrimitiveValue::CSS_HZ: - case CSSPrimitiveValue::CSS_KHZ: - case CSSPrimitiveValue::CSS_DIMENSION: - default: - break; - } - if (b && unitflags & FNonNeg && value->fValue < 0) - b = false; - return b; -} - -inline PassRefPtr CSSParser::createPrimitiveNumericValue(CSSParserValue* value) -{ - if (m_parsedCalculation) { - ASSERT(isCalculation(value)); - return CSSPrimitiveValue::create(m_parsedCalculation.release()); - } - -#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)); -#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)); -#endif - return cssValuePool().createValue(value->fValue, static_cast(value->unit)); -} - -inline PassRefPtr CSSParser::createPrimitiveStringValue(CSSParserValue* value) -{ - ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT); - return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING); -} - -static inline bool isComma(CSSParserValue* value) -{ - return value && value->unit == CSSParserValue::Operator && value->iValue == ','; -} - -static inline bool isForwardSlashOperator(CSSParserValue* value) -{ - ASSERT(value); - return value->unit == CSSParserValue::Operator && value->iValue == '/'; -} - -bool CSSParser::validWidth(CSSParserValue* value) -{ - int id = 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); -} - -inline PassRefPtr CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value) -{ - 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); -#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 (value->unit >= CSSParserValue::Q_EMS) - return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); - if (isCalculation(value)) - return CSSPrimitiveValue::create(m_parsedCalculation.release()); - - return 0; -} - -void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr prpValue, bool important) -{ - const StylePropertyShorthand& shorthand = shorthandForProperty(propId); - unsigned shorthandLength = shorthand.length(); - if (!shorthandLength) { - addProperty(propId, prpValue, important); - return; - } - - RefPtr value = prpValue; - ShorthandScope scope(this, propId); - const CSSPropertyID* longhands = shorthand.properties(); - for (unsigned i = 0; i < shorthandLength; ++i) - addProperty(longhands[i], value, important); -} - -bool CSSParser::parseValue(CSSPropertyID propId, bool important) -{ - if (!m_valueList) - return false; - - CSSParserValue* value = m_valueList->current(); - - if (!value) - 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; - - unsigned num = inShorthand() ? 1 : m_valueList->size(); - - if (id == CSSValueInherit) { - if (num != 1) - return false; - addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important); - return true; - } - else if (id == CSSValueInitial) { - if (num != 1) - return false; - addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important); - return true; - } - - if (isKeywordPropertyID(propId)) { - if (!isValidKeywordPropertyAndValue(propId, id, m_context)) - return false; - if (m_valueList->next() && !inShorthand()) - return false; - addProperty(propId, cssValuePool().createIdentifierValue(id), important); - return true; - } - -#if ENABLE(CSS_DEVICE_ADAPTATION) - if (inViewport()) - return parseViewportProperty(propId, important); -#endif - - bool validPrimitive = false; - RefPtr parsedValue; - - switch (propId) { - case CSSPropertySize: // {1,2} | auto | [ || [ portrait | landscape] ] - return parseSize(propId, important); - - case CSSPropertyQuotes: // [ ]+ | none | inherit - if (id) - validPrimitive = true; - else - return parseQuotes(propId, important); - break; - case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit - if (id == CSSValueNormal - || id == CSSValueEmbed - || id == CSSValueBidiOverride - || id == CSSValueWebkitIsolate - || id == CSSValueWebkitIsolateOverride - || id == CSSValueWebkitPlaintext) - validPrimitive = true; - break; - - case CSSPropertyContent: // [ | | | attr(X) | open-quote | - // close-quote | no-open-quote | no-close-quote ]+ | inherit - return parseContent(propId, important); - - case CSSPropertyWebkitAlt: // [ | attr(X) ] - return parseAlt(propId, important); - - case CSSPropertyClip: // | auto | inherit - if (id == CSSValueAuto) - validPrimitive = true; - else if (value->unit == CSSParserValue::Function) - return parseClipShape(propId, important); - break; - - /* Start of supported CSS properties with validation. This is needed for parseShorthand to work - * correctly and allows optimization in WebCore::applyRule(..) - */ - case CSSPropertyOverflow: { - ShorthandScope scope(this, propId); - if (num != 1 || !parseValue(CSSPropertyOverflowY, important)) - return false; - - RefPtr overflowXValue; - - // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been - // set using the shorthand, then for now overflow-x will default to auto, but once we implement - // 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); - else - overflowXValue = m_parsedProperties.last().value(); - addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); - return true; - } - - case CSSPropertyTextAlign: - // left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent - // | start | end | inherit | -webkit-auto (converted to start) - // NOTE: is not supported. - if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd) - validPrimitive = true; - break; - - case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit - if (m_valueList->size() != 1) - return false; - return parseFontWeight(important); - } - case CSSPropertyBorderSpacing: { - if (num == 1) { - ShorthandScope scope(this, CSSPropertyBorderSpacing); - if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important)) - return false; - CSSValue* value = m_parsedProperties.last().value(); - addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important); - return true; - } - else if (num == 2) { - ShorthandScope scope(this, CSSPropertyBorderSpacing); - if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important)) - return false; - return true; - } - return false; - } - case CSSPropertyWebkitBorderHorizontalSpacing: - case CSSPropertyWebkitBorderVerticalSpacing: - validPrimitive = validUnit(value, FLength | FNonNeg); - break; - case CSSPropertyOutlineColor: // | invert | inherit - // Outline color has "invert" as additional keyword. - // Also, we want to allow the special focus color even in strict parsing mode. - if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) { - validPrimitive = true; - break; - } - FALLTHROUGH; - case CSSPropertyBackgroundColor: // | inherit - case CSSPropertyBorderTopColor: // | inherit - case CSSPropertyBorderRightColor: - case CSSPropertyBorderBottomColor: - case CSSPropertyBorderLeftColor: - case CSSPropertyWebkitBorderStartColor: - case CSSPropertyWebkitBorderEndColor: - case CSSPropertyWebkitBorderBeforeColor: - case CSSPropertyWebkitBorderAfterColor: - case CSSPropertyColor: // | inherit - case CSSPropertyTextLineThroughColor: // CSS3 text decoration colors - case CSSPropertyTextUnderlineColor: - case CSSPropertyTextOverlineColor: - case CSSPropertyWebkitColumnRuleColor: - case CSSPropertyWebkitTextDecorationColor: - case CSSPropertyWebkitTextEmphasisColor: - case CSSPropertyWebkitTextFillColor: - case CSSPropertyWebkitTextStrokeColor: - if (id == CSSValueWebkitText) - validPrimitive = true; // Always allow this, even when strict parsing is on, - // 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())) { - validPrimitive = true; - } else { - parsedValue = parseColor(); - if (parsedValue) - m_valueList->next(); - } - break; - - case CSSPropertyCursor: { - // Grammar defined by CSS3 UI and modified by CSS4 images: - // [ [ [ ]?,]* - // [ 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 - RefPtr list; - while (value) { - RefPtr image = 0; - 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(")) { - image = parseImageSet(); - if (!image) - break; -#endif - } else - break; - - Vector coords; - value = m_valueList->next(); - while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) { - coords.append(int(value->fValue)); - value = m_valueList->next(); - } - bool hasHotSpot = false; - IntPoint hotSpot(-1, -1); - int nrcoords = coords.size(); - if (nrcoords > 0 && nrcoords != 2) - return false; - if (nrcoords == 2) { - hasHotSpot = true; - hotSpot = IntPoint(coords[0], coords[1]); - } - - if (!list) - list = CSSValueList::createCommaSeparated(); - - if (image) - 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 (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)); - m_valueList->next(); - parsedValue = list.release(); - break; - } else if (value) { - id = value->id; - 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) - validPrimitive = true; - } else { - ASSERT_NOT_REACHED(); - return false; - } - break; - } - -#if ENABLE(CURSOR_VISIBILITY) - case CSSPropertyWebkitCursorVisibility: - if (id == CSSValueAuto || id == CSSValueAutoHide) - validPrimitive = true; - break; -#endif - - case CSSPropertyBackgroundAttachment: - case CSSPropertyWebkitBackgroundBlendMode: - case CSSPropertyBackgroundClip: - case CSSPropertyWebkitBackgroundClip: - case CSSPropertyWebkitBackgroundComposite: - case CSSPropertyBackgroundImage: - case CSSPropertyBackgroundOrigin: - case CSSPropertyWebkitBackgroundOrigin: - case CSSPropertyBackgroundPosition: - case CSSPropertyBackgroundPositionX: - case CSSPropertyBackgroundPositionY: - case CSSPropertyBackgroundSize: - case CSSPropertyWebkitBackgroundSize: - case CSSPropertyBackgroundRepeat: - case CSSPropertyBackgroundRepeatX: - case CSSPropertyBackgroundRepeatY: - case CSSPropertyWebkitMaskClip: - case CSSPropertyWebkitMaskComposite: - case CSSPropertyWebkitMaskImage: - case CSSPropertyWebkitMaskOrigin: - case CSSPropertyWebkitMaskPosition: - case CSSPropertyWebkitMaskPositionX: - case CSSPropertyWebkitMaskPositionY: - case CSSPropertyWebkitMaskSize: - case CSSPropertyWebkitMaskSourceType: - case CSSPropertyWebkitMaskRepeat: - case CSSPropertyWebkitMaskRepeatX: - case CSSPropertyWebkitMaskRepeatY: - { - RefPtr val1; - RefPtr val2; - CSSPropertyID propId1, propId2; - bool result = false; - if (parseFillProperty(propId, propId1, propId2, val1, val2)) { - OwnPtr shorthandScope; - if (propId == CSSPropertyBackgroundPosition || - propId == CSSPropertyBackgroundRepeat || - propId == CSSPropertyWebkitMaskPosition || - propId == CSSPropertyWebkitMaskRepeat) { - shorthandScope = adoptPtr(new ShorthandScope(this, propId)); - } - addProperty(propId1, val1.release(), important); - if (val2) - addProperty(propId2, val2.release(), important); - result = true; - } - m_implicitShorthand = false; - return result; - } - case CSSPropertyListStyleImage: // | none | inherit - case CSSPropertyBorderImageSource: - case CSSPropertyWebkitMaskBoxImageSource: - if (id == CSSValueNone) { - parsedValue = cssValuePool().createIdentifierValue(CSSValueNone); - m_valueList->next(); - } else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSImageValue::create(completeURL(value->string)); - m_valueList->next(); - } else if (isGeneratedImageValue(value)) { - if (parseGeneratedImage(m_valueList.get(), 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(")) { - parsedValue = parseImageSet(); - if (!parsedValue) - return false; - m_valueList->next(); - } -#endif - break; - - case CSSPropertyWebkitTextStrokeWidth: - case CSSPropertyOutlineWidth: // | inherit - case CSSPropertyBorderTopWidth: //// | inherit - case CSSPropertyBorderRightWidth: // Which is defined as - case CSSPropertyBorderBottomWidth: // thin | medium | thick | - case CSSPropertyBorderLeftWidth: - case CSSPropertyWebkitBorderStartWidth: - case CSSPropertyWebkitBorderEndWidth: - case CSSPropertyWebkitBorderBeforeWidth: - case CSSPropertyWebkitBorderAfterWidth: - case CSSPropertyWebkitColumnRuleWidth: - if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FNonNeg); - break; - - case CSSPropertyLetterSpacing: // normal | | inherit - if (id == CSSValueNormal) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength); - break; - - case CSSPropertyWordSpacing: // normal | | | inherit - if (id == CSSValueNormal) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FPercent); - break; - - case CSSPropertyTextIndent: - parsedValue = parseTextIndent(); - break; - - case CSSPropertyPaddingTop: //// | inherit - case CSSPropertyPaddingRight: // Which is defined as - case CSSPropertyPaddingBottom: // | - case CSSPropertyPaddingLeft: //// - case CSSPropertyWebkitPaddingStart: - case CSSPropertyWebkitPaddingEnd: - case CSSPropertyWebkitPaddingBefore: - case CSSPropertyWebkitPaddingAfter: - validPrimitive = (!id && validUnit(value, 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)); - break; - - case CSSPropertyMinHeight: - case CSSPropertyWebkitMinLogicalHeight: - validPrimitive = validHeight(value); - break; - - case CSSPropertyHeight: - case CSSPropertyWebkitLogicalHeight: - validPrimitive = (id == CSSValueAuto || validHeight(value)); - 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 | - // | | inherit - - if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FLength | FPercent)); - break; - - case CSSPropertyBottom: // | | auto | inherit - case CSSPropertyLeft: // | | auto | inherit - case CSSPropertyRight: // | | auto | inherit - case CSSPropertyTop: // | | auto | inherit - case CSSPropertyMarginTop: //// | inherit - case CSSPropertyMarginRight: // Which is defined as - case CSSPropertyMarginBottom: // | | auto | inherit - case CSSPropertyMarginLeft: //// - case CSSPropertyWebkitMarginStart: - case CSSPropertyWebkitMarginEnd: - case CSSPropertyWebkitMarginBefore: - case CSSPropertyWebkitMarginAfter: - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FLength | FPercent)); - break; - - case CSSPropertyZIndex: // auto | | inherit - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FInteger, CSSQuirksMode)); - break; - - case CSSPropertyOrphans: // | inherit | auto (We've added support for auto for backwards compatibility) - case CSSPropertyWidows: // | inherit | auto (Ditto) - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FPositiveInteger, CSSQuirksMode)); - break; - - case CSSPropertyLineHeight: - return parseLineHeight(important); - case CSSPropertyCounterIncrement: // [ ? ]+ | none | inherit - if (id != CSSValueNone) - return parseCounter(propId, 1, important); - validPrimitive = true; - break; - case CSSPropertyCounterReset: // [ ? ]+ | none | inherit - if (id != CSSValueNone) - return parseCounter(propId, 0, important); - validPrimitive = true; - break; - case CSSPropertyFontFamily: - // [[ | ],]* [ | ] | inherit - { - parsedValue = parseFontFamily(); - break; - } - - case CSSPropertyWebkitTextDecoration: - // [ || || ] | inherit - return parseShorthand(CSSPropertyWebkitTextDecoration, webkitTextDecorationShorthand(), important); - - case CSSPropertyTextDecoration: - case CSSPropertyWebkitTextDecorationsInEffect: - case CSSPropertyWebkitTextDecorationLine: - // none | [ underline || overline || line-through || blink ] | inherit - return parseTextDecoration(propId, important); - - 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); - - case CSSPropertyZoom: // normal | reset | document | | | inherit - if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, CSSStrictMode)); - 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. - return parseFontFaceSrc(); - - case CSSPropertyUnicodeRange: - return parseFontFaceUnicodeRange(); - - /* CSS3 properties */ - - case CSSPropertyBorderImage: { - RefPtr result; - return parseBorderImage(propId, result, important); - } - case CSSPropertyWebkitBorderImage: - case CSSPropertyWebkitMaskBoxImage: { - RefPtr result; - if (parseBorderImage(propId, result)) { - addProperty(propId, result, important); - return true; - } - break; - } - case CSSPropertyBorderImageOutset: - case CSSPropertyWebkitMaskBoxImageOutset: { - RefPtr result; - if (parseBorderImageOutset(result)) { - addProperty(propId, result, important); - return true; - } - break; - } - case CSSPropertyBorderImageRepeat: - case CSSPropertyWebkitMaskBoxImageRepeat: { - RefPtr result; - if (parseBorderImageRepeat(result)) { - addProperty(propId, result, important); - return true; - } - break; - } - case CSSPropertyBorderImageSlice: - case CSSPropertyWebkitMaskBoxImageSlice: { - RefPtr result; - if (parseBorderImageSlice(propId, result)) { - addProperty(propId, result, important); - return true; - } - break; - } - case CSSPropertyBorderImageWidth: - case CSSPropertyWebkitMaskBoxImageWidth: { - RefPtr result; - if (parseBorderImageWidth(result)) { - addProperty(propId, result, important); - return true; - } - break; - } - case CSSPropertyBorderTopRightRadius: - case CSSPropertyBorderTopLeftRadius: - case CSSPropertyBorderBottomLeftRadius: - case CSSPropertyBorderBottomRightRadius: { - if (num != 1 && num != 2) - return false; - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); - if (!validPrimitive) - return false; - RefPtr parsedValue1 = createPrimitiveNumericValue(value); - RefPtr parsedValue2; - if (num == 2) { - value = m_valueList->next(); - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); - if (!validPrimitive) - return false; - parsedValue2 = createPrimitiveNumericValue(value); - } else - parsedValue2 = parsedValue1; - - addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important); - return true; - } - case CSSPropertyTabSize: - validPrimitive = validUnit(value, FInteger | FNonNeg); - break; - case CSSPropertyWebkitAspectRatio: - return parseAspectRatio(important); - case CSSPropertyBorderRadius: - case CSSPropertyWebkitBorderRadius: - return parseBorderRadius(propId, important); - case CSSPropertyOutlineOffset: - validPrimitive = validUnit(value, FLength); - break; - case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3 - case CSSPropertyBoxShadow: - case CSSPropertyWebkitBoxShadow: - if (id == CSSValueNone) - validPrimitive = true; - else { - RefPtr shadowValueList = parseShadow(m_valueList.get(), propId); - if (shadowValueList) { - addProperty(propId, shadowValueList.release(), important); - m_valueList->next(); - return true; - } - return false; - } - break; - case CSSPropertyWebkitBoxReflect: - if (id == CSSValueNone) - validPrimitive = true; - else - return parseReflect(propId, important); - break; - case CSSPropertyOpacity: - validPrimitive = validUnit(value, FNumber); - break; - case CSSPropertyWebkitBoxFlex: - validPrimitive = validUnit(value, FNumber); - break; - case CSSPropertyWebkitBoxFlexGroup: - validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode); - break; - case CSSPropertyWebkitBoxOrdinalGroup: - validPrimitive = validUnit(value, FInteger | FNonNeg, CSSStrictMode) && value->fValue; - break; -#if ENABLE(CSS_FILTERS) - case CSSPropertyWebkitFilter: - if (id == CSSValueNone) - validPrimitive = true; - else { - RefPtr currValue; - if (!parseFilter(m_valueList.get(), currValue)) - return false; - // m_valueList->next(); - addProperty(propId, currValue, important); - return true; - } - break; -#endif -#if ENABLE(CSS_COMPOSITING) - case CSSPropertyWebkitBlendMode: - if (cssCompositingEnabled()) - validPrimitive = true; - break; -#endif - case CSSPropertyWebkitFlex: { - 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); - return true; - } - return parseFlex(m_valueList.get(), important); - } - case CSSPropertyWebkitFlexBasis: - // FIXME: Support intrinsic dimensions too. - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)); - break; - case CSSPropertyWebkitFlexGrow: - case CSSPropertyWebkitFlexShrink: - validPrimitive = validUnit(value, FNumber | FNonNeg); - break; - case CSSPropertyWebkitOrder: - if (validUnit(value, 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(std::max(std::numeric_limits::min() + 2, value->fValue), static_cast(value->unit)); - m_valueList->next(); - } - break; - case CSSPropertyWebkitMarquee: - return parseShorthand(propId, webkitMarqueeShorthand(), important); - case CSSPropertyWebkitMarqueeIncrement: - if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FPercent); - break; - case CSSPropertyWebkitMarqueeRepetition: - if (id == CSSValueInfinite) - validPrimitive = true; - else - validPrimitive = validUnit(value, FInteger | FNonNeg); - break; - case CSSPropertyWebkitMarqueeSpeed: - if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast) - validPrimitive = true; - else - validPrimitive = validUnit(value, FTime | FInteger | FNonNeg); - break; -#if ENABLE(CSS_REGIONS) - case CSSPropertyWebkitFlowInto: - if (!cssRegionsEnabled()) - return false; - return parseFlowThread(propId, important); - case CSSPropertyWebkitFlowFrom: - if (!cssRegionsEnabled()) - return false; - return parseRegionThread(propId, important); -#endif - case CSSPropertyWebkitTransform: - if (id == CSSValueNone) - validPrimitive = true; - else { - RefPtr transformValue = parseTransform(); - if (transformValue) { - addProperty(propId, transformValue.release(), important); - return true; - } - return false; - } - break; - case CSSPropertyWebkitTransformOrigin: - case CSSPropertyWebkitTransformOriginX: - case CSSPropertyWebkitTransformOriginY: - case CSSPropertyWebkitTransformOriginZ: { - RefPtr val1; - RefPtr val2; - RefPtr val3; - CSSPropertyID propId1, propId2, propId3; - if (parseTransformOrigin(propId, propId1, propId2, propId3, val1, val2, val3)) { - addProperty(propId1, val1.release(), important); - if (val2) - addProperty(propId2, val2.release(), important); - if (val3) - addProperty(propId3, val3.release(), important); - return true; - } - return false; - } - case CSSPropertyWebkitPerspective: - 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 val = createPrimitiveNumericValue(value); - if (val) { - addProperty(propId, val.release(), important); - return true; - } - return false; - } - } - break; - case CSSPropertyWebkitPerspectiveOrigin: - case CSSPropertyWebkitPerspectiveOriginX: - case CSSPropertyWebkitPerspectiveOriginY: { - RefPtr val1; - RefPtr val2; - CSSPropertyID propId1, propId2; - if (parsePerspectiveOrigin(propId, propId1, propId2, val1, val2)) { - addProperty(propId1, val1.release(), important); - if (val2) - addProperty(propId2, val2.release(), important); - return true; - } - return false; - } - case CSSPropertyWebkitAnimationDelay: - case CSSPropertyWebkitAnimationDirection: - case CSSPropertyWebkitAnimationDuration: - case CSSPropertyWebkitAnimationFillMode: - case CSSPropertyWebkitAnimationName: - case CSSPropertyWebkitAnimationPlayState: - case CSSPropertyWebkitAnimationIterationCount: - case CSSPropertyWebkitAnimationTimingFunction: - case CSSPropertyTransitionDelay: - case CSSPropertyTransitionDuration: - case CSSPropertyTransitionTimingFunction: - case CSSPropertyTransitionProperty: - case CSSPropertyWebkitTransitionDelay: - case CSSPropertyWebkitTransitionDuration: - case CSSPropertyWebkitTransitionTimingFunction: - case CSSPropertyWebkitTransitionProperty: { - RefPtr val; - AnimationParseContext context; - if (parseAnimationProperty(propId, val, context)) { - addPropertyWithPrefixingVariant(propId, val.release(), important); - return true; - } - return false; - } - - case CSSPropertyWebkitGridAutoColumns: - case CSSPropertyWebkitGridAutoRows: - if (!cssGridLayoutEnabled()) - return false; - parsedValue = parseGridTrackSize(*m_valueList); - break; - - case CSSPropertyWebkitGridDefinitionColumns: - case CSSPropertyWebkitGridDefinitionRows: - if (!cssGridLayoutEnabled()) - return false; - return parseGridTrackList(propId, important); - - case CSSPropertyWebkitGridColumnStart: - case CSSPropertyWebkitGridColumnEnd: - case CSSPropertyWebkitGridRowStart: - case CSSPropertyWebkitGridRowEnd: - if (!cssGridLayoutEnabled()) - return false; - - parsedValue = parseGridPosition(); - break; - - case CSSPropertyWebkitGridColumn: - case CSSPropertyWebkitGridRow: { - if (!cssGridLayoutEnabled()) - return false; - - return parseGridItemPositionShorthand(propId, important); - } - - case CSSPropertyWebkitGridArea: - if (!cssGridLayoutEnabled()) - return false; - return parseGridAreaShorthand(important); - - case CSSPropertyWebkitGridTemplate: - if (!cssGridLayoutEnabled()) - return false; - - parsedValue = parseGridTemplate(); - break; - - case CSSPropertyWebkitMarginCollapse: { - if (num == 1) { - ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); - if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important)) - return false; - CSSValue* value = m_parsedProperties.last().value(); - addProperty(webkitMarginCollapseShorthand().properties()[1], value, important); - return true; - } - else if (num == 2) { - ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); - if (!parseValue(webkitMarginCollapseShorthand().properties()[0], important) || !parseValue(webkitMarginCollapseShorthand().properties()[1], important)) - return false; - return true; - } - return false; - } - case CSSPropertyTextLineThroughWidth: - case CSSPropertyTextOverlineWidth: - case CSSPropertyTextUnderlineWidth: - if (id == CSSValueAuto || id == CSSValueNormal || id == CSSValueThin || - id == CSSValueMedium || id == CSSValueThick) - validPrimitive = true; - else - validPrimitive = !id && validUnit(value, FNumber | FLength | FPercent); - break; - case CSSPropertyWebkitColumnCount: - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = !id && validUnit(value, FPositiveInteger, CSSQuirksMode); - break; - case CSSPropertyWebkitColumnGap: // normal | - if (id == CSSValueNormal) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FNonNeg); - break; - case CSSPropertyWebkitColumnAxis: - if (id == CSSValueHorizontal || id == CSSValueVertical || id == CSSValueAuto) - validPrimitive = true; - break; - case CSSPropertyWebkitColumnProgression: - if (id == CSSValueNormal || id == CSSValueReverse) - validPrimitive = true; - break; - case CSSPropertyWebkitColumnSpan: // 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; - break; - case CSSPropertyWebkitColumnWidth: // auto | - 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; - 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)); - break; -#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 && validUnit(value, FPercent | FNonNeg, CSSStrictMode)); - } - break; -#endif - - case CSSPropertyWebkitFontSizeDelta: // - validPrimitive = validUnit(value, FLength); - break; - - case CSSPropertyWebkitHighlight: - if (id == CSSValueNone || value->unit == CSSPrimitiveValue::CSS_STRING) - validPrimitive = true; - break; - - case CSSPropertyWebkitHyphenateCharacter: - if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) - validPrimitive = true; - break; - - case CSSPropertyWebkitHyphenateLimitBefore: - case CSSPropertyWebkitHyphenateLimitAfter: - if (id == CSSValueAuto || validUnit(value, FInteger | FNonNeg, CSSStrictMode)) - validPrimitive = true; - break; - - case CSSPropertyWebkitHyphenateLimitLines: - if (id == CSSValueNoLimit || validUnit(value, 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); - if (!lineGridValue.isEmpty()) { - addProperty(propId, cssValuePool().createValue(lineGridValue, CSSPrimitiveValue::CSS_STRING), important); - return true; - } - } - break; - case CSSPropertyWebkitLocale: - if (id == CSSValueAuto || value->unit == CSSPrimitiveValue::CSS_STRING) - validPrimitive = true; - break; - -#if ENABLE(DASHBOARD_SUPPORT) - case CSSPropertyWebkitDashboardRegion: // | - if (value->unit == CSSParserValue::Function || id == CSSValueNone) - return parseDashboardRegions(propId, important); - break; -#endif - -#if PLATFORM(IOS) - // FIXME: CSSPropertyWebkitCompositionFillColor shouldn't be iOS-specific. Once we fix up its usage in - // InlineTextBox::paintCompositionBackground() we should move it outside the PLATFORM(IOS)-guard. - // See . - case CSSPropertyWebkitCompositionFillColor: - if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu - || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) { - validPrimitive = true; - } else { - parsedValue = parseColor(); - if (parsedValue) - m_valueList->next(); - } - break; - case CSSPropertyWebkitTouchCallout: - if (id == CSSValueDefault || id == CSSValueNone) - validPrimitive = true; - break; -#endif -#if ENABLE(TOUCH_EVENTS) - case CSSPropertyWebkitTapHighlightColor: - if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu - || (id >= CSSValueWebkitFocusRingColor && id < CSSValueWebkitText && inQuirksMode())) { - validPrimitive = true; - } else { - parsedValue = parseColor(); - if (parsedValue) - m_valueList->next(); - } - break; -#endif - // End Apple-specific properties - - /* shorthand properties */ - case CSSPropertyBackground: { - // Position must come before color in this array because a plain old "0" is a legal color - // in quirks mode but it's usually the X coordinate of a position. - const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, - CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin, - CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize }; - return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); - } - case CSSPropertyWebkitMask: { - const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskSourceType, CSSPropertyWebkitMaskRepeat, - CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize }; - return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(properties), important); - } - case CSSPropertyBorder: - // [ 'border-width' || 'border-style' || ] | inherit - { - 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); - return true; - } - return false; - } - case CSSPropertyBorderTop: - // [ 'border-top-width' || 'border-style' || ] | inherit - return parseShorthand(propId, borderTopShorthand(), important); - case CSSPropertyBorderRight: - // [ 'border-right-width' || 'border-style' || ] | inherit - return parseShorthand(propId, borderRightShorthand(), important); - case CSSPropertyBorderBottom: - // [ 'border-bottom-width' || 'border-style' || ] | inherit - return parseShorthand(propId, borderBottomShorthand(), important); - case CSSPropertyBorderLeft: - // [ 'border-left-width' || 'border-style' || ] | inherit - return parseShorthand(propId, borderLeftShorthand(), important); - case CSSPropertyWebkitBorderStart: - return parseShorthand(propId, webkitBorderStartShorthand(), important); - case CSSPropertyWebkitBorderEnd: - return parseShorthand(propId, webkitBorderEndShorthand(), important); - case CSSPropertyWebkitBorderBefore: - return parseShorthand(propId, webkitBorderBeforeShorthand(), important); - case CSSPropertyWebkitBorderAfter: - return parseShorthand(propId, webkitBorderAfterShorthand(), important); - case CSSPropertyOutline: - // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit - return parseShorthand(propId, outlineShorthand(), important); - case CSSPropertyBorderColor: - // {1,4} | inherit - return parse4Values(propId, borderColorShorthand().properties(), important); - case CSSPropertyBorderWidth: - // {1,4} | inherit - return parse4Values(propId, borderWidthShorthand().properties(), important); - case CSSPropertyBorderStyle: - // {1,4} | inherit - return parse4Values(propId, borderStyleShorthand().properties(), important); - case CSSPropertyMargin: - // {1,4} | inherit - return parse4Values(propId, marginShorthand().properties(), important); - case CSSPropertyPadding: - // {1,4} | inherit - return parse4Values(propId, paddingShorthand().properties(), important); - case CSSPropertyWebkitFlexFlow: - return parseShorthand(propId, webkitFlexFlowShorthand(), 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; - case CSSPropertyListStyle: - return parseShorthand(propId, listStyleShorthand(), important); - case CSSPropertyWebkitColumns: - return parseShorthand(propId, webkitColumnsShorthand(), important); - case CSSPropertyWebkitColumnRule: - return parseShorthand(propId, webkitColumnRuleShorthand(), important); - case CSSPropertyWebkitTextStroke: - return parseShorthand(propId, webkitTextStrokeShorthand(), important); - case CSSPropertyWebkitAnimation: - return parseAnimationShorthand(important); - case CSSPropertyTransition: - case CSSPropertyWebkitTransition: - return parseTransitionShorthand(propId, important); - case CSSPropertyInvalid: - return false; - case CSSPropertyPage: - return parsePage(propId, important); - case CSSPropertyFontStretch: - case CSSPropertyTextLineThrough: - case CSSPropertyTextOverline: - case CSSPropertyTextUnderline: - return false; - // CSS Text Layout Module Level 3: Vertical writing support - case CSSPropertyWebkitTextEmphasis: - return parseShorthand(propId, webkitTextEmphasisShorthand(), 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) - validPrimitive = true; - break; - - case CSSPropertyWebkitLineBoxContain: - if (id == CSSValueNone) - validPrimitive = true; - else - return parseLineBoxContain(important); - break; - case CSSPropertyWebkitFontFeatureSettings: - if (id == CSSValueNormal) - validPrimitive = true; - else - return parseFontFeatureSettings(important); - break; - - case CSSPropertyWebkitFontVariantLigatures: - if (id == CSSValueNormal) - validPrimitive = true; - else - return parseFontVariantLigatures(important); - break; - case CSSPropertyWebkitClipPath: - parsedValue = parseClipPath(); - break; -#if ENABLE(CSS_SHAPES) - case CSSPropertyWebkitShapeInside: - case CSSPropertyWebkitShapeOutside: - parsedValue = parseShapeProperty(propId); - break; - case CSSPropertyWebkitShapeMargin: - case CSSPropertyWebkitShapePadding: - validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validUnit(value, FLength | FNonNeg)); - break; - case CSSPropertyWebkitShapeImageThreshold: - validPrimitive = (RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled() && !id && validUnit(value, FNumber)); - break; -#endif -#if ENABLE(CSS_IMAGE_ORIENTATION) - case CSSPropertyImageOrientation: - validPrimitive = !id && validUnit(value, FAngle); - break; -#endif -#if ENABLE(CSS_IMAGE_RESOLUTION) - case CSSPropertyImageResolution: - parsedValue = parseImageResolution(); - break; -#endif - case CSSPropertyBorderBottomStyle: - case CSSPropertyBorderCollapse: - case CSSPropertyBorderLeftStyle: - case CSSPropertyBorderRightStyle: - case CSSPropertyBorderTopStyle: - case CSSPropertyBoxSizing: - case CSSPropertyCaptionSide: - case CSSPropertyClear: - case CSSPropertyDirection: - case CSSPropertyDisplay: - case CSSPropertyEmptyCells: - case CSSPropertyFloat: - case CSSPropertyFontStyle: - case CSSPropertyImageRendering: - case CSSPropertyListStylePosition: - case CSSPropertyListStyleType: - case CSSPropertyObjectFit: - case CSSPropertyOutlineStyle: - case CSSPropertyOverflowWrap: - case CSSPropertyOverflowX: - case CSSPropertyOverflowY: - case CSSPropertyPageBreakAfter: - case CSSPropertyPageBreakBefore: - case CSSPropertyPageBreakInside: - case CSSPropertyPointerEvents: - case CSSPropertyPosition: - case CSSPropertyResize: - case CSSPropertySpeak: - case CSSPropertyTableLayout: - case CSSPropertyTextLineThroughMode: - case CSSPropertyTextLineThroughStyle: - case CSSPropertyTextOverflow: - case CSSPropertyTextOverlineMode: - case CSSPropertyTextOverlineStyle: - case CSSPropertyTextRendering: - case CSSPropertyTextTransform: - case CSSPropertyTextUnderlineMode: - case CSSPropertyTextUnderlineStyle: - case CSSPropertyVisibility: - case CSSPropertyWebkitAppearance: - case CSSPropertyWebkitBackfaceVisibility: - case CSSPropertyWebkitBorderAfterStyle: - case CSSPropertyWebkitBorderBeforeStyle: - case CSSPropertyWebkitBorderEndStyle: - case CSSPropertyWebkitBorderFit: - case CSSPropertyWebkitBorderStartStyle: - case CSSPropertyWebkitBoxAlign: -#if ENABLE(CSS_BOX_DECORATION_BREAK) - case CSSPropertyWebkitBoxDecorationBreak: -#endif - case CSSPropertyWebkitBoxDirection: - case CSSPropertyWebkitBoxLines: - case CSSPropertyWebkitBoxOrient: - case CSSPropertyWebkitBoxPack: - case CSSPropertyWebkitColorCorrection: - case CSSPropertyWebkitColumnBreakAfter: - case CSSPropertyWebkitColumnBreakBefore: - case CSSPropertyWebkitColumnBreakInside: - case CSSPropertyWebkitColumnFill: - case CSSPropertyWebkitColumnRuleStyle: - case CSSPropertyWebkitAlignContent: - case CSSPropertyWebkitAlignItems: - case CSSPropertyWebkitAlignSelf: - case CSSPropertyWebkitFlexDirection: - case CSSPropertyWebkitFlexWrap: - case CSSPropertyWebkitJustifyContent: - case CSSPropertyWebkitFontKerning: - case CSSPropertyWebkitFontSmoothing: - case CSSPropertyWebkitHyphens: - case CSSPropertyWebkitGridAutoFlow: - case CSSPropertyWebkitLineAlign: - case CSSPropertyWebkitLineBreak: - case CSSPropertyWebkitLineSnap: - case CSSPropertyWebkitMarginAfterCollapse: - case CSSPropertyWebkitMarginBeforeCollapse: - case CSSPropertyWebkitMarginBottomCollapse: - case CSSPropertyWebkitMarginTopCollapse: - case CSSPropertyWebkitMarqueeDirection: - case CSSPropertyWebkitMarqueeStyle: - case CSSPropertyWebkitNbspMode: -#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) - case CSSPropertyWebkitOverflowScrolling: -#endif - case CSSPropertyWebkitPrintColorAdjust: -#if ENABLE(CSS_REGIONS) - case CSSPropertyWebkitRegionBreakAfter: - case CSSPropertyWebkitRegionBreakBefore: - case CSSPropertyWebkitRegionBreakInside: - case CSSPropertyWebkitRegionFragment: -#endif - case CSSPropertyWebkitRtlOrdering: - case CSSPropertyWebkitRubyPosition: -#if ENABLE(CSS3_TEXT) - case CSSPropertyWebkitTextAlignLast: -#endif // CSS3_TEXT - case CSSPropertyWebkitTextCombine: -#if ENABLE(CSS3_TEXT) - case CSSPropertyWebkitTextJustify: -#endif // CSS3_TEXT - case CSSPropertyWebkitTextSecurity: - 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: - // These properties should be handled before in isValidKeywordPropertyAndValue(). - ASSERT_NOT_REACHED(); - return false; -#if ENABLE(CSS_DEVICE_ADAPTATION) - // Properties bellow are validated inside parseViewportProperty, because we - // check for parser state inViewportScope. We need to invalidate if someone - // adds them outside a @viewport rule. - case CSSPropertyMaxZoom: - case CSSPropertyMinZoom: - case CSSPropertyOrientation: - case CSSPropertyUserZoom: - validPrimitive = false; - break; -#endif -#if ENABLE(SVG) - default: - return parseSVGValue(propId, important); -#endif - } - - if (validPrimitive) { - parsedValue = parseValidPrimitive(id, value); - m_valueList->next(); - } - ASSERT(!m_parsedCalculation); - if (parsedValue) { - if (!m_valueList->current() || inShorthand()) { - addProperty(propId, parsedValue.release(), important); - return true; - } - } - return false; -} - -void CSSParser::addFillValue(RefPtr& lval, PassRefPtr rval) -{ - if (lval) { - if (lval->isBaseValueList()) - toCSSValueList(lval.get())->append(rval); - else { - PassRefPtr oldlVal(lval.release()); - PassRefPtr list = CSSValueList::createCommaSeparated(); - list->append(oldlVal); - list->append(rval); - lval = list; - } - } - else - lval = rval; -} - -static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtr& cssValue) -{ - if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddingBox - || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueWebkitText) { - cssValue = cssValuePool().createIdentifierValue(parserValue->id); - return true; - } - return false; -} - -bool CSSParser::useLegacyBackgroundSizeShorthandBehavior() const -{ - return m_context.useLegacyBackgroundSizeShorthandBehavior; -} - -const int cMaxFillProperties = 9; - -bool CSSParser::parseFillShorthand(CSSPropertyID propId, const CSSPropertyID* properties, int numProperties, bool important) -{ - ASSERT(numProperties <= cMaxFillProperties); - if (numProperties > cMaxFillProperties) - return false; - - ShorthandScope scope(this, propId); - - bool parsedProperty[cMaxFillProperties] = { false }; - RefPtr values[cMaxFillProperties]; - RefPtr clipValue; - RefPtr positionYValue; - RefPtr repeatYValue; - bool foundClip = false; - int i; - bool foundPositionCSSProperty = false; - - while (m_valueList->current()) { - CSSParserValue* val = m_valueList->current(); - if (val->unit == CSSParserValue::Operator && val->iValue == ',') { - // We hit the end. Fill in all remaining values with the initial value. - m_valueList->next(); - for (i = 0; i < numProperties; ++i) { - if (properties[i] == CSSPropertyBackgroundColor && parsedProperty[i]) - // Color is not allowed except as the last item in a list for backgrounds. - // Reject the entire property. - return false; - - if (!parsedProperty[i] && properties[i] != CSSPropertyBackgroundColor) { - addFillValue(values[i], cssValuePool().createImplicitInitialValue()); - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue()); - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - 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()); - } - } - parsedProperty[i] = false; - } - if (!m_valueList->current()) - break; - } - - bool sizeCSSPropertyExpected = false; - if (isForwardSlashOperator(val) && foundPositionCSSProperty) { - sizeCSSPropertyExpected = true; - m_valueList->next(); - } - - foundPositionCSSProperty = false; - bool found = false; - for (i = 0; !found && i < numProperties; ++i) { - - if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgroundSize && properties[i] != CSSPropertyWebkitMaskSize)) - continue; - if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgroundSize || properties[i] == CSSPropertyWebkitMaskSize)) - continue; - - if (!parsedProperty[i]) { - RefPtr val1; - RefPtr val2; - CSSPropertyID propId1, propId2; - CSSParserValue* parserValue = m_valueList->current(); - if (parseFillProperty(properties[i], propId1, propId2, val1, val2)) { - parsedProperty[i] = found = true; - addFillValue(values[i], val1.release()); - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, val2.release()); - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - addFillValue(repeatYValue, val2.release()); - 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. - else - 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()); - foundClip = true; - } - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - foundPositionCSSProperty = true; - } - } - } - - // if we didn't find at least one match, this is an - // invalid shorthand and we have to ignore it - if (!found) - return false; - } - - // Now add all of the properties we found. - for (i = 0; i < numProperties; i++) { - // Fill in any remaining properties with the initial value. - if (!parsedProperty[i]) { - addFillValue(values[i], cssValuePool().createImplicitInitialValue()); - if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) - addFillValue(positionYValue, cssValuePool().createImplicitInitialValue()); - if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) - 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()); - } - } - if (properties[i] == CSSPropertyBackgroundPosition) { - addProperty(CSSPropertyBackgroundPositionX, values[i].release(), important); - // it's OK to call positionYValue.release() since we only see CSSPropertyBackgroundPosition once - addProperty(CSSPropertyBackgroundPositionY, positionYValue.release(), important); - } else if (properties[i] == CSSPropertyWebkitMaskPosition) { - addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), important); - // it's OK to call positionYValue.release() since we only see CSSPropertyWebkitMaskPosition once - addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release(), important); - } else if (properties[i] == CSSPropertyBackgroundRepeat) { - addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), important); - // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once - addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), important); - } else if (properties[i] == CSSPropertyWebkitMaskRepeat) { - addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), important); - // it's OK to call repeatYValue.release() since we only see CSSPropertyBackgroundPosition once - addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), important); - } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip) - // Value is already set while updating origin - continue; - else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i] && useLegacyBackgroundSizeShorthandBehavior()) - continue; - else - addProperty(properties[i], values[i].release(), important); - - // Add in clip values when we hit the corresponding origin property. - if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip) - addProperty(CSSPropertyBackgroundClip, clipValue.release(), important); - else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip) - addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), important); - } - - return true; -} - -void CSSParser::addAnimationValue(RefPtr& lval, PassRefPtr rval) -{ - if (lval) { - if (lval->isValueList()) - toCSSValueList(lval.get())->append(rval); - else { - PassRefPtr oldVal(lval.release()); - PassRefPtr list = CSSValueList::createCommaSeparated(); - list->append(oldVal); - list->append(rval); - lval = list; - } - } - else - lval = rval; -} - -bool CSSParser::parseAnimationShorthand(bool important) -{ - const StylePropertyShorthand& animationProperties = webkitAnimationShorthandForParsing(); - const unsigned numProperties = 7; - - // 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 == webkitAnimationShorthand().length()); - - ShorthandScope scope(this, CSSPropertyWebkitAnimation); - - bool parsedProperty[numProperties] = { false }; - AnimationParseContext context; - RefPtr values[numProperties]; - - unsigned i; - while (m_valueList->current()) { - CSSParserValue* val = m_valueList->current(); - if (val->unit == CSSParserValue::Operator && val->iValue == ',') { - // We hit the end. Fill in all remaining values with the initial value. - m_valueList->next(); - for (i = 0; i < numProperties; ++i) { - if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); - parsedProperty[i] = false; - } - if (!m_valueList->current()) - break; - context.commitFirstAnimation(); - } - - bool found = false; - for (i = 0; i < numProperties; ++i) { - if (!parsedProperty[i]) { - RefPtr val; - if (parseAnimationProperty(animationProperties.properties()[i], val, context)) { - parsedProperty[i] = found = true; - addAnimationValue(values[i], val.release()); - break; - } - } - - // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid. - if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation()) - return false; - } - - // if we didn't find at least one match, this is an - // invalid shorthand and we have to ignore it - if (!found) - return false; - } - - 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()); - - addProperty(animationProperties.properties()[i], values[i].release(), important); - } - - return true; -} - -bool CSSParser::parseTransitionShorthand(CSSPropertyID propId, bool important) -{ - const unsigned numProperties = 4; - const StylePropertyShorthand& shorthand = shorthandForProperty(propId); - ASSERT(numProperties == shorthand.length()); - - ShorthandScope scope(this, propId); - - bool parsedProperty[numProperties] = { false }; - AnimationParseContext context; - RefPtr values[numProperties]; - - unsigned i; - while (m_valueList->current()) { - CSSParserValue* val = m_valueList->current(); - if (val->unit == CSSParserValue::Operator && val->iValue == ',') { - // We hit the end. Fill in all remaining values with the initial value. - m_valueList->next(); - for (i = 0; i < numProperties; ++i) { - if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); - parsedProperty[i] = false; - } - if (!m_valueList->current()) - break; - context.commitFirstAnimation(); - } - - bool found = false; - for (i = 0; !found && i < numProperties; ++i) { - if (!parsedProperty[i]) { - RefPtr val; - if (parseAnimationProperty(shorthand.properties()[i], val, context)) { - parsedProperty[i] = found = true; - addAnimationValue(values[i], val.release()); - } - - // There are more values to process but 'none' or 'all' were already defined as the animation property, the declaration becomes invalid. - if (!context.animationPropertyKeywordAllowed() && context.hasCommittedFirstAnimation()) - return false; - } - } - - // if we didn't find at least one match, this is an - // invalid shorthand and we have to ignore it - if (!found) - return false; - } - - // Fill in any remaining properties with the initial value. - for (i = 0; i < numProperties; ++i) { - if (!parsedProperty[i]) - addAnimationValue(values[i], cssValuePool().createImplicitInitialValue()); - } - - // Now add all of the properties we found. - for (i = 0; i < numProperties; i++) - addPropertyWithPrefixingVariant(shorthand.properties()[i], values[i].release(), important); - - return true; -} - -bool CSSParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important) -{ - // We try to match as many properties as possible - // We set up an array of booleans to mark which property has been found, - // and we try to search for properties until it makes no longer any sense. - ShorthandScope scope(this, propId); - - bool found = false; - unsigned propertiesParsed = 0; - bool propertyFound[6]= { false, false, false, false, false, false }; // 6 is enough size. - - while (m_valueList->current()) { - found = false; - for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) { - if (!propertyFound[propIndex] && parseValue(shorthand.properties()[propIndex], important)) { - propertyFound[propIndex] = found = true; - propertiesParsed++; - } - } - - // if we didn't find at least one match, this is an - // invalid shorthand and we have to ignore it - if (!found) - return false; - } - - if (propertiesParsed == shorthand.length()) - return true; - - // Fill in any remaining properties with the initial value. - 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]; - for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex) - addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important); - } else - addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important); - } - - return true; -} - -bool CSSParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important) -{ - /* From the CSS 2 specs, 8.3 - * If there is only one value, it applies to all sides. If there are two values, the top and - * bottom margins are set to the first value and the right and left margins are set to the second. - * If there are three values, the top is set to the first value, the left and right are set to the - * second, and the bottom is set to the third. If there are four values, they apply to the top, - * right, bottom, and left, respectively. - */ - - unsigned num = inShorthand() ? 1 : m_valueList->size(); - - ShorthandScope scope(this, propId); - - // the order is top, right, bottom, left - switch (num) { - case 1: { - if (!parseValue(properties[0], important)) - return false; - CSSValue* value = m_parsedProperties.last().value(); - ImplicitScope implicitScope(this, PropertyImplicit); - addProperty(properties[1], value, important); - addProperty(properties[2], value, important); - addProperty(properties[3], value, important); - break; - } - case 2: { - if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) - return false; - CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - ImplicitScope implicitScope(this, PropertyImplicit); - addProperty(properties[2], value, important); - value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - addProperty(properties[3], value, important); - break; - } - case 3: { - 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); - addProperty(properties[3], value, important); - break; - } - case 4: { - if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || - !parseValue(properties[2], important) || !parseValue(properties[3], important)) - return false; - break; - } - default: { - return false; - } - } - - return true; -} - -// auto | -bool CSSParser::parsePage(CSSPropertyID propId, bool important) -{ - ASSERT(propId == CSSPropertyPage); - - if (m_valueList->size() != 1) - return false; - - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - if (value->id == CSSValueAuto) { - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); - return true; - } else if (value->id == 0 && value->unit == CSSPrimitiveValue::CSS_IDENT) { - addProperty(propId, createPrimitiveStringValue(value), important); - return true; - } - return false; -} - -// {1,2} | auto | [ || [ portrait | landscape] ] -bool CSSParser::parseSize(CSSPropertyID propId, bool important) -{ - ASSERT(propId == CSSPropertySize); - - if (m_valueList->size() > 2) - return false; - - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - RefPtr parsedValues = CSSValueList::createSpaceSeparated(); - - // First parameter. - SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None); - if (paramType == None) - return false; - - // Second parameter, if any. - value = m_valueList->next(); - if (value) { - paramType = parseSizeParameter(parsedValues.get(), value, paramType); - if (paramType == None) - return false; - } - - addProperty(propId, parsedValues.release(), important); - return true; -} - -CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType) -{ - switch (value->id) { - case CSSValueAuto: - if (prevParamType == None) { - parsedValues->append(cssValuePool().createIdentifierValue(value->id)); - return Auto; - } - return None; - case CSSValueLandscape: - case CSSValuePortrait: - if (prevParamType == None || prevParamType == PageSize) { - parsedValues->append(cssValuePool().createIdentifierValue(value->id)); - return Orientation; - } - return None; - case CSSValueA3: - case CSSValueA4: - case CSSValueA5: - case CSSValueB4: - case CSSValueB5: - case CSSValueLedger: - case CSSValueLegal: - case CSSValueLetter: - 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)); - return PageSize; - } - return None; - case 0: - if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || prevParamType == Length)) { - parsedValues->append(createPrimitiveNumericValue(value)); - return Length; - } - return None; - default: - return None; - } -} - -// [ ]+ | inherit | none -// inherit and none are handled in parseValue. -bool CSSParser::parseQuotes(CSSPropertyID propId, bool important) -{ - RefPtr values = CSSValueList::createCommaSeparated(); - while (CSSParserValue* val = m_valueList->current()) { - RefPtr parsedValue; - if (val->unit == CSSPrimitiveValue::CSS_STRING) - parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING); - else - break; - values->append(parsedValue.release()); - m_valueList->next(); - } - if (values->length()) { - addProperty(propId, values.release(), important); - m_valueList->next(); - return true; - } - return false; -} - -bool CSSParser::parseAlt(CSSPropertyID propID, bool important) -{ - CSSParserValue* val = m_valueList->current(); - RefPtr parsedValue; - - if (val->unit == CSSPrimitiveValue::CSS_STRING) - parsedValue = createPrimitiveStringValue(val); - else if (val->unit == CSSParserValue::Function) { - CSSParserValueList* args = val->function->args.get(); - if (!args) - return false; - if (equalIgnoringCase(val->function->name, "attr(")) - parsedValue = parseAttr(args); - } - - if (parsedValue) { - addProperty(propID, parsedValue.release(), important); - m_valueList->next(); - return true; - } - - return false; -} - -// [ | | | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit -// in CSS 2.1 this got somewhat reduced: -// [ | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit -bool CSSParser::parseContent(CSSPropertyID propId, bool important) -{ - RefPtr values = CSSValueList::createCommaSeparated(); - - while (CSSParserValue* val = m_valueList->current()) { - RefPtr parsedValue; - if (val->unit == CSSPrimitiveValue::CSS_URI) { - // url - parsedValue = CSSImageValue::create(completeURL(val->string)); - } else if (val->unit == CSSParserValue::Function) { - // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...) - CSSParserValueList* args = val->function->args.get(); - if (!args) - return false; - if (equalIgnoringCase(val->function->name, "attr(")) { - parsedValue = parseAttr(args); - if (!parsedValue) - return false; - } else if (equalIgnoringCase(val->function->name, "counter(")) { - parsedValue = parseCounterContent(args, false); - if (!parsedValue) - return false; - } else if (equalIgnoringCase(val->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(")) { - parsedValue = parseImageSet(); - if (!parsedValue) - return false; -#endif - } else if (isGeneratedImageValue(val)) { - if (!parseGeneratedImage(m_valueList.get(), parsedValue)) - return false; - } else - return false; - } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) { - // open-quote - // close-quote - // no-open-quote - // no-close-quote - // inherit - // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503). - // none - // normal - switch (val->id) { - case CSSValueOpenQuote: - case CSSValueCloseQuote: - case CSSValueNoOpenQuote: - case CSSValueNoCloseQuote: - case CSSValueNone: - case CSSValueNormal: - parsedValue = cssValuePool().createIdentifierValue(val->id); - break; - default: - break; - } - } else if (val->unit == CSSPrimitiveValue::CSS_STRING) { - parsedValue = createPrimitiveStringValue(val); - } - if (!parsedValue) - break; - values->append(parsedValue.release()); - m_valueList->next(); - } - - if (values->length()) { - addProperty(propId, values.release(), important); - m_valueList->next(); - return true; - } - - return false; -} - -PassRefPtr CSSParser::parseAttr(CSSParserValueList* args) -{ - if (args->size() != 1) - return 0; - - CSSParserValue* a = args->current(); - - if (a->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - - 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 (m_context.isHTMLDocument) - attrName = attrName.lower(); - - return cssValuePool().createValue(attrName, CSSPrimitiveValue::CSS_ATTR); -} - -PassRefPtr 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); - return parseColor(); -} - -bool CSSParser::parseFillImage(CSSParserValueList* valueList, RefPtr& value) -{ - if (valueList->current()->id == CSSValueNone) { - value = cssValuePool().createIdentifierValue(CSSValueNone); - return true; - } - if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) { - value = CSSImageValue::create(completeURL(valueList->current()->string)); - return true; - } - - 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(")) { - value = parseImageSet(); - if (value) - return true; - } -#endif - - return false; -} - -PassRefPtr CSSParser::parseFillPositionX(CSSParserValueList* valueList) -{ - 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); - } - if (validUnit(valueList->current(), FPercent | FLength)) - return createPrimitiveNumericValue(valueList->current()); - return 0; -} - -PassRefPtr CSSParser::parseFillPositionY(CSSParserValueList* valueList) -{ - 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); - } - if (validUnit(valueList->current(), FPercent | FLength)) - return createPrimitiveNumericValue(valueList->current()); - return 0; -} - -PassRefPtr CSSParser::parseFillPositionComponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode parsingMode) -{ - 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; - cumulativeFlags |= XFillPosition; - individualFlag = XFillPosition; - if (id == CSSValueRight) - percent = 100; - } - else if (id == CSSValueTop || id == CSSValueBottom) { - if (cumulativeFlags & YFillPosition) - return 0; - cumulativeFlags |= YFillPosition; - individualFlag = YFillPosition; - if (id == CSSValueBottom) - percent = 100; - } else if (id == CSSValueCenter) { - // Center is ambiguous, so we're not sure which position we've found yet, an x or a y. - percent = 50; - cumulativeFlags |= AmbiguousFillPosition; - individualFlag = AmbiguousFillPosition; - } - - if (parsingMode == ResolveValuesAsKeyword) - return cssValuePool().createIdentifierValue(id); - - return cssValuePool().createValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE); - } - if (validUnit(valueList->current(), 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()); - } - return 0; -} - -static bool isValueConflictingWithCurrentEdge(int value1, int value2) -{ - if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSValueLeft || value2 == CSSValueRight)) - return true; - - if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSValueTop || value2 == CSSValueBottom)) - return true; - - return false; -} - -static bool isFillPositionKeyword(CSSValueID value) -{ - return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBottom || value == CSSValueRight || value == CSSValueCenter; -} - -void CSSParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtr& value1, RefPtr& value2, PassRefPtr parsedValue1, PassRefPtr parsedValue2) -{ - // [ left | right ] [ ] && [ top | bottom ] [ | ] - // In the case of 4 values requires the second value to be a length or a percentage. - if (isFillPositionKeyword(parsedValue2->getValueID())) - return; - - unsigned cumulativeFlags = 0; - FillPositionFlag value3Flag = InvalidFillPosition; - RefPtr value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword); - if (!value3) - return; - - CSSValueID ident1 = parsedValue1->getValueID(); - CSSValueID ident3 = value3->getValueID(); - - if (ident1 == CSSValueCenter) - return; - - if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter) - return; - - // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is - // needed as the second call to parseFillPositionComponent was on purpose not checking it. In the - // case of two values top 20px is invalid but in the case of 4 values it becomes valid. - if (isValueConflictingWithCurrentEdge(ident1, ident3)) - return; - - valueList->next(); - - cumulativeFlags = 0; - FillPositionFlag value4Flag = InvalidFillPosition; - RefPtr value4 = parseFillPositionComponent(valueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword); - if (!value4) - return; - - // 4th value must be a length or a percentage. - if (isFillPositionKeyword(value4->getValueID())) - return; - - value1 = createPrimitiveValuePair(parsedValue1, parsedValue2); - value2 = createPrimitiveValuePair(value3, value4); - - if (ident1 == CSSValueTop || ident1 == CSSValueBottom) - value1.swap(value2); - - valueList->next(); -} -void CSSParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtr& value1, RefPtr& value2, PassRefPtr parsedValue1, PassRefPtr parsedValue2) -{ - unsigned cumulativeFlags = 0; - FillPositionFlag value3Flag = InvalidFillPosition; - RefPtr value3 = parseFillPositionComponent(valueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword); - - // value3 is not an expected value, we return. - if (!value3) - return; - - valueList->next(); - - bool swapNeeded = false; - CSSValueID ident1 = parsedValue1->getValueID(); - CSSValueID ident2 = parsedValue2->getValueID(); - CSSValueID ident3 = value3->getValueID(); - - CSSValueID firstPositionKeyword; - CSSValueID secondPositionKeyword; - - if (ident1 == CSSValueCenter) { - // requires the first 'center' to be followed by a keyword. - if (!isFillPositionKeyword(ident2)) - return; - - // If 'center' is the first keyword then the last one needs to be a length. - if (isFillPositionKeyword(ident3)) - return; - - firstPositionKeyword = CSSValueLeft; - if (ident2 == CSSValueLeft || ident2 == CSSValueRight) { - firstPositionKeyword = CSSValueTop; - swapNeeded = true; - } - value1 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(firstPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); - value2 = createPrimitiveValuePair(parsedValue2, value3); - } else if (ident3 == CSSValueCenter) { - if (isFillPositionKeyword(ident2)) - return; - - secondPositionKeyword = CSSValueTop; - if (ident1 == CSSValueTop || ident1 == CSSValueBottom) { - secondPositionKeyword = CSSValueLeft; - swapNeeded = true; - } - value1 = createPrimitiveValuePair(parsedValue1, parsedValue2); - value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::CSS_PERCENTAGE)); - } else { - RefPtr firstPositionValue; - RefPtr secondPositionValue; - - if (isFillPositionKeyword(ident2)) { - // To match CSS grammar, we should only accept: [ center | left | right | bottom | top ] [ left | right | top | bottom ] [ | ]. - ASSERT(ident2 != CSSValueCenter); - - if (isFillPositionKeyword(ident3)) - return; - - secondPositionValue = value3; - secondPositionKeyword = ident2; - firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); - } else { - // Per CSS, we should only accept: [ right | left | top | bottom ] [ | ] [ center | left | right | bottom | top ]. - if (!isFillPositionKeyword(ident3)) - return; - - firstPositionValue = parsedValue2; - secondPositionKeyword = ident3; - secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE); - } - - if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword)) - return; - - value1 = createPrimitiveValuePair(parsedValue1, firstPositionValue); - value2 = createPrimitiveValuePair(cssValuePool().createIdentifierValue(secondPositionKeyword), secondPositionValue); - } - - if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded) - value1.swap(value2); - -#ifndef NDEBUG - CSSPrimitiveValue* first = toCSSPrimitiveValue(value1.get()); - CSSPrimitiveValue* second = toCSSPrimitiveValue(value2.get()); - 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) -{ - return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLength, ReleaseParsedCalcValue); -} - -void CSSParser::parseFillPosition(CSSParserValueList* valueList, RefPtr& value1, RefPtr& 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)) - break; - } - - if (numberOfValues > 4) - return; - - // If we are parsing two values, we can safely call the CSS 2.1 parsing function and return. - if (numberOfValues <= 2) { - parse2ValuesFillPosition(valueList, value1, value2); - return; - } - - ASSERT(numberOfValues > 2 && numberOfValues <= 4); - - CSSParserValue* value = valueList->current(); - - // requires the first value to be a background keyword. - if (!isFillPositionKeyword(value->id)) - return; - - // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length. - unsigned cumulativeFlags = 0; - FillPositionFlag value1Flag = InvalidFillPosition; - FillPositionFlag value2Flag = InvalidFillPosition; - value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword); - if (!value1) - return; - - 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 . - cumulativeFlags = AmbiguousFillPosition; - value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword); - if (value2) - valueList->next(); - else { - value1.clear(); - return; - } - - RefPtr parsedValue1 = toCSSPrimitiveValue(value1.get()); - RefPtr parsedValue2 = toCSSPrimitiveValue(value2.get()); - - value1.clear(); - value2.clear(); - - // Per CSS3 syntax, 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()); - else - parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release(), parsedValue2.release()); -} - -void CSSParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtr& value1, RefPtr& value2) -{ - 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; - FillPositionFlag value1Flag = InvalidFillPosition; - FillPositionFlag value2Flag = InvalidFillPosition; - value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag); - if (!value1) - return; - - // 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(); - - // First check for the comma. If so, we are finished parsing this value or value pair. - if (isComma(value)) - value = 0; - - if (value) { - value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag); - if (value2) - valueList->next(); - else { - if (!inShorthand()) { - value1.clear(); - return; - } - } - } - - if (!value2) - // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position - // 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); - - if (value1Flag == YFillPosition || value2Flag == XFillPosition) - value1.swap(value2); -} - -void CSSParser::parseFillRepeat(RefPtr& value1, RefPtr& value2) -{ - CSSValueID id = m_valueList->current()->id; - if (id == CSSValueRepeatX) { - m_implicitShorthand = true; - value1 = cssValuePool().createIdentifierValue(CSSValueRepeat); - value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); - m_valueList->next(); - return; - } - if (id == CSSValueRepeatY) { - m_implicitShorthand = true; - value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); - value2 = cssValuePool().createIdentifierValue(CSSValueRepeat); - m_valueList->next(); - return; - } - if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) - value1 = cssValuePool().createIdentifierValue(id); - else { - value1 = 0; - return; - } - - CSSParserValue* value = m_valueList->next(); - - // Parse the second value if one is available - if (value && !isComma(value)) { - id = value->id; - if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) { - value2 = cssValuePool().createIdentifierValue(id); - m_valueList->next(); - return; - } - } - - // If only one value was specified, value2 is the same as value1. - m_implicitShorthand = true; - value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get())->getValueID()); -} - -PassRefPtr 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); - - RefPtr parsedValue1; - - if (value->id == CSSValueAuto) - parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto); - else { - if (!validUnit(value, FLength | FPercent)) - return 0; - parsedValue1 = createPrimitiveNumericValue(value); - } - - RefPtr parsedValue2; - if ((value = m_valueList->next())) { - if (value->unit == CSSParserValue::Operator && value->iValue == ',') - allowComma = false; - else if (value->id != CSSValueAuto) { - if (!validUnit(value, FLength | FPercent)) { - if (!inShorthand()) - return 0; - // 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); - } - } else if (!parsedValue2 && propId == CSSPropertyWebkitBackgroundSize) { - // For backwards compatibility we set the second value to the first if it is omitted. - // We only need to do this for -webkit-background-size. It should be safe to let masks match - // the real property. - parsedValue2 = parsedValue1; - } - - if (!parsedValue2) - return parsedValue1; - return createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()); -} - -bool CSSParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, - RefPtr& retValue1, RefPtr& retValue2) -{ - RefPtr values; - RefPtr values2; - CSSParserValue* val; - RefPtr value; - RefPtr value2; - - bool allowComma = false; - - retValue1 = retValue2 = 0; - propId1 = propId; - propId2 = propId; - if (propId == CSSPropertyBackgroundPosition) { - propId1 = CSSPropertyBackgroundPositionX; - propId2 = CSSPropertyBackgroundPositionY; - } else if (propId == CSSPropertyWebkitMaskPosition) { - propId1 = CSSPropertyWebkitMaskPositionX; - propId2 = CSSPropertyWebkitMaskPositionY; - } else if (propId == CSSPropertyBackgroundRepeat) { - propId1 = CSSPropertyBackgroundRepeatX; - propId2 = CSSPropertyBackgroundRepeatY; - } else if (propId == CSSPropertyWebkitMaskRepeat) { - propId1 = CSSPropertyWebkitMaskRepeatX; - propId2 = CSSPropertyWebkitMaskRepeatY; - } - - while ((val = m_valueList->current())) { - RefPtr currValue; - RefPtr currValue2; - - if (allowComma) { - if (!isComma(val)) - return false; - m_valueList->next(); - allowComma = false; - } else { - allowComma = true; - switch (propId) { - case CSSPropertyBackgroundColor: - currValue = parseBackgroundColor(); - if (currValue) - m_valueList->next(); - break; - case CSSPropertyBackgroundAttachment: - if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) { - currValue = cssValuePool().createIdentifierValue(val->id); - m_valueList->next(); - } - break; - case CSSPropertyBackgroundImage: - case CSSPropertyWebkitMaskImage: - if (parseFillImage(m_valueList.get(), currValue)) - m_valueList->next(); - break; - case CSSPropertyWebkitBackgroundClip: - case CSSPropertyWebkitBackgroundOrigin: - case CSSPropertyWebkitMaskClip: - 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); - m_valueList->next(); - } - break; - case CSSPropertyBackgroundClip: - if (parseBackgroundClip(val, currValue)) - m_valueList->next(); - break; - case CSSPropertyBackgroundOrigin: - if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { - currValue = cssValuePool().createIdentifierValue(val->id); - m_valueList->next(); - } - break; - case CSSPropertyBackgroundPosition: - case CSSPropertyWebkitMaskPosition: - parseFillPosition(m_valueList.get(), currValue, currValue2); - // parseFillPosition advances the m_valueList pointer. - break; - case CSSPropertyBackgroundPositionX: - case CSSPropertyWebkitMaskPositionX: { - currValue = parseFillPositionX(m_valueList.get()); - if (currValue) - m_valueList->next(); - break; - } - case CSSPropertyBackgroundPositionY: - case CSSPropertyWebkitMaskPositionY: { - currValue = parseFillPositionY(m_valueList.get()); - if (currValue) - m_valueList->next(); - break; - } - case CSSPropertyWebkitBackgroundComposite: - case CSSPropertyWebkitMaskComposite: - if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) { - currValue = cssValuePool().createIdentifierValue(val->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); - m_valueList->next(); - } - break; - case CSSPropertyBackgroundRepeat: - case CSSPropertyWebkitMaskRepeat: - parseFillRepeat(currValue, currValue2); - // parseFillRepeat advances the m_valueList pointer - break; - case CSSPropertyBackgroundSize: - case CSSPropertyWebkitBackgroundSize: - case CSSPropertyWebkitMaskSize: { - currValue = parseFillSize(propId, allowComma); - if (currValue) - m_valueList->next(); - break; - } - case CSSPropertyWebkitMaskSourceType: { - if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id == CSSValueLuminance) { - currValue = cssValuePool().createIdentifierValue(val->id); - m_valueList->next(); - } else - currValue = 0; - break; - } - default: - break; - } - if (!currValue) - return false; - - if (value && !values) { - values = CSSValueList::createCommaSeparated(); - values->append(value.release()); - } - - if (value2 && !values2) { - values2 = CSSValueList::createCommaSeparated(); - values2->append(value2.release()); - } - - if (values) - values->append(currValue.release()); - else - value = currValue.release(); - if (currValue2) { - if (values2) - values2->append(currValue2.release()); - else - value2 = currValue2.release(); - } - } - - // When parsing any fill shorthand property, we let it handle building up the lists for all - // properties. - if (inShorthand()) - break; - } - - if (values && values->length()) { - retValue1 = values.release(); - if (values2 && values2->length()) - retValue2 = values2.release(); - return true; - } - if (value) { - retValue1 = value.release(); - retValue2 = value2.release(); - return true; - } - return false; -} - -PassRefPtr CSSParser::parseAnimationDelay() -{ - CSSParserValue* value = m_valueList->current(); - if (validUnit(value, FTime)) - return createPrimitiveNumericValue(value); - return 0; -} - -PassRefPtr 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; -} - -PassRefPtr CSSParser::parseAnimationDuration() -{ - CSSParserValue* value = m_valueList->current(); - if (validUnit(value, FTime | FNonNeg)) - return createPrimitiveNumericValue(value); - return 0; -} - -PassRefPtr 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; -} - -PassRefPtr 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; -} - -PassRefPtr 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); - } - } - return 0; -} - -PassRefPtr CSSParser::parseAnimationPlayState() -{ - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueRunning || value->id == CSSValuePaused) - return cssValuePool().createIdentifierValue(value->id); - return 0; -} - -PassRefPtr CSSParser::parseAnimationProperty(AnimationParseContext& context) -{ - 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")) { - context.sawAnimationPropertyKeyword(); - return cssValuePool().createIdentifierValue(CSSValueAll); - } - if (equalIgnoringCase(value, "none")) { - context.commitAnimationPropertyKeyword(); - context.sawAnimationPropertyKeyword(); - return cssValuePool().createIdentifierValue(CSSValueNone); - } - return 0; -} - -bool CSSParser::parseTransformOriginShorthand(RefPtr& value1, RefPtr& value2, RefPtr& value3) -{ - parse2ValuesFillPosition(m_valueList.get(), value1, value2); - - // now get z - if (m_valueList->current()) { - if (validUnit(m_valueList->current(), FLength)) { - value3 = createPrimitiveNumericValue(m_valueList->current()); - m_valueList->next(); - return true; - } - return false; - } - value3 = cssValuePool().createImplicitInitialValue(); - return true; -} - -bool CSSParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result) -{ - CSSParserValue* v = args->current(); - if (!validUnit(v, FNumber)) - return false; - result = v->fValue; - v = args->next(); - if (!v) - // The last number in the function has no comma after it, so we're done. - return true; - if (!isComma(v)) - return false; - args->next(); - return true; -} - -PassRefPtr 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); - - // We must be a function. - if (value->unit != CSSParserValue::Function) - return 0; - - CSSParserValueList* args = value->function->args.get(); - - if (equalIgnoringCase(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; - - // There are two values. - int numSteps; - bool stepAtStart = false; - - CSSParserValue* v = args->current(); - if (!validUnit(v, FInteger)) - return 0; - numSteps = clampToInteger(v->fValue); - if (numSteps < 1) - return 0; - v = args->next(); - - if (v) { - // 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; - } - - return CSSStepsTimingFunctionValue::create(numSteps, stepAtStart); - } - - if (equalIgnoringCase(value->function->name, "cubic-bezier(")) { - // For cubic bezier, 4 values must be specified. - if (!args || args->size() != 7) - return 0; - - // 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 (x1 < 0 || x1 > 1) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, y1)) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, x2)) - return 0; - if (x2 < 0 || x2 > 1) - return 0; - if (!parseCubicBezierTimingFunctionValue(args, y2)) - return 0; - - return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2); - } - - return 0; -} - -bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr& result, AnimationParseContext& context) -{ - RefPtr values; - CSSParserValue* val; - RefPtr value; - bool allowComma = false; - - result = 0; - - while ((val = m_valueList->current())) { - RefPtr currValue; - if (allowComma) { - if (!isComma(val)) - return false; - m_valueList->next(); - allowComma = false; - } - 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(); - return false; - } - - if (!currValue) - return false; - - if (value && !values) { - values = CSSValueList::createCommaSeparated(); - values->append(value.release()); - } - - if (values) - values->append(currValue.release()); - else - value = currValue.release(); - - allowComma = true; - } - - // When parsing the 'transition' shorthand property, we let it handle building up the lists for all - // properties. - if (inShorthand()) - break; - } - - if (values && values->length()) { - result = values.release(); - return true; - } - if (value) { - result = value.release(); - return true; - } - return false; -} - -// The function parses [ || ] in (which can be stand alone or with 'span'). -bool CSSParser::parseIntegerOrStringFromGridPosition(RefPtr& numericValue, RefPtr& gridLineName) -{ - CSSParserValue* value = m_valueList->current(); - if (validUnit(value, FInteger) && value->fValue) { - numericValue = createPrimitiveNumericValue(value); - value = m_valueList->next(); - if (value && value->unit == CSSPrimitiveValue::CSS_STRING) { - gridLineName = createPrimitiveStringValue(m_valueList->current()); - m_valueList->next(); - } - return true; - } - - if (value->unit == CSSPrimitiveValue::CSS_STRING) { - gridLineName = createPrimitiveStringValue(m_valueList->current()); - value = m_valueList->next(); - if (value && validUnit(value, FInteger) && value->fValue) { - numericValue = createPrimitiveNumericValue(value); - m_valueList->next(); - } - return true; - } - - return false; -} - -PassRefPtr CSSParser::parseGridPosition() -{ - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueAuto) { - m_valueList->next(); - return cssValuePool().createIdentifierValue(CSSValueAuto); - } - - if (value->id != CSSValueSpan && value->unit == CSSPrimitiveValue::CSS_IDENT) { - m_valueList->next(); - return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING); - } - - RefPtr numericValue; - RefPtr gridLineName; - bool hasSeenSpanKeyword = false; - - if (parseIntegerOrStringFromGridPosition(numericValue, gridLineName)) { - value = m_valueList->current(); - if (value && value->id == CSSValueSpan) { - hasSeenSpanKeyword = true; - m_valueList->next(); - } - } else if (value->id == CSSValueSpan) { - hasSeenSpanKeyword = true; - if (m_valueList->next()) - parseIntegerOrStringFromGridPosition(numericValue, gridLineName); - } - - // 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 0; - - // If we didn't parse anything, this is not a valid grid position. - if (!hasSeenSpanKeyword && !gridLineName && !numericValue) - return 0; - - // Negative numbers are not allowed for span (but are for ). - if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0) - return 0; - - RefPtr values = CSSValueList::createSpaceSeparated(); - if (hasSeenSpanKeyword) - values->append(cssValuePool().createIdentifierValue(CSSValueSpan)); - if (numericValue) - values->append(numericValue.release()); - if (gridLineName) - values->append(gridLineName.release()); - ASSERT(values->length()); - return values.release(); -} - -static PassRefPtr gridMissingGridPositionValue(CSSValue* value) -{ - if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isString()) - return value; - - return cssValuePool().createIdentifierValue(CSSValueAuto); -} - -bool CSSParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId, bool important) -{ - ShorthandScope scope(this, shorthandId); - const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId); - ASSERT(shorthand.length() == 2); - - RefPtr startValue = parseGridPosition(); - if (!startValue) - return false; - - RefPtr 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.get()); - - addProperty(shorthand.properties()[0], startValue, important); - addProperty(shorthand.properties()[1], endValue, important); - return true; -} - -bool CSSParser::parseGridAreaShorthand(bool important) -{ - ASSERT(cssGridLayoutEnabled()); - - ShorthandScope scope(this, CSSPropertyWebkitGridArea); - ASSERT(shorthandForProperty(CSSPropertyWebkitGridArea).length() == 4); - - RefPtr rowStartValue = parseGridPosition(); - if (!rowStartValue) - return false; - - RefPtr columnStartValue; - if (!parseSingleGridAreaLonghand(columnStartValue)) - return false; - - RefPtr rowEndValue; - if (!parseSingleGridAreaLonghand(rowEndValue)) - return false; - - RefPtr columnEndValue; - if (!parseSingleGridAreaLonghand(columnEndValue)) - return false; - - if (!columnStartValue) - columnStartValue = gridMissingGridPositionValue(rowStartValue.get()); - - if (!rowEndValue) - rowEndValue = gridMissingGridPositionValue(rowStartValue.get()); - - if (!columnEndValue) - columnEndValue = gridMissingGridPositionValue(columnStartValue.get()); - - addProperty(CSSPropertyWebkitGridRowStart, rowStartValue, important); - addProperty(CSSPropertyWebkitGridColumnStart, columnStartValue, important); - addProperty(CSSPropertyWebkitGridRowEnd, rowEndValue, important); - addProperty(CSSPropertyWebkitGridColumnEnd, columnEndValue, important); - return true; -} - -bool CSSParser::parseSingleGridAreaLonghand(RefPtr& property) -{ - if (!m_valueList->current()) - return true; - - if (!isForwardSlashOperator(m_valueList->current())) - return false; - - if (!m_valueList->next()) - return false; - - property = parseGridPosition(); - return true; -} - -void CSSParser::parseGridTrackNames(CSSParserValueList& parserValues, CSSValueList& values) -{ - do { - RefPtr name = createPrimitiveStringValue(parserValues.current()); - values.append(name.release()); - parserValues.next(); - } while (parserValues.current() && parserValues.current()->unit == CSSPrimitiveValue::CSS_STRING); -} - -bool CSSParser::parseGridTrackList(CSSPropertyID propId, bool important) -{ - CSSParserValue* value = m_valueList->current(); - if (value->id == CSSValueNone) { - if (m_valueList->next()) - return false; - - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); - return true; - } - - RefPtr values = CSSValueList::createSpaceSeparated(); - // Handle leading track names - if (m_valueList->current() && m_valueList->current()->unit == CSSPrimitiveValue::CSS_STRING) - parseGridTrackNames(*m_valueList, *values); - - bool seenTrackSizeOrRepeatFunction = false; - while (CSSParserValue* currentValue = m_valueList->current()) { - if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat(")) { - if (!parseGridTrackRepeatFunction(*values)) - return false; - } else { - RefPtr value = parseGridTrackSize(*m_valueList); - if (!value) - return false; - values->append(value.release()); - } - seenTrackSizeOrRepeatFunction = true; - - if (m_valueList->current() && m_valueList->current()->unit == CSSPrimitiveValue::CSS_STRING) - parseGridTrackNames(*m_valueList, *values); - } - - if (!seenTrackSizeOrRepeatFunction) - return false; - - addProperty(propId, values.release(), important); - return true; -} - -bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list) -{ - CSSParserValueList* arguments = m_valueList->current()->function->args.get(); - if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1))) - return false; - - ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0); - size_t repetitions = arguments->valueAt(0)->fValue; - RefPtr repeatedValues = CSSValueList::createSpaceSeparated(); - arguments->next(); // Skip the repetition count. - arguments->next(); // Skip the comma. - - while (arguments->current()) { - if (arguments->current()->unit == CSSPrimitiveValue::CSS_STRING) - parseGridTrackNames(*arguments, *repeatedValues); - - if (!arguments->current()) - break; - - RefPtr trackSize = parseGridTrackSize(*arguments); - if (!trackSize) - return false; - - repeatedValues->append(trackSize.release()); - } - - 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; -} - -PassRefPtr CSSParser::parseGridTrackSize(CSSParserValueList& inputList) -{ - CSSParserValue* currentValue = inputList.current(); - inputList.next(); - - if (currentValue->id == CSSValueAuto) - return cssValuePool().createIdentifierValue(CSSValueAuto); - - if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax(")) { - // The spec defines the following grammar: minmax( , ) - CSSParserValueList* arguments = currentValue->function->args.get(); - if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1))) - return 0; - - RefPtr minTrackBreadth = parseGridBreadth(arguments->valueAt(0)); - if (!minTrackBreadth) - return 0; - - RefPtr maxTrackBreadth = parseGridBreadth(arguments->valueAt(2)); - if (!maxTrackBreadth) - return 0; - - RefPtr parsedArguments = CSSValueList::createCommaSeparated(); - parsedArguments->append(minTrackBreadth); - parsedArguments->append(maxTrackBreadth); - return CSSFunctionValue::create("minmax(", parsedArguments); - } - - return parseGridBreadth(currentValue); -} - -PassRefPtr CSSParser::parseGridBreadth(CSSParserValue* currentValue) -{ - if (currentValue->id == CSSValueWebkitMinContent || currentValue->id == CSSValueWebkitMaxContent) - return cssValuePool().createIdentifierValue(currentValue->id); - - if (currentValue->unit == CSSPrimitiveValue::CSS_FR) { - double flexValue = currentValue->fValue; - - // Fractional unit is a non-negative dimension. - if (flexValue <= 0) - return 0; - - return cssValuePool().createValue(flexValue, CSSPrimitiveValue::CSS_FR); - } - - if (!validUnit(currentValue, FNonNeg | FLength | FPercent)) - return 0; - - return createPrimitiveNumericValue(currentValue); -} - -#if ENABLE(DASHBOARD_SUPPORT) - -#define DASHBOARD_REGION_NUM_PARAMETERS 6 -#define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2 - -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 == ',') - return args->next(); - } - return args->current(); -} - -bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) -{ - bool valid = true; - - CSSParserValue* value = m_valueList->current(); - - if (value->id == CSSValueNone) { - if (m_valueList->next()) - return false; - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); - return valid; - } - - RefPtr firstRegion = DashboardRegion::create(); - DashboardRegion* region = 0; - - while (value) { - if (region == 0) { - region = firstRegion.get(); - } else { - RefPtr nextRegion = DashboardRegion::create(); - region->m_next = nextRegion; - region = nextRegion.get(); - } - - if (value->unit != CSSParserValue::Function) { - valid = false; - break; - } - - // Commas count as values, so allow (function name is dashboard-region for DASHBOARD_SUPPORT feature): - // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) - // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l) - // also allow - // 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) { - valid = false; - break; - } - - int numArgs = args->size(); - if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) && - (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))) { - valid = false; - break; - } - - // First arg is a label. - CSSParserValue* arg = args->current(); - if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { - valid = false; - break; - } - - region->m_label = arg->string; - - // Second arg is a type. - arg = args->next(); - arg = skipCommaInDashboardRegion(args); - if (arg->unit != CSSPrimitiveValue::CSS_IDENT) { - valid = false; - break; - } - - if (equalIgnoringCase(arg, "circle")) - region->m_isCircle = true; - else if (equalIgnoringCase(arg, "rectangle")) - region->m_isRectangle = true; - else { - valid = false; - break; - } - - region->m_geometryType = arg->string; - - 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 amount = cssValuePool().createIdentifierValue(CSSValueInvalid); - - region->setTop(amount); - region->setRight(amount); - region->setBottom(amount); - region->setLeft(amount); - } else { - // Next four arguments must be offset numbers - int i; - for (i = 0; i < 4; i++) { - arg = args->next(); - arg = skipCommaInDashboardRegion(args); - - valid = arg->id == CSSValueAuto || validUnit(arg, FLength); - if (!valid) - break; - - RefPtr amount = arg->id == CSSValueAuto ? - cssValuePool().createIdentifierValue(CSSValueAuto) : - createPrimitiveNumericValue(arg); - - if (i == 0) - region->setTop(amount); - else if (i == 1) - region->setRight(amount); - else if (i == 2) - region->setBottom(amount); - else - region->setLeft(amount); - } - } - - if (args->next()) - return false; - - value = m_valueList->next(); - } - - if (valid) - addProperty(propId, cssValuePool().createValue(firstRegion.release()), important); - - return valid; -} - -#endif /* ENABLE(DASHBOARD_SUPPORT) */ - -PassRefPtr CSSParser::parseGridTemplate() -{ - NamedGridAreaMap gridAreaMap; - size_t rowCount = 0; - size_t columnCount = 0; - - while (CSSParserValue* currentValue = m_valueList->current()) { - if (currentValue->unit != CSSPrimitiveValue::CSS_STRING) - return 0; - - String gridRowNames = currentValue->string; - if (!gridRowNames.length()) - return 0; - - Vector columnNames; - gridRowNames.split(' ', columnNames); - - if (columnCount && (columnCount != columnNames.size())) { - // The declaration is invalid if all the rows don't have the number of columns. - return 0; - } - - if (!columnCount) { - columnCount = columnNames.size(); - ASSERT(columnCount); - } - - for (size_t 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. - size_t lookAheadColumn; - for (lookAheadColumn = currentColumn; lookAheadColumn < (columnCount - 1); ++lookAheadColumn) { - if (columnNames[lookAheadColumn + 1] != gridAreaName) - break; - } - - auto gridAreaIterator = gridAreaMap.find(gridAreaName); - if (gridAreaIterator == gridAreaMap.end()) - gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowCount), GridSpan(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.initialPositionIndex + 1) - return 0; - - // 2. The new area starts at the same position as the previously parsed area. - if (currentColumn != gridCoordinate.columns.initialPositionIndex) - return 0; - - // 3. The new area ends at the same position as the previously parsed area. - if (lookAheadColumn != gridCoordinate.columns.finalPositionIndex) - return 0; - - ++gridCoordinate.rows.finalPositionIndex; - } - currentColumn = lookAheadColumn; - } - - ++rowCount; - m_valueList->next(); - } - - if (!rowCount || !columnCount) - return 0; - - return CSSGridTemplateValue::create(gridAreaMap, rowCount, columnCount); -} - -PassRefPtr CSSParser::parseCounterContent(CSSParserValueList* args, bool counters) -{ - unsigned numArgs = args->size(); - if (counters && numArgs != 3 && numArgs != 5) - return 0; - if (!counters && numArgs != 1 && numArgs != 3) - return 0; - - CSSParserValue* i = args->current(); - if (i->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - RefPtr identifier = createPrimitiveStringValue(i); - - RefPtr separator; - if (!counters) - separator = cssValuePool().createValue(String(), CSSPrimitiveValue::CSS_STRING); - else { - i = args->next(); - if (i->unit != CSSParserValue::Operator || i->iValue != ',') - return 0; - - i = args->next(); - if (i->unit != CSSPrimitiveValue::CSS_STRING) - return 0; - - separator = createPrimitiveStringValue(i); - } - - RefPtr listStyle; - i = args->next(); - if (!i) // Make the list style default decimal - listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal); - else { - if (i->unit != CSSParserValue::Operator || i->iValue != ',') - return 0; - - i = args->next(); - if (i->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - - CSSValueID listStyleID = CSSValueInvalid; - if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValueKatakanaIroha)) - listStyleID = i->id; - else - return 0; - - listStyle = cssValuePool().createIdentifierValue(listStyleID); - } - - return cssValuePool().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(); - - if (!equalIgnoringCase(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::create(); - bool valid = true; - int i = 0; - CSSParserValue* a = args->current(); - while (a) { - valid = a->id == CSSValueAuto || validUnit(a, FLength); - if (!valid) - break; - RefPtr length = a->id == CSSValueAuto ? - cssValuePool().createIdentifierValue(CSSValueAuto) : - createPrimitiveNumericValue(a); - if (i == 0) - rect->setTop(length); - else if (i == 1) - rect->setRight(length); - else if (i == 2) - 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(); - } else { - valid = false; - break; - } - } - i++; - } - if (valid) { - addProperty(propId, cssValuePool().createValue(rect.release()), important); - m_valueList->next(); - return true; - } - return false; -} - -static void completeBorderRadii(RefPtr radii[4]) -{ - if (radii[3]) - return; - if (!radii[2]) { - if (!radii[1]) - radii[1] = radii[0]; - radii[2] = radii[0]; - } - radii[3] = radii[1]; -} - -// FIXME: This should be refactored with CSSParser::parseBorderRadius. -// CSSParser::parseBorderRadius contains support for some legacy radius construction. -PassRefPtr CSSParser::parseInsetRoundedCorners(PassRefPtr shape, CSSParserValueList* args) -{ - CSSParserValue* argument = args->next(); - - if (!argument) - return nullptr; - - std::unique_ptr radiusArguments(new CSSParserValueList); - while (argument) { - radiusArguments->addValue(*argument); - argument = args->next(); - } - - unsigned num = radiusArguments->size(); - if (!num || num > 9) - return nullptr; - - RefPtr radii[2][4]; - - unsigned indexAfterSlash = 0; - for (unsigned i = 0; i < num; ++i) { - CSSParserValue* value = radiusArguments->valueAt(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; - } - - if (i - indexAfterSlash >= 4) - return nullptr; - - if (!validUnit(value, FLength | FPercent | FNonNeg)) - return nullptr; - - RefPtr radius = createPrimitiveNumericValue(value); - - if (!indexAfterSlash) - radii[0][i] = radius; - else - radii[1][i - indexAfterSlash] = radius.release(); - } - - 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 CSSParser::parseBasicShapeInset(CSSParserValueList* args) -{ - ASSERT(args); - - RefPtr shape = CSSBasicShapeInset::create(); - - CSSParserValue* argument = args->current(); - Vector > widthArguments; - bool hasRoundedInset = false; - while (argument) { - if (argument->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(argument->string, "round")) { - hasRoundedInset = true; - break; - } - - Units unitFlags = FLength | FPercent; - if (!validUnit(argument, unitFlags) || widthArguments.size() > 4) - return nullptr; - - widthArguments.append(createPrimitiveNumericValue(argument)); - argument = args->next(); - } - - switch (widthArguments.size()) { - case 1: { - shape->setTop(widthArguments[0]); - shape->setRight(widthArguments[0]); - shape->setBottom(widthArguments[0]); - shape->setLeft(widthArguments[0]); - break; - } - case 2: { - shape->setTop(widthArguments[0]); - shape->setRight(widthArguments[1]); - shape->setBottom(widthArguments[0]); - shape->setLeft(widthArguments[1]); - break; - } - case 3: { - shape->setTop(widthArguments[0]); - shape->setRight(widthArguments[1]); - shape->setBottom(widthArguments[2]); - shape->setLeft(widthArguments[1]); - break; - } - case 4: { - shape->setTop(widthArguments[0]); - shape->setRight(widthArguments[1]); - shape->setBottom(widthArguments[2]); - shape->setLeft(widthArguments[3]); - break; - } - default: - return nullptr; - } - - if (hasRoundedInset) - return parseInsetRoundedCorners(shape, args); - return shape; -} - -PassRefPtr CSSParser::parseBasicShapeRectangle(CSSParserValueList* args) -{ - ASSERT(args); - - // rect(x, y, width, height, [[rx], ry]) - if (args->size() != 7 && args->size() != 9 && args->size() != 11) - return 0; - - RefPtr shape = CSSBasicShapeRectangle::create(); - - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); - 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 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; - - argument = args->next(); - } - argumentNumber++; - } - - if (argumentNumber < 4) - return 0; - return shape; -} - -PassRefPtr CSSParser::parseBasicShapeInsetRectangle(CSSParserValueList* args) -{ - ASSERT(args); - - // inset-rectangle(top, right, bottom, left, [[rx], ry]) - if (args->size() != 7 && args->size() != 9 && args->size() != 11) - return 0; - - RefPtr shape = CSSBasicShapeInsetRectangle::create(); - - unsigned argumentNumber = 0; - CSSParserValue* argument = args->current(); - while (argument) { - Units unitFlags = FLength | FPercent | FNonNeg; - if (!validUnit(argument, unitFlags)) - return 0; - - RefPtr 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); - break; - } - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - - argument = args->next(); - } - argumentNumber++; - } - - if (argumentNumber < 4) - return 0; - return shape; -} - -PassRefPtr CSSParser::parseShapeRadius(CSSParserValue* value) -{ - if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide) - return cssValuePool().createIdentifierValue(value->id); - - if (!validUnit(value, FLength | FPercent | FNonNeg)) - return 0; - - return createPrimitiveNumericValue(value); -} - -PassRefPtr CSSParser::parseBasicShapeCircle(CSSParserValueList* args) -{ - ASSERT(args); - - // circle(radius) - // circle(radius at - // circle(at ) - // where position defines centerX and centerY using a CSS data type. - RefPtr shape = CSSBasicShapeCircle::create(); - - 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 0; - - if (!args->currentIndex() && argument->id != CSSValueAt) { - if (RefPtr radius = parseShapeRadius(argument)) { - shape->setRadius(radius); - continue; - } - - return 0; - } - - if (argument->id == CSSValueAt) { - RefPtr centerX; - RefPtr centerY; - args->next(); // set list to start of position center - parseFillPosition(args, centerX, centerY); - if (centerX && centerY) { - ASSERT(centerX->isPrimitiveValue()); - ASSERT(centerY->isPrimitiveValue()); - shape->setCenterX(toCSSPrimitiveValue(centerX.get())); - shape->setCenterY(toCSSPrimitiveValue(centerY.get())); - } else - return 0; - } else - return 0; - } - - return shape; -} - -PassRefPtr CSSParser::parseDeprecatedBasicShapeCircle(CSSParserValueList* args) -{ - ASSERT(args); - - // circle(centerX, centerY, radius) - if (args->size() != 5) - return 0; - - RefPtr shape = CSSDeprecatedBasicShapeCircle::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; - } - - if (!validUnit(argument, unitFlags)) - return 0; - - RefPtr 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; - } - - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - argument = args->next(); - } - argumentNumber++; - } - - if (argumentNumber < 3) - return 0; - return shape; -} - -PassRefPtr CSSParser::parseBasicShapeEllipse(CSSParserValueList* args) -{ - ASSERT(args); - - // ellipse(radiusX) - // ellipse(radiusX at - // ellipse(radiusX radiusY) - // ellipse(radiusX radiusY at - // ellipse(at ) - // where position defines centerX and centerY using a CSS data type. - RefPtr shape = CSSBasicShapeEllipse::create(); - - 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 0; - - if (args->currentIndex() < 2 && argument->id != CSSValueAt) { - if (RefPtr radius = parseShapeRadius(argument)) { - if (!shape->radiusX()) - shape->setRadiusX(radius); - else - shape->setRadiusY(radius); - continue; - } - - return 0; - } - - if (argument->id != CSSValueAt) - return 0; - RefPtr centerX; - RefPtr centerY; - args->next(); // set list to start of position center - parseFillPosition(args, centerX, centerY); - if (!centerX || !centerY) - return 0; - - ASSERT(centerX->isPrimitiveValue()); - ASSERT(centerY->isPrimitiveValue()); - shape->setCenterX(toCSSPrimitiveValue(centerX.get())); - shape->setCenterY(toCSSPrimitiveValue(centerY.get())); - } - - return shape; -} - -PassRefPtr CSSParser::parseDeprecatedBasicShapeEllipse(CSSParserValueList* args) -{ - ASSERT(args); - - // ellipse(centerX, centerY, radiusX, radiusY) - if (args->size() != 7) - return 0; - - RefPtr shape = CSSDeprecatedBasicShapeEllipse::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 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; - } - - argument = args->next(); - if (argument) { - if (!isComma(argument)) - return 0; - argument = args->next(); - } - argumentNumber++; - } - - if (argumentNumber < 4) - return 0; - return shape; -} - -PassRefPtr CSSParser::parseBasicShapePolygon(CSSParserValueList* args) -{ - ASSERT(args); - - unsigned size = args->size(); - if (!size) - return 0; - - RefPtr shape = CSSBasicShapePolygon::create(); - - 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; - - argument = args->next(); - size -= 2; - } - - // , ... -> each pair has 3 elements except the last one - if (!size || (size % 3) - 2) - return 0; - - CSSParserValue* argumentX = argument; - while (argumentX) { - if (!validUnit(argumentX, FLength | FPercent)) - return 0; - - CSSParserValue* argumentY = args->next(); - if (!argumentY || !validUnit(argumentY, FLength | FPercent)) - return 0; - - RefPtr xLength = createPrimitiveNumericValue(argumentX); - RefPtr yLength = createPrimitiveNumericValue(argumentY); - - shape->appendPoint(xLength.release(), yLength.release()); - - CSSParserValue* commaOrNull = args->next(); - if (!commaOrNull) - argumentX = 0; - else if (!isComma(commaOrNull)) - return 0; - else - argumentX = args->next(); - } - - return shape; -} - -static bool isBoxValue(CSSValueID valueId, CSSPropertyID propId) -{ - switch (valueId) { - case CSSValueContentBox: - case CSSValuePaddingBox: - case CSSValueBorderBox: - case CSSValueMarginBox: - return true; - case CSSValueBoundingBox: - return propId == CSSPropertyWebkitClipPath; - default: break; - } - - return false; -} - -PassRefPtr CSSParser::parseBasicShapeAndOrBox(CSSPropertyID propId) -{ - CSSParserValue* value = m_valueList->current(); - - bool shapeFound = false; - bool boxFound = false; - CSSValueID valueId; - - RefPtr 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 shapeValue = parseBasicShape(); - if (!shapeValue) - return nullptr; - list->append(shapeValue.release()); - shapeFound = true; - } else if (isBoxValue(valueId, propId) && !boxFound) { - list->append(parseValidPrimitive(valueId, value)); - boxFound = true; - m_valueList->next(); - } else - return nullptr; - value = m_valueList->current(); - } - - if (m_valueList->current()) - return nullptr; - return list.release(); -} - -#if ENABLE(CSS_SHAPES) -PassRefPtr CSSParser::parseShapeProperty(CSSPropertyID propId) -{ - if (!RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled()) - return nullptr; - - CSSParserValue* value = m_valueList->current(); - CSSValueID valueId = value->id; - RefPtr keywordValue; - RefPtr shapeValue; - - if (valueId == CSSValueNone - || (valueId == CSSValueOutsideShape && propId == CSSPropertyWebkitShapeInside)) { - keywordValue = parseValidPrimitive(valueId, value); - m_valueList->next(); - return keywordValue.release(); - } - - RefPtr imageValue; - if (valueId != CSSValueNone && parseFillImage(m_valueList.get(), imageValue)) { - m_valueList->next(); - return imageValue.release(); - } - - return parseBasicShapeAndOrBox(propId); -} -#endif - -PassRefPtr CSSParser::parseClipPath() -{ - CSSParserValue* value = m_valueList->current(); - CSSValueID valueId = value->id; - - if (valueId == CSSValueNone) { - m_valueList->next(); - return parseValidPrimitive(valueId, value); - } -#if ENABLE(SVG) - if (value->unit == CSSPrimitiveValue::CSS_URI) { - m_valueList->next(); - return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI); - } -#endif - - return parseBasicShapeAndOrBox(CSSPropertyWebkitClipPath); -} - -// FIXME This function is temporary to allow for an orderly transition between -// the new CSS Shapes circle and ellipse syntax. It will be removed when the -// old syntax is removed. -static bool isDeprecatedBasicShape(CSSParserValueList* args) -{ - for (unsigned i = args->currentIndex(); i < args->size(); ++i) { - CSSParserValue* value = args->valueAt(i); - if (isComma(value)) - return true; - } - - return false; -} - -PassRefPtr CSSParser::parseBasicShape() -{ - CSSParserValue* value = m_valueList->current(); - ASSERT(value->unit == CSSParserValue::Function); - CSSParserValueList* args = value->function->args.get(); - - if (!args) - return nullptr; - - RefPtr shape; - if (equalIgnoringCase(value->function->name, "rectangle(")) - shape = parseBasicShapeRectangle(args); - else if (equalIgnoringCase(value->function->name, "circle(")) - if (isDeprecatedBasicShape(args)) - shape = parseDeprecatedBasicShapeCircle(args); - else - shape = parseBasicShapeCircle(args); - else if (equalIgnoringCase(value->function->name, "ellipse(")) - if (isDeprecatedBasicShape(args)) - shape = parseDeprecatedBasicShapeEllipse(args); - else - shape = parseBasicShapeEllipse(args); - else if (equalIgnoringCase(value->function->name, "polygon(")) - shape = parseBasicShapePolygon(args); - else if (equalIgnoringCase(value->function->name, "inset-rectangle(")) - shape = parseBasicShapeInsetRectangle(args); - else if (equalIgnoringCase(value->function->name, "inset(")) - shape = parseBasicShapeInset(args); - - if (!shape) - return nullptr; - - m_valueList->next(); - return cssValuePool().createValue(shape.release()); -} - -// [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' -bool CSSParser::parseFont(bool important) -{ - // Let's check if there is an inherit or initial somewhere in the shorthand. - for (unsigned i = 0; i < m_valueList->size(); ++i) { - if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->valueAt(i)->id == CSSValueInitial) - return false; - } - - ShorthandScope scope(this, CSSPropertyFont); - // Optional font-style, font-variant and font-weight. - bool fontStyleParsed = false; - bool fontVariantParsed = false; - 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); - 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); - fontVariantParsed = true; - } else if (!fontWeightParsed && parseFontWeight(important)) - fontWeightParsed = true; - else - break; - m_valueList->next(); - } - - if (!value) - return false; - - if (!fontStyleParsed) - addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); - if (!fontVariantParsed) - addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); - if (!fontWeightParsed) - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); - - // Now a font size _must_ come. - // | | | | inherit - if (!parseFontSize(important)) - return false; - - value = m_valueList->current(); - if (!value) - return false; - - if (isForwardSlashOperator(value)) { - // The line-height property. - value = m_valueList->next(); - if (!value) - return false; - if (!parseLineHeight(important)) - return false; - } else - addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important, true); - - // Font family must come now. - RefPtr parsedFamilyValue = parseFontFamily(); - if (!parsedFamilyValue) - return false; - - addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important); - - // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that - // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values - // but we don't seem to support them at the moment. They should also be added here once implemented. - if (m_valueList->current()) - return false; - - return true; -} - -class FontFamilyValueBuilder { -public: - FontFamilyValueBuilder(CSSValueList* list) - : m_list(list) - { - } - - void add(const CSSParserString& string) - { - if (!m_builder.isEmpty()) - m_builder.append(' '); - - if (string.is8Bit()) { - m_builder.append(string.characters8(), string.length()); - return; - } - - m_builder.append(string.characters16(), string.length()); - } - - void commit() - { - if (m_builder.isEmpty()) - return; - m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString())); - m_builder.clear(); - } - -private: - StringBuilder m_builder; - CSSValueList* m_list; -}; - -PassRefPtr CSSParser::parseFontFamily() -{ - RefPtr list = CSSValueList::createCommaSeparated(); - CSSParserValue* value = m_valueList->current(); - - FontFamilyValueBuilder familyBuilder(list.get()); - bool inFamily = false; - - while (value) { - CSSParserValue* nextValue = m_valueList->next(); - bool nextValBreaksFont = !nextValue || - (nextValue->unit == CSSParserValue::Operator && nextValue->iValue == ','); - bool nextValIsFontName = nextValue && - ((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; - if (valueIsKeyword && !inFamily) { - if (nextValBreaksFont) - value = m_valueList->next(); - else if (nextValIsFontName) - value = nextValue; - continue; - } - - if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) { - if (inFamily) - familyBuilder.add(value->string); - else if (nextValBreaksFont || !nextValIsFontName) - list->append(cssValuePool().createIdentifierValue(value->id)); - else { - familyBuilder.commit(); - familyBuilder.add(value->string); - inFamily = true; - } - } else if (value->unit == CSSPrimitiveValue::CSS_STRING) { - // Strings never share in a family name. - inFamily = false; - familyBuilder.commit(); - list->append(cssValuePool().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)); - else { - familyBuilder.commit(); - familyBuilder.add(value->string); - inFamily = true; - } - } else { - break; - } - - if (!nextValue) - break; - - if (nextValBreaksFont) { - value = m_valueList->next(); - familyBuilder.commit(); - inFamily = false; - } - else if (nextValIsFontName) - value = nextValue; - else - break; - } - familyBuilder.commit(); - - if (!list->length()) - list = 0; - return list.release(); -} - -bool CSSParser::parseLineHeight(bool important) -{ - CSSParserValue* value = m_valueList->current(); - CSSValueID id = value->id; - bool validPrimitive = false; - // normal | | | | inherit - if (id == CSSValueNormal) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg)); - if (validPrimitive && (!m_valueList->next() || inShorthand())) - addProperty(CSSPropertyLineHeight, parseValidPrimitive(id, value), important); - return validPrimitive; -} - -bool CSSParser::parseFontSize(bool important) -{ - CSSParserValue* value = m_valueList->current(); - CSSValueID id = value->id; - bool validPrimitive = false; - // | | | | inherit - if (id >= CSSValueXxSmall && id <= CSSValueLarger) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); - if (validPrimitive && (!m_valueList->next() || inShorthand())) - addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), important); - return validPrimitive; -} - -bool CSSParser::parseFontVariant(bool important) -{ - RefPtr values; - if (m_valueList->size() > 1) - values = CSSValueList::createCommaSeparated(); - CSSParserValue* val; - bool expectComma = false; - while ((val = m_valueList->current())) { - RefPtr 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); - CSSValueID value = static_cast(CSSValue100 + weight / 100 - 1); - ASSERT(value >= CSSValue100 && value <= CSSValue900); - return value; -} - -bool CSSParser::parseFontWeight(bool important) -{ - CSSParserValue* value = m_valueList->current(); - if ((value->id >= CSSValueNormal) && (value->id <= CSSValue900)) { - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(value->id), important); - return true; - } - if (validUnit(value, FInteger | FNonNeg, CSSQuirksMode)) { - int weight = static_cast(value->fValue); - if (!(weight % 100) && weight >= 100 && weight <= 900) { - addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue(createFontWeightValueKeyword(weight)), important); - return true; - } - } - return false; -} - -bool CSSParser::parseFontFaceSrcURI(CSSValueList* valueList) -{ - RefPtr uriValue(CSSFontFaceSrcValue::create(completeURL(m_valueList->current()->string))); - - CSSParserValue* value = m_valueList->next(); - if (!value) { - valueList->append(uriValue.releaseNonNull()); - return true; - } - if (value->unit == CSSParserValue::Operator && value->iValue == ',') { - m_valueList->next(); - valueList->append(uriValue.releaseNonNull()); - return true; - } - - if (value->unit != CSSParserValue::Function || !equalIgnoringCase(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, - // but CSSFontFaceSrcValue stores only one format. Allowing one format for now. - CSSParserValueList* args = value->function->args.get(); - 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.releaseNonNull()); - value = m_valueList->next(); - if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') - m_valueList->next(); - return true; -} - -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)); - else if (args->current()->unit == CSSPrimitiveValue::CSS_IDENT) { - StringBuilder builder; - for (CSSParserValue* localValue = args->current(); localValue; localValue = args->next()) { - if (localValue->unit != CSSPrimitiveValue::CSS_IDENT) - return false; - if (!builder.isEmpty()) - builder.append(' '); - builder.append(localValue->string); - } - valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString())); - } else - return false; - - if (CSSParserValue* value = m_valueList->next()) { - if (value->unit == CSSParserValue::Operator && value->iValue == ',') - m_valueList->next(); - } - return true; -} - -bool CSSParser::parseFontFaceSrc() -{ - RefPtr values(CSSValueList::createCommaSeparated()); - - while (CSSParserValue* value = m_valueList->current()) { - if (value->unit == CSSPrimitiveValue::CSS_URI) { - if (!parseFontFaceSrcURI(values.get())) - return false; - } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local(")) { - if (!parseFontFaceSrcLocal(values.get())) - return false; - } else - return false; - } - if (!values->length()) - return false; - - addProperty(CSSPropertySrc, values.release(), m_important); - m_valueList->next(); - return true; -} - -bool CSSParser::parseFontFaceUnicodeRange() -{ - RefPtr values = CSSValueList::createCommaSeparated(); - bool failed = false; - bool operatorExpected = false; - for (; m_valueList->current(); m_valueList->next(), operatorExpected = !operatorExpected) { - if (operatorExpected) { - if (m_valueList->current()->unit == CSSParserValue::Operator && m_valueList->current()->iValue == ',') - continue; - failed = true; - break; - } - if (m_valueList->current()->unit != CSSPrimitiveValue::CSS_UNICODE_RANGE) { - failed = true; - break; - } - - String rangeString = m_valueList->current()->string; - UChar32 from = 0; - UChar32 to = 0; - unsigned length = rangeString.length(); - - if (length < 3) { - failed = true; - break; - } - - unsigned i = 2; - while (i < length) { - UChar c = rangeString[i]; - if (c == '-' || c == '?') - break; - from *= 16; - if (c >= '0' && c <= '9') - from += c - '0'; - else if (c >= 'A' && c <= 'F') - from += 10 + c - 'A'; - else if (c >= 'a' && c <= 'f') - from += 10 + c - 'a'; - else { - failed = true; - break; - } - i++; - } - if (failed) - break; - - if (i == length) - to = from; - else if (rangeString[i] == '?') { - unsigned span = 1; - while (i < length && rangeString[i] == '?') { - span *= 16; - from *= 16; - i++; - } - if (i < length) - failed = true; - to = from + span - 1; - } else { - if (length < i + 2) { - failed = true; - break; - } - i++; - while (i < length) { - UChar c = rangeString[i]; - to *= 16; - if (c >= '0' && c <= '9') - to += c - '0'; - else if (c >= 'A' && c <= 'F') - to += 10 + c - 'A'; - else if (c >= 'a' && c <= 'f') - to += 10 + c - 'a'; - else { - failed = true; - break; - } - i++; - } - if (failed) - break; - } - if (from <= to) - values->append(CSSUnicodeRangeValue::create(from, to)); - } - if (failed || !values->length()) - return false; - addProperty(CSSPropertyUnicodeRange, values.release(), m_important); - return true; -} - -// Returns the number of characters which form a valid double -// and are terminated by the given terminator character -template -static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator) -{ - int length = end - string; - if (length < 1) - return 0; - - bool decimalMarkSeen = false; - int processedLength = 0; - - for (int i = 0; i < length; ++i) { - if (string[i] == terminator) { - processedLength = i; - break; - } - if (!isASCIIDigit(string[i])) { - if (!decimalMarkSeen && string[i] == '.') - decimalMarkSeen = true; - else - return 0; - } - } - - if (decimalMarkSeen && processedLength == 1) - return 0; - - return processedLength; -} - -// Returns the number of characters consumed for parsing a valid double -// terminated by the given terminator character -template -static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value) -{ - int length = checkForValidDouble(string, end, terminator); - if (!length) - return 0; - - int position = 0; - double localValue = 0; - - // The consumed characters here are guaranteed to be - // ASCII digits with or without a decimal mark - for (; position < length; ++position) { - if (string[position] == '.') - break; - localValue = localValue * 10 + string[position] - '0'; - } - - if (++position == length) { - value = localValue; - return length; - } - - double fraction = 0; - double scale = 1; - - while (position < length && scale < MAX_SCALE) { - fraction = fraction * 10 + string[position++] - '0'; - scale *= 10; - } - - value = localValue + fraction / scale; - return length; -} - -template -static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value) -{ - const CharacterType* current = string; - double localValue = 0; - bool negative = false; - while (current != end && isHTMLSpace(*current)) - current++; - if (current != end && *current == '-') { - negative = true; - current++; - } - if (current == end || !isASCIIDigit(*current)) - return false; - while (current != end && isASCIIDigit(*current)) { - double newValue = localValue * 10 + *current++ - '0'; - if (newValue >= 255) { - // Clamp values at 255. - localValue = 255; - while (current != end && isASCIIDigit(*current)) - ++current; - break; - } - localValue = newValue; - } - - if (current == end) - return false; - - if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%')) - return false; - - if (*current == '.') { - // We already parsed the integral part, try to parse - // the fraction part of the percentage value. - double percentage = 0; - int numCharactersParsed = parseDouble(current, end, '%', percentage); - if (!numCharactersParsed) - return false; - current += numCharactersParsed; - if (*current != '%') - return false; - localValue += percentage; - } - - if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%') - return false; - - if (*current == '%') { - expect = CSSPrimitiveValue::CSS_PERCENTAGE; - localValue = localValue / 100.0 * 256.0; - // Clamp values at 255 for percentages over 100% - if (localValue > 255) - localValue = 255; - current++; - } else - expect = CSSPrimitiveValue::CSS_NUMBER; - - while (current != end && isHTMLSpace(*current)) - current++; - if (current == end || *current++ != terminator) - return false; - // Clamp negative values at zero. - value = negative ? 0 : static_cast(localValue); - string = current; - return true; -} - -template -static inline bool isTenthAlpha(const CharacterType* string, const int length) -{ - // "0.X" - if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2])) - return true; - - // ".X" - if (length == 2 && string[0] == '.' && isASCIIDigit(string[1])) - return true; - - return false; -} - -template -static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value) -{ - while (string != end && isHTMLSpace(*string)) - string++; - - bool negative = false; - - if (string != end && *string == '-') { - negative = true; - string++; - } - - value = 0; - - int length = end - string; - if (length < 2) - return false; - - if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2])) - return false; - - if (string[0] != '0' && string[0] != '1' && string[0] != '.') { - if (checkForValidDouble(string, end, terminator)) { - value = negative ? 0 : 255; - string = end; - return true; - } - return false; - } - - if (length == 2 && string[0] != '.') { - value = !negative && string[0] == '1' ? 255 : 0; - string = end; - return true; - } - - if (isTenthAlpha(string, length - 1)) { - static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 }; - value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0']; - string = end; - return true; - } - - double alpha = 0; - if (!parseDouble(string, end, terminator, alpha)) - return false; - value = negative ? 0 : static_cast(alpha * nextafter(256.0, 0.0)); - string = end; - return true; -} - -template -static inline bool mightBeRGBA(const CharacterType* characters, unsigned length) -{ - if (length < 5) - return false; - return characters[4] == '(' - && isASCIIAlphaCaselessEqual(characters[0], 'r') - && isASCIIAlphaCaselessEqual(characters[1], 'g') - && isASCIIAlphaCaselessEqual(characters[2], 'b') - && isASCIIAlphaCaselessEqual(characters[3], 'a'); -} - -template -static inline bool mightBeRGB(const CharacterType* characters, unsigned length) -{ - if (length < 4) - return false; - return characters[3] == '(' - && isASCIIAlphaCaselessEqual(characters[0], 'r') - && isASCIIAlphaCaselessEqual(characters[1], 'g') - && isASCIIAlphaCaselessEqual(characters[2], 'b'); -} - -template -static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict) -{ - CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN; - - if (!strict && length >= 3) { - if (characters[0] == '#') { - if (Color::parseHexColor(characters + 1, length - 1, rgb)) - return true; - } else { - if (Color::parseHexColor(characters, length, rgb)) - return true; - } - } - - // Try rgba() syntax. - if (mightBeRGBA(characters, length)) { - const CharacterType* current = characters + 5; - const CharacterType* end = characters + length; - int red; - int green; - int blue; - int alpha; - - if (!parseColorIntOrPercentage(current, end, ',', expect, red)) - return false; - if (!parseColorIntOrPercentage(current, end, ',', expect, green)) - return false; - if (!parseColorIntOrPercentage(current, end, ',', expect, blue)) - return false; - if (!parseAlphaValue(current, end, ')', alpha)) - return false; - if (current != end) - return false; - rgb = makeRGBA(red, green, blue, alpha); - return true; - } - - // Try rgb() syntax. - if (mightBeRGB(characters, length)) { - const CharacterType* current = characters + 4; - const CharacterType* end = characters + length; - int red; - int green; - int blue; - if (!parseColorIntOrPercentage(current, end, ',', expect, red)) - return false; - if (!parseColorIntOrPercentage(current, end, ',', expect, green)) - return false; - if (!parseColorIntOrPercentage(current, end, ')', expect, blue)) - return false; - if (current != end) - return false; - rgb = makeRGB(red, green, blue); - return true; - } - - return false; -} - -template -bool CSSParser::fastParseColor(RGBA32& rgb, const StringType& name, bool strict) -{ - unsigned length = name.length(); - bool parseResult; - - if (!length) - return false; - - if (name.is8Bit()) - parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict); - else - parseResult = fastParseColorInternal(rgb, name.characters16(), length, strict); - - if (parseResult) - return true; - - // Try named colors. - Color tc; - tc.setNamedColor(name); - if (tc.isValid()) { - rgb = tc.rgb(); - return true; - } - return false; -} - -inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc) -{ - const double result = m_parsedCalculation ? m_parsedCalculation->doubleValue() : v->fValue; - if (releaseCalc == ReleaseParsedCalcValue) - m_parsedCalculation.release(); - return result; -} - -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(")); -} - -inline int CSSParser::colorIntFromValue(CSSParserValue* v) -{ - bool isPercent; - - if (m_parsedCalculation) - isPercent = m_parsedCalculation->category() == CalcPercent; - else - isPercent = v->unit == CSSPrimitiveValue::CSS_PERCENTAGE; - - const double value = parsedDouble(v, ReleaseParsedCalcValue); - - if (value <= 0.0) - return 0; - - if (isPercent) { - if (value >= 100.0) - return 255; - return static_cast(value * 256.0 / 100.0); - } - - if (value >= 255.0) - return 255; - - return static_cast(value); -} - -bool CSSParser::parseColorParameters(CSSParserValue* value, int* colorArray, bool parseAlpha) -{ - CSSParserValueList* args = value->function->args.get(); - CSSParserValue* v = args->current(); - Units unitType = FUnknown; - // Get the first value and its type - if (validUnit(v, FInteger, CSSStrictMode)) - unitType = FInteger; - else if (validUnit(v, FPercent, CSSStrictMode)) - unitType = FPercent; - else - return false; - - colorArray[0] = colorIntFromValue(v); - for (int i = 1; i < 3; i++) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') - return false; - v = args->next(); - if (!validUnit(v, unitType, CSSStrictMode)) - return false; - colorArray[i] = colorIntFromValue(v); - } - if (parseAlpha) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') - return false; - v = args->next(); - if (!validUnit(v, FNumber, CSSStrictMode)) - return false; - const double value = parsedDouble(v, ReleaseParsedCalcValue); - // 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(std::max(0, std::min(1, value)) * nextafter(256.0, 0.0)); - } - return true; -} - -// The CSS3 specification defines the format of a HSL color as -// hsl(, , ) -// and with alpha, the format is -// hsla(, , , ) -// The first value, HUE, is in an angle with a value between 0 and 360 -bool CSSParser::parseHSLParameters(CSSParserValue* value, double* colorArray, bool parseAlpha) -{ - CSSParserValueList* args = value->function->args.get(); - CSSParserValue* v = args->current(); - // Get the first value - if (!validUnit(v, FNumber, CSSStrictMode)) - return false; - // normalize the Hue value and change it to be between 0 and 1.0 - colorArray[0] = (((static_cast(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 != ',') - return false; - v = args->next(); - if (!validUnit(v, FPercent, CSSStrictMode)) - return false; - colorArray[i] = std::max(0, std::min(100, parsedDouble(v, ReleaseParsedCalcValue))) / 100.0; // needs to be value between 0 and 1.0 - } - if (parseAlpha) { - v = args->next(); - if (v->unit != CSSParserValue::Operator && v->iValue != ',') - return false; - v = args->next(); - if (!validUnit(v, FNumber, CSSStrictMode)) - return false; - colorArray[3] = std::max(0, std::min(1, parsedDouble(v, ReleaseParsedCalcValue))); - } - return true; -} - -PassRefPtr CSSParser::parseColor(CSSParserValue* value) -{ - RGBA32 c = Color::transparent; - if (!parseColorFromValue(value ? value : m_valueList->current(), c)) - return 0; - return cssValuePool().createColorValue(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((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)) - 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(")) { - 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(")) { - 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(")) { - 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(")) { - double colorValues[4]; - if (!parseHSLParameters(value, colorValues, true)) - return false; - c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]); - } else - return false; - } - - return true; -} - -// 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) - : property(prop) - , m_parser(parser) - , allowX(true) - , allowY(false) - , allowBlur(false) - , allowSpread(false) - , allowColor(true) - , allowStyle(prop == CSSPropertyWebkitBoxShadow || prop == CSSPropertyBoxShadow) - , allowBreak(true) - { - } - - bool allowLength() { return allowX || allowY || allowBlur || allowSpread; } - - void commitValue() - { - // Handle the ,, case gracefully by doing nothing. - if (x || y || blur || spread || color || style) { - if (!values) - values = CSSValueList::createCommaSeparated(); - - // Construct the current shadow value and add it to the list. - 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; - - allowX = true; - allowColor = true; - allowBreak = true; - allowY = false; - allowBlur = false; - allowSpread = false; - allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; - } - - void commitLength(CSSParserValue* v) - { - RefPtr val = m_parser->createPrimitiveNumericValue(v); - - if (allowX) { - x = val.release(); - allowX = false; - allowY = true; - allowColor = false; - allowStyle = false; - allowBreak = false; - } else if (allowY) { - y = val.release(); - allowY = false; - allowBlur = true; - allowColor = true; - allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; - allowBreak = true; - } else if (allowBlur) { - blur = val.release(); - allowBlur = false; - allowSpread = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; - } else if (allowSpread) { - spread = val.release(); - allowSpread = false; - } - } - - void commitColor(PassRefPtr val) - { - color = val; - allowColor = false; - if (allowX) { - allowStyle = false; - allowBreak = false; - } else { - allowBlur = false; - allowSpread = false; - allowStyle = property == CSSPropertyWebkitBoxShadow || property == CSSPropertyBoxShadow; - } - } - - void commitStyle(CSSParserValue* v) - { - style = cssValuePool().createIdentifierValue(v->id); - allowStyle = false; - if (allowX) - allowBreak = false; - else { - allowBlur = false; - allowSpread = false; - allowColor = false; - } - } - - CSSPropertyID property; - CSSParser* m_parser; - - RefPtr values; - RefPtr x; - RefPtr y; - RefPtr blur; - RefPtr spread; - RefPtr style; - RefPtr color; - - bool allowX; - bool allowY; - bool allowBlur; - bool allowSpread; - bool allowColor; - bool allowStyle; // inset or not. - bool allowBreak; -}; - -PassRefPtr CSSParser::parseShadow(CSSParserValueList* valueList, CSSPropertyID propId) -{ - ShadowParseContext context(propId, this); - CSSParserValue* val; - while ((val = valueList->current())) { - // Check for a comma break first. - if (val->unit == CSSParserValue::Operator) { - if (val->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) - // -webkit-svg-shadow does not support multiple values. - if (propId == CSSPropertyWebkitSvgShadow) - return 0; -#endif - // The value is good. Commit it. - context.commitValue(); - } else if (validUnit(val, FLength, CSSStrictMode)) { - // We required a length and didn't get one. Invalid. - if (!context.allowLength()) - return 0; - - // Blur radius must be non-negative. - if (context.allowBlur && !validUnit(val, FLength | FNonNeg, CSSStrictMode)) - return 0; - - // A length is allowed here. Construct the value and add it. - context.commitLength(val); - } else if (val->id == CSSValueInset) { - if (!context.allowStyle) - return 0; - - context.commitStyle(val); - } else { - // The only other type of value that's ok is a color value. - RefPtr parsedColor; - bool isColor = ((val->id >= CSSValueAqua && val->id <= CSSValueWindowtext) || val->id == CSSValueMenu - || (val->id >= CSSValueWebkitFocusRingColor && val->id <= CSSValueWebkitText && inQuirksMode()) - || val->id == CSSValueCurrentcolor); - if (isColor) { - if (!context.allowColor) - return 0; - parsedColor = cssValuePool().createIdentifierValue(val->id); - } - - if (!parsedColor) - // It's not built-in. Try to parse it as a color. - parsedColor = parseColor(val); - - if (!parsedColor || !context.allowColor) - return 0; // 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(); - } - - if (context.allowBreak) { - context.commitValue(); - if (context.values && context.values->length()) - return context.values.release(); - } - - return 0; -} - -bool CSSParser::parseReflect(CSSPropertyID propId, bool important) -{ - // box-reflect: - - // Direction comes first. - CSSParserValue* val = m_valueList->current(); - RefPtr direction; - switch (val->id) { - case CSSValueAbove: - case CSSValueBelow: - case CSSValueLeft: - case CSSValueRight: - direction = cssValuePool().createIdentifierValue(val->id); - break; - default: - return false; - } - - // The offset comes next. - val = m_valueList->next(); - RefPtr offset; - if (!val) - offset = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX); - else { - if (!validUnit(val, FLength | FPercent)) - return false; - offset = createPrimitiveNumericValue(val); - } - - // Now for the mask. - RefPtr mask; - val = m_valueList->next(); - if (val) { - if (!parseBorderImage(propId, mask)) - return false; - } - - addProperty(propId, CSSReflectValue::create(direction.release(), offset.release(), mask.release()), important); - m_valueList->next(); - return true; -} - -bool CSSParser::parseFlex(CSSParserValueList* args, bool important) -{ - if (!args || !args->size() || args->size() > 3) - return false; - static const double unsetValue = -1; - double flexGrow = unsetValue; - double flexShrink = unsetValue; - RefPtr flexBasis; - - while (CSSParserValue* arg = args->current()) { - if (validUnit(arg, FNumber | FNonNeg)) { - if (flexGrow == unsetValue) - flexGrow = arg->fValue; - else if (flexShrink == unsetValue) - flexShrink = arg->fValue; - else if (!arg->fValue) { - // 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); - } 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 { - // Not a valid arg for flex. - return false; - } - args->next(); - } - - if (flexGrow == unsetValue) - flexGrow = 1; - if (flexShrink == unsetValue) - flexShrink = 1; - if (!flexBasis) - flexBasis = cssValuePool().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); - return true; -} - -struct BorderImageParseContext { - BorderImageParseContext() - : m_canAdvance(false) - , m_allowCommit(true) - , m_allowImage(true) - , m_allowImageSlice(true) - , m_allowRepeat(true) - , m_allowForwardSlashOperator(false) - , m_requireWidth(false) - , m_requireOutset(false) - {} - - bool canAdvance() const { return m_canAdvance; } - void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; } - - bool allowCommit() const { return m_allowCommit; } - bool allowImage() const { return m_allowImage; } - bool allowImageSlice() const { return m_allowImageSlice; } - bool allowRepeat() const { return m_allowRepeat; } - bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; } - - bool requireWidth() const { return m_requireWidth; } - bool requireOutset() const { return m_requireOutset; } - - void commitImage(PassRefPtr image) - { - m_image = image; - m_canAdvance = true; - m_allowCommit = true; - m_allowImage = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false; - m_allowImageSlice = !m_imageSlice; - m_allowRepeat = !m_repeat; - } - void commitImageSlice(PassRefPtr slice) - { - m_imageSlice = slice; - m_canAdvance = true; - m_allowCommit = m_allowForwardSlashOperator = true; - m_allowImageSlice = m_requireWidth = m_requireOutset = false; - m_allowImage = !m_image; - m_allowRepeat = !m_repeat; - } - void commitForwardSlashOperator() - { - m_canAdvance = true; - m_allowCommit = m_allowImage = m_allowImageSlice = m_allowRepeat = m_allowForwardSlashOperator = false; - if (!m_borderSlice) { - m_requireWidth = true; - m_requireOutset = false; - } else { - m_requireOutset = true; - m_requireWidth = false; - } - } - void commitBorderWidth(PassRefPtr slice) - { - m_borderSlice = slice; - m_canAdvance = true; - m_allowCommit = m_allowForwardSlashOperator = true; - m_allowImageSlice = m_requireWidth = m_requireOutset = false; - m_allowImage = !m_image; - m_allowRepeat = !m_repeat; - } - void commitBorderOutset(PassRefPtr outset) - { - m_outset = outset; - m_canAdvance = true; - m_allowCommit = true; - m_allowImageSlice = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false; - m_allowImage = !m_image; - m_allowRepeat = !m_repeat; - } - void commitRepeat(PassRefPtr repeat) - { - m_repeat = repeat; - m_canAdvance = true; - m_allowCommit = true; - m_allowRepeat = m_allowForwardSlashOperator = m_requireWidth = m_requireOutset = false; - m_allowImageSlice = !m_imageSlice; - m_allowImage = !m_image; - } - - PassRefPtr commitWebKitBorderImage() - { - return createBorderImageValue(m_image, m_imageSlice, m_borderSlice, m_outset, m_repeat); - } - - void commitBorderImage(CSSParser* parser, bool important) - { - commitBorderImageProperty(CSSPropertyBorderImageSource, parser, m_image, important); - commitBorderImageProperty(CSSPropertyBorderImageSlice, parser, m_imageSlice, important); - commitBorderImageProperty(CSSPropertyBorderImageWidth, parser, m_borderSlice, important); - commitBorderImageProperty(CSSPropertyBorderImageOutset, parser, m_outset, important); - commitBorderImageProperty(CSSPropertyBorderImageRepeat, parser, m_repeat, important); - } - - void commitBorderImageProperty(CSSPropertyID propId, CSSParser* parser, PassRefPtr value, bool important) - { - if (value) - parser->addProperty(propId, value, important); - else - parser->addProperty(propId, cssValuePool().createImplicitInitialValue(), important, true); - } - - bool m_canAdvance; - - bool m_allowCommit; - bool m_allowImage; - bool m_allowImageSlice; - bool m_allowRepeat; - bool m_allowForwardSlashOperator; - - bool m_requireWidth; - bool m_requireOutset; - - RefPtr m_image; - RefPtr m_imageSlice; - RefPtr m_borderSlice; - RefPtr m_outset; - - RefPtr m_repeat; -}; - -bool CSSParser::parseBorderImage(CSSPropertyID propId, RefPtr& result, bool important) -{ - ShorthandScope scope(this, propId); - BorderImageParseContext context; - while (CSSParserValue* val = m_valueList->current()) { - context.setCanAdvance(false); - - if (!context.canAdvance() && context.allowForwardSlashOperator() && isForwardSlashOperator(val)) - context.commitForwardSlashOperator(); - - if (!context.canAdvance() && context.allowImage()) { - if (val->unit == CSSPrimitiveValue::CSS_URI) - context.commitImage(CSSImageValue::create(completeURL(val->string))); - else if (isGeneratedImageValue(val)) { - RefPtr value; - if (parseGeneratedImage(m_valueList.get(), 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(")) { - RefPtr value = parseImageSet(); - if (value) - context.commitImage(value.release()); - else - return false; -#endif - } else if (val->id == CSSValueNone) - context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone)); - } - - if (!context.canAdvance() && context.allowImageSlice()) { - RefPtr imageSlice; - if (parseBorderImageSlice(propId, imageSlice)) - context.commitImageSlice(imageSlice.release()); - } - - if (!context.canAdvance() && context.allowRepeat()) { - RefPtr repeat; - if (parseBorderImageRepeat(repeat)) - context.commitRepeat(repeat.release()); - } - - if (!context.canAdvance() && context.requireWidth()) { - RefPtr borderSlice; - if (parseBorderImageWidth(borderSlice)) - context.commitBorderWidth(borderSlice.release()); - } - - if (!context.canAdvance() && context.requireOutset()) { - RefPtr borderOutset; - if (parseBorderImageOutset(borderOutset)) - context.commitBorderOutset(borderOutset.release()); - } - - if (!context.canAdvance()) - return false; - - m_valueList->next(); - } - - if (context.allowCommit()) { - if (propId == CSSPropertyBorderImage) - context.commitBorderImage(this, important); - else - // Need to fully commit as a single value. - result = context.commitWebKitBorderImage(); - return true; - } - - return false; -} - -static bool isBorderImageRepeatKeyword(int id) -{ - return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound; -} - -bool CSSParser::parseBorderImageRepeat(RefPtr& result) -{ - RefPtr firstValue; - RefPtr secondValue; - CSSParserValue* val = m_valueList->current(); - if (!val) - return false; - if (isBorderImageRepeatKeyword(val->id)) - firstValue = cssValuePool().createIdentifierValue(val->id); - else - return false; - - val = m_valueList->next(); - if (val) { - if (isBorderImageRepeatKeyword(val->id)) - secondValue = cssValuePool().createIdentifierValue(val->id); - else if (!inShorthand()) { - // If we're not parsing a shorthand then we are invalid. - return false; - } else { - // We need to rewind the value list, so that when its advanced we'll - // end up back at this value. - m_valueList->previous(); - secondValue = firstValue; - } - } else - secondValue = firstValue; - - result = createPrimitiveValuePair(firstValue, secondValue); - return true; -} - -class BorderImageSliceParseContext { -public: - BorderImageSliceParseContext(CSSParser* parser) - : m_parser(parser) - , m_allowNumber(true) - , m_allowFill(true) - , m_allowFinalCommit(false) - , m_fill(false) - { } - - bool allowNumber() const { return m_allowNumber; } - bool allowFill() const { return m_allowFill; } - bool allowFinalCommit() const { return m_allowFinalCommit; } - CSSPrimitiveValue* top() const { return m_top.get(); } - - void commitNumber(CSSParserValue* v) - { - RefPtr val = m_parser->createPrimitiveNumericValue(v); - if (!m_top) - m_top = val; - else if (!m_right) - m_right = val; - else if (!m_bottom) - m_bottom = val; - else { - ASSERT(!m_left); - m_left = val; - } - - m_allowNumber = !m_left; - m_allowFinalCommit = true; - } - - void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_top; } - - PassRefPtr commitBorderImageSlice() - { - // We need to clone and repeat values for any omissions. - ASSERT(m_top); - if (!m_right) { - m_right = m_top; - m_bottom = m_top; - m_left = m_top; - } - if (!m_bottom) { - m_bottom = m_top; - m_left = m_right; - } - if (!m_left) - m_left = m_right; - - // Now build a rect value to hold all four of our primitive values. - RefPtr 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); - } - -private: - CSSParser* m_parser; - - bool m_allowNumber; - bool m_allowFill; - bool m_allowFinalCommit; - - RefPtr m_top; - RefPtr m_right; - RefPtr m_bottom; - RefPtr m_left; - - bool m_fill; -}; - -bool CSSParser::parseBorderImageSlice(CSSPropertyID propId, RefPtr& result) -{ - BorderImageSliceParseContext context(this); - CSSParserValue* val; - while ((val = m_valueList->current())) { - // 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) - context.commitFill(); - else if (!inShorthand()) { - // If we're not parsing a shorthand then we are invalid. - return false; - } else { - if (context.allowFinalCommit()) { - // We're going to successfully parse, but we don't want to consume this token. - m_valueList->previous(); - } - break; - } - m_valueList->next(); - } - - if (context.allowFinalCommit()) { - // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default. - // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling... - if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebkitMaskBoxImage || propId == CSSPropertyWebkitBoxReflect) - context.commitFill(); - - // Need to fully commit as a single value. - result = context.commitBorderImageSlice(); - return true; - } - - return false; -} - -class BorderImageQuadParseContext { -public: - BorderImageQuadParseContext(CSSParser* parser) - : m_parser(parser) - , m_allowNumber(true) - , m_allowFinalCommit(false) - { } - - bool allowNumber() const { return m_allowNumber; } - bool allowFinalCommit() const { return m_allowFinalCommit; } - CSSPrimitiveValue* top() const { return m_top.get(); } - - void commitNumber(CSSParserValue* v) - { - RefPtr val; - if (v->id == CSSValueAuto) - val = cssValuePool().createIdentifierValue(v->id); - else - val = m_parser->createPrimitiveNumericValue(v); - - if (!m_top) - m_top = val; - else if (!m_right) - m_right = val; - else if (!m_bottom) - m_bottom = val; - else { - ASSERT(!m_left); - m_left = val; - } - - m_allowNumber = !m_left; - m_allowFinalCommit = true; - } - - void setAllowFinalCommit() { m_allowFinalCommit = true; } - void setTop(PassRefPtr val) { m_top = val; } - - PassRefPtr commitBorderImageQuad() - { - // We need to clone and repeat values for any omissions. - ASSERT(m_top); - if (!m_right) { - m_right = m_top; - m_bottom = m_top; - m_left = m_top; - } - if (!m_bottom) { - m_bottom = m_top; - m_left = m_right; - } - if (!m_left) - m_left = m_right; - - // Now build a quad value to hold all four of our primitive values. - RefPtr 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()); - } - -private: - CSSParser* m_parser; - - bool m_allowNumber; - bool m_allowFinalCommit; - - RefPtr m_top; - RefPtr m_right; - RefPtr m_bottom; - RefPtr m_left; -}; - -bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr& result) -{ - BorderImageQuadParseContext context(this); - CSSParserValue* val; - while ((val = m_valueList->current())) { - if (context.allowNumber() && (validUnit(val, validUnits, CSSStrictMode) || val->id == CSSValueAuto)) { - context.commitNumber(val); - } else if (!inShorthand()) { - // If we're not parsing a shorthand then we are invalid. - return false; - } else { - if (context.allowFinalCommit()) - m_valueList->previous(); // The shorthand loop will advance back to this point. - break; - } - m_valueList->next(); - } - - if (context.allowFinalCommit()) { - // Need to fully commit as a single value. - result = context.commitBorderImageQuad(); - return true; - } - return false; -} - -bool CSSParser::parseBorderImageWidth(RefPtr& result) -{ - return parseBorderImageQuad(FLength | FInteger | FNonNeg | FPercent, result); -} - -bool CSSParser::parseBorderImageOutset(RefPtr& result) -{ - return parseBorderImageQuad(FLength | FInteger | FNonNeg, result); -} - -bool CSSParser::parseBorderRadius(CSSPropertyID propId, bool important) -{ - unsigned num = m_valueList->size(); - if (num > 9) - return false; - - ShorthandScope scope(this, propId); - RefPtr radii[2][4]; - - unsigned indexAfterSlash = 0; - for (unsigned i = 0; i < num; ++i) { - 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) - return false; - - indexAfterSlash = i + 1; - completeBorderRadii(radii[0]); - continue; - } - - if (i - indexAfterSlash >= 4) - return false; - - if (!validUnit(value, FLength | FPercent | FNonNeg)) - return false; - - RefPtr radius = createPrimitiveNumericValue(value); - - if (!indexAfterSlash) { - radii[0][i] = radius; - - // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2; - if (num == 2 && propId == CSSPropertyWebkitBorderRadius) { - indexAfterSlash = 1; - completeBorderRadii(radii[0]); - } - } else - radii[1][i - indexAfterSlash] = radius.release(); - } - - if (!indexAfterSlash) { - completeBorderRadii(radii[0]); - for (unsigned i = 0; i < 4; ++i) - radii[1][i] = radii[0][i]; - } else - completeBorderRadii(radii[1]); - - 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); - addProperty(CSSPropertyBorderBottomLeftRadius, createPrimitiveValuePair(radii[0][3].release(), radii[1][3].release()), important); - return true; -} - -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 != 3) - return false; - - CSSParserValue* lvalue = m_valueList->valueAt(0); - CSSParserValue* op = m_valueList->valueAt(1); - CSSParserValue* rvalue = m_valueList->valueAt(2); - - if (!isForwardSlashOperator(op)) - return false; - - if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg)) - return false; - - if (!lvalue->fValue || !rvalue->fValue) - return false; - - addProperty(CSSPropertyWebkitAspectRatio, CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue)), important); - - return true; -} - -bool CSSParser::parseCounter(CSSPropertyID propId, int defaultValue, bool important) -{ - enum { ID, VAL } state = ID; - - RefPtr list = CSSValueList::createCommaSeparated(); - RefPtr counterName; - - while (true) { - CSSParserValue* val = m_valueList->current(); - switch (state) { - case ID: - if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) { - counterName = createPrimitiveStringValue(val); - state = VAL; - m_valueList->next(); - continue; - } - break; - case VAL: { - int i = defaultValue; - if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) { - i = clampToInteger(val->fValue); - m_valueList->next(); - } - - list->append(createPrimitiveValuePair(counterName.release(), - cssValuePool().createValue(i, CSSPrimitiveValue::CSS_NUMBER))); - state = ID; - continue; - } - } - break; - } - - if (list->length() > 0) { - addProperty(propId, list.release(), important); - return true; - } - - return false; -} - -// This should go away once we drop support for -webkit-gradient -static PassRefPtr parseDeprecatedGradientPoint(CSSParserValue* a, bool horizontal) -{ - RefPtr 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(a->unit)); - return result; -} - -static bool parseDeprecatedGradientColorStop(CSSParser* p, CSSParserValue* a, CSSGradientColorStop& stop) -{ - if (a->unit != CSSParserValue::Function) - return false; - - if (!equalIgnoringCase(a->function->name, "from(") && - !equalIgnoringCase(a->function->name, "to(") && - !equalIgnoringCase(a->function->name, "color-stop(")) - return false; - - CSSParserValueList* args = a->function->args.get(); - if (!args) - return false; - - if (equalIgnoringCase(a->function->name, "from(") - || equalIgnoringCase(a->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); - else - stop.m_position = cssValuePool().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); - else - stop.m_color = p->parseColor(args->current()); - if (!stop.m_color) - return false; - } - - // The "color-stop" function expects 3 arguments. - if (equalIgnoringCase(a->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); - else if (stopArg->unit == CSSPrimitiveValue::CSS_NUMBER) - stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPrimitiveValue::CSS_NUMBER); - else - return false; - - stopArg = args->next(); - if (stopArg->unit != CSSParserValue::Operator || stopArg->iValue != ',') - return false; - - stopArg = args->next(); - CSSValueID id = stopArg->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu) - stop.m_color = cssValuePool().createIdentifierValue(id); - else - stop.m_color = p->parseColor(stopArg); - if (!stop.m_color) - return false; - } - - return true; -} - -bool CSSParser::parseDeprecatedGradient(CSSParserValueList* valueList, RefPtr& gradient) -{ - // Walk the arguments. - 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) - return false; - if (equalIgnoringCase(a, "linear")) - gradientType = CSSDeprecatedLinearGradient; - else if (equalIgnoringCase(a, "radial")) - gradientType = CSSDeprecatedRadialGradient; - else - return false; - - RefPtr result; - switch (gradientType) { - case CSSDeprecatedLinearGradient: - result = CSSLinearGradientValue::create(NonRepeating, gradientType); - break; - case CSSDeprecatedRadialGradient: - result = CSSRadialGradientValue::create(NonRepeating, gradientType); - break; - default: - // The rest of the gradient types shouldn't appear here. - ASSERT_NOT_REACHED(); - } - - // Comma. - a = args->next(); - if (!isComma(a)) - 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) - return false; - RefPtr point = parseDeprecatedGradientPoint(a, true); - if (!point) - return false; - result->setFirstX(point.release()); - - // First Y. It can be top, bottom, number or percent. - a = args->next(); - if (!a) - return false; - point = parseDeprecatedGradientPoint(a, false); - if (!point) - return false; - result->setFirstY(point.release()); - - // Comma after the first point. - a = args->next(); - if (!isComma(a)) - 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) - return false; - toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNumericValue(a)); - - // Comma after the first radius. - a = args->next(); - if (!isComma(a)) - 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) - return false; - point = parseDeprecatedGradientPoint(a, true); - if (!point) - return false; - result->setSecondX(point.release()); - - // Second Y. It can be top, bottom, number or percent. - a = args->next(); - if (!a) - return false; - point = parseDeprecatedGradientPoint(a, false); - if (!point) - return false; - result->setSecondY(point.release()); - - // For radial gradients only, we now expect the second radius. - if (gradientType == CSSDeprecatedRadialGradient) { - // Comma after the second point. - a = args->next(); - if (!isComma(a)) - return false; - - a = args->next(); - if (!a || a->unit != CSSPrimitiveValue::CSS_NUMBER) - return false; - toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveNumericValue(a)); - } - - // We now will accept any number of stops (0 or more). - a = args->next(); - while (a) { - // Look for the comma before the next stop. - if (!isComma(a)) - return false; - - // Now examine the stop itself. - a = args->next(); - if (!a) - return false; - - // The function name needs to be one of "from", "to", or "color-stop." - CSSGradientColorStop stop; - if (!parseDeprecatedGradientColorStop(this, a, stop)) - return false; - result->addStop(stop); - - // Advance - a = args->next(); - } - - gradient = result.release(); - return true; -} - -static PassRefPtr valueFromSideKeyword(CSSParserValue* a, bool& isHorizontal) -{ - if (a->unit != CSSPrimitiveValue::CSS_IDENT) - return 0; - - switch (a->id) { - case CSSValueLeft: - case CSSValueRight: - isHorizontal = true; - break; - case CSSValueTop: - case CSSValueBottom: - isHorizontal = false; - break; - default: - return 0; - } - return cssValuePool().createIdentifierValue(a->id); -} - -static PassRefPtr parseGradientColorOrKeyword(CSSParser* p, CSSParserValue* value) -{ - CSSValueID id = value->id; - if (id == CSSValueWebkitText || (id >= CSSValueAqua && id <= CSSValueWindowtext) || id == CSSValueMenu || id == CSSValueCurrentcolor) - return cssValuePool().createIdentifierValue(id); - - return p->parseColor(value); -} - -bool CSSParser::parseDeprecatedLinearGradient(CSSParserValueList* valueList, RefPtr& gradient, CSSGradientRepeat repeating) -{ - RefPtr result = CSSLinearGradientValue::create(repeating, CSSPrefixedLinearGradient); - - // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || !args->size()) - return false; - - CSSParserValue* a = args->current(); - if (!a) - return false; - - bool expectComma = false; - // Look for angle. - if (validUnit(a, FAngle, CSSStrictMode)) { - result->setAngle(createPrimitiveNumericValue(a)); - - args->next(); - expectComma = true; - } else { - // Look one or two optional keywords that indicate a side or corner. - RefPtr startX, startY; - - RefPtr location; - bool isHorizontal = false; - if ((location = valueFromSideKeyword(a, isHorizontal))) { - if (isHorizontal) - startX = location; - else - startY = location; - - if ((a = args->next())) { - if ((location = valueFromSideKeyword(a, isHorizontal))) { - if (isHorizontal) { - if (startX) - return false; - startX = location; - } else { - if (startY) - return false; - startY = location; - } - - args->next(); - } - } - - expectComma = true; - } - - if (!startX && !startY) - startY = cssValuePool().createIdentifierValue(CSSValueTop); - - result->setFirstX(startX.release()); - result->setFirstY(startY.release()); - } - - if (!parseGradientColorStops(args, result.get(), expectComma)) - return false; - - if (!result->stopCount()) - return false; - - gradient = result.release(); - return true; -} - -bool CSSParser::parseDeprecatedRadialGradient(CSSParserValueList* valueList, RefPtr& gradient, CSSGradientRepeat repeating) -{ - RefPtr result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient); - - // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || !args->size()) - return false; - - CSSParserValue* a = args->current(); - if (!a) - return false; - - bool expectComma = false; - - // Optional background-position - RefPtr centerX; - RefPtr centerY; - // parse2ValuesFillPosition advances the args next pointer. - parse2ValuesFillPosition(args, centerX, centerY); - a = args->current(); - if (!a) - return false; - - if (centerX || centerY) { - // Comma - if (!isComma(a)) - return false; - - a = args->next(); - if (!a) - return false; - } - - ASSERT(!centerX || centerX->isPrimitiveValue()); - ASSERT(!centerY || centerY->isPrimitiveValue()); - - result->setFirstX(toCSSPrimitiveValue(centerX.get())); - result->setSecondX(toCSSPrimitiveValue(centerX.get())); - // CSS3 radial gradients always share the same start and end point. - result->setFirstY(toCSSPrimitiveValue(centerY.get())); - result->setSecondY(toCSSPrimitiveValue(centerY.get())); - - RefPtr shapeValue; - RefPtr sizeValue; - - // Optional shape and/or size in any order. - for (int i = 0; i < 2; ++i) { - if (a->unit != CSSPrimitiveValue::CSS_IDENT) - break; - - bool foundValue = false; - switch (a->id) { - case CSSValueCircle: - case CSSValueEllipse: - shapeValue = cssValuePool().createIdentifierValue(a->id); - foundValue = true; - break; - case CSSValueClosestSide: - case CSSValueClosestCorner: - case CSSValueFarthestSide: - case CSSValueFarthestCorner: - case CSSValueContain: - case CSSValueCover: - sizeValue = cssValuePool().createIdentifierValue(a->id); - foundValue = true; - break; - default: - break; - } - - if (foundValue) { - a = args->next(); - if (!a) - return false; - - expectComma = true; - } - } - - result->setShape(shapeValue); - result->setSizingBehavior(sizeValue); - - // Or, two lengths or percentages - RefPtr horizontalSize; - RefPtr verticalSize; - - if (!shapeValue && !sizeValue) { - if (validUnit(a, FLength | FPercent)) { - horizontalSize = createPrimitiveNumericValue(a); - a = args->next(); - if (!a) - return false; - - expectComma = true; - } - - if (validUnit(a, FLength | FPercent)) { - verticalSize = createPrimitiveNumericValue(a); - - a = args->next(); - if (!a) - return false; - expectComma = true; - } - } - - // Must have neither or both. - if (!horizontalSize != !verticalSize) - return false; - - result->setEndHorizontalSize(horizontalSize); - result->setEndVerticalSize(verticalSize); - - if (!parseGradientColorStops(args, result.get(), expectComma)) - return false; - - gradient = result.release(); - return true; -} - -bool CSSParser::parseLinearGradient(CSSParserValueList* valueList, RefPtr& gradient, CSSGradientRepeat repeating) -{ - RefPtr result = CSSLinearGradientValue::create(repeating, CSSLinearGradient); - - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || !args->size()) - return false; - - CSSParserValue* a = args->current(); - if (!a) - return false; - - bool expectComma = false; - // Look for angle. - if (validUnit(a, FAngle, CSSStrictMode)) { - result->setAngle(createPrimitiveNumericValue(a)); - - args->next(); - expectComma = true; - } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) { - // to [ [left | right] || [top | bottom] ] - a = args->next(); - if (!a) - return false; - - RefPtr endX, endY; - RefPtr location; - bool isHorizontal = false; - - location = valueFromSideKeyword(a, isHorizontal); - if (!location) - return false; - - if (isHorizontal) - endX = location; - else - endY = location; - - a = args->next(); - if (!a) - return false; - - location = valueFromSideKeyword(a, isHorizontal); - if (location) { - if (isHorizontal) { - if (endX) - return false; - endX = location; - } else { - if (endY) - return false; - endY = location; - } - - args->next(); - } - - expectComma = true; - result->setFirstX(endX.release()); - result->setFirstY(endY.release()); - } - - if (!parseGradientColorStops(args, result.get(), expectComma)) - return false; - - if (!result->stopCount()) - return false; - - gradient = result.release(); - return true; -} - -bool CSSParser::parseRadialGradient(CSSParserValueList* valueList, RefPtr& gradient, CSSGradientRepeat repeating) -{ - RefPtr result = CSSRadialGradientValue::create(repeating, CSSRadialGradient); - - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || !args->size()) - return false; - - CSSParserValue* a = args->current(); - if (!a) - return false; - - bool expectComma = false; - - RefPtr shapeValue; - RefPtr sizeValue; - RefPtr horizontalSize; - RefPtr verticalSize; - - // First part of grammar, the size/shape clause: - // [ circle || ] | - // [ ellipse || [ | ]{2} ] | - // [ [ circle | ellipse] || ] - for (int i = 0; i < 3; ++i) { - if (a->unit == CSSPrimitiveValue::CSS_IDENT) { - bool badIdent = false; - switch (a->id) { - case CSSValueCircle: - case CSSValueEllipse: - if (shapeValue) - return false; - shapeValue = cssValuePool().createIdentifierValue(a->id); - break; - case CSSValueClosestSide: - case CSSValueClosestCorner: - case CSSValueFarthestSide: - case CSSValueFarthestCorner: - if (sizeValue || horizontalSize) - return false; - sizeValue = cssValuePool().createIdentifierValue(a->id); - break; - default: - badIdent = true; - } - - if (badIdent) - break; - - a = args->next(); - if (!a) - return false; - } else if (validUnit(a, FLength | FPercent)) { - - if (sizeValue || horizontalSize) - return false; - horizontalSize = createPrimitiveNumericValue(a); - - a = args->next(); - if (!a) - return false; - - if (validUnit(a, FLength | FPercent)) { - verticalSize = createPrimitiveNumericValue(a); - ++i; - a = args->next(); - if (!a) - return false; - } - } else - break; - } - - // You can specify size as a keyword or a length/percentage, not both. - if (sizeValue && horizontalSize) - return false; - // Circles must have 0 or 1 lengths. - if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize) - return false; - // Ellipses must have 0 or 2 length/percentages. - if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize) - return false; - // If there's only one size, it must be a length. - if (!verticalSize && horizontalSize && horizontalSize->isPercentage()) - return false; - - result->setShape(shapeValue); - result->setSizingBehavior(sizeValue); - result->setEndHorizontalSize(horizontalSize); - result->setEndVerticalSize(verticalSize); - - // Second part of grammar, the center-position clause: - // at - RefPtr centerX; - RefPtr centerY; - if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "at")) { - a = args->next(); - if (!a) - return false; - - parseFillPosition(args, centerX, centerY); - if (!(centerX && centerY)) - return false; - - a = args->current(); - if (!a) - return false; - - ASSERT(centerX->isPrimitiveValue()); - ASSERT(centerY->isPrimitiveValue()); - result->setFirstX(toCSSPrimitiveValue(centerX.get())); - result->setFirstY(toCSSPrimitiveValue(centerY.get())); - // Right now, CSS radial gradients have the same start and end centers. - result->setSecondX(toCSSPrimitiveValue(centerX.get())); - result->setSecondY(toCSSPrimitiveValue(centerY.get())); - } - - if (shapeValue || sizeValue || horizontalSize || centerX || centerY) - expectComma = true; - - if (!parseGradientColorStops(args, result.get(), expectComma)) - return false; - - gradient = result.release(); - return true; -} - -bool CSSParser::parseGradientColorStops(CSSParserValueList* valueList, CSSGradientValue* gradient, bool expectComma) -{ - CSSParserValue* a = valueList->current(); - - // Now look for color stops. - while (a) { - // Look for the comma before the next stop. - if (expectComma) { - if (!isComma(a)) - return false; - - a = valueList->next(); - if (!a) - return false; - } - - // = [ | ]? - CSSGradientColorStop stop; - stop.m_color = parseGradientColorOrKeyword(this, a); - if (!stop.m_color) - return false; - - a = valueList->next(); - if (a) { - if (validUnit(a, FLength | FPercent)) { - stop.m_position = createPrimitiveNumericValue(a); - a = valueList->next(); - } - } - - gradient->addStop(stop); - expectComma = true; - } - - // Must have 2 or more stops to be valid. - return gradient->stopCount() >= 2; -} - -bool CSSParser::isGeneratedImageValue(CSSParserValue* val) const -{ - if (val->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(") - || equalIgnoringCase(val->function->name, "-webkit-filter("); -} - -bool CSSParser::parseGeneratedImage(CSSParserValueList* valueList, RefPtr& value) -{ - CSSParserValue* val = valueList->current(); - - if (val->unit != CSSParserValue::Function) - return false; - - if (equalIgnoringCase(val->function->name, "-webkit-gradient(")) - return parseDeprecatedGradient(valueList, value); - - if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient(")) - return parseDeprecatedLinearGradient(valueList, value, NonRepeating); - - if (equalIgnoringCase(val->function->name, "linear-gradient(")) - return parseLinearGradient(valueList, value, NonRepeating); - - if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient(")) - return parseDeprecatedLinearGradient(valueList, value, Repeating); - - if (equalIgnoringCase(val->function->name, "repeating-linear-gradient(")) - return parseLinearGradient(valueList, value, Repeating); - - if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient(")) - return parseDeprecatedRadialGradient(valueList, value, NonRepeating); - - if (equalIgnoringCase(val->function->name, "radial-gradient(")) - return parseRadialGradient(valueList, value, NonRepeating); - - if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient(")) - return parseDeprecatedRadialGradient(valueList, value, Repeating); - - if (equalIgnoringCase(val->function->name, "repeating-radial-gradient(")) - return parseRadialGradient(valueList, value, Repeating); - - if (equalIgnoringCase(val->function->name, "-webkit-canvas(")) - return parseCanvas(valueList, value); - - if (equalIgnoringCase(val->function->name, "-webkit-cross-fade(")) - return parseCrossfade(valueList, value); - -#if ENABLE(CSS_FILTERS) - if (equalIgnoringCase(val->function->name, "-webkit-filter(")) - return parseFilterImage(valueList, value); -#endif - - return false; -} - -#if ENABLE(CSS_FILTERS) -bool CSSParser::parseFilterImage(CSSParserValueList* valueList, RefPtr& filter) -{ - RefPtr result; - - // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args) - return false; - CSSParserValue* value = args->current(); - RefPtr imageValue; - RefPtr 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; -} -#endif - -bool CSSParser::parseCrossfade(CSSParserValueList* valueList, RefPtr& crossfade) -{ - RefPtr result; - - // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || args->size() != 5) - return false; - CSSParserValue* a = args->current(); - RefPtr fromImageValue; - RefPtr toImageValue; - - // The first argument is the "from" image. It is a fill image. - if (!a || !parseFillImage(args, fromImageValue)) - return false; - a = args->next(); - - // Skip a comma - if (!isComma(a)) - return false; - a = args->next(); - - // The second argument is the "to" image. It is a fill image. - if (!a || !parseFillImage(args, toImageValue)) - return false; - a = args->next(); - - // Skip a comma - if (!isComma(a)) - return false; - a = args->next(); - - // The third argument is the crossfade value. It is a percentage or a fractional number. - RefPtr percentage; - if (!a) - return false; - - if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE) - percentage = cssValuePool().createValue(clampTo(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER); - else if (a->unit == CSSPrimitiveValue::CSS_NUMBER) - percentage = cssValuePool().createValue(clampTo(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER); - else - return false; - - result = CSSCrossfadeValue::create(fromImageValue, toImageValue); - result->setPercentage(percentage); - - crossfade = result; - - return true; -} - -bool CSSParser::parseCanvas(CSSParserValueList* valueList, RefPtr& canvas) -{ - // Walk the arguments. - CSSParserValueList* args = valueList->current()->function->args.get(); - if (!args || args->size() != 1) - return false; - - // The first argument is the canvas name. It is an identifier. - CSSParserValue* value = args->current(); - if (!value || value->unit != CSSPrimitiveValue::CSS_IDENT) - return false; - - canvas = CSSCanvasValue::create(value->string); - return true; -} - -#if ENABLE(CSS_IMAGE_RESOLUTION) -PassRefPtr CSSParser::parseImageResolution() -{ - RefPtr list = CSSValueList::createSpaceSeparated(); - bool haveResolution = false; - bool haveFromImage = false; - bool haveSnap = false; - - CSSParserValue* value = m_valueList->current(); - while (value) { - if (!haveFromImage && value->id == CSSValueFromImage) { - list->append(cssValuePool().createIdentifierValue(value->id)); - haveFromImage = true; - } else if (!haveSnap && value->id == CSSValueSnap) { - list->append(cssValuePool().createIdentifierValue(value->id)); - haveSnap = true; - } else if (!haveResolution && validUnit(value, FResolution | FNonNeg) && value->fValue > 0) { - list->append(createPrimitiveNumericValue(value)); - haveResolution = true; - } else - return 0; - value = m_valueList->next(); - } - if (!list->length()) - return 0; - if (!haveFromImage && !haveResolution) - return 0; - return list.release(); -} -#endif - -#if ENABLE(CSS_IMAGE_SET) -PassRefPtr CSSParser::parseImageSet() -{ - CSSParserValue* value = m_valueList->current(); - ASSERT(value->unit == CSSParserValue::Function); - - CSSParserValueList* functionArgs = value->function->args.get(); - if (!functionArgs || !functionArgs->size() || !functionArgs->current()) - return 0; - - RefPtr imageSet = CSSImageSetValue::create(); - CSSParserValue* arg = functionArgs->current(); - while (arg) { - if (arg->unit != CSSPrimitiveValue::CSS_URI) - return 0; - - imageSet->append(CSSImageValue::create(completeURL(arg->string))); - arg = functionArgs->next(); - if (!arg || arg->unit != CSSPrimitiveValue::CSS_DIMENSION) - return 0; - - double imageScaleFactor = 0; - const String& string = arg->string; - unsigned length = string.length(); - if (!length) - return 0; - if (string.is8Bit()) { - const LChar* start = string.characters8(); - parseDouble(start, start + length, 'x', imageScaleFactor); - } else { - const UChar* start = string.characters16(); - parseDouble(start, start + length, 'x', imageScaleFactor); - } - if (imageScaleFactor <= 0) - return 0; - imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER)); - - // If there are no more arguments, we're done. - arg = functionArgs->next(); - if (!arg) - break; - - // If there are more arguments, they should be after a comma. - if (!isComma(arg)) - return 0; - - // Skip the comma and move on to the next argument. - arg = functionArgs->next(); - } - - return imageSet.release(); -} -#endif - -class TransformOperationInfo { -public: - TransformOperationInfo(const CSSParserString& name) - : m_type(WebKitCSSTransformValue::UnknownTransformOperation) - , m_argCount(1) - , m_allowSingleArgument(false) - , m_unit(CSSParser::FUnknown) - { - const UChar* characters; - unsigned nameLength = name.length(); - - const unsigned longestNameLength = 12; - UChar characterBuffer[longestNameLength]; - if (name.is8Bit()) { - unsigned length = std::min(longestNameLength, nameLength); - const LChar* characters8 = name.characters8(); - for (unsigned i = 0; i < length; ++i) - characterBuffer[i] = characters8[i]; - characters = characterBuffer; - } else - characters = name.characters16(); - - switch (nameLength) { - case 5: - // Valid name: skew(. - if (((characters[0] == 's') || (characters[0] == 'S')) - & ((characters[1] == 'k') || (characters[1] == 'K')) - & ((characters[2] == 'e') || (characters[2] == 'E')) - & ((characters[3] == 'w') || (characters[3] == 'W')) - & (characters[4] == '(')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::SkewTransformOperation; - m_allowSingleArgument = true; - m_argCount = 3; - } - break; - case 6: - // Valid names: skewx(, skewy(, scale(. - if ((characters[1] == 'c') || (characters[1] == 'C')) { - if (((characters[0] == 's') || (characters[0] == 'S')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'l') || (characters[3] == 'L')) - & ((characters[4] == 'e') || (characters[4] == 'E')) - & (characters[5] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::ScaleTransformOperation; - m_allowSingleArgument = true; - m_argCount = 3; - } - } else if (((characters[0] == 's') || (characters[0] == 'S')) - & ((characters[1] == 'k') || (characters[1] == 'K')) - & ((characters[2] == 'e') || (characters[2] == 'E')) - & ((characters[3] == 'w') || (characters[3] == 'W')) - & (characters[5] == '(')) { - if ((characters[4] == 'x') || (characters[4] == 'X')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::SkewXTransformOperation; - } else if ((characters[4] == 'y') || (characters[4] == 'Y')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::SkewYTransformOperation; - } - } - break; - case 7: - // Valid names: matrix(, rotate(, scalex(, scaley(, scalez(. - if ((characters[0] == 'm') || (characters[0] == 'M')) { - if (((characters[1] == 'a') || (characters[1] == 'A')) - & ((characters[2] == 't') || (characters[2] == 'T')) - & ((characters[3] == 'r') || (characters[3] == 'R')) - & ((characters[4] == 'i') || (characters[4] == 'I')) - & ((characters[5] == 'x') || (characters[5] == 'X')) - & (characters[6] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::MatrixTransformOperation; - m_argCount = 11; - } - } else if ((characters[0] == 'r') || (characters[0] == 'R')) { - if (((characters[1] == 'o') || (characters[1] == 'O')) - & ((characters[2] == 't') || (characters[2] == 'T')) - & ((characters[3] == 'a') || (characters[3] == 'A')) - & ((characters[4] == 't') || (characters[4] == 'T')) - & ((characters[5] == 'e') || (characters[5] == 'E')) - & (characters[6] == '(')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::RotateTransformOperation; - } - } else if (((characters[0] == 's') || (characters[0] == 'S')) - & ((characters[1] == 'c') || (characters[1] == 'C')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'l') || (characters[3] == 'L')) - & ((characters[4] == 'e') || (characters[4] == 'E')) - & (characters[6] == '(')) { - if ((characters[5] == 'x') || (characters[5] == 'X')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::ScaleXTransformOperation; - } else if ((characters[5] == 'y') || (characters[5] == 'Y')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::ScaleYTransformOperation; - } else if ((characters[5] == 'z') || (characters[5] == 'Z')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::ScaleZTransformOperation; - } - } - break; - case 8: - // Valid names: rotatex(, rotatey(, rotatez(, scale3d(. - if ((characters[0] == 's') || (characters[0] == 'S')) { - if (((characters[1] == 'c') || (characters[1] == 'C')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'l') || (characters[3] == 'L')) - & ((characters[4] == 'e') || (characters[4] == 'E')) - & (characters[5] == '3') - & ((characters[6] == 'd') || (characters[6] == 'D')) - & (characters[7] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::Scale3DTransformOperation; - m_argCount = 5; - } - } else if (((characters[0] == 'r') || (characters[0] == 'R')) - & ((characters[1] == 'o') || (characters[1] == 'O')) - & ((characters[2] == 't') || (characters[2] == 'T')) - & ((characters[3] == 'a') || (characters[3] == 'A')) - & ((characters[4] == 't') || (characters[4] == 'T')) - & ((characters[5] == 'e') || (characters[5] == 'E')) - & (characters[7] == '(')) { - if ((characters[6] == 'x') || (characters[6] == 'X')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::RotateXTransformOperation; - } else if ((characters[6] == 'y') || (characters[6] == 'Y')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::RotateYTransformOperation; - } else if ((characters[6] == 'z') || (characters[6] == 'Z')) { - m_unit = CSSParser::FAngle; - m_type = WebKitCSSTransformValue::RotateZTransformOperation; - } - } - break; - case 9: - // Valid names: matrix3d(, rotate3d(. - if ((characters[0] == 'm') || (characters[0] == 'M')) { - if (((characters[1] == 'a') || (characters[1] == 'A')) - & ((characters[2] == 't') || (characters[2] == 'T')) - & ((characters[3] == 'r') || (characters[3] == 'R')) - & ((characters[4] == 'i') || (characters[4] == 'I')) - & ((characters[5] == 'x') || (characters[5] == 'X')) - & (characters[6] == '3') - & ((characters[7] == 'd') || (characters[7] == 'D')) - & (characters[8] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::Matrix3DTransformOperation; - m_argCount = 31; - } - } else if (((characters[0] == 'r') || (characters[0] == 'R')) - & ((characters[1] == 'o') || (characters[1] == 'O')) - & ((characters[2] == 't') || (characters[2] == 'T')) - & ((characters[3] == 'a') || (characters[3] == 'A')) - & ((characters[4] == 't') || (characters[4] == 'T')) - & ((characters[5] == 'e') || (characters[5] == 'E')) - & (characters[6] == '3') - & ((characters[7] == 'd') || (characters[7] == 'D')) - & (characters[8] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::Rotate3DTransformOperation; - m_argCount = 7; - } - break; - case 10: - // Valid name: translate(. - if (((characters[0] == 't') || (characters[0] == 'T')) - & ((characters[1] == 'r') || (characters[1] == 'R')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'n') || (characters[3] == 'N')) - & ((characters[4] == 's') || (characters[4] == 'S')) - & ((characters[5] == 'l') || (characters[5] == 'L')) - & ((characters[6] == 'a') || (characters[6] == 'A')) - & ((characters[7] == 't') || (characters[7] == 'T')) - & ((characters[8] == 'e') || (characters[8] == 'E')) - & (characters[9] == '(')) { - m_unit = CSSParser::FLength | CSSParser::FPercent; - m_type = WebKitCSSTransformValue::TranslateTransformOperation; - m_allowSingleArgument = true; - m_argCount = 3; - } - break; - case 11: - // Valid names: translatex(, translatey(, translatez(. - if (((characters[0] == 't') || (characters[0] == 'T')) - & ((characters[1] == 'r') || (characters[1] == 'R')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'n') || (characters[3] == 'N')) - & ((characters[4] == 's') || (characters[4] == 'S')) - & ((characters[5] == 'l') || (characters[5] == 'L')) - & ((characters[6] == 'a') || (characters[6] == 'A')) - & ((characters[7] == 't') || (characters[7] == 'T')) - & ((characters[8] == 'e') || (characters[8] == 'E')) - & (characters[10] == '(')) { - if ((characters[9] == 'x') || (characters[9] == 'X')) { - m_unit = CSSParser::FLength | CSSParser::FPercent; - m_type = WebKitCSSTransformValue::TranslateXTransformOperation; - } else if ((characters[9] == 'y') || (characters[9] == 'Y')) { - m_unit = CSSParser::FLength | CSSParser::FPercent; - m_type = WebKitCSSTransformValue::TranslateYTransformOperation; - } else if ((characters[9] == 'z') || (characters[9] == 'Z')) { - m_unit = CSSParser::FLength | CSSParser::FPercent; - m_type = WebKitCSSTransformValue::TranslateZTransformOperation; - } - } - break; - case 12: - // Valid names: perspective(, translate3d(. - if ((characters[0] == 'p') || (characters[0] == 'P')) { - if (((characters[1] == 'e') || (characters[1] == 'E')) - & ((characters[2] == 'r') || (characters[2] == 'R')) - & ((characters[3] == 's') || (characters[3] == 'S')) - & ((characters[4] == 'p') || (characters[4] == 'P')) - & ((characters[5] == 'e') || (characters[5] == 'E')) - & ((characters[6] == 'c') || (characters[6] == 'C')) - & ((characters[7] == 't') || (characters[7] == 'T')) - & ((characters[8] == 'i') || (characters[8] == 'I')) - & ((characters[9] == 'v') || (characters[9] == 'V')) - & ((characters[10] == 'e') || (characters[10] == 'E')) - & (characters[11] == '(')) { - m_unit = CSSParser::FNumber; - m_type = WebKitCSSTransformValue::PerspectiveTransformOperation; - } - } else if (((characters[0] == 't') || (characters[0] == 'T')) - & ((characters[1] == 'r') || (characters[1] == 'R')) - & ((characters[2] == 'a') || (characters[2] == 'A')) - & ((characters[3] == 'n') || (characters[3] == 'N')) - & ((characters[4] == 's') || (characters[4] == 'S')) - & ((characters[5] == 'l') || (characters[5] == 'L')) - & ((characters[6] == 'a') || (characters[6] == 'A')) - & ((characters[7] == 't') || (characters[7] == 'T')) - & ((characters[8] == 'e') || (characters[8] == 'E')) - & (characters[9] == '3') - & ((characters[10] == 'd') || (characters[10] == 'D')) - & (characters[11] == '(')) { - m_unit = CSSParser::FLength | CSSParser::FPercent; - m_type = WebKitCSSTransformValue::Translate3DTransformOperation; - m_argCount = 5; - } - break; - } // end switch () - } - - WebKitCSSTransformValue::TransformOperationType type() const { return m_type; } - unsigned argCount() const { return m_argCount; } - CSSParser::Units unit() const { return m_unit; } - - bool unknown() const { return m_type == WebKitCSSTransformValue::UnknownTransformOperation; } - bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); } - -private: - WebKitCSSTransformValue::TransformOperationType m_type; - unsigned m_argCount; - bool m_allowSingleArgument; - CSSParser::Units m_unit; -}; - -PassRefPtr CSSParser::parseTransform() -{ - if (!m_valueList) - return 0; - - RefPtr list = CSSValueList::createSpaceSeparated(); - for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - RefPtr parsedTransformValue = parseTransformValue(value); - if (!parsedTransformValue) - return 0; - - list->append(parsedTransformValue.release()); - } - - return list.release(); -} - -PassRefPtr CSSParser::parseTransformValue(CSSParserValue *value) -{ - if (value->unit != CSSParserValue::Function || !value->function) - return 0; - - // Every primitive requires at least one argument. - CSSParserValueList* args = value->function->args.get(); - if (!args) - return 0; - - // See if the specified primitive is one we understand. - TransformOperationInfo info(value->function->name); - if (info.unknown()) - return 0; - - if (!info.hasCorrectArgCount(args->size())) - return 0; - - // 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. - - // Create the new WebKitCSSTransformValue for this operation and add it to our list. - RefPtr transformValue = WebKitCSSTransformValue::create(info.type()); - - // Snag our values. - CSSParserValue* a = args->current(); - unsigned argNumber = 0; - while (a) { - 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; - } else if (info.type() == WebKitCSSTransformValue::Translate3DTransformOperation && argNumber == 2) { - // 3rd param of translate3d() cannot be a percentage - if (!validUnit(a, FLength, CSSStrictMode)) - return 0; - } else if (info.type() == WebKitCSSTransformValue::TranslateZTransformOperation && !argNumber) { - // 1st param of translateZ() cannot be a percentage - if (!validUnit(a, FLength, CSSStrictMode)) - return 0; - } 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; - - // Add the value to the current transform operation. - transformValue->append(createPrimitiveNumericValue(a)); - - a = args->next(); - if (!a) - break; - if (a->unit != CSSParserValue::Operator || a->iValue != ',') - return 0; - a = args->next(); - - argNumber++; - } - - return transformValue.release(); -} - -bool CSSParser::isBlendMode(CSSValueID valueID) -{ - return (valueID >= CSSValueMultiply && valueID <= CSSValueLuminosity) - || valueID == CSSValueNormal - || valueID == CSSValueOverlay; -} - -bool CSSParser::isCompositeOperator(CSSValueID valueID) -{ - // FIXME: Add CSSValueDestination and CSSValueLighter when the Compositing spec updates. - return valueID >= CSSValueClear && valueID <= CSSValueXor; -} - -#if ENABLE(CSS_FILTERS) - -static void filterInfoForName(const CSSParserString& name, WebKitCSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount) -{ - if (equalIgnoringCase(name, "grayscale(")) - filterType = WebKitCSSFilterValue::GrayscaleFilterOperation; - else if (equalIgnoringCase(name, "sepia(")) - filterType = WebKitCSSFilterValue::SepiaFilterOperation; - else if (equalIgnoringCase(name, "saturate(")) - filterType = WebKitCSSFilterValue::SaturateFilterOperation; - else if (equalIgnoringCase(name, "hue-rotate(")) - filterType = WebKitCSSFilterValue::HueRotateFilterOperation; - else if (equalIgnoringCase(name, "invert(")) - filterType = WebKitCSSFilterValue::InvertFilterOperation; - else if (equalIgnoringCase(name, "opacity(")) - filterType = WebKitCSSFilterValue::OpacityFilterOperation; - else if (equalIgnoringCase(name, "brightness(")) - filterType = WebKitCSSFilterValue::BrightnessFilterOperation; - else if (equalIgnoringCase(name, "contrast(")) - filterType = WebKitCSSFilterValue::ContrastFilterOperation; - else if (equalIgnoringCase(name, "blur(")) - filterType = WebKitCSSFilterValue::BlurFilterOperation; - else if (equalIgnoringCase(name, "drop-shadow(")) { - filterType = WebKitCSSFilterValue::DropShadowFilterOperation; - maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed. - } -} - -PassRefPtr CSSParser::parseBuiltinFilterArguments(CSSParserValueList* args, WebKitCSSFilterValue::FilterOperationType filterType) -{ - RefPtr filterValue = WebKitCSSFilterValue::create(filterType); - ASSERT(args); - - switch (filterType) { - case WebKitCSSFilterValue::GrayscaleFilterOperation: - case WebKitCSSFilterValue::SepiaFilterOperation: - case WebKitCSSFilterValue::SaturateFilterOperation: - case WebKitCSSFilterValue::InvertFilterOperation: - 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()) { - 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; - } - - filterValue->append(cssValuePool().createValue(amount, static_cast(value->unit))); - } - break; - } - case WebKitCSSFilterValue::BrightnessFilterOperation: { - // One optional argument, if missing use 100%. - if (args->size() > 1) - return 0; - - if (args->size()) { - CSSParserValue* value = args->current(); - if (!validUnit(value, FNumber | FPercent, CSSStrictMode)) - return 0; - - filterValue->append(cssValuePool().createValue(value->fValue, static_cast(value->unit))); - } - break; - } - case WebKitCSSFilterValue::HueRotateFilterOperation: { - // hue-rotate() takes one optional angle. - if (args->size() > 1) - return 0; - - if (args->size()) { - CSSParserValue* argument = args->current(); - if (!validUnit(argument, FAngle, CSSStrictMode)) - return 0; - - filterValue->append(createPrimitiveNumericValue(argument)); - } - break; - } - case WebKitCSSFilterValue::BlurFilterOperation: { - // Blur takes a single length. Zero parameters are allowed. - if (args->size() > 1) - return 0; - - if (args->size()) { - CSSParserValue* argument = args->current(); - if (!validUnit(argument, FLength | FNonNeg, CSSStrictMode)) - return 0; - - filterValue->append(createPrimitiveNumericValue(argument)); - } - break; - } - case WebKitCSSFilterValue::DropShadowFilterOperation: { - // drop-shadow() takes a single shadow. - RefPtr shadowValueList = parseShadow(args, CSSPropertyWebkitFilter); - if (!shadowValueList || shadowValueList->length() != 1) - return 0; - - filterValue->append((shadowValueList.release())->itemWithoutBoundsCheck(0)); - break; - } - default: - ASSERT_NOT_REACHED(); - } - return filterValue.release(); -} - -bool CSSParser::parseFilter(CSSParserValueList* valueList, RefPtr& result) -{ - if (!valueList) - return false; - - // The filter is a list of functional primitives that specify individual operations. - RefPtr list = CSSValueList::createSpaceSeparated(); - for (auto value = valueList->current(); value; value = valueList->next()) { - if (value->unit != CSSPrimitiveValue::CSS_URI && (value->unit != CSSParserValue::Function || !value->function)) - 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 referenceFilterValue = WebKitCSSFilterValue::create(WebKitCSSFilterValue::ReferenceFilterOperation); - referenceFilterValue->append(CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI)); - list->append(referenceFilterValue.release()); -#endif - } else { - const CSSParserString name = value->function->name; - unsigned maximumArgumentCount = 1; - - filterInfoForName(name, filterType, maximumArgumentCount); - - if (filterType == WebKitCSSFilterValue::UnknownFilterOperation) - return false; - - CSSParserValueList* args = value->function->args.get(); - if (!args) - return false; - - RefPtr filterValue = parseBuiltinFilterArguments(args, filterType); - if (!filterValue) - return false; - - list->append(filterValue.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")); -} -#endif - -bool CSSParser::cssRegionsEnabled() const -{ - return m_context.isCSSRegionsEnabled; -} - -bool CSSParser::cssCompositingEnabled() const -{ - return m_context.isCSSCompositingEnabled; -} - -bool CSSParser::cssGridLayoutEnabled() const -{ - return m_context.isCSSGridLayoutEnabled; -} - -#if ENABLE(CSS_REGIONS) - -// none | -bool CSSParser::parseFlowThread(CSSPropertyID propId, bool important) -{ - ASSERT(propId == CSSPropertyWebkitFlowInto); - ASSERT(cssRegionsEnabled()); - - if (m_valueList->size() != 1) - return false; - - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - if (value->unit != CSSPrimitiveValue::CSS_IDENT) - return false; - - if (value->id == CSSValueNone) { - addProperty(propId, cssValuePool().createIdentifierValue(value->id), important); - return true; - } - - String inputProperty = String(value->string); - if (!inputProperty.isEmpty()) { - if (!validFlowName(inputProperty)) - return false; - addProperty(propId, cssValuePool().createValue(inputProperty, CSSPrimitiveValue::CSS_STRING), important); - } else - addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); - - return true; -} - -// -webkit-flow-from: none | -bool CSSParser::parseRegionThread(CSSPropertyID propId, bool important) -{ - ASSERT(propId == CSSPropertyWebkitFlowFrom); - ASSERT(cssRegionsEnabled()); - - if (m_valueList->size() != 1) - return false; - - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - if (value->unit != CSSPrimitiveValue::CSS_IDENT) - return false; - - if (value->id == CSSValueNone) - addProperty(propId, cssValuePool().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); - } else - addProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); - } - - return true; -} -#endif - -bool CSSParser::parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr& value, RefPtr& value2, RefPtr& value3) -{ - propId1 = propId; - propId2 = propId; - propId3 = propId; - if (propId == CSSPropertyWebkitTransformOrigin) { - propId1 = CSSPropertyWebkitTransformOriginX; - propId2 = CSSPropertyWebkitTransformOriginY; - propId3 = CSSPropertyWebkitTransformOriginZ; - } - - 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(); - return false; - } - - return value; -} - -bool CSSParser::parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr& value, RefPtr& value2) -{ - propId1 = propId; - propId2 = propId; - if (propId == CSSPropertyWebkitPerspectiveOrigin) { - propId1 = CSSPropertyWebkitPerspectiveOriginX; - propId2 = CSSPropertyWebkitPerspectiveOriginY; - } - - 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(); - return false; - } - - return value; -} - -void CSSParser::addTextDecorationProperty(CSSPropertyID propId, PassRefPtr value, bool important) -{ - // The text-decoration-line property takes priority over text-decoration, unless the latter has important priority set. - if (propId == CSSPropertyTextDecoration && !important && !inShorthand()) { - for (unsigned i = 0; i < m_parsedProperties.size(); ++i) { - if (m_parsedProperties[i].id() == CSSPropertyWebkitTextDecorationLine) - return; - } - } - addProperty(propId, value, important); -} - -bool CSSParser::parseTextDecoration(CSSPropertyID propId, bool important) -{ - CSSParserValue* value = m_valueList->current(); - if (value && value->id == CSSValueNone) { - addTextDecorationProperty(propId, cssValuePool().createIdentifierValue(CSSValueNone), important); - m_valueList->next(); - return true; - } - - RefPtr list = CSSValueList::createSpaceSeparated(); - bool isValid = true; - while (isValid && value) { - switch (value->id) { - case CSSValueBlink: - case CSSValueLineThrough: - case CSSValueOverline: - case CSSValueUnderline: -#if ENABLE(LETTERPRESS) - case CSSValueWebkitLetterpress: -#endif - list->append(cssValuePool().createIdentifierValue(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 || inShorthand())) { - addTextDecorationProperty(propId, list.release(), important); - return true; - } - - return false; -} - -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 CSSValueInk: - addProperty(CSSPropertyWebkitTextDecorationSkip, cssValuePool().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) { - case CSSValueAuto: - case CSSValueAlphabetic: - case CSSValueUnder: - if (m_valueList->next()) - return false; - - addProperty(CSSPropertyWebkitTextUnderlinePosition, cssValuePool().createIdentifierValue(value->id), important); - return true; - default: - break; - } - return false; -} - -bool CSSParser::parseTextEmphasisStyle(bool important) -{ - unsigned valueListSize = m_valueList->size(); - - RefPtr fill; - RefPtr shape; - - for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - if (value->unit == CSSPrimitiveValue::CSS_STRING) { - if (fill || shape || (valueListSize != 1 && !inShorthand())) - return false; - addProperty(CSSPropertyWebkitTextEmphasisStyle, createPrimitiveStringValue(value), important); - m_valueList->next(); - return true; - } - - if (value->id == CSSValueNone) { - if (fill || shape || (valueListSize != 1 && !inShorthand())) - return false; - addProperty(CSSPropertyWebkitTextEmphasisStyle, cssValuePool().createIdentifierValue(CSSValueNone), important); - m_valueList->next(); - return true; - } - - if (value->id == CSSValueOpen || value->id == CSSValueFilled) { - if (fill) - return false; - fill = cssValuePool().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); - } else if (!inShorthand()) - return false; - else - break; - } - - if (fill && shape) { - RefPtr parsedValues = CSSValueList::createSpaceSeparated(); - parsedValues->append(fill.release()); - parsedValues->append(shape.release()); - addProperty(CSSPropertyWebkitTextEmphasisStyle, parsedValues.release(), important); - return true; - } - if (fill) { - addProperty(CSSPropertyWebkitTextEmphasisStyle, fill.release(), important); - return true; - } - if (shape) { - addProperty(CSSPropertyWebkitTextEmphasisStyle, shape.release(), important); - return true; - } - - return false; -} - -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 list = CSSValueList::createSpaceSeparated(); - list->append(cssValuePool().createIdentifierValue(overUnderValueID)); - if (foundLeftOrRight) - list->append(cssValuePool().createIdentifierValue(leftRightValueID)); - addProperty(CSSPropertyWebkitTextEmphasisPosition, list, important); - return true; -} - -PassRefPtr CSSParser::parseTextIndent() -{ - // | | inherit when CSS3_TEXT is disabled. - // [ | ] && [ -webkit-hanging || -webkit-each-line ]? | inherit when CSS3_TEXT is enabled. - RefPtr list = CSSValueList::createSpaceSeparated(); - bool hasLengthOrPercentage = false; -#if ENABLE(CSS3_TEXT) - bool hasEachLine = false; - bool hasHanging = false; -#endif - - CSSParserValue* value = m_valueList->current(); - while (value) { - if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent)) { - list->append(createPrimitiveNumericValue(value)); - hasLengthOrPercentage = true; - } -#if ENABLE(CSS3_TEXT) - else if (!hasEachLine && value->id == CSSValueWebkitEachLine) { - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitEachLine)); - hasEachLine = true; - } else if (!hasHanging && value->id == CSSValueWebkitHanging) { - list->append(cssValuePool().createIdentifierValue(CSSValueWebkitHanging)); - hasHanging = true; - } -#endif - else - return 0; - - value = m_valueList->next(); - } - - if (!hasLengthOrPercentage) - return 0; - - return list.release(); -} - -bool CSSParser::parseLineBoxContain(bool important) -{ - LineBoxContain lineBoxContain = LineBoxContainNone; - - for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - if (value->id == CSSValueBlock) { - if (lineBoxContain & LineBoxContainBlock) - return false; - lineBoxContain |= LineBoxContainBlock; - } else if (value->id == CSSValueInline) { - if (lineBoxContain & LineBoxContainInline) - return false; - lineBoxContain |= LineBoxContainInline; - } else if (value->id == CSSValueFont) { - if (lineBoxContain & LineBoxContainFont) - return false; - lineBoxContain |= LineBoxContainFont; - } else if (value->id == CSSValueGlyphs) { - if (lineBoxContain & LineBoxContainGlyphs) - return false; - lineBoxContain |= LineBoxContainGlyphs; - } else if (value->id == CSSValueReplaced) { - if (lineBoxContain & LineBoxContainReplaced) - return false; - lineBoxContain |= LineBoxContainReplaced; - } else if (value->id == CSSValueInlineBox) { - if (lineBoxContain & LineBoxContainInlineBox) - return false; - lineBoxContain |= LineBoxContainInlineBox; - } else - return false; - } - - if (!lineBoxContain) - return false; - - addProperty(CSSPropertyWebkitLineBoxContain, CSSLineBoxContainValue::create(lineBoxContain), important); - return true; -} - -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) - return false; - for (unsigned i = 0; i < tagNameLength; ++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; - } - - String tag = value->string; - int tagValue = 1; - // Feature tag values could follow: | on | off - value = m_valueList->next(); - if (value) { - if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) { - tagValue = clampToInteger(value->fValue); - if (tagValue < 0) - return false; - m_valueList->next(); - } else if (value->id == CSSValueOn || value->id == CSSValueOff) { - tagValue = value->id == CSSValueOn; - m_valueList->next(); - } - } - settings->append(CSSFontFeatureValue::create(tag, tagValue)); - return true; -} - -bool CSSParser::parseFontFeatureSettings(bool important) -{ - if (m_valueList->size() == 1 && m_valueList->current()->id == CSSValueNormal) { - RefPtr normalValue = cssValuePool().createIdentifierValue(CSSValueNormal); - m_valueList->next(); - addProperty(CSSPropertyWebkitFontFeatureSettings, normalValue.release(), important); - return true; - } - - RefPtr settings = CSSValueList::createCommaSeparated(); - for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) { - if (!parseFontFeatureTag(settings.get())) - return false; - - // If the list isn't parsed fully, the current value should be comma. - value = m_valueList->current(); - if (value && !isComma(value)) - return false; - } - if (settings->length()) { - addProperty(CSSPropertyWebkitFontFeatureSettings, settings.release(), important); - return true; - } - return false; -} - -bool CSSParser::parseFontVariantLigatures(bool important) -{ - RefPtr ligatureValues = CSSValueList::createSpaceSeparated(); - bool sawCommonLigaturesValue = false; - bool sawDiscretionaryLigaturesValue = false; - bool sawHistoricalLigaturesValue = false; - - 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: - if (sawCommonLigaturesValue) - return false; - sawCommonLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); - break; - case CSSValueNoDiscretionaryLigatures: - case CSSValueDiscretionaryLigatures: - if (sawDiscretionaryLigaturesValue) - return false; - sawDiscretionaryLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); - break; - case CSSValueNoHistoricalLigatures: - case CSSValueHistoricalLigatures: - if (sawHistoricalLigaturesValue) - return false; - sawHistoricalLigaturesValue = true; - ligatureValues->append(cssValuePool().createIdentifierValue(value->id)); - break; - default: - return false; - } - } - - if (!ligatureValues->length()) - return false; - - addProperty(CSSPropertyWebkitFontVariantLigatures, ligatureValues.release(), important); - return true; -} - -bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValueRange range) -{ - ASSERT(isCalculation(value)); - - CSSParserValueList* args = value->function->args.get(); - if (!args || !args->size()) - return false; - - ASSERT(!m_parsedCalculation); - m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range); - - if (!m_parsedCalculation) - return false; - - return true; -} - -#define END_TOKEN 0 - -#include "CSSGrammar.h" - -enum CharacterType { - // Types for the main switch. - - // The first 4 types must be grouped together, as they - // represent the allowed chars in an identifier. - CharacterCaselessU, - CharacterIdentifierStart, - CharacterNumber, - CharacterDash, - - CharacterOther, - CharacterNull, - CharacterWhiteSpace, - CharacterEndMediaQuery, - CharacterEndNthChild, - CharacterQuote, - CharacterExclamationMark, - CharacterHashmark, - CharacterDollar, - CharacterAsterisk, - CharacterPlus, - CharacterDot, - CharacterSlash, - CharacterLess, - CharacterAt, - CharacterBackSlash, - CharacterXor, - CharacterVerticalBar, - CharacterTilde, -}; - -// 128 ASCII codes -static const CharacterType typesOfASCIICharacters[128] = { -/* 0 - Null */ CharacterNull, -/* 1 - Start of Heading */ CharacterOther, -/* 2 - Start of Text */ CharacterOther, -/* 3 - End of Text */ CharacterOther, -/* 4 - End of Transm. */ CharacterOther, -/* 5 - Enquiry */ CharacterOther, -/* 6 - Acknowledgment */ CharacterOther, -/* 7 - Bell */ CharacterOther, -/* 8 - Back Space */ CharacterOther, -/* 9 - Horizontal Tab */ CharacterWhiteSpace, -/* 10 - Line Feed */ CharacterWhiteSpace, -/* 11 - Vertical Tab */ CharacterOther, -/* 12 - Form Feed */ CharacterWhiteSpace, -/* 13 - Carriage Return */ CharacterWhiteSpace, -/* 14 - Shift Out */ CharacterOther, -/* 15 - Shift In */ CharacterOther, -/* 16 - Data Line Escape */ CharacterOther, -/* 17 - Device Control 1 */ CharacterOther, -/* 18 - Device Control 2 */ CharacterOther, -/* 19 - Device Control 3 */ CharacterOther, -/* 20 - Device Control 4 */ CharacterOther, -/* 21 - Negative Ack. */ CharacterOther, -/* 22 - Synchronous Idle */ CharacterOther, -/* 23 - End of Transmit */ CharacterOther, -/* 24 - Cancel */ CharacterOther, -/* 25 - End of Medium */ CharacterOther, -/* 26 - Substitute */ CharacterOther, -/* 27 - Escape */ CharacterOther, -/* 28 - File Separator */ CharacterOther, -/* 29 - Group Separator */ CharacterOther, -/* 30 - Record Separator */ CharacterOther, -/* 31 - Unit Separator */ CharacterOther, -/* 32 - Space */ CharacterWhiteSpace, -/* 33 - ! */ CharacterExclamationMark, -/* 34 - " */ CharacterQuote, -/* 35 - # */ CharacterHashmark, -/* 36 - $ */ CharacterDollar, -/* 37 - % */ CharacterOther, -/* 38 - & */ CharacterOther, -/* 39 - ' */ CharacterQuote, -/* 40 - ( */ CharacterOther, -/* 41 - ) */ CharacterEndNthChild, -/* 42 - * */ CharacterAsterisk, -/* 43 - + */ CharacterPlus, -/* 44 - , */ CharacterOther, -/* 45 - - */ CharacterDash, -/* 46 - . */ CharacterDot, -/* 47 - / */ CharacterSlash, -/* 48 - 0 */ CharacterNumber, -/* 49 - 1 */ CharacterNumber, -/* 50 - 2 */ CharacterNumber, -/* 51 - 3 */ CharacterNumber, -/* 52 - 4 */ CharacterNumber, -/* 53 - 5 */ CharacterNumber, -/* 54 - 6 */ CharacterNumber, -/* 55 - 7 */ CharacterNumber, -/* 56 - 8 */ CharacterNumber, -/* 57 - 9 */ CharacterNumber, -/* 58 - : */ CharacterOther, -/* 59 - ; */ CharacterEndMediaQuery, -/* 60 - < */ CharacterLess, -/* 61 - = */ CharacterOther, -/* 62 - > */ CharacterOther, -/* 63 - ? */ CharacterOther, -/* 64 - @ */ CharacterAt, -/* 65 - A */ CharacterIdentifierStart, -/* 66 - B */ CharacterIdentifierStart, -/* 67 - C */ CharacterIdentifierStart, -/* 68 - D */ CharacterIdentifierStart, -/* 69 - E */ CharacterIdentifierStart, -/* 70 - F */ CharacterIdentifierStart, -/* 71 - G */ CharacterIdentifierStart, -/* 72 - H */ CharacterIdentifierStart, -/* 73 - I */ CharacterIdentifierStart, -/* 74 - J */ CharacterIdentifierStart, -/* 75 - K */ CharacterIdentifierStart, -/* 76 - L */ CharacterIdentifierStart, -/* 77 - M */ CharacterIdentifierStart, -/* 78 - N */ CharacterIdentifierStart, -/* 79 - O */ CharacterIdentifierStart, -/* 80 - P */ CharacterIdentifierStart, -/* 81 - Q */ CharacterIdentifierStart, -/* 82 - R */ CharacterIdentifierStart, -/* 83 - S */ CharacterIdentifierStart, -/* 84 - T */ CharacterIdentifierStart, -/* 85 - U */ CharacterCaselessU, -/* 86 - V */ CharacterIdentifierStart, -/* 87 - W */ CharacterIdentifierStart, -/* 88 - X */ CharacterIdentifierStart, -/* 89 - Y */ CharacterIdentifierStart, -/* 90 - Z */ CharacterIdentifierStart, -/* 91 - [ */ CharacterOther, -/* 92 - \ */ CharacterBackSlash, -/* 93 - ] */ CharacterOther, -/* 94 - ^ */ CharacterXor, -/* 95 - _ */ CharacterIdentifierStart, -/* 96 - ` */ CharacterOther, -/* 97 - a */ CharacterIdentifierStart, -/* 98 - b */ CharacterIdentifierStart, -/* 99 - c */ CharacterIdentifierStart, -/* 100 - d */ CharacterIdentifierStart, -/* 101 - e */ CharacterIdentifierStart, -/* 102 - f */ CharacterIdentifierStart, -/* 103 - g */ CharacterIdentifierStart, -/* 104 - h */ CharacterIdentifierStart, -/* 105 - i */ CharacterIdentifierStart, -/* 106 - j */ CharacterIdentifierStart, -/* 107 - k */ CharacterIdentifierStart, -/* 108 - l */ CharacterIdentifierStart, -/* 109 - m */ CharacterIdentifierStart, -/* 110 - n */ CharacterIdentifierStart, -/* 111 - o */ CharacterIdentifierStart, -/* 112 - p */ CharacterIdentifierStart, -/* 113 - q */ CharacterIdentifierStart, -/* 114 - r */ CharacterIdentifierStart, -/* 115 - s */ CharacterIdentifierStart, -/* 116 - t */ CharacterIdentifierStart, -/* 117 - u */ CharacterCaselessU, -/* 118 - v */ CharacterIdentifierStart, -/* 119 - w */ CharacterIdentifierStart, -/* 120 - x */ CharacterIdentifierStart, -/* 121 - y */ CharacterIdentifierStart, -/* 122 - z */ CharacterIdentifierStart, -/* 123 - { */ CharacterEndMediaQuery, -/* 124 - | */ CharacterVerticalBar, -/* 125 - } */ CharacterOther, -/* 126 - ~ */ CharacterTilde, -/* 127 - Delete */ CharacterOther, -}; - -// Utility functions for the CSS tokenizer. - -template -static inline bool isCSSLetter(CharacterType character) -{ - return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash; -} - -template -static inline bool isCSSEscape(CharacterType character) -{ - return character >= ' ' && character != 127; -} - -template -static inline bool isURILetter(CharacterType character) -{ - return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!'; -} - -template -static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter) -{ - return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128 - || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1])); -} - -template -static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString) -{ - // Compare an character memory data with a zero terminated string. - do { - // The input must be part of an identifier if constantChar or constString - // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'. - ASSERT((*constantString >= 'a' && *constantString <= 'z') || *constantString == '-'); - ASSERT(*constantString != '-' || isCSSLetter(*cssString)); - if (toASCIILowerUnchecked(*cssString++) != (*constantString++)) - return false; - } while (*constantString); - return true; -} - -template -static inline bool isEqualToCSSCaseSensitiveIdentifier(CharacterType* string, const char* constantString) -{ - do { - if (*string++ != *constantString++) - return false; - } while (*constantString); - return true; -} - -template -static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter) -{ - // Returns with 0, if escape check is failed. Otherwise - // it returns with the following character. - ASSERT(*currentCharacter == '\\'); - - ++currentCharacter; - if (!isCSSEscape(*currentCharacter)) - return 0; - - if (isASCIIHexDigit(*currentCharacter)) { - int length = 6; - - do { - ++currentCharacter; - } while (isASCIIHexDigit(*currentCharacter) && --length); - - // Optional space after the escape sequence. - if (isHTMLSpace(*currentCharacter)) - ++currentCharacter; - return currentCharacter; - } - return currentCharacter + 1; -} - -template -static inline CharacterType* skipWhiteSpace(CharacterType* currentCharacter) -{ - while (isHTMLSpace(*currentCharacter)) - ++currentCharacter; - return currentCharacter; -} - -// Main CSS tokenizer functions. - -template <> -LChar* CSSParserString::characters() const { return characters8(); } - -template <> -UChar* CSSParserString::characters() const { return characters16(); } - -template <> -inline LChar*& CSSParser::currentCharacter() -{ - return m_currentCharacter8; -} - -template <> -inline UChar*& CSSParser::currentCharacter() -{ - return m_currentCharacter16; -} - -UChar*& CSSParser::currentCharacter16() -{ - if (!m_currentCharacter16) { - m_dataStart16 = std::make_unique(m_length); - m_currentCharacter16 = m_dataStart16.get(); - } - - return m_currentCharacter16; -} - -template <> -inline LChar* CSSParser::tokenStart() -{ - return m_tokenStart.ptr8; -} - -template <> -inline UChar* CSSParser::tokenStart() -{ - return m_tokenStart.ptr16; -} - -CSSParser::Location CSSParser::currentLocation() -{ - Location location; - location.lineNumber = m_tokenStartLineNumber; - if (is8BitSource()) - location.token.init(tokenStart(), currentCharacter() - tokenStart()); - else - location.token.init(tokenStart(), currentCharacter() - tokenStart()); - return location; -} - -template -inline bool CSSParser::isIdentifierStart() -{ - // Check whether an identifier is started. - return isIdentifierStartAfterDash((*currentCharacter() != '-') ? currentCharacter() : currentCharacter() + 1); -} - -template -static inline CharacterType* checkAndSkipString(CharacterType* currentCharacter, int quote) -{ - // Returns with 0, if string check is failed. Otherwise - // it returns with the following character. This is necessary - // since we cannot revert escape sequences, thus strings - // must be validated before parsing. - while (true) { - if (UNLIKELY(*currentCharacter == quote)) { - // String parsing is successful. - return currentCharacter + 1; - } - if (UNLIKELY(!*currentCharacter)) { - // String parsing is successful up to end of input. - return currentCharacter; - } - if (UNLIKELY(*currentCharacter <= '\r' && (*currentCharacter == '\n' || (*currentCharacter | 0x1) == '\r'))) { - // String parsing is failed for character '\n', '\f' or '\r'. - return 0; - } - - if (LIKELY(currentCharacter[0] != '\\')) - ++currentCharacter; - else if (currentCharacter[1] == '\n' || currentCharacter[1] == '\f') - currentCharacter += 2; - else if (currentCharacter[1] == '\r') - currentCharacter += currentCharacter[2] == '\n' ? 3 : 2; - else { - currentCharacter = checkAndSkipEscape(currentCharacter); - if (!currentCharacter) - return 0; - } - } -} - -template -unsigned CSSParser::parseEscape(CharacterType*& src) -{ - ASSERT(*src == '\\' && isCSSEscape(src[1])); - - unsigned unicode = 0; - - ++src; - if (isASCIIHexDigit(*src)) { - - int length = 6; - - do { - unicode = (unicode << 4) + toASCIIHexValue(*src++); - } while (--length && isASCIIHexDigit(*src)); - - // Characters above 0x10ffff are not handled. - if (unicode > 0x10ffff) - unicode = 0xfffd; - - // Optional space after the escape sequence. - if (isHTMLSpace(*src)) - ++src; - - return unicode; - } - - return *currentCharacter()++; -} - -template <> -inline void CSSParser::UnicodeToChars(LChar*& result, unsigned unicode) -{ - ASSERT(unicode <= 0xff); - *result = unicode; - - ++result; -} - -template <> -inline void CSSParser::UnicodeToChars(UChar*& result, unsigned unicode) -{ - // Replace unicode with a surrogate pairs when it is bigger than 0xffff - if (U16_LENGTH(unicode) == 2) { - *result++ = U16_LEAD(unicode); - *result = U16_TRAIL(unicode); - } else - *result = unicode; - - ++result; -} - -template -inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestCharacterType*& result, bool& hasEscape) -{ - hasEscape = false; - do { - if (LIKELY(*src != '\\')) - *result++ = *src++; - else { - hasEscape = true; - SrcCharacterType* savedEscapeStart = src; - unsigned unicode = parseEscape(src); - if (unicode > 0xff && sizeof(DestCharacterType) == 1) { - src = savedEscapeStart; - return false; - } - UnicodeToChars(result, unicode); - } - } while (isCSSLetter(src[0]) || (src[0] == '\\' && isCSSEscape(src[1]))); - - return true; -} - -template -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* start = currentCharacter(); - if (UNLIKELY(!parseIdentifierInternal(currentCharacter(), result, hasEscape))) { - // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue - ASSERT(is8BitSource()); - UChar*& result16 = currentCharacter16(); - UChar* start16 = result16; - int i = 0; - for (; i < result - start; i++) - result16[i] = start[i]; - - result16 += i; - - parseIdentifierInternal(currentCharacter(), result16, hasEscape); - - resultString.init(start16, result16 - start16); - - return; - } - - resultString.init(start, result - start); -} - -template -inline bool CSSParser::parseStringInternal(SrcCharacterType*& src, DestCharacterType*& result, UChar quote) -{ - while (true) { - if (UNLIKELY(*src == quote)) { - // String parsing is done. - ++src; - return true; - } - if (UNLIKELY(!*src)) { - // String parsing is done, but don't advance pointer if at the end of input. - return true; - } - ASSERT(*src > '\r' || (*src < '\n' && *src) || *src == '\v'); - - if (LIKELY(src[0] != '\\')) - *result++ = *src++; - else if (src[1] == '\n' || src[1] == '\f') - src += 2; - else if (src[1] == '\r') - src += src[2] == '\n' ? 3 : 2; - else { - SrcCharacterType* savedEscapeStart = src; - unsigned unicode = parseEscape(src); - if (unicode > 0xff && sizeof(DestCharacterType) == 1) { - src = savedEscapeStart; - return false; - } - UnicodeToChars(result, unicode); - } - } - - return true; -} - -template -inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resultString, UChar quote) -{ - CharacterType* start = currentCharacter(); - - if (UNLIKELY(!parseStringInternal(currentCharacter(), result, quote))) { - // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue - ASSERT(is8BitSource()); - UChar*& result16 = currentCharacter16(); - UChar* start16 = result16; - int i = 0; - for (; i < result - start; i++) - result16[i] = start[i]; - - result16 += i; - - parseStringInternal(currentCharacter(), result16, quote); - - resultString.init(start16, result16 - start16); - return; - } - - resultString.init(start, result - start); -} - -template -inline bool CSSParser::findURI(CharacterType*& start, CharacterType*& end, UChar& quote) -{ - start = skipWhiteSpace(currentCharacter()); - - if (*start == '"' || *start == '\'') { - quote = *start++; - end = checkAndSkipString(start, quote); - if (!end) - return false; - } else { - quote = 0; - end = start; - while (isURILetter(*end)) { - if (LIKELY(*end != '\\')) - ++end; - else { - end = checkAndSkipEscape(end); - if (!end) - return false; - } - } - } - - end = skipWhiteSpace(end); - if (*end != ')') - return false; - - return true; -} - -template -inline bool CSSParser::parseURIInternal(SrcCharacterType*& src, DestCharacterType*& dest, UChar quote) -{ - if (quote) { - ASSERT(quote == '"' || quote == '\''); - return parseStringInternal(src, dest, quote); - } - - while (isURILetter(*src)) { - if (LIKELY(*src != '\\')) - *dest++ = *src++; - else { - unsigned unicode = parseEscape(src); - if (unicode > 0xff && sizeof(SrcCharacterType) == 1) - return false; - UnicodeToChars(dest, unicode); - } - } - - return true; -} - -template -inline void CSSParser::parseURI(CSSParserString& string) -{ - CharacterType* uriStart; - CharacterType* uriEnd; - UChar quote; - if (!findURI(uriStart, uriEnd, quote)) - return; - - CharacterType* dest = currentCharacter() = uriStart; - if (LIKELY(parseURIInternal(currentCharacter(), dest, quote))) - string.init(uriStart, dest - uriStart); - else { - // An escape sequence was encountered that can't be stored in 8 bits. - // Reset the current character to the start of the URI and re-parse with - // a 16-bit destination. - ASSERT(is8BitSource()); - UChar* uriStart16 = currentCharacter16(); - currentCharacter() = uriStart; - bool result = parseURIInternal(currentCharacter(), currentCharacter16(), quote); - ASSERT_UNUSED(result, result); - string.init(uriStart16, currentCharacter16() - uriStart16); - } - - currentCharacter() = uriEnd + 1; - m_token = URI; -} - -template -inline bool CSSParser::parseUnicodeRange() -{ - CharacterType* character = currentCharacter() + 1; - int length = 6; - ASSERT(*currentCharacter() == '+'); - - while (isASCIIHexDigit(*character) && length) { - ++character; - --length; - } - - if (length && *character == '?') { - // At most 5 hex digit followed by a question mark. - do { - ++character; - --length; - } while (*character == '?' && length); - currentCharacter() = character; - return true; - } - - if (length < 6) { - // At least one hex digit. - if (character[0] == '-' && isASCIIHexDigit(character[1])) { - // Followed by a dash and a hex digit. - ++character; - length = 6; - do { - ++character; - } while (--length && isASCIIHexDigit(*character)); - } - currentCharacter() = character; - return true; - } - return false; -} - -template -bool CSSParser::parseNthChild() -{ - CharacterType* character = currentCharacter(); - - while (isASCIIDigit(*character)) - ++character; - if (isASCIIAlphaCaselessEqual(*character, 'n')) { - currentCharacter() = character + 1; - return true; - } - return false; -} - -template -bool CSSParser::parseNthChildExtra() -{ - CharacterType* character = skipWhiteSpace(currentCharacter()); - if (*character != '+' && *character != '-') - return false; - - character = skipWhiteSpace(character + 1); - if (!isASCIIDigit(*character)) - return false; - - do { - ++character; - } while (isASCIIDigit(*character)); - - currentCharacter() = character; - return true; -} - -template -inline bool CSSParser::detectFunctionTypeToken(int length) -{ - ASSERT(length > 0); - CharacterType* name = tokenStart(); - - switch (length) { - case 3: - if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't')) { - m_token = NOTFUNCTION; - return true; - } - if (isASCIIAlphaCaselessEqual(name[0], 'u') && isASCIIAlphaCaselessEqual(name[1], 'r') && isASCIIAlphaCaselessEqual(name[2], 'l')) { - m_token = URI; - 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 - return false; - - case 4: - if (isEqualToCSSIdentifier(name, "calc")) { - m_token = CALCFUNCTION; - return true; - } - return false; - - case 9: - if (isEqualToCSSIdentifier(name, "nth-child")) { - m_parsingMode = NthChildMode; - return true; - } - return false; - - case 11: - if (isEqualToCSSIdentifier(name, "nth-of-type")) { - m_parsingMode = NthChildMode; - return true; - } - return false; - - case 14: - if (isEqualToCSSIdentifier(name, "nth-last-child")) { - m_parsingMode = NthChildMode; - return true; - } - return false; - - case 16: - if (isEqualToCSSIdentifier(name, "nth-last-of-type")) { - m_parsingMode = NthChildMode; - return true; - } - return false; - } - - return false; -} - -template -inline void CSSParser::detectMediaQueryToken(int length) -{ - ASSERT(m_parsingMode == MediaQueryMode); - CharacterType* name = tokenStart(); - - if (length == 3) { - if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd')) - m_token = MEDIA_AND; - else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't')) - m_token = MEDIA_NOT; - } else if (length == 4) { - if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'n') - && isASCIIAlphaCaselessEqual(name[2], 'l') && isASCIIAlphaCaselessEqual(name[3], 'y')) - m_token = MEDIA_ONLY; - } -} - -template -inline void CSSParser::detectNumberToken(CharacterType* type, int length) -{ - ASSERT(length > 0); - - switch (toASCIILowerUnchecked(type[0])) { - case 'c': - if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'm')) - m_token = CMS; - else if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'h')) - m_token = CHS; - return; - - case 'd': - if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'g')) - m_token = DEGS; -#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - else if (length > 2 && isASCIIAlphaCaselessEqual(type[1], 'p')) { - if (length == 4) { - // There is a discussion about the name of this unit on www-style. - // Keep this compile time guard in place until that is resolved. - // http://lists.w3.org/Archives/Public/www-style/2012May/0915.html - if (isASCIIAlphaCaselessEqual(type[2], 'p') && isASCIIAlphaCaselessEqual(type[3], 'x')) - m_token = DPPX; - else if (isASCIIAlphaCaselessEqual(type[2], 'c') && isASCIIAlphaCaselessEqual(type[3], 'm')) - m_token = DPCM; - } else if (length == 3 && isASCIIAlphaCaselessEqual(type[2], 'i')) - m_token = DPI; - } -#endif - return; - - case 'e': - if (length == 2) { - if (isASCIIAlphaCaselessEqual(type[1], 'm')) - m_token = EMS; - else if (isASCIIAlphaCaselessEqual(type[1], 'x')) - m_token = EXS; - } - 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')) - m_token = GRADS; - return; - - case 'h': - if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'z')) - m_token = HERTZ; - return; - - case 'i': - if (length == 2 && isASCIIAlphaCaselessEqual(type[1], 'n')) - m_token = INS; - return; - - case 'k': - if (length == 3 && isASCIIAlphaCaselessEqual(type[1], 'h') && isASCIIAlphaCaselessEqual(type[2], 'z')) - m_token = KHERTZ; - return; - - case 'm': - if (length == 2) { - if (isASCIIAlphaCaselessEqual(type[1], 'm')) - m_token = MMS; - else if (isASCIIAlphaCaselessEqual(type[1], 's')) - m_token = MSECS; - } - return; - - case 'p': - if (length == 2) { - if (isASCIIAlphaCaselessEqual(type[1], 'x')) - m_token = PXS; - else if (isASCIIAlphaCaselessEqual(type[1], 't')) - m_token = PTS; - else if (isASCIIAlphaCaselessEqual(type[1], 'c')) - m_token = PCS; - } - return; - - case 'r': - if (length == 3) { - if (isASCIIAlphaCaselessEqual(type[1], 'a') && isASCIIAlphaCaselessEqual(type[2], 'd')) - m_token = RADS; - else if (isASCIIAlphaCaselessEqual(type[1], 'e') && isASCIIAlphaCaselessEqual(type[2], 'm')) - m_token = REMS; - } - return; - - case 's': - if (length == 1) - m_token = SECS; - return; - - case 't': - if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'u') - && isASCIIAlphaCaselessEqual(type[2], 'r') && isASCIIAlphaCaselessEqual(type[3], 'n')) - m_token = TURNS; - return; - case 'v': - if (length == 2) { - if (isASCIIAlphaCaselessEqual(type[1], 'w')) - m_token = VW; - else if (isASCIIAlphaCaselessEqual(type[1], 'h')) - m_token = VH; - } else if (length == 4 && isASCIIAlphaCaselessEqual(type[1], 'm')) { - if (isASCIIAlphaCaselessEqual(type[2], 'i') && isASCIIAlphaCaselessEqual(type[3], 'n')) - m_token = VMIN; - else if (isASCIIAlphaCaselessEqual(type[2], 'a') && isASCIIAlphaCaselessEqual(type[3], 'x')) - m_token = VMAX; - } - return; - - default: - if (type[0] == '_' && length == 5 && type[1] == '_' && isASCIIAlphaCaselessEqual(type[2], 'q') - && isASCIIAlphaCaselessEqual(type[3], 'e') && isASCIIAlphaCaselessEqual(type[4], 'm')) - m_token = QEMS; - return; - } -} - -template -inline void CSSParser::detectDashToken(int length) -{ - CharacterType* name = tokenStart(); - - if (length == 11) { - if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an")) - m_token = ANYFUNCTION; - else if (isASCIIAlphaCaselessEqual(name[10], 'n') && isEqualToCSSIdentifier(name + 1, "webkit-mi")) - m_token = MINFUNCTION; - else if (isASCIIAlphaCaselessEqual(name[10], 'x') && isEqualToCSSIdentifier(name + 1, "webkit-ma")) - m_token = MAXFUNCTION; - } 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 -inline void CSSParser::detectAtToken(int length, bool hasEscape) -{ - CharacterType* name = tokenStart(); - ASSERT(name[0] == '@' && length >= 2); - - // charset, font-face, import, media, namespace, page, supports, - // -webkit-keyframes, and -webkit-mediaquery are not affected by hasEscape. - switch (toASCIILowerUnchecked(name[1])) { - case 'b': - if (hasEscape) - return; - - switch (length) { - case 12: - if (isEqualToCSSIdentifier(name + 2, "ottom-left")) - m_token = BOTTOMLEFT_SYM; - return; - - case 13: - if (isEqualToCSSIdentifier(name + 2, "ottom-right")) - m_token = BOTTOMRIGHT_SYM; - return; - - case 14: - if (isEqualToCSSIdentifier(name + 2, "ottom-center")) - m_token = BOTTOMCENTER_SYM; - return; - - case 19: - if (isEqualToCSSIdentifier(name + 2, "ottom-left-corner")) - m_token = BOTTOMLEFTCORNER_SYM; - return; - - case 20: - if (isEqualToCSSIdentifier(name + 2, "ottom-right-corner")) - m_token = BOTTOMRIGHTCORNER_SYM; - return; - } - return; - - case 'c': - if (length == 8 && isEqualToCSSIdentifier(name + 2, "harset")) - m_token = CHARSET_SYM; - return; - - case 'f': - if (length == 10 && isEqualToCSSIdentifier(name + 2, "ont-face")) - 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; - m_token = IMPORT_SYM; - } - return; - - case 'l': - if (hasEscape) - return; - - if (length == 9) { - if (isEqualToCSSIdentifier(name + 2, "eft-top")) - m_token = LEFTTOP_SYM; - } else if (length == 12) { - // Checking the last character first could further reduce the possibile cases. - if (isASCIIAlphaCaselessEqual(name[11], 'e') && isEqualToCSSIdentifier(name + 2, "eft-middl")) - m_token = LEFTMIDDLE_SYM; - else if (isASCIIAlphaCaselessEqual(name[11], 'm') && isEqualToCSSIdentifier(name + 2, "eft-botto")) - m_token = LEFTBOTTOM_SYM; - } - return; - - case 'm': - if (length == 6 && isEqualToCSSIdentifier(name + 2, "edia")) { - m_parsingMode = MediaQueryMode; - m_token = MEDIA_SYM; - } - return; - - case 'n': - if (length == 10 && isEqualToCSSIdentifier(name + 2, "amespace")) - m_token = NAMESPACE_SYM; - return; - - case 'p': - if (length == 5 && isEqualToCSSIdentifier(name + 2, "age")) - m_token = PAGE_SYM; - return; - - case 'r': - if (hasEscape) - return; - - if (length == 10) { - if (isEqualToCSSIdentifier(name + 2, "ight-top")) - m_token = RIGHTTOP_SYM; - } else if (length == 13) { - // Checking the last character first could further reduce the possibile cases. - if (isASCIIAlphaCaselessEqual(name[12], 'e') && isEqualToCSSIdentifier(name + 2, "ight-middl")) - m_token = RIGHTMIDDLE_SYM; - else if (isASCIIAlphaCaselessEqual(name[12], 'm') && isEqualToCSSIdentifier(name + 2, "ight-botto")) - m_token = RIGHTBOTTOM_SYM; - } - 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) - return; - - switch (length) { - case 9: - if (isEqualToCSSIdentifier(name + 2, "op-left")) - m_token = TOPLEFT_SYM; - return; - - case 10: - if (isEqualToCSSIdentifier(name + 2, "op-right")) - m_token = TOPRIGHT_SYM; - return; - - case 11: - if (isEqualToCSSIdentifier(name + 2, "op-center")) - m_token = TOPCENTER_SYM; - return; - - case 16: - if (isEqualToCSSIdentifier(name + 2, "op-left-corner")) - m_token = TOPLEFTCORNER_SYM; - return; - - case 17: - if (isEqualToCSSIdentifier(name + 2, "op-right-corner")) - m_token = TOPRIGHTCORNER_SYM; - return; - } - return; - - case '-': - switch (length) { - case 13: - if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-rule")) - m_token = WEBKIT_RULE_SYM; - return; - - case 14: - if (hasEscape) - return; - - // Checking the last character first could further reduce the possibile cases. - if (isASCIIAlphaCaselessEqual(name[13], 's') && isEqualToCSSIdentifier(name + 2, "webkit-decl")) - m_token = WEBKIT_DECLS_SYM; - else if (isASCIIAlphaCaselessEqual(name[13], 'e') && isEqualToCSSIdentifier(name + 2, "webkit-valu")) - m_token = WEBKIT_VALUE_SYM; - return; - - case 15: - if (hasEscape) - return; - -#if ENABLE(CSS_REGIONS) - if (isASCIIAlphaCaselessEqual(name[14], 'n') && isEqualToCSSIdentifier(name + 2, "webkit-regio")) - m_token = WEBKIT_REGION_RULE_SYM; -#endif - return; - - case 17: - if (hasEscape) - return; - - if (isASCIIAlphaCaselessEqual(name[16], 'r') && isEqualToCSSIdentifier(name + 2, "webkit-selecto")) - m_token = WEBKIT_SELECTOR_SYM; -#if ENABLE(CSS_DEVICE_ADAPTATION) - else if (isASCIIAlphaCaselessEqual(name[16], 't') && isEqualToCSSIdentifier(name + 2, "webkit-viewpor")) - m_token = WEBKIT_VIEWPORT_RULE_SYM; -#endif - return; - - case 18: - if (isEqualToCSSIdentifier(name + 2, "webkit-keyframes")) - m_token = WEBKIT_KEYFRAMES_SYM; - return; - - case 19: - if (isEqualToCSSIdentifier(name + 2, "webkit-mediaquery")) { - m_parsingMode = MediaQueryMode; - m_token = WEBKIT_MEDIAQUERY_SYM; - } - return; - - case 22: - if (!hasEscape && isEqualToCSSIdentifier(name + 2, "webkit-keyframe-rule")) - m_token = WEBKIT_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 -inline void CSSParser::detectSupportsToken(int length) -{ - ASSERT(m_parsingMode == SupportsMode); - CharacterType* name = tokenStart(); - - if (length == 2) { - if (isASCIIAlphaCaselessEqual(name[0], 'o') && isASCIIAlphaCaselessEqual(name[1], 'r')) - m_token = SUPPORTS_OR; - } else if (length == 3) { - if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd')) - m_token = SUPPORTS_AND; - else if (isASCIIAlphaCaselessEqual(name[0], 'n') && isASCIIAlphaCaselessEqual(name[1], 'o') && isASCIIAlphaCaselessEqual(name[2], 't')) - m_token = SUPPORTS_NOT; - } -} -#endif - -template -int CSSParser::realLex(void* yylvalWithoutType) -{ - YYSTYPE* yylval = static_cast(yylvalWithoutType); - // Write pointer for the next character. - SrcCharacterType* result; - CSSParserString resultString; - bool hasEscape; - - // The input buffer is terminated by a \0 character, so - // it is safe to read one character ahead of a known non-null. -#ifndef NDEBUG - // In debug we check with an ASSERT that the length is > 0 for string types. - yylval->string.clear(); -#endif - -restartAfterComment: - result = currentCharacter(); - setTokenStart(result); - m_tokenStartLineNumber = m_lineNumber; - m_token = *currentCharacter(); - ++currentCharacter(); - - switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) { - case CharacterCaselessU: - if (UNLIKELY(*currentCharacter() == '+')) { - if (parseUnicodeRange()) { - m_token = UNICODERANGE; - yylval->string.init(tokenStart(), currentCharacter() - tokenStart()); - break; - } - } - FALLTHROUGH; // To CharacterIdentifierStart. - - case CharacterIdentifierStart: - --currentCharacter(); - parseIdentifier(result, yylval->string, hasEscape); - m_token = IDENT; - - if (UNLIKELY(*currentCharacter() == '(')) { -#if ENABLE(CSS3_CONDITIONAL_RULES) - if (m_parsingMode == SupportsMode && !hasEscape) { - detectSupportsToken(result - tokenStart()); - if (m_token != IDENT) - break; - } -#endif - m_token = FUNCTION; - bool shouldSkipParenthesis = true; - if (!hasEscape) { - bool detected = detectFunctionTypeToken(result - tokenStart()); - if (!detected && m_parsingMode == MediaQueryMode) { - // ... and(max-width: 480px) ... looks like a function, but in fact it is not, - // so run more detection code in the MediaQueryMode. - detectMediaQueryToken(result - tokenStart()); - shouldSkipParenthesis = false; - } - } - - if (LIKELY(shouldSkipParenthesis)) { - ++currentCharacter(); - ++result; - ++yylval->string.m_length; - } - - if (token() == URI) { - m_token = FUNCTION; - // Check whether it is really an URI. - if (yylval->string.is8Bit()) - parseURI(yylval->string); - else - parseURI(yylval->string); - } - } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) { - if (m_parsingMode == MediaQueryMode) - detectMediaQueryToken(result - tokenStart()); -#if ENABLE(CSS3_CONDITIONAL_RULES) - else if (m_parsingMode == SupportsMode) - detectSupportsToken(result - tokenStart()); -#endif - else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart()[0], 'n')) { - if (result - tokenStart() == 1) { - // String "n" is IDENT but "n+1" is NTH. - if (parseNthChildExtra()) { - m_token = NTH; - yylval->string.m_length = currentCharacter() - tokenStart(); - } - } else if (result - tokenStart() >= 2 && tokenStart()[1] == '-') { - // String "n-" is IDENT but "n-1" is NTH. - // Set currentCharacter to '-' to continue parsing. - SrcCharacterType* nextCharacter = result; - currentCharacter() = tokenStart() + 1; - if (parseNthChildExtra()) { - m_token = NTH; - yylval->string.setLength(currentCharacter() - tokenStart()); - } else { - // Revert the change to currentCharacter if unsuccessful. - currentCharacter() = nextCharacter; - } - } - } - } - break; - - case CharacterDot: - if (!isASCIIDigit(currentCharacter()[0])) - break; - FALLTHROUGH; // To CharacterNumber. - - case CharacterNumber: { - bool dotSeen = (m_token == '.'); - - while (true) { - if (!isASCIIDigit(currentCharacter()[0])) { - // Only one dot is allowed for a number, - // and it must be followed by a digit. - if (currentCharacter()[0] != '.' || dotSeen || !isASCIIDigit(currentCharacter()[1])) - break; - dotSeen = true; - } - ++currentCharacter(); - } - - if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*currentCharacter(), 'n')) { - // "[0-9]+n" is always an NthChild. - ++currentCharacter(); - parseNthChildExtra(); - m_token = NTH; - yylval->string.init(tokenStart(), currentCharacter() - tokenStart()); - 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'. - SrcCharacterType* character = currentCharacter(); - if (isASCIIAlphaCaselessEqual(*character, 'e')) { - ASSERT(character - tokenStart() > 0); - ++character; - if (*character == '-' || *character == '+' || isASCIIDigit(*character)) { - ++character; - while (isASCIIDigit(*character)) - ++character; - // Use FLOATTOKEN if the string contains exponents. - dotSeen = true; - currentCharacter() = character; - } - } - if (!parseSVGNumber(tokenStart(), character - tokenStart(), yylval->number)) - break; - } else -#endif - yylval->number = charactersToDouble(tokenStart(), currentCharacter() - tokenStart()); - - // Type of the function. - if (isIdentifierStart()) { - SrcCharacterType* type = currentCharacter(); - result = currentCharacter(); - - parseIdentifier(result, resultString, hasEscape); - - m_token = DIMEN; - if (!hasEscape) - detectNumberToken(type, currentCharacter() - type); - - if (m_token == DIMEN) { - // The decoded number is overwritten, but this is intentional. - yylval->string.init(tokenStart(), currentCharacter() - tokenStart()); - } - } else if (*currentCharacter() == '%') { - // Although the CSS grammar says {num}% we follow - // webkit at the moment which uses {num}%+. - do { - ++currentCharacter(); - } while (*currentCharacter() == '%'); - m_token = PERCENTAGE; - } else - m_token = dotSeen ? FLOATTOKEN : INTEGER; - break; - } - - case CharacterDash: - if (isIdentifierStartAfterDash(currentCharacter())) { - --currentCharacter(); - parseIdentifier(result, resultString, hasEscape); - m_token = IDENT; - - if (*currentCharacter() == '(') { - m_token = FUNCTION; - if (!hasEscape) - detectDashToken(result - tokenStart()); - ++currentCharacter(); - ++result; - } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(tokenStart()[1], 'n')) { - if (result - tokenStart() == 2) { - // String "-n" is IDENT but "-n+1" is NTH. - if (parseNthChildExtra()) { - m_token = NTH; - result = currentCharacter(); - } - } else if (result - tokenStart() >= 3 && tokenStart()[2] == '-') { - // String "-n-" is IDENT but "-n-1" is NTH. - // Set currentCharacter to second '-' of '-n-' to continue parsing. - SrcCharacterType* nextCharacter = result; - currentCharacter() = tokenStart() + 2; - if (parseNthChildExtra()) { - m_token = NTH; - result = currentCharacter(); - } else { - // Revert the change to currentCharacter if unsuccessful. - currentCharacter() = nextCharacter; - } - } - } - resultString.setLength(result - tokenStart()); - yylval->string = resultString; - } else if (currentCharacter()[0] == '-' && currentCharacter()[1] == '>') { - currentCharacter() += 2; - m_token = SGML_CD; - } else if (UNLIKELY(m_parsingMode == NthChildMode)) { - // "-[0-9]+n" is always an NthChild. - if (parseNthChild()) { - parseNthChildExtra(); - m_token = NTH; - yylval->string.init(tokenStart(), currentCharacter() - tokenStart()); - } - } - break; - - case CharacterOther: - // m_token is simply the current character. - break; - - case CharacterNull: - // Do not advance pointer at the end of input. - --currentCharacter(); - break; - - case CharacterWhiteSpace: - m_token = WHITESPACE; - // Might start with a '\n'. - --currentCharacter(); - do { - if (*currentCharacter() == '\n') - ++m_lineNumber; - ++currentCharacter(); - } while (*currentCharacter() <= ' ' && (typesOfASCIICharacters[*currentCharacter()] == CharacterWhiteSpace)); - break; - - case CharacterEndMediaQuery: - if (m_parsingMode == MediaQueryMode) - m_parsingMode = NormalMode; - break; - - case CharacterEndNthChild: - if (m_parsingMode == NthChildMode) - m_parsingMode = NormalMode; - break; - - case CharacterQuote: - if (checkAndSkipString(currentCharacter(), m_token)) { - ++result; - parseString(result, yylval->string, m_token); - m_token = STRING; - } - break; - - case CharacterExclamationMark: { - SrcCharacterType* start = skipWhiteSpace(currentCharacter()); - if (isEqualToCSSIdentifier(start, "important")) { - m_token = IMPORTANT_SYM; - currentCharacter() = start + 9; - } - break; - } - - case CharacterHashmark: { - SrcCharacterType* start = currentCharacter(); - result = currentCharacter(); - - if (isASCIIDigit(*currentCharacter())) { - // This must be a valid hex number token. - do { - ++currentCharacter(); - } while (isASCIIHexDigit(*currentCharacter())); - m_token = HEX; - yylval->string.init(start, currentCharacter() - start); - } else if (isIdentifierStart()) { - m_token = IDSEL; - parseIdentifier(result, yylval->string, hasEscape); - if (!hasEscape) { - // Check whether the identifier is also a valid hex number. - SrcCharacterType* current = start; - m_token = HEX; - do { - if (!isASCIIHexDigit(*current)) { - m_token = IDSEL; - break; - } - ++current; - } while (current < result); - } - } - break; - } - - case CharacterSlash: - // Ignore comments. They are not even considered as white spaces. - if (*currentCharacter() == '*') { - ++currentCharacter(); - while (currentCharacter()[0] != '*' || currentCharacter()[1] != '/') { - if (*currentCharacter() == '\n') - ++m_lineNumber; - if (*currentCharacter() == '\0') { - // Unterminated comments are simply ignored. - currentCharacter() -= 2; - break; - } - ++currentCharacter(); - } - currentCharacter() += 2; - goto restartAfterComment; - } - break; - - case CharacterDollar: - if (*currentCharacter() == '=') { - ++currentCharacter(); - m_token = ENDSWITH; - } - break; - - case CharacterAsterisk: - if (*currentCharacter() == '=') { - ++currentCharacter(); - m_token = CONTAINS; - } - break; - - case CharacterPlus: - if (UNLIKELY(m_parsingMode == NthChildMode)) { - // Simplest case. "+[0-9]*n" is always NthChild. - if (parseNthChild()) { - parseNthChildExtra(); - m_token = NTH; - yylval->string.init(tokenStart(), currentCharacter() - tokenStart()); - } - } - break; - - case CharacterLess: - if (currentCharacter()[0] == '!' && currentCharacter()[1] == '-' && currentCharacter()[2] == '-') { - currentCharacter() += 3; - m_token = SGML_CD; - } - break; - - case CharacterAt: - if (isIdentifierStart()) { - m_token = ATKEYWORD; - ++result; - parseIdentifier(result, resultString, hasEscape); - detectAtToken(result - tokenStart(), hasEscape); - } - break; - - case CharacterBackSlash: - if (isCSSEscape(*currentCharacter())) { - --currentCharacter(); - parseIdentifier(result, yylval->string, hasEscape); - m_token = IDENT; - } - break; - - case CharacterXor: - if (*currentCharacter() == '=') { - ++currentCharacter(); - m_token = BEGINSWITH; - } - break; - - case CharacterVerticalBar: - if (*currentCharacter() == '=') { - ++currentCharacter(); - m_token = DASHMATCH; - } - break; - - case CharacterTilde: - if (*currentCharacter() == '=') { - ++currentCharacter(); - m_token = INCLUDES; - } - break; - - default: - ASSERT_NOT_REACHED(); - break; - } - - return token(); -} - -PassRefPtr CSSParser::createImportRule(const CSSParserString& url, PassRefPtr media) -{ - if (!media || !m_allowImportRules) { - popRuleData(); - return 0; - } - RefPtr rule = StyleRuleImport::create(url, media); - processAndAddNewRuleToSourceTreeIfNeeded(); - return rule.release(); -} - -PassRefPtr CSSParser::createMediaRule(PassRefPtr media, RuleList* rules) -{ - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr rule; - RuleList emptyRules; - if (!media) { - // To comply with w3c test suite expectation, create an empty media query - // even when it is syntactically incorrect. - rule = StyleRuleMedia::create(MediaQuerySet::create(), emptyRules); - } else - rule = StyleRuleMedia::create(media, rules ? *rules : emptyRules); - processAndAddNewRuleToSourceTreeIfNeeded(); - return rule.release(); -} - -PassRefPtr CSSParser::createEmptyMediaRule(RuleList* rules) -{ - return createMediaRule(MediaQuerySet::create(), rules); -} - -#if ENABLE(CSS3_CONDITIONAL_RULES) -PassRefPtr CSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules) -{ - m_allowImportRules = m_allowNamespaceDeclarations = false; - - RefPtr data = popSupportsRuleData(); - RefPtr rule; - String conditionText; - unsigned conditionOffset = data->ruleHeaderRange.start + 9; - unsigned conditionLength = data->ruleHeaderRange.length() - 9; - - if (is8BitSource()) - conditionText = String(m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace(); - else - conditionText = String(m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace(); - - if (rules) - rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules); - else { - RuleList emptyRules; - rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules); - } - - processAndAddNewRuleToSourceTreeIfNeeded(); - - return rule.release(); -} - -void CSSParser::markSupportsRuleHeaderStart() -{ - if (!m_supportsRuleDataStack) - m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList()); - - RefPtr data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE); - data->ruleHeaderRange.start = tokenStartOffset(); - m_supportsRuleDataStack->append(data); -} - -void CSSParser::markSupportsRuleHeaderEnd() -{ - ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty()); - - if (is8BitSource()) - m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart() - m_dataStart8.get(); - else - m_supportsRuleDataStack->last()->ruleHeaderRange.end = tokenStart() - m_dataStart16.get(); -} - -PassRefPtr CSSParser::popSupportsRuleData() -{ - ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty()); - RefPtr data = m_supportsRuleDataStack->last(); - m_supportsRuleDataStack->removeLast(); - return data.release(); -} - -#endif - -void CSSParser::processAndAddNewRuleToSourceTreeIfNeeded() -{ - if (!isExtractingSourceData()) - return; - markRuleBodyEnd(); - RefPtr rule = popRuleData(); - fixUnparsedPropertyRanges(rule.get()); - addNewRuleToSourceTree(rule.release()); -} - -void CSSParser::addNewRuleToSourceTree(PassRefPtr rule) -{ - // Precondition: (isExtractingSourceData()). - if (!m_ruleSourceDataResult) - return; - if (m_currentRuleDataStack->isEmpty()) - m_ruleSourceDataResult->append(rule); - else - m_currentRuleDataStack->last()->childRules.append(rule); -} - -PassRefPtr CSSParser::popRuleData() -{ - if (!m_ruleSourceDataResult) - return 0; - - ASSERT(!m_currentRuleDataStack->isEmpty()); - m_currentRuleData.clear(); - RefPtr data = m_currentRuleDataStack->last(); - m_currentRuleDataStack->removeLast(); - return data.release(); -} - -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: "); - } - - if (location.token.is8Bit()) - builder.append(location.token.characters8(), location.token.length()); - else - builder.append(location.token.characters16(), location.token.length()); - - logError(builder.toString(), location.lineNumber); - - m_ignoreErrorsInDeclaration = true; -} - -bool CSSParser::isLoggingErrors() -{ - return m_logErrors && !m_ignoreErrorsInDeclaration; -} - -void CSSParser::logError(const String& message, int lineNumber) -{ - // FIXME: CSS parser console message errors should include column numbers. - PageConsole& console = m_styleSheet->singleOwnerDocument()->page()->console(); - console.addMessage(CSSMessageSource, WarningMessageLevel, message, m_styleSheet->baseURL().string(), lineNumber + 1, 0); -} - -PassRefPtr CSSParser::createKeyframesRule(const String& name, PassOwnPtr>> popKeyframes) -{ - OwnPtr>> keyframes = popKeyframes; - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr rule = StyleRuleKeyframes::create(); - for (size_t i = 0; i < keyframes->size(); ++i) - rule->parserAppendKeyframe(keyframes->at(i)); - rule->setName(name); - processAndAddNewRuleToSourceTreeIfNeeded(); - return rule.release(); -} - -PassRefPtr CSSParser::createStyleRule(Vector>* selectors) -{ - RefPtr rule; - if (selectors) { - m_allowImportRules = false; - m_allowNamespaceDeclarations = false; - if (m_hasFontFaceOnlyValues) - deleteFontFaceOnlyValues(); - rule = StyleRule::create(m_lastSelectorLineNumber, createStyleProperties()); - rule->parserAdoptSelectorVector(*selectors); - processAndAddNewRuleToSourceTreeIfNeeded(); - } else - popRuleData(); - clearProperties(); - return rule.release(); -} - -PassRefPtr 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() || toCSSValueList(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; - } - } - RefPtr rule = StyleRuleFontFace::create(createStyleProperties()); - clearProperties(); - processAndAddNewRuleToSourceTreeIfNeeded(); - return rule.release(); -} - -#if ENABLE(SHADOW_DOM) -PassRefPtr CSSParser::createHostRule(RuleList* rules) -{ - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr rule; - if (rules) - rule = StyleRuleHost::create(*rules); - else { - RuleList emptyRules; - rule = StyleRuleHost::create(emptyRules); - } - processAndAddNewRuleToSourceTreeIfNeeded(); - return rule.release(); -} -#endif - -void CSSParser::addNamespace(const AtomicString& prefix, const AtomicString& uri) -{ - if (!m_styleSheet || !m_allowNamespaceDeclarations) - return; - m_allowImportRules = false; - m_styleSheet->parserAddNamespace(prefix, uri); - if (prefix.isEmpty() && !uri.isNull()) - m_defaultNamespace = uri; -} - -QualifiedName CSSParser::determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName) -{ - if (!m_styleSheet) - return QualifiedName(prefix, localName, m_defaultNamespace); - return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(prefix)); -} - -void CSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector& specifiers) -{ - if (m_defaultNamespace != starAtom || specifiers.isCustomPseudoElement()) - rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true); -} - -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 (tag == anyQName()) - return; -#if ENABLE(VIDEO_TRACK) - if (specifiers.pseudoType() != CSSSelector::PseudoCue) -#endif - specifiers.prependTagSelector(tag, tagIsForNamespaceRule); - return; - } - - CSSParserSelector* lastShadowDescendant = &specifiers; - CSSParserSelector* history = &specifiers; - while (history->tagHistory()) { - history = history->tagHistory(); - if (history->isCustomPseudoElement() || history->hasShadowDescendant()) - lastShadowDescendant = history; - } - - if (lastShadowDescendant->tagHistory()) { - if (tag != anyQName()) - lastShadowDescendant->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule); - 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. '*'). - lastShadowDescendant->setTagHistory(adoptPtr(new CSSParserSelector(tag))); - lastShadowDescendant->setRelation(CSSSelector::ShadowDescendant); -} - -OwnPtr CSSParser::rewriteSpecifiers(OwnPtr specifiers, OwnPtr newSpecifier) -{ -#if ENABLE(VIDEO_TRACK) - if (newSpecifier->isCustomPseudoElement() || newSpecifier->pseudoType() == CSSSelector::PseudoCue) { -#else - if (newSpecifier->isCustomPseudoElement()) { -#endif - // Unknown pseudo element always goes at the top of selector chain. - newSpecifier->appendTagHistory(CSSSelector::ShadowDescendant, specifiers.release()); - return newSpecifier; - } - if (specifiers->isCustomPseudoElement()) { - // Specifiers for unknown pseudo element go right behind it in the chain. - specifiers->insertTagHistory(CSSSelector::SubSelector, newSpecifier.release(), CSSSelector::ShadowDescendant); - return specifiers; - } - specifiers->appendTagHistory(CSSSelector::SubSelector, newSpecifier.release()); - return specifiers; -} - -PassRefPtr CSSParser::createPageRule(PassOwnPtr pageSelector) -{ - // FIXME: Margin at-rules are ignored. - m_allowImportRules = m_allowNamespaceDeclarations = false; - RefPtr rule; - if (pageSelector) { - rule = StyleRulePage::create(createStyleProperties()); - Vector> selectorVector; - selectorVector.append(pageSelector); - rule->parserAdoptSelectorVector(selectorVector); - processAndAddNewRuleToSourceTreeIfNeeded(); - } else - popRuleData(); - clearProperties(); - return rule.release(); -} - -OwnPtr>> CSSParser::createSelectorVector() -{ - if (m_recycledSelectorVector) { - m_recycledSelectorVector->shrink(0); - return std::move(m_recycledSelectorVector); - } - return adoptPtr(new Vector>); -} - -void CSSParser::recycleSelectorVector(OwnPtr>> vector) -{ - if (vector && !m_recycledSelectorVector) - m_recycledSelectorVector = std::move(vector); -} - -PassRefPtr CSSParser::createRegionRule(Vector>* regionSelector, RuleList* rules) -{ - if (!cssRegionsEnabled() || !regionSelector || !rules) { - popRuleData(); - return 0; - } - - m_allowImportRules = m_allowNamespaceDeclarations = false; - - RefPtr regionRule = StyleRuleRegion::create(regionSelector, *rules); - - if (isExtractingSourceData()) - addNewRuleToSourceTree(CSSRuleSourceData::createUnknown()); - - return regionRule.release(); -} - -void CSSParser::createMarginAtRule(CSSSelector::MarginBoxType /* marginBox */) -{ - // FIXME: Implement margin at-rule here, using: - // - marginBox: margin box - // - m_parsedProperties: properties at [m_numParsedPropertiesBeforeMarginBox, m_parsedProperties.size()] are for this at-rule. - // 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(); -} - -void CSSParser::startDeclarationsForMarginBox() -{ - m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size(); -} - -void CSSParser::endDeclarationsForMarginBox() -{ - rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox); - 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; - } -} - -PassRefPtr CSSParser::createKeyframe(CSSParserValueList& keys) -{ - // Create a key string from the passed keys - StringBuilder keyString; - 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) { - clearProperties(); - return 0; - } - - ASSERT(keys.valueAt(i)->unit == CSSPrimitiveValue::CSS_NUMBER); - float key = static_cast(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; - } - if (i != 0) - keyString.append(','); - keyString.appendNumber(key); - keyString.append('%'); - } - - RefPtr keyframe = StyleKeyframe::create(createStyleProperties()); - keyframe->setKeyText(keyString.toString()); - - clearProperties(); - - return keyframe.release(); -} - -void CSSParser::invalidBlockHit() -{ - if (m_styleSheet && !m_hadSyntacticallyValidCSSRule) - m_styleSheet->setHasSyntacticallyValidCSSHeader(false); -} - -void CSSParser::updateLastSelectorLineAndPosition() -{ - m_lastSelectorLineNumber = m_lineNumber; -} - -void CSSParser::updateLastMediaLine(MediaQuerySet* media) -{ - media->setLastLine(m_lineNumber); -} - -template -static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData) -{ - Vector& propertyData = ruleData->styleSourceData->propertyData; - unsigned size = propertyData.size(); - if (!size) - return; - - unsigned styleStart = ruleData->ruleBodyRange.start; - CSSPropertySourceData* nextData = &(propertyData.at(0)); - for (unsigned i = 0; i < size; ++i) { - CSSPropertySourceData* currentData = nextData; - nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0; - - if (currentData->parsedOk) - continue; - if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';') - continue; - - unsigned propertyEndInStyleSheet; - if (!nextData) - propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1; - else - propertyEndInStyleSheet = styleStart + nextData->range.start - 1; - - while (isHTMLSpace(characters[propertyEndInStyleSheet])) - --propertyEndInStyleSheet; - - // propertyEndInStyleSheet points at the last property text character. - unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character. - if (currentData->range.end != newPropertyEnd) { - currentData->range.end = newPropertyEnd; - unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length(); - while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':') - ++valueStartInStyleSheet; - if (valueStartInStyleSheet < propertyEndInStyleSheet) - ++valueStartInStyleSheet; // Shift past the ':'. - while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet])) - ++valueStartInStyleSheet; - // Need to exclude the trailing ';' from the property value. - currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1)); - } - } -} - -void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData) -{ - if (!ruleData->styleSourceData) - return; - - if (is8BitSource()) { - fixUnparsedProperties(m_dataStart8.get() + m_parsedTextPrefixLength, ruleData); - return; - } - - fixUnparsedProperties(m_dataStart16.get() + m_parsedTextPrefixLength, ruleData); -} - -void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType) -{ - if (!isExtractingSourceData()) - return; - - // Pop off data for a previous invalid rule. - if (m_currentRuleData) - m_currentRuleDataStack->removeLast(); - - RefPtr data = CSSRuleSourceData::create(ruleType); - data->ruleHeaderRange.start = tokenStartOffset(); - m_currentRuleData = data; - m_currentRuleDataStack->append(data.release()); -} - -template -inline void CSSParser::setRuleHeaderEnd(const CharacterType* dataStart) -{ - CharacterType* listEnd = tokenStart(); - while (listEnd > dataStart + 1) { - if (isHTMLSpace(*(listEnd - 1))) - --listEnd; - else - break; - } - - m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - dataStart; -} - -void CSSParser::markRuleHeaderEnd() -{ - if (!isExtractingSourceData()) - return; - ASSERT(!m_currentRuleDataStack->isEmpty()); - - if (is8BitSource()) - setRuleHeaderEnd(m_dataStart8.get()); - else - setRuleHeaderEnd(m_dataStart16.get()); -} - -void CSSParser::markSelectorStart() -{ - if (!isExtractingSourceData()) - return; - ASSERT(!m_selectorRange.end); - - m_selectorRange.start = tokenStartOffset(); -} - -void CSSParser::markSelectorEnd() -{ - if (!isExtractingSourceData()) - return; - ASSERT(!m_selectorRange.end); - ASSERT(m_currentRuleDataStack->size()); - - m_selectorRange.end = tokenStartOffset(); - m_currentRuleDataStack->last()->selectorRanges.append(m_selectorRange); - m_selectorRange.start = 0; - m_selectorRange.end = 0; -} - -void CSSParser::markRuleBodyStart() -{ - if (!isExtractingSourceData()) - return; - m_currentRuleData.clear(); - unsigned offset = tokenStartOffset(); - if (tokenStartChar() == '{') - ++offset; // Skip the rule body opening brace. - ASSERT(!m_currentRuleDataStack->isEmpty()); - m_currentRuleDataStack->last()->ruleBodyRange.start = offset; -} - -void CSSParser::markRuleBodyEnd() -{ - // Precondition: (!isExtractingSourceData()) - unsigned offset = tokenStartOffset(); - ASSERT(!m_currentRuleDataStack->isEmpty()); - m_currentRuleDataStack->last()->ruleBodyRange.end = offset; -} - -void CSSParser::markPropertyStart() -{ - m_ignoreErrorsInDeclaration = false; - if (!isExtractingSourceData()) - return; - if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData) - return; - - m_propertyRange.start = tokenStartOffset(); -} - -void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) -{ - if (!isExtractingSourceData()) - return; - if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData) - return; - - unsigned offset = tokenStartOffset(); - if (tokenStartChar() == ';') // Include semicolon into the property text. - ++offset; - m_propertyRange.end = offset; - if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) { - // 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_WITH_SECURITY_IMPLICATION(start < end); - String propertyString; - if (is8BitSource()) - propertyString = String(m_dataStart8.get() + start, end - start).stripWhiteSpace(); - else - propertyString = String(m_dataStart16.get() + start, end - start).stripWhiteSpace(); - if (propertyString.endsWith(';')) - propertyString = propertyString.left(propertyString.length() - 1); - size_t colonIndex = propertyString.find(':'); - ASSERT(colonIndex != notFound); - - String name = propertyString.left(colonIndex).stripWhiteSpace(); - String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace(); - // The property range is relative to the declaration start offset. - SourceRange& topRuleBodyRange = m_currentRuleDataStack->last()->ruleBodyRange; - m_currentRuleDataStack->last()->styleSourceData->propertyData.append( - CSSPropertySourceData(name, value, isImportantFound, isPropertyParsed, SourceRange(start - topRuleBodyRange.start, end - topRuleBodyRange.start))); - } - resetPropertyRange(); -} - -#if ENABLE(CSS_DEVICE_ADAPTATION) -PassRefPtr CSSParser::createViewportRule() -{ - m_allowImportRules = m_allowNamespaceDeclarations = false; - - RefPtr rule = StyleRuleViewport::create(createStyleProperties()); - clearProperties(); - - processAndAddNewRuleToSourceTreeIfNeeded(); - - return rule.release(); -} - -bool CSSParser::parseViewportProperty(CSSPropertyID propId, bool important) -{ - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - CSSValueID id = value->id; - bool validPrimitive = false; - - switch (propId) { - case CSSPropertyMinWidth: // auto | device-width | device-height | | - case CSSPropertyMaxWidth: - case CSSPropertyMinHeight: - case CSSPropertyMaxHeight: - if (id == CSSValueAuto || id == CSSValueDeviceWidth || id == CSSValueDeviceHeight) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg)); - break; - case CSSPropertyWidth: // shorthand - return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMaxWidth, important); - case CSSPropertyHeight: - return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyMaxHeight, important); - case CSSPropertyMinZoom: // auto | | - case CSSPropertyMaxZoom: - case CSSPropertyZoom: - if (id == CSSValueAuto) - validPrimitive = true; - else - validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg)); - break; - case CSSPropertyUserZoom: // zoom | fixed - if (id == CSSValueZoom || id == CSSValueFixed) - validPrimitive = true; - break; - case CSSPropertyOrientation: // auto | portrait | landscape - if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandscape) - validPrimitive = true; - default: - break; - } - - RefPtr parsedValue; - if (validPrimitive) { - parsedValue = parseValidPrimitive(id, value); - m_valueList->next(); - } - - if (parsedValue) { - if (!m_valueList->current() || inShorthand()) { - addProperty(propId, parsedValue.release(), important); - return true; - } - } - - return false; -} - -bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important) -{ - unsigned numValues = m_valueList->size(); - - if (numValues > 2) - return false; - - ShorthandScope scope(this, propId); - - if (!parseViewportProperty(first, important)) - return false; - - // If just one value is supplied, the second value - // is implicitly initialized with the first value. - if (numValues == 1) - m_valueList->previous(); - - return parseViewportProperty(second, important); -} -#endif - -template -static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length) -{ - char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character - - for (unsigned i = 0; i != length; ++i) { - CharacterType c = propertyName[i]; - if (c == 0 || c >= 0x7F) - return CSSPropertyInvalid; // illegal character - buffer[i] = toASCIILower(c); - } - buffer[length] = '\0'; - - const char* name = buffer; - if (buffer[0] == '-') { -#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::sharedFeatures().legacyCSSVendorPrefixesEnabled() - && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) { - memmove(buffer + 7, buffer + 6, length + 1 - 6); - memcpy(buffer, "-webkit", 7); - ++length; - } -#endif -#if PLATFORM(IOS) - cssPropertyNameIOSAliasing(buffer, name, length); -#endif - } - - const Property* hashTableEntry = findProperty(name, length); - const CSSPropertyID propertyID = hashTableEntry ? static_cast(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; -} - -CSSPropertyID cssPropertyID(const String& string) -{ - unsigned length = string.length(); - - if (!length) - return CSSPropertyInvalid; - if (length > maxCSSPropertyNameLength) - return CSSPropertyInvalid; - - return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length); -} - -CSSPropertyID cssPropertyID(const CSSParserString& string) -{ - unsigned length = string.length(); - - if (!length) - return CSSPropertyInvalid; - if (length > maxCSSPropertyNameLength) - return CSSPropertyInvalid; - - return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length); -} - -#if PLATFORM(IOS) -void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength) -{ - if (!strcmp(propertyName, "-webkit-hyphenate-locale")) { - // Worked in iOS 4.2. - static const char* const webkitLocale = "-webkit-locale"; - propertyNameAlias = webkitLocale; - newLength = strlen(webkitLocale); - } -} -#endif - -template -static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length) -{ - char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character - - for (unsigned i = 0; i != length; ++i) { - CharacterType c = valueKeyword[i]; - if (c == 0 || c >= 0x7F) - return CSSValueInvalid; // illegal keyword. - buffer[i] = WTF::toASCIILower(c); - } - buffer[length] = '\0'; - - if (buffer[0] == '-') { - // If the prefix is -apple- or -khtml-, change it to -webkit-. - // This makes the string one character longer. - // On iOS we don't want to change values starting with -apple-system to -webkit-system. - if ((hasPrefix(buffer, length, "-apple-") && !hasPrefix(buffer, length, "-apple-system")) || hasPrefix(buffer, length, "-khtml-")) { - memmove(buffer + 7, buffer + 6, length + 1 - 6); - memcpy(buffer, "-webkit", 7); - ++length; - } - } - - const Value* hashTableEntry = findValue(buffer, length); - return hashTableEntry ? static_cast(hashTableEntry->id) : CSSValueInvalid; -} - -CSSValueID cssValueKeywordID(const CSSParserString& string) -{ - unsigned length = string.length(); - if (!length) - return CSSValueInvalid; - if (length > maxCSSValueKeywordLength) - return CSSValueInvalid; - - return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length); -} - -template -static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length) -{ - const CharacterType* end = characters + length; - - // -? - if (characters != end && characters[0] == '-') - ++characters; - - // {nmstart} - if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0]))) - return false; - ++characters; - - // {nmchar}* - for (; characters != end; ++characters) { - if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0]))) - return false; - } - - return true; -} - -// "ident" from the CSS tokenizer, minus backslash-escape sequences -static bool isCSSTokenizerIdentifier(const String& string) -{ - unsigned length = string.length(); - - if (!length) - return false; - - if (string.is8Bit()) - return isCSSTokenizerIdentifier(string.characters8(), length); - return isCSSTokenizerIdentifier(string.characters16(), length); -} - -template -static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length) -{ - const CharacterType* end = characters + length; - - for (; characters != end; ++characters) { - CharacterType c = characters[0]; - switch (c) { - case '!': - case '#': - case '$': - case '%': - case '&': - break; - default: - if (c < '*') - return false; - if (c <= '~') - break; - if (c < 128) - return false; - } - } - - return true; -} - -// "url" from the CSS tokenizer, minus backslash-escape sequences -static bool isCSSTokenizerURL(const String& string) -{ - unsigned length = string.length(); - - if (!length) - return true; - - if (string.is8Bit()) - return isCSSTokenizerURL(string.characters8(), length); - return isCSSTokenizerURL(string.characters16(), length); -} - - -template -static inline String quoteCSSStringInternal(const CharacterType* characters, unsigned length) -{ - // For efficiency, we first pre-calculate the length of the quoted string, then we build the actual one. - // Please see below for the actual logic. - unsigned quotedStringSize = 2; // Two quotes surrounding the entire string. - bool afterEscape = false; - for (unsigned i = 0; i < length; ++i) { - CharacterType ch = characters[i]; - if (ch == '\\' || ch == '\'') { - quotedStringSize += 2; - afterEscape = false; - } else if (ch < 0x20 || ch == 0x7F) { - quotedStringSize += 2 + (ch >= 0x10); - afterEscape = true; - } else { - quotedStringSize += 1 + (afterEscape && (isASCIIHexDigit(ch) || ch == ' ')); - afterEscape = false; - } - } - - StringBuffer buffer(quotedStringSize); - unsigned index = 0; - buffer[index++] = '\''; - afterEscape = false; - for (unsigned i = 0; i < length; ++i) { - CharacterType ch = characters[i]; - if (ch == '\\' || ch == '\'') { - buffer[index++] = '\\'; - buffer[index++] = ch; - afterEscape = false; - } else if (ch < 0x20 || ch == 0x7F) { // Control characters. - buffer[index++] = '\\'; - placeByteAsHexCompressIfPossible(ch, buffer, index, Lowercase); - afterEscape = true; - } else { - // Space character may be required to separate backslash-escape sequence and normal characters. - if (afterEscape && (isASCIIHexDigit(ch) || ch == ' ')) - buffer[index++] = ' '; - buffer[index++] = ch; - afterEscape = false; - } - } - buffer[index++] = '\''; - - ASSERT(quotedStringSize == index); - return String::adopt(buffer); -} - -// We use single quotes for now because markup.cpp uses double quotes. -String quoteCSSString(const String& string) -{ - // This function expands each character to at most 3 characters ('\u0010' -> '\' '1' '0') as well as adds - // 2 quote characters (before and after). Make sure the resulting size (3 * length + 2) will not overflow unsigned. - - unsigned length = string.length(); - - if (!length) - return String("\'\'"); - - if (length > std::numeric_limits::max() / 3 - 2) - return emptyString(); - - if (string.is8Bit()) - return quoteCSSStringInternal(string.characters8(), length); - return quoteCSSStringInternal(string.characters16(), length); -} - -String quoteCSSStringIfNeeded(const String& string) -{ - return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string); -} - -String quoteCSSURLIfNeeded(const String& string) -{ - return isCSSTokenizerURL(string) ? string : quoteCSSString(string); -} - -bool isValidNthToken(const CSSParserString& token) -{ - // The tokenizer checks for the construct of an+b. - // 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"); -} - -} diff --git a/Source/WebCore/css/CSSParser.h b/Source/WebCore/css/CSSParser.h deleted file mode 100644 index c7fd264e0..000000000 --- a/Source/WebCore/css/CSSParser.h +++ /dev/null @@ -1,693 +0,0 @@ -/* - * Copyright (C) 2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2008 Eric Seidel - * Copyright (C) 2009 - 2010 Torch Mobile (Beijing) Co. Ltd. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef CSSParser_h -#define CSSParser_h - -#include "CSSCalculationValue.h" -#include "CSSGradientValue.h" -#include "CSSParserMode.h" -#include "CSSParserValues.h" -#include "CSSProperty.h" -#include "CSSPropertyNames.h" -#include "CSSPropertySourceData.h" -#include "CSSValueKeywords.h" -#include "Color.h" -#include "MediaQuery.h" -#include -#include -#include -#include -#include - -#if ENABLE(CSS_FILTERS) -#include "WebKitCSSFilterValue.h" -#endif - -namespace WebCore { - -class AnimationParseContext; -class CSSBorderImageSliceValue; -class CSSPrimitiveValue; -class CSSSelectorList; -class CSSValue; -class CSSValueList; -class CSSBasicShape; -class CSSBasicShapeInset; -class Document; -class Element; -class ImmutableStyleProperties; -class MediaQueryExp; -class MediaQuerySet; -class MutableStyleProperties; -class StyleKeyframe; -class StylePropertyShorthand; -class StyleRuleBase; -class StyleRuleKeyframes; -class StyleKeyframe; -class StyleSheetContents; -class StyledElement; - -class CSSParser { - friend inline int cssyylex(void*, CSSParser*); - -public: - struct Location; - enum SyntaxErrorType { - PropertyDeclarationError, - GeneralSyntaxError - }; - - CSSParser(const CSSParserContext&); - - ~CSSParser(); - - void parseSheet(StyleSheetContents*, const String&, int startLineNumber = 0, RuleSourceDataList* = 0, bool = false); - PassRefPtr parseRule(StyleSheetContents*, const String&); - PassRefPtr parseKeyframeRule(StyleSheetContents*, const String&); -#if ENABLE(CSS3_CONDITIONAL_RULES) - bool parseSupportsCondition(const String&); -#endif - static bool parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, CSSParserMode, StyleSheetContents*); - static bool parseColor(RGBA32& color, const String&, bool strict = false); - static bool parseSystemColor(RGBA32& color, const String&, Document*); - static PassRefPtr parseFontFaceValue(const AtomicString&); - PassRefPtr parseValidPrimitive(CSSValueID ident, CSSParserValue*); - bool parseDeclaration(MutableStyleProperties*, const String&, PassRefPtr, StyleSheetContents* contextStyleSheet); - static PassRef parseInlineStyleDeclaration(const String&, Element*); - PassOwnPtr parseMediaQuery(const String&); - - void addPropertyWithPrefixingVariant(CSSPropertyID, PassRefPtr, bool important, bool implicit = false); - void addProperty(CSSPropertyID, PassRefPtr, bool important, bool implicit = false); - void rollbackLastProperties(int num); - bool hasProperties() const { return !m_parsedProperties.isEmpty(); } - void addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr, bool); - - bool parseValue(CSSPropertyID, bool important); - bool parseShorthand(CSSPropertyID, const StylePropertyShorthand&, bool important); - bool parse4Values(CSSPropertyID, const CSSPropertyID* properties, bool important); - bool parseContent(CSSPropertyID, bool important); - bool parseQuotes(CSSPropertyID, bool important); - bool parseAlt(CSSPropertyID, bool important); - - PassRefPtr parseAttr(CSSParserValueList* args); - - PassRefPtr parseBackgroundColor(); - - bool parseFillImage(CSSParserValueList*, RefPtr&); - - enum FillPositionFlag { InvalidFillPosition = 0, AmbiguousFillPosition = 1, XFillPosition = 2, YFillPosition = 4 }; - enum FillPositionParsingMode { ResolveValuesAsPercent = 0, ResolveValuesAsKeyword = 1 }; - PassRefPtr parseFillPositionComponent(CSSParserValueList*, unsigned& cumulativeFlags, FillPositionFlag& individualFlag, FillPositionParsingMode = ResolveValuesAsPercent); - PassRefPtr parseFillPositionX(CSSParserValueList*); - PassRefPtr parseFillPositionY(CSSParserValueList*); - void parse2ValuesFillPosition(CSSParserValueList*, RefPtr&, RefPtr&); - bool isPotentialPositionValue(CSSParserValue*); - void parseFillPosition(CSSParserValueList*, RefPtr&, RefPtr&); - void parse3ValuesFillPosition(CSSParserValueList*, RefPtr&, RefPtr&, PassRefPtr, PassRefPtr); - void parse4ValuesFillPosition(CSSParserValueList*, RefPtr&, RefPtr&, PassRefPtr, PassRefPtr); - - void parseFillRepeat(RefPtr&, RefPtr&); - PassRefPtr parseFillSize(CSSPropertyID, bool &allowComma); - - bool parseFillProperty(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr&, RefPtr&); - bool parseFillShorthand(CSSPropertyID, const CSSPropertyID* properties, int numProperties, bool important); - - void addFillValue(RefPtr& lval, PassRefPtr rval); - - void addAnimationValue(RefPtr& lval, PassRefPtr rval); - - PassRefPtr parseAnimationDelay(); - PassRefPtr parseAnimationDirection(); - PassRefPtr parseAnimationDuration(); - PassRefPtr parseAnimationFillMode(); - PassRefPtr parseAnimationIterationCount(); - PassRefPtr parseAnimationName(); - PassRefPtr parseAnimationPlayState(); - PassRefPtr parseAnimationProperty(AnimationParseContext&); - PassRefPtr parseAnimationTimingFunction(); - - bool parseTransformOriginShorthand(RefPtr&, RefPtr&, RefPtr&); - bool parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result); - bool parseAnimationProperty(CSSPropertyID, RefPtr&, AnimationParseContext&); - bool parseTransitionShorthand(CSSPropertyID, bool important); - bool parseAnimationShorthand(bool important); - - bool cssGridLayoutEnabled() const; - PassRefPtr parseGridPosition(); - bool parseGridItemPositionShorthand(CSSPropertyID, bool important); - bool parseGridAreaShorthand(bool important); - bool parseSingleGridAreaLonghand(RefPtr&); - bool parseGridTrackList(CSSPropertyID, bool important); - bool parseGridTrackRepeatFunction(CSSValueList&); - PassRefPtr parseGridTrackSize(CSSParserValueList& inputList); - PassRefPtr parseGridBreadth(CSSParserValue*); - PassRefPtr parseGridTemplate(); - void parseGridTrackNames(CSSParserValueList& inputList, CSSValueList& values); - - bool parseDashboardRegions(CSSPropertyID, bool important); - - bool parseClipShape(CSSPropertyID, bool important); - -#if ENABLE(CSS_SHAPES) - PassRefPtr parseShapeProperty(CSSPropertyID); -#endif - - PassRefPtr parseBasicShapeAndOrBox(CSSPropertyID propId); - PassRefPtr parseBasicShape(); - PassRefPtr parseShapeRadius(CSSParserValue*); - PassRefPtr parseBasicShapeRectangle(CSSParserValueList*); - PassRefPtr parseBasicShapeCircle(CSSParserValueList*); - PassRefPtr parseDeprecatedBasicShapeCircle(CSSParserValueList*); - PassRefPtr parseBasicShapeEllipse(CSSParserValueList*); - PassRefPtr parseDeprecatedBasicShapeEllipse(CSSParserValueList*); - PassRefPtr parseBasicShapePolygon(CSSParserValueList*); - PassRefPtr parseBasicShapeInsetRectangle(CSSParserValueList*); - PassRefPtr parseBasicShapeInset(CSSParserValueList*); - - bool parseFont(bool important); - PassRefPtr parseFontFamily(); - - bool parseCounter(CSSPropertyID, int defaultValue, bool important); - PassRefPtr parseCounterContent(CSSParserValueList* args, bool counters); - - bool parseColorParameters(CSSParserValue*, int* colorValues, bool parseAlpha); - bool parseHSLParameters(CSSParserValue*, double* colorValues, bool parseAlpha); - PassRefPtr parseColor(CSSParserValue* = 0); - bool parseColorFromValue(CSSParserValue*, RGBA32&); - void parseSelector(const String&, CSSSelectorList&); - - template - static bool fastParseColor(RGBA32&, const StringType&, bool strict); - - bool parseLineHeight(bool important); - bool parseFontSize(bool important); - bool parseFontVariant(bool important); - bool parseFontWeight(bool important); - bool parseFontFaceSrc(); - bool parseFontFaceUnicodeRange(); - -#if ENABLE(SVG) - bool parseSVGValue(CSSPropertyID propId, bool important); - PassRefPtr parseSVGPaint(); - PassRefPtr parseSVGColor(); - PassRefPtr parseSVGStrokeDasharray(); -#endif - - // CSS3 Parsing Routines (for properties specific to CSS3) - PassRefPtr parseShadow(CSSParserValueList*, CSSPropertyID); - bool parseBorderImage(CSSPropertyID, RefPtr&, bool important = false); - bool parseBorderImageRepeat(RefPtr&); - bool parseBorderImageSlice(CSSPropertyID, RefPtr&); - bool parseBorderImageWidth(RefPtr&); - bool parseBorderImageOutset(RefPtr&); - bool parseBorderRadius(CSSPropertyID, bool important); - - bool parseAspectRatio(bool important); - - bool parseReflect(CSSPropertyID, bool important); - - bool parseFlex(CSSParserValueList* args, bool important); - - // Image generators - bool parseCanvas(CSSParserValueList*, RefPtr&); - - bool parseDeprecatedGradient(CSSParserValueList*, RefPtr&); - bool parseDeprecatedLinearGradient(CSSParserValueList*, RefPtr&, CSSGradientRepeat repeating); - bool parseDeprecatedRadialGradient(CSSParserValueList*, RefPtr&, CSSGradientRepeat repeating); - bool parseLinearGradient(CSSParserValueList*, RefPtr&, CSSGradientRepeat repeating); - bool parseRadialGradient(CSSParserValueList*, RefPtr&, CSSGradientRepeat repeating); - bool parseGradientColorStops(CSSParserValueList*, CSSGradientValue*, bool expectComma); - - bool parseCrossfade(CSSParserValueList*, RefPtr&); - -#if ENABLE(CSS_IMAGE_RESOLUTION) - PassRefPtr parseImageResolution(); -#endif - -#if ENABLE(CSS_IMAGE_SET) - PassRefPtr parseImageSet(); -#endif - -#if ENABLE(CSS_FILTERS) - bool parseFilterImage(CSSParserValueList*, RefPtr&); - - bool parseFilter(CSSParserValueList*, RefPtr&); - PassRefPtr parseBuiltinFilterArguments(CSSParserValueList*, WebKitCSSFilterValue::FilterOperationType); -#endif - - PassRefPtr parseClipPath(); - - static bool isBlendMode(CSSValueID); - static bool isCompositeOperator(CSSValueID); - - PassRefPtr parseTransform(); - PassRefPtr parseTransformValue(CSSParserValue*); - bool parseTransformOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, CSSPropertyID& propId3, RefPtr&, RefPtr&, RefPtr&); - bool parsePerspectiveOrigin(CSSPropertyID propId, CSSPropertyID& propId1, CSSPropertyID& propId2, RefPtr&, RefPtr&); - - bool parseTextEmphasisStyle(bool important); - bool parseTextEmphasisPosition(bool important); - - void addTextDecorationProperty(CSSPropertyID, PassRefPtr, bool important); - bool parseTextDecoration(CSSPropertyID propId, bool important); - bool parseTextDecorationSkip(bool important); - bool parseTextUnderlinePosition(bool important); - - PassRefPtr parseTextIndent(); - - bool parseLineBoxContain(bool important); - bool parseCalculation(CSSParserValue*, CalculationPermittedValueRange); - - bool parseFontFeatureTag(CSSValueList*); - bool parseFontFeatureSettings(bool important); - - bool cssRegionsEnabled() const; - bool cssCompositingEnabled() const; - bool parseFlowThread(CSSPropertyID, bool important); - bool parseRegionThread(CSSPropertyID, bool important); - - bool parseFontVariantLigatures(bool important); - - // Faster than doing a new/delete each time since it keeps one vector. - OwnPtr>> createSelectorVector(); - void recycleSelectorVector(OwnPtr>>); - - PassRefPtr createImportRule(const CSSParserString&, PassRefPtr); - PassRefPtr createKeyframe(CSSParserValueList&); - PassRefPtr createKeyframesRule(const String&, PassOwnPtr>>); - - typedef Vector> RuleList; - PassRefPtr createMediaRule(PassRefPtr, RuleList*); - PassRefPtr createEmptyMediaRule(RuleList*); - PassRefPtr createStyleRule(Vector>* selectors); - PassRefPtr createFontFaceRule(); - PassRefPtr createPageRule(PassOwnPtr pageSelector); - PassRefPtr createRegionRule(Vector>* regionSelector, RuleList* rules); - void createMarginAtRule(CSSSelector::MarginBoxType); -#if ENABLE(CSS3_CONDITIONAL_RULES) - PassRefPtr createSupportsRule(bool conditionIsSupported, RuleList*); - void markSupportsRuleHeaderStart(); - void markSupportsRuleHeaderEnd(); - PassRefPtr popSupportsRuleData(); -#endif -#if ENABLE(SHADOW_DOM) - PassRefPtr createHostRule(RuleList*); -#endif - - void startDeclarationsForMarginBox(); - void endDeclarationsForMarginBox(); - - void addNamespace(const AtomicString& prefix, const AtomicString& uri); - QualifiedName determineNameInNamespace(const AtomicString& prefix, const AtomicString& localName); - - void rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector&, bool isNamespacePlaceholder = false); - void rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector&); - OwnPtr rewriteSpecifiers(OwnPtr, OwnPtr); - - void invalidBlockHit(); - - void updateLastSelectorLineAndPosition(); - void updateLastMediaLine(MediaQuerySet*); - - void clearProperties(); - - PassRef createStyleProperties(); - - CSSParserContext m_context; - - bool m_important; - CSSPropertyID m_id; - StyleSheetContents* m_styleSheet; - RefPtr m_rule; - RefPtr m_keyframe; - OwnPtr m_mediaQuery; - OwnPtr m_valueList; -#if ENABLE(CSS3_CONDITIONAL_RULES) - bool m_supportsCondition; -#endif - - typedef Vector ParsedPropertyVector; - ParsedPropertyVector m_parsedProperties; - CSSSelectorList* m_selectorListForParseSelector; - - unsigned m_numParsedPropertiesBeforeMarginBox; - - int m_inParseShorthand; - CSSPropertyID m_currentShorthand; - bool m_implicitShorthand; - - bool m_hasFontFaceOnlyValues; - bool m_hadSyntacticallyValidCSSRule; - bool m_logErrors; - bool m_ignoreErrorsInDeclaration; - - AtomicString m_defaultNamespace; - - // tokenizer methods and data - size_t m_parsedTextPrefixLength; - SourceRange m_selectorRange; - SourceRange m_propertyRange; - OwnPtr m_currentRuleDataStack; - RefPtr m_currentRuleData; - RuleSourceDataList* m_ruleSourceDataResult; - - void fixUnparsedPropertyRanges(CSSRuleSourceData*); - void markRuleHeaderStart(CSSRuleSourceData::Type); - void markRuleHeaderEnd(); - void markSelectorStart(); - void markSelectorEnd(); - void markRuleBodyStart(); - void markRuleBodyEnd(); - void markPropertyStart(); - void markPropertyEnd(bool isImportantFound, bool isPropertyParsed); - void processAndAddNewRuleToSourceTreeIfNeeded(); - void addNewRuleToSourceTree(PassRefPtr); - PassRefPtr popRuleData(); - void resetPropertyRange() { m_propertyRange.start = m_propertyRange.end = UINT_MAX; } - bool isExtractingSourceData() const { return !!m_currentRuleDataStack; } - void syntaxError(const Location&, SyntaxErrorType = GeneralSyntaxError); - - inline int lex(void* yylval) { return (this->*m_lexFunc)(yylval); } - - int token() { return m_token; } - -#if ENABLE(CSS_DEVICE_ADAPTATION) - void markViewportRuleBodyStart() { m_inViewport = true; } - void markViewportRuleBodyEnd() { m_inViewport = false; } - PassRefPtr createViewportRule(); -#endif - - PassRefPtr createPrimitiveNumericValue(CSSParserValue*); - PassRefPtr createPrimitiveStringValue(CSSParserValue*); - - static URL completeURL(const CSSParserContext&, const String& url); - - Location currentLocation(); - -private: - bool is8BitSource() { return m_is8BitSource; } - - template - int realLex(void* yylval); - - UChar*& currentCharacter16(); - - template - inline CharacterType*& currentCharacter(); - - template - inline CharacterType* tokenStart(); - - template - inline void setTokenStart(CharacterType*); - - inline unsigned tokenStartOffset(); - inline UChar tokenStartChar(); - - template - inline bool isIdentifierStart(); - - template - unsigned parseEscape(CharacterType*&); - template - inline void UnicodeToChars(DestCharacterType*&, unsigned); - template - inline bool parseIdentifierInternal(SrcCharacterType*&, DestCharacterType*&, bool&); - - template - inline void parseIdentifier(CharacterType*&, CSSParserString&, bool&); - - template - inline bool parseStringInternal(SrcCharacterType*&, DestCharacterType*&, UChar); - - template - inline void parseString(CharacterType*&, CSSParserString& resultString, UChar); - - template - inline bool findURI(CharacterType*& start, CharacterType*& end, UChar& quote); - - template - inline bool parseURIInternal(SrcCharacterType*&, DestCharacterType*&, UChar quote); - - template - inline void parseURI(CSSParserString&); - template - inline bool parseUnicodeRange(); - template - bool parseNthChild(); - template - bool parseNthChildExtra(); - template - inline bool detectFunctionTypeToken(int); - template - inline void detectMediaQueryToken(int); - template - inline void detectNumberToken(CharacterType*, int); - template - inline void detectDashToken(int); - template - inline void detectAtToken(int, bool); -#if ENABLE(CSS3_CONDITIONAL_RULES) - template - inline void detectSupportsToken(int); -#endif - - template - inline void setRuleHeaderEnd(const CharacterType*); - - void setStyleSheet(StyleSheetContents* styleSheet) { m_styleSheet = styleSheet; } - - inline bool inStrictMode() const { return m_context.mode == CSSStrictMode || m_context.mode == SVGAttributeMode; } - inline bool inQuirksMode() const { return m_context.mode == CSSQuirksMode; } - - URL completeURL(const String& url) const; - - void recheckAtKeyword(const UChar* str, int len); - - template - inline void setupParser(const char (&prefix)[prefixLength], const String& string, const char (&suffix)[suffixLength]) - { - setupParser(prefix, prefixLength - 1, string, suffix, suffixLength - 1); - } - void setupParser(const char* prefix, unsigned prefixLength, const String&, const char* suffix, unsigned suffixLength); - bool inShorthand() const { return m_inParseShorthand; } - - bool validWidth(CSSParserValue*); - bool validHeight(CSSParserValue*); - - void deleteFontFaceOnlyValues(); - - bool isGeneratedImageValue(CSSParserValue*) const; - bool parseGeneratedImage(CSSParserValueList*, RefPtr&); - - bool parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, StyleSheetContents* contextStyleSheet); - PassRef parseDeclaration(const String&, StyleSheetContents* contextStyleSheet); - - PassRefPtr parseInsetRoundedCorners(PassRefPtr, CSSParserValueList*); - - enum SizeParameterType { - None, - Auto, - Length, - PageSize, - Orientation, - }; - - bool parsePage(CSSPropertyID propId, bool important); - bool parseSize(CSSPropertyID propId, bool important); - SizeParameterType parseSizeParameter(CSSValueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType); - - bool parseFontFaceSrcURI(CSSValueList*); - bool parseFontFaceSrcLocal(CSSValueList*); - - bool parseColor(const String&); - - bool parseIntegerOrStringFromGridPosition(RefPtr& numericValue, RefPtr& gridLineName); - - enum ParsingMode { - NormalMode, - MediaQueryMode, -#if ENABLE(CSS3_CONDITIONAL_RULES) - SupportsMode, -#endif - NthChildMode - }; - - ParsingMode m_parsingMode; - bool m_is8BitSource; - std::unique_ptr m_dataStart8; - std::unique_ptr m_dataStart16; - LChar* m_currentCharacter8; - UChar* m_currentCharacter16; - union { - LChar* ptr8; - UChar* ptr16; - } m_tokenStart; - unsigned m_length; - int m_token; - int m_lineNumber; - int m_tokenStartLineNumber; - int m_lastSelectorLineNumber; - - bool m_allowImportRules; - bool m_allowNamespaceDeclarations; - -#if ENABLE(CSS_DEVICE_ADAPTATION) - bool parseViewportProperty(CSSPropertyID propId, bool important); - bool parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first, CSSPropertyID second, bool important); - - bool inViewport() const { return m_inViewport; } - bool m_inViewport; -#endif - - bool useLegacyBackgroundSizeShorthandBehavior() const; - - int (CSSParser::*m_lexFunc)(void*); - - OwnPtr>> m_recycledSelectorVector; - - RefPtr m_parsedCalculation; - -#if ENABLE(CSS3_CONDITIONAL_RULES) - OwnPtr m_supportsRuleDataStack; -#endif - - // defines units allowed for a certain property, used in parseUnit - enum Units { - FUnknown = 0x0000, - FInteger = 0x0001, - FNumber = 0x0002, // Real Numbers - FPercent = 0x0004, - FLength = 0x0008, - FAngle = 0x0010, - FTime = 0x0020, - FFrequency = 0x0040, - FPositiveInteger = 0x0080, - FRelative = 0x0100, -#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - FResolution = 0x0200, -#endif - FNonNeg = 0x0400 - }; - - friend inline Units operator|(Units a, Units b) - { - return static_cast(static_cast(a) | static_cast(b)); - } - - enum ReleaseParsedCalcValueCondition { - ReleaseParsedCalcValue, - DoNotReleaseParsedCalcValue - }; - - bool isLoggingErrors(); - void logError(const String& message, int lineNumber); - - bool validCalculationUnit(CSSParserValue*, Units, ReleaseParsedCalcValueCondition releaseCalc = DoNotReleaseParsedCalcValue); - - bool shouldAcceptUnitLessValues(CSSParserValue*, Units, CSSParserMode); - - inline bool validUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc = DoNotReleaseParsedCalcValue) { return validUnit(value, unitflags, m_context.mode, releaseCalc); } - bool validUnit(CSSParserValue*, Units, CSSParserMode, ReleaseParsedCalcValueCondition releaseCalc = DoNotReleaseParsedCalcValue); - - bool parseBorderImageQuad(Units, RefPtr&); - int colorIntFromValue(CSSParserValue*); - double parsedDouble(CSSParserValue*, ReleaseParsedCalcValueCondition releaseCalc = DoNotReleaseParsedCalcValue); - bool isCalculation(CSSParserValue*); - - friend class TransformOperationInfo; -#if ENABLE(CSS_FILTERS) - friend class FilterOperationInfo; -#endif -}; - -CSSPropertyID cssPropertyID(const CSSParserString&); -CSSPropertyID cssPropertyID(const String&); -CSSValueID cssValueKeywordID(const CSSParserString&); -#if PLATFORM(IOS) -void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength); -#endif - -class ShorthandScope { - WTF_MAKE_FAST_ALLOCATED; -public: - ShorthandScope(CSSParser* parser, CSSPropertyID propId) : m_parser(parser) - { - if (!(m_parser->m_inParseShorthand++)) - m_parser->m_currentShorthand = propId; - } - ~ShorthandScope() - { - if (!(--m_parser->m_inParseShorthand)) - m_parser->m_currentShorthand = CSSPropertyInvalid; - } - -private: - CSSParser* m_parser; -}; - -struct CSSParser::Location { - int lineNumber; - CSSParserString token; -}; - -String quoteCSSString(const String&); -String quoteCSSStringIfNeeded(const String&); -String quoteCSSURLIfNeeded(const String&); - -bool isValidNthToken(const CSSParserString&); - -template <> -inline void CSSParser::setTokenStart(LChar* tokenStart) -{ - m_tokenStart.ptr8 = tokenStart; -} - -template <> -inline void CSSParser::setTokenStart(UChar* tokenStart) -{ - m_tokenStart.ptr16 = tokenStart; -} - -inline unsigned CSSParser::tokenStartOffset() -{ - if (is8BitSource()) - return m_tokenStart.ptr8 - m_dataStart8.get(); - return m_tokenStart.ptr16 - m_dataStart16.get(); -} - -inline UChar CSSParser::tokenStartChar() -{ - if (is8BitSource()) - return *m_tokenStart.ptr8; - return *m_tokenStart.ptr16; -} - -inline int cssyylex(void* yylval, CSSParser* parser) -{ - return parser->lex(yylval); -} - -} // namespace WebCore - -#endif // CSSParser_h diff --git a/Source/WebCore/css/CSSParserMode.h b/Source/WebCore/css/CSSParserMode.h deleted file mode 100644 index 02e0529f1..000000000 --- a/Source/WebCore/css/CSSParserMode.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CSSParserMode_h -#define CSSParserMode_h - -#include "URL.h" - -namespace WebCore { - -class Document; - -enum CSSParserMode { - CSSQuirksMode, - CSSStrictMode, - // SVG should always be in strict mode. For SVG attributes, the rules differ to strict sometimes. - SVGAttributeMode -}; - -inline CSSParserMode strictToCSSParserMode(bool inStrictMode) -{ - return inStrictMode ? CSSStrictMode : CSSQuirksMode; -} - -inline bool isStrictParserMode(CSSParserMode cssParserMode) -{ - return cssParserMode == CSSStrictMode || cssParserMode == SVGAttributeMode; -} - -struct CSSParserContext { - WTF_MAKE_FAST_ALLOCATED; -public: - CSSParserContext(CSSParserMode, const URL& baseURL = URL()); - CSSParserContext(Document&, const URL& baseURL = URL(), const String& charset = emptyString()); - - URL baseURL; - String charset; - CSSParserMode mode; - bool isHTMLDocument; - bool isCSSStickyPositionEnabled; - bool isCSSRegionsEnabled; - bool isCSSCompositingEnabled; - bool isCSSGridLayoutEnabled; - bool needsSiteSpecificQuirks; - bool enforcesCSSMIMETypeInNoQuirksMode; - bool useLegacyBackgroundSizeShorthandBehavior; -}; - -bool operator==(const CSSParserContext&, const CSSParserContext&); -inline bool operator!=(const CSSParserContext& a, const CSSParserContext& b) { return !(a == b); } - -const CSSParserContext& strictCSSParserContext(); - -}; - -#endif // CSSParserMode_h diff --git a/Source/WebCore/css/CSSParserValues.cpp b/Source/WebCore/css/CSSParserValues.cpp deleted file mode 100644 index 9b47d5b76..000000000 --- a/Source/WebCore/css/CSSParserValues.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2008 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "CSSParserValues.h" - -#include "CSSPrimitiveValue.h" -#include "CSSFunctionValue.h" -#include "CSSSelector.h" -#include "CSSSelectorList.h" - -namespace WebCore { - -using namespace WTF; - -void destroy(const CSSParserValue& value) -{ - if (value.unit == CSSParserValue::Function) - delete value.function; -} - -CSSParserValueList::~CSSParserValueList() -{ - for (size_t i = 0, size = m_values.size(); i < size; i++) - destroy(m_values[i]); -} - -void CSSParserValueList::addValue(const CSSParserValue& v) -{ - m_values.append(v); -} - -void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& v) -{ - m_values.insert(i, v); -} - -void CSSParserValueList::deleteValueAt(unsigned i) -{ - m_values.remove(i); -} - -void CSSParserValueList::extend(CSSParserValueList& valueList) -{ - for (unsigned int i = 0; i < valueList.size(); ++i) - m_values.append(*(valueList.valueAt(i))); -} - -PassRefPtr CSSParserValue::createCSSValue() -{ - RefPtr parsedValue; - if (id) - return CSSPrimitiveValue::createIdentifier(id); - - if (unit == CSSParserValue::Operator) { - RefPtr primitiveValue = CSSPrimitiveValue::createParserOperator(iValue); - primitiveValue->setPrimitiveType(CSSPrimitiveValue::CSS_PARSER_OPERATOR); - return primitiveValue.release(); - } - if (unit == CSSParserValue::Function) - return CSSFunctionValue::create(function); - if (unit >= CSSParserValue::Q_EMS) - return CSSPrimitiveValue::createAllowingMarginQuirk(fValue, CSSPrimitiveValue::CSS_EMS); - - CSSPrimitiveValue::UnitTypes primitiveUnit = static_cast(unit); - switch (primitiveUnit) { - case CSSPrimitiveValue::CSS_IDENT: - case CSSPrimitiveValue::CSS_PROPERTY_ID: - case CSSPrimitiveValue::CSS_VALUE_ID: - return CSSPrimitiveValue::create(string, CSSPrimitiveValue::CSS_PARSER_IDENTIFIER); - case CSSPrimitiveValue::CSS_NUMBER: - return CSSPrimitiveValue::create(fValue, isInt ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER); - case CSSPrimitiveValue::CSS_STRING: - case CSSPrimitiveValue::CSS_URI: - case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: - return CSSPrimitiveValue::create(string, primitiveUnit); - case CSSPrimitiveValue::CSS_PERCENTAGE: - case CSSPrimitiveValue::CSS_EMS: - case CSSPrimitiveValue::CSS_EXS: - case CSSPrimitiveValue::CSS_PX: - case CSSPrimitiveValue::CSS_CM: - case CSSPrimitiveValue::CSS_MM: - case CSSPrimitiveValue::CSS_IN: - case CSSPrimitiveValue::CSS_PT: - case CSSPrimitiveValue::CSS_PC: - case CSSPrimitiveValue::CSS_DEG: - case CSSPrimitiveValue::CSS_RAD: - case CSSPrimitiveValue::CSS_GRAD: - case CSSPrimitiveValue::CSS_MS: - case CSSPrimitiveValue::CSS_S: - case CSSPrimitiveValue::CSS_HZ: - case CSSPrimitiveValue::CSS_KHZ: - case CSSPrimitiveValue::CSS_VW: - case CSSPrimitiveValue::CSS_VH: - case CSSPrimitiveValue::CSS_VMIN: - case CSSPrimitiveValue::CSS_VMAX: - case CSSPrimitiveValue::CSS_TURN: - case CSSPrimitiveValue::CSS_REMS: - case CSSPrimitiveValue::CSS_CHS: - case CSSPrimitiveValue::CSS_FR: - return CSSPrimitiveValue::create(fValue, primitiveUnit); - case CSSPrimitiveValue::CSS_UNKNOWN: - case CSSPrimitiveValue::CSS_DIMENSION: - case CSSPrimitiveValue::CSS_ATTR: - case CSSPrimitiveValue::CSS_COUNTER: - case CSSPrimitiveValue::CSS_RECT: - case CSSPrimitiveValue::CSS_RGBCOLOR: - case CSSPrimitiveValue::CSS_DPPX: - case CSSPrimitiveValue::CSS_DPI: - case CSSPrimitiveValue::CSS_DPCM: - case CSSPrimitiveValue::CSS_PAIR: -#if ENABLE(DASHBOARD_SUPPORT) - case CSSPrimitiveValue::CSS_DASHBOARD_REGION: -#endif - case CSSPrimitiveValue::CSS_UNICODE_RANGE: - case CSSPrimitiveValue::CSS_PARSER_OPERATOR: - case CSSPrimitiveValue::CSS_PARSER_INTEGER: - case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: - case CSSPrimitiveValue::CSS_COUNTER_NAME: - case CSSPrimitiveValue::CSS_SHAPE: - case CSSPrimitiveValue::CSS_QUAD: - case CSSPrimitiveValue::CSS_CALC: - case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: - case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: - return 0; - } - - ASSERT_NOT_REACHED(); - return 0; -} - -CSSParserSelector::CSSParserSelector() - : m_selector(adoptPtr(new CSSSelector)) -{ -} - -CSSParserSelector::CSSParserSelector(const QualifiedName& tagQName) - : m_selector(adoptPtr(new CSSSelector(tagQName))) -{ -} - -CSSParserSelector::~CSSParserSelector() -{ - if (!m_tagHistory) - return; - Vector, 16> toDelete; - OwnPtr selector = m_tagHistory.release(); - while (true) { - OwnPtr next = selector->m_tagHistory.release(); - toDelete.append(selector.release()); - if (!next) - break; - selector = next.release(); - } -} - -void CSSParserSelector::adoptSelectorVector(Vector>& selectorVector) -{ - OwnPtr selectorList = adoptPtr(new CSSSelectorList); - selectorList->adoptSelectorVector(selectorVector); - m_selector->setSelectorList(selectorList.release()); -} - -bool CSSParserSelector::isSimple() const -{ - if (m_selector->selectorList() || m_selector->matchesPseudoElement()) - return false; - - if (!m_tagHistory) - return true; - - if (m_selector->m_match == CSSSelector::Tag) { - // We can't check against anyQName() here because namespace may not be nullAtom. - // Example: - // @namespace "http://www.w3.org/2000/svg"; - // svg:not(:root) { ... - if (m_selector->tagQName().localName() == starAtom) - return m_tagHistory->isSimple(); - } - - return false; -} - -void CSSParserSelector::insertTagHistory(CSSSelector::Relation before, PassOwnPtr selector, CSSSelector::Relation after) -{ - if (m_tagHistory) - selector->setTagHistory(m_tagHistory.release()); - setRelation(before); - selector->setRelation(after); - m_tagHistory = selector; -} - -void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr selector) -{ - CSSParserSelector* end = this; - while (end->tagHistory()) - end = end->tagHistory(); - end->setRelation(relation); - end->setTagHistory(selector); -} - -void CSSParserSelector::prependTagSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule) -{ - OwnPtr second = adoptPtr(new CSSParserSelector); - second->m_selector = m_selector.release(); - second->m_tagHistory = m_tagHistory.release(); - m_tagHistory = second.release(); - - m_selector = adoptPtr(new CSSSelector(tagQName, tagIsForNamespaceRule)); - m_selector->m_relation = CSSSelector::SubSelector; -} - -} - diff --git a/Source/WebCore/css/CSSParserValues.h b/Source/WebCore/css/CSSParserValues.h deleted file mode 100644 index 233b8c2cc..000000000 --- a/Source/WebCore/css/CSSParserValues.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef CSSParserValues_h -#define CSSParserValues_h - -#include "CSSSelector.h" -#include "CSSValueKeywords.h" -#include "CSSValueList.h" -#include -#include - -namespace WebCore { - -class CSSValue; -class QualifiedName; - -struct CSSParserString { - void init(LChar* characters, unsigned length) - { - m_data.characters8 = characters; - m_length = length; - m_is8Bit = true; - } - - void init(UChar* characters, unsigned length) - { - m_data.characters16 = characters; - m_length = length; - m_is8Bit = false; - } - - void init(const String& string) - { - m_length = string.length(); - if (!m_length || string.is8Bit()) { - m_data.characters8 = const_cast(string.characters8()); - m_is8Bit = true; - } else { - m_data.characters16 = const_cast(string.characters16()); - m_is8Bit = false; - } - } - - void clear() - { - m_data.characters8 = 0; - m_length = 0; - m_is8Bit = true; - } - - bool is8Bit() const { return m_is8Bit; } - LChar* characters8() const { ASSERT(is8Bit()); return m_data.characters8; } - UChar* characters16() const { ASSERT(!is8Bit()); return m_data.characters16; } - template - CharacterType* characters() const; - - unsigned length() const { return m_length; } - void setLength(unsigned length) { m_length = length; } - - void lower(); - - UChar operator[](unsigned i) const - { - ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); - if (is8Bit()) - return m_data.characters8[i]; - return m_data.characters16[i]; - } - - bool equalIgnoringCase(const char* str) const - { - if (is8Bit()) - return WTF::equalIgnoringCase(str, characters8(), length()); - return WTF::equalIgnoringCase(str, characters16(), length()); - } - - operator String() const { return is8Bit() ? String(m_data.characters8, m_length) : String(m_data.characters16, m_length); } - operator AtomicString() const { return is8Bit() ? AtomicString(m_data.characters8, m_length) : AtomicString(m_data.characters16, m_length); } - - union { - LChar* characters8; - UChar* characters16; - } m_data; - unsigned m_length; - bool m_is8Bit; -}; - -struct CSSParserFunction; - -struct CSSParserValue { - CSSValueID id; - bool isInt; - union { - double fValue; - int iValue; - CSSParserString string; - CSSParserFunction* function; - }; - enum { - Operator = 0x100000, - Function = 0x100001, - Q_EMS = 0x100002 - }; - int unit; - - PassRefPtr createCSSValue(); -}; - -void destroy(const CSSParserValue&); - -class CSSParserValueList { - WTF_MAKE_FAST_ALLOCATED; -public: - CSSParserValueList() - : m_current(0) - { - } - ~CSSParserValueList(); - - void addValue(const CSSParserValue&); - void insertValueAt(unsigned, const CSSParserValue&); - void deleteValueAt(unsigned); - void extend(CSSParserValueList&); - - unsigned size() const { return m_values.size(); } - unsigned currentIndex() { return m_current; } - CSSParserValue* current() { return m_current < m_values.size() ? &m_values[m_current] : 0; } - CSSParserValue* next() { ++m_current; return current(); } - CSSParserValue* previous() - { - if (!m_current) - return 0; - --m_current; - return current(); - } - - CSSParserValue* valueAt(unsigned i) { return i < m_values.size() ? &m_values[i] : 0; } - - void clear() { m_values.clear(); } - -private: - unsigned m_current; - Vector m_values; -}; - -struct CSSParserFunction { - WTF_MAKE_FAST_ALLOCATED; -public: - CSSParserString name; - OwnPtr args; -}; - -class CSSParserSelector { - WTF_MAKE_FAST_ALLOCATED; -public: - CSSParserSelector(); - explicit CSSParserSelector(const QualifiedName&); - ~CSSParserSelector(); - - PassOwnPtr releaseSelector() { return m_selector.release(); } - - void setValue(const AtomicString& value) { m_selector->setValue(value); } - void setAttribute(const QualifiedName& value, bool isCaseInsensitive) { m_selector->setAttribute(value, isCaseInsensitive); } - void setArgument(const AtomicString& value) { m_selector->setArgument(value); } - void setMatch(CSSSelector::Match value) { m_selector->m_match = value; } - void setRelation(CSSSelector::Relation value) { m_selector->m_relation = value; } - void setForPage() { m_selector->setForPage(); } - - void adoptSelectorVector(Vector>& selectorVector); - - CSSSelector::PseudoType pseudoType() const { return m_selector->pseudoType(); } - bool isCustomPseudoElement() const { return m_selector->isCustomPseudoElement(); } - - bool isSimple() const; - bool hasShadowDescendant() const; - - CSSParserSelector* tagHistory() const { return m_tagHistory.get(); } - void setTagHistory(PassOwnPtr selector) { m_tagHistory = selector; } - void clearTagHistory() { m_tagHistory.clear(); } - void insertTagHistory(CSSSelector::Relation before, PassOwnPtr, CSSSelector::Relation after); - void appendTagHistory(CSSSelector::Relation, PassOwnPtr); - void prependTagSelector(const QualifiedName&, bool tagIsForNamespaceRule = false); - -private: - OwnPtr m_selector; - OwnPtr m_tagHistory; -}; - -inline bool CSSParserSelector::hasShadowDescendant() const -{ - return m_selector->relation() == CSSSelector::ShadowDescendant; -} - -} - -#endif diff --git a/Source/WebCore/css/CSSPendingSubstitutionValue.cpp b/Source/WebCore/css/CSSPendingSubstitutionValue.cpp new file mode 100644 index 000000000..2d9a077cf --- /dev/null +++ b/Source/WebCore/css/CSSPendingSubstitutionValue.cpp @@ -0,0 +1,40 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "CSSPendingSubstitutionValue.h" + +namespace WebCore { + +String CSSPendingSubstitutionValue::customCSSText() const +{ + return ""; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSPendingSubstitutionValue.h b/Source/WebCore/css/CSSPendingSubstitutionValue.h new file mode 100644 index 000000000..be845abe1 --- /dev/null +++ b/Source/WebCore/css/CSSPendingSubstitutionValue.h @@ -0,0 +1,73 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "CSSPropertyNames.h" +#include "CSSValue.h" +#include "CSSVariableReferenceValue.h" + +namespace WebCore { + +class CSSPendingSubstitutionValue : public CSSValue { +public: + static Ref create(CSSPropertyID shorthandPropertyId, Ref&& shorthandValue) + { + return adoptRef(*new CSSPendingSubstitutionValue(shorthandPropertyId, WTFMove(shorthandValue))); + } + + CSSVariableReferenceValue* shorthandValue() const + { + return m_shorthandValue.get(); + } + + CSSPropertyID shorthandPropertyId() const + { + return m_shorthandPropertyId; + } + + bool equals(const CSSPendingSubstitutionValue& other) const { return m_shorthandValue == other.m_shorthandValue; } + String customCSSText() const; + +private: + CSSPendingSubstitutionValue(CSSPropertyID shorthandPropertyId, Ref&& shorthandValue) + : CSSValue(PendingSubstitutionValueClass) + , m_shorthandPropertyId(shorthandPropertyId) + , m_shorthandValue(WTFMove(shorthandValue)) + { + } + + CSSPropertyID m_shorthandPropertyId; + RefPtr m_shorthandValue; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSPendingSubstitutionValue, isPendingSubstitutionValue()) + diff --git a/Source/WebCore/css/CSSPrimitiveValue.cpp b/Source/WebCore/css/CSSPrimitiveValue.cpp index 1492d25a3..482fd3da8 100644 --- a/Source/WebCore/css/CSSPrimitiveValue.cpp +++ b/Source/WebCore/css/CSSPrimitiveValue.cpp @@ -23,15 +23,20 @@ #include "CSSBasicShapes.h" #include "CSSCalculationValue.h" +#include "CSSFontFamily.h" #include "CSSHelper.h" -#include "CSSParser.h" +#include "CSSMarkup.h" +#include "CSSParserSelector.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSPropertyNames.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" #include "CalculationValue.h" #include "Color.h" #include "Counter.h" +#include "DeprecatedCSSOMPrimitiveValue.h" #include "ExceptionCode.h" -#include "Font.h" +#include "FontCascade.h" #include "Node.h" #include "Pair.h" #include "RGBColor.h" @@ -40,6 +45,7 @@ #include "StyleSheetContents.h" #include #include +#include #include #include #include @@ -52,22 +58,20 @@ using namespace WTF; namespace WebCore { -static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitTypes unitType) +static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitType unitType) { switch (unitType) { case CSSPrimitiveValue::CSS_CALC: - case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: + case CSSPrimitiveValue::CSS_CHS: case CSSPrimitiveValue::CSS_CM: case CSSPrimitiveValue::CSS_DEG: case CSSPrimitiveValue::CSS_DIMENSION: -#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - case CSSPrimitiveValue::CSS_DPPX: - case CSSPrimitiveValue::CSS_DPI: - case CSSPrimitiveValue::CSS_DPCM: -#endif case CSSPrimitiveValue::CSS_EMS: + case CSSPrimitiveValue::CSS_QUIRKY_EMS: case CSSPrimitiveValue::CSS_EXS: + case CSSPrimitiveValue::CSS_FR: case CSSPrimitiveValue::CSS_GRAD: case CSSPrimitiveValue::CSS_HZ: case CSSPrimitiveValue::CSS_IN: @@ -75,48 +79,111 @@ static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::Unit case CSSPrimitiveValue::CSS_MM: case CSSPrimitiveValue::CSS_MS: case CSSPrimitiveValue::CSS_NUMBER: - case CSSPrimitiveValue::CSS_PERCENTAGE: case CSSPrimitiveValue::CSS_PC: + case CSSPrimitiveValue::CSS_PERCENTAGE: case CSSPrimitiveValue::CSS_PT: case CSSPrimitiveValue::CSS_PX: case CSSPrimitiveValue::CSS_RAD: case CSSPrimitiveValue::CSS_REMS: - case CSSPrimitiveValue::CSS_CHS: case CSSPrimitiveValue::CSS_S: case CSSPrimitiveValue::CSS_TURN: - case CSSPrimitiveValue::CSS_VW: case CSSPrimitiveValue::CSS_VH: - case CSSPrimitiveValue::CSS_VMIN: case CSSPrimitiveValue::CSS_VMAX: - case CSSPrimitiveValue::CSS_FR: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VW: return true; + case CSSPrimitiveValue::CSS_DPCM: + case CSSPrimitiveValue::CSS_DPI: + case CSSPrimitiveValue::CSS_DPPX: +#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) + return true; +#else + return false; +#endif case CSSPrimitiveValue::CSS_ATTR: case CSSPrimitiveValue::CSS_COUNTER: case CSSPrimitiveValue::CSS_COUNTER_NAME: + case CSSPrimitiveValue::CSS_FONT_FAMILY: + case CSSPrimitiveValue::CSS_IDENT: + case CSSPrimitiveValue::CSS_PAIR: + case CSSPrimitiveValue::CSS_PROPERTY_ID: + case CSSPrimitiveValue::CSS_QUAD: + case CSSPrimitiveValue::CSS_RECT: + case CSSPrimitiveValue::CSS_RGBCOLOR: + case CSSPrimitiveValue::CSS_SHAPE: + case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_UNICODE_RANGE: + case CSSPrimitiveValue::CSS_UNKNOWN: + case CSSPrimitiveValue::CSS_URI: + case CSSPrimitiveValue::CSS_VALUE_ID: #if ENABLE(DASHBOARD_SUPPORT) case CSSPrimitiveValue::CSS_DASHBOARD_REGION: #endif -#if !ENABLE(CSS_IMAGE_RESOLUTION) && !ENABLE(RESOLUTION_MEDIA_QUERY) - case CSSPrimitiveValue::CSS_DPPX: - case CSSPrimitiveValue::CSS_DPI: + return false; + } + + ASSERT_NOT_REACHED(); + return false; +} + +#if !ASSERT_DISABLED + +static inline bool isStringType(CSSPrimitiveValue::UnitType type) +{ + switch (type) { + case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_URI: + case CSSPrimitiveValue::CSS_ATTR: + case CSSPrimitiveValue::CSS_COUNTER_NAME: + case CSSPrimitiveValue::CSS_DIMENSION: + return true; + case CSSPrimitiveValue::CSS_CALC: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: + case CSSPrimitiveValue::CSS_CHS: + case CSSPrimitiveValue::CSS_CM: + case CSSPrimitiveValue::CSS_COUNTER: + case CSSPrimitiveValue::CSS_DEG: case CSSPrimitiveValue::CSS_DPCM: -#endif + case CSSPrimitiveValue::CSS_DPI: + case CSSPrimitiveValue::CSS_DPPX: + case CSSPrimitiveValue::CSS_EMS: + case CSSPrimitiveValue::CSS_QUIRKY_EMS: + case CSSPrimitiveValue::CSS_EXS: + case CSSPrimitiveValue::CSS_FONT_FAMILY: + case CSSPrimitiveValue::CSS_FR: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_HZ: case CSSPrimitiveValue::CSS_IDENT: - case CSSPrimitiveValue::CSS_PROPERTY_ID: - case CSSPrimitiveValue::CSS_VALUE_ID: + case CSSPrimitiveValue::CSS_IN: + case CSSPrimitiveValue::CSS_KHZ: + case CSSPrimitiveValue::CSS_MM: + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_NUMBER: case CSSPrimitiveValue::CSS_PAIR: - case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: - case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: - case CSSPrimitiveValue::CSS_PARSER_INTEGER: - case CSSPrimitiveValue::CSS_PARSER_OPERATOR: - case CSSPrimitiveValue::CSS_RECT: + case CSSPrimitiveValue::CSS_PC: + case CSSPrimitiveValue::CSS_PERCENTAGE: + case CSSPrimitiveValue::CSS_PROPERTY_ID: + case CSSPrimitiveValue::CSS_PT: + case CSSPrimitiveValue::CSS_PX: case CSSPrimitiveValue::CSS_QUAD: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_RECT: + case CSSPrimitiveValue::CSS_REMS: case CSSPrimitiveValue::CSS_RGBCOLOR: + case CSSPrimitiveValue::CSS_S: case CSSPrimitiveValue::CSS_SHAPE: - case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_TURN: case CSSPrimitiveValue::CSS_UNICODE_RANGE: case CSSPrimitiveValue::CSS_UNKNOWN: - case CSSPrimitiveValue::CSS_URI: + case CSSPrimitiveValue::CSS_VALUE_ID: + case CSSPrimitiveValue::CSS_VH: + case CSSPrimitiveValue::CSS_VMAX: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VW: +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPrimitiveValue::CSS_DASHBOARD_REGION: +#endif return false; } @@ -124,7 +191,9 @@ static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::Unit return false; } -CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitTypes type) +#endif // !ASSERT_DISABLED + +CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitType type) { // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment). @@ -151,11 +220,6 @@ CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValu case CSS_HZ: case CSS_KHZ: return UFrequency; - case CSS_VW: - case CSS_VH: - case CSS_VMIN: - case CSS_VMAX: - return UViewportPercentageLength; #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) case CSS_DPPX: case CSS_DPI: @@ -170,7 +234,7 @@ CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValu typedef HashMap CSSTextCache; static CSSTextCache& cssTextCache() { - DEFINE_STATIC_LOCAL(CSSTextCache, cache, ()); + static NeverDestroyed cache; return cache; } @@ -179,20 +243,29 @@ unsigned short CSSPrimitiveValue::primitiveType() const if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID) return CSS_IDENT; + // Web-exposed content expects font family values to have CSS_STRING primitive type + // so we need to map our internal CSS_FONT_FAMILY type here. + if (m_primitiveUnitType == CSS_FONT_FAMILY) + return CSS_STRING; + if (m_primitiveUnitType != CSSPrimitiveValue::CSS_CALC) return m_primitiveUnitType; switch (m_value.calc->category()) { case CalcNumber: return CSSPrimitiveValue::CSS_NUMBER; - case CalcPercent: - return CSSPrimitiveValue::CSS_PERCENTAGE; case CalcLength: return CSSPrimitiveValue::CSS_PX; + case CalcPercent: + return CSSPrimitiveValue::CSS_PERCENTAGE; case CalcPercentNumber: return CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER; case CalcPercentLength: return CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH; + case CalcAngle: + case CalcTime: + case CalcFrequency: + return m_value.calc->primitiveType(); case CalcOther: return CSSPrimitiveValue::CSS_UNKNOWN; } @@ -201,12 +274,8 @@ unsigned short CSSPrimitiveValue::primitiveType() const static const AtomicString& propertyName(CSSPropertyID propertyID) { - ASSERT_ARG(propertyID, propertyID >= 0); ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties)); - if (propertyID < 0) - return nullAtom; - return getPropertyNameAtomicString(propertyID); } @@ -239,14 +308,7 @@ CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID) m_value.propertyID = propertyID; } -CSSPrimitiveValue::CSSPrimitiveValue(int parserOperator) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_PARSER_OPERATOR; - m_value.parserOperator = parserOperator; -} - -CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) +CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type) : CSSValue(PrimitiveClass) { m_primitiveUnitType = type; @@ -254,19 +316,20 @@ CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) m_value.num = num; } -CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) +CSSPrimitiveValue::CSSPrimitiveValue(const String& string, UnitType type) : CSSValue(PrimitiveClass) { + ASSERT(isStringType(type)); m_primitiveUnitType = type; - if ((m_value.string = str.impl())) + if ((m_value.string = string.impl())) m_value.string->ref(); } -CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) +CSSPrimitiveValue::CSSPrimitiveValue(const Color& color) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_RGBCOLOR; - m_value.rgbcolor = color; + m_value.color = new Color(color); } CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) @@ -275,7 +338,7 @@ CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) init(length); } -CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle* style) +CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle& style) : CSSValue(PrimitiveClass) { switch (length.type()) { @@ -287,10 +350,6 @@ CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle* st case FillAvailable: case FitContent: case Percent: - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: init(length); return; case Fixed: @@ -298,21 +357,21 @@ CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle* st m_value.num = adjustFloatForAbsoluteZoom(length.value(), style); return; case Calculated: { - RefPtr calcValue = CSSCalcValue::create(length.calculationValue().get(), style); - init(calcValue.release()); + init(CSSCalcValue::create(length.calculationValue(), style)); return; } case Relative: case Undefined: ASSERT_NOT_REACHED(); - break; + return; } + ASSERT_NOT_REACHED(); } -CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize) +CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize, const RenderStyle& style) : CSSValue(PrimitiveClass) { - init(lengthSize); + init(lengthSize, style); } void CSSPrimitiveValue::init(const Length& length) @@ -321,94 +380,79 @@ void CSSPrimitiveValue::init(const Length& length) case Auto: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueAuto; - break; + return; case WebCore::Fixed: m_primitiveUnitType = CSS_PX; m_value.num = length.value(); - break; + return; case Intrinsic: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueIntrinsic; - break; + return; case MinIntrinsic: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueMinIntrinsic; - break; + return; case MinContent: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueWebkitMinContent; - break; + return; case MaxContent: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueWebkitMaxContent; - break; + return; case FillAvailable: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueWebkitFillAvailable; - break; + return; case FitContent: m_primitiveUnitType = CSS_VALUE_ID; m_value.valueID = CSSValueWebkitFitContent; - break; + return; case Percent: m_primitiveUnitType = CSS_PERCENTAGE; ASSERT(std::isfinite(length.percent())); m_value.num = length.percent(); - break; - case ViewportPercentageWidth: - m_primitiveUnitType = CSS_VW; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageHeight: - m_primitiveUnitType = CSS_VH; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageMin: - m_primitiveUnitType = CSS_VMIN; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageMax: - m_primitiveUnitType = CSS_VMAX; - m_value.num = length.viewportPercentageLength(); - break; + return; case Calculated: case Relative: case Undefined: ASSERT_NOT_REACHED(); - break; + return; } + ASSERT_NOT_REACHED(); } -void CSSPrimitiveValue::init(const LengthSize& lengthSize) +void CSSPrimitiveValue::init(const LengthSize& lengthSize, const RenderStyle& style) { m_primitiveUnitType = CSS_PAIR; m_hasCachedCSSText = false; - m_value.pair = Pair::create(create(lengthSize.width()), create(lengthSize.height())).leakRef(); + m_value.pair = &Pair::create(create(lengthSize.width, style), create(lengthSize.height, style)).leakRef(); } -void CSSPrimitiveValue::init(PassRefPtr c) +void CSSPrimitiveValue::init(Ref&& counter) { m_primitiveUnitType = CSS_COUNTER; m_hasCachedCSSText = false; - m_value.counter = c.leakRef(); + m_value.counter = &counter.leakRef(); } -void CSSPrimitiveValue::init(PassRefPtr r) +void CSSPrimitiveValue::init(Ref&& r) { m_primitiveUnitType = CSS_RECT; m_hasCachedCSSText = false; - m_value.rect = r.leakRef(); + m_value.rect = &r.leakRef(); } -void CSSPrimitiveValue::init(PassRefPtr quad) +void CSSPrimitiveValue::init(Ref&& quad) { m_primitiveUnitType = CSS_QUAD; m_hasCachedCSSText = false; - m_value.quad = quad.leakRef(); + m_value.quad = &quad.leakRef(); } #if ENABLE(DASHBOARD_SUPPORT) -void CSSPrimitiveValue::init(PassRefPtr r) +void CSSPrimitiveValue::init(RefPtr&& r) { m_primitiveUnitType = CSS_DASHBOARD_REGION; m_hasCachedCSSText = false; @@ -416,25 +460,25 @@ void CSSPrimitiveValue::init(PassRefPtr r) } #endif -void CSSPrimitiveValue::init(PassRefPtr p) +void CSSPrimitiveValue::init(Ref&& p) { m_primitiveUnitType = CSS_PAIR; m_hasCachedCSSText = false; - m_value.pair = p.leakRef(); + m_value.pair = &p.leakRef(); } -void CSSPrimitiveValue::init(PassRefPtr c) +void CSSPrimitiveValue::init(Ref&& shape) { - m_primitiveUnitType = CSS_CALC; + m_primitiveUnitType = CSS_SHAPE; m_hasCachedCSSText = false; - m_value.calc = c.leakRef(); + m_value.shape = &shape.leakRef(); } -void CSSPrimitiveValue::init(PassRefPtr shape) +void CSSPrimitiveValue::init(RefPtr&& c) { - m_primitiveUnitType = CSS_SHAPE; + m_primitiveUnitType = CSS_CALC; m_hasCachedCSSText = false; - m_value.shape = shape.leakRef(); + m_value.calc = c.leakRef(); } CSSPrimitiveValue::~CSSPrimitiveValue() @@ -444,15 +488,16 @@ CSSPrimitiveValue::~CSSPrimitiveValue() void CSSPrimitiveValue::cleanup() { - switch (static_cast(m_primitiveUnitType)) { + auto type = static_cast(m_primitiveUnitType); + switch (type) { case CSS_STRING: case CSS_URI: case CSS_ATTR: case CSS_COUNTER_NAME: - case CSS_PARSER_HEXCOLOR: if (m_value.string) m_value.string->deref(); break; + case CSS_DIMENSION: case CSS_COUNTER: m_value.counter->deref(); break; @@ -481,10 +526,20 @@ void CSSPrimitiveValue::cleanup() case CSS_SHAPE: m_value.shape->deref(); break; + case CSS_FONT_FAMILY: + ASSERT(m_value.fontFamily); + delete m_value.fontFamily; + m_value.fontFamily = nullptr; + break; + case CSS_RGBCOLOR: + ASSERT(m_value.color); + delete m_value.color; + m_value.color = nullptr; + break; case CSS_NUMBER: - case CSS_PARSER_INTEGER: case CSS_PERCENTAGE: case CSS_EMS: + case CSS_QUIRKY_EMS: case CSS_EXS: case CSS_REMS: case CSS_CHS: @@ -511,14 +566,11 @@ void CSSPrimitiveValue::cleanup() case CSS_DPCM: case CSS_FR: case CSS_IDENT: - case CSS_RGBCOLOR: - case CSS_DIMENSION: case CSS_UNKNOWN: case CSS_UNICODE_RANGE: - case CSS_PARSER_OPERATOR: - case CSS_PARSER_IDENTIFIER: case CSS_PROPERTY_ID: case CSS_VALUE_ID: + ASSERT(!isStringType(type)); break; } m_primitiveUnitType = 0; @@ -528,91 +580,96 @@ void CSSPrimitiveValue::cleanup() } } -double CSSPrimitiveValue::computeDegrees() +double CSSPrimitiveValue::computeDegrees() const { - switch (m_primitiveUnitType) { + switch (primitiveType()) { case CSS_DEG: - return getDoubleValue(); + return doubleValue(); case CSS_RAD: - return rad2deg(getDoubleValue()); + return rad2deg(doubleValue()); case CSS_GRAD: - return grad2deg(getDoubleValue()); + return grad2deg(doubleValue()); case CSS_TURN: - return turn2deg(getDoubleValue()); + return turn2deg(doubleValue()); default: ASSERT_NOT_REACHED(); return 0; } } -template<> int CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return roundForImpreciseConversion(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); + return roundForImpreciseConversion(computeLengthDouble(conversionData)); } -template<> unsigned CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return roundForImpreciseConversion(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); + return roundForImpreciseConversion(computeLengthDouble(conversionData)); } -template<> Length CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { -#if ENABLE(SUBPIXEL_LAYOUT) - return Length(clampTo(computeLengthDouble(style, rootStyle, multiplier, computingFontSize), minValueForCssLength, maxValueForCssLength), Fixed); -#else - return Length(clampTo(roundForImpreciseConversion(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)), minValueForCssLength, maxValueForCssLength), Fixed); -#endif + return Length(clampTo(computeLengthDouble(conversionData), minValueForCssLength, maxValueForCssLength), Fixed); } -template<> short CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return roundForImpreciseConversion(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); + return roundForImpreciseConversion(computeLengthDouble(conversionData)); } -template<> unsigned short CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return roundForImpreciseConversion(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); + return roundForImpreciseConversion(computeLengthDouble(conversionData)); } -template<> float CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return static_cast(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); + return static_cast(computeLengthDouble(conversionData)); } -template<> double CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const { - return computeLengthDouble(style, rootStyle, multiplier, computingFontSize); + return computeLengthDouble(conversionData); } -double CSSPrimitiveValue::computeLengthDouble(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const +double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const { if (m_primitiveUnitType == CSS_CALC) // The multiplier and factor is applied to each value in the calc expression individually - return m_value.calc->computeLengthPx(style, rootStyle, multiplier, computingFontSize); + return m_value.calc->computeLengthPx(conversionData); + + return computeNonCalcLengthDouble(conversionData, static_cast(primitiveType()), m_value.num); +} +double CSSPrimitiveValue::computeNonCalcLengthDouble(const CSSToLengthConversionData& conversionData, UnitType primitiveType, double value) +{ double factor; - switch (primitiveType()) { + switch (primitiveType) { case CSS_EMS: - factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); + case CSS_QUIRKY_EMS: + ASSERT(conversionData.style()); + factor = conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize(); break; case CSS_EXS: + ASSERT(conversionData.style()); // FIXME: We have a bug right now where the zoom will be applied twice to EX units. // We really need to compute EX using fontMetrics for the original specifiedSize and not use // our actual constructed rendering font. - if (style->fontMetrics().hasXHeight()) - factor = style->fontMetrics().xHeight(); + if (conversionData.style()->fontMetrics().hasXHeight()) + factor = conversionData.style()->fontMetrics().xHeight(); else - factor = (computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize()) / 2.0; + factor = (conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize()) / 2.0; break; case CSS_REMS: - if (rootStyle) - factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); + if (conversionData.rootStyle()) + factor = conversionData.computingFontSize() ? conversionData.rootStyle()->fontDescription().specifiedSize() : conversionData.rootStyle()->fontDescription().computedSize(); else factor = 1.0; break; case CSS_CHS: - factor = style->fontMetrics().zeroWidth(); + ASSERT(conversionData.style()); + factor = conversionData.style()->fontMetrics().zeroWidth(); break; case CSS_PX: factor = 1.0; @@ -638,10 +695,16 @@ double CSSPrimitiveValue::computeLengthDouble(const RenderStyle* style, const Re ASSERT_NOT_REACHED(); return -1.0; case CSS_VH: + factor = conversionData.viewportHeightFactor(); + break; case CSS_VW: + factor = conversionData.viewportWidthFactor(); + break; case CSS_VMAX: + factor = conversionData.viewportMaxFactor(); + break; case CSS_VMIN: - factor = 1.0; + factor = conversionData.viewportMinFactor(); break; default: ASSERT_NOT_REACHED(); @@ -651,22 +714,22 @@ double CSSPrimitiveValue::computeLengthDouble(const RenderStyle* style, const Re // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference // as well as enforcing the implicit "smart minimum." - double result = getDoubleValue() * factor; - if (computingFontSize || isFontRelativeLength()) + double result = value * factor; + if (conversionData.computingFontSize() || isFontRelativeLength(primitiveType)) return result; - return result * multiplier; + return result * conversionData.zoom(); } -void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec) +ExceptionOr CSSPrimitiveValue::setFloatValue(unsigned short, double) { // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. // No other engine supports mutating style through this API. Computed style is always read-only anyway. // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. - ec = NO_MODIFICATION_ALLOWED_ERR; + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(unsigned short unitType) +double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType) { double factor = 1.0; // FIXME: the switch can be replaced by an array of scale factors. @@ -718,32 +781,26 @@ double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(unsigned short u return factor; } -double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const +ExceptionOr CSSPrimitiveValue::getFloatValue(unsigned short unitType) const { - double result = 0; - bool success = getDoubleValueInternal(static_cast(unitType), &result); - if (!success) { - ec = INVALID_ACCESS_ERR; - return 0.0; - } - - ec = 0; - return result; + auto result = doubleValueInternal(static_cast(unitType)); + if (!result) + return Exception { INVALID_ACCESS_ERR }; + return clampTo(result.value()); } -double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const +double CSSPrimitiveValue::doubleValue(UnitType unitType) const { - double result = 0; - getDoubleValueInternal(static_cast(unitType), &result); - return result; + return doubleValueInternal(unitType).value_or(0); } -double CSSPrimitiveValue::getDoubleValue() const +double CSSPrimitiveValue::doubleValue() const { return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue(); } -CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) + +CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) { // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit // in each category (based on unitflags). @@ -760,8 +817,6 @@ CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(Uni return CSS_DEG; case UFrequency: return CSS_HZ; - case UViewportPercentageLength: - return CSS_UNKNOWN; // Cannot convert between numbers and relative lengths. #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) case UResolution: return CSS_DPPX; @@ -771,43 +826,41 @@ CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(Uni } } -bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const +std::optional CSSPrimitiveValue::doubleValueInternal(UnitType requestedUnitType) const { - if (!isValidCSSUnitTypeForDoubleConversion(static_cast(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType)) - return false; + if (!isValidCSSUnitTypeForDoubleConversion(static_cast(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType)) + return std::nullopt; - UnitTypes sourceUnitType = static_cast(primitiveType()); - if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) { - *result = getDoubleValue(); - return true; - } + UnitType sourceUnitType = static_cast(primitiveType()); + if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) + return doubleValue(); UnitCategory sourceCategory = unitCategory(sourceUnitType); ASSERT(sourceCategory != UOther); - UnitTypes targetUnitType = requestedUnitType; + UnitType targetUnitType = requestedUnitType; UnitCategory targetCategory = unitCategory(targetUnitType); ASSERT(targetCategory != UOther); // Cannot convert between unrelated unit categories if one of them is not UNumber. if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber) - return false; + return std::nullopt; if (targetCategory == UNumber) { // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category. targetUnitType = canonicalUnitTypeForCategory(sourceCategory); if (targetUnitType == CSS_UNKNOWN) - return false; + return std::nullopt; } if (sourceUnitType == CSS_NUMBER) { // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode. sourceUnitType = canonicalUnitTypeForCategory(targetCategory); if (sourceUnitType == CSS_UNKNOWN) - return false; + return std::nullopt; } - double convertedValue = getDoubleValue(); + double convertedValue = doubleValue(); // First convert the value from m_primitiveUnitType to canonical type. double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType); @@ -817,509 +870,281 @@ bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, doub factor = conversionToCanonicalUnitsScaleFactor(targetUnitType); convertedValue /= factor; - *result = convertedValue; - return true; + return convertedValue; } -void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec) +ExceptionOr CSSPrimitiveValue::setStringValue(unsigned short, const String&) { // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. // No other engine supports mutating style through this API. Computed style is always read-only anyway. // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. - ec = NO_MODIFICATION_ALLOWED_ERR; + return Exception { NO_MODIFICATION_ALLOWED_ERR }; } -String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const +ExceptionOr CSSPrimitiveValue::getStringValue() const { - ec = 0; switch (m_primitiveUnitType) { case CSS_STRING: case CSS_ATTR: case CSS_URI: return m_value.string; + case CSS_FONT_FAMILY: + return String { m_value.fontFamily->familyName }; case CSS_VALUE_ID: - return valueName(m_value.valueID); + return String { valueName(m_value.valueID).string() }; case CSS_PROPERTY_ID: - return propertyName(m_value.propertyID); + return String { propertyName(m_value.propertyID).string() }; default: - ec = INVALID_ACCESS_ERR; - break; + return Exception { INVALID_ACCESS_ERR }; } - - return String(); } -String CSSPrimitiveValue::getStringValue() const +String CSSPrimitiveValue::stringValue() const { switch (m_primitiveUnitType) { case CSS_STRING: case CSS_ATTR: case CSS_URI: return m_value.string; + case CSS_FONT_FAMILY: + return m_value.fontFamily->familyName; case CSS_VALUE_ID: return valueName(m_value.valueID); case CSS_PROPERTY_ID: return propertyName(m_value.propertyID); default: - break; + return String(); } - - return String(); -} - -Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const -{ - ec = 0; - if (m_primitiveUnitType != CSS_COUNTER) { - ec = INVALID_ACCESS_ERR; - return 0; - } - - return m_value.counter; } -Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const +ExceptionOr CSSPrimitiveValue::getCounterValue() const { - ec = 0; - if (m_primitiveUnitType != CSS_RECT) { - ec = INVALID_ACCESS_ERR; - return 0; - } - - return m_value.rect; + if (m_primitiveUnitType != CSS_COUNTER) + return Exception { INVALID_ACCESS_ERR }; + return *m_value.counter; } -Quad* CSSPrimitiveValue::getQuadValue(ExceptionCode& ec) const +ExceptionOr CSSPrimitiveValue::getRectValue() const { - ec = 0; - if (m_primitiveUnitType != CSS_QUAD) { - ec = INVALID_ACCESS_ERR; - return 0; - } - - return m_value.quad; + if (m_primitiveUnitType != CSS_RECT) + return Exception { INVALID_ACCESS_ERR }; + return *m_value.rect; } -PassRefPtr CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const +ExceptionOr> CSSPrimitiveValue::getRGBColorValue() const { - ec = 0; - if (m_primitiveUnitType != CSS_RGBCOLOR) { - ec = INVALID_ACCESS_ERR; - return 0; - } + if (m_primitiveUnitType != CSS_RGBCOLOR) + return Exception { INVALID_ACCESS_ERR }; - // FIMXE: This should not return a new object for each invocation. - return RGBColor::create(m_value.rgbcolor); + // FIXME: This should not return a new object for each invocation. + return RGBColor::create(m_value.color->rgb()); } -Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const +NEVER_INLINE Ref CSSPrimitiveValue::formatNumberValue(const char* suffix, unsigned suffixLength) const { - ec = 0; - if (m_primitiveUnitType != CSS_PAIR) { - ec = INVALID_ACCESS_ERR; - return 0; - } - - return m_value.pair; -} + DecimalNumber decimal(m_value.num); -static String formatNumber(double number, const char* suffix, unsigned suffixLength) -{ - DecimalNumber decimal(number); + unsigned bufferLength = decimal.bufferLengthForStringDecimal() + suffixLength; + LChar* buffer; + auto string = StringImpl::createUninitialized(bufferLength, buffer); - StringBuffer buffer(decimal.bufferLengthForStringDecimal() + suffixLength); - unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length()); - ASSERT(length + suffixLength == buffer.length()); + unsigned length = decimal.toStringDecimal(buffer, bufferLength); for (unsigned i = 0; i < suffixLength; ++i) buffer[length + i] = static_cast(suffix[i]); - return String::adopt(buffer); + return string; } template -ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount]) -{ - return formatNumber(number, characters, characterCount - 1); -} - -String CSSPrimitiveValue::customCSSText() const -{ - // FIXME: return the original value instead of a generated one (e.g. color - // name if it was specified) - check what spec says about this - - if (m_hasCachedCSSText) { - ASSERT(cssTextCache().contains(this)); - return cssTextCache().get(this); - } - - String text; - switch (m_primitiveUnitType) { - case CSS_UNKNOWN: - // FIXME - break; - case CSS_NUMBER: - case CSS_PARSER_INTEGER: - text = formatNumber(m_value.num, ""); - break; - case CSS_PERCENTAGE: - text = formatNumber(m_value.num, "%"); - break; - case CSS_EMS: - text = formatNumber(m_value.num, "em"); - break; - case CSS_EXS: - text = formatNumber(m_value.num, "ex"); - break; - case CSS_REMS: - text = formatNumber(m_value.num, "rem"); - break; - case CSS_CHS: - text = formatNumber(m_value.num, "ch"); - break; - case CSS_PX: - text = formatNumber(m_value.num, "px"); - break; - case CSS_CM: - text = formatNumber(m_value.num, "cm"); - break; -#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - case CSS_DPPX: - text = formatNumber(m_value.num, "dppx"); - break; - case CSS_DPI: - text = formatNumber(m_value.num, "dpi"); - break; - case CSS_DPCM: - text = formatNumber(m_value.num, "dpcm"); - break; -#endif - case CSS_MM: - text = formatNumber(m_value.num, "mm"); - break; - case CSS_IN: - text = formatNumber(m_value.num, "in"); - break; - case CSS_PT: - text = formatNumber(m_value.num, "pt"); - break; - case CSS_PC: - text = formatNumber(m_value.num, "pc"); - break; - case CSS_DEG: - text = formatNumber(m_value.num, "deg"); - break; - case CSS_RAD: - text = formatNumber(m_value.num, "rad"); - break; - case CSS_GRAD: - text = formatNumber(m_value.num, "grad"); - break; - case CSS_MS: - text = formatNumber(m_value.num, "ms"); - break; - case CSS_S: - text = formatNumber(m_value.num, "s"); - break; - case CSS_HZ: - text = formatNumber(m_value.num, "hz"); - break; - case CSS_KHZ: - text = formatNumber(m_value.num, "khz"); - break; - case CSS_TURN: - text = formatNumber(m_value.num, "turn"); - break; - case CSS_FR: - text = formatNumber(m_value.num, "fr"); - break; - case CSS_DIMENSION: - // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store - // the actual dimension, just the numeric value as a string. - break; - case CSS_STRING: - text = quoteCSSStringIfNeeded(m_value.string); - break; - case CSS_URI: - text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ')'; - break; - case CSS_VALUE_ID: - text = valueName(m_value.valueID); - break; - case CSS_PROPERTY_ID: - text = propertyName(m_value.propertyID); - break; - case CSS_ATTR: { - StringBuilder result; - result.reserveCapacity(6 + m_value.string->length()); - result.appendLiteral("attr("); - result.append(m_value.string); - result.append(')'); - - text = result.toString(); - break; - } - case CSS_COUNTER_NAME: - text = "counter(" + String(m_value.string) + ')'; - break; - case CSS_COUNTER: { - StringBuilder result; - String separator = m_value.counter->separator(); - if (separator.isEmpty()) - result.appendLiteral("counter("); - else - result.appendLiteral("counters("); - - result.append(m_value.counter->identifier()); - if (!separator.isEmpty()) { - result.appendLiteral(", "); - result.append(quoteCSSStringIfNeeded(separator)); - } - String listStyle = m_value.counter->listStyle(); - if (!listStyle.isEmpty()) { - result.appendLiteral(", "); - result.append(listStyle); - } - result.append(')'); - - text = result.toString(); - break; - } - case CSS_RECT: - text = getRectValue()->cssText(); - break; - case CSS_QUAD: - text = getQuadValue()->cssText(); - break; - case CSS_RGBCOLOR: - case CSS_PARSER_HEXCOLOR: { - RGBA32 rgbColor = m_value.rgbcolor; - if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR) - Color::parseHexColor(m_value.string, rgbColor); - Color color(rgbColor); - - Vector result; - result.reserveInitialCapacity(32); - bool colorHasAlpha = color.hasAlpha(); - if (colorHasAlpha) - result.append("rgba(", 5); - else - result.append("rgb(", 4); - - appendNumber(result, static_cast(color.red())); - result.append(", ", 2); - - appendNumber(result, static_cast(color.green())); - result.append(", ", 2); - - appendNumber(result, static_cast(color.blue())); - if (colorHasAlpha) { - result.append(", ", 2); - - NumberToStringBuffer buffer; - const char* alphaString = numberToFixedPrecisionString(color.alpha() / 255.0f, 6, buffer, true); - result.append(alphaString, strlen(alphaString)); - } - - result.append(')'); - text = String::adopt(result); - break; - } - case CSS_PAIR: - text = getPairValue()->cssText(); - break; -#if ENABLE(DASHBOARD_SUPPORT) - case CSS_DASHBOARD_REGION: { - StringBuilder result; - for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { - if (!result.isEmpty()) - result.append(' '); - result.appendLiteral("dashboard-region("); - result.append(region->m_label); - if (region->m_isCircle) - result.appendLiteral(" circle"); - else if (region->m_isRectangle) - result.appendLiteral(" rectangle"); - else - break; - if (region->top()->m_primitiveUnitType == CSS_VALUE_ID && region->top()->getValueID() == CSSValueInvalid) { - ASSERT(region->right()->m_primitiveUnitType == CSS_VALUE_ID); - ASSERT(region->bottom()->m_primitiveUnitType == CSS_VALUE_ID); - ASSERT(region->left()->m_primitiveUnitType == CSS_VALUE_ID); - ASSERT(region->right()->getValueID() == CSSValueInvalid); - ASSERT(region->bottom()->getValueID() == CSSValueInvalid); - ASSERT(region->left()->getValueID() == CSSValueInvalid); - } else { - result.append(' '); - result.append(region->top()->cssText()); - result.append(' '); - result.append(region->right()->cssText()); - result.append(' '); - result.append(region->bottom()->cssText()); - result.append(' '); - result.append(region->left()->cssText()); - } - result.append(')'); - } - text = result.toString(); - break; - } -#endif - case CSS_PARSER_OPERATOR: { - char c = static_cast(m_value.parserOperator); - text = String(&c, 1U); - break; - } - case CSS_PARSER_IDENTIFIER: - text = quoteCSSStringIfNeeded(m_value.string); - break; - case CSS_CALC: - text = m_value.calc->cssText(); - break; - case CSS_SHAPE: - text = m_value.shape->cssText(); - break; - case CSS_VW: - text = formatNumber(m_value.num, "vw"); - break; - case CSS_VH: - text = formatNumber(m_value.num, "vh"); - break; - case CSS_VMIN: - text = formatNumber(m_value.num, "vmin"); - break; - case CSS_VMAX: - text = formatNumber(m_value.num, "vmax"); - break; - } - - ASSERT(!cssTextCache().contains(this)); - cssTextCache().set(this, text); - m_hasCachedCSSText = true; - return text; -} - -void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet& urls, const StyleSheetContents* styleSheet) const -{ - if (m_primitiveUnitType == CSS_URI) - addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); -} - -Length CSSPrimitiveValue::viewportPercentageLength() const +ALWAYS_INLINE Ref CSSPrimitiveValue::formatNumberValue(const char (&characters)[characterCount]) const { - ASSERT(isViewportPercentageLength()); - Length viewportLength; - switch (m_primitiveUnitType) { - case CSS_VW: - viewportLength = Length(getDoubleValue(), ViewportPercentageWidth); - break; - case CSS_VH: - viewportLength = Length(getDoubleValue(), ViewportPercentageHeight); - break; - case CSS_VMIN: - viewportLength = Length(getDoubleValue(), ViewportPercentageMin); - break; - case CSS_VMAX: - viewportLength = Length(getDoubleValue(), ViewportPercentageMax); - break; - default: - break; - } - return viewportLength; + return formatNumberValue(characters, characterCount - 1); } -PassRefPtr CSSPrimitiveValue::cloneForCSSOM() const +ALWAYS_INLINE String CSSPrimitiveValue::formatNumberForCustomCSSText() const { - RefPtr result; - switch (m_primitiveUnitType) { - case CSS_STRING: - case CSS_URI: - case CSS_ATTR: - case CSS_COUNTER_NAME: - result = CSSPrimitiveValue::create(m_value.string, static_cast(m_primitiveUnitType)); - break; - case CSS_COUNTER: - result = CSSPrimitiveValue::create(m_value.counter->cloneForCSSOM()); - break; - case CSS_RECT: - result = CSSPrimitiveValue::create(m_value.rect->cloneForCSSOM()); - break; - case CSS_QUAD: - result = CSSPrimitiveValue::create(m_value.quad->cloneForCSSOM()); - break; - case CSS_PAIR: - // Pair is not exposed to the CSSOM, no need for a deep clone. - result = CSSPrimitiveValue::create(m_value.pair); - break; -#if ENABLE(DASHBOARD_SUPPORT) - case CSS_DASHBOARD_REGION: - // DashboardRegion is not exposed to the CSSOM, no need for a deep clone. - result = CSSPrimitiveValue::create(m_value.region); - break; -#endif - case CSS_CALC: - // CSSCalcValue is not exposed to the CSSOM, no need for a deep clone. - result = CSSPrimitiveValue::create(m_value.calc); - break; - case CSS_SHAPE: - // CSSShapeValue is not exposed to the CSSOM, no need for a deep clone. - result = CSSPrimitiveValue::create(m_value.shape); - break; + case CSS_UNKNOWN: + return String(); case CSS_NUMBER: - case CSS_PARSER_INTEGER: + return formatNumberValue(""); case CSS_PERCENTAGE: + return formatNumberValue("%"); case CSS_EMS: + case CSS_QUIRKY_EMS: + return formatNumberValue("em"); case CSS_EXS: + return formatNumberValue("ex"); case CSS_REMS: + return formatNumberValue("rem"); case CSS_CHS: + return formatNumberValue("ch"); case CSS_PX: + return formatNumberValue("px"); case CSS_CM: + return formatNumberValue("cm"); +#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) + case CSS_DPPX: + return formatNumberValue("dppx"); + case CSS_DPI: + return formatNumberValue("dpi"); + case CSS_DPCM: + return formatNumberValue("dpcm"); +#endif case CSS_MM: + return formatNumberValue("mm"); case CSS_IN: + return formatNumberValue("in"); case CSS_PT: + return formatNumberValue("pt"); case CSS_PC: + return formatNumberValue("pc"); case CSS_DEG: + return formatNumberValue("deg"); case CSS_RAD: + return formatNumberValue("rad"); case CSS_GRAD: + return formatNumberValue("grad"); case CSS_MS: + return formatNumberValue("ms"); case CSS_S: + return formatNumberValue("s"); case CSS_HZ: + return formatNumberValue("hz"); case CSS_KHZ: + return formatNumberValue("khz"); case CSS_TURN: + return formatNumberValue("turn"); + case CSS_FR: + return formatNumberValue("fr"); + case CSS_DIMENSION: + // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store + // the actual dimension, just the numeric value as a string. + case CSS_STRING: + // FIME-NEWPARSER: Once we have CSSCustomIdentValue hooked up, this can just be + // serializeString, since custom identifiers won't be the same value as strings + // any longer. + return serializeAsStringOrCustomIdent(m_value.string); + case CSS_FONT_FAMILY: + return serializeFontFamily(m_value.fontFamily->familyName); + case CSS_URI: + return serializeURL(m_value.string); + case CSS_VALUE_ID: + return valueName(m_value.valueID); + case CSS_PROPERTY_ID: + return propertyName(m_value.propertyID); + case CSS_ATTR: { + StringBuilder result; + result.reserveCapacity(6 + m_value.string->length()); + result.appendLiteral("attr("); + result.append(String(m_value.string)); + result.append(')'); + + return result.toString(); + } + case CSS_COUNTER_NAME: + return "counter(" + String(m_value.string) + ')'; + case CSS_COUNTER: { + StringBuilder result; + String separator = m_value.counter->separator(); + if (separator.isEmpty()) + result.appendLiteral("counter("); + else + result.appendLiteral("counters("); + + result.append(m_value.counter->identifier()); + if (!separator.isEmpty()) { + result.appendLiteral(", "); + serializeString(separator, result); + } + String listStyle = m_value.counter->listStyle(); + if (!listStyle.isEmpty()) { + result.appendLiteral(", "); + result.append(listStyle); + } + result.append(')'); + + return result.toString(); + } + case CSS_RECT: + return rectValue()->cssText(); + case CSS_QUAD: + return quadValue()->cssText(); + case CSS_RGBCOLOR: + return color().cssText(); + case CSS_PAIR: + return pairValue()->cssText(); +#if ENABLE(DASHBOARD_SUPPORT) + case CSS_DASHBOARD_REGION: { + StringBuilder result; + for (DashboardRegion* region = dashboardRegionValue(); region; region = region->m_next.get()) { + if (!result.isEmpty()) + result.append(' '); + result.appendLiteral("dashboard-region("); + result.append(region->m_label); + if (region->m_isCircle) + result.appendLiteral(" circle"); + else if (region->m_isRectangle) + result.appendLiteral(" rectangle"); + else + break; + if (region->top()->m_primitiveUnitType == CSS_VALUE_ID && region->top()->valueID() == CSSValueInvalid) { + ASSERT(region->right()->m_primitiveUnitType == CSS_VALUE_ID); + ASSERT(region->bottom()->m_primitiveUnitType == CSS_VALUE_ID); + ASSERT(region->left()->m_primitiveUnitType == CSS_VALUE_ID); + ASSERT(region->right()->valueID() == CSSValueInvalid); + ASSERT(region->bottom()->valueID() == CSSValueInvalid); + ASSERT(region->left()->valueID() == CSSValueInvalid); + } else { + result.append(' '); + result.append(region->top()->cssText()); + result.append(' '); + result.append(region->right()->cssText()); + result.append(' '); + result.append(region->bottom()->cssText()); + result.append(' '); + result.append(region->left()->cssText()); + } + result.append(')'); + } + return result.toString(); + } +#endif + case CSS_CALC: + return m_value.calc->cssText(); + case CSS_SHAPE: + return m_value.shape->cssText(); case CSS_VW: + return formatNumberValue("vw"); case CSS_VH: + return formatNumberValue("vh"); case CSS_VMIN: + return formatNumberValue("vmin"); case CSS_VMAX: -#if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - case CSS_DPPX: - case CSS_DPI: - case CSS_DPCM: -#endif - case CSS_FR: - result = CSSPrimitiveValue::create(m_value.num, static_cast(m_primitiveUnitType)); - break; - case CSS_PROPERTY_ID: - result = CSSPrimitiveValue::createIdentifier(m_value.propertyID); - break; - case CSS_VALUE_ID: - result = CSSPrimitiveValue::createIdentifier(m_value.valueID); - break; - case CSS_RGBCOLOR: - result = CSSPrimitiveValue::createColor(m_value.rgbcolor); - break; - case CSS_DIMENSION: - case CSS_UNKNOWN: - case CSS_PARSER_OPERATOR: - case CSS_PARSER_IDENTIFIER: - case CSS_PARSER_HEXCOLOR: - ASSERT_NOT_REACHED(); - break; + return formatNumberValue("vmax"); + } + return String(); +} + +String CSSPrimitiveValue::customCSSText() const +{ + // FIXME: return the original value instead of a generated one (e.g. color + // name if it was specified) - check what spec says about this + + CSSTextCache& cssTextCache = WebCore::cssTextCache(); + + if (m_hasCachedCSSText) { + ASSERT(cssTextCache.contains(this)); + return cssTextCache.get(this); } - if (result) - result->setCSSOMSafe(); - return result; + String text = formatNumberForCustomCSSText(); + + ASSERT(!cssTextCache.contains(this)); + m_hasCachedCSSText = true; + cssTextCache.set(this, text); + return text; } bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const @@ -1331,9 +1156,9 @@ bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const case CSS_UNKNOWN: return false; case CSS_NUMBER: - case CSS_PARSER_INTEGER: case CSS_PERCENTAGE: case CSS_EMS: + case CSS_QUIRKY_EMS: case CSS_EXS: case CSS_REMS: case CSS_PX: @@ -1358,19 +1183,17 @@ bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const case CSS_VW: case CSS_VH: case CSS_VMIN: - case CSS_DIMENSION: case CSS_FR: return m_value.num == other.m_value.num; case CSS_PROPERTY_ID: return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID); case CSS_VALUE_ID: return valueName(m_value.valueID) == valueName(other.m_value.valueID); + case CSS_DIMENSION: case CSS_STRING: case CSS_URI: case CSS_ATTR: case CSS_COUNTER_NAME: - case CSS_PARSER_IDENTIFIER: - case CSS_PARSER_HEXCOLOR: return equal(m_value.string, other.m_value.string); case CSS_COUNTER: return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter); @@ -1379,21 +1202,26 @@ bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const case CSS_QUAD: return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad); case CSS_RGBCOLOR: - return m_value.rgbcolor == other.m_value.rgbcolor; + return color() == other.color(); case CSS_PAIR: return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair); #if ENABLE(DASHBOARD_SUPPORT) case CSS_DASHBOARD_REGION: return m_value.region && other.m_value.region && m_value.region->equals(*other.m_value.region); #endif - case CSS_PARSER_OPERATOR: - return m_value.parserOperator == other.m_value.parserOperator; case CSS_CALC: return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc); case CSS_SHAPE: return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape); + case CSS_FONT_FAMILY: + return fontFamily() == other.fontFamily(); } return false; } +Ref CSSPrimitiveValue::createDeprecatedCSSOMPrimitiveWrapper() const +{ + return DeprecatedCSSOMPrimitiveValue::create(*this); +} + } // namespace WebCore diff --git a/Source/WebCore/css/CSSPrimitiveValue.h b/Source/WebCore/css/CSSPrimitiveValue.h index dabc6e11e..bc6f48cdd 100644 --- a/Source/WebCore/css/CSSPrimitiveValue.h +++ b/Source/WebCore/css/CSSPrimitiveValue.h @@ -19,30 +19,33 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSPrimitiveValue_h -#define CSSPrimitiveValue_h +#pragma once #include "CSSPropertyNames.h" #include "CSSValue.h" #include "CSSValueKeywords.h" #include "Color.h" #include "LayoutUnit.h" +#include #include #include -#include +#include namespace WebCore { +class CSSBasicShape; class CSSCalcValue; +class CSSToLengthConversionData; class Counter; class DashboardRegion; +class DeprecatedCSSOMPrimitiveValue; class Pair; class Quad; class RGBColor; class Rect; class RenderStyle; -class CSSBasicShape; +struct CSSFontFamily; struct Length; struct LengthSize; @@ -52,8 +55,7 @@ const int maxValueForCssLength = intMaxForLayoutUnit - 2; const int minValueForCssLength = intMinForLayoutUnit + 2; // Dimension calculations are imprecise, often resulting in values of e.g. -// 44.99998. We need to go ahead and round if we're really close to the next -// integer value. +// 44.99998. We need to round if we're really close to the next integer value. template inline T roundForImpreciseConversion(double value) { value += (value < 0) ? -0.01 : +0.01; @@ -71,9 +73,9 @@ template<> inline float roundForImpreciseConversion(double value) return static_cast(value); } -class CSSPrimitiveValue : public CSSValue { +class CSSPrimitiveValue final : public CSSValue { public: - enum UnitTypes { + enum UnitType { CSS_UNKNOWN = 0, CSS_NUMBER = 1, CSS_PERCENTAGE = 2, @@ -115,14 +117,6 @@ public: #endif CSS_UNICODE_RANGE = 102, - // These next types are just used internally to allow us to translate back and forth from CSSPrimitiveValues to CSSParserValues. - CSS_PARSER_OPERATOR = 103, - CSS_PARSER_INTEGER = 104, - CSS_PARSER_HEXCOLOR = 105, - - // This is used internally for unknown identifiers - CSS_PARSER_IDENTIFIER = 106, - // These are from CSS3 Values and Units, but that isn't a finished standard yet CSS_TURN = 107, CSS_REMS = 108, @@ -141,8 +135,16 @@ public: CSS_CALC_PERCENTAGE_WITH_NUMBER = 114, CSS_CALC_PERCENTAGE_WITH_LENGTH = 115, + CSS_FONT_FAMILY = 116, + CSS_PROPERTY_ID = 117, - CSS_VALUE_ID = 118 + CSS_VALUE_ID = 118, + + // This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE. + // The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em. + // When the quirky value is used, if you're in quirks mode, the margin will collapse away + // inside a table cell. This quirk is specified in the HTML spec but our impl is different. + CSS_QUIRKY_EMS = 120 }; // This enum follows the CSSParser::Units enum augmented with UNIT_FREQUENCY for frequencies. @@ -153,43 +155,37 @@ public: UAngle, UTime, UFrequency, - UViewportPercentageLength, #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) UResolution, #endif UOther }; - static UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes); - - bool isAngle() const - { - return m_primitiveUnitType == CSS_DEG - || m_primitiveUnitType == CSS_RAD - || m_primitiveUnitType == CSS_GRAD - || m_primitiveUnitType == CSS_TURN; - } + static UnitCategory unitCategory(UnitType); + + bool isAngle() const; bool isAttr() const { return m_primitiveUnitType == CSS_ATTR; } bool isCounter() const { return m_primitiveUnitType == CSS_COUNTER; } bool isFontIndependentLength() const { return m_primitiveUnitType >= CSS_PX && m_primitiveUnitType <= CSS_PC; } - bool isFontRelativeLength() const - { - return m_primitiveUnitType == CSS_EMS - || m_primitiveUnitType == CSS_EXS - || m_primitiveUnitType == CSS_REMS - || m_primitiveUnitType == CSS_CHS; - } - bool isLength() const - { - unsigned short type = primitiveType(); - return (type >= CSS_EMS && type <= CSS_PC) || type == CSS_REMS || type == CSS_CHS; - } + static bool isFontRelativeLength(UnitType); + bool isFontRelativeLength() const { return isFontRelativeLength(static_cast(m_primitiveUnitType)); } + + bool isQuirkyEms() const { return primitiveType() == UnitType::CSS_QUIRKY_EMS; } + + static bool isViewportPercentageLength(UnitType type) { return type >= CSS_VW && type <= CSS_VMAX; } + bool isViewportPercentageLength() const { return isViewportPercentageLength(static_cast(m_primitiveUnitType)); } + + static bool isLength(UnitType); + bool isLength() const { return isLength(static_cast(primitiveType())); } bool isNumber() const { return primitiveType() == CSS_NUMBER; } bool isPercentage() const { return primitiveType() == CSS_PERCENTAGE; } bool isPx() const { return primitiveType() == CSS_PX; } bool isRect() const { return m_primitiveUnitType == CSS_RECT; } + bool isPair() const { return m_primitiveUnitType == CSS_PAIR; } + bool isPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID; } bool isRGBColor() const { return m_primitiveUnitType == CSS_RGBCOLOR; } bool isShape() const { return m_primitiveUnitType == CSS_SHAPE; } bool isString() const { return m_primitiveUnitType == CSS_STRING; } + bool isFontFamily() const { return m_primitiveUnitType == CSS_FONT_FAMILY; } bool isTime() const { return m_primitiveUnitType == CSS_S || m_primitiveUnitType == CSS_MS; } bool isURI() const { return m_primitiveUnitType == CSS_URI; } bool isCalculated() const { return m_primitiveUnitType == CSS_CALC; } @@ -198,13 +194,9 @@ public: bool isDotsPerInch() const { return primitiveType() == CSS_DPI; } bool isDotsPerPixel() const { return primitiveType() == CSS_DPPX; } bool isDotsPerCentimeter() const { return primitiveType() == CSS_DPCM; } - bool isResolution() const - { - unsigned short type = primitiveType(); - return type >= CSS_DPPX && type <= CSS_DPCM; - } - bool isViewportPercentageLength() const { return m_primitiveUnitType >= CSS_VW && m_primitiveUnitType <= CSS_VMAX; } + static bool isResolution(UnitType); + bool isResolution() const { return isResolution(static_cast(primitiveType())); } bool isViewportPercentageWidth() const { return m_primitiveUnitType == CSS_VW; } bool isViewportPercentageHeight() const { return m_primitiveUnitType == CSS_VH; } bool isViewportPercentageMax() const { return m_primitiveUnitType == CSS_VMAX; } @@ -212,199 +204,223 @@ public: bool isValueID() const { return m_primitiveUnitType == CSS_VALUE_ID; } bool isFlex() const { return primitiveType() == CSS_FR; } - static PassRef createIdentifier(CSSValueID valueID) { return adoptRef(*new CSSPrimitiveValue(valueID)); } - static PassRef createIdentifier(CSSPropertyID propertyID) { return adoptRef(*new CSSPrimitiveValue(propertyID)); } - static PassRef createParserOperator(int parserOperator) { return adoptRef(*new CSSPrimitiveValue(parserOperator)); } + static Ref createIdentifier(CSSValueID valueID) { return adoptRef(*new CSSPrimitiveValue(valueID)); } + static Ref createIdentifier(CSSPropertyID propertyID) { return adoptRef(*new CSSPrimitiveValue(propertyID)); } - static PassRef createColor(unsigned rgbValue) { return adoptRef(*new CSSPrimitiveValue(rgbValue)); } - static PassRef create(double value, UnitTypes type) { return adoptRef(*new CSSPrimitiveValue(value, type)); } - static PassRef create(const String& value, UnitTypes type) { return adoptRef(*new CSSPrimitiveValue(value, type)); } - static PassRef create(const Length& value, const RenderStyle* style) { return adoptRef(*new CSSPrimitiveValue(value, style)); } - static PassRef create(const LengthSize& value) { return adoptRef(*new CSSPrimitiveValue(value)); } + static Ref create(double value, UnitType type) { return adoptRef(*new CSSPrimitiveValue(value, type)); } + static Ref create(const String& value, UnitType type) { return adoptRef(*new CSSPrimitiveValue(value, type)); } + static Ref create(const Length& value, const RenderStyle& style) { return adoptRef(*new CSSPrimitiveValue(value, style)); } + static Ref create(const LengthSize& value, const RenderStyle& style) { return adoptRef(*new CSSPrimitiveValue(value, style)); } - template static PassRef create(T value) - { - return adoptRef(*new CSSPrimitiveValue(value)); - } + template static Ref create(T&&); // This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE. // The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em. // When the quirky value is used, if you're in quirks mode, the margin will collapse away // inside a table cell. - static PassRef createAllowingMarginQuirk(double value, UnitTypes type) - { - CSSPrimitiveValue* quirkValue = new CSSPrimitiveValue(value, type); - quirkValue->m_isQuirkValue = true; - return adoptRef(*quirkValue); - } + static Ref createAllowingMarginQuirk(double value, UnitType); ~CSSPrimitiveValue(); void cleanup(); - unsigned short primitiveType() const; + WEBCORE_EXPORT unsigned short primitiveType() const; + WEBCORE_EXPORT ExceptionOr setFloatValue(unsigned short unitType, double floatValue); + WEBCORE_EXPORT ExceptionOr getFloatValue(unsigned short unitType) const; + WEBCORE_EXPORT ExceptionOr setStringValue(unsigned short stringType, const String& stringValue); + WEBCORE_EXPORT ExceptionOr getStringValue() const; + WEBCORE_EXPORT ExceptionOr getCounterValue() const; + WEBCORE_EXPORT ExceptionOr getRectValue() const; + WEBCORE_EXPORT ExceptionOr> getRGBColorValue() const; + + double computeDegrees() const; + + enum TimeUnit { Seconds, Milliseconds }; + template T computeTime() const; - double computeDegrees(); + template T computeLength(const CSSToLengthConversionData&) const; + template Length convertToLength(const CSSToLengthConversionData&) const; - enum TimeUnit { Seconds, Milliseconds }; - template T computeTime() - { - if (timeUnit == Seconds && m_primitiveUnitType == CSS_S) - return getValue(); - if (timeUnit == Seconds && m_primitiveUnitType == CSS_MS) - return getValue() / 1000; - if (timeUnit == Milliseconds && m_primitiveUnitType == CSS_MS) - return getValue(); - if (timeUnit == Milliseconds && m_primitiveUnitType == CSS_S) - return getValue() * 1000; - ASSERT_NOT_REACHED(); - return 0; - } - - /* - * computes a length in pixels out of the given CSSValue. Need the RenderStyle to get - * the fontinfo in case val is defined in em or ex. - * - * The metrics have to be a bit different for screen and printer output. - * For screen output we assume 1 inch == 72 px, for printer we assume 300 dpi - * - * this is screen/printer dependent, so we probably need a config option for this, - * and some tool to calibrate. - */ - template T computeLength(const RenderStyle* currStyle, const RenderStyle* rootStyle, float multiplier = 1.0f, bool computingFontSize = false) const; - - // Converts to a Length, mapping various unit types appropriately. - template Length convertToLength(const RenderStyle* currStyle, const RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const; - - // use with care!!! - void setPrimitiveType(unsigned short type) { m_primitiveUnitType = type; } - - double getDoubleValue(unsigned short unitType, ExceptionCode&) const; - double getDoubleValue(unsigned short unitType) const; - double getDoubleValue() const; - - void setFloatValue(unsigned short unitType, double floatValue, ExceptionCode&); - float getFloatValue(unsigned short unitType, ExceptionCode& ec) const { return getValue(unitType, ec); } - float getFloatValue(unsigned short unitType) const { return getValue(unitType); } - float getFloatValue() const { return getValue(); } - - int getIntValue(unsigned short unitType, ExceptionCode& ec) const { return getValue(unitType, ec); } - int getIntValue(unsigned short unitType) const { return getValue(unitType); } - int getIntValue() const { return getValue(); } - - template inline T getValue(unsigned short unitType, ExceptionCode& ec) const { return clampTo(getDoubleValue(unitType, ec)); } - template inline T getValue(unsigned short unitType) const { return clampTo(getDoubleValue(unitType)); } - template inline T getValue() const { return clampTo(getDoubleValue()); } - - void setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode&); - String getStringValue(ExceptionCode&) const; - String getStringValue() const; - - Counter* getCounterValue(ExceptionCode&) const; - Counter* getCounterValue() const { return m_primitiveUnitType != CSS_COUNTER ? 0 : m_value.counter; } - - Rect* getRectValue(ExceptionCode&) const; - Rect* getRectValue() const { return m_primitiveUnitType != CSS_RECT ? 0 : m_value.rect; } - - Quad* getQuadValue(ExceptionCode&) const; - Quad* getQuadValue() const { return m_primitiveUnitType != CSS_QUAD ? 0 : m_value.quad; } - - PassRefPtr getRGBColorValue(ExceptionCode&) const; - RGBA32 getRGBA32Value() const { return m_primitiveUnitType != CSS_RGBCOLOR ? 0 : m_value.rgbcolor; } - - Pair* getPairValue(ExceptionCode&) const; - Pair* getPairValue() const { return m_primitiveUnitType != CSS_PAIR ? 0 : m_value.pair; } + bool convertingToLengthRequiresNonNullStyle(int lengthConversion) const; -#if ENABLE(DASHBOARD_SUPPORT) - DashboardRegion* getDashboardRegionValue() const { return m_primitiveUnitType != CSS_DASHBOARD_REGION ? 0 : m_value.region; } -#endif + double doubleValue(UnitType) const; + double doubleValue() const; - CSSBasicShape* getShapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? 0 : m_value.shape; } + template inline T value(UnitType type) const { return clampTo(doubleValue(type)); } + template inline T value() const { return clampTo(doubleValue()); } - CSSCalcValue* cssCalcValue() const { return m_primitiveUnitType != CSS_CALC ? 0 : m_value.calc; } + float floatValue(UnitType type) const { return value(type); } + float floatValue() const { return value(); } - CSSPropertyID getPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID ? m_value.propertyID : CSSPropertyInvalid; } - CSSValueID getValueID() const { return m_primitiveUnitType == CSS_VALUE_ID ? m_value.valueID : CSSValueInvalid; } + int intValue(UnitType type) const { return value(type); } + int intValue() const { return value(); } - template inline operator T() const; // Defined in CSSPrimitiveValueMappings.h + WEBCORE_EXPORT String stringValue() const; - String customCSSText() const; + const Color& color() const { ASSERT(m_primitiveUnitType == CSS_RGBCOLOR); return *m_value.color; } + Counter* counterValue() const { return m_primitiveUnitType != CSS_COUNTER ? nullptr : m_value.counter; } + CSSCalcValue* cssCalcValue() const { return m_primitiveUnitType != CSS_CALC ? nullptr : m_value.calc; } + const CSSFontFamily& fontFamily() const { ASSERT(m_primitiveUnitType == CSS_FONT_FAMILY); return *m_value.fontFamily; } + Pair* pairValue() const { return m_primitiveUnitType != CSS_PAIR ? nullptr : m_value.pair; } + CSSPropertyID propertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID ? m_value.propertyID : CSSPropertyInvalid; } + Quad* quadValue() const { return m_primitiveUnitType != CSS_QUAD ? nullptr : m_value.quad; } + Rect* rectValue() const { return m_primitiveUnitType != CSS_RECT ? nullptr : m_value.rect; } + CSSBasicShape* shapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? nullptr : m_value.shape; } + CSSValueID valueID() const { return m_primitiveUnitType == CSS_VALUE_ID ? m_value.valueID : CSSValueInvalid; } - bool isQuirkValue() { return m_isQuirkValue; } +#if ENABLE(DASHBOARD_SUPPORT) + DashboardRegion* dashboardRegionValue() const { return m_primitiveUnitType != CSS_DASHBOARD_REGION ? nullptr : m_value.region; } +#endif - void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; + template inline operator T() const; // Defined in CSSPrimitiveValueMappings.h - Length viewportPercentageLength() const; + String customCSSText() const; - PassRefPtr cloneForCSSOM() const; - void setCSSOMSafe() { m_isCSSOMSafe = true; } + // FIXME-NEWPARSER: Can ditch the boolean and just use the unit type once old parser is gone. + bool isQuirkValue() const { return m_isQuirkValue || primitiveType() == CSS_QUIRKY_EMS; } bool equals(const CSSPrimitiveValue&) const; - static UnitTypes canonicalUnitTypeForCategory(UnitCategory); - static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType); + static UnitType canonicalUnitTypeForCategory(UnitCategory); + static double conversionToCanonicalUnitsScaleFactor(UnitType); + static double computeNonCalcLengthDouble(const CSSToLengthConversionData&, UnitType, double value); + + Ref createDeprecatedCSSOMPrimitiveWrapper() const; + +#if COMPILER(MSVC) + // FIXME: This should be private, but for some reason MSVC then fails to invoke it from LazyNeverDestroyed::construct. +public: +#else private: + friend class CSSValuePool; + friend class LazyNeverDestroyed; +#endif + CSSPrimitiveValue(CSSValueID); CSSPrimitiveValue(CSSPropertyID); - // FIXME: int vs. unsigned overloading is too subtle to distinguish the color and operator cases. - CSSPrimitiveValue(int parserOperator); - CSSPrimitiveValue(unsigned color); // RGB value + CSSPrimitiveValue(const Color&); CSSPrimitiveValue(const Length&); - CSSPrimitiveValue(const Length&, const RenderStyle*); - CSSPrimitiveValue(const LengthSize&); - CSSPrimitiveValue(const String&, UnitTypes); - CSSPrimitiveValue(double, UnitTypes); + CSSPrimitiveValue(const Length&, const RenderStyle&); + CSSPrimitiveValue(const LengthSize&, const RenderStyle&); + CSSPrimitiveValue(const String&, UnitType); + CSSPrimitiveValue(double, UnitType); template CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h - template CSSPrimitiveValue(T* val) - : CSSValue(PrimitiveClass) - { - init(PassRefPtr(val)); - } - - template CSSPrimitiveValue(PassRefPtr val) - : CSSValue(PrimitiveClass) - { - init(val); - } + template CSSPrimitiveValue(RefPtr&&); + template CSSPrimitiveValue(Ref&&); static void create(int); // compile-time guard static void create(unsigned); // compile-time guard template operator T*(); // compile-time guard void init(const Length&); - void init(const LengthSize&); - void init(PassRefPtr); - void init(PassRefPtr); - void init(PassRefPtr); - void init(PassRefPtr); - void init(PassRefPtr); // FIXME: Dashboard region should not be a primitive value. - void init(PassRefPtr); - void init(PassRefPtr); - bool getDoubleValueInternal(UnitTypes targetUnitType, double* result) const; - - double computeLengthDouble(const RenderStyle* currentStyle, const RenderStyle* rootStyle, float multiplier, bool computingFontSize) const; + void init(const LengthSize&, const RenderStyle&); + void init(Ref&&); + void init(RefPtr&&); + void init(Ref&&); + void init(Ref&&); + void init(Ref&&); + void init(Ref&&); + +#if ENABLE(DASHBOARD_SUPPORT) + void init(RefPtr&&); // FIXME: Dashboard region should not be a primitive value. +#endif + + std::optional doubleValueInternal(UnitType targetUnitType) const; + + double computeLengthDouble(const CSSToLengthConversionData&) const; + + ALWAYS_INLINE String formatNumberForCustomCSSText() const; + template ALWAYS_INLINE Ref formatNumberValue(const char (&characters)[characterCount]) const; + NEVER_INLINE Ref formatNumberValue(const char* suffix, unsigned suffixLength) const; union { CSSPropertyID propertyID; CSSValueID valueID; - int parserOperator; double num; StringImpl* string; Counter* counter; Rect* rect; Quad* quad; - unsigned rgbcolor; + const Color* color; Pair* pair; DashboardRegion* region; CSSBasicShape* shape; CSSCalcValue* calc; + const CSSFontFamily* fontFamily; } m_value; }; -CSS_VALUE_TYPE_CASTS(CSSPrimitiveValue, isPrimitiveValue()) +inline bool CSSPrimitiveValue::isAngle() const +{ + return m_primitiveUnitType == CSS_DEG + || m_primitiveUnitType == CSS_RAD + || m_primitiveUnitType == CSS_GRAD + || m_primitiveUnitType == CSS_TURN; +} + +inline bool CSSPrimitiveValue::isFontRelativeLength(UnitType type) +{ + return type == CSS_EMS + || type == CSS_EXS + || type == CSS_REMS + || type == CSS_CHS + || type == CSS_QUIRKY_EMS; +} + +inline bool CSSPrimitiveValue::isLength(UnitType type) +{ + return (type >= CSS_EMS && type <= CSS_PC) + || type == CSS_REMS + || type == CSS_CHS + || isViewportPercentageLength(type) + || type == CSS_QUIRKY_EMS; +} + +inline bool CSSPrimitiveValue::isResolution(UnitType type) +{ + return type >= CSS_DPPX && type <= CSS_DPCM; +} + +template inline Ref CSSPrimitiveValue::create(T&& value) +{ + return adoptRef(*new CSSPrimitiveValue(std::forward(value))); +} + +inline Ref CSSPrimitiveValue::createAllowingMarginQuirk(double value, UnitType type) +{ + auto result = adoptRef(*new CSSPrimitiveValue(value, type)); + result->m_isQuirkValue = true; + return result; +} + +template inline T CSSPrimitiveValue::computeTime() const +{ + if (timeUnit == Seconds && primitiveType() == CSS_S) + return value(); + if (timeUnit == Seconds && primitiveType() == CSS_MS) + return value() / 1000; + if (timeUnit == Milliseconds && primitiveType() == CSS_MS) + return value(); + if (timeUnit == Milliseconds && primitiveType() == CSS_S) + return value() * 1000; + ASSERT_NOT_REACHED(); + return 0; +} + +template inline CSSPrimitiveValue::CSSPrimitiveValue(RefPtr&& value) + : CSSValue(PrimitiveClass) +{ + init(WTFMove(value)); +} + +template inline CSSPrimitiveValue::CSSPrimitiveValue(Ref&& value) + : CSSValue(PrimitiveClass) +{ + init(WTFMove(value)); +} } // namespace WebCore -#endif // CSSPrimitiveValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSPrimitiveValue, isPrimitiveValue()) diff --git a/Source/WebCore/css/CSSPrimitiveValue.idl b/Source/WebCore/css/CSSPrimitiveValue.idl deleted file mode 100644 index 6e93645c6..000000000 --- a/Source/WebCore/css/CSSPrimitiveValue.idl +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2006, 2008 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -[ - ImplementationLacksVTable, -] interface CSSPrimitiveValue : CSSValue { - - // UnitTypes - const unsigned short CSS_UNKNOWN = 0; - const unsigned short CSS_NUMBER = 1; - const unsigned short CSS_PERCENTAGE = 2; - const unsigned short CSS_EMS = 3; - const unsigned short CSS_EXS = 4; - const unsigned short CSS_PX = 5; - const unsigned short CSS_CM = 6; - const unsigned short CSS_MM = 7; - const unsigned short CSS_IN = 8; - const unsigned short CSS_PT = 9; - const unsigned short CSS_PC = 10; - const unsigned short CSS_DEG = 11; - const unsigned short CSS_RAD = 12; - const unsigned short CSS_GRAD = 13; - const unsigned short CSS_MS = 14; - const unsigned short CSS_S = 15; - const unsigned short CSS_HZ = 16; - const unsigned short CSS_KHZ = 17; - const unsigned short CSS_DIMENSION = 18; - const unsigned short CSS_STRING = 19; - const unsigned short CSS_URI = 20; - const unsigned short CSS_IDENT = 21; - const unsigned short CSS_ATTR = 22; - const unsigned short CSS_COUNTER = 23; - const unsigned short CSS_RECT = 24; - const unsigned short CSS_RGBCOLOR = 25; - const unsigned short CSS_VW = 26; - const unsigned short CSS_VH = 27; - const unsigned short CSS_VMIN = 28; - const unsigned short CSS_VMAX = 29; - - readonly attribute unsigned short primitiveType; - - [ObjCLegacyUnnamedParameters, RaisesException] void setFloatValue([Default=Undefined] optional unsigned short unitType, - [Default=Undefined] optional float floatValue); - [RaisesException] float getFloatValue([Default=Undefined] optional unsigned short unitType); - [ObjCLegacyUnnamedParameters, RaisesException] void setStringValue([Default=Undefined] optional unsigned short stringType, - [Default=Undefined] optional DOMString stringValue); - [RaisesException] DOMString getStringValue(); - [RaisesException] Counter getCounterValue(); - [RaisesException] Rect getRectValue(); - [RaisesException] RGBColor getRGBColorValue(); -}; - diff --git a/Source/WebCore/css/CSSPrimitiveValueMappings.h b/Source/WebCore/css/CSSPrimitiveValueMappings.h index 9a6260c8c..d9dbdb751 100644 --- a/Source/WebCore/css/CSSPrimitiveValueMappings.h +++ b/Source/WebCore/css/CSSPrimitiveValueMappings.h @@ -27,33 +27,30 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSPrimitiveValueMappings_h -#define CSSPrimitiveValueMappings_h +#pragma once #include "CSSCalculationValue.h" +#include "CSSFontFamily.h" #include "CSSPrimitiveValue.h" #include "CSSReflectionDirection.h" -#include "ColorSpace.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" -#include "FontDescription.h" -#include "FontSmoothingMode.h" #include "GraphicsTypes.h" -#if ENABLE(CSS_IMAGE_ORIENTATION) -#include "ImageOrientation.h" -#endif #include "Length.h" #include "LineClampValue.h" #include "Path.h" #include "RenderStyleConstants.h" #include "SVGRenderStyleDefs.h" -#include "TextDirection.h" -#include "TextRenderingMode.h" +#include "TextFlags.h" #include "ThemeTypes.h" #include "UnicodeBidi.h" #include "WritingMode.h" - #include +#if ENABLE(CSS_IMAGE_ORIENTATION) +#include "ImageOrientation.h" +#endif + namespace WebCore { template<> inline CSSPrimitiveValue::CSSPrimitiveValue(short i) @@ -81,8 +78,8 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(unsigned short i) template<> inline CSSPrimitiveValue::operator unsigned short() const { - if (m_primitiveUnitType == CSS_NUMBER) - return clampTo(m_value.num); + if (primitiveType() == CSS_NUMBER) + return value(); ASSERT_NOT_REACHED(); return 0; @@ -90,8 +87,8 @@ template<> inline CSSPrimitiveValue::operator unsigned short() const template<> inline CSSPrimitiveValue::operator int() const { - if (m_primitiveUnitType == CSS_NUMBER) - return clampTo(m_value.num); + if (primitiveType() == CSS_NUMBER) + return value(); ASSERT_NOT_REACHED(); return 0; @@ -99,8 +96,8 @@ template<> inline CSSPrimitiveValue::operator int() const template<> inline CSSPrimitiveValue::operator unsigned() const { - if (m_primitiveUnitType == CSS_NUMBER) - return clampTo(m_value.num); + if (primitiveType() == CSS_NUMBER) + return value(); ASSERT_NOT_REACHED(); return 0; @@ -116,8 +113,8 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(float i) template<> inline CSSPrimitiveValue::operator float() const { - if (m_primitiveUnitType == CSS_NUMBER) - return clampTo(m_value.num); + if (primitiveType() == CSS_NUMBER) + return value(); ASSERT_NOT_REACHED(); return 0.0f; @@ -132,11 +129,11 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineClampValue i) template<> inline CSSPrimitiveValue::operator LineClampValue() const { - if (m_primitiveUnitType == CSS_NUMBER) - return LineClampValue(clampTo(m_value.num), LineClampLineCount); + if (primitiveType() == CSS_NUMBER) + return LineClampValue(value(), LineClampLineCount); - if (m_primitiveUnitType == CSS_PERCENTAGE) - return LineClampValue(clampTo(m_value.num), LineClampPercentage); + if (primitiveType() == CSS_PERCENTAGE) + return LineClampValue(value(), LineClampPercentage); ASSERT_NOT_REACHED(); return LineClampValue(); @@ -525,6 +522,12 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e) case MediaTimeRemainingPart: m_value.valueID = CSSValueMediaTimeRemainingDisplay; break; + case MediaControlsLightBarBackgroundPart: + m_value.valueID = CSSValueMediaControlsLightBarBackground; + break; + case MediaControlsDarkBarBackgroundPart: + m_value.valueID = CSSValueMediaControlsDarkBarBackground; + break; case MenulistPart: m_value.valueID = CSSValueMenulist; break; @@ -553,14 +556,10 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e) m_value.valueID = CSSValueRatingLevelIndicator; break; case ProgressBarPart: -#if ENABLE(PROGRESS_ELEMENT) m_value.valueID = CSSValueProgressBar; -#endif break; case ProgressBarValuePart: -#if ENABLE(PROGRESS_ELEMENT) m_value.valueID = CSSValueProgressBarValue; -#endif break; case SliderHorizontalPart: m_value.valueID = CSSValueSliderHorizontal; @@ -604,11 +603,21 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e) case CapsLockIndicatorPart: m_value.valueID = CSSValueCapsLockIndicator; break; - case InputSpeechButtonPart: -#if ENABLE(INPUT_SPEECH) - m_value.valueID = CSSValueWebkitInputSpeechButton; +#if ENABLE(ATTACHMENT_ELEMENT) + case AttachmentPart: + m_value.valueID = CSSValueAttachment; + break; +#endif +#if ENABLE(SERVICE_CONTROLS) + case ImageControlsButtonPart: + m_value.valueID = CSSValueImageControlsButton; + break; #endif +#if ENABLE(APPLE_PAY) + case ApplePayButtonPart: + m_value.valueID = CSSValueApplePayButton; break; +#endif } } @@ -895,45 +904,45 @@ template<> inline CSSPrimitiveValue::operator EBoxDecorationBreak() const } #endif -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BackgroundEdgeOrigin e) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Edge e) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; switch (e) { - case TopEdge: + case Edge::Top: m_value.valueID = CSSValueTop; break; - case RightEdge: + case Edge::Right: m_value.valueID = CSSValueRight; break; - case BottomEdge: + case Edge::Bottom: m_value.valueID = CSSValueBottom; break; - case LeftEdge: + case Edge::Left: m_value.valueID = CSSValueLeft; break; } } -template<> inline CSSPrimitiveValue::operator BackgroundEdgeOrigin() const +template<> inline CSSPrimitiveValue::operator Edge() const { ASSERT(isValueID()); switch (m_value.valueID) { case CSSValueTop: - return TopEdge; + return Edge::Top; case CSSValueRight: - return RightEdge; + return Edge::Right; case CSSValueBottom: - return BottomEdge; + return Edge::Bottom; case CSSValueLeft: - return LeftEdge; + return Edge::Left; default: break; } ASSERT_NOT_REACHED(); - return TopEdge; + return Edge::Top; } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxSizing e) @@ -1149,112 +1158,112 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECursor e) { m_primitiveUnitType = CSS_VALUE_ID; switch (e) { - case CURSOR_AUTO: + case CursorAuto: m_value.valueID = CSSValueAuto; break; - case CURSOR_CROSS: + case CursorCross: m_value.valueID = CSSValueCrosshair; break; - case CURSOR_DEFAULT: + case CursorDefault: m_value.valueID = CSSValueDefault; break; - case CURSOR_POINTER: + case CursorPointer: m_value.valueID = CSSValuePointer; break; - case CURSOR_MOVE: + case CursorMove: m_value.valueID = CSSValueMove; break; - case CURSOR_CELL: + case CursorCell: m_value.valueID = CSSValueCell; break; - case CURSOR_VERTICAL_TEXT: + case CursorVerticalText: m_value.valueID = CSSValueVerticalText; break; - case CURSOR_CONTEXT_MENU: + case CursorContextMenu: m_value.valueID = CSSValueContextMenu; break; - case CURSOR_ALIAS: + case CursorAlias: m_value.valueID = CSSValueAlias; break; - case CURSOR_COPY: + case CursorCopy: m_value.valueID = CSSValueCopy; break; - case CURSOR_NONE: + case CursorNone: m_value.valueID = CSSValueNone; break; - case CURSOR_PROGRESS: + case CursorProgress: m_value.valueID = CSSValueProgress; break; - case CURSOR_NO_DROP: + case CursorNoDrop: m_value.valueID = CSSValueNoDrop; break; - case CURSOR_NOT_ALLOWED: + case CursorNotAllowed: m_value.valueID = CSSValueNotAllowed; break; - case CURSOR_WEBKIT_ZOOM_IN: - m_value.valueID = CSSValueWebkitZoomIn; + case CursorZoomIn: + m_value.valueID = CSSValueZoomIn; break; - case CURSOR_WEBKIT_ZOOM_OUT: - m_value.valueID = CSSValueWebkitZoomOut; + case CursorZoomOut: + m_value.valueID = CSSValueZoomOut; break; - case CURSOR_E_RESIZE: + case CursorEResize: m_value.valueID = CSSValueEResize; break; - case CURSOR_NE_RESIZE: + case CursorNeResize: m_value.valueID = CSSValueNeResize; break; - case CURSOR_NW_RESIZE: + case CursorNwResize: m_value.valueID = CSSValueNwResize; break; - case CURSOR_N_RESIZE: + case CursorNResize: m_value.valueID = CSSValueNResize; break; - case CURSOR_SE_RESIZE: + case CursorSeResize: m_value.valueID = CSSValueSeResize; break; - case CURSOR_SW_RESIZE: + case CursorSwResize: m_value.valueID = CSSValueSwResize; break; - case CURSOR_S_RESIZE: + case CursorSResize: m_value.valueID = CSSValueSResize; break; - case CURSOR_W_RESIZE: + case CursorWResize: m_value.valueID = CSSValueWResize; break; - case CURSOR_EW_RESIZE: + case CursorEwResize: m_value.valueID = CSSValueEwResize; break; - case CURSOR_NS_RESIZE: + case CursorNsResize: m_value.valueID = CSSValueNsResize; break; - case CURSOR_NESW_RESIZE: + case CursorNeswResize: m_value.valueID = CSSValueNeswResize; break; - case CURSOR_NWSE_RESIZE: + case CursorNwseResize: m_value.valueID = CSSValueNwseResize; break; - case CURSOR_COL_RESIZE: + case CursorColResize: m_value.valueID = CSSValueColResize; break; - case CURSOR_ROW_RESIZE: + case CursorRowResize: m_value.valueID = CSSValueRowResize; break; - case CURSOR_TEXT: + case CursorText: m_value.valueID = CSSValueText; break; - case CURSOR_WAIT: + case CursorWait: m_value.valueID = CSSValueWait; break; - case CURSOR_HELP: + case CursorHelp: m_value.valueID = CSSValueHelp; break; - case CURSOR_ALL_SCROLL: + case CursorAllScroll: m_value.valueID = CSSValueAllScroll; break; - case CURSOR_WEBKIT_GRAB: + case CursorWebkitGrab: m_value.valueID = CSSValueWebkitGrab; break; - case CURSOR_WEBKIT_GRABBING: + case CursorWebkitGrabbing: m_value.valueID = CSSValueWebkitGrabbing; break; } @@ -1263,15 +1272,20 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECursor e) template<> inline CSSPrimitiveValue::operator ECursor() const { ASSERT(isValueID()); - - if (m_value.valueID == CSSValueCopy) - return CURSOR_COPY; - if (m_value.valueID == CSSValueNone) - return CURSOR_NONE; - return static_cast(m_value.valueID - CSSValueAuto); + switch (m_value.valueID) { + case CSSValueCopy: + return CursorCopy; + case CSSValueWebkitZoomIn: + return CursorZoomIn; + case CSSValueWebkitZoomOut: + return CursorZoomOut; + case CSSValueNone: + return CursorNone; + default: + return static_cast(m_value.valueID - CSSValueAuto); + } } - #if ENABLE(CURSOR_VISIBILITY) template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CursorVisibility e) : CSSValue(PrimitiveClass) @@ -1315,9 +1329,6 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EDisplay e) case LIST_ITEM: m_value.valueID = CSSValueListItem; break; - case RUN_IN: - m_value.valueID = CSSValueRunIn; - break; case COMPACT: m_value.valueID = CSSValueCompact; break; @@ -1361,20 +1372,25 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EDisplay e) m_value.valueID = CSSValueWebkitInlineBox; break; case FLEX: - m_value.valueID = CSSValueWebkitFlex; + case WEBKIT_FLEX: + m_value.valueID = CSSValueFlex; break; case INLINE_FLEX: - m_value.valueID = CSSValueWebkitInlineFlex; + case WEBKIT_INLINE_FLEX: + m_value.valueID = CSSValueInlineFlex; break; case GRID: - m_value.valueID = CSSValueWebkitGrid; + m_value.valueID = CSSValueGrid; break; case INLINE_GRID: - m_value.valueID = CSSValueWebkitInlineGrid; + m_value.valueID = CSSValueInlineGrid; break; case NONE: m_value.valueID = CSSValueNone; break; + case CONTENTS: + m_value.valueID = CSSValueContents; + break; } } @@ -1387,6 +1403,10 @@ template<> inline CSSPrimitiveValue::operator EDisplay() const EDisplay display = static_cast(m_value.valueID - CSSValueInline); ASSERT(display >= INLINE && display <= NONE); + if (display == WEBKIT_FLEX) + return FLEX; + if (display == WEBKIT_INLINE_FLEX) + return INLINE_FLEX; return display; } @@ -1421,103 +1441,6 @@ template<> inline CSSPrimitiveValue::operator EEmptyCell() const return SHOW; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EAlignItems e) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (e) { - case AlignAuto: - m_value.valueID = CSSValueAuto; - break; - case AlignFlexStart: - m_value.valueID = CSSValueFlexStart; - break; - case AlignFlexEnd: - m_value.valueID = CSSValueFlexEnd; - break; - case AlignCenter: - m_value.valueID = CSSValueCenter; - break; - case AlignStretch: - m_value.valueID = CSSValueStretch; - break; - case AlignBaseline: - m_value.valueID = CSSValueBaseline; - break; - } -} - -template<> inline CSSPrimitiveValue::operator EAlignItems() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueAuto: - return AlignAuto; - case CSSValueFlexStart: - return AlignFlexStart; - case CSSValueFlexEnd: - return AlignFlexEnd; - case CSSValueCenter: - return AlignCenter; - case CSSValueStretch: - return AlignStretch; - case CSSValueBaseline: - return AlignBaseline; - default: - break; - } - - ASSERT_NOT_REACHED(); - return AlignFlexStart; -} - -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EJustifyContent e) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (e) { - case JustifyFlexStart: - m_value.valueID = CSSValueFlexStart; - break; - case JustifyFlexEnd: - m_value.valueID = CSSValueFlexEnd; - break; - case JustifyCenter: - m_value.valueID = CSSValueCenter; - break; - case JustifySpaceBetween: - m_value.valueID = CSSValueSpaceBetween; - break; - case JustifySpaceAround: - m_value.valueID = CSSValueSpaceAround; - break; - } -} - -template<> inline CSSPrimitiveValue::operator EJustifyContent() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueFlexStart: - return JustifyFlexStart; - case CSSValueFlexEnd: - return JustifyFlexEnd; - case CSSValueCenter: - return JustifyCenter; - case CSSValueSpaceBetween: - return JustifySpaceBetween; - case CSSValueSpaceAround: - return JustifySpaceAround; - default: - break; - } - - ASSERT_NOT_REACHED(); - return JustifyFlexStart; -} - template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexDirection e) : CSSValue(PrimitiveClass) { @@ -1706,6 +1629,29 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineBreak e) } } +template<> inline CSSPrimitiveValue::operator HangingPunctuation() const +{ + ASSERT(isValueID()); + + switch (m_value.valueID) { + case CSSValueNone: + return NoHangingPunctuation; + case CSSValueFirst: + return FirstHangingPunctuation; + case CSSValueLast: + return LastHangingPunctuation; + case CSSValueAllowEnd: + return AllowEndHangingPunctuation; + case CSSValueForceEnd: + return ForceEndHangingPunctuation; + default: + break; + } + + ASSERT_NOT_REACHED(); + return NoHangingPunctuation; +} + template<> inline CSSPrimitiveValue::operator LineBreak() const { ASSERT(isValueID()); @@ -2237,9 +2183,6 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EOverflow e) case OAUTO: m_value.valueID = CSSValueAuto; break; - case OMARQUEE: - m_value.valueID = CSSValueWebkitMarquee; - break; case OOVERLAY: m_value.valueID = CSSValueOverlay; break; @@ -2265,8 +2208,6 @@ template<> inline CSSPrimitiveValue::operator EOverflow() const return OSCROLL; case CSSValueAuto: return OAUTO; - case CSSValueWebkitMarquee: - return OMARQUEE; case CSSValueOverlay: return OOVERLAY; case CSSValueWebkitPagedX: @@ -2281,42 +2222,131 @@ template<> inline CSSPrimitiveValue::operator EOverflow() const return OVISIBLE; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPageBreak e) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BreakBetween e) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; switch (e) { - case PBAUTO: + case AutoBreakBetween: m_value.valueID = CSSValueAuto; break; - case PBALWAYS: - m_value.valueID = CSSValueAlways; - break; - case PBAVOID: + case AvoidBreakBetween: m_value.valueID = CSSValueAvoid; break; + case AvoidColumnBreakBetween: + m_value.valueID = CSSValueAvoidColumn; + break; + case AvoidPageBreakBetween: + m_value.valueID = CSSValueAvoidPage; + break; + case AvoidRegionBreakBetween: + m_value.valueID = CSSValueAvoidRegion; + break; + case ColumnBreakBetween: + m_value.valueID = CSSValueColumn; + break; + case PageBreakBetween: + m_value.valueID = CSSValuePage; + break; + case RegionBreakBetween: + m_value.valueID = CSSValueRegion; + break; + case LeftPageBreakBetween: + m_value.valueID = CSSValueLeft; + break; + case RightPageBreakBetween: + m_value.valueID = CSSValueRight; + break; + case RectoPageBreakBetween: + m_value.valueID = CSSValueRecto; + break; + case VersoPageBreakBetween: + m_value.valueID = CSSValueVerso; + break; } } -template<> inline CSSPrimitiveValue::operator EPageBreak() const +template<> inline CSSPrimitiveValue::operator BreakBetween() const { ASSERT(isValueID()); switch (m_value.valueID) { case CSSValueAuto: - return PBAUTO; + return AutoBreakBetween; + case CSSValueAvoid: + return AvoidBreakBetween; + case CSSValueAvoidColumn: + return AvoidColumnBreakBetween; + case CSSValueAvoidPage: + return AvoidPageBreakBetween; + case CSSValueAvoidRegion: + return AvoidRegionBreakBetween; + case CSSValueColumn: + return ColumnBreakBetween; + case CSSValuePage: + return PageBreakBetween; + case CSSValueRegion: + return RegionBreakBetween; case CSSValueLeft: + return LeftPageBreakBetween; case CSSValueRight: - case CSSValueAlways: - return PBALWAYS; // CSS2.1: "Conforming user agents may map left/right to always." + return RightPageBreakBetween; + case CSSValueRecto: + return RectoPageBreakBetween; + case CSSValueVerso: + return VersoPageBreakBetween; + default: + break; + } + + ASSERT_NOT_REACHED(); + return AutoBreakBetween; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BreakInside e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (e) { + case AutoBreakInside: + m_value.valueID = CSSValueAuto; + break; + case AvoidBreakInside: + m_value.valueID = CSSValueAvoid; + break; + case AvoidColumnBreakInside: + m_value.valueID = CSSValueAvoidColumn; + break; + case AvoidPageBreakInside: + m_value.valueID = CSSValueAvoidPage; + break; + case AvoidRegionBreakInside: + m_value.valueID = CSSValueAvoidRegion; + break; + } +} + +template<> inline CSSPrimitiveValue::operator BreakInside() const +{ + ASSERT(isValueID()); + + switch (m_value.valueID) { + case CSSValueAuto: + return AutoBreakInside; case CSSValueAvoid: - return PBAVOID; + return AvoidBreakInside; + case CSSValueAvoidColumn: + return AvoidColumnBreakInside; + case CSSValueAvoidPage: + return AvoidPageBreakInside; + case CSSValueAvoidRegion: + return AvoidRegionBreakInside; default: break; } ASSERT_NOT_REACHED(); - return PBAUTO; + return AutoBreakInside; } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPosition e) @@ -2337,9 +2367,7 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPosition e) m_value.valueID = CSSValueFixed; break; case StickyPosition: -#if ENABLE(CSS_STICKY_POSITION) m_value.valueID = CSSValueWebkitSticky; -#endif break; } } @@ -2357,10 +2385,8 @@ template<> inline CSSPrimitiveValue::operator EPosition() const return AbsolutePosition; case CSSValueFixed: return FixedPosition; -#if ENABLE(CSS_STICKY_POSITION) case CSSValueWebkitSticky: return StickyPosition; -#endif default: break; } @@ -2565,18 +2591,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextJustify e) case TextJustifyInterWord: m_value.valueID = CSSValueInterWord; break; - case TextJustifyInterIdeograph: - m_value.valueID = CSSValueInterIdeograph; - break; - case TextJustifyInterCluster: - m_value.valueID = CSSValueInterCluster; - break; case TextJustifyDistribute: m_value.valueID = CSSValueDistribute; break; - case TextJustifyKashida: - m_value.valueID = CSSValueKashida; - break; } } @@ -2591,14 +2608,8 @@ template<> inline CSSPrimitiveValue::operator TextJustify() const return TextJustifyNone; case CSSValueInterWord: return TextJustifyInterWord; - case CSSValueInterIdeograph: - return TextJustifyInterIdeograph; - case CSSValueInterCluster: - return TextJustifyInterCluster; case CSSValueDistribute: return TextJustifyDistribute; - case CSSValueKashida: - return TextJustifyKashida; default: break; } @@ -3109,6 +3120,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWordBreak e) case BreakAllWordBreak: m_value.valueID = CSSValueBreakAll; break; + case KeepAllWordBreak: + m_value.valueID = CSSValueKeepAll; + break; case BreakWordBreak: m_value.valueID = CSSValueBreakWord; break; @@ -3122,6 +3136,8 @@ template<> inline CSSPrimitiveValue::operator EWordBreak() const switch (m_value.valueID) { case CSSValueBreakAll: return BreakAllWordBreak; + case CSSValueKeepAll: + return KeepAllWordBreak; case CSSValueBreakWord: return BreakWordBreak; case CSSValueNormal: @@ -3222,8 +3238,13 @@ template<> inline CSSPrimitiveValue::operator WritingMode() const switch (m_value.valueID) { case CSSValueHorizontalTb: + case CSSValueLrTb: + case CSSValueRl: + case CSSValueRlTb: return TopToBottomWritingMode; case CSSValueVerticalRl: + case CSSValueTb: + case CSSValueTbRl: return RightToLeftWritingMode; case CSSValueVerticalLr: return LeftToRightWritingMode; @@ -3279,6 +3300,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(RubyPosition position) case RubyPositionAfter: m_value.valueID = CSSValueAfter; break; + case RubyPositionInterCharacter: + m_value.valueID = CSSValueInterCharacter; + break; } } @@ -3291,6 +3315,8 @@ template<> inline CSSPrimitiveValue::operator RubyPosition() const return RubyPositionBefore; case CSSValueAfter: return RubyPositionAfter; + case CSSValueInterCharacter: + return RubyPositionInterCharacter; default: break; } @@ -3420,16 +3446,13 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextOrientation e) { m_primitiveUnitType = CSS_VALUE_ID; switch (e) { - case TextOrientationSideways: + case TextOrientation::Sideways: m_value.valueID = CSSValueSideways; break; - case TextOrientationSidewaysRight: - m_value.valueID = CSSValueSidewaysRight; + case TextOrientation::Mixed: + m_value.valueID = CSSValueMixed; break; - case TextOrientationVerticalRight: - m_value.valueID = CSSValueVerticalRight; - break; - case TextOrientationUpright: + case TextOrientation::Upright: m_value.valueID = CSSValueUpright; break; } @@ -3441,19 +3464,21 @@ template<> inline CSSPrimitiveValue::operator TextOrientation() const switch (m_value.valueID) { case CSSValueSideways: - return TextOrientationSideways; + return TextOrientation::Sideways; case CSSValueSidewaysRight: - return TextOrientationSidewaysRight; + return TextOrientation::Sideways; case CSSValueVerticalRight: - return TextOrientationVerticalRight; + return TextOrientation::Mixed; + case CSSValueMixed: + return TextOrientation::Mixed; case CSSValueUpright: - return TextOrientationUpright; + return TextOrientation::Upright; default: break; } ASSERT_NOT_REACHED(); - return TextOrientationVerticalRight; + return TextOrientation::Mixed; } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPointerEvents e) @@ -3477,13 +3502,13 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPointerEvents e) m_value.valueID = CSSValueVisible; break; case PE_VISIBLE_STROKE: - m_value.valueID = CSSValueVisiblestroke; + m_value.valueID = CSSValueVisibleStroke; break; case PE_VISIBLE_FILL: - m_value.valueID = CSSValueVisiblefill; + m_value.valueID = CSSValueVisibleFill; break; case PE_VISIBLE_PAINTED: - m_value.valueID = CSSValueVisiblepainted; + m_value.valueID = CSSValueVisiblePainted; break; case PE_AUTO: m_value.valueID = CSSValueAuto; @@ -3505,11 +3530,11 @@ template<> inline CSSPrimitiveValue::operator EPointerEvents() const return PE_AUTO; case CSSValueNone: return PE_NONE; - case CSSValueVisiblepainted: + case CSSValueVisiblePainted: return PE_VISIBLE_PAINTED; - case CSSValueVisiblefill: + case CSSValueVisibleFill: return PE_VISIBLE_FILL; - case CSSValueVisiblestroke: + case CSSValueVisibleStroke: return PE_VISIBLE_STROKE; case CSSValueVisible: return PE_VISIBLE; @@ -3527,18 +3552,18 @@ template<> inline CSSPrimitiveValue::operator EPointerEvents() const return PE_ALL; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontDescription::Kerning kerning) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Kerning kerning) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; switch (kerning) { - case FontDescription::AutoKerning: + case Kerning::Auto: m_value.valueID = CSSValueAuto; return; - case FontDescription::NormalKerning: + case Kerning::Normal: m_value.valueID = CSSValueNormal; return; - case FontDescription::NoneKerning: + case Kerning::NoShift: m_value.valueID = CSSValueNone; return; } @@ -3547,23 +3572,23 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontDescription::Kerning m_value.valueID = CSSValueAuto; } -template<> inline CSSPrimitiveValue::operator FontDescription::Kerning() const +template<> inline CSSPrimitiveValue::operator Kerning() const { ASSERT(isValueID()); switch (m_value.valueID) { case CSSValueAuto: - return FontDescription::AutoKerning; + return Kerning::Auto; case CSSValueNormal: - return FontDescription::NormalKerning; + return Kerning::Normal; case CSSValueNone: - return FontDescription::NoneKerning; + return Kerning::NoShift; default: break; } ASSERT_NOT_REACHED(); - return FontDescription::AutoKerning; + return Kerning::Auto; } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ObjectFit fit) @@ -3804,13 +3829,13 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextRenderingMode e) m_value.valueID = CSSValueAuto; break; case OptimizeSpeed: - m_value.valueID = CSSValueOptimizespeed; + m_value.valueID = CSSValueOptimizeSpeed; break; case OptimizeLegibility: - m_value.valueID = CSSValueOptimizelegibility; + m_value.valueID = CSSValueOptimizeLegibility; break; case GeometricPrecision: - m_value.valueID = CSSValueGeometricprecision; + m_value.valueID = CSSValueGeometricPrecision; break; } } @@ -3822,11 +3847,11 @@ template<> inline CSSPrimitiveValue::operator TextRenderingMode() const switch (m_value.valueID) { case CSSValueAuto: return AutoTextRendering; - case CSSValueOptimizespeed: + case CSSValueOptimizeSpeed: return OptimizeSpeed; - case CSSValueOptimizelegibility: + case CSSValueOptimizeLegibility: return OptimizeLegibility; - case CSSValueGeometricprecision: + case CSSValueGeometricPrecision: return GeometricPrecision; default: break; @@ -3836,42 +3861,6 @@ template<> inline CSSPrimitiveValue::operator TextRenderingMode() const return AutoTextRendering; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ColorSpace space) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (space) { - case ColorSpaceDeviceRGB: - m_value.valueID = CSSValueDefault; - break; - case ColorSpaceSRGB: - m_value.valueID = CSSValueSrgb; - break; - case ColorSpaceLinearRGB: - // CSS color correction does not support linearRGB yet. - ASSERT_NOT_REACHED(); - m_value.valueID = CSSValueDefault; - break; - } -} - -template<> inline CSSPrimitiveValue::operator ColorSpace() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueDefault: - return ColorSpaceDeviceRGB; - case CSSValueSrgb: - return ColorSpaceSRGB; - default: - break; - } - - ASSERT_NOT_REACHED(); - return ColorSpaceDeviceRGB; -} - template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Hyphens hyphens) : CSSValue(PrimitiveClass) { @@ -4110,6 +4099,12 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BlendMode blendMode) case BlendModeLuminosity: m_value.valueID = CSSValueLuminosity; break; + case BlendModePlusDarker: + m_value.valueID = CSSValuePlusDarker; + break; + case BlendModePlusLighter: + m_value.valueID = CSSValuePlusLighter; + break; } } @@ -4150,6 +4145,10 @@ template<> inline CSSPrimitiveValue::operator BlendMode() const return BlendModeColor; case CSSValueLuminosity: return BlendModeLuminosity; + case CSSValuePlusDarker: + return BlendModePlusDarker; + case CSSValuePlusLighter: + return BlendModePlusLighter; default: break; } @@ -4158,7 +4157,37 @@ template<> inline CSSPrimitiveValue::operator BlendMode() const return BlendModeNormal; } -#if ENABLE(SVG) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Isolation isolation) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (isolation) { + case IsolationAuto: + m_value.valueID = CSSValueAuto; + break; + case IsolationIsolate: + m_value.valueID = CSSValueIsolate; + break; + default: + ASSERT_NOT_REACHED(); + } +} + +template<> inline CSSPrimitiveValue::operator Isolation() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueAuto: + return IsolationAuto; + case CSSValueIsolate: + return IsolationIsolate; + default: + break; + } + + ASSERT_NOT_REACHED(); + return IsolationAuto; +} template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineCap e) : CSSValue(PrimitiveClass) @@ -4345,8 +4374,6 @@ template<> inline CSSPrimitiveValue::operator EAlignmentBaseline() const return AB_AUTO; } -#endif - template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBorderCollapse e) : CSSValue(PrimitiveClass) { @@ -4409,22 +4436,25 @@ template<> inline CSSPrimitiveValue::operator EBorderFit() const return BorderFitLines; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EImageRendering e) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EImageRendering imageRendering) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; - switch (e) { + switch (imageRendering) { case ImageRenderingAuto: m_value.valueID = CSSValueAuto; break; case ImageRenderingCrispEdges: - m_value.valueID = CSSValueWebkitCrispEdges; + m_value.valueID = CSSValueCrispEdges; + break; + case ImageRenderingPixelated: + m_value.valueID = CSSValuePixelated; break; case ImageRenderingOptimizeSpeed: - m_value.valueID = CSSValueOptimizespeed; + m_value.valueID = CSSValueOptimizeSpeed; break; case ImageRenderingOptimizeQuality: - m_value.valueID = CSSValueOptimizequality; + m_value.valueID = CSSValueOptimizeQuality; break; } } @@ -4437,11 +4467,14 @@ template<> inline CSSPrimitiveValue::operator EImageRendering() const case CSSValueAuto: return ImageRenderingAuto; case CSSValueWebkitOptimizeContrast: + case CSSValueCrispEdges: case CSSValueWebkitCrispEdges: return ImageRenderingCrispEdges; - case CSSValueOptimizespeed: + case CSSValuePixelated: + return ImageRenderingPixelated; + case CSSValueOptimizeSpeed: return ImageRenderingOptimizeSpeed; - case CSSValueOptimizequality: + case CSSValueOptimizeQuality: return ImageRenderingOptimizeQuality; default: break; @@ -4549,172 +4582,59 @@ template<> inline CSSPrimitiveValue::operator ColumnProgression() const return NormalColumnProgression; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WrapFlow wrapFlow) +enum LengthConversion { + AnyConversion = ~0, + FixedIntegerConversion = 1 << 0, + FixedFloatConversion = 1 << 1, + AutoConversion = 1 << 2, + PercentConversion = 1 << 3, + CalculatedConversion = 1 << 4 +}; + +inline bool CSSPrimitiveValue::convertingToLengthRequiresNonNullStyle(int lengthConversion) const +{ + ASSERT(isFontRelativeLength()); + // This matches the implementation in CSSPrimitiveValue::computeLengthDouble(). + switch (m_primitiveUnitType) { + case CSS_EMS: + case CSS_EXS: + case CSS_CHS: + return lengthConversion & (FixedIntegerConversion | FixedFloatConversion); + default: + return false; + } +} + +template Length CSSPrimitiveValue::convertToLength(const CSSToLengthConversionData& conversionData) const +{ + if (isFontRelativeLength() && convertingToLengthRequiresNonNullStyle(supported) && !conversionData.style()) + return Length(Undefined); + if ((supported & FixedIntegerConversion) && isLength()) + return computeLength(conversionData); + if ((supported & FixedFloatConversion) && isLength()) + return Length(computeLength(conversionData), Fixed); + if ((supported & PercentConversion) && isPercentage()) + return Length(doubleValue(), Percent); + if ((supported & AutoConversion) && valueID() == CSSValueAuto) + return Length(Auto); + if ((supported & CalculatedConversion) && isCalculated()) + return Length(cssCalcValue()->createCalculationValue(conversionData)); + return Length(Undefined); +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBufferedRendering e) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; - switch (wrapFlow) { - case WrapFlowAuto: + switch (e) { + case BR_AUTO: m_value.valueID = CSSValueAuto; break; - case WrapFlowBoth: - m_value.valueID = CSSValueBoth; - break; - case WrapFlowStart: - m_value.valueID = CSSValueStart; - break; - case WrapFlowEnd: - m_value.valueID = CSSValueEnd; - break; - case WrapFlowMaximum: - m_value.valueID = CSSValueMaximum; + case BR_DYNAMIC: + m_value.valueID = CSSValueDynamic; break; - case WrapFlowClear: - m_value.valueID = CSSValueClear; - break; - } -} - -template<> inline CSSPrimitiveValue::operator WrapFlow() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueAuto: - return WrapFlowAuto; - case CSSValueBoth: - return WrapFlowBoth; - case CSSValueStart: - return WrapFlowStart; - case CSSValueEnd: - return WrapFlowEnd; - case CSSValueMaximum: - return WrapFlowMaximum; - case CSSValueClear: - return WrapFlowClear; - default: - break; - } - - ASSERT_NOT_REACHED(); - return WrapFlowAuto; -} - -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(WrapThrough wrapThrough) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (wrapThrough) { - case WrapThroughWrap: - m_value.valueID = CSSValueWrap; - break; - case WrapThroughNone: - m_value.valueID = CSSValueNone; - break; - } -} - -template<> inline CSSPrimitiveValue::operator WrapThrough() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueWrap: - return WrapThroughWrap; - case CSSValueNone: - return WrapThroughNone; - default: - break; - } - - ASSERT_NOT_REACHED(); - return WrapThroughWrap; -} - -template<> inline CSSPrimitiveValue::operator GridAutoFlow() const -{ - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueNone: - return AutoFlowNone; - case CSSValueColumn: - return AutoFlowColumn; - case CSSValueRow: - return AutoFlowRow; - default: - break; - } - - ASSERT_NOT_REACHED(); - return AutoFlowNone; - -} - -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(GridAutoFlow flow) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (flow) { - case AutoFlowNone: - m_value.valueID = CSSValueNone; - break; - case AutoFlowColumn: - m_value.valueID = CSSValueColumn; - break; - case AutoFlowRow: - m_value.valueID = CSSValueRow; - break; - } -} - -enum LengthConversion { - AnyConversion = ~0, - FixedIntegerConversion = 1 << 0, - FixedFloatConversion = 1 << 1, - AutoConversion = 1 << 2, - PercentConversion = 1 << 3, - FractionConversion = 1 << 4, - CalculatedConversion = 1 << 5, - ViewportPercentageConversion = 1 << 6 -}; - -template Length CSSPrimitiveValue::convertToLength(const RenderStyle* style, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const -{ - if ((supported & (FixedIntegerConversion | FixedFloatConversion)) && isFontRelativeLength() && (!style || !rootStyle)) - return Length(Undefined); - if ((supported & FixedIntegerConversion) && isLength()) - return computeLength(style, rootStyle, multiplier, computingFontSize); - if ((supported & FixedFloatConversion) && isLength()) - return Length(computeLength(style, rootStyle, multiplier), Fixed); - if ((supported & PercentConversion) && isPercentage()) - return Length(getDoubleValue(), Percent); - if ((supported & FractionConversion) && isNumber()) - return Length(getDoubleValue() * 100.0, Percent); - if ((supported & AutoConversion) && getValueID() == CSSValueAuto) - return Length(Auto); - if ((supported & CalculatedConversion) && isCalculated()) - return Length(cssCalcValue()->toCalcValue(style, rootStyle, multiplier)); - if ((supported & ViewportPercentageConversion) && isViewportPercentageLength()) - return viewportPercentageLength(); - return Length(Undefined); -} - -#if ENABLE(SVG) - -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBufferedRendering e) - : CSSValue(PrimitiveClass) -{ - m_primitiveUnitType = CSS_VALUE_ID; - switch (e) { - case BR_AUTO: - m_value.valueID = CSSValueAuto; - break; - case BR_DYNAMIC: - m_value.valueID = CSSValueDynamic; - break; - case BR_STATIC: - m_value.valueID = CSSValueStatic; + case BR_STATIC: + m_value.valueID = CSSValueStatic; break; } } @@ -4747,10 +4667,10 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorInterpolation e) m_value.valueID = CSSValueAuto; break; case CI_SRGB: - m_value.valueID = CSSValueSrgb; + m_value.valueID = CSSValueSRGB; break; case CI_LINEARRGB: - m_value.valueID = CSSValueLinearrgb; + m_value.valueID = CSSValueLinearRGB; break; } } @@ -4760,9 +4680,9 @@ template<> inline CSSPrimitiveValue::operator EColorInterpolation() const ASSERT(isValueID()); switch (m_value.valueID) { - case CSSValueSrgb: + case CSSValueSRGB: return CI_SRGB; - case CSSValueLinearrgb: + case CSSValueLinearRGB: return CI_LINEARRGB; case CSSValueAuto: return CI_AUTO; @@ -4783,10 +4703,10 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorRendering e) m_value.valueID = CSSValueAuto; break; case CR_OPTIMIZESPEED: - m_value.valueID = CSSValueOptimizespeed; + m_value.valueID = CSSValueOptimizeSpeed; break; case CR_OPTIMIZEQUALITY: - m_value.valueID = CSSValueOptimizequality; + m_value.valueID = CSSValueOptimizeQuality; break; } } @@ -4796,9 +4716,9 @@ template<> inline CSSPrimitiveValue::operator EColorRendering() const ASSERT(isValueID()); switch (m_value.valueID) { - case CSSValueOptimizespeed: + case CSSValueOptimizeSpeed: return CR_OPTIMIZESPEED; - case CSSValueOptimizequality: + case CSSValueOptimizeQuality: return CR_OPTIMIZEQUALITY; case CSSValueAuto: return CR_AUTO; @@ -4900,13 +4820,13 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EShapeRendering e) m_value.valueID = CSSValueAuto; break; case SR_OPTIMIZESPEED: - m_value.valueID = CSSValueOptimizespeed; + m_value.valueID = CSSValueOptimizeSpeed; break; case SR_CRISPEDGES: m_value.valueID = CSSValueCrispedges; break; case SR_GEOMETRICPRECISION: - m_value.valueID = CSSValueGeometricprecision; + m_value.valueID = CSSValueGeometricPrecision; break; } } @@ -4918,11 +4838,11 @@ template<> inline CSSPrimitiveValue::operator EShapeRendering() const switch (m_value.valueID) { case CSSValueAuto: return SR_AUTO; - case CSSValueOptimizespeed: + case CSSValueOptimizeSpeed: return SR_OPTIMIZESPEED; case CSSValueCrispedges: return SR_CRISPEDGES; - case CSSValueGeometricprecision: + case CSSValueGeometricPrecision: return SR_GEOMETRICPRECISION; default: break; @@ -4968,55 +4888,18 @@ template<> inline CSSPrimitiveValue::operator ETextAnchor() const return TA_START; } -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(SVGWritingMode e) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(const Color& color) : CSSValue(PrimitiveClass) { - m_primitiveUnitType = CSS_VALUE_ID; - switch (e) { - case WM_LRTB: - m_value.valueID = CSSValueLrTb; - break; - case WM_LR: - m_value.valueID = CSSValueLr; - break; - case WM_RLTB: - m_value.valueID = CSSValueRlTb; - break; - case WM_RL: - m_value.valueID = CSSValueRl; - break; - case WM_TBRL: - m_value.valueID = CSSValueTbRl; - break; - case WM_TB: - m_value.valueID = CSSValueTb; - break; - } + m_primitiveUnitType = CSS_RGBCOLOR; + m_value.color = new Color(color); } -template<> inline CSSPrimitiveValue::operator SVGWritingMode() const +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CSSFontFamily fontFamily) + : CSSValue(PrimitiveClass) { - ASSERT(isValueID()); - - switch (m_value.valueID) { - case CSSValueLrTb: - return WM_LRTB; - case CSSValueLr: - return WM_LR; - case CSSValueRlTb: - return WM_RLTB; - case CSSValueRl: - return WM_RL; - case CSSValueTbRl: - return WM_TBRL; - case CSSValueTb: - return WM_TB; - default: - break; - } - - ASSERT_NOT_REACHED(); - return WM_LRTB; + m_primitiveUnitType = CSS_FONT_FAMILY; + m_value.fontFamily = new CSSFontFamily(WTFMove(fontFamily)); } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EVectorEffect e) @@ -5081,8 +4964,6 @@ template<> inline CSSPrimitiveValue::operator EMaskType() const return MT_LUMINANCE; } -#endif // ENABLE(SVG) - #if ENABLE(CSS_IMAGE_ORIENTATION) template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ImageOrientationEnum e) @@ -5113,7 +4994,7 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ImageOrientationEnum e) template<> inline CSSPrimitiveValue::operator ImageOrientationEnum() const { ASSERT(isAngle()); - double quarters = 4 * getDoubleValue(CSS_TURN); + double quarters = 4 * doubleValue(CSS_TURN); int orientation = 3 & static_cast(quarters < 0 ? floor(quarters) : ceil(quarters)); switch (orientation) { case 0: @@ -5132,14 +5013,11 @@ template<> inline CSSPrimitiveValue::operator ImageOrientationEnum() const #endif // ENABLE(CSS_IMAGE_ORIENTATION) -template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LayoutBox layoutBox) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CSSBoxType cssBox) : CSSValue(PrimitiveClass) { m_primitiveUnitType = CSS_VALUE_ID; - switch (layoutBox) { - case BoundingBox: - m_value.valueID = CSSValueBoundingBox; - break; + switch (cssBox) { case MarginBox: m_value.valueID = CSSValueMarginBox; break; @@ -5152,6 +5030,15 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LayoutBox layoutBox) case ContentBox: m_value.valueID = CSSValueContentBox; break; + case Fill: + m_value.valueID = CSSValueFill; + break; + case Stroke: + m_value.valueID = CSSValueStroke; + break; + case ViewBox: + m_value.valueID = CSSValueViewBox; + break; case BoxMissing: ASSERT_NOT_REACHED(); m_value.valueID = CSSValueNone; @@ -5159,11 +5046,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LayoutBox layoutBox) } } -template<> inline CSSPrimitiveValue::operator LayoutBox() const +template<> inline CSSPrimitiveValue::operator CSSBoxType() const { - switch (getValueID()) { - case CSSValueBoundingBox: - return BoundingBox; + switch (valueID()) { case CSSValueMarginBox: return MarginBox; case CSSValueBorderBox: @@ -5172,6 +5057,13 @@ template<> inline CSSPrimitiveValue::operator LayoutBox() const return PaddingBox; case CSSValueContentBox: return ContentBox; + // The following are used in an SVG context. + case CSSValueFill: + return Fill; + case CSSValueStroke: + return Stroke; + case CSSValueViewBox: + return ViewBox; default: break; } @@ -5179,6 +5071,657 @@ template<> inline CSSPrimitiveValue::operator LayoutBox() const return BoxMissing; } +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ItemPosition itemPosition) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (itemPosition) { + case ItemPositionAuto: + m_value.valueID = CSSValueAuto; + break; + case ItemPositionNormal: + m_value.valueID = CSSValueNormal; + break; + case ItemPositionStretch: + m_value.valueID = CSSValueStretch; + break; + case ItemPositionBaseline: + m_value.valueID = CSSValueBaseline; + break; + case ItemPositionLastBaseline: + m_value.valueID = CSSValueLastBaseline; + break; + case ItemPositionCenter: + m_value.valueID = CSSValueCenter; + break; + case ItemPositionStart: + m_value.valueID = CSSValueStart; + break; + case ItemPositionEnd: + m_value.valueID = CSSValueEnd; + break; + case ItemPositionSelfStart: + m_value.valueID = CSSValueSelfStart; + break; + case ItemPositionSelfEnd: + m_value.valueID = CSSValueSelfEnd; + break; + case ItemPositionFlexStart: + m_value.valueID = CSSValueFlexStart; + break; + case ItemPositionFlexEnd: + m_value.valueID = CSSValueFlexEnd; + break; + case ItemPositionLeft: + m_value.valueID = CSSValueLeft; + break; + case ItemPositionRight: + m_value.valueID = CSSValueRight; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ItemPosition() const +{ + switch (m_value.valueID) { + case CSSValueAuto: + return ItemPositionAuto; + case CSSValueNormal: + return ItemPositionNormal; + case CSSValueStretch: + return ItemPositionStretch; + case CSSValueBaseline: + return ItemPositionBaseline; + case CSSValueLastBaseline: + return ItemPositionLastBaseline; + case CSSValueCenter: + return ItemPositionCenter; + case CSSValueStart: + return ItemPositionStart; + case CSSValueEnd: + return ItemPositionEnd; + case CSSValueSelfStart: + return ItemPositionSelfStart; + case CSSValueSelfEnd: + return ItemPositionSelfEnd; + case CSSValueFlexStart: + return ItemPositionFlexStart; + case CSSValueFlexEnd: + return ItemPositionFlexEnd; + case CSSValueLeft: + return ItemPositionLeft; + case CSSValueRight: + return ItemPositionRight; + default: + break; + } + ASSERT_NOT_REACHED(); + return ItemPositionAuto; } -#endif +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(OverflowAlignment overflowAlignment) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (overflowAlignment) { + case OverflowAlignmentDefault: + m_value.valueID = CSSValueDefault; + break; + case OverflowAlignmentUnsafe: + m_value.valueID = CSSValueUnsafe; + break; + case OverflowAlignmentSafe: + m_value.valueID = CSSValueSafe; + break; + } +} + +template<> inline CSSPrimitiveValue::operator OverflowAlignment() const +{ + switch (m_value.valueID) { + case CSSValueUnsafe: + return OverflowAlignmentUnsafe; + case CSSValueSafe: + return OverflowAlignmentSafe; + default: + break; + } + ASSERT_NOT_REACHED(); + return OverflowAlignmentUnsafe; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ContentPosition contentPosition) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (contentPosition) { + case ContentPositionNormal: + m_value.valueID = CSSValueNormal; + break; + case ContentPositionBaseline: + m_value.valueID = CSSValueBaseline; + break; + case ContentPositionLastBaseline: + m_value.valueID = CSSValueLastBaseline; + break; + case ContentPositionCenter: + m_value.valueID = CSSValueCenter; + break; + case ContentPositionStart: + m_value.valueID = CSSValueStart; + break; + case ContentPositionEnd: + m_value.valueID = CSSValueEnd; + break; + case ContentPositionFlexStart: + m_value.valueID = CSSValueFlexStart; + break; + case ContentPositionFlexEnd: + m_value.valueID = CSSValueFlexEnd; + break; + case ContentPositionLeft: + m_value.valueID = CSSValueLeft; + break; + case ContentPositionRight: + m_value.valueID = CSSValueRight; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ContentPosition() const +{ + switch (m_value.valueID) { + case CSSValueNormal: + return ContentPositionNormal; + case CSSValueBaseline: + return ContentPositionBaseline; + case CSSValueLastBaseline: + return ContentPositionLastBaseline; + case CSSValueCenter: + return ContentPositionCenter; + case CSSValueStart: + return ContentPositionStart; + case CSSValueEnd: + return ContentPositionEnd; + case CSSValueFlexStart: + return ContentPositionFlexStart; + case CSSValueFlexEnd: + return ContentPositionFlexEnd; + case CSSValueLeft: + return ContentPositionLeft; + case CSSValueRight: + return ContentPositionRight; + default: + break; + } + ASSERT_NOT_REACHED(); + return ContentPositionNormal; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ContentDistributionType contentDistribution) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (contentDistribution) { + case ContentDistributionDefault: + m_value.valueID = CSSValueDefault; + break; + case ContentDistributionSpaceBetween: + m_value.valueID = CSSValueSpaceBetween; + break; + case ContentDistributionSpaceAround: + m_value.valueID = CSSValueSpaceAround; + break; + case ContentDistributionSpaceEvenly: + m_value.valueID = CSSValueSpaceEvenly; + break; + case ContentDistributionStretch: + m_value.valueID = CSSValueStretch; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ContentDistributionType() const +{ + switch (m_value.valueID) { + case CSSValueSpaceBetween: + return ContentDistributionSpaceBetween; + case CSSValueSpaceAround: + return ContentDistributionSpaceAround; + case CSSValueSpaceEvenly: + return ContentDistributionSpaceEvenly; + case CSSValueStretch: + return ContentDistributionStretch; + default: + break; + } + ASSERT_NOT_REACHED(); + return ContentDistributionStretch; +} + +template<> inline CSSPrimitiveValue::operator TextZoom() const +{ + ASSERT(isValueID()); + + switch (m_value.valueID) { + case CSSValueNormal: + return TextZoomNormal; + case CSSValueReset: + return TextZoomReset; + default: + break; + } + + ASSERT_NOT_REACHED(); + return TextZoomNormal; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextZoom textZoom) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (textZoom) { + case TextZoomNormal: + m_value.valueID = CSSValueNormal; + return; + case TextZoomReset: + m_value.valueID = CSSValueReset; + return; + } + + ASSERT_NOT_REACHED(); + m_value.valueID = CSSValueNormal; +} + +#if ENABLE(TOUCH_EVENTS) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TouchAction touchAction) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (touchAction) { + case TouchAction::Auto: + m_value.valueID = CSSValueAuto; + break; + case TouchAction::Manipulation: + m_value.valueID = CSSValueManipulation; + break; + } +} + +template<> inline CSSPrimitiveValue::operator TouchAction() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueAuto: + return TouchAction::Auto; + case CSSValueManipulation: + return TouchAction::Manipulation; + default: + break; + } + ASSERT_NOT_REACHED(); + return TouchAction::Auto; +} +#endif + +#if ENABLE(CSS_SCROLL_SNAP) + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ScrollSnapStrictness strictness) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (strictness) { + case ScrollSnapStrictness::None: + m_value.valueID = CSSValueNone; + break; + case ScrollSnapStrictness::Proximity: + m_value.valueID = CSSValueProximity; + break; + case ScrollSnapStrictness::Mandatory: + m_value.valueID = CSSValueMandatory; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ScrollSnapStrictness() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueNone: + return ScrollSnapStrictness::None; + case CSSValueProximity: + return ScrollSnapStrictness::Proximity; + case CSSValueMandatory: + return ScrollSnapStrictness::Mandatory; + default: + ASSERT_NOT_REACHED(); + return ScrollSnapStrictness::None; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ScrollSnapAxis axis) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (axis) { + case ScrollSnapAxis::XAxis: + m_value.valueID = CSSValueX; + break; + case ScrollSnapAxis::YAxis: + m_value.valueID = CSSValueY; + break; + case ScrollSnapAxis::Block: + m_value.valueID = CSSValueBlock; + break; + case ScrollSnapAxis::Inline: + m_value.valueID = CSSValueInline; + break; + case ScrollSnapAxis::Both: + m_value.valueID = CSSValueBoth; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ScrollSnapAxis() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueX: + return ScrollSnapAxis::XAxis; + case CSSValueY: + return ScrollSnapAxis::YAxis; + case CSSValueBlock: + return ScrollSnapAxis::Block; + case CSSValueInline: + return ScrollSnapAxis::Inline; + case CSSValueBoth: + return ScrollSnapAxis::Both; + default: + ASSERT_NOT_REACHED(); + return ScrollSnapAxis::Both; + } +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ScrollSnapAxisAlignType type) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (type) { + case ScrollSnapAxisAlignType::None: + m_value.valueID = CSSValueNone; + break; + case ScrollSnapAxisAlignType::Start: + m_value.valueID = CSSValueStart; + break; + case ScrollSnapAxisAlignType::Center: + m_value.valueID = CSSValueCenter; + break; + case ScrollSnapAxisAlignType::End: + m_value.valueID = CSSValueEnd; + break; + } +} + +template<> inline CSSPrimitiveValue::operator ScrollSnapAxisAlignType() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueNone: + return ScrollSnapAxisAlignType::None; + case CSSValueStart: + return ScrollSnapAxisAlignType::Start; + case CSSValueCenter: + return ScrollSnapAxisAlignType::Center; + case CSSValueEnd: + return ScrollSnapAxisAlignType::End; + default: + ASSERT_NOT_REACHED(); + return ScrollSnapAxisAlignType::None; + } +} + +#endif + +#if ENABLE(CSS_TRAILING_WORD) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TrailingWord e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (e) { + case TrailingWord::Auto: + m_value.valueID = CSSValueAuto; + break; + case TrailingWord::PartiallyBalanced: + m_value.valueID = CSSValueWebkitPartiallyBalanced; + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator TrailingWord() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueAuto: + return TrailingWord::Auto; + case CSSValueWebkitPartiallyBalanced: + return TrailingWord::PartiallyBalanced; + default: + break; + } + ASSERT_NOT_REACHED(); + return TrailingWord::Auto; +} +#endif + +#if ENABLE(APPLE_PAY) +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ApplePayButtonStyle e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (e) { + case ApplePayButtonStyle::White: + m_value.valueID = CSSValueWhite; + break; + case ApplePayButtonStyle::WhiteOutline: + m_value.valueID = CSSValueWhiteOutline; + break; + case ApplePayButtonStyle::Black: + m_value.valueID = CSSValueBlack; + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator ApplePayButtonStyle() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueWhite: + return ApplePayButtonStyle::White; + case CSSValueWhiteOutline: + return ApplePayButtonStyle::WhiteOutline; + case CSSValueBlack: + return ApplePayButtonStyle::Black; + default: + break; + } + ASSERT_NOT_REACHED(); + return ApplePayButtonStyle::Black; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ApplePayButtonType e) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (e) { + case ApplePayButtonType::Plain: + m_value.valueID = CSSValuePlain; + break; + case ApplePayButtonType::Buy: + m_value.valueID = CSSValueBuy; + break; + case ApplePayButtonType::SetUp: + m_value.valueID = CSSValueSetUp; + break; + case ApplePayButtonType::Donate: + m_value.valueID = CSSValueDonate; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator ApplePayButtonType() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValuePlain: + return ApplePayButtonType::Plain; + case CSSValueBuy: + return ApplePayButtonType::Buy; + case CSSValueSetUp: + return ApplePayButtonType::SetUp; + case CSSValueDonate: + return ApplePayButtonType::Donate; + default: + break; + } + ASSERT_NOT_REACHED(); + return ApplePayButtonType::Plain; +} +#endif + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantPosition position) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (position) { + case FontVariantPosition::Normal: + m_value.valueID = CSSValueNormal; + break; + case FontVariantPosition::Subscript: + m_value.valueID = CSSValueSub; + break; + case FontVariantPosition::Superscript: + m_value.valueID = CSSValueSuper; + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator FontVariantPosition() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueNormal: + return FontVariantPosition::Normal; + case CSSValueSub: + return FontVariantPosition::Subscript; + case CSSValueSuper: + return FontVariantPosition::Superscript; + default: + break; + } + ASSERT_NOT_REACHED(); + return FontVariantPosition::Normal; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantCaps caps) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (caps) { + case FontVariantCaps::Normal: + m_value.valueID = CSSValueNormal; + break; + case FontVariantCaps::Small: + m_value.valueID = CSSValueSmallCaps; + break; + case FontVariantCaps::AllSmall: + m_value.valueID = CSSValueAllSmallCaps; + break; + case FontVariantCaps::Petite: + m_value.valueID = CSSValuePetiteCaps; + break; + case FontVariantCaps::AllPetite: + m_value.valueID = CSSValueAllPetiteCaps; + break; + case FontVariantCaps::Unicase: + m_value.valueID = CSSValueUnicase; + break; + case FontVariantCaps::Titling: + m_value.valueID = CSSValueTitlingCaps; + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator FontVariantCaps() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueNormal: + return FontVariantCaps::Normal; + case CSSValueSmallCaps: + return FontVariantCaps::Small; + case CSSValueAllSmallCaps: + return FontVariantCaps::AllSmall; + case CSSValuePetiteCaps: + return FontVariantCaps::Petite; + case CSSValueAllPetiteCaps: + return FontVariantCaps::AllPetite; + case CSSValueUnicase: + return FontVariantCaps::Unicase; + case CSSValueTitlingCaps: + return FontVariantCaps::Titling; + default: + break; + } + ASSERT_NOT_REACHED(); + return FontVariantCaps::Normal; +} + +template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantAlternates alternates) + : CSSValue(PrimitiveClass) +{ + m_primitiveUnitType = CSS_VALUE_ID; + switch (alternates) { + case FontVariantAlternates::Normal: + m_value.valueID = CSSValueNormal; + break; + case FontVariantAlternates::HistoricalForms: + m_value.valueID = CSSValueHistoricalForms; + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<> inline CSSPrimitiveValue::operator FontVariantAlternates() const +{ + ASSERT(isValueID()); + switch (m_value.valueID) { + case CSSValueNormal: + return FontVariantAlternates::Normal; + case CSSValueHistoricalForms: + return FontVariantAlternates::HistoricalForms; + default: + break; + } + ASSERT_NOT_REACHED(); + return FontVariantAlternates::Normal; +} + +} diff --git a/Source/WebCore/css/CSSProperties.json b/Source/WebCore/css/CSSProperties.json new file mode 100644 index 000000000..ada98535d --- /dev/null +++ b/Source/WebCore/css/CSSProperties.json @@ -0,0 +1,4200 @@ +{ + "instructions": [ + "CSS Properties", + "", + "Some properties are used internally, but are not part of CSS. They are used to get", + "HTML4 compatibility in the rendering engine.", + "", + "Microsoft extensions are documented here:", + "http://msdn.microsoft.com/workshop/author/css/reference/attributes.asp", + "", + "1. Possible Keys", + "", + "Keys that control CSS behavior:", + "", + "* inherited:", + "Whether the property is inherited.", + "", + "* animatable:", + "Indicates that this CSS property is an animation / transition property.", + "It must have corresponding methods on the Animation class.", + "", + "Keys that control code generation:", + "", + "* initial:", + "Overrides the method name on RenderStyle to get the initial value for", + "the property. By default, \"initial\" + PropertyId is used (e.g.", + "initialBorderCollapse()).", + "", + "* getter:", + "Overrides the method name on RenderStyle to get the current value for", + "the property. By default, the PropertyId with first letter lowercased", + "is used (e.g. borderCollapse()).", + "", + "* setter:", + "Overrides the method name on RenderStyle to set the current value for", + "the property. By default, \"set\" + PropertyId is used (e.g.", + "setBorderCollapse()).", + "", + "* name-for-methods:", + "Overrides the getter / setter / initial method names on RenderStyle.", + "For example, '\"name-for-methods\": \"OverflowWrap\"' will use", + "\"overflowWrap() / setOverflowWrap() / initialOverflowWrap()\".", + "", + "* converter:", + "The name of the converter helper function in css/StyleBuilderConverter.h", + "to use. The converter helper function takes ", + "If converting the input CSSValue into the setter method argument type", + "is not trivial (i.e. the CSSPrimitiveValue cannot be implicitly converted", + "to the expected type), then you can indicate that a converter helper", + "function in css/StyleBuilderConverter.h should be used.", + "", + "* conditional-converter:", + "Similar to property converter, but the converter function returns a", + "WTF::Optional<> to indicate if the property setter should be called", + "or not.", + "", + "* custom:", + "A string that is \"All\", \"Initial\", \"Inherit\", or \"Value\" or some combination", + "of the latter three separated by '|' (e.g. \"Inherit|Value\"). These options", + "are described as follows:", + "", + "All - the CSS property requires special handling to set its initial value,", + "inherit value, and its value. Prefer this option over listing the individual", + "options.", + "", + "Initial - the CSS property requires special handling to set its initial value.", + "", + "Inherit - the CSS property requires special handling to set its inherit value.", + "", + "Value - the CSS property requires special handling to set its value, and a", + "regular converter helper cannot be used.", + "", + "The custom code for the property should be located in css/StyleBuilderCustom.h", + "and named applyValue[CSSPropertyName]().", + "", + "* svg:", + "Indicates that this is an SVG CSS property and that the corresponding", + "methods are on SVGRenderStyle instead of RenderStyle.", + "", + "* auto-functions:", + "Indicates that this CSS property requires handling of \"auto\" and has", + "corresponding hasAutoXXX() / setHasAutoXXX() methods on RenderStyle.", + "", + "* visited-link-color-support:", + "Indicates that this CSS property is a color property with a", + "\"setVisitedLinkXXX()\" setter on RenderStyle to be called when", + "StyleResolver::applyPropertyToVisitedLinkStyle() return true.", + "The regular setter on RenderStyle will only be called if", + "StyleResolver::applyPropertyToRegularStyle() returns true.", + "", + "* no-default-color:", + "Should only with used with \"VisitedLinkColorSupport\". It indicates that for", + "setting the inherited value, it will not fallback to using the parent's", + "\"color\" property if the inherited color is invalid.", + "", + "* fone-property:", + "Indicates that this CSS property is font-related. It must have corresponding", + "methods on the FontDescription class.", + "", + "* fill-layer-property:", + "Indicates that this CSS property is a FillLayer property. It must have", + "corresponding methods on the FillLayer class.", + "", + "* skip-builder:", + "Ignore this property in the StyleBuilder.", + "", + "* longhands:", + "Indicated the array longhand property names associated with this shorthand", + "property. Shorthand properties should not use the StyleBuilder. An", + "ASSERT_NOT_REACHED() will be generated for this property in the StyleBuilder.", + "property1, property2, ... are the longhands for this shorthand property. A", + "corresponding \"StylePropertyShorthand propertyIdShorthand()\" function will be", + "generated in StylePropertyShorthandFunctions.h header.", + "", + "* high-priority:", + "Whether the property needs to be applied before non-high-priority properties", + "in CSS cascading order.", + "", + "* aliases:", + "An array of the alternative names for this property.", + "", + "* enable-if:", + "Indicates that code should only be generated for this property/value if the", + "specified macro define is enabled. Prefix the macro define with '!' to", + "generate code when the macro define is not enabled.", + "", + "2. Lesser known capabilities of this file format", + "", + "Conditional CSS keyword value:", + "", + "Typically the value of key \"values\" is an array of strings that represent the", + "CSS keyword values that are recognized by a CSS property. This array may also", + "contain objects of the form:", + "", + " {", + " \"value\": \"awesome\",", + " \"enable-if\": \"ENABLE_AWESOME_FEATURE\"", + " }", + "", + "The key \"value\" is the name of the conditional keyword and key \"enable-if\"", + "describes the code generation criterion. See the documentation for \"enable-if\"", + "above for more details.", + "", + "Conditonal CSS property definition:", + "", + "A CSS property can have more than one definition so long as the key \"enable-if\"", + "differs in each definition. For example, ", + "", + " \"awesome-property\": [", + " {", + " \"inherited\": true,", + " ...,", + " \"codegen-properties\": {", + " ...", + " \"enable-if\": \"ENABLE_AWESOME_FEATURE\"", + " }", + " },", + " {", + " \"inherited\": false,", + " ...,", + " \"codegen-properties\": {", + " ...", + " \"enable-if\": \"!ENABLE_AWESOME_FEATURE\"", + " }", + " },", + " ...", + " ],", + "", + "The first definition in parse order whose \"enable-if\" criterion evaluates", + "to true is chosen for code generation." + ], + "properties": { + "color": { + "inherited": true, + "codegen-properties": { + "visited-link-color-support": true, + "no-default-color": true, + "high-priority": true + } + }, + "direction": { + "inherited": true, + "values": [ + "ltr", + "rtl" + ], + "codegen-properties": { + "custom": "Value", + "high-priority": true + } + }, + "display": { + "values": [ + "inline", + "block", + "list-item", + "compact", + "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", + "flex", + "-webkit-flex", + "inline-flex", + "-webkit-inline-flex", + "contents", + "none", + "grid", + "inline-grid" + ], + "codegen-properties": { + "custom": "Inherit|Value", + "high-priority": true + } + }, + "font-family": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "high-priority": true + } + }, + "font-size": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "high-priority": true + } + }, + "font-style": { + "inherited": true, + "values": [ + "normal", + "italic", + "oblique" + ], + "codegen-properties": { + "name-for-methods": "Italic", + "font-property": true, + "high-priority": true + } + }, + "font-weight": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "high-priority": true + } + }, + "text-rendering": { + "inherited": true, + "values": [ + "auto", + "optimizespeed", + "optimizelegibility", + "geometricprecision" + ], + "codegen-properties": { + "name-for-methods": "TextRenderingMode", + "font-property": true, + "high-priority": true + } + }, + "font-feature-settings": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "FeatureSettings", + "converter": "FontFeatureSettings", + "custom": "Initial|Inherit", + "font-property": true, + "high-priority": true + } + }, + "font-variation-settings": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "VariationSettings", + "converter": "FontVariationSettings", + "custom": "Initial|Inherit", + "font-property": true, + "high-priority": true, + "enable-if": "ENABLE_VARIATION_FONTS" + } + }, + "-webkit-font-kerning": { + "inherited": true, + "values": [ + "auto", + "normal", + "none" + ], + "codegen-properties": { + "aliases": [ + "font-kerning" + ], + "name-for-methods": "Kerning", + "font-property": true, + "high-priority": true + } + }, + "-webkit-font-smoothing": { + "inherited": true, + "values": [ + "auto", + "none", + "antialiased", + "subpixel-antialiased" + ], + "codegen-properties": { + "font-property": true, + "high-priority": true + } + }, + "font-variant-ligatures": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "VariantLigatures", + "custom": "All", + "font-property": true, + "high-priority": true + } + }, + "font-variant-position": { + "inherited": true, + "values": [ + "normal", + "sub", + "super" + ], + "codegen-properties": { + "name-for-methods": "VariantPosition", + "font-property": true, + "high-priority": true + } + }, + "font-variant-caps": { + "inherited": true, + "values": [ + "normal", + "small-caps", + "all-small-caps", + "petite-caps", + "all-petite-caps", + "unicase", + "titling-caps" + ], + "codegen-properties": { + "name-for-methods": "VariantCaps", + "font-property": true, + "high-priority": true + } + }, + "font-variant-numeric": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "VariantNumeric", + "custom": "All", + "font-property": true, + "high-priority": true + } + }, + "font-variant-alternates": { + "inherited": true, + "values": [ + "normal", + "historical-forms" + ], + "codegen-properties": { + "name-for-methods": "VariantAlternates", + "font-property": true, + "high-priority": true + } + }, + "font-variant-east-asian": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "VariantEastAsian", + "custom": "All", + "font-property": true, + "high-priority": true + } + }, + "-webkit-locale": { + "inherited": true, + "codegen-properties": { + "custom": "Value", + "font-property": true, + "high-priority": true + } + }, + "-webkit-text-orientation": { + "inherited": true, + "values": [ + "sideways", + "sideways-right", + "vertical-right", + "mixed", + "upright" + ], + "codegen-properties": { + "aliases": [ + "-epub-text-orientation" + ], + "custom": "Value", + "high-priority": true + } + }, + "-webkit-text-size-adjust": { + "inherited": true, + "codegen-properties": { + "custom": "Value", + "high-priority": true, + "enable-if": "ENABLE_TEXT_AUTOSIZING" + } + }, + "writing-mode": { + "inherited": true, + "values": [ + "lr-tb", + "rl-tb", + "tb-rl", + "lr", + "rl", + "tb" + ], + "codegen-properties": { + "aliases": [ + "-webkit-writing-mode", + "-epub-writing-mode" + ], + "custom": "Value", + "high-priority": true + } + }, + "-webkit-text-zoom": { + "inherited": true, + "values": [ + "normal", + "reset" + ], + "codegen-properties": { + "custom": "Value", + "high-priority": true + } + }, + "zoom": { + "codegen-properties": { + "custom": "All", + "high-priority": true + } + }, + "font-synthesis": { + "inherited": true, + "codegen-properties": { + "converter": "FontSynthesis", + "font-property": true, + "high-priority": true + } + }, + "-webkit-ruby-position": { + "*": [ + "This is the highest priority property and \"is resolved before all other properties", + "to ensure that its value can be checked when determining a smart default font size\"", + "()." + ], + "inherited": true, + "values": [ + "before", + "after", + "inter-character" + ] + }, + "alignment-baseline": { + "values": [ + "auto", + "baseline", + "middle", + "before-edge", + "after-edge", + "central", + "text-before-edge", + "text-after-edge", + "ideographic", + "hanging", + "mathematical" + ], + "codegen-properties": { + "svg": true + } + }, + "all": { + "codegen-properties": { + "longhands": [ + "all" + ] + } + }, + "animation": { + "codegen-properties": { + "aliases": [ + "-webkit-animation" + ], + "longhands": [ + "animation-name", + "animation-duration", + "animation-timing-function", + "animation-delay", + "animation-iteration-count", + "animation-direction", + "animation-fill-mode", + "animation-play-state" + ] + } + }, + "animation-delay": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-delay" + ], + "name-for-methods": "Delay" + } + }, + "animation-direction": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-direction" + ], + "name-for-methods": "Direction" + } + }, + "animation-duration": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-duration" + ], + "name-for-methods": "Duration" + } + }, + "animation-fill-mode": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-fill-mode" + ], + "name-for-methods": "FillMode" + } + }, + "animation-iteration-count": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-iteration-count" + ], + "name-for-methods": "IterationCount" + } + }, + "animation-name": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-name" + ], + "name-for-methods": "Name" + } + }, + "animation-play-state": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-play-state" + ], + "name-for-methods": "PlayState" + } + }, + "animation-timing-function": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-animation-timing-function" + ], + "name-for-methods": "TimingFunction" + } + }, + "background": { + "codegen-properties": { + "longhands": [ + "background-image", + "background-position-x", + "background-position-y", + "background-size", + "background-repeat-x", + "background-repeat-y", + "background-attachment", + "background-origin", + "background-clip", + "background-color" + ] + } + }, + "background-attachment": { + "codegen-properties": { + "name-for-methods": "Attachment", + "fill-layer-property": true + } + }, + "background-blend-mode": { + "codegen-properties": { + "name-for-methods": "BlendMode", + "fill-layer-property": true + } + }, + "background-clip": { + "codegen-properties": { + "name-for-methods": "Clip", + "fill-layer-property": true + } + }, + "background-color": { + "codegen-properties": { + "visited-link-color-support": true, + "no-default-color": true + } + }, + "background-image": { + "codegen-properties": { + "name-for-methods": "Image", + "fill-layer-property": true + } + }, + "background-origin": { + "codegen-properties": { + "name-for-methods": "Origin", + "fill-layer-property": true + } + }, + "background-position": { + "codegen-properties": { + "longhands": [ + "background-position-x", + "background-position-y" + ] + } + }, + "background-position-x": { + "codegen-properties": { + "name-for-methods": "XPosition", + "fill-layer-property": true + } + }, + "background-position-y": { + "codegen-properties": { + "name-for-methods": "YPosition", + "fill-layer-property": true + } + }, + "background-repeat": { + "codegen-properties": { + "longhands": [ + "background-repeat-x", + "background-repeat-y" + ] + } + }, + "background-repeat-x": { + "codegen-properties": { + "name-for-methods": "RepeatX", + "fill-layer-property": true, + "internal-only": true + } + }, + "background-repeat-y": { + "codegen-properties": { + "name-for-methods": "RepeatY", + "fill-layer-property": true, + "internal-only": true + } + }, + "background-size": { + "codegen-properties": { + "name-for-methods": "Size", + "fill-layer-property": true + } + }, + "baseline-shift": { + "codegen-properties": { + "custom": "Value", + "svg": true + } + }, + "border": { + "codegen-properties": { + "longhands": [ + "border-top-color", + "border-top-style", + "border-top-width", + "border-right-color", + "border-right-style", + "border-right-width", + "border-bottom-color", + "border-bottom-style", + "border-bottom-width", + "border-left-color", + "border-left-style", + "border-left-width" + ] + } + }, + "border-bottom": { + "codegen-properties": { + "longhands": [ + "border-bottom-width", + "border-bottom-style", + "border-bottom-color" + ] + } + }, + "border-bottom-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "border-bottom-left-radius": { + "codegen-properties": { + "aliases": [ + "-webkit-border-bottom-left-radius" + ], + "initial": "initialBorderRadius", + "converter": "Radius" + } + }, + "border-bottom-right-radius": { + "codegen-properties": { + "aliases": [ + "-webkit-border-bottom-right-radius" + ], + "initial": "initialBorderRadius", + "converter": "Radius" + } + }, + "border-bottom-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "initial": "initialBorderStyle" + } + }, + "border-bottom-width": { + "codegen-properties": { + "initial": "initialBorderWidth", + "converter": "LineWidth" + } + }, + "border-collapse": { + "inherited": true, + "values": [ + "collapse", + "separate" + ] + }, + "border-color": { + "codegen-properties": { + "longhands": [ + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color" + ] + } + }, + "border-image": { + "codegen-properties": { + "longhands": [ + "border-image-source", + "border-image-slice", + "border-image-width", + "border-image-outset", + "border-image-repeat" + ] + } + }, + "border-image-outset": { + "codegen-properties": { + "custom": "All" + } + }, + "border-image-repeat": { + "codegen-properties": { + "custom": "All" + } + }, + "border-image-slice": { + "codegen-properties": { + "custom": "All" + } + }, + "border-image-source": { + "codegen-properties": { + "converter": "StyleImage" + } + }, + "border-image-width": { + "codegen-properties": { + "custom": "All" + } + }, + "border-left": { + "codegen-properties": { + "longhands": [ + "border-left-width", + "border-left-style", + "border-left-color" + ] + } + }, + "border-left-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "border-left-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "initial": "initialBorderStyle" + } + }, + "border-left-width": { + "codegen-properties": { + "initial": "initialBorderWidth", + "converter": "LineWidth" + } + }, + "border-radius": { + "codegen-properties": { + "longhands": [ + "border-top-left-radius", + "border-top-right-radius", + "border-bottom-right-radius", + "border-bottom-left-radius" + ] + } + }, + "border-right": { + "codegen-properties": { + "longhands": [ + "border-right-width", + "border-right-style", + "border-right-color" + ] + } + }, + "border-right-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "border-right-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "initial": "initialBorderStyle" + } + }, + "border-right-width": { + "codegen-properties": { + "initial": "initialBorderWidth", + "converter": "LineWidth" + } + }, + "border-spacing": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "-webkit-border-horizontal-spacing", + "-webkit-border-vertical-spacing" + ] + } + }, + "border-style": { + "codegen-properties": { + "longhands": [ + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style" + ] + } + }, + "border-top": { + "codegen-properties": { + "longhands": [ + "border-top-width", + "border-top-style", + "border-top-color" + ] + } + }, + "border-top-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "border-top-left-radius": { + "codegen-properties": { + "aliases": [ + "-webkit-border-top-left-radius" + ], + "initial": "initialBorderRadius", + "converter": "Radius" + } + }, + "border-top-right-radius": { + "codegen-properties": { + "aliases": [ + "-webkit-border-top-right-radius" + ], + "initial": "initialBorderRadius", + "converter": "Radius" + } + }, + "border-top-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "initial": "initialBorderStyle" + } + }, + "border-top-width": { + "codegen-properties": { + "initial": "initialBorderWidth", + "converter": "LineWidth" + } + }, + "border-width": { + "codegen-properties": { + "longhands": [ + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width" + ] + } + }, + "bottom": { + "codegen-properties": { + "initial": "initialOffset", + "converter": "LengthOrAuto" + } + }, + "box-shadow": { + "codegen-properties": { + "custom": "All" + } + }, + "box-sizing": { + "*": [ + "-webkit-box-sizing worked in Safari 4 and earlier." + ], + "values": [ + "border-box", + "content-box" + ], + "codegen-properties": { + "aliases": [ + "-webkit-box-sizing" + ] + } + }, + "break-after": { + "values": [ + "auto", + "avoid", + "left", + "right", + "recto", + "verso", + "column", + "page", + "region", + "avoid-column", + "avoid-page", + "avoid-region" + ], + "codegen-properties": { + "initial": "initialBreakBetween" + } + }, + "break-before": { + "values": [ + "auto", + "avoid", + "left", + "right", + "recto", + "verso", + "column", + "page", + "region", + "avoid-column", + "avoid-page", + "avoid-region" + ], + "codegen-properties": { + "initial": "initialBreakBetween" + } + }, + "break-inside": { + "values": [ + "auto", + "avoid", + "avoid-column", + "avoid-page", + "avoid-region" + ], + "codegen-properties": { + "initial": "initialBreakInside" + } + }, + "buffered-rendering": { + "values": [ + "auto", + "dynamic", + "static" + ], + "codegen-properties": { + "svg": true + } + }, + "caption-side": { + "inherited": true, + "values": [ + "left", + "right", + "top", + "bottom" + ], + "codegen-properties": { + "aliases": [ + "-epub-caption-side" + ] + } + }, + "clear": { + "values": [ + "none", + "left", + "right", + "both" + ] + }, + "clip": { + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-clip-path": { + "codegen-properties": { + "converter": "ClipPath" + } + }, + "clip-path": { + "codegen-properties": { + "name-for-methods": "ClipperResource", + "converter": "SVGURIReference", + "svg": true + } + }, + "clip-rule": { + "inherited": true, + "values": [ + "nonzero", + "evenodd" + ], + "codegen-properties": { + "svg": true + } + }, + "color-interpolation": { + "inherited": true, + "values": [ + "auto", + "srgb", + "linearrgb" + ], + "codegen-properties": { + "svg": true + } + }, + "color-interpolation-filters": { + "inherited": true, + "values": [ + "auto", + "srgb", + "linearrgb" + ], + "codegen-properties": { + "svg": true + } + }, + "color-profile": { + "codegen-properties": { + "skip-builder": true + } + }, + "color-rendering": { + "inherited": true, + "values": [ + "auto", + "optimizespeed", + "optimizequality" + ], + "codegen-properties": { + "svg": true + } + }, + "content": { + "codegen-properties": { + "custom": "All" + } + }, + "counter-increment": { + "codegen-properties": { + "custom": "All" + } + }, + "counter-reset": { + "codegen-properties": { + "custom": "All" + } + }, + "cursor": { + "inherited": true, + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-cursor-visibility": { + "inherited": true, + "values": [ + "auto", + "auto-hide" + ], + "codegen-properties": { + "enable-if": "ENABLE_CURSOR_VISIBILITY" + } + }, + "cx": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "cy": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "dominant-baseline": { + "values": [ + "auto", + "middle", + "use-script", + "no-change", + "reset-size", + "central", + "text-before-edge", + "text-after-edge", + "ideographic", + "hanging", + "mathematical" + ], + "codegen-properties": { + "svg": true + } + }, + "empty-cells": { + "inherited": true, + "values": [ + "show", + "hide" + ] + }, + "enable-background": { + "codegen-properties": { + "skip-builder": true + } + }, + "fill": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "svg": true + } + }, + "fill-opacity": { + "inherited": true, + "codegen-properties": { + "converter": "Opacity", + "svg": true + } + }, + "fill-rule": { + "inherited": true, + "values": [ + "nonzero", + "evenodd" + ], + "codegen-properties": { + "svg": true + } + }, + "float": { + "values": [ + "left", + "right", + "none", + "center" + ], + "codegen-properties": { + "name-for-methods": "Floating" + } + }, + "flood-color": { + "codegen-properties": { + "converter": "SVGColor", + "svg": true + } + }, + "flood-opacity": { + "codegen-properties": { + "converter": "Opacity", + "svg": true + } + }, + "font": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "font-family", + "font-size", + "font-style", + "font-variant-caps", + "font-weight", + "line-height" + ] + } + }, + "font-variant": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "font-variant-ligatures", + "font-variant-position", + "font-variant-caps", + "font-variant-numeric", + "font-variant-alternates", + "font-variant-east-asian" + ] + } + }, + "font-stretch": { + "values": [], + "codegen-properties": { + "skip-builder": true + } + }, + "glyph-orientation-horizontal": { + "inherited": true, + "codegen-properties": { + "converter": "GlyphOrientation", + "svg": true + } + }, + "glyph-orientation-vertical": { + "inherited": true, + "codegen-properties": { + "converter": "GlyphOrientationOrAuto", + "svg": true + } + }, + "hanging-punctuation": { + "inherited": true, + "codegen-properties": { + "converter": "HangingPunctuation" + } + }, + "height": { + "codegen-properties": { + "initial": "initialSize", + "converter": "LengthSizing" + } + }, + "image-orientation": { + "inherited": true, + "codegen-properties": { + "enable-if": "ENABLE_CSS_IMAGE_ORIENTATION" + } + }, + "image-rendering": { + "inherited": true, + "values": [ + "auto", + "optimizespeed", + "optimizequality", + "-webkit-crisp-edges", + "-webkit-optimize-contrast", + "crisp-edges", + "pixelated" + ] + }, + "image-resolution": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "enable-if": "ENABLE_CSS_IMAGE_RESOLUTION" + } + }, + "kerning": { + "inherited": true, + "codegen-properties": { + "converter": "SVGLengthValue", + "svg": true + } + }, + "left": { + "codegen-properties": { + "initial": "initialOffset", + "converter": "LengthOrAuto" + } + }, + "letter-spacing": { + "inherited": true, + "codegen-properties": { + "converter": "Spacing" + } + }, + "lighting-color": { + "codegen-properties": { + "converter": "SVGColor", + "svg": true + } + }, + "line-height": [ + { + "inherited": true, + "codegen-properties": { + "custom": "All", + "enable-if": "ENABLE_TEXT_AUTOSIZING" + } + }, + { + "inherited": true, + "codegen-properties": { + "getter": "specifiedLineHeight", + "conditional-converter": "LineHeight", + "enable-if": "!ENABLE_TEXT_AUTOSIZING" + } + } + ], + "list-style": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "list-style-type", + "list-style-position", + "list-style-image" + ] + } + }, + "list-style-image": { + "inherited": true, + "codegen-properties": { + "converter": "StyleImage" + } + }, + "list-style-position": { + "inherited": true, + "values": [ + "inside", + "outside" + ] + }, + "list-style-type": { + "inherited": true, + "values": [ + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "arabic-indic", + "binary", + "bengali", + "cambodian", + "khmer", + "devanagari", + "gujarati", + "gurmukhi", + "kannada", + "lower-hexadecimal", + "lao", + "malayalam", + "mongolian", + "myanmar", + "octal", + "oriya", + "persian", + "urdu", + "telugu", + "tibetan", + "thai", + "upper-hexadecimal", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "afar", + "ethiopic-halehame-aa-et", + "ethiopic-halehame-aa-er", + "amharic", + "ethiopic-halehame-am-et", + "amharic-abegede", + "ethiopic-abegede-am-et", + "cjk-earthly-branch", + "cjk-heavenly-stem", + "ethiopic", + "ethiopic-halehame-gez", + "ethiopic-abegede", + "ethiopic-abegede-gez", + "hangul-consonant", + "hangul", + "lower-norwegian", + "oromo", + "ethiopic-halehame-om-et", + "sidama", + "ethiopic-halehame-sid-et", + "somali", + "ethiopic-halehame-so-et", + "tigre", + "ethiopic-halehame-tig", + "tigrinya-er", + "ethiopic-halehame-ti-er", + "tigrinya-er-abegede", + "ethiopic-abegede-ti-er", + "tigrinya-et", + "ethiopic-halehame-ti-et", + "tigrinya-et-abegede", + "ethiopic-abegede-ti-et", + "upper-greek", + "upper-norwegian", + "asterisks", + "footnotes", + "hebrew", + "armenian", + "lower-armenian", + "upper-armenian", + "georgian", + "cjk-ideographic", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + "none" + ] + }, + "margin": { + "codegen-properties": { + "longhands": [ + "margin-top", + "margin-right", + "margin-bottom", + "margin-left" + ] + } + }, + "margin-bottom": { + "codegen-properties": { + "initial": "initialMargin", + "converter": "LengthOrAuto" + } + }, + "margin-left": { + "codegen-properties": { + "initial": "initialMargin", + "converter": "LengthOrAuto" + } + }, + "margin-right": { + "codegen-properties": { + "initial": "initialMargin", + "converter": "LengthOrAuto" + } + }, + "margin-top": { + "codegen-properties": { + "initial": "initialMargin", + "converter": "LengthOrAuto" + } + }, + "marker": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "marker-start", + "marker-mid", + "marker-end" + ] + } + }, + "marker-end": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "MarkerEndResource", + "converter": "SVGURIReference", + "svg": true + } + }, + "marker-mid": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "MarkerMidResource", + "converter": "SVGURIReference", + "svg": true + } + }, + "marker-start": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "MarkerStartResource", + "converter": "SVGURIReference", + "svg": true + } + }, + "mask": { + "codegen-properties": { + "name-for-methods": "MaskerResource", + "converter": "SVGURIReference", + "svg": true + } + }, + "mask-type": { + "values": [ + "luminance", + "alpha" + ], + "codegen-properties": { + "svg": true + } + }, + "max-height": { + "codegen-properties": { + "initial": "initialMaxSize", + "converter": "LengthMaxSizing" + } + }, + "max-width": { + "codegen-properties": { + "initial": "initialMaxSize", + "converter": "LengthMaxSizing" + } + }, + "min-height": { + "codegen-properties": { + "initial": "initialMinSize", + "converter": "LengthSizing" + } + }, + "min-width": { + "codegen-properties": { + "initial": "initialMinSize", + "converter": "LengthSizing" + } + }, + "object-fit": { + "values": [ + "fill", + "contain", + "cover", + "none", + "scale-down" + ] + }, + "object-position": { + "codegen-properties": { + "converter": "ObjectPosition" + } + }, + "opacity": { + "*": [ + "Honor -webkit-opacity as a synonym for opacity. This was the only syntax that worked in Safari 1.1,", + "and may be in use on some websites and widgets." + ], + "codegen-properties": { + "aliases": [ + "-webkit-opacity" + ] + } + }, + "orphans": { + "inherited": true, + "codegen-properties": { + "auto-functions": true + } + }, + "outline": { + "codegen-properties": { + "longhands": [ + "outline-color", + "outline-style", + "outline-width" + ] + } + }, + "outline-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "outline-offset": { + "codegen-properties": { + "converter": "ComputedLength" + } + }, + "outline-style": { + "values": [ + "auto", + "none", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "custom": "All" + } + }, + "outline-width": { + "codegen-properties": { + "converter": "LineWidth" + } + }, + "overflow": { + "codegen-properties": { + "longhands": [ + "overflow-x", + "overflow-y" + ] + } + }, + "overflow-wrap": { + "values": [ + "normal", + "break-word" + ] + }, + "overflow-x": { + "values": [ + "visible", + "hidden", + "scroll", + "auto", + "overlay" + ] + }, + "overflow-y": { + "values": [ + "visible", + "hidden", + "scroll", + "auto", + "overlay", + "-webkit-paged-x", + "-webkit-paged-y" + ] + }, + "padding": { + "codegen-properties": { + "longhands": [ + "padding-top", + "padding-right", + "padding-bottom", + "padding-left" + ] + } + }, + "padding-bottom": { + "codegen-properties": { + "initial": "initialPadding", + "converter": "Length" + } + }, + "padding-left": { + "codegen-properties": { + "initial": "initialPadding", + "converter": "Length" + } + }, + "padding-right": { + "codegen-properties": { + "initial": "initialPadding", + "converter": "Length" + } + }, + "padding-top": { + "codegen-properties": { + "initial": "initialPadding", + "converter": "Length" + } + }, + "page": { + "codegen-properties": { + "skip-builder": true + } + }, + "page-break-after": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakAfter", + "converter": "PageBreakBetween" + } + }, + "page-break-before": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakBefore", + "converter": "PageBreakBetween" + } + }, + "page-break-inside": { + "values": [ + "auto", + "avoid" + ], + "codegen-properties": { + "initial": "initialBreakInside", + "name-for-methods": "BreakInside", + "converter": "PageBreakInside" + } + }, + "paint-order": { + "codegen-properties": { + "converter": "PaintOrder" + } + }, + "pointer-events": { + "inherited": true, + "values": [ + "visible", + "none", + "all", + "auto", + "visiblepainted", + "visiblefill", + "visiblestroke", + "painted", + "fill", + "stroke" + ] + }, + "position": { + "values": [ + "static", + "relative", + "absolute", + "fixed", + "-webkit-sticky" + ] + }, + "quotes": { + "inherited": true, + "codegen-properties": { + "converter": "Quotes" + } + }, + "r": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "resize": { + "inherited": true, + "values": [ + "none", + "both", + "horizontal", + "vertical", + "auto" + ], + "codegen-properties": { + "converter": "Resize" + } + }, + "right": { + "codegen-properties": { + "initial": "initialOffset", + "converter": "LengthOrAuto" + } + }, + "rx": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "ry": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "shape-rendering": { + "inherited": true, + "values": [ + "auto", + "optimizespeed", + "crispedges", + "geometricprecision" + ], + "codegen-properties": { + "svg": true + } + }, + "size": { + "codegen-properties": { + "custom": "All" + } + }, + "src": { + "codegen-properties": { + "skip-builder": true + } + }, + "stop-color": { + "codegen-properties": { + "converter": "SVGColor", + "svg": true + } + }, + "stop-opacity": { + "codegen-properties": { + "converter": "Opacity", + "svg": true + } + }, + "stroke": { + "inherited": true, + "codegen-properties": { + "custom": "All", + "svg": true + } + }, + "stroke-dasharray": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "StrokeDashArray", + "converter": "StrokeDashArray", + "svg": true + } + }, + "stroke-dashoffset": { + "inherited": true, + "codegen-properties": { + "initial": "initialZeroLength", + "name-for-methods": "StrokeDashOffset", + "converter": "Length" + } + }, + "stroke-linecap": { + "inherited": true, + "values": [ + "butt", + "round", + "square" + ], + "codegen-properties": { + "name-for-methods": "CapStyle" + } + }, + "stroke-linejoin": { + "inherited": true, + "values": [ + "miter", + "round", + "bevel" + ], + "codegen-properties": { + "name-for-methods": "JoinStyle" + } + }, + "stroke-miterlimit": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "StrokeMiterLimit", + "converter": "Number", + "svg": true + } + }, + "stroke-opacity": { + "inherited": true, + "codegen-properties": { + "converter": "Opacity", + "svg": true + } + }, + "stroke-width": { + "inherited": true, + "codegen-properties": { + "initial": "initialOneLength", + "converter": "Length" + } + }, + "speak": { + "inherited": true, + "values": [ + "none", + "normal", + "spell-out", + "digits", + "literal-punctuation", + "no-punctuation" + ] + }, + "table-layout": { + "values": [ + "auto", + "fixed" + ] + }, + "tab-size": { + "inherited": true + }, + "text-align": { + "inherited": true, + "values": [ + "-webkit-auto", + "left", + "right", + "center", + "justify", + "-webkit-left", + "-webkit-right", + "-webkit-center", + "-webkit-match-parent", + "start", + "end" + ], + "codegen-properties": { + "converter": "TextAlign", + "custom": "Initial|Value" + } + }, + "text-anchor": { + "inherited": true, + "values": [ + "start", + "middle", + "end" + ], + "codegen-properties": { + "svg": true + } + }, + "text-decoration": { + "codegen-properties": { + "converter": "TextDecoration" + } + }, + "text-indent": { + "inherited": true, + "codegen-properties": { + "custom": "All" + } + }, + "text-line-through": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-line-through-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-line-through-mode": { + "values": [ + "continuous", + "skip-white-space" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-line-through-style": { + "values": [ + "none", + "solid", + "double", + "dashed", + "dot-dash", + "dot-dot-dash", + "wave" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-line-through-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-overflow": { + "values": [ + "clip", + "ellipsis" + ] + }, + "text-overline": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-overline-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-overline-mode": { + "values": [ + "continuous", + "skip-white-space" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-overline-style": { + "values": [ + "none", + "solid", + "double", + "dashed", + "dot-dash", + "dot-dot-dash", + "wave" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-overline-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-shadow": { + "inherited": true, + "codegen-properties": { + "custom": "All" + } + }, + "text-transform": { + "inherited": true, + "values": [ + "capitalize", + "uppercase", + "lowercase", + "none" + ], + "codegen-properties": { + "aliases": [ + "-epub-text-transform" + ] + } + }, + "text-underline": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-underline-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "text-underline-mode": { + "values": [ + "continuous", + "skip-white-space" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-underline-style": { + "values": [ + "none", + "solid", + "double", + "dashed", + "dot-dash", + "dot-dot-dash", + "wave" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "text-underline-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "top": { + "codegen-properties": { + "initial": "initialOffset", + "converter": "LengthOrAuto" + } + }, + "transition": { + "codegen-properties": { + "aliases": [ + "-webkit-transition" + ], + "longhands": [ + "transition-property", + "transition-duration", + "transition-timing-function", + "transition-delay" + ] + } + }, + "transition-delay": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-transition-delay" + ], + "name-for-methods": "Delay" + } + }, + "transition-duration": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-transition-duration" + ], + "name-for-methods": "Duration" + } + }, + "transition-property": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-transition-property" + ], + "name-for-methods": "Property" + } + }, + "transition-timing-function": { + "animatable": true, + "codegen-properties": { + "aliases": [ + "-webkit-transition-timing-function" + ], + "name-for-methods": "TimingFunction" + } + }, + "unicode-bidi": { + "values": [ + "normal", + "embed", + "bidi-override", + "-webkit-isolate", + "-webkit-isolate-override", + "-webkit-plaintext" + ] + }, + "unicode-range": { + "codegen-properties": { + "skip-builder": true + } + }, + "vector-effect": { + "values": [ + "none", + "non-scaling-stroke" + ], + "codegen-properties": { + "svg": true + } + }, + "vertical-align": { + "codegen-properties": { + "custom": "Value" + } + }, + "visibility": { + "inherited": true, + "values": [ + "visible", + "hidden", + "collapse" + ] + }, + "white-space": { + "inherited": true, + "values": [ + "normal", + "pre", + "pre-wrap", + "pre-line", + "nowrap" + ] + }, + "widows": { + "inherited": true, + "codegen-properties": { + "auto-functions": true + } + }, + "width": { + "codegen-properties": { + "initial": "initialSize", + "converter": "LengthSizing" + } + }, + "will-change": { + "codegen-properties": { + "custom": "Value" + } + }, + "word-break": { + "inherited": true, + "values": [ + "normal", + "break-all", + "keep-all", + "break-word" + ], + "codegen-properties": { + "aliases": [ + "-epub-word-break" + ] + } + }, + "word-spacing": { + "inherited": true, + "codegen-properties": { + "conditional-converter": "WordSpacing" + } + }, + "word-wrap": { + "inherited": true, + "values": [ + "normal", + "break-word" + ], + "codegen-properties": { + "name-for-methods": "OverflowWrap" + } + }, + "x": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "y": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "z-index": { + "codegen-properties": { + "auto-functions": true + } + }, + "alt": { + "codegen-properties": { + "aliases": [ + "-webkit-alt" + ], + "name-for-methods": "ContentAltText", + "custom": "Value" + } + }, + "-webkit-animation-trigger": { + "animatable": true, + "codegen-properties": { + "name-for-methods": "Trigger", + "enable-if": "ENABLE_CSS_ANIMATIONS_LEVEL_2" + } + }, + "-webkit-appearance": { + "values": [ + "checkbox", + "radio", + "push-button", + "square-button", + "button", + "button-bevel", + "default-button", + "inner-spin-button", + "listbox", + "listitem", + "media-controls-background", + "media-controls-dark-bar-background", + "media-controls-fullscreen-background", + "media-controls-light-bar-background", + "media-current-time-display", + "media-enter-fullscreen-button", + "media-exit-fullscreen-button", + "media-fullscreen-volume-slider", + "media-fullscreen-volume-slider-thumb", + "media-mute-button", + "media-overlay-play-button", + "media-play-button", + "media-return-to-realtime-button", + "media-rewind-button", + "media-seek-back-button", + "media-seek-forward-button", + "media-slider", + "media-sliderthumb", + "media-time-remaining-display", + "media-toggle-closed-captions-button", + "media-volume-slider", + "media-volume-slider-container", + "media-volume-slider-mute-button", + "media-volume-sliderthumb", + "menulist", + "menulist-button", + "menulist-text", + "menulist-textfield", + "meter", + "progress-bar", + "progress-bar-value", + "slider-horizontal", + "slider-vertical", + "sliderthumb-horizontal", + "sliderthumb-vertical", + "caret", + "searchfield", + "searchfield-decoration", + "searchfield-results-decoration", + "searchfield-results-button", + "searchfield-cancel-button", + "snapshotted-plugin-overlay", + "textfield", + "relevancy-level-indicator", + "continuous-capacity-level-indicator", + "discrete-capacity-level-indicator", + "rating-level-indicator", + "image-controls-button", + "-apple-pay-button", + "textarea", + "attachment", + "caps-lock-indicator", + "none" + ] + }, + "-webkit-aspect-ratio": { + "inherited": true, + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-backface-visibility": { + "values": [ + "visible", + "hidden" + ] + }, + "-webkit-background-clip": { + "codegen-properties": { + "name-for-methods": "Clip", + "fill-layer-property": true + } + }, + "-webkit-background-composite": { + "codegen-properties": { + "name-for-methods": "Composite", + "fill-layer-property": true + } + }, + "-webkit-background-origin": { + "codegen-properties": { + "name-for-methods": "Origin", + "fill-layer-property": true + } + }, + "-webkit-background-size": { + "*": [ + "Differs from background-size only in the interpretation of a single value: \"-webkit-background-size: l;\"", + "is equivalent to \"background-size: l l;\" whereas \"background-size: l;\" is equivalent to", + "\"background-size: l auto;\"" + ], + "codegen-properties": { + "name-for-methods": "Size", + "fill-layer-property": true + } + }, + "-webkit-border-after": { + "codegen-properties": { + "longhands": [ + "-webkit-border-after-width", + "-webkit-border-after-style", + "-webkit-border-after-color" + ] + } + }, + "-webkit-border-after-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-after-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-after-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-before": { + "codegen-properties": { + "longhands": [ + "-webkit-border-before-width", + "-webkit-border-before-style", + "-webkit-border-before-color" + ] + } + }, + "-webkit-border-before-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-before-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-before-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-end": { + "codegen-properties": { + "longhands": [ + "-webkit-border-end-width", + "-webkit-border-end-style", + "-webkit-border-end-color" + ] + } + }, + "-webkit-border-end-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-end-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-end-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-fit": { + "values": [ + "border", + "lines" + ] + }, + "-webkit-border-horizontal-spacing": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "HorizontalBorderSpacing", + "converter": "ComputedLength" + } + }, + "-webkit-border-image": { + "codegen-properties": { + "initial": "initialNinePieceImage", + "converter": "BorderImage" + } + }, + "-webkit-border-radius": { + "*": [ + "Differs from border-radius only in the interpretation of a value consisting of two lengths:", + "\"-webkit-border-radius: l1 l2;\" is equivalent to \"border-radius: l1 / l2;\"." + ], + "codegen-properties": { + "longhands": [ + "border-top-left-radius", + "border-top-right-radius", + "border-bottom-right-radius", + "border-bottom-left-radius" + ] + } + }, + "-webkit-border-start": { + "codegen-properties": { + "longhands": [ + "-webkit-border-start-width", + "-webkit-border-start-style", + "-webkit-border-start-color" + ] + } + }, + "-webkit-border-start-color": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-start-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-start-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-border-vertical-spacing": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "VerticalBorderSpacing", + "converter": "ComputedLength" + } + }, + "-webkit-box-align": { + "values": [ + "stretch", + "start", + "end", + "center", + "baseline" + ] + }, + "-webkit-box-direction": { + "inherited": true, + "values": [ + "normal", + "reverse" + ] + }, + "-webkit-box-flex": {}, + "-webkit-box-flex-group": {}, + "-webkit-box-lines": { + "values": [ + "single", + "multiple" + ] + }, + "-webkit-box-ordinal-group": {}, + "-webkit-box-orient": { + "values": [ + "horizontal", + "vertical", + "inline-axis", + "block-axis" + ] + }, + "-webkit-box-pack": { + "values": [ + "start", + "end", + "center", + "justify" + ] + }, + "-webkit-box-reflect": { + "codegen-properties": { + "converter": "Reflection" + } + }, + "-webkit-box-shadow": { + "*": [ + "Differs from box-shadow in its treatement of blur radii > 8px. Let -webkit-box-shadow blur", + "radius be w_r and box-shadow blur radius be b_r. For w_r > 8px, b_r = 8 + 4 * sqrt((w_r - 8) / 2)." + ], + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-column-axis": { + "values": [ + "horizontal", + "vertical", + "auto" + ] + }, + "-webkit-column-break-after": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakAfter", + "converter": "ColumnBreakBetween" + } + }, + "-webkit-column-break-before": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakBefore", + "converter": "ColumnBreakBetween" + } + }, + "-webkit-column-break-inside": { + "values": [ + "auto", + "avoid" + ], + "codegen-properties": { + "initial": "initialBreakInside", + "name-for-methods": "BreakInside", + "converter": "ColumnBreakInside" + } + }, + "column-count": { + "codegen-properties": { + "aliases": [ + "-webkit-column-count" + ], + "auto-functions": true + } + }, + "column-fill": { + "values": [ + "auto", + "balance" + ], + "codegen-properties": { + "aliases": [ + "-webkit-column-fill" + ] + } + }, + "column-gap": { + "codegen-properties": { + "aliases": [ + "-webkit-column-gap" + ], + "custom": "All" + } + }, + "-webkit-column-progression": { + "values": [ + "normal", + "reverse" + ] + }, + "column-rule": { + "codegen-properties": { + "aliases": [ + "-webkit-column-rule" + ], + "longhands": [ + "column-rule-width", + "column-rule-style", + "column-rule-color" + ] + } + }, + "column-rule-color": { + "codegen-properties": { + "aliases": [ + "-webkit-column-rule-color" + ], + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "column-rule-style": { + "values": [ + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double" + ], + "codegen-properties": { + "aliases": [ + "-webkit-column-rule-style" + ], + "initial": "initialBorderStyle" + } + }, + "column-rule-width": { + "codegen-properties": { + "aliases": [ + "-webkit-column-rule-width" + ], + "converter": "LineWidth" + } + }, + "column-span": { + "codegen-properties": { + "aliases": [ + "-webkit-column-span" + ] + } + }, + "column-width": { + "codegen-properties": { + "aliases": [ + "-webkit-column-width" + ], + "converter": "ComputedLength", + "auto-functions": true + } + }, + "columns": { + "codegen-properties": { + "aliases": [ + "-webkit-columns" + ], + "longhands": [ + "column-width", + "column-count" + ] + } + }, + "-webkit-box-decoration-break": { + "values": [ + "clone", + "slice" + ], + "codegen-properties": { + "enable-if": "ENABLE_CSS_BOX_DECORATION_BREAK" + } + }, + "mix-blend-mode": { + "values": [ + "normal", + "multiply", + "screen", + "overlay", + "darken", + "lighten", + "color-dodge", + "color-burn", + "hard-light", + "soft-light", + "difference", + "exclusion", + "plus-darker", + "plus-lighter" + ], + "codegen-properties": { + "name-for-methods": "BlendMode", + "enable-if": "ENABLE_CSS_COMPOSITING" + } + }, + "isolation": { + "values": [ + "auto", + "isolate" + ], + "codegen-properties": { + "enable-if": "ENABLE_CSS_COMPOSITING" + } + }, + "filter": { + "codegen-properties": { + "aliases": [ + "-webkit-filter" + ], + "conditional-converter": "FilterOperations" + } + }, + "align-content": { + "values": [ + "flex-start", + "flex-end", + "center", + "space-between", + "space-around", + "stretch" + ], + "codegen-properties": { + "aliases": [ + "-webkit-align-content" + ], + "initial": "initialContentAlignment", + "converter": "ContentAlignmentData" + } + }, + "align-items": { + "values": [ + "flex-start", + "flex-end", + "center", + "baseline", + "stretch" + ], + "codegen-properties": { + "aliases": [ + "-webkit-align-items" + ], + "initial": "initialDefaultAlignment", + "converter": "SelfOrDefaultAlignmentData" + } + }, + "align-self": { + "values": [ + "auto", + "flex-start", + "flex-end", + "center", + "baseline", + "stretch" + ], + "codegen-properties": { + "aliases": [ + "-webkit-align-self" + ], + "initial": "initialSelfAlignment", + "converter": "SelfOrDefaultAlignmentData" + } + }, + "flex": { + "codegen-properties": { + "aliases": [ + "-webkit-flex" + ], + "longhands": [ + "flex-grow", + "flex-shrink", + "flex-basis" + ] + } + }, + "flex-basis": { + "codegen-properties": { + "aliases": [ + "-webkit-flex-basis" + ], + "converter": "LengthOrAuto" + } + }, + "flex-direction": { + "values": [ + "row", + "row-reverse", + "column", + "column-reverse" + ], + "codegen-properties": { + "aliases": [ + "-webkit-flex-direction" + ] + } + }, + "flex-flow": { + "codegen-properties": { + "aliases": [ + "-webkit-flex-flow" + ], + "longhands": [ + "flex-direction", + "flex-wrap" + ] + } + }, + "flex-grow": { + "codegen-properties": { + "aliases": [ + "-webkit-flex-grow" + ] + } + }, + "flex-shrink": { + "codegen-properties": { + "aliases": [ + "-webkit-flex-shrink" + ] + } + }, + "flex-wrap": { + "values": [ + "nowrap", + "wrap", + "wrap-reverse" + ], + "codegen-properties": { + "aliases": [ + "-webkit-flex-wrap" + ] + } + }, + "justify-content": { + "values": [ + "flex-start", + "flex-end", + "center", + "space-between", + "space-around" + ], + "codegen-properties": { + "aliases": [ + "-webkit-justify-content" + ], + "initial": "initialContentAlignment", + "converter": "ContentAlignmentData" + } + }, + "-webkit-backdrop-filter": { + "codegen-properties": { + "conditional-converter": "FilterOperations", + "enable-if": "ENABLE_FILTERS_LEVEL_2" + } + }, + "-webkit-font-size-delta": { + "codegen-properties": { + "skip-builder": true + } + }, + "justify-self": { + "codegen-properties": { + "initial": "initialSelfAlignment", + "converter": "SelfOrDefaultAlignmentData" + } + }, + "justify-items": { + "codegen-properties": { + "aliases": [ + "-webkit-justify-items" + ], + "initial": "initialSelfAlignment", + "converter": "SelfOrDefaultAlignmentData" + } + }, + "grid": { + "codegen-properties": { + "longhands": [ + "grid-template-rows", + "grid-template-columns", + "grid-template-areas", + "grid-auto-flow", + "grid-auto-rows", + "grid-auto-columns", + "grid-column-gap", + "grid-row-gap" + ] + } + }, + "grid-area": { + "codegen-properties": { + "longhands": [ + "grid-row-start", + "grid-column-start", + "grid-row-end", + "grid-column-end" + ] + } + }, + "grid-auto-columns": { + "codegen-properties": { + "converter": "GridTrackSizeList" + } + }, + "grid-auto-rows": { + "codegen-properties": { + "converter": "GridTrackSizeList" + } + }, + "grid-column-end": { + "codegen-properties": { + "name-for-methods": "GridItemColumnEnd", + "conditional-converter": "GridPosition" + } + }, + "grid-column-gap": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "grid-column-start": { + "codegen-properties": { + "name-for-methods": "GridItemColumnStart", + "conditional-converter": "GridPosition" + } + }, + "grid-template": { + "codegen-properties": { + "longhands": [ + "grid-template-rows", + "grid-template-columns", + "grid-template-areas" + ] + } + }, + "grid-template-columns": { + "codegen-properties": { + "custom": "All" + } + }, + "grid-template-rows": { + "codegen-properties": { + "custom": "All" + } + }, + "grid-row-end": { + "codegen-properties": { + "name-for-methods": "GridItemRowEnd", + "conditional-converter": "GridPosition" + } + }, + "grid-row-gap": { + "codegen-properties": { + "initial": "initialZeroLength", + "converter": "Length" + } + }, + "grid-row-start": { + "codegen-properties": { + "name-for-methods": "GridItemRowStart", + "conditional-converter": "GridPosition" + } + }, + "grid-column": { + "codegen-properties": { + "longhands": [ + "grid-column-start", + "grid-column-end" + ] + } + }, + "grid-gap": { + "codegen-properties": { + "longhands": [ + "grid-row-gap", + "grid-column-gap" + ] + } + }, + "grid-row": { + "codegen-properties": { + "longhands": [ + "grid-row-start", + "grid-row-end" + ] + } + }, + "grid-template-areas": { + "codegen-properties": { + "custom": "All" + } + }, + "grid-auto-flow": { + "codegen-properties": { + "converter": "GridAutoFlow" + } + }, + "-webkit-hyphenate-character": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "HyphenationString", + "converter": "StringOrAuto" + } + }, + "-webkit-hyphenate-limit-after": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "HyphenationLimitAfter", + "converter": "NumberOrAuto" + } + }, + "-webkit-hyphenate-limit-before": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "HyphenationLimitBefore", + "converter": "NumberOrAuto" + } + }, + "-webkit-hyphenate-limit-lines": { + "inherited": true, + "codegen-properties": { + "name-for-methods": "HyphenationLimitLines", + "converter": "WebkitHyphenateLimitLines" + } + }, + "-webkit-hyphens": { + "inherited": true, + "values": [ + "none", + "manual", + "auto" + ], + "codegen-properties": { + "aliases": [ + "-epub-hyphens" + ] + } + }, + "-webkit-initial-letter": { + "codegen-properties": { + "converter": "InitialLetter" + } + }, + "-webkit-line-box-contain": { + "inherited": true, + "codegen-properties": { + "converter": "LineBoxContain" + } + }, + "-webkit-line-align": { + "inherited": true, + "values": [ + "none", + "edges" + ] + }, + "-webkit-line-break": { + "inherited": true, + "values": [ + "auto", + "loose", + "normal", + "strict", + "after-white-space" + ] + }, + "-webkit-line-clamp": {}, + "-webkit-line-grid": { + "inherited": true, + "codegen-properties": { + "converter": "StringOrNone" + } + }, + "-webkit-line-snap": { + "inherited": true, + "values": [ + "none", + "baseline", + "contain" + ] + }, + "-webkit-logical-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-logical-height": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-margin-after-collapse": { + "values": [ + "collapse", + "separate", + "discard" + ] + }, + "-webkit-margin-before-collapse": { + "values": [ + "collapse", + "separate", + "discard" + ] + }, + "-webkit-margin-bottom-collapse": { + "values": [ + "collapse", + "separate", + "discard" + ], + "codegen-properties": { + "name-for-methods": "MarginAfterCollapse" + } + }, + "-webkit-margin-top-collapse": { + "values": [ + "collapse", + "separate", + "discard" + ], + "codegen-properties": { + "name-for-methods": "MarginBeforeCollapse" + } + }, + "-webkit-margin-collapse": { + "codegen-properties": { + "longhands": [ + "-webkit-margin-before-collapse", + "-webkit-margin-after-collapse" + ] + } + }, + "-webkit-margin-after": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-margin-before": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-margin-end": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-margin-start": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-marquee": { + "codegen-properties": { + "longhands": [ + "-webkit-marquee-direction", + "-webkit-marquee-increment", + "-webkit-marquee-repetition", + "-webkit-marquee-style", + "-webkit-marquee-speed" + ] + } + }, + "-webkit-marquee-direction": { + "values": [ + "forwards", + "backwards", + "ahead", + "reverse", + "left", + "right", + "down", + "up", + "auto" + ] + }, + "-webkit-marquee-increment": { + "codegen-properties": { + "conditional-converter": "MarqueeIncrement" + } + }, + "-webkit-marquee-repetition": { + "codegen-properties": { + "name-for-methods": "MarqueeLoopCount", + "converter": "MarqueeRepetition" + } + }, + "-webkit-marquee-speed": { + "codegen-properties": { + "converter": "MarqueeSpeed" + } + }, + "-webkit-marquee-style": { + "values": [ + "none", + "slide", + "scroll", + "alternate" + ], + "codegen-properties": { + "name-for-methods": "MarqueeBehavior" + } + }, + "-webkit-mask": { + "codegen-properties": { + "longhands": [ + "-webkit-mask-image", + "-webkit-mask-source-type", + "-webkit-mask-position-x", + "-webkit-mask-position-y", + "-webkit-mask-size", + "-webkit-mask-repeat-x", + "-webkit-mask-repeat-y", + "-webkit-mask-origin", + "-webkit-mask-clip" + ] + } + }, + "-webkit-mask-box-image": { + "codegen-properties": { + "initial": "initialNinePieceImage", + "converter": "BorderMask" + } + }, + "-webkit-mask-box-image-outset": { + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-mask-box-image-repeat": { + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-mask-box-image-slice": { + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-mask-box-image-source": { + "codegen-properties": { + "converter": "StyleImage" + } + }, + "-webkit-mask-box-image-width": { + "codegen-properties": { + "custom": "All" + } + }, + "-webkit-mask-clip": { + "codegen-properties": { + "name-for-methods": "Clip", + "fill-layer-property": true + } + }, + "-webkit-mask-composite": { + "codegen-properties": { + "name-for-methods": "Composite", + "fill-layer-property": true + } + }, + "-webkit-mask-image": { + "codegen-properties": { + "name-for-methods": "Image", + "fill-layer-property": true + } + }, + "-webkit-mask-origin": { + "codegen-properties": { + "name-for-methods": "Origin", + "fill-layer-property": true + } + }, + "-webkit-mask-position": { + "codegen-properties": { + "longhands": [ + "-webkit-mask-position-x", + "-webkit-mask-position-y" + ] + } + }, + "-webkit-mask-position-x": { + "codegen-properties": { + "name-for-methods": "XPosition", + "fill-layer-property": true + } + }, + "-webkit-mask-position-y": { + "codegen-properties": { + "name-for-methods": "YPosition", + "fill-layer-property": true + } + }, + "-webkit-mask-repeat": { + "codegen-properties": { + "longhands": [ + "-webkit-mask-repeat-x", + "-webkit-mask-repeat-y" + ] + } + }, + "-webkit-mask-repeat-x": { + "codegen-properties": { + "name-for-methods": "RepeatX", + "fill-layer-property": true, + "internal-only": true + } + }, + "-webkit-mask-repeat-y": { + "codegen-properties": { + "name-for-methods": "RepeatY", + "fill-layer-property": true, + "internal-only": true + } + }, + "-webkit-mask-size": { + "codegen-properties": { + "name-for-methods": "Size", + "fill-layer-property": true + } + }, + "-webkit-mask-source-type": { + "codegen-properties": { + "name-for-methods": "MaskSourceType", + "fill-layer-property": true + } + }, + "-webkit-max-logical-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-max-logical-height": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-min-logical-width": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-min-logical-height": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-nbsp-mode": { + "inherited": true, + "values": [ + "normal", + "space" + ], + "codegen-properties": { + "initial": "initialNBSPMode", + "setter": "setNBSPMode" + } + }, + "order": { + "codegen-properties": { + "aliases": [ + "-webkit-order" + ] + } + }, + "-webkit-padding-after": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-padding-before": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-padding-end": { + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-padding-start": { + "codegen-properties": { + "skip-builder": true + } + }, + "perspective": { + "codegen-properties": { + "aliases": [ + "-webkit-perspective" + ], + "conditional-converter": "Perspective" + } + }, + "perspective-origin": { + "codegen-properties": { + "aliases": [ + "-webkit-perspective-origin" + ], + "longhands": [ + "perspective-origin-x", + "perspective-origin-y" + ] + } + }, + "perspective-origin-x": { + "codegen-properties": { + "aliases": [ + "-webkit-perspective-origin-x" + ], + "converter": "PositionComponentX" + } + }, + "perspective-origin-y": { + "codegen-properties": { + "aliases": [ + "-webkit-perspective-origin-y" + ], + "converter": "PositionComponentY" + } + }, + "-webkit-print-color-adjust": { + "inherited": true, + "values": [ + "exact", + "economy" + ] + }, + "-webkit-rtl-ordering": { + "inherited": true, + "values": [ + "logical", + "visual" + ], + "codegen-properties": { + "initial": "initialRTLOrdering", + "setter": "setRTLOrdering" + } + }, + "-webkit-svg-shadow": { + "codegen-properties": { + "custom": "All", + "svg": true + } + }, + "-webkit-text-combine": { + "inherited": true, + "values": [ + "none", + "horizontal" + ], + "codegen-properties": { + "aliases": [ + "-epub-text-combine" + ] + } + }, + "-webkit-text-align-last": { + "inherited": true, + "values": [ + "left", + "right", + "center", + "justify", + "start", + "end", + "auto" + ], + "codegen-properties": { + "enable-if": "ENABLE_CSS3_TEXT" + } + }, + "-webkit-text-justify": { + "inherited": true, + "values": [ + "inter-word", + "distribute", + "auto", + "none" + ], + "codegen-properties": { + "enable-if": "ENABLE_CSS3_TEXT" + } + }, + "-webkit-text-decoration": { + "codegen-properties": { + "longhands": [ + "-webkit-text-decoration-line", + "-webkit-text-decoration-style", + "-webkit-text-decoration-color" + ] + } + }, + "-webkit-text-decoration-line": { + "codegen-properties": { + "name-for-methods": "TextDecoration", + "converter": "TextDecoration" + } + }, + "-webkit-text-decoration-style": { + "values": [ + "solid", + "double", + "dotted", + "dashed", + "wavy" + ] + }, + "-webkit-text-decoration-color": { + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "-webkit-text-decoration-skip": { + "inherited": true, + "codegen-properties": { + "converter": "TextDecorationSkip" + } + }, + "-webkit-text-underline-position": { + "inherited": true, + "codegen-properties": { + "converter": "TextUnderlinePosition" + } + }, + "-webkit-text-decorations-in-effect": { + "inherited": true, + "codegen-properties": { + "skip-builder": true + } + }, + "-webkit-text-emphasis": { + "inherited": true, + "codegen-properties": { + "aliases": [ + "-epub-text-emphasis", + "text-emphasis" + ], + "longhands": [ + "-webkit-text-emphasis-style", + "-webkit-text-emphasis-color" + ] + } + }, + "-webkit-text-emphasis-color": { + "inherited": true, + "codegen-properties": { + "aliases": [ + "-epub-text-emphasis-color", + "text-emphasis-color" + ], + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "-webkit-text-emphasis-position": { + "inherited": true, + "codegen-properties": { + "aliases": [ + "text-emphasis-position" + ], + "converter": "TextEmphasisPosition" + } + }, + "-webkit-text-emphasis-style": { + "inherited": true, + "codegen-properties": { + "aliases": [ + "-epub-text-emphasis-style", + "text-emphasis-style" + ], + "custom": "All" + } + }, + "-webkit-text-fill-color": { + "inherited": true, + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "-webkit-text-security": { + "inherited": true, + "values": [ + "disc", + "circle", + "square", + "none" + ] + }, + "-webkit-text-stroke": { + "inherited": true, + "codegen-properties": { + "longhands": [ + "-webkit-text-stroke-width", + "-webkit-text-stroke-color" + ] + } + }, + "-webkit-text-stroke-color": { + "inherited": true, + "codegen-properties": { + "initial": "invalidColor", + "visited-link-color-support": true + } + }, + "-webkit-text-stroke-width": { + "inherited": true, + "codegen-properties": { + "converter": "TextStrokeWidth" + } + }, + "transform": { + "codegen-properties": { + "aliases": [ + "-webkit-transform" + ], + "converter": "Transform" + } + }, + "transform-origin": { + "codegen-properties": { + "aliases": [ + "-webkit-transform-origin" + ], + "longhands": [ + "transform-origin-x", + "transform-origin-y", + "transform-origin-z" + ] + } + }, + "transform-origin-x": { + "codegen-properties": { + "aliases": [ + "-webkit-transform-origin-x" + ], + "converter": "PositionComponentX" + } + }, + "transform-origin-y": { + "codegen-properties": { + "aliases": [ + "-webkit-transform-origin-y" + ], + "converter": "PositionComponentY" + } + }, + "transform-origin-z": { + "codegen-properties": { + "aliases": [ + "-webkit-transform-origin-z" + ], + "converter": "ComputedLength" + } + }, + "transform-style": { + "values": [ + "flat", + "preserve-3d" + ], + "codegen-properties": { + "name-for-methods": "TransformStyle3D" + } + }, + "-webkit-transform-style": { + "*": [ + "Keeping -webkit-transform-style around is how we'll detect legacy content. At that point", + "we'll have to add a custom builder and a new ETransformStyle3D type." + ], + "values": [ + "flat", + "preserve-3d" + ], + "codegen-properties": { + "name-for-methods": "TransformStyle3D" + } + }, + "-webkit-user-drag": { + "values": [ + "auto", + "none", + "element" + ] + }, + "-webkit-user-modify": { + "inherited": true, + "values": [] + }, + "-webkit-user-select": { + "inherited": true, + "values": [] + }, + "-webkit-flow-into": { + "codegen-properties": { + "name-for-methods": "FlowThread", + "converter": "StringOrNone", + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "-webkit-flow-from": { + "codegen-properties": { + "name-for-methods": "RegionThread", + "converter": "StringOrNone", + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "-webkit-region-fragment": { + "values": [ + "auto", + "break" + ], + "codegen-properties": { + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "-webkit-region-break-after": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakAfter", + "converter": "RegionBreakBetween", + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "-webkit-region-break-before": { + "values": [ + "auto", + "always", + "avoid", + "left", + "right" + ], + "codegen-properties": { + "initial": "initialBreakBetween", + "name-for-methods": "BreakBefore", + "converter": "RegionBreakBetween", + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "-webkit-region-break-inside": { + "values": [ + "auto", + "avoid" + ], + "codegen-properties": { + "initial": "initialBreakInside", + "name-for-methods": "BreakInside", + "converter": "RegionBreakInside", + "enable-if": "ENABLE_CSS_REGIONS" + } + }, + "scroll-padding": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "longhands": [ + "scroll-padding-top", + "scroll-padding-right", + "scroll-padding-bottom", + "scroll-padding-left" + ] + } + }, + "scroll-padding-bottom": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollPadding", + "converter": "Length" + } + }, + "scroll-padding-left": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollPadding", + "converter": "Length" + } + }, + "scroll-padding-right": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollPadding", + "converter": "Length" + } + }, + "scroll-padding-top": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollPadding", + "converter": "Length" + } + }, + "scroll-snap-align": { + "codegen-properties": { + "converter": "ScrollSnapAlign", + "enable-if": "ENABLE_CSS_SCROLL_SNAP" + } + }, + "scroll-snap-margin": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "longhands": [ + "scroll-snap-margin-top", + "scroll-snap-margin-right", + "scroll-snap-margin-bottom", + "scroll-snap-margin-left" + ] + } + }, + "scroll-snap-margin-bottom": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollSnapMargin", + "converter": "Length" + } + }, + "scroll-snap-margin-left": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollSnapMargin", + "converter": "Length" + } + }, + "scroll-snap-margin-right": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollSnapMargin", + "converter": "Length" + } + }, + "scroll-snap-margin-top": { + "codegen-properties": { + "enable-if": "ENABLE_CSS_SCROLL_SNAP", + "initial": "initialScrollSnapMargin", + "converter": "Length" + } + }, + "scroll-snap-type": { + "codegen-properties": { + "converter": "ScrollSnapType", + "enable-if": "ENABLE_CSS_SCROLL_SNAP" + } + }, + "shape-outside": { + "codegen-properties": { + "aliases": [ + "-webkit-shape-outside" + ], + "converter": "ShapeValue" + } + }, + "shape-margin": { + "codegen-properties": { + "aliases": [ + "-webkit-shape-margin" + ], + "converter": "Length" + } + }, + "shape-image-threshold": { + "codegen-properties": { + "aliases": [ + "-webkit-shape-image-threshold" + ], + "converter": "NumberOrAuto" + } + }, + "max-zoom": { + "codegen-properties": { + "skip-builder": true, + "enable-if": "ENABLE_CSS_DEVICE_ADAPTATION" + } + }, + "min-zoom": { + "codegen-properties": { + "skip-builder": true, + "enable-if": "ENABLE_CSS_DEVICE_ADAPTATION" + } + }, + "orientation": { + "codegen-properties": { + "skip-builder": true, + "enable-if": "ENABLE_CSS_DEVICE_ADAPTATION" + } + }, + "user-zoom": { + "codegen-properties": { + "skip-builder": true, + "enable-if": "ENABLE_CSS_DEVICE_ADAPTATION" + } + }, + "-webkit-tap-highlight-color": { + "inherited": true, + "codegen-properties": { + "converter": "TapHighlightColor", + "enable-if": "ENABLE_TOUCH_EVENTS" + } + }, + "-webkit-dashboard-region": { + "codegen-properties": { + "name-for-methods": "DashboardRegions", + "custom": "Value", + "enable-if": "ENABLE_DASHBOARD_SUPPORT" + } + }, + "-webkit-overflow-scrolling": { + "inherited": true, + "values": [ + "auto", + "touch" + ], + "codegen-properties": { + "name-for-methods": "UseTouchOverflowScrolling", + "converter": "OverflowScrolling", + "enable-if": "ENABLE_ACCELERATED_OVERFLOW_SCROLLING" + } + }, + "touch-action": { + "values": [ + "auto", + "manipulation" + ], + "codegen-properties": { + "enable-if": "ENABLE_TOUCH_EVENTS" + } + }, + "-webkit-touch-callout": { + "inherited": true, + "values": [ + "default", + "none" + ], + "codegen-properties": { + "name-for-methods": "TouchCalloutEnabled", + "converter": "TouchCallout", + "enable-if": "WTF_PLATFORM_IOS" + } + }, + "-apple-trailing-word": { + "inherited": true, + "values": [ + "auto", + "-webkit-partially-balanced" + ], + "codegen-properties": { + "name-for-methods": "TrailingWord", + "enable-if": "ENABLE_CSS_TRAILING_WORD" + } + }, + "-apple-pay-button-style": { + "codegen-properties": { + "enable-if": "ENABLE_APPLE_PAY" + } + }, + "-apple-pay-button-type": { + "codegen-properties": { + "enable-if": "ENABLE_APPLE_PAY" + } + }, + "fill-color" : { + "codegen-properties": { + "skip-codegen": true + } + }, + "fill-image" : { + "codegen-properties": { + "skip-codegen": true + } + }, + "fill-origin" : { + "codegen-properties": { + "skip-codegen": true + } + }, + "fill-position" : { + "codegen-properties": { + "skip-codegen": true + } + } + } +} diff --git a/Source/WebCore/css/CSSProperty.cpp b/Source/WebCore/css/CSSProperty.cpp index 0dd27c102..9d48b1d04 100644 --- a/Source/WebCore/css/CSSProperty.cpp +++ b/Source/WebCore/css/CSSProperty.cpp @@ -1,6 +1,6 @@ /** * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,8 +24,8 @@ #include "CSSValueList.h" #include "RenderStyleConstants.h" #include "StylePropertyShorthand.h" - -#include +#include "StylePropertyShorthandFunctions.h" +#include namespace WebCore { @@ -41,124 +41,21 @@ CSSPropertyID StylePropertyMetadata::shorthandID() const if (!m_isSetFromShorthand) return CSSPropertyInvalid; - Vector shorthands = matchingShorthandsForLonghand(static_cast(m_propertyID)); + auto shorthands = matchingShorthandsForLonghand(static_cast(m_propertyID)); ASSERT(shorthands.size() && m_indexInShorthandsVector >= 0 && m_indexInShorthandsVector < shorthands.size()); return shorthands[m_indexInShorthandsVector].id(); } void CSSProperty::wrapValueInCommaSeparatedList() { - RefPtr value = m_value.release(); - m_value = CSSValueList::createCommaSeparated(); - toCSSValueList(m_value.get())->append(value.release()); + auto list = CSSValueList::createCommaSeparated(); + list.get().append(m_value.releaseNonNull()); + m_value = WTFMove(list); } -enum LogicalBoxSide { BeforeSide, EndSide, AfterSide, StartSide }; -enum PhysicalBoxSide { TopSide, RightSide, BottomSide, LeftSide }; - static CSSPropertyID resolveToPhysicalProperty(TextDirection direction, WritingMode writingMode, LogicalBoxSide logicalSide, const StylePropertyShorthand& shorthand) { - if (direction == LTR) { - if (writingMode == TopToBottomWritingMode) { - // The common case. The logical and physical box sides match. - // Left = Start, Right = End, Before = Top, After = Bottom - return shorthand.properties()[logicalSide]; - } - - if (writingMode == BottomToTopWritingMode) { - // Start = Left, End = Right, Before = Bottom, After = Top. - switch (logicalSide) { - case StartSide: - return shorthand.properties()[LeftSide]; - case EndSide: - return shorthand.properties()[RightSide]; - case BeforeSide: - return shorthand.properties()[BottomSide]; - default: - return shorthand.properties()[TopSide]; - } - } - - if (writingMode == LeftToRightWritingMode) { - // Start = Top, End = Bottom, Before = Left, After = Right. - switch (logicalSide) { - case StartSide: - return shorthand.properties()[TopSide]; - case EndSide: - return shorthand.properties()[BottomSide]; - case BeforeSide: - return shorthand.properties()[LeftSide]; - default: - return shorthand.properties()[RightSide]; - } - } - - // Start = Top, End = Bottom, Before = Right, After = Left - switch (logicalSide) { - case StartSide: - return shorthand.properties()[TopSide]; - case EndSide: - return shorthand.properties()[BottomSide]; - case BeforeSide: - return shorthand.properties()[RightSide]; - default: - return shorthand.properties()[LeftSide]; - } - } - - if (writingMode == TopToBottomWritingMode) { - // Start = Right, End = Left, Before = Top, After = Bottom - switch (logicalSide) { - case StartSide: - return shorthand.properties()[RightSide]; - case EndSide: - return shorthand.properties()[LeftSide]; - case BeforeSide: - return shorthand.properties()[TopSide]; - default: - return shorthand.properties()[BottomSide]; - } - } - - if (writingMode == BottomToTopWritingMode) { - // Start = Right, End = Left, Before = Bottom, After = Top - switch (logicalSide) { - case StartSide: - return shorthand.properties()[RightSide]; - case EndSide: - return shorthand.properties()[LeftSide]; - case BeforeSide: - return shorthand.properties()[BottomSide]; - default: - return shorthand.properties()[TopSide]; - } - } - - if (writingMode == LeftToRightWritingMode) { - // Start = Bottom, End = Top, Before = Left, After = Right - switch (logicalSide) { - case StartSide: - return shorthand.properties()[BottomSide]; - case EndSide: - return shorthand.properties()[TopSide]; - case BeforeSide: - return shorthand.properties()[LeftSide]; - default: - return shorthand.properties()[RightSide]; - } - } - - // Start = Bottom, End = Top, Before = Right, After = Left - switch (logicalSide) { - case StartSide: - return shorthand.properties()[BottomSide]; - case EndSide: - return shorthand.properties()[TopSide]; - case BeforeSide: - return shorthand.properties()[RightSide]; - default: - return shorthand.properties()[LeftSide]; - } + return shorthand.properties()[mapLogicalSideToPhysicalSide(makeTextFlow(writingMode, direction), logicalSide)]; } enum LogicalExtent { LogicalWidth, LogicalHeight }; @@ -173,7 +70,7 @@ static CSSPropertyID resolveToPhysicalProperty(WritingMode writingMode, LogicalE static const StylePropertyShorthand& borderDirections() { static const CSSPropertyID properties[4] = { CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft }; - DEFINE_STATIC_LOCAL(StylePropertyShorthand, borderDirections, (CSSPropertyBorder, properties, WTF_ARRAY_LENGTH(properties))); + static NeverDestroyed borderDirections(CSSPropertyBorder, properties); return borderDirections; } @@ -257,6 +154,23 @@ CSSPropertyID CSSProperty::resolveDirectionAwareProperty(CSSPropertyID propertyI } } +bool CSSProperty::isDescriptorOnly(CSSPropertyID propertyID) +{ + switch (propertyID) { +#if ENABLE(CSS_DEVICE_ADAPTATION) + case CSSPropertyMinZoom: + case CSSPropertyMaxZoom: + case CSSPropertyOrientation: + case CSSPropertyUserZoom: +#endif + case CSSPropertySrc: + case CSSPropertyUnicodeRange: + return true; + default: + return false; + } +} + bool CSSProperty::isDirectionAwareProperty(CSSPropertyID propertyID) { switch (propertyID) { diff --git a/Source/WebCore/css/CSSProperty.h b/Source/WebCore/css/CSSProperty.h index f5f1a6a05..debf1951f 100644 --- a/Source/WebCore/css/CSSProperty.h +++ b/Source/WebCore/css/CSSProperty.h @@ -1,6 +1,6 @@ /* * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006 Apple Inc. * Copyright (C) 2013 Intel Corporation. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -19,15 +19,11 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSProperty_h -#define CSSProperty_h +#pragma once #include "CSSPropertyNames.h" #include "CSSValue.h" -#include "RenderStyleConstants.h" -#include "TextDirection.h" #include "WritingMode.h" -#include #include namespace WebCore { @@ -44,6 +40,16 @@ struct StylePropertyMetadata { } CSSPropertyID shorthandID() const; + + bool operator==(const StylePropertyMetadata& other) const + { + return m_propertyID == other.m_propertyID + && m_isSetFromShorthand == other.m_isSetFromShorthand + && m_indexInShorthandsVector == other.m_indexInShorthandsVector + && m_important == other.m_important + && m_implicit == other.m_implicit + && m_inherited == other.m_inherited; + } uint16_t m_propertyID : 10; uint16_t m_isSetFromShorthand : 1; @@ -55,16 +61,9 @@ struct StylePropertyMetadata { class CSSProperty { public: - CSSProperty(CSSPropertyID propertyID, PassRefPtr value, bool important = false, bool isSetFromShorthand = false, int indexInShorthandsVector = 0, bool implicit = false) + CSSProperty(CSSPropertyID propertyID, RefPtr&& value, bool important = false, bool isSetFromShorthand = false, int indexInShorthandsVector = 0, bool implicit = false) : m_metadata(propertyID, isSetFromShorthand, indexInShorthandsVector, important, implicit, isInheritedProperty(propertyID)) - , m_value(value) - { - } - - // FIXME: Remove this. - CSSProperty(StylePropertyMetadata metadata, CSSValue* value) - : m_metadata(metadata) - , m_value(value) + , m_value(WTFMove(value)) { } @@ -80,55 +79,30 @@ public: static CSSPropertyID resolveDirectionAwareProperty(CSSPropertyID, TextDirection, WritingMode); static bool isInheritedProperty(CSSPropertyID); static bool isDirectionAwareProperty(CSSPropertyID); + static bool isDescriptorOnly(CSSPropertyID); const StylePropertyMetadata& metadata() const { return m_metadata; } + bool operator==(const CSSProperty& other) const + { + if (!(m_metadata == other.m_metadata)) + return false; + + if (!m_value && !other.m_value) + return true; + + if (!m_value || !other.m_value) + return false; + + return m_value->equals(*other.m_value); + } + private: StylePropertyMetadata m_metadata; RefPtr m_value; }; -inline CSSPropertyID prefixingVariantForPropertyId(CSSPropertyID propId) -{ - CSSPropertyID propertyId = CSSPropertyInvalid; - switch (propId) { - case CSSPropertyTransitionDelay: - propertyId = CSSPropertyWebkitTransitionDelay; - break; - case CSSPropertyTransitionDuration: - propertyId = CSSPropertyWebkitTransitionDuration; - break; - case CSSPropertyTransitionProperty: - propertyId = CSSPropertyWebkitTransitionProperty; - break; - case CSSPropertyTransitionTimingFunction: - propertyId = CSSPropertyWebkitTransitionTimingFunction; - break; - case CSSPropertyTransition: - propertyId = CSSPropertyWebkitTransition; - break; - case CSSPropertyWebkitTransitionDelay: - propertyId = CSSPropertyTransitionDelay; - break; - case CSSPropertyWebkitTransitionDuration: - propertyId = CSSPropertyTransitionDuration; - break; - case CSSPropertyWebkitTransitionProperty: - propertyId = CSSPropertyTransitionProperty; - break; - case CSSPropertyWebkitTransitionTimingFunction: - propertyId = CSSPropertyTransitionTimingFunction; - break; - case CSSPropertyWebkitTransition: - propertyId = CSSPropertyTransition; - break; - default: - propertyId = propId; - break; - } - ASSERT(propertyId != CSSPropertyInvalid); - return propertyId; -} +typedef Vector ParsedPropertyVector; } // namespace WebCore @@ -138,5 +112,3 @@ template <> struct VectorTraits : VectorTraitsBase #include #include @@ -52,7 +52,7 @@ struct SourceRange { }; struct CSSPropertySourceData { - CSSPropertySourceData(const String& name, const String& value, bool important, bool parsedOk, const SourceRange& range); + CSSPropertySourceData(const String& name, const String& value, bool important, bool disabled, bool parsedOk, const SourceRange&); CSSPropertySourceData(const CSSPropertySourceData& other); CSSPropertySourceData(); @@ -62,57 +62,43 @@ struct CSSPropertySourceData { String name; String value; bool important; + bool disabled; bool parsedOk; SourceRange range; }; struct CSSStyleSourceData : public RefCounted { - static PassRefPtr create() + static Ref create() { - return adoptRef(new CSSStyleSourceData()); + return adoptRef(*new CSSStyleSourceData); } Vector propertyData; }; struct CSSRuleSourceData; -typedef Vector> RuleSourceDataList; +typedef Vector> RuleSourceDataList; typedef Vector SelectorRangeList; struct CSSRuleSourceData : public RefCounted { - enum Type { - UNKNOWN_RULE, - STYLE_RULE, - CHARSET_RULE, - IMPORT_RULE, - MEDIA_RULE, - FONT_FACE_RULE, - PAGE_RULE, - KEYFRAMES_RULE, - REGION_RULE, - HOST_RULE, - VIEWPORT_RULE, - SUPPORTS_RULE, - }; - - static PassRefPtr create(Type type) + static Ref create(StyleRule::Type type) { - return adoptRef(new CSSRuleSourceData(type)); + return adoptRef(*new CSSRuleSourceData(type)); } - static PassRefPtr createUnknown() + static Ref createUnknown() { - return adoptRef(new CSSRuleSourceData(UNKNOWN_RULE)); + return adoptRef(*new CSSRuleSourceData(StyleRule::Unknown)); } - CSSRuleSourceData(Type type) + CSSRuleSourceData(StyleRule::Type type) : type(type) { - if (type == STYLE_RULE || type == FONT_FACE_RULE || type == PAGE_RULE) + if (type == StyleRule::Style || type == StyleRule::FontFace || type == StyleRule::Page) styleSourceData = CSSStyleSourceData::create(); } - Type type; + StyleRule::Type type; // Range of the selector list in the enclosing source. SourceRange ruleHeaderRange; @@ -131,5 +117,3 @@ struct CSSRuleSourceData : public RefCounted { }; } // namespace WebCore - -#endif // CSSPropertySourceData_h diff --git a/Source/WebCore/css/CSSReflectValue.cpp b/Source/WebCore/css/CSSReflectValue.cpp index b497af01c..8a7905ce9 100644 --- a/Source/WebCore/css/CSSReflectValue.cpp +++ b/Source/WebCore/css/CSSReflectValue.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -38,16 +38,10 @@ String CSSReflectValue::customCSSText() const return m_direction->cssText() + ' ' + m_offset->cssText(); } -void CSSReflectValue::addSubresourceStyleURLs(ListHashSet& urls, const StyleSheetContents* styleSheet) const -{ - if (m_mask) - m_mask->addSubresourceStyleURLs(urls, styleSheet); -} - bool CSSReflectValue::equals(const CSSReflectValue& other) const { - return m_direction == other.m_direction - && compareCSSValuePtr(m_offset, other.m_offset) + return m_direction.ptr() == other.m_direction.ptr() + && compareCSSValue(m_offset, other.m_offset) && compareCSSValuePtr(m_mask, other.m_mask); } diff --git a/Source/WebCore/css/CSSReflectValue.h b/Source/WebCore/css/CSSReflectValue.h index 544c2341c..678bcdd4d 100644 --- a/Source/WebCore/css/CSSReflectValue.h +++ b/Source/WebCore/css/CSSReflectValue.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,52 +23,47 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSReflectValue_h -#define CSSReflectValue_h +#pragma once #include "CSSReflectionDirection.h" #include "CSSValue.h" -#include #include namespace WebCore { class CSSPrimitiveValue; -class CSSReflectValue : public CSSValue { +class CSSReflectValue final : public CSSValue { public: - static PassRef create(PassRefPtr direction, - PassRefPtr offset, PassRefPtr mask) + static Ref create(Ref&& direction, Ref&& offset, RefPtr&& mask) { - return adoptRef(*new CSSReflectValue(direction, offset, mask)); + return adoptRef(*new CSSReflectValue(WTFMove(direction), WTFMove(offset), WTFMove(mask))); } - CSSPrimitiveValue* direction() const { return m_direction.get(); } - CSSPrimitiveValue* offset() const { return m_offset.get(); } + CSSPrimitiveValue& direction() { return m_direction.get(); } + CSSPrimitiveValue& offset() { return m_offset.get(); } + const CSSPrimitiveValue& direction() const { return m_direction.get(); } + const CSSPrimitiveValue& offset() const { return m_offset.get(); } CSSValue* mask() const { return m_mask.get(); } String customCSSText() const; - void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; - bool equals(const CSSReflectValue&) const; private: - CSSReflectValue(PassRefPtr direction, PassRefPtr offset, PassRefPtr mask) + CSSReflectValue(Ref&& direction, Ref&& offset, RefPtr&& mask) : CSSValue(ReflectClass) - , m_direction(direction) - , m_offset(offset) - , m_mask(mask) + , m_direction(WTFMove(direction)) + , m_offset(WTFMove(offset)) + , m_mask(WTFMove(mask)) { } - RefPtr m_direction; - RefPtr m_offset; + Ref m_direction; + Ref m_offset; RefPtr m_mask; }; -CSS_VALUE_TYPE_CASTS(CSSReflectValue, isReflectValue()) - } // namespace WebCore -#endif // CSSReflectValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSReflectValue, isReflectValue()) diff --git a/Source/WebCore/css/CSSReflectionDirection.h b/Source/WebCore/css/CSSReflectionDirection.h index e30bc1c13..17c1245c8 100644 --- a/Source/WebCore/css/CSSReflectionDirection.h +++ b/Source/WebCore/css/CSSReflectionDirection.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,13 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSReflectionDirection_h -#define CSSReflectionDirection_h +#pragma once namespace WebCore { enum CSSReflectionDirection { ReflectionBelow, ReflectionAbove, ReflectionLeft, ReflectionRight }; } // namespace WebCore - -#endif // CSSReflectionDirection_h diff --git a/Source/WebCore/css/CSSRevertValue.cpp b/Source/WebCore/css/CSSRevertValue.cpp new file mode 100644 index 000000000..9a63ef9ef --- /dev/null +++ b/Source/WebCore/css/CSSRevertValue.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSRevertValue.h" + +#include + +namespace WebCore { + +String CSSRevertValue::customCSSText() const +{ + return ASCIILiteral("Revert"); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSRevertValue.h b/Source/WebCore/css/CSSRevertValue.h new file mode 100644 index 000000000..a73d6d00d --- /dev/null +++ b/Source/WebCore/css/CSSRevertValue.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include + +namespace WebCore { + +class CSSRevertValue final : public CSSValue { +public: + String customCSSText() const; + + bool equals(const CSSRevertValue&) const { return true; } + +#if COMPILER(MSVC) + // FIXME: This should be private, but for some reason MSVC then fails to invoke it from LazyNeverDestroyed::construct. +public: +#else +private: + friend class LazyNeverDestroyed; +#endif + CSSRevertValue() + : CSSValue(RevertClass) + { + } +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSRevertValue, isRevertValue()) diff --git a/Source/WebCore/css/CSSRule.cpp b/Source/WebCore/css/CSSRule.cpp index f01cffafd..411762e81 100644 --- a/Source/WebCore/css/CSSRule.cpp +++ b/Source/WebCore/css/CSSRule.cpp @@ -23,7 +23,6 @@ #include "CSSRule.h" #include "CSSStyleSheet.h" -#include "NotImplemented.h" #include "StyleRule.h" #include "StyleSheetContents.h" @@ -45,9 +44,9 @@ COMPILE_ASSERT(StyleRuleBase::Region == static_cast(CSSRule COMPILE_ASSERT(StyleRuleBase::Viewport == static_cast(CSSRule::WEBKIT_VIEWPORT_RULE), enums_should_match); #endif -void CSSRule::setCssText(const String& /*cssText*/, ExceptionCode& /*ec*/) +ExceptionOr CSSRule::setCssText(const String&) { - notImplemented(); + return { }; } const CSSParserContext& CSSRule::parserContext() const diff --git a/Source/WebCore/css/CSSRule.h b/Source/WebCore/css/CSSRule.h index a80399d16..e52c56319 100644 --- a/Source/WebCore/css/CSSRule.h +++ b/Source/WebCore/css/CSSRule.h @@ -20,18 +20,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSRule_h -#define CSSRule_h +#pragma once -#include -#include +#include "ExceptionOr.h" +#include namespace WebCore { class CSSStyleSheet; class StyleRuleBase; + struct CSSParserContext; -typedef int ExceptionCode; class CSSRule : public RefCounted { public: @@ -48,25 +47,26 @@ public: // 7 was VARIABLES_RULE; we now match other browsers with 7 as // KEYFRAMES_RULE: // . - WEBKIT_KEYFRAMES_RULE, - WEBKIT_KEYFRAME_RULE, -#if ENABLE(CSS3_CONDITIONAL_RULES) + KEYFRAMES_RULE, + KEYFRAME_RULE, + NAMESPACE_RULE = 10, // Matches other browsers. SUPPORTS_RULE = 12, -#endif #if ENABLE(CSS_DEVICE_ADAPTATION) WEBKIT_VIEWPORT_RULE = 15, #endif #if ENABLE(CSS_REGIONS) WEBKIT_REGION_RULE = 16, #endif -#if ENABLE(SHADOW_DOM) - HOST_RULE = 1001, -#endif + }; + + enum DeprecatedType { + WEBKIT_KEYFRAMES_RULE = 7, + WEBKIT_KEYFRAME_RULE = 8 }; virtual Type type() const = 0; virtual String cssText() const = 0; - virtual void reattach(StyleRuleBase*) = 0; + virtual void reattach(StyleRuleBase&) = 0; void setParentStyleSheet(CSSStyleSheet* styleSheet) { @@ -89,8 +89,7 @@ public: CSSRule* parentRule() const { return m_parentIsRule ? m_parentRule : 0; } - // NOTE: Just calls notImplemented(). - void setCssText(const String&, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr setCssText(const String&); protected: CSSRule(CSSStyleSheet* parent) @@ -117,4 +116,7 @@ private: } // namespace WebCore -#endif // CSSRule_h +#define SPECIALIZE_TYPE_TRAITS_CSS_RULE(ToValueTypeName, predicate) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ + static bool isType(const WebCore::CSSRule& rule) { return rule.type() == WebCore::predicate; } \ +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/css/CSSRule.idl b/Source/WebCore/css/CSSRule.idl index 589f897ca..3069b018b 100644 --- a/Source/WebCore/css/CSSRule.idl +++ b/Source/WebCore/css/CSSRule.idl @@ -18,15 +18,13 @@ * Boston, MA 02110-1301, USA. */ -// Introduced in DOM Level 2: [ + CustomToJSObject, + ExportToWrappedFunction, + GenerateIsReachable, JSCustomHeader, JSCustomMarkFunction, - GenerateIsReachable, - CustomToJSObject, - ObjCPolymorphic, ] interface CSSRule { - // RuleType const unsigned short UNKNOWN_RULE = 0; const unsigned short STYLE_RULE = 1; @@ -35,27 +33,21 @@ const unsigned short MEDIA_RULE = 4; const unsigned short FONT_FACE_RULE = 5; const unsigned short PAGE_RULE = 6; - const unsigned short WEBKIT_KEYFRAMES_RULE = 7; - const unsigned short WEBKIT_KEYFRAME_RULE = 8; -#if defined(ENABLE_CSS3_CONDITIONAL_RULES) && ENABLE_CSS3_CONDITIONAL_RULES + const unsigned short KEYFRAMES_RULE = 7; + const unsigned short KEYFRAME_RULE = 8; + const unsigned short NAMESPACE_RULE = 10; const unsigned short SUPPORTS_RULE = 12; -#endif -#if defined(ENABLE_CSS_DEVICE_ADAPTATION) && ENABLE_CSS_DEVICE_ADAPTATION - const unsigned short WEBKIT_VIEWPORT_RULE = 15; -#endif -#if defined(ENABLE_CSS_REGIONS) && ENABLE_CSS_REGIONS - const unsigned short WEBKIT_REGION_RULE = 16; -#endif -#if defined(ENABLE_SHADOW_DOM) && ENABLE_SHADOW_DOM - const unsigned short HOST_RULE = 1001; -#endif + [Conditional=CSS_DEVICE_ADAPTATION] const unsigned short WEBKIT_VIEWPORT_RULE = 15; + [Conditional=CSS_REGIONS] const unsigned short WEBKIT_REGION_RULE = 16; - readonly attribute unsigned short type; + // Legacy synonyms for the above, kept to avoid breaking existing content. + const unsigned short WEBKIT_KEYFRAMES_RULE = 7; + const unsigned short WEBKIT_KEYFRAME_RULE = 8; - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString cssText; + readonly attribute unsigned short type; - readonly attribute CSSStyleSheet parentStyleSheet; - readonly attribute CSSRule parentRule; + [SetterMayThrowException] attribute DOMString? cssText; + readonly attribute CSSStyleSheet? parentStyleSheet; + readonly attribute CSSRule? parentRule; }; - diff --git a/Source/WebCore/css/CSSRuleList.cpp b/Source/WebCore/css/CSSRuleList.cpp index a158d6f2e..8dab3a2d7 100644 --- a/Source/WebCore/css/CSSRuleList.cpp +++ b/Source/WebCore/css/CSSRuleList.cpp @@ -1,7 +1,7 @@ /** * (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2005, 2006, 2012 Apple Computer, Inc. + * Copyright (C) 2002, 2005, 2006, 2012 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/Source/WebCore/css/CSSRuleList.h b/Source/WebCore/css/CSSRuleList.h index 4da15b488..35a0925fe 100644 --- a/Source/WebCore/css/CSSRuleList.h +++ b/Source/WebCore/css/CSSRuleList.h @@ -1,7 +1,7 @@ /* * (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 2002-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2006, 2012 Apple Computer, Inc. + * Copyright (C) 2002, 2006, 2012 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,14 +19,10 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSRuleList_h -#define CSSRuleList_h +#pragma once -#include -#include #include #include -#include namespace WebCore { @@ -50,23 +46,23 @@ protected: CSSRuleList(); }; -class StaticCSSRuleList : public CSSRuleList { +class StaticCSSRuleList final : public CSSRuleList { public: - static PassRefPtr create() { return adoptRef(new StaticCSSRuleList()); } + static Ref create() { return adoptRef(*new StaticCSSRuleList); } - virtual void ref() { ++m_refCount; } - virtual void deref(); + void ref() final { ++m_refCount; } + void deref() final; Vector>& rules() { return m_rules; } - virtual CSSStyleSheet* styleSheet() const { return 0; } + CSSStyleSheet* styleSheet() const final { return nullptr; } private: StaticCSSRuleList(); ~StaticCSSRuleList(); - virtual unsigned length() const { return m_rules.size(); } - virtual CSSRule* item(unsigned index) const { return index < m_rules.size() ? m_rules[index].get() : 0; } + unsigned length() const final { return m_rules.size(); } + CSSRule* item(unsigned index) const final { return index < m_rules.size() ? m_rules[index].get() : nullptr; } Vector> m_rules; unsigned m_refCount; @@ -74,21 +70,22 @@ private: // The rule owns the live list. template -class LiveCSSRuleList : public CSSRuleList { +class LiveCSSRuleList final : public CSSRuleList { public: - LiveCSSRuleList(Rule* rule) : m_rule(rule) { } + LiveCSSRuleList(Rule& rule) + : m_rule(rule) + { + } - virtual void ref() { m_rule->ref(); } - virtual void deref() { m_rule->deref(); } + void ref() final { m_rule.ref(); } + void deref() final { m_rule.deref(); } private: - virtual unsigned length() const { return m_rule->length(); } - virtual CSSRule* item(unsigned index) const { return m_rule->item(index); } - virtual CSSStyleSheet* styleSheet() const { return m_rule->parentStyleSheet(); } + unsigned length() const final { return m_rule.length(); } + CSSRule* item(unsigned index) const final { return m_rule.item(index); } + CSSStyleSheet* styleSheet() const final { return m_rule.parentStyleSheet(); } - Rule* m_rule; + Rule& m_rule; }; } // namespace WebCore - -#endif // CSSRuleList_h diff --git a/Source/WebCore/css/CSSRuleList.idl b/Source/WebCore/css/CSSRuleList.idl index 5b9ca91a4..4fcc488ed 100644 --- a/Source/WebCore/css/CSSRuleList.idl +++ b/Source/WebCore/css/CSSRuleList.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,12 +23,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Introduced in DOM Level 2: [ CustomIsReachable, + ExportToWrappedFunction, SkipVTableValidation, ] interface CSSRuleList { - readonly attribute unsigned long length; - getter CSSRule item([Default=Undefined] optional unsigned long index); + readonly attribute unsigned long length; + getter CSSRule item(unsigned long index); }; - diff --git a/Source/WebCore/css/CSSSegmentedFontFace.cpp b/Source/WebCore/css/CSSSegmentedFontFace.cpp index f32832cc5..621344163 100644 --- a/Source/WebCore/css/CSSSegmentedFontFace.cpp +++ b/Source/WebCore/css/CSSSegmentedFontFace.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,159 +30,107 @@ #include "CSSFontFaceSource.h" #include "CSSFontSelector.h" #include "Document.h" +#include "Font.h" +#include "FontCache.h" #include "FontDescription.h" #include "RuntimeEnabledFeatures.h" -#include "SegmentedFontData.h" -#include "SimpleFontData.h" namespace WebCore { -CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector) - : m_fontSelector(fontSelector) +CSSSegmentedFontFace::CSSSegmentedFontFace() { } CSSSegmentedFontFace::~CSSSegmentedFontFace() { - pruneTable(); - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) - m_fontFaces[i]->removedFromSegmentedFontFace(this); + for (auto& face : m_fontFaces) + face->removeClient(*this); } -void CSSSegmentedFontFace::pruneTable() +void CSSSegmentedFontFace::appendFontFace(Ref&& fontFace) { - // Make sure the glyph page tree prunes out all uses of this custom font. - if (m_fontDataTable.isEmpty()) - return; - - m_fontDataTable.clear(); + m_cache.clear(); + fontFace->addClient(*this); + m_fontFaces.append(WTFMove(fontFace)); } -bool CSSSegmentedFontFace::isValid() const +void CSSSegmentedFontFace::fontLoaded(CSSFontFace&) { - // Valid if at least one font face is valid. - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->isValid()) - return true; - } - return false; + m_cache.clear(); } -void CSSSegmentedFontFace::fontLoaded(CSSFontFace*) -{ - pruneTable(); - -#if ENABLE(FONT_LOAD_EVENTS) - if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && !isLoading()) { - Vector> callbacks; - m_callbacks.swap(callbacks); - for (size_t index = 0; index < callbacks.size(); ++index) { - if (checkFont()) - callbacks[index]->notifyLoaded(); - else - callbacks[index]->notifyError(); - } +class CSSFontAccessor final : public FontAccessor { +public: + static Ref create(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) + { + return adoptRef(*new CSSFontAccessor(fontFace, fontDescription, syntheticBold, syntheticItalic)); } -#endif -} -void CSSSegmentedFontFace::appendFontFace(PassRefPtr fontFace) -{ - pruneTable(); - fontFace->addedToSegmentedFontFace(this); - m_fontFaces.append(fontFace); -} - -static void appendFontDataWithInvalidUnicodeRangeIfLoading(SegmentedFontData* newFontData, PassRefPtr prpFaceFontData, const Vector& ranges) -{ - RefPtr faceFontData = prpFaceFontData; - if (faceFontData->isLoading()) { - newFontData->appendRange(FontDataRange(0, 0, faceFontData)); - return; + const Font* font() const final + { + if (!m_result) + m_result = m_fontFace->font(m_fontDescription, m_syntheticBold, m_syntheticItalic); + return m_result.value().get(); } - unsigned numRanges = ranges.size(); - if (!numRanges) { - newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData)); - return; +private: + CSSFontAccessor(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) + : m_fontFace(fontFace) + , m_fontDescription(fontDescription) + , m_syntheticBold(syntheticBold) + , m_syntheticItalic(syntheticItalic) + { } - for (unsigned j = 0; j < numRanges; ++j) - newFontData->appendRange(FontDataRange(ranges[j].from(), ranges[j].to(), faceFontData)); -} - -PassRefPtr CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription) -{ - if (!isValid()) - return 0; - - FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); - unsigned hashKey = ((fontDescription.computedPixelSize() + 1) << (FontTraitsMaskWidth + FontWidthVariantWidth + 1)) - | ((fontDescription.orientation() == Vertical ? 1 : 0) << (FontTraitsMaskWidth + FontWidthVariantWidth)) - | fontDescription.widthVariant() << FontTraitsMaskWidth - | desiredTraitsMask; - - RefPtr& fontData = m_fontDataTable.add(hashKey, nullptr).iterator->value; - if (fontData && fontData->numRanges()) - return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. - - if (!fontData) - fontData = SegmentedFontData::create(); - - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (!m_fontFaces[i]->isValid()) - continue; - FontTraitsMask traitsMask = m_fontFaces[i]->traitsMask(); - bool syntheticBold = !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); - bool syntheticItalic = !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); - if (RefPtr faceFontData = m_fontFaces[i]->getFontData(fontDescription, syntheticBold, syntheticItalic)) { - ASSERT(!faceFontData->isSegmented()); - appendFontDataWithInvalidUnicodeRangeIfLoading(fontData.get(), faceFontData.release(), m_fontFaces[i]->ranges()); - } + bool isLoading() const final + { + return m_result && m_result.value() && m_result.value()->isLoading(); } - if (fontData->numRanges()) - return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. - return 0; -} + mutable std::optional> m_result; // Caches nullptr too + mutable Ref m_fontFace; + FontDescription m_fontDescription; + bool m_syntheticBold; + bool m_syntheticItalic; +}; -#if ENABLE(FONT_LOAD_EVENTS) -bool CSSSegmentedFontFace::isLoading() const +static void appendFont(FontRanges& ranges, Ref&& fontAccessor, const Vector& unicodeRanges) { - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->loadState() == CSSFontFace::Loading) - return true; + if (unicodeRanges.isEmpty()) { + ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(fontAccessor) }); + return; } - return false; -} -bool CSSSegmentedFontFace::checkFont() const -{ - unsigned size = m_fontFaces.size(); - for (unsigned i = 0; i < size; i++) { - if (m_fontFaces[i]->loadState() != CSSFontFace::Loaded) - return false; - } - return true; + for (auto& range : unicodeRanges) + ranges.appendRange({ range.from, range.to, fontAccessor.copyRef() }); } -void CSSSegmentedFontFace::loadFont(const FontDescription& fontDescription, PassRefPtr callback) +FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription) { - getFontData(fontDescription); // Kick off the load. - - if (callback) { - if (isLoading()) - m_callbacks.append(callback); - else if (checkFont()) - callback->notifyLoaded(); - else - callback->notifyError(); + FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); + + auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges()); + auto& result = addResult.iterator->value; + + if (addResult.isNewEntry) { + for (auto& face : m_fontFaces) { + if (face->allSourcesFailed()) + continue; + + FontTraitsMask traitsMask = face->traitsMask(); + bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); + bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); + + // This doesn't trigger an unnecessary download because every element styled with this family will need font metrics in order to run layout. + // Metrics used for layout come from FontRanges::fontForFirstRange(), which assumes that the first font is non-null. + // We're kicking off this necessary first download now. + auto fontAccessor = CSSFontAccessor::create(face, fontDescription, syntheticBold, syntheticItalic); + if (result.isNull() && !fontAccessor->font()) + continue; + appendFont(result, WTFMove(fontAccessor), face->ranges()); + } } + return result; } -#endif } diff --git a/Source/WebCore/css/CSSSegmentedFontFace.h b/Source/WebCore/css/CSSSegmentedFontFace.h index fb2b4a730..f66e73393 100644 --- a/Source/WebCore/css/CSSSegmentedFontFace.h +++ b/Source/WebCore/css/CSSSegmentedFontFace.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,65 +23,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSSegmentedFontFace_h -#define CSSSegmentedFontFace_h +#pragma once +#include "CSSFontFace.h" +#include "FontCache.h" #include -#include #include #include -#include namespace WebCore { -class CSSFontFace; class CSSFontSelector; -class FontData; class FontDescription; -class SegmentedFontData; +class FontRanges; -class CSSSegmentedFontFace : public RefCounted { +class CSSSegmentedFontFace final : public RefCounted, public CSSFontFace::Client { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr create(CSSFontSelector* selector) { return adoptRef(new CSSSegmentedFontFace(selector)); } + static Ref create() + { + return adoptRef(*new CSSSegmentedFontFace()); + } ~CSSSegmentedFontFace(); - CSSFontSelector* fontSelector() const { return m_fontSelector; } + void appendFontFace(Ref&&); - void fontLoaded(CSSFontFace*); + FontRanges fontRanges(const FontDescription&); - void appendFontFace(PassRefPtr); + Vector, 1>& constituentFaces() { return m_fontFaces; } - PassRefPtr getFontData(const FontDescription&); - -#if ENABLE(FONT_LOAD_EVENTS) - class LoadFontCallback : public RefCounted { - public: - virtual ~LoadFontCallback() { } - virtual void notifyLoaded() = 0; - virtual void notifyError() = 0; - }; - - bool checkFont() const; - void loadFont(const FontDescription&, PassRefPtr loadCallback); -#endif + // CSSFontFace::Client needs to be able to be held in a RefPtr. + void ref() final { RefCounted::ref(); } + void deref() final { RefCounted::deref(); } private: - CSSSegmentedFontFace(CSSFontSelector*); + CSSSegmentedFontFace(); + void fontLoaded(CSSFontFace&) final; - void pruneTable(); - bool isValid() const; -#if ENABLE(FONT_LOAD_EVENTS) - bool isLoading() const; -#endif - - CSSFontSelector* m_fontSelector; - HashMap> m_fontDataTable; - Vector, 1> m_fontFaces; -#if ENABLE(FONT_LOAD_EVENTS) - Vector> m_callbacks; -#endif + HashMap> m_cache; + Vector, 1> m_fontFaces; }; } // namespace WebCore - -#endif // CSSSegmentedFontFace_h diff --git a/Source/WebCore/css/CSSSelector.cpp b/Source/WebCore/css/CSSSelector.cpp index 3e645ca16..2388a79a3 100644 --- a/Source/WebCore/css/CSSSelector.cpp +++ b/Source/WebCore/css/CSSSelector.cpp @@ -3,7 +3,7 @@ * 1999 Waldo Bastian (bastian@kde.org) * 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch) * 2001-2003 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2002, 2006, 2007, 2008, 2009, 2010, 2013, 2014 Apple Inc. All rights reserved. * Copyright (C) 2008 David Smith (catfish.man@gmail.com) * Copyright (C) 2010 Google Inc. All rights reserved. * @@ -26,12 +26,12 @@ #include "config.h" #include "CSSSelector.h" -#include "CSSOMUtils.h" +#include "CSSMarkup.h" #include "CSSSelectorList.h" #include "HTMLNames.h" +#include "SelectorPseudoTypeMap.h" #include #include -#include #include #include #include @@ -41,99 +41,223 @@ namespace WebCore { using namespace HTMLNames; +struct SameSizeAsCSSSelector { + unsigned flags; + void* unionPointer; +}; + +static_assert(CSSSelector::RelationType::Subselector == 0, "Subselector must be 0 for consumeCombinator."); +static_assert(sizeof(CSSSelector) == sizeof(SameSizeAsCSSSelector), "CSSSelector should remain small."); + +CSSSelector::CSSSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule) + : m_relation(DescendantSpace) + , m_match(Tag) + , m_pseudoType(0) + , m_parsedNth(false) + , m_isLastInSelectorList(false) + , m_isLastInTagHistory(true) + , m_hasRareData(false) + , m_hasNameWithCase(false) + , m_isForPage(false) + , m_tagIsForNamespaceRule(tagIsForNamespaceRule) + , m_caseInsensitiveAttributeValueMatching(false) +#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + , m_destructorHasBeenCalled(false) +#endif +{ + const AtomicString& tagLocalName = tagQName.localName(); + const AtomicString tagLocalNameASCIILowercase = tagLocalName.convertToASCIILowercase(); + + if (tagLocalName == tagLocalNameASCIILowercase) { + m_data.m_tagQName = tagQName.impl(); + m_data.m_tagQName->ref(); + } else { + m_data.m_nameWithCase = adoptRef(new NameWithCase(tagQName, tagLocalNameASCIILowercase)).leakRef(); + m_hasNameWithCase = true; + } +} + void CSSSelector::createRareData() { - ASSERT(m_match != Tag); + ASSERT(match() != Tag); + ASSERT(!m_hasNameWithCase); if (m_hasRareData) return; // Move the value to the rare data stucture. - m_data.m_rareData = RareData::create(adoptRef(m_data.m_value)).leakRef(); + AtomicString value { adoptRef(m_data.m_value) }; + m_data.m_rareData = &RareData::create(WTFMove(value)).leakRef(); m_hasRareData = true; } -unsigned CSSSelector::specificity() const -{ - // make sure the result doesn't overflow - static const unsigned maxValueMask = 0xffffff; - static const unsigned idMask = 0xff0000; - static const unsigned classMask = 0xff00; - static const unsigned elementMask = 0xff; +static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity); - if (isForPage()) - return specificityForPage() & maxValueMask; +static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector, bool isComputingMaximumSpecificity) +{ + unsigned total = simpleSelectorSpecificityInternal(firstSimpleSelector, isComputingMaximumSpecificity); - unsigned total = 0; - unsigned temp = 0; - - for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) { - temp = total + selector->specificityForOneSelector(); - // Clamp each component to its max in the case of overflow. - if ((temp & idMask) < (total & idMask)) - total |= idMask; - else if ((temp & classMask) < (total & classMask)) - total |= classMask; - else if ((temp & elementMask) < (total & elementMask)) - total |= elementMask; - else - total = temp; - } + for (const CSSSelector* selector = firstSimpleSelector.tagHistory(); selector; selector = selector->tagHistory()) + total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector, isComputingMaximumSpecificity)); return total; } -inline unsigned CSSSelector::specificityForOneSelector() const -{ - // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function - // isn't quite correct. - switch (m_match) { - case Id: - return 0x10000; - case Exact: - case Class: - case Set: - case List: - case Hyphen: - case PseudoClass: - case PseudoElement: - case Contain: - case Begin: - case End: - // FIXME: PsuedoAny should base the specificity on the sub-selectors. - // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html - if (pseudoType() == PseudoNot && selectorList()) - return selectorList()->first()->specificityForOneSelector(); - return 0x100; - case Tag: - return (tagQName().localName() != starAtom) ? 1 : 0; - case Unknown: +static unsigned maxSpecificity(const CSSSelectorList& selectorList) +{ + unsigned maxSpecificity = 0; + for (const CSSSelector* subSelector = selectorList.first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) + maxSpecificity = std::max(maxSpecificity, selectorSpecificity(*subSelector, true)); + return maxSpecificity; +} + +static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity) +{ + ASSERT_WITH_MESSAGE(!simpleSelector.isForPage(), "At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors."); + + switch (simpleSelector.match()) { + case CSSSelector::Id: + return static_cast(SelectorSpecificityIncrement::ClassA); + + case CSSSelector::PagePseudoClass: + break; + case CSSSelector::PseudoClass: + if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassMatches) { + ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :matches()."); + if (!isComputingMaximumSpecificity) + return 0; + return maxSpecificity(*simpleSelector.selectorList()); + } + + if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassNot) { + ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :not()."); + return maxSpecificity(*simpleSelector.selectorList()); + } + FALLTHROUGH; + case CSSSelector::Exact: + case CSSSelector::Class: + case CSSSelector::Set: + case CSSSelector::List: + case CSSSelector::Hyphen: + case CSSSelector::Contain: + case CSSSelector::Begin: + case CSSSelector::End: + return static_cast(SelectorSpecificityIncrement::ClassB); + case CSSSelector::Tag: + return (simpleSelector.tagQName().localName() != starAtom) ? static_cast(SelectorSpecificityIncrement::ClassC) : 0; + case CSSSelector::PseudoElement: + return static_cast(SelectorSpecificityIncrement::ClassC); + case CSSSelector::Unknown: return 0; } ASSERT_NOT_REACHED(); return 0; } +unsigned CSSSelector::simpleSelectorSpecificity() const +{ + return simpleSelectorSpecificityInternal(*this, false); +} + +static unsigned staticSpecificityInternal(const CSSSelector& firstSimpleSelector, bool& ok); + +static unsigned simpleSelectorFunctionalPseudoClassStaticSpecificity(const CSSSelector& simpleSelector, bool& ok) +{ + if (simpleSelector.match() == CSSSelector::PseudoClass) { + CSSSelector::PseudoClassType pseudoClassType = simpleSelector.pseudoClassType(); + if (pseudoClassType == CSSSelector::PseudoClassMatches || pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild) { + const CSSSelectorList* selectorList = simpleSelector.selectorList(); + if (!selectorList) { + ASSERT_WITH_MESSAGE(pseudoClassType != CSSSelector::PseudoClassMatches, ":matches() should never be created without a valid selector list."); + return 0; + } + + const CSSSelector& firstSubselector = *selectorList->first(); + + unsigned initialSpecificity = staticSpecificityInternal(firstSubselector, ok); + if (!ok) + return 0; + + const CSSSelector* subselector = &firstSubselector; + while ((subselector = CSSSelectorList::next(subselector))) { + unsigned subSelectorSpecificity = staticSpecificityInternal(*subselector, ok); + if (initialSpecificity != subSelectorSpecificity) + ok = false; + if (!ok) + return 0; + } + return initialSpecificity; + } + } + return 0; +} + +static unsigned functionalPseudoClassStaticSpecificity(const CSSSelector& firstSimpleSelector, bool& ok) +{ + unsigned total = 0; + for (const CSSSelector* selector = &firstSimpleSelector; selector; selector = selector->tagHistory()) { + total = CSSSelector::addSpecificities(total, simpleSelectorFunctionalPseudoClassStaticSpecificity(*selector, ok)); + if (!ok) + return 0; + } + return total; +} + +static unsigned staticSpecificityInternal(const CSSSelector& firstSimpleSelector, bool& ok) +{ + unsigned staticSpecificity = selectorSpecificity(firstSimpleSelector, false); + return CSSSelector::addSpecificities(staticSpecificity, functionalPseudoClassStaticSpecificity(firstSimpleSelector, ok)); +} + +unsigned CSSSelector::staticSpecificity(bool &ok) const +{ + ok = true; + return staticSpecificityInternal(*this, ok); +} + +unsigned CSSSelector::addSpecificities(unsigned a, unsigned b) +{ + unsigned total = a; + + unsigned newIdValue = (b & idMask); + if (((total & idMask) + newIdValue) & ~idMask) + total |= idMask; + else + total += newIdValue; + + unsigned newClassValue = (b & classMask); + if (((total & classMask) + newClassValue) & ~classMask) + total |= classMask; + else + total += newClassValue; + + unsigned newElementValue = (b & elementMask); + if (((total & elementMask) + newElementValue) & ~elementMask) + total |= elementMask; + else + total += newElementValue; + + return total; +} + unsigned CSSSelector::specificityForPage() const { + ASSERT(isForPage()); + // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context unsigned s = 0; for (const CSSSelector* component = this; component; component = component->tagHistory()) { - switch (component->m_match) { + switch (component->match()) { case Tag: s += tagQName().localName() == starAtom ? 0 : 4; break; - case PseudoClass: - switch (component->pseudoType()) { - case PseudoFirstPage: + case PagePseudoClass: + switch (component->pagePseudoClassType()) { + case PagePseudoClassFirst: s += 2; break; - case PseudoLeftPage: - case PseudoRightPage: + case PagePseudoClassLeft: + case PagePseudoClassRight: s += 1; break; - case PseudoNotParsed: - break; - default: - ASSERT_NOT_REACHED(); } break; default: @@ -143,112 +267,41 @@ unsigned CSSSelector::specificityForPage() const return s; } -PseudoId CSSSelector::pseudoId(PseudoType type) +PseudoId CSSSelector::pseudoId(PseudoElementType type) { switch (type) { - case PseudoFirstLine: + case PseudoElementFirstLine: return FIRST_LINE; - case PseudoFirstLetter: + case PseudoElementFirstLetter: return FIRST_LETTER; - case PseudoSelection: + case PseudoElementSelection: return SELECTION; - case PseudoBefore: + case PseudoElementBefore: return BEFORE; - case PseudoAfter: + case PseudoElementAfter: return AFTER; - case PseudoScrollbar: + case PseudoElementScrollbar: return SCROLLBAR; - case PseudoScrollbarButton: + case PseudoElementScrollbarButton: return SCROLLBAR_BUTTON; - case PseudoScrollbarCorner: + case PseudoElementScrollbarCorner: return SCROLLBAR_CORNER; - case PseudoScrollbarThumb: + case PseudoElementScrollbarThumb: return SCROLLBAR_THUMB; - case PseudoScrollbarTrack: + case PseudoElementScrollbarTrack: return SCROLLBAR_TRACK; - case PseudoScrollbarTrackPiece: + case PseudoElementScrollbarTrackPiece: return SCROLLBAR_TRACK_PIECE; - case PseudoResizer: + case PseudoElementResizer: return RESIZER; -#if ENABLE(FULLSCREEN_API) - case PseudoFullScreen: - return FULL_SCREEN; - case PseudoFullScreenDocument: - return FULL_SCREEN_DOCUMENT; - case PseudoFullScreenAncestor: - return FULL_SCREEN_ANCESTOR; - case PseudoAnimatingFullScreenTransition: - return ANIMATING_FULL_SCREEN_TRANSITION; -#endif - case PseudoUnknown: - case PseudoEmpty: - case PseudoFirstChild: - case PseudoFirstOfType: - case PseudoLastChild: - case PseudoLastOfType: - case PseudoOnlyChild: - case PseudoOnlyOfType: - case PseudoNthChild: - case PseudoNthOfType: - case PseudoNthLastChild: - case PseudoNthLastOfType: - case PseudoLink: - case PseudoVisited: - case PseudoAny: - case PseudoAnyLink: - case PseudoAutofill: - case PseudoHover: - case PseudoDrag: - case PseudoFocus: - case PseudoActive: - case PseudoChecked: - case PseudoEnabled: - case PseudoFullPageMedia: - case PseudoDefault: - case PseudoDisabled: - case PseudoOptional: - case PseudoRequired: - case PseudoReadOnly: - case PseudoReadWrite: - case PseudoValid: - case PseudoInvalid: - case PseudoIndeterminate: - case PseudoTarget: - case PseudoLang: - case PseudoNot: - case PseudoRoot: - case PseudoScope: - case PseudoScrollbarBack: - case PseudoScrollbarForward: - case PseudoWindowInactive: - case PseudoCornerPresent: - case PseudoDecrement: - case PseudoIncrement: - case PseudoHorizontal: - case PseudoVertical: - case PseudoStart: - case PseudoEnd: - case PseudoDoubleButton: - case PseudoSingleButton: - case PseudoNoButton: - case PseudoFirstPage: - case PseudoLeftPage: - case PseudoRightPage: - case PseudoInRange: - case PseudoOutOfRange: - case PseudoUserAgentCustomElement: - case PseudoWebKitCustomElement: #if ENABLE(VIDEO_TRACK) - case PseudoCue: - case PseudoFutureCue: - case PseudoPastCue: + case PseudoElementCue: #endif -#if ENABLE(IFRAME_SEAMLESS) - case PseudoSeamlessDocument: -#endif - return NOPSEUDO; - case PseudoNotParsed: - ASSERT_NOT_REACHED(); + case PseudoElementSlotted: + case PseudoElementUnknown: + case PseudoElementUserAgentCustom: + case PseudoElementWebKitCustom: + case PseudoElementWebKitCustomLegacyPrefixed: return NOPSEUDO; } @@ -256,253 +309,23 @@ PseudoId CSSSelector::pseudoId(PseudoType type) return NOPSEUDO; } -static NEVER_INLINE void populatePseudoTypeByNameMap(HashMap& map) -{ - struct TableEntry { - const char* name; - unsigned nameLength; - CSSSelector::PseudoType type; - }; - - // Could use strlen in this macro but not all compilers can constant-fold it. -#define TABLE_ENTRY(name, type) { name, sizeof(name) - 1, CSSSelector::type }, - - static const TableEntry table[] = { - TABLE_ENTRY("-khtml-drag", PseudoDrag) - TABLE_ENTRY("-webkit-any(", PseudoAny) - TABLE_ENTRY("-webkit-any-link", PseudoAnyLink) - TABLE_ENTRY("-webkit-autofill", PseudoAutofill) - TABLE_ENTRY("-webkit-drag", PseudoDrag) - TABLE_ENTRY("-webkit-full-page-media", PseudoFullPageMedia) - TABLE_ENTRY("-webkit-resizer", PseudoResizer) - TABLE_ENTRY("-webkit-scrollbar", PseudoScrollbar) - TABLE_ENTRY("-webkit-scrollbar-button", PseudoScrollbarButton) - TABLE_ENTRY("-webkit-scrollbar-corner", PseudoScrollbarCorner) - TABLE_ENTRY("-webkit-scrollbar-thumb", PseudoScrollbarThumb) - TABLE_ENTRY("-webkit-scrollbar-track", PseudoScrollbarTrack) - TABLE_ENTRY("-webkit-scrollbar-track-piece", PseudoScrollbarTrackPiece) - TABLE_ENTRY("active", PseudoActive) - TABLE_ENTRY("after", PseudoAfter) - TABLE_ENTRY("before", PseudoBefore) - TABLE_ENTRY("checked", PseudoChecked) - TABLE_ENTRY("corner-present", PseudoCornerPresent) - TABLE_ENTRY("decrement", PseudoDecrement) - TABLE_ENTRY("default", PseudoDefault) - TABLE_ENTRY("disabled", PseudoDisabled) - TABLE_ENTRY("double-button", PseudoDoubleButton) - TABLE_ENTRY("empty", PseudoEmpty) - TABLE_ENTRY("enabled", PseudoEnabled) - TABLE_ENTRY("end", PseudoEnd) - TABLE_ENTRY("first", PseudoFirstPage) - TABLE_ENTRY("first-child", PseudoFirstChild) - TABLE_ENTRY("first-letter", PseudoFirstLetter) - TABLE_ENTRY("first-line", PseudoFirstLine) - TABLE_ENTRY("first-of-type", PseudoFirstOfType) - TABLE_ENTRY("focus", PseudoFocus) - TABLE_ENTRY("horizontal", PseudoHorizontal) - TABLE_ENTRY("hover", PseudoHover) - TABLE_ENTRY("in-range", PseudoInRange) - TABLE_ENTRY("increment", PseudoIncrement) - TABLE_ENTRY("indeterminate", PseudoIndeterminate) - TABLE_ENTRY("invalid", PseudoInvalid) - TABLE_ENTRY("lang(", PseudoLang) - TABLE_ENTRY("last-child", PseudoLastChild) - TABLE_ENTRY("last-of-type", PseudoLastOfType) - TABLE_ENTRY("left", PseudoLeftPage) - TABLE_ENTRY("link", PseudoLink) - TABLE_ENTRY("no-button", PseudoNoButton) - TABLE_ENTRY("not(", PseudoNot) - TABLE_ENTRY("nth-child(", PseudoNthChild) - TABLE_ENTRY("nth-last-child(", PseudoNthLastChild) - TABLE_ENTRY("nth-last-of-type(", PseudoNthLastOfType) - TABLE_ENTRY("nth-of-type(", PseudoNthOfType) - TABLE_ENTRY("only-child", PseudoOnlyChild) - TABLE_ENTRY("only-of-type", PseudoOnlyOfType) - TABLE_ENTRY("optional", PseudoOptional) - TABLE_ENTRY("out-of-range", PseudoOutOfRange) - TABLE_ENTRY("read-only", PseudoReadOnly) - TABLE_ENTRY("read-write", PseudoReadWrite) - TABLE_ENTRY("required", PseudoRequired) - TABLE_ENTRY("right", PseudoRightPage) - TABLE_ENTRY("root", PseudoRoot) - TABLE_ENTRY("scope", PseudoScope) - TABLE_ENTRY("selection", PseudoSelection) - TABLE_ENTRY("single-button", PseudoSingleButton) - TABLE_ENTRY("start", PseudoStart) - TABLE_ENTRY("target", PseudoTarget) - TABLE_ENTRY("valid", PseudoValid) - TABLE_ENTRY("vertical", PseudoVertical) - TABLE_ENTRY("visited", PseudoVisited) - TABLE_ENTRY("window-inactive", PseudoWindowInactive) - -#if ENABLE(FULLSCREEN_API) - TABLE_ENTRY("-webkit-animating-full-screen-transition", PseudoAnimatingFullScreenTransition) - TABLE_ENTRY("-webkit-full-screen", PseudoFullScreen) - TABLE_ENTRY("-webkit-full-screen-ancestor", PseudoFullScreenAncestor) - TABLE_ENTRY("-webkit-full-screen-document", PseudoFullScreenDocument) -#endif - -#if ENABLE(IFRAME_SEAMLESS) - TABLE_ENTRY("-webkit-seamless-document", PseudoSeamlessDocument) -#endif - -#if ENABLE(VIDEO_TRACK) - TABLE_ENTRY("cue(", PseudoCue) - TABLE_ENTRY("future", PseudoFutureCue) - TABLE_ENTRY("past", PseudoPastCue) -#endif - }; - -#undef TABLE_ENTRY - - for (unsigned i = 0; i < WTF_ARRAY_LENGTH(table); ++i) - map.add(AtomicString(table[i].name, table[i].nameLength, AtomicString::ConstructFromLiteral), table[i].type); -} - -CSSSelector::PseudoType CSSSelector::parsePseudoType(const AtomicString& name) +CSSSelector::PseudoElementType CSSSelector::parsePseudoElementType(const String& name) { if (name.isNull()) - return PseudoUnknown; - - static NeverDestroyed> types; - if (types.get().isEmpty()) - populatePseudoTypeByNameMap(types); - if (PseudoType type = types.get().get(name)) - return type; - - if (name.startsWith("-webkit-")) - return PseudoWebKitCustomElement; - - // FIXME: This is strange. Why would all strings that start with "cue" be "user agent custom"? - if (name.startsWith("x-") || name.startsWith("cue")) - return PseudoUserAgentCustomElement; - - return PseudoUnknown; -} - -void CSSSelector::extractPseudoType() const -{ - if (m_match != PseudoClass && m_match != PseudoElement && m_match != PagePseudoClass) - return; + return PseudoElementUnknown; - m_pseudoType = parsePseudoType(value()); + PseudoElementType type = parsePseudoElementString(*name.impl()); + if (type == PseudoElementUnknown) { + if (name.startsWith("-webkit-")) + type = PseudoElementWebKitCustom; - bool element = false; // pseudo-element - bool compat = false; // single colon compatbility mode - bool isPagePseudoClass = false; // Page pseudo-class - - switch (m_pseudoType) { - case PseudoAfter: - case PseudoBefore: -#if ENABLE(VIDEO_TRACK) - case PseudoCue: -#endif - case PseudoFirstLetter: - case PseudoFirstLine: - compat = true; - FALLTHROUGH; -#if ENABLE(SHADOW_DOM) - case PseudoDistributed: -#endif - case PseudoResizer: - case PseudoScrollbar: - case PseudoScrollbarCorner: - case PseudoScrollbarButton: - case PseudoScrollbarThumb: - case PseudoScrollbarTrack: - case PseudoScrollbarTrackPiece: - case PseudoSelection: - case PseudoUserAgentCustomElement: - case PseudoWebKitCustomElement: - element = true; - break; - case PseudoUnknown: - case PseudoEmpty: - case PseudoFirstChild: - case PseudoFirstOfType: - case PseudoLastChild: - case PseudoLastOfType: - case PseudoOnlyChild: - case PseudoOnlyOfType: - case PseudoNthChild: - case PseudoNthOfType: - case PseudoNthLastChild: - case PseudoNthLastOfType: - case PseudoLink: - case PseudoVisited: - case PseudoAny: - case PseudoAnyLink: - case PseudoAutofill: - case PseudoHover: - case PseudoDrag: - case PseudoFocus: - case PseudoActive: - case PseudoChecked: - case PseudoEnabled: - case PseudoFullPageMedia: - case PseudoDefault: - case PseudoDisabled: - case PseudoOptional: - case PseudoRequired: - case PseudoReadOnly: - case PseudoReadWrite: - case PseudoScope: - case PseudoValid: - case PseudoInvalid: - case PseudoIndeterminate: - case PseudoTarget: - case PseudoLang: - case PseudoNot: - case PseudoRoot: - case PseudoScrollbarBack: - case PseudoScrollbarForward: - case PseudoWindowInactive: - case PseudoCornerPresent: - case PseudoDecrement: - case PseudoIncrement: - case PseudoHorizontal: - case PseudoVertical: - case PseudoStart: - case PseudoEnd: - case PseudoDoubleButton: - case PseudoSingleButton: - case PseudoNoButton: - case PseudoNotParsed: -#if ENABLE(FULLSCREEN_API) - case PseudoFullScreen: - case PseudoFullScreenDocument: - case PseudoFullScreenAncestor: - case PseudoAnimatingFullScreenTransition: -#endif -#if ENABLE(IFRAME_SEAMLESS) - case PseudoSeamlessDocument: -#endif - case PseudoInRange: - case PseudoOutOfRange: -#if ENABLE(VIDEO_TRACK) - case PseudoFutureCue: - case PseudoPastCue: -#endif - break; - case PseudoFirstPage: - case PseudoLeftPage: - case PseudoRightPage: - isPagePseudoClass = true; - break; + if (name.startsWith("x-")) + type = PseudoElementUserAgentCustom; } - - bool matchPagePseudoClass = (m_match == PagePseudoClass); - if (matchPagePseudoClass != isPagePseudoClass) - m_pseudoType = PseudoUnknown; - else if (m_match == PseudoClass && element) { - if (!compat) - m_pseudoType = PseudoUnknown; - else - m_match = PseudoElement; - } else if (m_match == PseudoElement && !element) - m_pseudoType = PseudoUnknown; + return type; } + bool CSSSelector::operator==(const CSSSelector& other) const { const CSSSelector* sel1 = this; @@ -511,13 +334,13 @@ bool CSSSelector::operator==(const CSSSelector& other) const while (sel1 && sel2) { if (sel1->attribute() != sel2->attribute() || sel1->relation() != sel2->relation() - || sel1->m_match != sel2->m_match + || sel1->match() != sel2->match() || sel1->value() != sel2->value() - || sel1->pseudoType() != sel2->pseudoType() + || sel1->m_pseudoType != sel2->m_pseudoType || sel1->argument() != sel2->argument()) { return false; } - if (sel1->m_match == Tag) { + if (sel1->match() == Tag) { if (sel1->tagQName() != sel2->tagQName()) return false; } @@ -531,11 +354,46 @@ bool CSSSelector::operator==(const CSSSelector& other) const return true; } +static void appendPseudoClassFunctionTail(StringBuilder& str, const CSSSelector* selector) +{ + switch (selector->pseudoClassType()) { +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::PseudoClassDir: +#endif + case CSSSelector::PseudoClassLang: + case CSSSelector::PseudoClassNthChild: + case CSSSelector::PseudoClassNthLastChild: + case CSSSelector::PseudoClassNthOfType: + case CSSSelector::PseudoClassNthLastOfType: +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::PseudoClassRole: +#endif + str.append(selector->argument()); + str.append(')'); + break; + default: + break; + } + +} + +static void appendLangArgumentList(StringBuilder& str, const Vector& argumentList) +{ + unsigned argumentListSize = argumentList.size(); + for (unsigned i = 0; i < argumentListSize; ++i) { + str.append('"'); + str.append(argumentList[i]); + str.append('"'); + if (i != argumentListSize - 1) + str.appendLiteral(", "); + } +} + String CSSSelector::selectorText(const String& rightSide) const { StringBuilder str; - if (m_match == CSSSelector::Tag && !m_tagIsForNamespaceRule) { + if (match() == CSSSelector::Tag && !m_tagIsForNamespaceRule) { if (tagQName().prefix().isNull()) str.append(tagQName().localName()); else { @@ -547,55 +405,272 @@ String CSSSelector::selectorText(const String& rightSide) const const CSSSelector* cs = this; while (true) { - if (cs->m_match == CSSSelector::Id) { + if (cs->match() == CSSSelector::Id) { str.append('#'); - serializeIdentifier(cs->value(), str); - } else if (cs->m_match == CSSSelector::Class) { + serializeIdentifier(cs->serializingValue(), str); + } else if (cs->match() == CSSSelector::Class) { str.append('.'); - serializeIdentifier(cs->value(), str); - } else if (cs->m_match == CSSSelector::PseudoClass || cs->m_match == CSSSelector::PagePseudoClass) { - str.append(':'); - str.append(cs->value()); - - switch (cs->pseudoType()) { - case PseudoNot: - if (const CSSSelectorList* selectorList = cs->selectorList()) - str.append(selectorList->first()->selectorText()); + serializeIdentifier(cs->serializingValue(), str); + } else if (cs->match() == CSSSelector::PseudoClass) { + switch (cs->pseudoClassType()) { +#if ENABLE(FULLSCREEN_API) + case CSSSelector::PseudoClassAnimatingFullScreenTransition: + str.appendLiteral(":-webkit-animating-full-screen-transition"); + break; +#endif + case CSSSelector::PseudoClassAny: { + str.appendLiteral(":-webkit-any("); + cs->selectorList()->buildSelectorsText(str); str.append(')'); break; - case PseudoLang: - case PseudoNthChild: - case PseudoNthLastChild: - case PseudoNthOfType: - case PseudoNthLastOfType: + } + case CSSSelector::PseudoClassAnyLink: + str.appendLiteral(":any-link"); + break; + case CSSSelector::PseudoClassAnyLinkDeprecated: + str.appendLiteral(":-webkit-any-link"); + break; + case CSSSelector::PseudoClassAutofill: + str.appendLiteral(":-webkit-autofill"); + break; + case CSSSelector::PseudoClassDrag: + str.appendLiteral(":-webkit-drag"); + break; + case CSSSelector::PseudoClassFullPageMedia: + str.appendLiteral(":-webkit-full-page-media"); + break; +#if ENABLE(FULLSCREEN_API) + case CSSSelector::PseudoClassFullScreen: + str.appendLiteral(":-webkit-full-screen"); + break; + case CSSSelector::PseudoClassFullScreenAncestor: + str.appendLiteral(":-webkit-full-screen-ancestor"); + break; + case CSSSelector::PseudoClassFullScreenDocument: + str.appendLiteral(":-webkit-full-screen-document"); + break; +#endif + case CSSSelector::PseudoClassActive: + str.appendLiteral(":active"); + break; + case CSSSelector::PseudoClassChecked: + str.appendLiteral(":checked"); + break; + case CSSSelector::PseudoClassCornerPresent: + str.appendLiteral(":corner-present"); + break; + case CSSSelector::PseudoClassDecrement: + str.appendLiteral(":decrement"); + break; + case CSSSelector::PseudoClassDefault: + str.appendLiteral(":default"); + break; +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::PseudoClassDir: + str.appendLiteral(":dir("); + appendPseudoClassFunctionTail(str, cs); + break; +#endif + case CSSSelector::PseudoClassDisabled: + str.appendLiteral(":disabled"); + break; + case CSSSelector::PseudoClassDoubleButton: + str.appendLiteral(":double-button"); + break; + case CSSSelector::PseudoClassEmpty: + str.appendLiteral(":empty"); + break; + case CSSSelector::PseudoClassEnabled: + str.appendLiteral(":enabled"); + break; + case CSSSelector::PseudoClassEnd: + str.appendLiteral(":end"); + break; + case CSSSelector::PseudoClassFirstChild: + str.appendLiteral(":first-child"); + break; + case CSSSelector::PseudoClassFirstOfType: + str.appendLiteral(":first-of-type"); + break; + case CSSSelector::PseudoClassFocus: + str.appendLiteral(":focus"); + break; + case CSSSelector::PseudoClassFocusWithin: + str.appendLiteral(":focus-within"); + break; +#if ENABLE(VIDEO_TRACK) + case CSSSelector::PseudoClassFuture: + str.appendLiteral(":future"); + break; +#endif + case CSSSelector::PseudoClassHorizontal: + str.appendLiteral(":horizontal"); + break; + case CSSSelector::PseudoClassHover: + str.appendLiteral(":hover"); + break; + case CSSSelector::PseudoClassInRange: + str.appendLiteral(":in-range"); + break; + case CSSSelector::PseudoClassIncrement: + str.appendLiteral(":increment"); + break; + case CSSSelector::PseudoClassIndeterminate: + str.appendLiteral(":indeterminate"); + break; + case CSSSelector::PseudoClassInvalid: + str.appendLiteral(":invalid"); + break; + case CSSSelector::PseudoClassLang: + str.appendLiteral(":lang("); + ASSERT_WITH_MESSAGE(cs->langArgumentList() && !cs->langArgumentList()->isEmpty(), "An empty :lang() is invalid and should never be generated by the parser."); + appendLangArgumentList(str, *cs->langArgumentList()); + str.append(')'); + break; + case CSSSelector::PseudoClassLastChild: + str.appendLiteral(":last-child"); + break; + case CSSSelector::PseudoClassLastOfType: + str.appendLiteral(":last-of-type"); + break; + case CSSSelector::PseudoClassLink: + str.appendLiteral(":link"); + break; + case CSSSelector::PseudoClassNoButton: + str.appendLiteral(":no-button"); + break; + case CSSSelector::PseudoClassNot: + str.appendLiteral(":not("); + cs->selectorList()->buildSelectorsText(str); + str.append(')'); + break; + case CSSSelector::PseudoClassNthChild: + str.appendLiteral(":nth-child("); str.append(cs->argument()); + if (const CSSSelectorList* selectorList = cs->selectorList()) { + str.appendLiteral(" of "); + selectorList->buildSelectorsText(str); + } str.append(')'); break; - case PseudoAny: { - const CSSSelector* firstSubSelector = cs->selectorList()->first(); - for (const CSSSelector* subSelector = firstSubSelector; subSelector; subSelector = CSSSelectorList::next(subSelector)) { - if (subSelector != firstSubSelector) - str.append(','); - str.append(subSelector->selectorText()); + case CSSSelector::PseudoClassNthLastChild: + str.appendLiteral(":nth-last-child("); + str.append(cs->argument()); + if (const CSSSelectorList* selectorList = cs->selectorList()) { + str.appendLiteral(" of "); + selectorList->buildSelectorsText(str); } str.append(')'); break; + case CSSSelector::PseudoClassNthLastOfType: + str.appendLiteral(":nth-last-of-type("); + appendPseudoClassFunctionTail(str, cs); + break; + case CSSSelector::PseudoClassNthOfType: + str.appendLiteral(":nth-of-type("); + appendPseudoClassFunctionTail(str, cs); + break; + case CSSSelector::PseudoClassOnlyChild: + str.appendLiteral(":only-child"); + break; + case CSSSelector::PseudoClassOnlyOfType: + str.appendLiteral(":only-of-type"); + break; + case CSSSelector::PseudoClassOptional: + str.appendLiteral(":optional"); + break; + case CSSSelector::PseudoClassMatches: { + str.appendLiteral(":matches("); + cs->selectorList()->buildSelectorsText(str); + str.append(')'); + break; } - default: + case CSSSelector::PseudoClassPlaceholderShown: + str.appendLiteral(":placeholder-shown"); + break; + case CSSSelector::PseudoClassOutOfRange: + str.appendLiteral(":out-of-range"); + break; +#if ENABLE(VIDEO_TRACK) + case CSSSelector::PseudoClassPast: + str.appendLiteral(":past"); + break; +#endif + case CSSSelector::PseudoClassReadOnly: + str.appendLiteral(":read-only"); + break; + case CSSSelector::PseudoClassReadWrite: + str.appendLiteral(":read-write"); + break; + case CSSSelector::PseudoClassRequired: + str.appendLiteral(":required"); break; +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::PseudoClassRole: + str.appendLiteral(":role("); + appendPseudoClassFunctionTail(str, cs); + break; +#endif + case CSSSelector::PseudoClassRoot: + str.appendLiteral(":root"); + break; + case CSSSelector::PseudoClassScope: + str.appendLiteral(":scope"); + break; + case CSSSelector::PseudoClassSingleButton: + str.appendLiteral(":single-button"); + break; + case CSSSelector::PseudoClassStart: + str.appendLiteral(":start"); + break; + case CSSSelector::PseudoClassTarget: + str.appendLiteral(":target"); + break; + case CSSSelector::PseudoClassValid: + str.appendLiteral(":valid"); + break; + case CSSSelector::PseudoClassVertical: + str.appendLiteral(":vertical"); + break; + case CSSSelector::PseudoClassVisited: + str.appendLiteral(":visited"); + break; + case CSSSelector::PseudoClassWindowInactive: + str.appendLiteral(":window-inactive"); + break; + case CSSSelector::PseudoClassHost: + str.appendLiteral(":host"); + break; + case CSSSelector::PseudoClassDefined: + str.appendLiteral(":defined"); + break; + case CSSSelector::PseudoClassUnknown: + ASSERT_NOT_REACHED(); + } + } else if (cs->match() == CSSSelector::PseudoElement) { + switch (cs->pseudoElementType()) { + case CSSSelector::PseudoElementSlotted: + str.appendLiteral("::slotted("); + cs->selectorList()->buildSelectorsText(str); + str.append(')'); + break; + case CSSSelector::PseudoElementWebKitCustomLegacyPrefixed: + if (cs->value() == "placeholder") + str.appendLiteral("::-webkit-input-placeholder"); + break; + default: + str.appendLiteral("::"); + str.append(cs->serializingValue()); } - } else if (cs->m_match == CSSSelector::PseudoElement) { - str.appendLiteral("::"); - str.append(cs->value()); } else if (cs->isAttributeSelector()) { str.append('['); const AtomicString& prefix = cs->attribute().prefix(); - if (!prefix.isNull()) { + if (!prefix.isEmpty()) { str.append(prefix); str.append('|'); } str.append(cs->attribute().localName()); - switch (cs->m_match) { + switch (cs->match()) { case CSSSelector::Exact: str.append('='); break; @@ -621,19 +696,35 @@ String CSSSelector::selectorText(const String& rightSide) const default: break; } - if (cs->m_match != CSSSelector::Set) { - serializeString(cs->value(), str); - str.append(']'); + if (cs->match() != CSSSelector::Set) { + serializeString(cs->serializingValue(), str); + if (cs->attributeValueMatchingIsCaseInsensitive()) + str.appendLiteral(" i]"); + else + str.append(']'); + } + } else if (cs->match() == CSSSelector::PagePseudoClass) { + switch (cs->pagePseudoClassType()) { + case PagePseudoClassFirst: + str.appendLiteral(":first"); + break; + case PagePseudoClassLeft: + str.appendLiteral(":left"); + break; + case PagePseudoClassRight: + str.appendLiteral(":right"); + break; } } - if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory()) + + if (cs->relation() != CSSSelector::Subselector || !cs->tagHistory()) break; cs = cs->tagHistory(); } if (const CSSSelector* tagHistory = cs->tagHistory()) { switch (cs->relation()) { - case CSSSelector::Descendant: + case CSSSelector::DescendantSpace: return tagHistory->selectorText(" " + str.toString() + rightSide); case CSSSelector::Child: return tagHistory->selectorText(" > " + str.toString() + rightSide); @@ -641,7 +732,11 @@ String CSSSelector::selectorText(const String& rightSide) const return tagHistory->selectorText(" + " + str.toString() + rightSide); case CSSSelector::IndirectAdjacent: return tagHistory->selectorText(" ~ " + str.toString() + rightSide); - case CSSSelector::SubSelector: +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::DescendantDoubleChild: + return tagHistory->selectorText(" >> " + str.toString() + rightSide); +#endif + case CSSSelector::Subselector: ASSERT_NOT_REACHED(); #if ASSERT_DISABLED FALLTHROUGH; @@ -657,21 +752,45 @@ void CSSSelector::setAttribute(const QualifiedName& value, bool isCaseInsensitiv { createRareData(); m_data.m_rareData->m_attribute = value; - m_data.m_rareData->m_attributeCanonicalLocalName = isCaseInsensitive ? value.localName().lower() : value.localName(); + m_data.m_rareData->m_attributeCanonicalLocalName = isCaseInsensitive ? value.localName().convertToASCIILowercase() : value.localName(); } +void CSSSelector::setAttribute(const QualifiedName& value, bool convertToLowercase, AttributeMatchType matchType) +{ + createRareData(); + m_data.m_rareData->m_attribute = value; + m_data.m_rareData->m_attributeCanonicalLocalName = convertToLowercase ? value.localName().convertToASCIILowercase() : value.localName(); + m_caseInsensitiveAttributeValueMatching = matchType == CaseInsensitive; +} + void CSSSelector::setArgument(const AtomicString& value) { createRareData(); m_data.m_rareData->m_argument = value; } -void CSSSelector::setSelectorList(PassOwnPtr selectorList) +void CSSSelector::setLangArgumentList(std::unique_ptr> argumentList) { createRareData(); - m_data.m_rareData->m_selectorList = selectorList; + m_data.m_rareData->m_langArgumentList = WTFMove(argumentList); } +void CSSSelector::setSelectorList(std::unique_ptr selectorList) +{ + createRareData(); + m_data.m_rareData->m_selectorList = WTFMove(selectorList); +} + +void CSSSelector::setNth(int a, int b) +{ + createRareData(); + m_parsedNth = true; // FIXME-NEWPARSER: Can remove this parsed boolean once old parser is gone. + m_data.m_rareData->m_a = a; + m_data.m_rareData->m_b = b; +} + +// FIXME-NEWPARSER: All the code to parse nth-child stuff can be removed when +// the new parser is enabled. bool CSSSelector::parseNth() const { if (!m_hasRareData) @@ -688,8 +807,23 @@ bool CSSSelector::matchNth(int count) const return m_data.m_rareData->matchNth(count); } -CSSSelector::RareData::RareData(PassRefPtr value) - : m_value(value.leakRef()) +int CSSSelector::nthA() const +{ + ASSERT(m_hasRareData); + ASSERT(m_parsedNth); + return m_data.m_rareData->m_a; +} + +int CSSSelector::nthB() const +{ + ASSERT(m_hasRareData); + ASSERT(m_parsedNth); + return m_data.m_rareData->m_b; +} + +CSSSelector::RareData::RareData(AtomicString&& value) + : m_matchingValue(value) + , m_serializingValue(value) , m_a(0) , m_b(0) , m_attribute(anyQName()) @@ -699,49 +833,65 @@ CSSSelector::RareData::RareData(PassRefPtr value) CSSSelector::RareData::~RareData() { - if (m_value) - m_value->deref(); } // a helper function for parsing nth-arguments bool CSSSelector::RareData::parseNth() { - String argument = m_argument.lower(); - - if (argument.isEmpty()) + if (m_argument.isEmpty()) return false; - m_a = 0; - m_b = 0; - if (argument == "odd") { + if (equalLettersIgnoringASCIICase(m_argument, "odd")) { m_a = 2; m_b = 1; - } else if (argument == "even") { + } else if (equalLettersIgnoringASCIICase(m_argument, "even")) { m_a = 2; m_b = 0; } else { - size_t n = argument.find('n'); + m_a = 0; + m_b = 0; + + size_t n = std::min(m_argument.find('n'), m_argument.find('N')); if (n != notFound) { - if (argument[0] == '-') { + if (m_argument[0] == '-') { if (n == 1) m_a = -1; // -n == -1n - else - m_a = argument.substring(0, n).toInt(); + else { + bool ok; + m_a = StringView(m_argument).substring(0, n).toIntStrict(ok); + if (!ok) + return false; + } } else if (!n) m_a = 1; // n == 1n - else - m_a = argument.substring(0, n).toInt(); - - size_t p = argument.find('+', n); - if (p != notFound) - m_b = argument.substring(p + 1, argument.length() - p - 1).toInt(); else { - p = argument.find('-', n); - if (p != notFound) - m_b = -argument.substring(p + 1, argument.length() - p - 1).toInt(); + bool ok; + m_a = StringView(m_argument).substring(0, n).toIntStrict(ok); + if (!ok) + return false; } - } else - m_b = argument.toInt(); + + size_t p = m_argument.find('+', n); + if (p != notFound) { + bool ok; + m_b = StringView(m_argument).substring(p + 1).toIntStrict(ok); + if (!ok) + return false; + } else { + p = m_argument.find('-', n); + if (p != notFound) { + bool ok; + m_b = -StringView(m_argument).substring(p + 1).toIntStrict(ok); + if (!ok) + return false; + } + } + } else { + bool ok; + m_b = m_argument.string().toIntStrict(&ok); + if (!ok) + return false; + } } return true; } diff --git a/Source/WebCore/css/CSSSelector.h b/Source/WebCore/css/CSSSelector.h index 55ac62463..665a5f951 100644 --- a/Source/WebCore/css/CSSSelector.h +++ b/Source/WebCore/css/CSSSelector.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) * 1999 Waldo Bastian (bastian@kde.org) - * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013, 2014 Apple 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 @@ -19,18 +19,21 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSSelector_h -#define CSSSelector_h +#pragma once #include "QualifiedName.h" #include "RenderStyleConstants.h" #include -#include -#include namespace WebCore { class CSSSelectorList; + enum class SelectorSpecificityIncrement { + ClassA = 0x10000, + ClassB = 0x100, + ClassC = 1 + }; + // this class represents a selector for a StyleRule class CSSSelector { WTF_MAKE_FAST_ALLOCATED; @@ -44,14 +47,20 @@ namespace WebCore { /** * Re-create selector text from selector's data */ - String selectorText(const String& = "") const; + String selectorText(const String& = emptyString()) const; // checks if the 2 selectors (including sub selectors) agree. bool operator==(const CSSSelector&) const; - // tag == -1 means apply to all elements (Selector = *) + static const unsigned maxValueMask = 0xffffff; + static const unsigned idMask = 0xff0000; + static const unsigned classMask = 0xff00; + static const unsigned elementMask = 0xff; - unsigned specificity() const; + unsigned staticSpecificity(bool& ok) const; + unsigned specificityForPage() const; + unsigned simpleSelectorSpecificity() const; + static unsigned addSpecificities(unsigned, unsigned); /* how the attribute value has to match.... Default is Exact */ enum Match { @@ -71,101 +80,122 @@ namespace WebCore { PagePseudoClass }; - enum Relation { - Descendant = 0, + enum RelationType { + Subselector, + DescendantSpace, Child, DirectAdjacent, IndirectAdjacent, - SubSelector, - ShadowDescendant, +#if ENABLE(CSS_SELECTORS_LEVEL4) + DescendantDoubleChild, +#endif + ShadowDescendant }; - enum PseudoType { - PseudoNotParsed = 0, - PseudoUnknown, - PseudoEmpty, - PseudoFirstChild, - PseudoFirstOfType, - PseudoLastChild, - PseudoLastOfType, - PseudoOnlyChild, - PseudoOnlyOfType, - PseudoFirstLine, - PseudoFirstLetter, - PseudoNthChild, - PseudoNthOfType, - PseudoNthLastChild, - PseudoNthLastOfType, - PseudoLink, - PseudoVisited, - PseudoAny, - PseudoAnyLink, - PseudoAutofill, - PseudoHover, - PseudoDrag, - PseudoFocus, - PseudoActive, - PseudoChecked, - PseudoEnabled, - PseudoFullPageMedia, - PseudoDefault, - PseudoDisabled, - PseudoOptional, - PseudoRequired, - PseudoReadOnly, - PseudoReadWrite, - PseudoValid, - PseudoInvalid, - PseudoIndeterminate, - PseudoTarget, - PseudoBefore, - PseudoAfter, - PseudoLang, - PseudoNot, - PseudoResizer, - PseudoRoot, - PseudoScope, - PseudoScrollbar, - PseudoScrollbarBack, - PseudoScrollbarButton, - PseudoScrollbarCorner, - PseudoScrollbarForward, - PseudoScrollbarThumb, - PseudoScrollbarTrack, - PseudoScrollbarTrackPiece, - PseudoWindowInactive, - PseudoCornerPresent, - PseudoDecrement, - PseudoIncrement, - PseudoHorizontal, - PseudoVertical, - PseudoStart, - PseudoEnd, - PseudoDoubleButton, - PseudoSingleButton, - PseudoNoButton, - PseudoSelection, - PseudoLeftPage, - PseudoRightPage, - PseudoFirstPage, + enum PseudoClassType { + PseudoClassUnknown = 0, + PseudoClassEmpty, + PseudoClassFirstChild, + PseudoClassFirstOfType, + PseudoClassLastChild, + PseudoClassLastOfType, + PseudoClassOnlyChild, + PseudoClassOnlyOfType, + PseudoClassNthChild, + PseudoClassNthOfType, + PseudoClassNthLastChild, + PseudoClassNthLastOfType, + PseudoClassLink, + PseudoClassVisited, + PseudoClassAny, + PseudoClassAnyLink, + PseudoClassAnyLinkDeprecated, + PseudoClassAutofill, + PseudoClassHover, + PseudoClassDrag, + PseudoClassFocus, + PseudoClassFocusWithin, + PseudoClassActive, + PseudoClassChecked, + PseudoClassEnabled, + PseudoClassFullPageMedia, + PseudoClassDefault, + PseudoClassDisabled, + PseudoClassMatches, + PseudoClassOptional, + PseudoClassPlaceholderShown, + PseudoClassRequired, + PseudoClassReadOnly, + PseudoClassReadWrite, + PseudoClassValid, + PseudoClassInvalid, + PseudoClassIndeterminate, + PseudoClassTarget, + PseudoClassLang, + PseudoClassNot, + PseudoClassRoot, + PseudoClassScope, + PseudoClassWindowInactive, + PseudoClassCornerPresent, + PseudoClassDecrement, + PseudoClassIncrement, + PseudoClassHorizontal, + PseudoClassVertical, + PseudoClassStart, + PseudoClassEnd, + PseudoClassDoubleButton, + PseudoClassSingleButton, + PseudoClassNoButton, #if ENABLE(FULLSCREEN_API) - PseudoFullScreen, - PseudoFullScreenDocument, - PseudoFullScreenAncestor, - PseudoAnimatingFullScreenTransition, + PseudoClassFullScreen, + PseudoClassFullScreenDocument, + PseudoClassFullScreenAncestor, + PseudoClassAnimatingFullScreenTransition, #endif - PseudoInRange, - PseudoOutOfRange, - PseudoUserAgentCustomElement, - PseudoWebKitCustomElement, + PseudoClassInRange, + PseudoClassOutOfRange, #if ENABLE(VIDEO_TRACK) - PseudoCue, - PseudoFutureCue, - PseudoPastCue, + PseudoClassFuture, + PseudoClassPast, #endif -#if ENABLE(IFRAME_SEAMLESS) - PseudoSeamlessDocument, +#if ENABLE(CSS_SELECTORS_LEVEL4) + PseudoClassDir, + PseudoClassRole, #endif + PseudoClassHost, + PseudoClassDefined, + }; + + enum PseudoElementType { + PseudoElementUnknown = 0, + PseudoElementAfter, + PseudoElementBefore, +#if ENABLE(VIDEO_TRACK) + PseudoElementCue, +#endif + PseudoElementFirstLetter, + PseudoElementFirstLine, + PseudoElementResizer, + PseudoElementScrollbar, + PseudoElementScrollbarButton, + PseudoElementScrollbarCorner, + PseudoElementScrollbarThumb, + PseudoElementScrollbarTrack, + PseudoElementScrollbarTrackPiece, + PseudoElementSelection, + PseudoElementSlotted, + PseudoElementUserAgentCustom, + PseudoElementWebKitCustom, + + // WebKitCustom that appeared in an old prefixed form + // and need special handling. + PseudoElementWebKitCustomLegacyPrefixed, + }; + + enum PagePseudoClassType { + PagePseudoClassFirst = 1, + PagePseudoClassLeft, + PagePseudoClassRight, }; enum MarginBoxType { @@ -187,97 +217,181 @@ namespace WebCore { RightBottomMarginBox, }; - PseudoType pseudoType() const - { - if (m_pseudoType == PseudoNotParsed) - extractPseudoType(); - return static_cast(m_pseudoType); - } + enum AttributeMatchType { + CaseSensitive, + CaseInsensitive, + }; - static PseudoType parsePseudoType(const AtomicString&); - static PseudoId pseudoId(PseudoType); + static PseudoElementType parsePseudoElementType(const String&); + static PseudoId pseudoId(PseudoElementType); // Selectors are kept in an array by CSSSelectorList. The next component of the selector is // the next item in the array. const CSSSelector* tagHistory() const { return m_isLastInTagHistory ? 0 : const_cast(this + 1); } const QualifiedName& tagQName() const; + const AtomicString& tagLowercaseLocalName() const; + const AtomicString& value() const; + const AtomicString& serializingValue() const; const QualifiedName& attribute() const; const AtomicString& attributeCanonicalLocalName() const; const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; } - const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : 0; } + bool attributeValueMatchingIsCaseInsensitive() const; + const Vector* langArgumentList() const { return m_hasRareData ? m_data.m_rareData->m_langArgumentList.get() : nullptr; } + const CSSSelectorList* selectorList() const { return m_hasRareData ? m_data.m_rareData->m_selectorList.get() : nullptr; } - void setValue(const AtomicString&); - void setAttribute(const QualifiedName&, bool isCaseInsensitive); + void setValue(const AtomicString&, bool matchLowerCase = false); + + // FIXME-NEWPARSER: These two methods can go away once the old parser is gone. + void setAttribute(const QualifiedName&, bool); + void setAttributeValueMatchingIsCaseInsensitive(bool); + void setAttribute(const QualifiedName&, bool convertToLowercase, AttributeMatchType); + void setNth(int a, int b); void setArgument(const AtomicString&); - void setSelectorList(PassOwnPtr); + void setLangArgumentList(std::unique_ptr>); + void setSelectorList(std::unique_ptr); bool parseNth() const; bool matchNth(int count) const; + int nthA() const; + int nthB() const; + +#if ENABLE(CSS_SELECTORS_LEVEL4) + bool hasDescendantRelation() const { return relation() == DescendantSpace || relation() == DescendantDoubleChild; } +#else + bool hasDescendantRelation() const { return relation() == DescendantSpace; } +#endif + + bool hasDescendantOrChildRelation() const { return relation() == Child || hasDescendantRelation(); } + + PseudoClassType pseudoClassType() const + { + ASSERT(match() == PseudoClass); + return static_cast(m_pseudoType); + } + void setPseudoClassType(PseudoClassType pseudoType) + { + m_pseudoType = pseudoType; + ASSERT(m_pseudoType == pseudoType); + } + + PseudoElementType pseudoElementType() const + { + ASSERT(match() == PseudoElement); + return static_cast(m_pseudoType); + } + void setPseudoElementType(PseudoElementType pseudoElementType) + { + m_pseudoType = pseudoElementType; + ASSERT(m_pseudoType == pseudoElementType); + } + + PagePseudoClassType pagePseudoClassType() const + { + ASSERT(match() == PagePseudoClass); + return static_cast(m_pseudoType); + } + void setPagePseudoType(PagePseudoClassType pagePseudoType) + { + m_pseudoType = pagePseudoType; + ASSERT(m_pseudoType == pagePseudoType); + } bool matchesPseudoElement() const; bool isUnknownPseudoElement() const; bool isCustomPseudoElement() const; + bool isWebKitCustomPseudoElement() const; bool isSiblingSelector() const; bool isAttributeSelector() const; - Relation relation() const { return static_cast(m_relation); } + RelationType relation() const { return static_cast(m_relation); } + void setRelation(RelationType relation) + { + m_relation = relation; + ASSERT(m_relation == relation); + } + + Match match() const { return static_cast(m_match); } + void setMatch(Match match) + { + m_match = match; + ASSERT(m_match == match); + } bool isLastInSelectorList() const { return m_isLastInSelectorList; } void setLastInSelectorList() { m_isLastInSelectorList = true; } bool isLastInTagHistory() const { return m_isLastInTagHistory; } void setNotLastInTagHistory() { m_isLastInTagHistory = false; } - bool isSimple() const; - bool isForPage() const { return m_isForPage; } void setForPage() { m_isForPage = true; } - unsigned m_relation : 3; // enum Relation - mutable unsigned m_match : 4; // enum Match - mutable unsigned m_pseudoType : 8; // PseudoType - private: - mutable bool m_parsedNth : 1; // Used for :nth-* - bool m_isLastInSelectorList : 1; - bool m_isLastInTagHistory : 1; - bool m_hasRareData : 1; - bool m_isForPage : 1; - bool m_tagIsForNamespaceRule : 1; - - unsigned specificityForOneSelector() const; - unsigned specificityForPage() const; - void extractPseudoType() const; + unsigned m_relation : 4; // enum RelationType. + mutable unsigned m_match : 4; // enum Match. + mutable unsigned m_pseudoType : 8; // PseudoType. + mutable unsigned m_parsedNth : 1; // Used for :nth-*. + unsigned m_isLastInSelectorList : 1; + unsigned m_isLastInTagHistory : 1; + unsigned m_hasRareData : 1; + unsigned m_hasNameWithCase : 1; + unsigned m_isForPage : 1; + unsigned m_tagIsForNamespaceRule : 1; + unsigned m_caseInsensitiveAttributeValueMatching : 1; +#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + unsigned m_destructorHasBeenCalled : 1; +#endif + + unsigned simpleSelectorSpecificityForPage() const; // Hide. CSSSelector& operator=(const CSSSelector&); struct RareData : public RefCounted { - static PassRefPtr create(PassRefPtr value) { return adoptRef(new RareData(value)); } + static Ref create(AtomicString&& value) { return adoptRef(*new RareData(WTFMove(value))); } ~RareData(); bool parseNth(); bool matchNth(int count); - AtomicStringImpl* m_value; // Plain pointer to keep things uniform with the union. + // For quirks mode, class and id are case-insensitive. In the case where uppercase + // letters are used in quirks mode, |m_matchingValue| holds the lowercase class/id + // and |m_serializingValue| holds the original string. + AtomicString m_matchingValue; + AtomicString m_serializingValue; + int m_a; // Used for :nth-* int m_b; // Used for :nth-* QualifiedName m_attribute; // used for attribute selector AtomicString m_attributeCanonicalLocalName; - AtomicString m_argument; // Used for :contains, :lang and :nth-* - OwnPtr m_selectorList; // Used for :-webkit-any and :not + AtomicString m_argument; // Used for :contains and :nth-* + std::unique_ptr> m_langArgumentList; // Used for :lang arguments. + std::unique_ptr m_selectorList; // Used for :matches() and :not(). private: - RareData(PassRefPtr value); + RareData(AtomicString&& value); }; void createRareData(); + struct NameWithCase : public RefCounted { + NameWithCase(const QualifiedName& originalName, const AtomicString& lowercaseName) + : m_originalName(originalName) + , m_lowercaseLocalName(lowercaseName) + { + ASSERT(originalName.localName() != lowercaseName); + } + + const QualifiedName m_originalName; + const AtomicString m_lowercaseLocalName; + }; + union DataUnion { DataUnion() : m_value(0) { } AtomicStringImpl* m_value; QualifiedName::QualifiedNameImpl* m_tagQName; RareData* m_rareData; + NameWithCase* m_nameWithCase; } m_data; }; @@ -297,96 +411,98 @@ inline const AtomicString& CSSSelector::attributeCanonicalLocalName() const inline bool CSSSelector::matchesPseudoElement() const { - if (m_pseudoType == PseudoUnknown) - extractPseudoType(); - return m_match == PseudoElement; + return match() == PseudoElement; } inline bool CSSSelector::isUnknownPseudoElement() const { - return m_match == PseudoElement && m_pseudoType == PseudoUnknown; + return match() == PseudoElement && pseudoElementType() == PseudoElementUnknown; } inline bool CSSSelector::isCustomPseudoElement() const { - return m_match == PseudoElement && (m_pseudoType == PseudoUserAgentCustomElement || m_pseudoType == PseudoWebKitCustomElement); + return match() == PseudoElement + && (pseudoElementType() == PseudoElementUserAgentCustom + || pseudoElementType() == PseudoElementWebKitCustom + || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed); +} + +inline bool CSSSelector::isWebKitCustomPseudoElement() const +{ + return pseudoElementType() == PseudoElementWebKitCustom || pseudoElementType() == PseudoElementWebKitCustomLegacyPrefixed; +} + +static inline bool pseudoClassIsRelativeToSiblings(CSSSelector::PseudoClassType type) +{ + return type == CSSSelector::PseudoClassEmpty + || type == CSSSelector::PseudoClassFirstChild + || type == CSSSelector::PseudoClassFirstOfType + || type == CSSSelector::PseudoClassLastChild + || type == CSSSelector::PseudoClassLastOfType + || type == CSSSelector::PseudoClassOnlyChild + || type == CSSSelector::PseudoClassOnlyOfType + || type == CSSSelector::PseudoClassNthChild + || type == CSSSelector::PseudoClassNthOfType + || type == CSSSelector::PseudoClassNthLastChild + || type == CSSSelector::PseudoClassNthLastOfType; } inline bool CSSSelector::isSiblingSelector() const { - PseudoType type = pseudoType(); - return m_relation == DirectAdjacent - || m_relation == IndirectAdjacent - || type == PseudoEmpty - || type == PseudoFirstChild - || type == PseudoFirstOfType - || type == PseudoLastChild - || type == PseudoLastOfType - || type == PseudoOnlyChild - || type == PseudoOnlyOfType - || type == PseudoNthChild - || type == PseudoNthOfType - || type == PseudoNthLastChild - || type == PseudoNthLastOfType; + return relation() == DirectAdjacent + || relation() == IndirectAdjacent + || (match() == CSSSelector::PseudoClass && pseudoClassIsRelativeToSiblings(pseudoClassType())); } inline bool CSSSelector::isAttributeSelector() const { - return m_match == CSSSelector::Exact - || m_match == CSSSelector::Set - || m_match == CSSSelector::List - || m_match == CSSSelector::Hyphen - || m_match == CSSSelector::Contain - || m_match == CSSSelector::Begin - || m_match == CSSSelector::End; + return match() == CSSSelector::Exact + || match() == CSSSelector::Set + || match() == CSSSelector::List + || match() == CSSSelector::Hyphen + || match() == CSSSelector::Contain + || match() == CSSSelector::Begin + || match() == CSSSelector::End; } -inline void CSSSelector::setValue(const AtomicString& value) +inline void CSSSelector::setValue(const AtomicString& value, bool matchLowerCase) { - ASSERT(m_match != Tag); - ASSERT(m_pseudoType == PseudoNotParsed); + ASSERT(match() != Tag); + AtomicString matchingValue = matchLowerCase ? value.convertToASCIILowercase() : value; + if (!m_hasRareData && matchingValue != value) + createRareData(); + // Need to do ref counting manually for the union. - if (m_hasRareData) { - if (m_data.m_rareData->m_value) - m_data.m_rareData->m_value->deref(); - m_data.m_rareData->m_value = value.impl(); - m_data.m_rareData->m_value->ref(); + if (!m_hasRareData) { + if (m_data.m_value) + m_data.m_value->deref(); + m_data.m_value = value.impl(); + m_data.m_value->ref(); return; } - if (m_data.m_value) - m_data.m_value->deref(); - m_data.m_value = value.impl(); - m_data.m_value->ref(); + + m_data.m_rareData->m_matchingValue = WTFMove(matchingValue); + m_data.m_rareData->m_serializingValue = value; } inline CSSSelector::CSSSelector() - : m_relation(Descendant) + : m_relation(DescendantSpace) , m_match(Unknown) - , m_pseudoType(PseudoNotParsed) + , m_pseudoType(0) , m_parsedNth(false) , m_isLastInSelectorList(false) , m_isLastInTagHistory(true) , m_hasRareData(false) + , m_hasNameWithCase(false) , m_isForPage(false) , m_tagIsForNamespaceRule(false) + , m_caseInsensitiveAttributeValueMatching(false) +#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + , m_destructorHasBeenCalled(false) +#endif { } -inline CSSSelector::CSSSelector(const QualifiedName& tagQName, bool tagIsForNamespaceRule) - : m_relation(Descendant) - , m_match(Tag) - , m_pseudoType(PseudoNotParsed) - , m_parsedNth(false) - , m_isLastInSelectorList(false) - , m_isLastInTagHistory(true) - , m_hasRareData(false) - , m_isForPage(false) - , m_tagIsForNamespaceRule(tagIsForNamespaceRule) -{ - m_data.m_tagQName = tagQName.impl(); - m_data.m_tagQName->ref(); -} - inline CSSSelector::CSSSelector(const CSSSelector& o) : m_relation(o.m_relation) , m_match(o.m_match) @@ -395,15 +511,23 @@ inline CSSSelector::CSSSelector(const CSSSelector& o) , m_isLastInSelectorList(o.m_isLastInSelectorList) , m_isLastInTagHistory(o.m_isLastInTagHistory) , m_hasRareData(o.m_hasRareData) + , m_hasNameWithCase(o.m_hasNameWithCase) , m_isForPage(o.m_isForPage) , m_tagIsForNamespaceRule(o.m_tagIsForNamespaceRule) + , m_caseInsensitiveAttributeValueMatching(o.m_caseInsensitiveAttributeValueMatching) +#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + , m_destructorHasBeenCalled(false) +#endif { - if (o.m_match == Tag) { - m_data.m_tagQName = o.m_data.m_tagQName; - m_data.m_tagQName->ref(); - } else if (o.m_hasRareData) { + if (o.m_hasRareData) { m_data.m_rareData = o.m_data.m_rareData; m_data.m_rareData->ref(); + } else if (o.m_hasNameWithCase) { + m_data.m_nameWithCase = o.m_data.m_nameWithCase; + m_data.m_nameWithCase->ref(); + } if (o.match() == Tag) { + m_data.m_tagQName = o.m_data.m_tagQName; + m_data.m_tagQName->ref(); } else if (o.m_data.m_value) { m_data.m_value = o.m_data.m_value; m_data.m_value->ref(); @@ -412,29 +536,72 @@ inline CSSSelector::CSSSelector(const CSSSelector& o) inline CSSSelector::~CSSSelector() { - if (m_match == Tag) - m_data.m_tagQName->deref(); - else if (m_hasRareData) + ASSERT_WITH_SECURITY_IMPLICATION(!m_destructorHasBeenCalled); +#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + m_destructorHasBeenCalled = true; +#endif + if (m_hasRareData) { m_data.m_rareData->deref(); - else if (m_data.m_value) + m_data.m_rareData = nullptr; + m_hasRareData = false; + } else if (m_hasNameWithCase) { + m_data.m_nameWithCase->deref(); + m_data.m_nameWithCase = nullptr; + m_hasNameWithCase = false; + } else if (match() == Tag) { + m_data.m_tagQName->deref(); + m_data.m_tagQName = nullptr; + m_match = Unknown; + } else if (m_data.m_value) { m_data.m_value->deref(); + m_data.m_value = nullptr; + } } inline const QualifiedName& CSSSelector::tagQName() const { - ASSERT(m_match == Tag); + ASSERT(match() == Tag); + if (m_hasNameWithCase) + return m_data.m_nameWithCase->m_originalName; return *reinterpret_cast(&m_data.m_tagQName); } +inline const AtomicString& CSSSelector::tagLowercaseLocalName() const +{ + if (m_hasNameWithCase) + return m_data.m_nameWithCase->m_lowercaseLocalName; + return m_data.m_tagQName->m_localName; +} + inline const AtomicString& CSSSelector::value() const { - ASSERT(m_match != Tag); + ASSERT(match() != Tag); + if (m_hasRareData) + return m_data.m_rareData->m_matchingValue; + // AtomicString is really just an AtomicStringImpl* so the cast below is safe. - // FIXME: Perhaps call sites could be changed to accept AtomicStringImpl? - return *reinterpret_cast(m_hasRareData ? &m_data.m_rareData->m_value : &m_data.m_value); + return *reinterpret_cast(&m_data.m_value); } +inline const AtomicString& CSSSelector::serializingValue() const +{ + ASSERT(match() != Tag); + if (m_hasRareData) + return m_data.m_rareData->m_serializingValue; + + // AtomicString is really just an AtomicStringImpl* so the cast below is safe. + return *reinterpret_cast(&m_data.m_value); +} -} // namespace WebCore +inline void CSSSelector::setAttributeValueMatchingIsCaseInsensitive(bool isCaseInsensitive) +{ + ASSERT(isAttributeSelector() && match() != CSSSelector::Set); + m_caseInsensitiveAttributeValueMatching = isCaseInsensitive; +} + +inline bool CSSSelector::attributeValueMatchingIsCaseInsensitive() const +{ + return m_caseInsensitiveAttributeValueMatching; +} -#endif // CSSSelector_h +} // namespace WebCore diff --git a/Source/WebCore/css/CSSSelectorList.cpp b/Source/WebCore/css/CSSSelectorList.cpp index 661a4f2d2..fd7e13410 100644 --- a/Source/WebCore/css/CSSSelectorList.cpp +++ b/Source/WebCore/css/CSSSelectorList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,16 +27,11 @@ #include "config.h" #include "CSSSelectorList.h" -#include "CSSParserValues.h" +#include "CSSParserSelector.h" #include namespace WebCore { -CSSSelectorList::~CSSSelectorList() -{ - deleteSelectors(); -} - CSSSelectorList::CSSSelectorList(const CSSSelectorList& other) { unsigned otherComponentCount = other.componentCount(); @@ -47,16 +42,13 @@ CSSSelectorList::CSSSelectorList(const CSSSelectorList& other) new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]); } -void CSSSelectorList::adopt(CSSSelectorList& list) +CSSSelectorList::CSSSelectorList(CSSSelectorList&& other) + : m_selectorArray(other.m_selectorArray) { - deleteSelectors(); - m_selectorArray = list.m_selectorArray; - list.m_selectorArray = 0; - - ASSERT_WITH_SECURITY_IMPLICATION(componentCount()); + other.m_selectorArray = nullptr; } -void CSSSelectorList::adoptSelectorVector(Vector>& selectorVector) +void CSSSelectorList::adoptSelectorVector(Vector>& selectorVector) { ASSERT_WITH_SECURITY_IMPLICATION(!selectorVector.isEmpty()); @@ -74,7 +66,7 @@ void CSSSelectorList::adoptSelectorVector(Vector>& sel while (current) { { // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.) - CSSSelector* currentSelector = current->releaseSelector().leakPtr(); + CSSSelector* currentSelector = current->releaseSelector().release(); memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector)); // Free the underlying memory without invoking the destructor. @@ -103,30 +95,46 @@ unsigned CSSSelectorList::componentCount() const return (current - m_selectorArray) + 1; } +CSSSelectorList& CSSSelectorList::operator=(CSSSelectorList&& other) +{ + deleteSelectors(); + m_selectorArray = other.m_selectorArray; + other.m_selectorArray = nullptr; + + return *this; +} + void CSSSelectorList::deleteSelectors() { if (!m_selectorArray) return; - for (CSSSelector* s = m_selectorArray; ; ++s) { + CSSSelector* selectorArray = m_selectorArray; + m_selectorArray = nullptr; + + bool isLastSelector = false; + for (CSSSelector* s = selectorArray; !isLastSelector; ++s) { + isLastSelector = s->isLastInSelectorList(); s->~CSSSelector(); - if (s->isLastInSelectorList()) - break; } - fastFree(m_selectorArray); + fastFree(selectorArray); } String CSSSelectorList::selectorsText() const { StringBuilder result; + buildSelectorsText(result); + return result.toString(); +} - for (const CSSSelector* s = first(); s; s = next(s)) { - if (s != first()) - result.append(", "); - result.append(s->selectorText()); +void CSSSelectorList::buildSelectorsText(StringBuilder& stringBuilder) const +{ + const CSSSelector* firstSubselector = first(); + for (const CSSSelector* subSelector = firstSubselector; subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (subSelector != firstSubselector) + stringBuilder.appendLiteral(", "); + stringBuilder.append(subSelector->selectorText()); } - - return result.toString(); } template @@ -163,9 +171,9 @@ class SelectorNeedsNamespaceResolutionFunctor { public: bool operator()(const CSSSelector* selector) { - if (selector->m_match == CSSSelector::Tag && selector->tagQName().prefix() != nullAtom && selector->tagQName().prefix() != starAtom) + if (selector->match() == CSSSelector::Tag && !selector->tagQName().prefix().isEmpty() && selector->tagQName().prefix() != starAtom) return true; - if (selector->isAttributeSelector() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) + if (selector->isAttributeSelector() && !selector->attribute().prefix().isEmpty() && selector->attribute().prefix() != starAtom) return true; return false; } diff --git a/Source/WebCore/css/CSSSelectorList.h b/Source/WebCore/css/CSSSelectorList.h index 0173401df..8a88b9666 100644 --- a/Source/WebCore/css/CSSSelectorList.h +++ b/Source/WebCore/css/CSSSelectorList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,10 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSSelectorList_h -#define CSSSelectorList_h +#pragma once #include "CSSSelector.h" +#include namespace WebCore { @@ -37,11 +37,11 @@ class CSSSelectorList { public: CSSSelectorList() : m_selectorArray(0) { } CSSSelectorList(const CSSSelectorList&); + CSSSelectorList(CSSSelectorList&&); - ~CSSSelectorList(); + ~CSSSelectorList() { deleteSelectors(); } - void adopt(CSSSelectorList& list); - void adoptSelectorVector(Vector>& selectorVector); + void adoptSelectorVector(Vector>& selectorVector); void adoptSelectorArray(CSSSelector* selectors) { ASSERT(!m_selectorArray); m_selectorArray = selectors; } bool isValid() const { return !!m_selectorArray; } @@ -63,9 +63,12 @@ public: bool hasInvalidSelector() const; String selectorsText() const; + void buildSelectorsText(StringBuilder&) const; unsigned componentCount() const; + CSSSelectorList& operator=(CSSSelectorList&&); + private: void deleteSelectors(); @@ -83,5 +86,3 @@ inline const CSSSelector* CSSSelectorList::next(const CSSSelector* current) } } // namespace WebCore - -#endif // CSSSelectorList_h diff --git a/Source/WebCore/css/CSSShadowValue.cpp b/Source/WebCore/css/CSSShadowValue.cpp index 77d224721..94947d7b9 100644 --- a/Source/WebCore/css/CSSShadowValue.cpp +++ b/Source/WebCore/css/CSSShadowValue.cpp @@ -1,6 +1,6 @@ /** * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2009 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,19 +26,14 @@ namespace WebCore { // Used for text-shadow and box-shadow -CSSShadowValue::CSSShadowValue(PassRefPtr x, - PassRefPtr y, - PassRefPtr blur, - PassRefPtr spread, - PassRefPtr style, - PassRefPtr color) +CSSShadowValue::CSSShadowValue(RefPtr&& x, RefPtr&& y, RefPtr&& blur, RefPtr&& spread, RefPtr&& style, RefPtr&& color) : CSSValue(ShadowClass) - , x(x) - , y(y) - , blur(blur) - , spread(spread) - , style(style) - , color(color) + , x(WTFMove(x)) + , y(WTFMove(y)) + , blur(WTFMove(blur)) + , spread(WTFMove(spread)) + , style(WTFMove(style)) + , color(WTFMove(color)) { } diff --git a/Source/WebCore/css/CSSShadowValue.h b/Source/WebCore/css/CSSShadowValue.h index 6175df826..26857028c 100644 --- a/Source/WebCore/css/CSSShadowValue.h +++ b/Source/WebCore/css/CSSShadowValue.h @@ -18,11 +18,9 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSShadowValue_h -#define CSSShadowValue_h +#pragma once #include "CSSValue.h" -#include #include namespace WebCore { @@ -30,16 +28,16 @@ namespace WebCore { class CSSPrimitiveValue; // Used for text-shadow and box-shadow -class CSSShadowValue : public CSSValue { +class CSSShadowValue final : public CSSValue { public: - static PassRef create(PassRefPtr x, - PassRefPtr y, - PassRefPtr blur, - PassRefPtr spread, - PassRefPtr style, - PassRefPtr color) + static Ref create(RefPtr&& x, + RefPtr&& y, + RefPtr&& blur, + RefPtr&& spread, + RefPtr&& style, + RefPtr&& color) { - return adoptRef(*new CSSShadowValue(x, y, blur, spread, style, color)); + return adoptRef(*new CSSShadowValue(WTFMove(x), WTFMove(y), WTFMove(blur), WTFMove(spread), WTFMove(style), WTFMove(color))); } String customCSSText() const; @@ -54,16 +52,14 @@ public: RefPtr color; private: - CSSShadowValue(PassRefPtr x, - PassRefPtr y, - PassRefPtr blur, - PassRefPtr spread, - PassRefPtr style, - PassRefPtr color); + CSSShadowValue(RefPtr&& x, + RefPtr&& y, + RefPtr&& blur, + RefPtr&& spread, + RefPtr&& style, + RefPtr&& color); }; -CSS_VALUE_TYPE_CASTS(CSSShadowValue, isShadowValue()) +} // namespace WebCore -} // namespace - -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSShadowValue, isShadowValue()) diff --git a/Source/WebCore/css/CSSStyleDeclaration.h b/Source/WebCore/css/CSSStyleDeclaration.h index ad3d8d584..e4e303859 100644 --- a/Source/WebCore/css/CSSStyleDeclaration.h +++ b/Source/WebCore/css/CSSStyleDeclaration.h @@ -18,10 +18,11 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSStyleDeclaration_h -#define CSSStyleDeclaration_h +#pragma once #include "CSSPropertyNames.h" +#include "DeprecatedCSSOMValue.h" +#include "ExceptionOr.h" #include "ScriptWrappable.h" #include @@ -35,8 +36,6 @@ class MutableStyleProperties; class StyleProperties; class StyledElement; -typedef int ExceptionCode; - class CSSStyleDeclaration : public ScriptWrappable { WTF_MAKE_NONCOPYABLE(CSSStyleDeclaration); WTF_MAKE_FAST_ALLOCATED; public: @@ -45,34 +44,33 @@ public: virtual void ref() = 0; virtual void deref() = 0; + virtual StyledElement* parentElement() const { return nullptr; } virtual CSSRule* parentRule() const = 0; virtual String cssText() const = 0; - virtual void setCssText(const String&, ExceptionCode&) = 0; + virtual ExceptionOr setCssText(const String&) = 0; virtual unsigned length() const = 0; virtual String item(unsigned index) const = 0; - virtual PassRefPtr getPropertyCSSValue(const String& propertyName) = 0; + virtual RefPtr getPropertyCSSValue(const String& propertyName) = 0; virtual String getPropertyValue(const String& propertyName) = 0; virtual String getPropertyPriority(const String& propertyName) = 0; virtual String getPropertyShorthand(const String& propertyName) = 0; virtual bool isPropertyImplicit(const String& propertyName) = 0; - virtual void setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode&) = 0; - virtual String removeProperty(const String& propertyName, ExceptionCode&) = 0; + virtual ExceptionOr setProperty(const String& propertyName, const String& value, const String& priority) = 0; + virtual ExceptionOr removeProperty(const String& propertyName) = 0; // CSSPropertyID versions of the CSSOM functions to support bindings and editing. // Use the non-virtual methods in the concrete subclasses when possible. // The CSSValue returned by this function should not be exposed to the web as it may be used by multiple documents at the same time. - virtual PassRefPtr getPropertyCSSValueInternal(CSSPropertyID) = 0; + virtual RefPtr getPropertyCSSValueInternal(CSSPropertyID) = 0; virtual String getPropertyValueInternal(CSSPropertyID) = 0; - virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) = 0; + virtual ExceptionOr setPropertyInternal(CSSPropertyID, const String& value, bool important) = 0; - virtual PassRef copyProperties() const = 0; + virtual Ref copyProperties() const = 0; - virtual CSSStyleSheet* parentStyleSheet() const { return 0; } + virtual CSSStyleSheet* parentStyleSheet() const { return nullptr; } protected: CSSStyleDeclaration() { } }; } // namespace WebCore - -#endif // CSSStyleDeclaration_h diff --git a/Source/WebCore/css/CSSStyleDeclaration.idl b/Source/WebCore/css/CSSStyleDeclaration.idl index a9bdc54fc..54cb55eda 100644 --- a/Source/WebCore/css/CSSStyleDeclaration.idl +++ b/Source/WebCore/css/CSSStyleDeclaration.idl @@ -18,32 +18,33 @@ * Boston, MA 02110-1301, USA. */ -// Introduced in DOM Level 2: [ - JSCustomHeader, - JSCustomMarkFunction, + CustomEnumerateProperty, + CustomNamedSetter, + ExportMacro=WEBCORE_EXPORT, GenerateIsReachable, JSCustomGetOwnPropertySlotAndDescriptor, - CustomNamedSetter, - CustomEnumerateProperty, + JSCustomHeader, + JSCustomMarkFunction, SkipVTableValidation, ] interface CSSStyleDeclaration { - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString cssText; + [CEReactions, SetterMayThrowException] attribute DOMString cssText; - [TreatReturnedNullStringAs=Null] DOMString getPropertyValue([Default=Undefined] optional DOMString propertyName); - [Custom] CSSValue getPropertyCSSValue([Default=Undefined] optional DOMString propertyName); - [TreatReturnedNullStringAs=Null, RaisesException] DOMString removeProperty([Default=Undefined] optional DOMString propertyName); - [TreatReturnedNullStringAs=Null] DOMString getPropertyPriority([Default=Undefined] optional DOMString propertyName); - [ObjCLegacyUnnamedParameters, RaisesException] void setProperty([Default=Undefined] optional DOMString propertyName, - [TreatNullAs=NullString, Default=Undefined] optional DOMString value, - [Default=Undefined] optional DOMString priority); + DOMString getPropertyValue(DOMString propertyName); - readonly attribute unsigned long length; - getter DOMString item([Default=Undefined] optional unsigned long index); - readonly attribute CSSRule parentRule; + // This method is deprecated, and we would like to drop support for it someday + [Custom] DeprecatedCSSOMValue? getPropertyCSSValue(DOMString propertyName); - // Extensions - [TreatReturnedNullStringAs=Null] DOMString getPropertyShorthand([Default=Undefined] optional DOMString propertyName); - boolean isPropertyImplicit([Default=Undefined] optional DOMString propertyName); -}; + [CEReactions, MayThrowException] DOMString removeProperty(DOMString propertyName); + DOMString? getPropertyPriority(DOMString propertyName); + [CEReactions, MayThrowException] void setProperty(DOMString propertyName, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = ""); + + readonly attribute unsigned long length; + getter DOMString item(unsigned long index); + readonly attribute CSSRule? parentRule; + + // FIXME: Using "undefined" as default parameter value is wrong. + DOMString? getPropertyShorthand(optional DOMString propertyName = "undefined"); + boolean isPropertyImplicit(optional DOMString propertyName = "undefined"); +}; diff --git a/Source/WebCore/css/CSSStyleRule.cpp b/Source/WebCore/css/CSSStyleRule.cpp index 23fc473c0..e0e30d00f 100644 --- a/Source/WebCore/css/CSSStyleRule.cpp +++ b/Source/WebCore/css/CSSStyleRule.cpp @@ -30,6 +30,7 @@ #include "RuleSet.h" #include "StyleProperties.h" #include "StyleRule.h" +#include #include namespace WebCore { @@ -37,11 +38,11 @@ namespace WebCore { typedef HashMap SelectorTextCache; static SelectorTextCache& selectorTextCache() { - DEFINE_STATIC_LOCAL(SelectorTextCache, cache, ()); + static NeverDestroyed cache; return cache; } -CSSStyleRule::CSSStyleRule(StyleRule* styleRule, CSSStyleSheet* parent) +CSSStyleRule::CSSStyleRule(StyleRule& styleRule, CSSStyleSheet* parent) : CSSRule(parent) , m_styleRule(styleRule) { @@ -58,23 +59,16 @@ CSSStyleRule::~CSSStyleRule() } } -CSSStyleDeclaration* CSSStyleRule::style() +CSSStyleDeclaration& CSSStyleRule::style() { - if (!m_propertiesCSSOMWrapper) { + if (!m_propertiesCSSOMWrapper) m_propertiesCSSOMWrapper = StyleRuleCSSStyleDeclaration::create(m_styleRule->mutableProperties(), *this); - } - return m_propertiesCSSOMWrapper.get(); + return *m_propertiesCSSOMWrapper; } String CSSStyleRule::generateSelectorText() const { - StringBuilder builder; - for (const CSSSelector* selector = m_styleRule->selectorList().first(); selector; selector = CSSSelectorList::next(selector)) { - if (selector != m_styleRule->selectorList().first()) - builder.appendLiteral(", "); - builder.append(selector->selectorText()); - } - return builder.toString(); + return m_styleRule->selectorList().selectorsText(); } String CSSStyleRule::selectorText() const @@ -131,11 +125,9 @@ String CSSStyleRule::cssText() const return result.toString(); } -void CSSStyleRule::reattach(StyleRuleBase* rule) +void CSSStyleRule::reattach(StyleRuleBase& rule) { - ASSERT(rule); - ASSERT_WITH_SECURITY_IMPLICATION(rule->isStyleRule()); - m_styleRule = static_cast(rule); + m_styleRule = downcast(rule); if (m_propertiesCSSOMWrapper) m_propertiesCSSOMWrapper->reattach(m_styleRule->mutableProperties()); } diff --git a/Source/WebCore/css/CSSStyleRule.h b/Source/WebCore/css/CSSStyleRule.h index ffd103077..71f355055 100644 --- a/Source/WebCore/css/CSSStyleRule.h +++ b/Source/WebCore/css/CSSStyleRule.h @@ -19,8 +19,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSStyleRule_h -#define CSSStyleRule_h +#pragma once #include "CSSRule.h" @@ -30,33 +29,33 @@ class CSSStyleDeclaration; class StyleRuleCSSStyleDeclaration; class StyleRule; -class CSSStyleRule : public CSSRule { +class CSSStyleRule final : public CSSRule { public: - static PassRefPtr create(StyleRule* rule, CSSStyleSheet* sheet) { return adoptRef(new CSSStyleRule(rule, sheet)); } + static Ref create(StyleRule& rule, CSSStyleSheet* sheet) { return adoptRef(*new CSSStyleRule(rule, sheet)); } virtual ~CSSStyleRule(); - virtual CSSRule::Type type() const { return STYLE_RULE; } - virtual String cssText() const override; - virtual void reattach(StyleRuleBase*) override; + WEBCORE_EXPORT String selectorText() const; + WEBCORE_EXPORT void setSelectorText(const String&); - String selectorText() const; - void setSelectorText(const String&); - - CSSStyleDeclaration* style(); + WEBCORE_EXPORT CSSStyleDeclaration& style(); // FIXME: Not CSSOM. Remove. - StyleRule* styleRule() const { return m_styleRule.get(); } + StyleRule& styleRule() const { return m_styleRule.get(); } private: - CSSStyleRule(StyleRule*, CSSStyleSheet*); + CSSStyleRule(StyleRule&, CSSStyleSheet*); + + CSSRule::Type type() const final { return STYLE_RULE; } + String cssText() const final; + void reattach(StyleRuleBase&) final; String generateSelectorText() const; - RefPtr m_styleRule; - mutable RefPtr m_propertiesCSSOMWrapper; + Ref m_styleRule; + RefPtr m_propertiesCSSOMWrapper; }; } // namespace WebCore -#endif // CSSStyleRule_h +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSStyleRule, CSSRule::STYLE_RULE) diff --git a/Source/WebCore/css/CSSStyleRule.idl b/Source/WebCore/css/CSSStyleRule.idl index 23cd73af4..125ddbc59 100644 --- a/Source/WebCore/css/CSSStyleRule.idl +++ b/Source/WebCore/css/CSSStyleRule.idl @@ -20,10 +20,8 @@ // Introduced in DOM Level 2: interface CSSStyleRule : CSSRule { - - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString] attribute DOMString selectorText; + attribute DOMString? selectorText; readonly attribute CSSStyleDeclaration style; - }; diff --git a/Source/WebCore/css/CSSStyleSheet.cpp b/Source/WebCore/css/CSSStyleSheet.cpp index d8229a44a..462b2f43b 100644 --- a/Source/WebCore/css/CSSStyleSheet.cpp +++ b/Source/WebCore/css/CSSStyleSheet.cpp @@ -21,42 +21,43 @@ #include "config.h" #include "CSSStyleSheet.h" -#include "CSSCharsetRule.h" #include "CSSFontFaceRule.h" #include "CSSImportRule.h" +#include "CSSKeyframesRule.h" #include "CSSParser.h" #include "CSSRuleList.h" #include "CSSStyleRule.h" #include "CachedCSSStyleSheet.h" #include "Document.h" -#include "DocumentStyleSheetCollection.h" #include "ExceptionCode.h" -#include "HTMLNames.h" +#include "ExtensionStyleSheets.h" +#include "HTMLLinkElement.h" #include "HTMLStyleElement.h" #include "MediaList.h" #include "Node.h" -#include "SVGNames.h" +#include "SVGStyleElement.h" #include "SecurityOrigin.h" +#include "ShadowRoot.h" #include "StyleResolver.h" #include "StyleRule.h" +#include "StyleScope.h" #include "StyleSheetContents.h" -#include "WebKitCSSKeyframesRule.h" #include namespace WebCore { -class StyleSheetCSSRuleList : public CSSRuleList { +class StyleSheetCSSRuleList final : public CSSRuleList { public: StyleSheetCSSRuleList(CSSStyleSheet* sheet) : m_styleSheet(sheet) { } private: - virtual void ref() { m_styleSheet->ref(); } - virtual void deref() { m_styleSheet->deref(); } - - virtual unsigned length() const { return m_styleSheet->length(); } - virtual CSSRule* item(unsigned index) const { return m_styleSheet->item(index); } - - virtual CSSStyleSheet* styleSheet() const { return m_styleSheet; } + void ref() final { m_styleSheet->ref(); } + void deref() final { m_styleSheet->deref(); } + + unsigned length() const final { return m_styleSheet->length(); } + CSSRule* item(unsigned index) const final { return m_styleSheet->item(index); } + + CSSStyleSheet* styleSheet() const final { return m_styleSheet; } CSSStyleSheet* m_styleSheet; }; @@ -67,49 +68,51 @@ static bool isAcceptableCSSStyleSheetParent(Node* parentNode) // Only these nodes can be parents of StyleSheets, and they need to call clearOwnerNode() when moved out of document. return !parentNode || parentNode->isDocumentNode() - || parentNode->hasTagName(HTMLNames::linkTag) - || isHTMLStyleElement(parentNode) -#if ENABLE(SVG) - || parentNode->hasTagName(SVGNames::styleTag) -#endif + || is(*parentNode) + || is(*parentNode) + || is(*parentNode) || parentNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE; } #endif -PassRef CSSStyleSheet::create(PassRef sheet, CSSImportRule* ownerRule) -{ - return adoptRef(*new CSSStyleSheet(std::move(sheet), ownerRule)); +Ref CSSStyleSheet::create(Ref&& sheet, CSSImportRule* ownerRule) +{ + return adoptRef(*new CSSStyleSheet(WTFMove(sheet), ownerRule)); } -PassRef CSSStyleSheet::create(PassRef sheet, Node* ownerNode) -{ - return adoptRef(*new CSSStyleSheet(std::move(sheet), ownerNode, false)); +Ref CSSStyleSheet::create(Ref&& sheet, Node& ownerNode, const std::optional& isCleanOrigin) +{ + return adoptRef(*new CSSStyleSheet(WTFMove(sheet), ownerNode, TextPosition(), false, isCleanOrigin)); } -PassRef CSSStyleSheet::createInline(Node& ownerNode, const URL& baseURL, const String& encoding) +Ref CSSStyleSheet::createInline(Ref&& sheet, Element& owner, const TextPosition& startPosition) { - CSSParserContext parserContext(ownerNode.document(), baseURL, encoding); - return adoptRef(*new CSSStyleSheet(StyleSheetContents::create(baseURL.string(), parserContext), &ownerNode, true)); + return adoptRef(*new CSSStyleSheet(WTFMove(sheet), owner, startPosition, true, true)); } -CSSStyleSheet::CSSStyleSheet(PassRef contents, CSSImportRule* ownerRule) - : m_contents(std::move(contents)) +CSSStyleSheet::CSSStyleSheet(Ref&& contents, CSSImportRule* ownerRule) + : m_contents(WTFMove(contents)) , m_isInlineStylesheet(false) , m_isDisabled(false) + , m_mutatedRules(false) , m_ownerNode(0) , m_ownerRule(ownerRule) + , m_startPosition() { m_contents->registerClient(this); } -CSSStyleSheet::CSSStyleSheet(PassRef contents, Node* ownerNode, bool isInlineStylesheet) - : m_contents(std::move(contents)) +CSSStyleSheet::CSSStyleSheet(Ref&& contents, Node& ownerNode, const TextPosition& startPosition, bool isInlineStylesheet, const std::optional& isOriginClean) + : m_contents(WTFMove(contents)) , m_isInlineStylesheet(isInlineStylesheet) , m_isDisabled(false) - , m_ownerNode(ownerNode) + , m_mutatedRules(false) + , m_isOriginClean(isOriginClean) + , m_ownerNode(&ownerNode) , m_ownerRule(0) + , m_startPosition(startPosition) { - ASSERT(isAcceptableCSSStyleSheetParent(ownerNode)); + ASSERT(isAcceptableCSSStyleSheetParent(&ownerNode)); m_contents->registerClient(this); } @@ -163,38 +166,36 @@ void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContent ASSERT(m_contents->isMutable()); ASSERT(m_contents->hasOneClient()); - Document* owner = ownerDocument(); - if (!owner) + auto* scope = styleScope(); + if (!scope) return; - if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !owner->styleSheetCollection().activeStyleSheetsContains(this)) { + if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !scope->activeStyleSheetsContains(this)) { if (insertedKeyframesRule) { - if (StyleResolver* resolver = owner->styleResolverIfExists()) - resolver->addKeyframeStyle(insertedKeyframesRule); + if (auto* resolver = scope->resolverIfExists()) + resolver->addKeyframeStyle(*insertedKeyframesRule); return; } - owner->scheduleOptimizedStyleSheetUpdate(); + scope->didChangeActiveStyleSheetCandidates(); return; } - owner->styleResolverChanged(DeferRecalcStyle); + scope->didChangeStyleSheetContents(); + + m_mutatedRules = true; } void CSSStyleSheet::didMutate() { - Document* owner = ownerDocument(); - if (!owner) + auto* scope = styleScope(); + if (!scope) return; - owner->styleResolverChanged(DeferRecalcStyle); + scope->didChangeStyleSheetContents(); } void CSSStyleSheet::clearOwnerNode() { - Document* owner = ownerDocument(); - m_ownerNode = 0; - if (!owner) - return; - owner->styleResolverChanged(DeferRecalcStyleIfNeeded); + m_ownerNode = nullptr; } void CSSStyleSheet::reattachChildRuleCSSOMWrappers() @@ -202,7 +203,7 @@ void CSSStyleSheet::reattachChildRuleCSSOMWrappers() for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) { if (!m_childRuleCSSOMWrappers[i]) continue; - m_childRuleCSSOMWrappers[i]->reattach(m_contents->ruleAt(i)); + m_childRuleCSSOMWrappers[i]->reattach(*m_contents->ruleAt(i)); } } @@ -212,19 +213,16 @@ void CSSStyleSheet::setDisabled(bool disabled) return; m_isDisabled = disabled; - didMutate(); + if (auto* scope = styleScope()) + scope->didChangeActiveStyleSheetCandidates(); } -void CSSStyleSheet::setMediaQueries(PassRefPtr mediaQueries) +void CSSStyleSheet::setMediaQueries(Ref&& mediaQueries) { - m_mediaQueries = mediaQueries; + m_mediaQueries = WTFMove(mediaQueries); if (m_mediaCSSOMWrapper && m_mediaQueries) m_mediaCSSOMWrapper->reattach(m_mediaQueries.get()); - -#if ENABLE(RESOLUTION_MEDIA_QUERY) - // Add warning message to inspector whenever dpi/dpcm values are used for "screen" media. reportMediaQueryWarningIfNeeded(ownerDocument(), m_mediaQueries.get()); -#endif } unsigned CSSStyleSheet::length() const @@ -243,98 +241,87 @@ CSSRule* CSSStyleSheet::item(unsigned index) ASSERT(m_childRuleCSSOMWrappers.size() == ruleCount); RefPtr& cssRule = m_childRuleCSSOMWrappers[index]; - if (!cssRule) { - if (index == 0 && m_contents->hasCharsetRule()) { - ASSERT(!m_contents->ruleAt(0)); - cssRule = CSSCharsetRule::create(this, m_contents->encodingFromCharsetRule()); - } else - cssRule = m_contents->ruleAt(index)->createCSSOMWrapper(this); - } + if (!cssRule) + cssRule = m_contents->ruleAt(index)->createCSSOMWrapper(this); return cssRule.get(); } bool CSSStyleSheet::canAccessRules() const { - if (m_isInlineStylesheet) - return true; + if (m_isOriginClean) + return m_isOriginClean.value(); + URL baseURL = m_contents->baseURL(); if (baseURL.isEmpty()) return true; Document* document = ownerDocument(); if (!document) return true; - if (document->securityOrigin()->canRequest(baseURL)) - return true; - return false; + return document->securityOrigin().canRequest(baseURL); } -PassRefPtr CSSStyleSheet::rules() +RefPtr CSSStyleSheet::rules() { if (!canAccessRules()) - return 0; + return nullptr; // IE behavior. - RefPtr nonCharsetRules = StaticCSSRuleList::create(); + RefPtr ruleList = StaticCSSRuleList::create(); unsigned ruleCount = length(); - for (unsigned i = 0; i < ruleCount; ++i) { - CSSRule* rule = item(i); - if (rule->type() == CSSRule::CHARSET_RULE) - continue; - nonCharsetRules->rules().append(rule); - } - return nonCharsetRules.release(); + for (unsigned i = 0; i < ruleCount; ++i) + ruleList->rules().append(item(i)); + return ruleList; +} + +ExceptionOr CSSStyleSheet::deprecatedInsertRule(const String& ruleString) +{ + if (auto* document = ownerDocument()) + document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Calling CSSStyleSheet.insertRule() with one argument is deprecated. Please pass the index argument as well: insertRule(x, 0).")); + + return insertRule(ruleString, 0); } -unsigned CSSStyleSheet::insertRule(const String& ruleString, unsigned index, ExceptionCode& ec) +ExceptionOr CSSStyleSheet::insertRule(const String& ruleString, unsigned index) { ASSERT(m_childRuleCSSOMWrappers.isEmpty() || m_childRuleCSSOMWrappers.size() == m_contents->ruleCount()); - ec = 0; - if (index > length()) { - ec = INDEX_SIZE_ERR; - return 0; - } - CSSParser p(m_contents.get().parserContext()); - RefPtr rule = p.parseRule(&m_contents.get(), ruleString); + if (index > length()) + return Exception { INDEX_SIZE_ERR }; + RefPtr rule = CSSParser::parseRule(m_contents.get().parserContext(), m_contents.ptr(), ruleString); - if (!rule) { - ec = SYNTAX_ERR; - return 0; - } + if (!rule) + return Exception { SYNTAX_ERR }; - RuleMutationScope mutationScope(this, RuleInsertion, rule->type() == StyleRuleBase::Keyframes ? static_cast(rule.get()) : 0); + RuleMutationScope mutationScope(this, RuleInsertion, is(*rule) ? downcast(rule.get()) : nullptr); - bool success = m_contents.get().wrapperInsertRule(rule, index); - if (!success) { - ec = HIERARCHY_REQUEST_ERR; - return 0; - } + bool success = m_contents.get().wrapperInsertRule(rule.releaseNonNull(), index); + if (!success) + return Exception { HIERARCHY_REQUEST_ERR }; if (!m_childRuleCSSOMWrappers.isEmpty()) m_childRuleCSSOMWrappers.insert(index, RefPtr()); return index; } -void CSSStyleSheet::deleteRule(unsigned index, ExceptionCode& ec) +ExceptionOr CSSStyleSheet::deleteRule(unsigned index) { ASSERT(m_childRuleCSSOMWrappers.isEmpty() || m_childRuleCSSOMWrappers.size() == m_contents->ruleCount()); - ec = 0; - if (index >= length()) { - ec = INDEX_SIZE_ERR; - return; - } + if (index >= length()) + return Exception { INDEX_SIZE_ERR }; RuleMutationScope mutationScope(this); m_contents->wrapperDeleteRule(index); if (!m_childRuleCSSOMWrappers.isEmpty()) { if (m_childRuleCSSOMWrappers[index]) - m_childRuleCSSOMWrappers[index]->setParentStyleSheet(0); + m_childRuleCSSOMWrappers[index]->setParentStyleSheet(nullptr); m_childRuleCSSOMWrappers.remove(index); } + + return { }; } -int CSSStyleSheet::addRule(const String& selector, const String& style, int index, ExceptionCode& ec) +ExceptionOr CSSStyleSheet::addRule(const String& selector, const String& style, std::optional index) { StringBuilder text; text.append(selector); @@ -343,22 +330,18 @@ int CSSStyleSheet::addRule(const String& selector, const String& style, int inde if (!style.isEmpty()) text.append(' '); text.append('}'); - insertRule(text.toString(), index, ec); + auto insertRuleResult = insertRule(text.toString(), index.value_or(length())); + if (insertRuleResult.hasException()) + return insertRuleResult.releaseException(); // As per Microsoft documentation, always return -1. return -1; } -int CSSStyleSheet::addRule(const String& selector, const String& style, ExceptionCode& ec) -{ - return addRule(selector, style, length(), ec); -} - - -PassRefPtr CSSStyleSheet::cssRules() +RefPtr CSSStyleSheet::cssRules() { if (!canAccessRules()) - return 0; + return nullptr; if (!m_ruleListCSSOMWrapper) m_ruleListCSSOMWrapper = std::make_unique(this); return m_ruleListCSSOMWrapper.get(); @@ -380,9 +363,9 @@ bool CSSStyleSheet::isLoading() const } MediaList* CSSStyleSheet::media() const -{ +{ if (!m_mediaQueries) - return 0; + return nullptr; if (!m_mediaCSSOMWrapper) m_mediaCSSOMWrapper = MediaList::create(m_mediaQueries.get(), const_cast(this)); @@ -391,15 +374,34 @@ MediaList* CSSStyleSheet::media() const CSSStyleSheet* CSSStyleSheet::parentStyleSheet() const { - return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0; + return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr; } -Document* CSSStyleSheet::ownerDocument() const +CSSStyleSheet& CSSStyleSheet::rootStyleSheet() { - const CSSStyleSheet* root = this; + auto* root = this; while (root->parentStyleSheet()) root = root->parentStyleSheet(); - return root->ownerNode() ? &root->ownerNode()->document() : 0; + return *root; +} + +const CSSStyleSheet& CSSStyleSheet::rootStyleSheet() const +{ + return const_cast(*this).rootStyleSheet(); +} + +Document* CSSStyleSheet::ownerDocument() const +{ + auto& root = rootStyleSheet(); + return root.ownerNode() ? &root.ownerNode()->document() : nullptr; +} + +Style::Scope* CSSStyleSheet::styleScope() +{ + auto* ownerNode = rootStyleSheet().ownerNode(); + if (!ownerNode) + return nullptr; + return &Style::Scope::forNode(*ownerNode); } void CSSStyleSheet::clearChildRuleCSSOMWrappers() @@ -417,7 +419,7 @@ CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMu } CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule) - : m_styleSheet(rule ? rule->parentStyleSheet() : 0) + : m_styleSheet(rule ? rule->parentStyleSheet() : nullptr) , m_mutationType(OtherMutation) , m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation) , m_insertedKeyframesRule(nullptr) diff --git a/Source/WebCore/css/CSSStyleSheet.h b/Source/WebCore/css/CSSStyleSheet.h index dca3e13ac..e8b711415 100644 --- a/Source/WebCore/css/CSSStyleSheet.h +++ b/Source/WebCore/css/CSSStyleSheet.h @@ -18,20 +18,20 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSStyleSheet_h -#define CSSStyleSheet_h +#pragma once #include "CSSParserMode.h" -#include "CSSRule.h" +#include "ExceptionOr.h" #include "StyleSheet.h" #include #include #include +#include #include +#include namespace WebCore { -class CSSCharsetRule; class CSSImportRule; class CSSParser; class CSSRule; @@ -39,54 +39,63 @@ class CSSRuleList; class CSSStyleSheet; class CachedCSSStyleSheet; class Document; +class Element; class MediaQuerySet; -class SecurityOrigin; class StyleRuleKeyframes; class StyleSheetContents; -typedef int ExceptionCode; +namespace Style { +class Scope; +} class CSSStyleSheet final : public StyleSheet { public: - static PassRef create(PassRef, CSSImportRule* ownerRule = 0); - static PassRef create(PassRef, Node* ownerNode); - static PassRef createInline(Node&, const URL&, const String& encoding = String()); + static Ref create(Ref&&, CSSImportRule* ownerRule = 0); + static Ref create(Ref&&, Node& ownerNode, const std::optional& isOriginClean = std::nullopt); + static Ref createInline(Ref&&, Element& owner, const TextPosition& startPosition); virtual ~CSSStyleSheet(); - virtual CSSStyleSheet* parentStyleSheet() const override; - virtual Node* ownerNode() const override { return m_ownerNode; } - virtual MediaList* media() const override; - virtual String href() const override; - virtual String title() const override { return m_title; } - virtual bool disabled() const override { return m_isDisabled; } - virtual void setDisabled(bool) override; + CSSStyleSheet* parentStyleSheet() const final; + Node* ownerNode() const final { return m_ownerNode; } + MediaList* media() const final; + String href() const final; + String title() const final { return m_title; } + bool disabled() const final { return m_isDisabled; } + void setDisabled(bool) final; - PassRefPtr cssRules(); - unsigned insertRule(const String& rule, unsigned index, ExceptionCode&); - void deleteRule(unsigned index, ExceptionCode&); + WEBCORE_EXPORT RefPtr cssRules(); + WEBCORE_EXPORT ExceptionOr insertRule(const String& rule, unsigned index); + ExceptionOr deprecatedInsertRule(const String& rule); + WEBCORE_EXPORT ExceptionOr deleteRule(unsigned index); - // IE Extensions - PassRefPtr rules(); - int addRule(const String& selector, const String& style, int index, ExceptionCode&); - int addRule(const String& selector, const String& style, ExceptionCode&); - void removeRule(unsigned index, ExceptionCode& ec) { deleteRule(index, ec); } + WEBCORE_EXPORT RefPtr rules(); + WEBCORE_EXPORT ExceptionOr addRule(const String& selector, const String& style, std::optional index); + ExceptionOr removeRule(unsigned index) { return deleteRule(index); } // For CSSRuleList. unsigned length() const; CSSRule* item(unsigned index); - virtual void clearOwnerNode() override; - virtual CSSImportRule* ownerRule() const override { return m_ownerRule; } - virtual URL baseURL() const override; - virtual bool isLoading() const override; + void clearOwnerNode() final; + CSSImportRule* ownerRule() const final { return m_ownerRule; } + URL baseURL() const final; + bool isLoading() const final; void clearOwnerRule() { m_ownerRule = 0; } + Document* ownerDocument() const; + CSSStyleSheet& rootStyleSheet(); + const CSSStyleSheet& rootStyleSheet() const; + Style::Scope* styleScope(); + MediaQuerySet* mediaQueries() const { return m_mediaQueries.get(); } - void setMediaQueries(PassRefPtr); + void setMediaQueries(Ref&&); void setTitle(const String& title) { m_title = title; } + bool hadRulesMutation() const { return m_mutatedRules; } + void clearHadRulesMutation() { m_mutatedRules = false; } + enum RuleMutationType { OtherMutation, RuleInsertion }; enum WhetherContentsWereClonedForMutation { ContentsWereNotClonedForMutation = 0, ContentsWereClonedForMutation }; @@ -112,33 +121,43 @@ public: void clearChildRuleCSSOMWrappers(); void reattachChildRuleCSSOMWrappers(); - StyleSheetContents& contents() { return m_contents.get(); } + StyleSheetContents& contents() { return m_contents; } + + bool isInline() const { return m_isInlineStylesheet; } + TextPosition startPosition() const { return m_startPosition; } void detachFromDocument() { m_ownerNode = nullptr; } private: - CSSStyleSheet(PassRef, CSSImportRule* ownerRule); - CSSStyleSheet(PassRef, Node* ownerNode, bool isInlineStylesheet); + CSSStyleSheet(Ref&&, CSSImportRule* ownerRule); + CSSStyleSheet(Ref&&, Node* ownerNode, const TextPosition& startPosition, bool isInlineStylesheet); + CSSStyleSheet(Ref&&, Node& ownerNode, const TextPosition& startPosition, bool isInlineStylesheet, const std::optional&); - virtual bool isCSSStyleSheet() const override { return true; } - virtual String type() const override { return ASCIILiteral("text/css"); } + bool isCSSStyleSheet() const final { return true; } + String type() const final { return ASCIILiteral("text/css"); } bool canAccessRules() const; - + Ref m_contents; bool m_isInlineStylesheet; bool m_isDisabled; + bool m_mutatedRules; + std::optional m_isOriginClean; String m_title; RefPtr m_mediaQueries; Node* m_ownerNode; CSSImportRule* m_ownerRule; + TextPosition m_startPosition; + mutable RefPtr m_mediaCSSOMWrapper; mutable Vector> m_childRuleCSSOMWrappers; mutable std::unique_ptr m_ruleListCSSOMWrapper; }; -} // namespace +} // namespace WebCore -#endif +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::CSSStyleSheet) + static bool isType(const WebCore::StyleSheet& styleSheet) { return styleSheet.isCSSStyleSheet(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/css/CSSStyleSheet.idl b/Source/WebCore/css/CSSStyleSheet.idl index d02132f5f..0ceb415b7 100644 --- a/Source/WebCore/css/CSSStyleSheet.idl +++ b/Source/WebCore/css/CSSStyleSheet.idl @@ -18,21 +18,18 @@ * Boston, MA 02110-1301, USA. */ -// Introduced in DOM Level 2: interface CSSStyleSheet : StyleSheet { - readonly attribute CSSRule ownerRule; - readonly attribute CSSRuleList cssRules; + readonly attribute CSSRule ownerRule; + readonly attribute CSSRuleList cssRules; - [ObjCLegacyUnnamedParameters, RaisesException] unsigned long insertRule([Default=Undefined] optional DOMString rule, - [Default=Undefined] optional unsigned long index); - [RaisesException] void deleteRule([Default=Undefined] optional unsigned long index); + [MayThrowException] unsigned long insertRule(DOMString rule, unsigned long index); + [MayThrowException, ImplementedAs=deprecatedInsertRule] unsigned long insertRule(DOMString rule); // Deprecated. - // IE Extensions - readonly attribute CSSRuleList rules; + [MayThrowException] void deleteRule(unsigned long index); - [RaisesException] long addRule([Default=Undefined] optional DOMString selector, - [Default=Undefined] optional DOMString style, - optional unsigned long index); - [RaisesException] void removeRule([Default=Undefined] optional unsigned long index); -}; + readonly attribute CSSRuleList rules; + // The following two operations are WebKit-specific. + [MayThrowException] long addRule(optional DOMString selector = "undefined", optional DOMString style = "undefined", optional unsigned long index); + [MayThrowException] void removeRule(optional unsigned long index = 0); +}; diff --git a/Source/WebCore/css/CSSSupportsRule.cpp b/Source/WebCore/css/CSSSupportsRule.cpp index fe2fad909..791e11608 100644 --- a/Source/WebCore/css/CSSSupportsRule.cpp +++ b/Source/WebCore/css/CSSSupportsRule.cpp @@ -33,15 +33,12 @@ #include "CSSRule.h" #include "CSSRuleList.h" #include "CSSStyleSheet.h" -#include "ExceptionCode.h" #include "StyleRule.h" #include -#if ENABLE(CSS3_CONDITIONAL_RULES) - namespace WebCore { -CSSSupportsRule::CSSSupportsRule(StyleRuleSupports* supportsRule, CSSStyleSheet* parent) +CSSSupportsRule::CSSSupportsRule(StyleRuleSupports& supportsRule, CSSStyleSheet* parent) : CSSGroupingRule(supportsRule, parent) { } @@ -50,9 +47,9 @@ String CSSSupportsRule::cssText() const { StringBuilder result; - result.append("@supports "); + result.appendLiteral("@supports "); result.append(conditionText()); - result.append(" {\n"); + result.appendLiteral(" {\n"); appendCssTextForItems(result); result.append('}'); @@ -61,9 +58,7 @@ String CSSSupportsRule::cssText() const String CSSSupportsRule::conditionText() const { - return toStyleRuleSupports(m_groupRule.get())->conditionText(); + return downcast(m_groupRule.get()).conditionText(); } } // namespace WebCore - -#endif diff --git a/Source/WebCore/css/CSSSupportsRule.h b/Source/WebCore/css/CSSSupportsRule.h index 838685196..5ede1aa5c 100644 --- a/Source/WebCore/css/CSSSupportsRule.h +++ b/Source/WebCore/css/CSSSupportsRule.h @@ -26,38 +26,34 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSSupportsRule_h -#define CSSSupportsRule_h +#pragma once #include "CSSGroupingRule.h" -#if ENABLE(CSS3_CONDITIONAL_RULES) - namespace WebCore { class CSSRule; class StyleRuleSupports; -class CSSSupportsRule : public CSSGroupingRule { +class CSSSupportsRule final : public CSSGroupingRule { public: - static PassRefPtr create(StyleRuleSupports* rule, CSSStyleSheet* sheet) + static Ref create(StyleRuleSupports& rule, CSSStyleSheet* sheet) { - return adoptRef(new CSSSupportsRule(rule, sheet)); + return adoptRef(*new CSSSupportsRule(rule, sheet)); } virtual ~CSSSupportsRule() { } - virtual CSSRule::Type type() const override { return SUPPORTS_RULE; } - virtual String cssText() const override; + String cssText() const final; String conditionText() const; private: - CSSSupportsRule(StyleRuleSupports*, CSSStyleSheet*); + CSSSupportsRule(StyleRuleSupports&, CSSStyleSheet*); + + CSSRule::Type type() const final { return SUPPORTS_RULE; } }; } // namespace WebCore -#endif // ENABLE(CSS3_CONDITIONAL_RULES) - -#endif // CSSSupportsRule_h +SPECIALIZE_TYPE_TRAITS_CSS_RULE(CSSSupportsRule, CSSRule::SUPPORTS_RULE) diff --git a/Source/WebCore/css/CSSSupportsRule.idl b/Source/WebCore/css/CSSSupportsRule.idl index 7bd7f7869..f96500b19 100644 --- a/Source/WebCore/css/CSSSupportsRule.idl +++ b/Source/WebCore/css/CSSSupportsRule.idl @@ -26,15 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -[ - NoInterfaceObject, - Conditional=CSS3_CONDITIONAL_RULES, -] interface CSSSupportsRule : CSSRule { +interface CSSSupportsRule : CSSRule { readonly attribute CSSRuleList cssRules; readonly attribute DOMString conditionText; - [RaisesException] unsigned long insertRule([Default=Undefined] optional DOMString rule, - [Default=Undefined] optional unsigned long index); - [RaisesException] void deleteRule([Default=Undefined] optional unsigned long index); + [MayThrowException] unsigned long insertRule(DOMString rule, unsigned long index); + [MayThrowException] void deleteRule(unsigned long index); }; - diff --git a/Source/WebCore/css/CSSTimingFunctionValue.cpp b/Source/WebCore/css/CSSTimingFunctionValue.cpp index 22d2833d7..2dd61957e 100644 --- a/Source/WebCore/css/CSSTimingFunctionValue.cpp +++ b/Source/WebCore/css/CSSTimingFunctionValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,17 +26,23 @@ #include "config.h" #include "CSSTimingFunctionValue.h" -#include +#include namespace WebCore { String CSSCubicBezierTimingFunctionValue::customCSSText() const { - return "cubic-bezier(" - + String::number(m_x1) + ", " - + String::number(m_y1) + ", " - + String::number(m_x2) + ", " - + String::number(m_y2) + ')'; + StringBuilder builder; + builder.appendLiteral("cubic-bezier("); + builder.appendNumber(m_x1); + builder.appendLiteral(", "); + builder.appendNumber(m_y1); + builder.appendLiteral(", "); + builder.appendNumber(m_x2); + builder.appendLiteral(", "); + builder.appendNumber(m_y2); + builder.append(')'); + return builder.toString(); } bool CSSCubicBezierTimingFunctionValue::equals(const CSSCubicBezierTimingFunctionValue& other) const @@ -44,10 +50,16 @@ bool CSSCubicBezierTimingFunctionValue::equals(const CSSCubicBezierTimingFunctio return m_x1 == other.m_x1 && m_x2 == other.m_x2 && m_y1 == other.m_y1 && m_y2 == other.m_y2; } - String CSSStepsTimingFunctionValue::customCSSText() const { - return "steps(" + String::number(m_steps) + ", " + (m_stepAtStart ? "start" : "end") + ')'; + StringBuilder builder; + builder.appendLiteral("steps("); + builder.appendNumber(m_steps); + if (m_stepAtStart) + builder.appendLiteral(", start)"); + else + builder.appendLiteral(", end)"); + return builder.toString(); } bool CSSStepsTimingFunctionValue::equals(const CSSStepsTimingFunctionValue& other) const @@ -55,4 +67,25 @@ bool CSSStepsTimingFunctionValue::equals(const CSSStepsTimingFunctionValue& othe return m_steps == other.m_steps && m_stepAtStart == other.m_stepAtStart; } +String CSSSpringTimingFunctionValue::customCSSText() const +{ + StringBuilder builder; + builder.appendLiteral("spring("); + builder.appendNumber(m_mass); + builder.append(' '); + builder.appendNumber(m_stiffness); + builder.append(' '); + builder.appendNumber(m_damping); + builder.append(' '); + builder.appendNumber(m_initialVelocity); + builder.append(')'); + return builder.toString(); +} + +bool CSSSpringTimingFunctionValue::equals(const CSSSpringTimingFunctionValue& other) const +{ + return m_mass == other.m_mass && m_stiffness == other.m_stiffness && m_damping == other.m_damping && m_initialVelocity == other.m_initialVelocity; +} + + } // namespace WebCore diff --git a/Source/WebCore/css/CSSTimingFunctionValue.h b/Source/WebCore/css/CSSTimingFunctionValue.h index c015c97e4..a9bf4ee62 100644 --- a/Source/WebCore/css/CSSTimingFunctionValue.h +++ b/Source/WebCore/css/CSSTimingFunctionValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,17 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSTimingFunctionValue_h -#define CSSTimingFunctionValue_h +#pragma once #include "CSSValue.h" -#include namespace WebCore { -class CSSCubicBezierTimingFunctionValue : public CSSValue { +class CSSCubicBezierTimingFunctionValue final : public CSSValue { public: - static PassRef create(double x1, double y1, double x2, double y2) + static Ref create(double x1, double y1, double x2, double y2) { return adoptRef(*new CSSCubicBezierTimingFunctionValue(x1, y1, x2, y2)); } @@ -63,11 +61,9 @@ private: double m_y2; }; -CSS_VALUE_TYPE_CASTS(CSSCubicBezierTimingFunctionValue, isCubicBezierTimingFunctionValue()) - -class CSSStepsTimingFunctionValue : public CSSValue { +class CSSStepsTimingFunctionValue final : public CSSValue { public: - static PassRef create(int steps, bool stepAtStart) + static Ref create(int steps, bool stepAtStart) { return adoptRef(*new CSSStepsTimingFunctionValue(steps, stepAtStart)); } @@ -91,8 +87,40 @@ private: bool m_stepAtStart; }; -CSS_VALUE_TYPE_CASTS(CSSStepsTimingFunctionValue, isStepsTimingFunctionValue()) +class CSSSpringTimingFunctionValue final : public CSSValue { +public: + static Ref create(double mass, double stiffness, double damping, double initialVelocity) + { + return adoptRef(*new CSSSpringTimingFunctionValue(mass, stiffness, damping, initialVelocity)); + } + + double mass() const { return m_mass; } + double stiffness() const { return m_stiffness; } + double damping() const { return m_damping; } + double initialVelocity() const { return m_initialVelocity; } + + String customCSSText() const; + + bool equals(const CSSSpringTimingFunctionValue&) const; + +private: + CSSSpringTimingFunctionValue(double mass, double stiffness, double damping, double initialVelocity) + : CSSValue(SpringTimingFunctionClass) + , m_mass(mass) + , m_stiffness(stiffness) + , m_damping(damping) + , m_initialVelocity(initialVelocity) + { + } + + double m_mass; + double m_stiffness; + double m_damping; + double m_initialVelocity; +}; -} // namespace +} // namespace WebCore -#endif +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCubicBezierTimingFunctionValue, isCubicBezierTimingFunctionValue()) +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSStepsTimingFunctionValue, isStepsTimingFunctionValue()) +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSSpringTimingFunctionValue, isSpringTimingFunctionValue()) diff --git a/Source/WebCore/css/CSSToLengthConversionData.cpp b/Source/WebCore/css/CSSToLengthConversionData.cpp new file mode 100644 index 000000000..b56274747 --- /dev/null +++ b/Source/WebCore/css/CSSToLengthConversionData.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSToLengthConversionData.h" + +#include "RenderStyle.h" +#include "RenderView.h" + +namespace WebCore { + +float CSSToLengthConversionData::zoom() const +{ + if (m_useEffectiveZoom) + return m_style ? m_style->effectiveZoom() : 1; + return m_zoom; +} + +double CSSToLengthConversionData::viewportWidthFactor() const +{ + if (m_style && !m_computingFontSize) + const_cast(m_style)->setHasViewportUnits(); + + if (!m_renderView) + return 0; + + return m_renderView->viewportSizeForCSSViewportUnits().width() / 100.0; +} + +double CSSToLengthConversionData::viewportHeightFactor() const +{ + if (m_style && !m_computingFontSize) + const_cast(m_style)->setHasViewportUnits(); + + if (!m_renderView) + return 0; + + return m_renderView->viewportSizeForCSSViewportUnits().height() / 100.0; +} + +double CSSToLengthConversionData::viewportMinFactor() const +{ + if (m_style && !m_computingFontSize) + const_cast(m_style)->setHasViewportUnits(); + + if (!m_renderView) + return 0; + + IntSize viewportSizeForCSSViewportUnits = m_renderView->viewportSizeForCSSViewportUnits(); + return std::min(viewportSizeForCSSViewportUnits.width(), viewportSizeForCSSViewportUnits.height()) / 100.0; +} + +double CSSToLengthConversionData::viewportMaxFactor() const +{ + if (m_style && !m_computingFontSize) + const_cast(m_style)->setHasViewportUnits(); + + if (!m_renderView) + return 0; + + IntSize viewportSizeForCSSViewportUnits = m_renderView->viewportSizeForCSSViewportUnits(); + return std::max(viewportSizeForCSSViewportUnits.width(), viewportSizeForCSSViewportUnits.height()) / 100.0; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSToLengthConversionData.h b/Source/WebCore/css/CSSToLengthConversionData.h new file mode 100644 index 000000000..e526496aa --- /dev/null +++ b/Source/WebCore/css/CSSToLengthConversionData.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace WebCore { + +class RenderStyle; +class RenderView; + +class CSSToLengthConversionData { +public: + CSSToLengthConversionData(const RenderStyle* style, const RenderStyle* rootStyle, const RenderView* renderView, float zoom, bool computingFontSize = false) + : m_style(style) + , m_rootStyle(rootStyle) + , m_renderView(renderView) + , m_zoom(zoom) + , m_useEffectiveZoom(false) + , m_computingFontSize(computingFontSize) + { + ASSERT(zoom > 0); + } + + CSSToLengthConversionData(const RenderStyle* style, const RenderStyle* rootStyle, const RenderView* renderView, bool computingFontSize = false) + : m_style(style) + , m_rootStyle(rootStyle) + , m_renderView(renderView) + , m_zoom(1) + , m_useEffectiveZoom(true) + , m_computingFontSize(computingFontSize) + { + } + + CSSToLengthConversionData() + : CSSToLengthConversionData(nullptr, nullptr, nullptr) + { + } + + const RenderStyle* style() const { return m_style; } + const RenderStyle* rootStyle() const { return m_rootStyle; } + float zoom() const; + bool computingFontSize() const { return m_computingFontSize; } + + double viewportWidthFactor() const; + double viewportHeightFactor() const; + double viewportMinFactor() const; + double viewportMaxFactor() const; + + CSSToLengthConversionData copyWithAdjustedZoom(float newZoom) const + { + return CSSToLengthConversionData(m_style, m_rootStyle, m_renderView, newZoom, m_computingFontSize); + } + +private: + const RenderStyle* m_style; + const RenderStyle* m_rootStyle; + const RenderView* m_renderView; + float m_zoom; + bool m_useEffectiveZoom; + bool m_computingFontSize; +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSToStyleMap.cpp b/Source/WebCore/css/CSSToStyleMap.cpp index 988cd835c..e68b6db7f 100644 --- a/Source/WebCore/css/CSSToStyleMap.cpp +++ b/Source/WebCore/css/CSSToStyleMap.cpp @@ -29,7 +29,11 @@ #include "CSSToStyleMap.h" #include "Animation.h" +#include "CSSAnimationTriggerScrollValue.h" #include "CSSBorderImageSliceValue.h" +#include "CSSImageGeneratorValue.h" +#include "CSSImageSetValue.h" +#include "CSSImageValue.h" #include "CSSPrimitiveValue.h" #include "CSSPrimitiveValueMappings.h" #include "CSSTimingFunctionValue.h" @@ -37,16 +41,23 @@ #include "FillLayer.h" #include "Pair.h" #include "Rect.h" +#include "RenderView.h" +#include "StyleBuilderConverter.h" #include "StyleResolver.h" namespace WebCore { +CSSToStyleMap::CSSToStyleMap(StyleResolver* resolver) + : m_resolver(resolver) +{ +} + RenderStyle* CSSToStyleMap::style() const { return m_resolver->style(); } - -RenderStyle* CSSToStyleMap::rootElementStyle() const + +const RenderStyle* CSSToStyleMap::rootElementStyle() const { return m_resolver->rootElementStyle(); } @@ -55,262 +66,223 @@ bool CSSToStyleMap::useSVGZoomRules() const { return m_resolver->useSVGZoomRules(); } - -PassRefPtr CSSToStyleMap::styleImage(CSSPropertyID propertyId, CSSValue* value) + +RefPtr CSSToStyleMap::styleImage(CSSValue& value) { - return m_resolver->styleImage(propertyId, value); + return m_resolver->styleImage(value); } -void CSSToStyleMap::mapFillAttachment(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillAttachment(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setAttachment(FillLayer::initialFillAttachment(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setAttachment(FillLayer::initialFillAttachment(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - switch (toCSSPrimitiveValue(value)->getValueID()) { + switch (downcast(value).valueID()) { case CSSValueFixed: - layer->setAttachment(FixedBackgroundAttachment); + layer.setAttachment(FixedBackgroundAttachment); break; case CSSValueScroll: - layer->setAttachment(ScrollBackgroundAttachment); + layer.setAttachment(ScrollBackgroundAttachment); break; case CSSValueLocal: - layer->setAttachment(LocalBackgroundAttachment); + layer.setAttachment(LocalBackgroundAttachment); break; default: return; } } -void CSSToStyleMap::mapFillClip(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillClip(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setClip(FillLayer::initialFillClip(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setClip(FillLayer::initialFillClip(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setClip(*primitiveValue); + layer.setClip(downcast(value)); } -void CSSToStyleMap::mapFillComposite(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillComposite(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setComposite(FillLayer::initialFillComposite(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setComposite(FillLayer::initialFillComposite(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setComposite(*primitiveValue); + layer.setComposite(downcast(value)); } -void CSSToStyleMap::mapFillBlendMode(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillBlendMode(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setBlendMode(FillLayer::initialFillBlendMode(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setBlendMode(FillLayer::initialFillBlendMode(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setBlendMode(*primitiveValue); + layer.setBlendMode(downcast(value)); } -void CSSToStyleMap::mapFillOrigin(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillOrigin(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setOrigin(FillLayer::initialFillOrigin(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setOrigin(FillLayer::initialFillOrigin(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setOrigin(*primitiveValue); + layer.setOrigin(downcast(value)); } - -void CSSToStyleMap::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillImage(CSSPropertyID propertyID, FillLayer& layer, CSSValue& value) { - if (value->isInitialValue()) { - layer->setImage(FillLayer::initialFillImage(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setImage(FillLayer::initialFillImage(layer.type())); return; } - layer->setImage(styleImage(property, value)); + layer.setImage(styleImage(value)); } -void CSSToStyleMap::mapFillRepeatX(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillRepeatX(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setRepeatX(FillLayer::initialFillRepeatX(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setRepeatX(*primitiveValue); + layer.setRepeatX(downcast(value)); } -void CSSToStyleMap::mapFillRepeatY(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillRepeatY(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setRepeatY(FillLayer::initialFillRepeatY(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - layer->setRepeatY(*primitiveValue); + layer.setRepeatY(downcast(value)); } -void CSSToStyleMap::mapFillSize(CSSPropertyID, FillLayer* layer, CSSValue* value) +static inline bool convertToLengthSize(const CSSPrimitiveValue& primitiveValue, CSSToLengthConversionData conversionData, LengthSize& size) { - if (!value->isPrimitiveValue()) { - layer->setSizeType(SizeNone); - return; - } - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueContain) - layer->setSizeType(Contain); - else if (primitiveValue->getValueID() == CSSValueCover) - layer->setSizeType(Cover); - else - layer->setSizeType(SizeLength); - - LengthSize b = FillLayer::initialFillSizeLength(layer->type()); + if (auto* pair = primitiveValue.pairValue()) { + size.width = pair->first()->convertToLength(conversionData); + size.height = pair->second()->convertToLength(conversionData); + } else + size.width = primitiveValue.convertToLength(conversionData); + return !size.width.isUndefined() && !size.height.isUndefined(); +} - if (value->isInitialValue() || primitiveValue->getValueID() == CSSValueContain || primitiveValue->getValueID() == CSSValueCover) { - layer->setSizeLength(b); +void CSSToStyleMap::mapFillSize(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) +{ + if (value.treatAsInitialValue(propertyID)) { + layer.setSize(FillLayer::initialFillSize(layer.type())); return; } - float zoomFactor = style()->effectiveZoom(); - - Length firstLength; - Length secondLength; - - if (Pair* pair = primitiveValue->getPairValue()) { - CSSPrimitiveValue* first = static_cast(pair->first()); - CSSPrimitiveValue* second = static_cast(pair->second()); - firstLength = first->convertToLength(style(), rootElementStyle(), zoomFactor); - secondLength = second->convertToLength(style(), rootElementStyle(), zoomFactor); - } else { - firstLength = primitiveValue->convertToLength(style(), rootElementStyle(), zoomFactor); - secondLength = Length(); - } - - if (firstLength.isUndefined() || secondLength.isUndefined()) + if (!is(value)) return; - b.setWidth(firstLength); - b.setHeight(secondLength); - layer->setSizeLength(b); + auto& primitiveValue = downcast(value); + FillSize fillSize; + switch (primitiveValue.valueID()) { + case CSSValueContain: + fillSize.type = Contain; + break; + case CSSValueCover: + fillSize.type = Cover; + break; + default: + ASSERT(fillSize.type == SizeLength); + if (!convertToLengthSize(primitiveValue, m_resolver->state().cssToLengthConversionData(), fillSize.size)) + return; + break; + } + layer.setSize(fillSize); } -void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setXPosition(FillLayer::initialFillXPosition(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setXPosition(FillLayer::initialFillXPosition(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - float zoomFactor = style()->effectiveZoom(); - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Pair* pair = primitiveValue->getPairValue(); + auto* primitiveValue = &downcast(value); + Pair* pair = primitiveValue->pairValue(); + Length length; if (pair) { ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionX || propertyID == CSSPropertyWebkitMaskPositionX); - primitiveValue = pair->second(); - } - - Length length; - if (primitiveValue->isLength()) - length = primitiveValue->computeLength(style(), rootElementStyle(), zoomFactor); - else if (primitiveValue->isPercentage()) - length = Length(primitiveValue->getDoubleValue(), Percent); - else if (primitiveValue->isCalculatedPercentageWithLength()) - length = Length(primitiveValue->cssCalcValue()->toCalcValue(style(), rootElementStyle(), zoomFactor)); - else if (primitiveValue->isViewportPercentageLength()) - length = primitiveValue->viewportPercentageLength(); - else - return; + length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second()); + } else + length = StyleBuilderConverter::convertPositionComponentX(*m_resolver, value); - layer->setXPosition(length); + layer.setXPosition(length); if (pair) - layer->setBackgroundXOrigin(*(pair->first())); + layer.setBackgroundXOrigin(*pair->first()); } -void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setYPosition(FillLayer::initialFillYPosition(layer->type())); + if (value.treatAsInitialValue(propertyID)) { + layer.setYPosition(FillLayer::initialFillYPosition(layer.type())); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - float zoomFactor = style()->effectiveZoom(); - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Pair* pair = primitiveValue->getPairValue(); + auto* primitiveValue = &downcast(value); + Pair* pair = primitiveValue->pairValue(); + Length length; if (pair) { ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionY || propertyID == CSSPropertyWebkitMaskPositionY); - primitiveValue = pair->second(); - } - - Length length; - if (primitiveValue->isLength()) - length = primitiveValue->computeLength(style(), rootElementStyle(), zoomFactor); - else if (primitiveValue->isPercentage()) - length = Length(primitiveValue->getDoubleValue(), Percent); - else if (primitiveValue->isCalculatedPercentageWithLength()) - length = Length(primitiveValue->cssCalcValue()->toCalcValue(style(), rootElementStyle(), zoomFactor)); - else if (primitiveValue->isViewportPercentageLength()) - length = primitiveValue->viewportPercentageLength(); - else - return; - - layer->setYPosition(length); + length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second()); + } else + length = StyleBuilderConverter::convertPositionComponentY(*m_resolver, value); + + layer.setYPosition(length); if (pair) - layer->setBackgroundYOrigin(*(pair->first())); + layer.setBackgroundYOrigin(*pair->first()); } -void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID, FillLayer* layer, CSSValue* value) +void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value) { - EMaskSourceType type = FillLayer::initialMaskSourceType(layer->type()); - if (value->isInitialValue()) { - layer->setMaskSourceType(type); + EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer.type()); + if (value.treatAsInitialValue(propertyID)) { + layer.setMaskSourceType(type); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - switch (primitiveValue->getValueID()) { + switch (downcast(value).valueID()) { case CSSValueAlpha: type = EMaskSourceType::MaskAlpha; break; @@ -323,198 +295,200 @@ void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID, FillLayer* layer, CSSVa ASSERT_NOT_REACHED(); } - layer->setMaskSourceType(type); + layer.setMaskSourceType(type); } -void CSSToStyleMap::mapAnimationDelay(Animation* animation, CSSValue* value) +void CSSToStyleMap::mapAnimationDelay(Animation& animation, const CSSValue& value) { - if (value->isInitialValue()) { - animation->setDelay(Animation::initialAnimationDelay()); + if (value.treatAsInitialValue(CSSPropertyAnimationDelay)) { + animation.setDelay(Animation::initialDelay()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - animation->setDelay(primitiveValue->computeTime()); + animation.setDelay(downcast(value).computeTime()); } -void CSSToStyleMap::mapAnimationDirection(Animation* layer, CSSValue* value) +void CSSToStyleMap::mapAnimationDirection(Animation& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setDirection(Animation::initialAnimationDirection()); + if (value.treatAsInitialValue(CSSPropertyAnimationDirection)) { + layer.setDirection(Animation::initialDirection()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - switch (primitiveValue->getValueID()) { + switch (downcast(value).valueID()) { case CSSValueNormal: - layer->setDirection(Animation::AnimationDirectionNormal); + layer.setDirection(Animation::AnimationDirectionNormal); break; case CSSValueAlternate: - layer->setDirection(Animation::AnimationDirectionAlternate); + layer.setDirection(Animation::AnimationDirectionAlternate); break; case CSSValueReverse: - layer->setDirection(Animation::AnimationDirectionReverse); + layer.setDirection(Animation::AnimationDirectionReverse); break; case CSSValueAlternateReverse: - layer->setDirection(Animation::AnimationDirectionAlternateReverse); + layer.setDirection(Animation::AnimationDirectionAlternateReverse); break; default: break; } } -void CSSToStyleMap::mapAnimationDuration(Animation* animation, CSSValue* value) +void CSSToStyleMap::mapAnimationDuration(Animation& animation, const CSSValue& value) { - if (value->isInitialValue()) { - animation->setDuration(Animation::initialAnimationDuration()); + if (value.treatAsInitialValue(CSSPropertyAnimationDuration)) { + animation.setDuration(Animation::initialDuration()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - animation->setDuration(primitiveValue->computeTime()); + animation.setDuration(downcast(value).computeTime()); } -void CSSToStyleMap::mapAnimationFillMode(Animation* layer, CSSValue* value) +void CSSToStyleMap::mapAnimationFillMode(Animation& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setFillMode(Animation::initialAnimationFillMode()); + if (value.treatAsInitialValue(CSSPropertyAnimationFillMode)) { + layer.setFillMode(Animation::initialFillMode()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - switch (primitiveValue->getValueID()) { + switch (downcast(value).valueID()) { case CSSValueNone: - layer->setFillMode(AnimationFillModeNone); + layer.setFillMode(AnimationFillModeNone); break; case CSSValueForwards: - layer->setFillMode(AnimationFillModeForwards); + layer.setFillMode(AnimationFillModeForwards); break; case CSSValueBackwards: - layer->setFillMode(AnimationFillModeBackwards); + layer.setFillMode(AnimationFillModeBackwards); break; case CSSValueBoth: - layer->setFillMode(AnimationFillModeBoth); + layer.setFillMode(AnimationFillModeBoth); break; default: break; } } -void CSSToStyleMap::mapAnimationIterationCount(Animation* animation, CSSValue* value) +void CSSToStyleMap::mapAnimationIterationCount(Animation& animation, const CSSValue& value) { - if (value->isInitialValue()) { - animation->setIterationCount(Animation::initialAnimationIterationCount()); + if (value.treatAsInitialValue(CSSPropertyAnimationIterationCount)) { + animation.setIterationCount(Animation::initialIterationCount()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueInfinite) - animation->setIterationCount(Animation::IterationCountInfinite); + auto& primitiveValue = downcast(value); + if (primitiveValue.valueID() == CSSValueInfinite) + animation.setIterationCount(Animation::IterationCountInfinite); else - animation->setIterationCount(primitiveValue->getFloatValue()); + animation.setIterationCount(primitiveValue.floatValue()); } -void CSSToStyleMap::mapAnimationName(Animation* layer, CSSValue* value) +void CSSToStyleMap::mapAnimationName(Animation& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setName(Animation::initialAnimationName()); + if (value.treatAsInitialValue(CSSPropertyAnimationName)) { + layer.setName(Animation::initialName()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueNone) - layer->setIsNoneAnimation(true); + auto& primitiveValue = downcast(value); + if (primitiveValue.valueID() == CSSValueNone) + layer.setIsNoneAnimation(true); else - layer->setName(primitiveValue->getStringValue()); + layer.setName(primitiveValue.stringValue(), m_resolver->state().styleScopeOrdinal()); } -void CSSToStyleMap::mapAnimationPlayState(Animation* layer, CSSValue* value) +void CSSToStyleMap::mapAnimationPlayState(Animation& layer, const CSSValue& value) { - if (value->isInitialValue()) { - layer->setPlayState(Animation::initialAnimationPlayState()); + if (value.treatAsInitialValue(CSSPropertyAnimationPlayState)) { + layer.setPlayState(Animation::initialPlayState()); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - EAnimPlayState playState = (primitiveValue->getValueID() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying; - layer->setPlayState(playState); + EAnimPlayState playState = (downcast(value).valueID() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying; + layer.setPlayState(playState); } -void CSSToStyleMap::mapAnimationProperty(Animation* animation, CSSValue* value) +void CSSToStyleMap::mapAnimationProperty(Animation& animation, const CSSValue& value) { - if (value->isInitialValue()) { - animation->setAnimationMode(Animation::AnimateAll); - animation->setProperty(CSSPropertyInvalid); + if (value.treatAsInitialValue(CSSPropertyAnimation)) { + animation.setAnimationMode(Animation::AnimateAll); + animation.setProperty(CSSPropertyInvalid); return; } - if (!value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueAll) { - animation->setAnimationMode(Animation::AnimateAll); - animation->setProperty(CSSPropertyInvalid); - } else if (primitiveValue->getValueID() == CSSValueNone) { - animation->setAnimationMode(Animation::AnimateNone); - animation->setProperty(CSSPropertyInvalid); - } else { - animation->setAnimationMode(Animation::AnimateSingleProperty); - animation->setProperty(primitiveValue->getPropertyID()); + auto& primitiveValue = downcast(value); + if (primitiveValue.valueID() == CSSValueAll) { + animation.setAnimationMode(Animation::AnimateAll); + animation.setProperty(CSSPropertyInvalid); + return; + } + if (primitiveValue.valueID() == CSSValueNone) { + animation.setAnimationMode(Animation::AnimateNone); + animation.setProperty(CSSPropertyInvalid); + return; + } + if (primitiveValue.propertyID() == CSSPropertyInvalid) { + animation.setAnimationMode(Animation::AnimateUnknownProperty); + animation.setProperty(CSSPropertyInvalid); + animation.setUnknownProperty(primitiveValue.stringValue()); + return; } + animation.setAnimationMode(Animation::AnimateSingleProperty); + animation.setProperty(primitiveValue.propertyID()); } -void CSSToStyleMap::mapAnimationTimingFunction(Animation* animation, CSSValue* value) +void CSSToStyleMap::mapAnimationTimingFunction(Animation& animation, const CSSValue& value) { - if (value->isInitialValue()) { - animation->setTimingFunction(Animation::initialAnimationTimingFunction()); + if (value.treatAsInitialValue(CSSPropertyAnimationTimingFunction)) { + animation.setTimingFunction(Animation::initialTimingFunction()); return; } - if (value->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - switch (primitiveValue->getValueID()) { + if (is(value)) { + switch (downcast(value).valueID()) { case CSSValueLinear: - animation->setTimingFunction(LinearTimingFunction::create()); + animation.setTimingFunction(LinearTimingFunction::create()); break; case CSSValueEase: - animation->setTimingFunction(CubicBezierTimingFunction::create()); + animation.setTimingFunction(CubicBezierTimingFunction::create()); break; case CSSValueEaseIn: - animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseIn)); + animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseIn)); break; case CSSValueEaseOut: - animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseOut)); + animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseOut)); break; case CSSValueEaseInOut: - animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseInOut)); + animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseInOut)); break; case CSSValueStepStart: - animation->setTimingFunction(StepsTimingFunction::create(1, true)); + animation.setTimingFunction(StepsTimingFunction::create(1, true)); break; case CSSValueStepEnd: - animation->setTimingFunction(StepsTimingFunction::create(1, false)); + animation.setTimingFunction(StepsTimingFunction::create(1, false)); break; default: break; @@ -522,58 +496,78 @@ void CSSToStyleMap::mapAnimationTimingFunction(Animation* animation, CSSValue* v return; } - if (value->isCubicBezierTimingFunctionValue()) { - CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value); - animation->setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2())); - } else if (value->isStepsTimingFunctionValue()) { - CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value); - animation->setTimingFunction(StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart())); + if (is(value)) { + auto& cubicTimingFunction = downcast(value); + animation.setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction.x1(), cubicTimingFunction.y1(), cubicTimingFunction.x2(), cubicTimingFunction.y2())); + } else if (is(value)) { + auto& stepsTimingFunction = downcast(value); + animation.setTimingFunction(StepsTimingFunction::create(stepsTimingFunction.numberOfSteps(), stepsTimingFunction.stepAtStart())); + } else if (is(value)) { + auto& springTimingFunction = downcast(value); + animation.setTimingFunction(SpringTimingFunction::create(springTimingFunction.mass(), springTimingFunction.stiffness(), springTimingFunction.damping(), springTimingFunction.initialVelocity())); } } +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) +void CSSToStyleMap::mapAnimationTrigger(Animation& animation, const CSSValue& value) +{ + if (value.treatAsInitialValue(CSSPropertyWebkitAnimationTrigger)) { + animation.setTrigger(Animation::initialTrigger()); + return; + } + + if (value.isPrimitiveValue()) { + auto& primitiveValue = downcast(value); + if (primitiveValue.valueID() == CSSValueAuto) + animation.setTrigger(AutoAnimationTrigger::create()); + return; + } + + if (value.isAnimationTriggerScrollValue()) { + auto& scrollTrigger = downcast(value); + + const CSSPrimitiveValue& startValue = downcast(scrollTrigger.startValue()); + Length startLength = startValue.computeLength(m_resolver->state().cssToLengthConversionData()); + + Length endLength; + if (scrollTrigger.hasEndValue()) { + const CSSPrimitiveValue* endValue = downcast(scrollTrigger.endValue()); + endLength = endValue->computeLength(m_resolver->state().cssToLengthConversionData()); + } + + animation.setTrigger(ScrollAnimationTrigger::create(startLength, endLength)); + } +} +#endif + void CSSToStyleMap::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image) { // If we're not a value list, then we are "none" and don't need to alter the empty image at all. - if (!value || !value->isValueList()) + if (!is(value)) return; // Retrieve the border image value. - CSSValueList* borderImage = toCSSValueList(value); - - // Set the image (this kicks off the load). - CSSPropertyID imageProperty; - if (property == CSSPropertyWebkitBorderImage) - imageProperty = CSSPropertyBorderImageSource; - else if (property == CSSPropertyWebkitMaskBoxImage) - imageProperty = CSSPropertyWebkitMaskBoxImageSource; - else - imageProperty = property; - - for (unsigned i = 0 ; i < borderImage->length() ; ++i) { - CSSValue* current = borderImage->item(i); + CSSValueList& borderImage = downcast(*value); - if (current->isImageValue() || current->isImageGeneratorValue() -#if ENABLE(CSS_IMAGE_SET) - || current->isImageSetValue() -#endif - ) - image.setImage(styleImage(imageProperty, current)); - else if (current->isBorderImageSliceValue()) + for (auto& current : borderImage) { + if (is(current.get()) || is(current.get()) || is(current.get())) + image.setImage(styleImage(current.get())); + else if (is(current.get())) mapNinePieceImageSlice(current, image); - else if (current->isValueList()) { - CSSValueList* slashList = toCSSValueList(current); + else if (is(current.get())) { + CSSValueList& slashList = downcast(current.get()); // Map in the image slices. - if (slashList->item(0) && slashList->item(0)->isBorderImageSliceValue()) - mapNinePieceImageSlice(slashList->item(0), image); + if (is(slashList.item(0))) + mapNinePieceImageSlice(*slashList.item(0), image); // Map in the border slices. - if (slashList->item(1)) - image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1))); + if (slashList.item(1)) + image.setBorderSlices(mapNinePieceImageQuad(*slashList.item(1))); // Map in the outset. - if (slashList->item(2)) - image.setOutset(mapNinePieceImageQuad(slashList->item(2))); - } else if (current->isPrimitiveValue()) { + if (slashList.item(2)) + image.setOutset(mapNinePieceImageQuad(*slashList.item(2))); + } else if (is(current.get())) { // Set the appropriate rules for stretch/round/repeat of the slices. mapNinePieceImageRepeat(current, image); } @@ -594,96 +588,96 @@ void CSSToStyleMap::mapNinePieceImage(CSSPropertyID property, CSSValue* value, N } } -void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) +void CSSToStyleMap::mapNinePieceImageSlice(CSSValue& value, NinePieceImage& image) { - if (!value || !value->isBorderImageSliceValue()) + if (!is(value)) return; // Retrieve the border image value. - CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value); + auto& borderImageSlice = downcast(value); // Set up a length box to represent our image slices. LengthBox box; - Quad* slices = borderImageSlice->slices(); + Quad* slices = borderImageSlice.slices(); if (slices->top()->isPercentage()) - box.m_top = Length(slices->top()->getDoubleValue(), Percent); + box.top() = Length(slices->top()->doubleValue(), Percent); else - box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + box.top() = Length(slices->top()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); if (slices->bottom()->isPercentage()) - box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent); + box.bottom() = Length(slices->bottom()->doubleValue(), Percent); else - box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + box.bottom() = Length((int)slices->bottom()->floatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); if (slices->left()->isPercentage()) - box.m_left = Length(slices->left()->getDoubleValue(), Percent); + box.left() = Length(slices->left()->doubleValue(), Percent); else - box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + box.left() = Length(slices->left()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); if (slices->right()->isPercentage()) - box.m_right = Length(slices->right()->getDoubleValue(), Percent); + box.right() = Length(slices->right()->doubleValue(), Percent); else - box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); + box.right() = Length(slices->right()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); image.setImageSlices(box); // Set our fill mode. - image.setFill(borderImageSlice->m_fill); + image.setFill(borderImageSlice.m_fill); } -LengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) +LengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue& value) { - if (!value || !value->isPrimitiveValue()) + if (!is(value)) return LengthBox(); // Get our zoom value. - float zoom = useSVGZoomRules() ? 1.0f : style()->effectiveZoom(); + CSSToLengthConversionData conversionData = useSVGZoomRules() ? m_resolver->state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f) : m_resolver->state().cssToLengthConversionData(); // Retrieve the primitive value. - CSSPrimitiveValue* borderWidths = toCSSPrimitiveValue(value); + auto& borderWidths = downcast(value); // Set up a length box to represent our image slices. LengthBox box; // Defaults to 'auto' so we don't have to handle that explicitly below. - Quad* slices = borderWidths->getQuadValue(); + Quad* slices = borderWidths.quadValue(); if (slices->top()->isNumber()) - box.m_top = Length(slices->top()->getIntValue(), Relative); + box.top() = Length(slices->top()->intValue(), Relative); else if (slices->top()->isPercentage()) - box.m_top = Length(slices->top()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); - else if (slices->top()->getValueID() != CSSValueAuto) - box.m_top = slices->top()->computeLength(style(), rootElementStyle(), zoom); + box.top() = Length(slices->top()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->top()->valueID() != CSSValueAuto) + box.top() = slices->top()->computeLength(conversionData); if (slices->right()->isNumber()) - box.m_right = Length(slices->right()->getIntValue(), Relative); + box.right() = Length(slices->right()->intValue(), Relative); else if (slices->right()->isPercentage()) - box.m_right = Length(slices->right()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); - else if (slices->right()->getValueID() != CSSValueAuto) - box.m_right = slices->right()->computeLength(style(), rootElementStyle(), zoom); + box.right() = Length(slices->right()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->right()->valueID() != CSSValueAuto) + box.right() = slices->right()->computeLength(conversionData); if (slices->bottom()->isNumber()) - box.m_bottom = Length(slices->bottom()->getIntValue(), Relative); + box.bottom() = Length(slices->bottom()->intValue(), Relative); else if (slices->bottom()->isPercentage()) - box.m_bottom = Length(slices->bottom()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); - else if (slices->bottom()->getValueID() != CSSValueAuto) - box.m_bottom = slices->bottom()->computeLength(style(), rootElementStyle(), zoom); + box.bottom() = Length(slices->bottom()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->bottom()->valueID() != CSSValueAuto) + box.bottom() = slices->bottom()->computeLength(conversionData); if (slices->left()->isNumber()) - box.m_left = Length(slices->left()->getIntValue(), Relative); + box.left() = Length(slices->left()->intValue(), Relative); else if (slices->left()->isPercentage()) - box.m_left = Length(slices->left()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); - else if (slices->left()->getValueID() != CSSValueAuto) - box.m_left = slices->left()->computeLength(style(), rootElementStyle(), zoom); + box.left() = Length(slices->left()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent); + else if (slices->left()->valueID() != CSSValueAuto) + box.left() = slices->left()->computeLength(conversionData); return box; } -void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) +void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue& value, NinePieceImage& image) { - if (!value || !value->isPrimitiveValue()) + if (!is(value)) return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Pair* pair = primitiveValue->getPairValue(); + CSSPrimitiveValue& primitiveValue = downcast(value); + Pair* pair = primitiveValue.pairValue(); if (!pair || !pair->first() || !pair->second()) return; - CSSValueID firstIdentifier = pair->first()->getValueID(); - CSSValueID secondIdentifier = pair->second()->getValueID(); + CSSValueID firstIdentifier = pair->first()->valueID(); + CSSValueID secondIdentifier = pair->second()->valueID(); ENinePieceImageRule horizontalRule; switch (firstIdentifier) { diff --git a/Source/WebCore/css/CSSToStyleMap.h b/Source/WebCore/css/CSSToStyleMap.h index cf50c8594..31bb0b938 100644 --- a/Source/WebCore/css/CSSToStyleMap.h +++ b/Source/WebCore/css/CSSToStyleMap.h @@ -19,73 +19,75 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSToStyleMap_h -#define CSSToStyleMap_h +#pragma once #include "CSSPropertyNames.h" -#include "LengthBox.h" +#include +#include namespace WebCore { -class FillLayer; -class CSSValue; class Animation; +class CSSValue; +class FillLayer; +class LengthBox; +class NinePieceImage; class RenderStyle; class StyleImage; class StyleResolver; -class NinePieceImage; class CSSToStyleMap { WTF_MAKE_NONCOPYABLE(CSSToStyleMap); WTF_MAKE_FAST_ALLOCATED; public: - CSSToStyleMap(StyleResolver* resolver) : m_resolver(resolver) { } + CSSToStyleMap(StyleResolver*); - void mapFillAttachment(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillClip(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillComposite(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillBlendMode(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillOrigin(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillImage(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillRepeatX(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillRepeatY(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillSize(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillXPosition(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillYPosition(CSSPropertyID, FillLayer*, CSSValue*); - void mapFillMaskSourceType(CSSPropertyID, FillLayer*, CSSValue*); + void mapFillAttachment(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillClip(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillComposite(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillBlendMode(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillOrigin(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillImage(CSSPropertyID, FillLayer&, CSSValue&); + void mapFillRepeatX(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillRepeatY(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillSize(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillXPosition(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillYPosition(CSSPropertyID, FillLayer&, const CSSValue&); + void mapFillMaskSourceType(CSSPropertyID, FillLayer&, const CSSValue&); - void mapAnimationDelay(Animation*, CSSValue*); - void mapAnimationDirection(Animation*, CSSValue*); - void mapAnimationDuration(Animation*, CSSValue*); - void mapAnimationFillMode(Animation*, CSSValue*); - void mapAnimationIterationCount(Animation*, CSSValue*); - void mapAnimationName(Animation*, CSSValue*); - void mapAnimationPlayState(Animation*, CSSValue*); - void mapAnimationProperty(Animation*, CSSValue*); - void mapAnimationTimingFunction(Animation*, CSSValue*); + void mapAnimationDelay(Animation&, const CSSValue&); + void mapAnimationDirection(Animation&, const CSSValue&); + void mapAnimationDuration(Animation&, const CSSValue&); + void mapAnimationFillMode(Animation&, const CSSValue&); + void mapAnimationIterationCount(Animation&, const CSSValue&); + void mapAnimationName(Animation&, const CSSValue&); + void mapAnimationPlayState(Animation&, const CSSValue&); + void mapAnimationProperty(Animation&, const CSSValue&); + void mapAnimationTimingFunction(Animation&, const CSSValue&); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + void mapAnimationTrigger(Animation&, const CSSValue&); +#endif void mapNinePieceImage(CSSPropertyID, CSSValue*, NinePieceImage&); - void mapNinePieceImageSlice(CSSValue*, NinePieceImage&); - LengthBox mapNinePieceImageQuad(CSSValue*); - void mapNinePieceImageRepeat(CSSValue*, NinePieceImage&); + void mapNinePieceImageSlice(CSSValue&, NinePieceImage&); + LengthBox mapNinePieceImageQuad(CSSValue&); + void mapNinePieceImageRepeat(CSSValue&, NinePieceImage&); private: // FIXME: These accessors should be replaced by a ResolveState object // similar to how PaintInfo/LayoutState cache values needed for // the current paint/layout. RenderStyle* style() const; - RenderStyle* rootElementStyle() const; + const RenderStyle* rootElementStyle() const; bool useSVGZoomRules() const; // FIXME: This should be part of some sort of StyleImageCache object which // is held by the StyleResolver, and likely provided to this object // during the resolve. - PassRefPtr styleImage(CSSPropertyID, CSSValue*); + RefPtr styleImage(CSSValue&); StyleResolver* m_resolver; }; -} - -#endif +} // namespace WebCore diff --git a/Source/WebCore/css/CSSUnicodeRangeValue.cpp b/Source/WebCore/css/CSSUnicodeRangeValue.cpp index 6c22e2e84..8426ceebe 100644 --- a/Source/WebCore/css/CSSUnicodeRangeValue.cpp +++ b/Source/WebCore/css/CSSUnicodeRangeValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,9 +32,7 @@ namespace WebCore { String CSSUnicodeRangeValue::customCSSText() const { - String result; - // FIXME: Implement. - return result; + return String::format("U+%x-%x", m_from, m_to); } bool CSSUnicodeRangeValue::equals(const CSSUnicodeRangeValue& other) const diff --git a/Source/WebCore/css/CSSUnicodeRangeValue.h b/Source/WebCore/css/CSSUnicodeRangeValue.h index 2ec0188d3..2c58fe523 100644 --- a/Source/WebCore/css/CSSUnicodeRangeValue.h +++ b/Source/WebCore/css/CSSUnicodeRangeValue.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,18 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSUnicodeRangeValue_h -#define CSSUnicodeRangeValue_h +#pragma once #include "CSSValue.h" -#include -#include namespace WebCore { -class CSSUnicodeRangeValue : public CSSValue { +class CSSUnicodeRangeValue final : public CSSValue { public: - static PassRef create(UChar32 from, UChar32 to) + static Ref create(UChar32 from, UChar32 to) { return adoptRef(*new CSSUnicodeRangeValue(from, to)); } @@ -58,8 +55,6 @@ private: UChar32 m_to; }; -CSS_VALUE_TYPE_CASTS(CSSUnicodeRangeValue, isUnicodeRangeValue()) - } // namespace WebCore -#endif // CSSUnicodeRangeValue_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSUnicodeRangeValue, isUnicodeRangeValue()) diff --git a/Source/WebCore/css/CSSUnknownRule.h b/Source/WebCore/css/CSSUnknownRule.h index a74143a3c..be064530b 100644 --- a/Source/WebCore/css/CSSUnknownRule.h +++ b/Source/WebCore/css/CSSUnknownRule.h @@ -19,23 +19,26 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSUnknownRule_h -#define CSSUnknownRule_h +#pragma once #include "CSSRule.h" namespace WebCore { -class CSSUnknownRule : public CSSRule { +class CSSUnknownRule final : public CSSRule { public: - CSSUnknownRule() : CSSRule(0) { } + CSSUnknownRule() + : CSSRule(nullptr) + { + } + virtual ~CSSUnknownRule() { } - virtual CSSRule::Type type() const override { return UNKNOWN_RULE; } - virtual String cssText() const override { return String(); } - virtual void reattach(StyleRuleBase*) override { } + String cssText() const final { return String(); } + void reattach(StyleRuleBase&) final { } + +private: + CSSRule::Type type() const final { return UNKNOWN_RULE; } }; } // namespace WebCore - -#endif // CSSUnknownRule_h diff --git a/Source/WebCore/css/CSSUnknownRule.idl b/Source/WebCore/css/CSSUnknownRule.idl index 046a5e69e..6a6ae60ed 100644 --- a/Source/WebCore/css/CSSUnknownRule.idl +++ b/Source/WebCore/css/CSSUnknownRule.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2006 Samuel Weinig * * This library is free software; you can redistribute it and/or diff --git a/Source/WebCore/css/CSSUnsetValue.cpp b/Source/WebCore/css/CSSUnsetValue.cpp new file mode 100644 index 000000000..98472d73f --- /dev/null +++ b/Source/WebCore/css/CSSUnsetValue.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CSSUnsetValue.h" + +#include + +namespace WebCore { + +String CSSUnsetValue::customCSSText() const +{ + return ASCIILiteral("unset"); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSUnsetValue.h b/Source/WebCore/css/CSSUnsetValue.h new file mode 100644 index 000000000..edf717a2a --- /dev/null +++ b/Source/WebCore/css/CSSUnsetValue.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include + +namespace WebCore { + +class CSSUnsetValue final : public CSSValue { +public: + String customCSSText() const; + + bool equals(const CSSUnsetValue&) const { return true; } + +#if COMPILER(MSVC) + // FIXME: This should be private, but for some reason MSVC then fails to invoke it from LazyNeverDestroyed::construct. +public: +#else +private: + friend class LazyNeverDestroyed; +#endif + CSSUnsetValue() + : CSSValue(UnsetClass) + { + } +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSUnsetValue, isUnsetValue()) diff --git a/Source/WebCore/css/CSSValue.cpp b/Source/WebCore/css/CSSValue.cpp index 760e8d0ad..c619e8f80 100644 --- a/Source/WebCore/css/CSSValue.cpp +++ b/Source/WebCore/css/CSSValue.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,34 +28,46 @@ #include "config.h" #include "CSSValue.h" +#include "CSSAnimationTriggerScrollValue.h" #include "CSSAspectRatioValue.h" #include "CSSBorderImageSliceValue.h" #include "CSSCalculationValue.h" #include "CSSCanvasValue.h" +#include "CSSContentDistributionValue.h" #include "CSSCrossfadeValue.h" #include "CSSCursorImageValue.h" +#include "CSSCustomIdentValue.h" +#include "CSSCustomPropertyValue.h" #include "CSSFilterImageValue.h" #include "CSSFontFaceSrcValue.h" #include "CSSFontFeatureValue.h" #include "CSSFontValue.h" +#include "CSSFontVariationValue.h" #include "CSSFunctionValue.h" #include "CSSGradientValue.h" -#include "CSSGridTemplateValue.h" #include "CSSImageSetValue.h" #include "CSSImageValue.h" #include "CSSInheritedValue.h" #include "CSSInitialValue.h" #include "CSSLineBoxContainValue.h" +#include "CSSNamedImageValue.h" +#include "CSSPendingSubstitutionValue.h" #include "CSSPrimitiveValue.h" +#include "CSSProperty.h" #include "CSSReflectValue.h" #include "CSSShadowValue.h" #include "CSSTimingFunctionValue.h" #include "CSSUnicodeRangeValue.h" +#include "CSSUnsetValue.h" #include "CSSValueList.h" -#include "SVGColor.h" -#include "SVGPaint.h" -#include "WebKitCSSFilterValue.h" -#include "WebKitCSSTransformValue.h" +#include "CSSVariableReferenceValue.h" + +#include "CSSGridAutoRepeatValue.h" +#include "CSSGridLineNamesValue.h" +#include "CSSGridTemplateAreasValue.h" + +#include "DeprecatedCSSOMPrimitiveValue.h" +#include "DeprecatedCSSOMValueList.h" namespace WebCore { @@ -65,29 +77,9 @@ struct SameSizeAsCSSValue : public RefCounted { COMPILE_ASSERT(sizeof(CSSValue) == sizeof(SameSizeAsCSSValue), CSS_value_should_stay_small); -class TextCloneCSSValue : public CSSValue { -public: - static PassRef create(ClassType classType, const String& text) - { - return adoptRef(*new TextCloneCSSValue(classType, text)); - } - - String cssText() const { return m_cssText; } - -private: - TextCloneCSSValue(ClassType classType, const String& text) - : CSSValue(classType, /*isCSSOMSafe*/ true) - , m_cssText(text) - { - m_isTextClone = true; - } - - String m_cssText; -}; - bool CSSValue::isImplicitInitialValue() const { - return m_classType == InitialClass && toCSSInitialValue(this)->isImplicit(); + return m_classType == InitialClass && downcast(*this).isImplicit(); } CSSValue::Type CSSValue::cssValueType() const @@ -100,45 +92,27 @@ CSSValue::Type CSSValue::cssValueType() const return CSS_VALUE_LIST; if (isInitialValue()) return CSS_INITIAL; + if (isUnsetValue()) + return CSS_UNSET; + if (isRevertValue()) + return CSS_REVERT; return CSS_CUSTOM; } -void CSSValue::addSubresourceStyleURLs(ListHashSet& urls, const StyleSheetContents* styleSheet) const +bool CSSValue::traverseSubresources(const std::function& handler) const { - // This should get called for internal instances only. - ASSERT(!isCSSOMSafe()); - - if (isPrimitiveValue()) - toCSSPrimitiveValue(this)->addSubresourceStyleURLs(urls, styleSheet); - else if (isValueList()) - toCSSValueList(this)->addSubresourceStyleURLs(urls, styleSheet); - else if (classType() == FontFaceSrcClass) - toCSSFontFaceSrcValue(this)->addSubresourceStyleURLs(urls, styleSheet); - else if (classType() == ReflectClass) - toCSSReflectValue(this)->addSubresourceStyleURLs(urls, styleSheet); -} - -bool CSSValue::hasFailedOrCanceledSubresources() const -{ - // This should get called for internal instances only. - ASSERT(!isCSSOMSafe()); - - if (isValueList()) - return toCSSValueList(this)->hasFailedOrCanceledSubresources(); - if (classType() == FontFaceSrcClass) - return toCSSFontFaceSrcValue(this)->hasFailedOrCanceledSubresources(); - if (classType() == ImageClass) - return toCSSImageValue(this)->hasFailedOrCanceledSubresources(); - if (classType() == CrossfadeClass) - return toCSSCrossfadeValue(this)->hasFailedOrCanceledSubresources(); -#if ENABLE(CSS_FILTERS) - if (classType() == FilterImageClass) - return toCSSFilterImageValue(this)->hasFailedOrCanceledSubresources(); -#endif -#if ENABLE(CSS_IMAGE_SET) - if (classType() == ImageSetClass) - return toCSSImageSetValue(this)->hasFailedOrCanceledSubresources(); -#endif + if (is(*this)) + return downcast(*this).traverseSubresources(handler); + if (is(*this)) + return downcast(*this).traverseSubresources(handler); + if (is(*this)) + return downcast(*this).traverseSubresources(handler); + if (is(*this)) + return downcast(*this).traverseSubresources(handler); + if (is(*this)) + return downcast(*this).traverseSubresources(handler); + if (is(*this)) + return downcast(*this).traverseSubresources(handler); return false; } @@ -150,11 +124,6 @@ inline static bool compareCSSValues(const CSSValue& first, const CSSValue& secon bool CSSValue::equals(const CSSValue& other) const { - if (m_isTextClone) { - ASSERT(isCSSOMSafe()); - return static_cast(this)->cssText() == other.cssText(); - } - if (m_classType == other.m_classType) { switch (m_classType) { case AspectRatioClass: @@ -163,18 +132,22 @@ bool CSSValue::equals(const CSSValue& other) const return compareCSSValues(*this, other); case CanvasClass: return compareCSSValues(*this, other); + case NamedImageClass: + return compareCSSValues(*this, other); case CursorImageClass: return compareCSSValues(*this, other); -#if ENABLE(CSS_FILTERS) case FilterImageClass: return compareCSSValues(*this, other); -#endif case FontClass: return compareCSSValues(*this, other); case FontFaceSrcClass: return compareCSSValues(*this, other); case FontFeatureClass: return compareCSSValues(*this, other); +#if ENABLE(VARIATION_FONTS) + case FontVariationClass: + return compareCSSValues(*this, other); +#endif case FunctionClass: return compareCSSValues(*this, other); case LinearGradientClass: @@ -189,8 +162,16 @@ bool CSSValue::equals(const CSSValue& other) const return compareCSSValues(*this, other); case InitialClass: return compareCSSValues(*this, other); - case GridTemplateClass: - return compareCSSValues(*this, other); + case UnsetClass: + return compareCSSValues(*this, other); + case RevertClass: + return compareCSSValues(*this, other); + case GridAutoRepeatClass: + return compareCSSValues(*this, other); + case GridLineNamesClass: + return compareCSSValues(*this, other); + case GridTemplateAreasClass: + return compareCSSValues(*this, other); case PrimitiveClass: return compareCSSValues(*this, other); case ReflectClass: @@ -201,263 +182,279 @@ bool CSSValue::equals(const CSSValue& other) const return compareCSSValues(*this, other); case StepsTimingFunctionClass: return compareCSSValues(*this, other); + case SpringTimingFunctionClass: + return compareCSSValues(*this, other); case UnicodeRangeClass: return compareCSSValues(*this, other); case ValueListClass: return compareCSSValues(*this, other); - case WebKitCSSTransformClass: - return compareCSSValues(*this, other); case LineBoxContainClass: return compareCSSValues(*this, other); case CalculationClass: return compareCSSValues(*this, other); -#if ENABLE(CSS_IMAGE_SET) case ImageSetClass: return compareCSSValues(*this, other); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case AnimationTriggerScrollClass: + return compareCSSValues(*this, other); #endif -#if ENABLE(CSS_FILTERS) - case WebKitCSSFilterClass: - return compareCSSValues(*this, other); -#endif -#if ENABLE(SVG) - case SVGColorClass: - return compareCSSValues(*this, other); - case SVGPaintClass: - return compareCSSValues(*this, other); -#endif + case CSSContentDistributionClass: + return compareCSSValues(*this, other); + case CustomPropertyClass: + return compareCSSValues(*this, other); + case VariableReferenceClass: + return compareCSSValues(*this, other); + case PendingSubstitutionValueClass: + return compareCSSValues(*this, other); default: ASSERT_NOT_REACHED(); return false; } - } else if (m_classType == ValueListClass && other.m_classType != ValueListClass) - return toCSSValueList(this)->equals(other); - else if (m_classType != ValueListClass && other.m_classType == ValueListClass) + } else if (is(*this) && !is(other)) + return downcast(*this).equals(other); + else if (!is(*this) && is(other)) return static_cast(other).equals(*this); return false; } String CSSValue::cssText() const { - if (m_isTextClone) { - ASSERT(isCSSOMSafe()); - return static_cast(this)->cssText(); - } - ASSERT(!isCSSOMSafe() || isSubtypeExposedToCSSOM()); - switch (classType()) { case AspectRatioClass: - return toCSSAspectRatioValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case BorderImageSliceClass: - return toCSSBorderImageSliceValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case CanvasClass: - return toCSSCanvasValue(this)->customCSSText(); + return downcast(*this).customCSSText(); + case NamedImageClass: + return downcast(*this).customCSSText(); case CursorImageClass: - return toCSSCursorImageValue(this)->customCSSText(); -#if ENABLE(CSS_FILTERS) + return downcast(*this).customCSSText(); case FilterImageClass: - return toCSSFilterImageValue(this)->customCSSText(); -#endif + return downcast(*this).customCSSText(); case FontClass: - return toCSSFontValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case FontFaceSrcClass: - return toCSSFontFaceSrcValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case FontFeatureClass: - return toCSSFontFeatureValue(this)->customCSSText(); + return downcast(*this).customCSSText(); +#if ENABLE(VARIATION_FONTS) + case FontVariationClass: + return downcast(*this).customCSSText(); +#endif case FunctionClass: - return toCSSFunctionValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case LinearGradientClass: - return toCSSLinearGradientValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case RadialGradientClass: - return toCSSRadialGradientValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case CrossfadeClass: - return toCSSCrossfadeValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case ImageClass: - return toCSSImageValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case InheritedClass: - return toCSSInheritedValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case InitialClass: - return toCSSInitialValue(this)->customCSSText(); - case GridTemplateClass: - return toCSSGridTemplateValue(this)->customCSSText(); + return downcast(*this).customCSSText(); + case UnsetClass: + return downcast(*this).customCSSText(); + case RevertClass: + return downcast(*this).customCSSText(); + case GridAutoRepeatClass: + return downcast(*this).customCSSText(); + case GridLineNamesClass: + return downcast(*this).customCSSText(); + case GridTemplateAreasClass: + return downcast(*this).customCSSText(); case PrimitiveClass: - return toCSSPrimitiveValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case ReflectClass: - return toCSSReflectValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case ShadowClass: - return toCSSShadowValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case CubicBezierTimingFunctionClass: - return toCSSCubicBezierTimingFunctionValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case StepsTimingFunctionClass: - return toCSSStepsTimingFunctionValue(this)->customCSSText(); + return downcast(*this).customCSSText(); + case SpringTimingFunctionClass: + return downcast(*this).customCSSText(); case UnicodeRangeClass: - return toCSSUnicodeRangeValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case ValueListClass: - return toCSSValueList(this)->customCSSText(); - case WebKitCSSTransformClass: - return toWebKitCSSTransformValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case LineBoxContainClass: - return toCSSLineBoxContainValue(this)->customCSSText(); + return downcast(*this).customCSSText(); case CalculationClass: - return toCSSCalcValue(this)->customCSSText(); -#if ENABLE(CSS_IMAGE_SET) + return downcast(*this).customCSSText(); case ImageSetClass: - return toCSSImageSetValue(this)->customCSSText(); -#endif -#if ENABLE(CSS_FILTERS) - case WebKitCSSFilterClass: - return toWebKitCSSFilterValue(this)->customCSSText(); -#endif -#if ENABLE(SVG) - case SVGColorClass: - return toSVGColor(this)->customCSSText(); - case SVGPaintClass: - return toSVGPaint(this)->customCSSText(); + return downcast(*this).customCSSText(); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case AnimationTriggerScrollClass: + return downcast(*this).customCSSText(); #endif + case CSSContentDistributionClass: + return downcast(*this).customCSSText(); + case CustomPropertyClass: + return downcast(*this).customCSSText(); + case CustomIdentClass: + return downcast(*this).customCSSText(); + case VariableReferenceClass: + return downcast(*this).customCSSText(); + case PendingSubstitutionValueClass: + return downcast(*this).customCSSText(); } + ASSERT_NOT_REACHED(); return String(); } void CSSValue::destroy() { - if (m_isTextClone) { - ASSERT(isCSSOMSafe()); - delete static_cast(this); - return; - } - ASSERT(!isCSSOMSafe() || isSubtypeExposedToCSSOM()); - switch (classType()) { case AspectRatioClass: - delete toCSSAspectRatioValue(this); + delete downcast(this); return; case BorderImageSliceClass: - delete toCSSBorderImageSliceValue(this); + delete downcast(this); return; case CanvasClass: - delete toCSSCanvasValue(this); + delete downcast(this); + return; + case NamedImageClass: + delete downcast(this); return; case CursorImageClass: - delete toCSSCursorImageValue(this); + delete downcast(this); return; case FontClass: - delete toCSSFontValue(this); + delete downcast(this); return; case FontFaceSrcClass: - delete toCSSFontFaceSrcValue(this); + delete downcast(this); return; case FontFeatureClass: - delete toCSSFontFeatureValue(this); + delete downcast(this); + return; +#if ENABLE(VARIATION_FONTS) + case FontVariationClass: + delete downcast(this); return; +#endif case FunctionClass: - delete toCSSFunctionValue(this); + delete downcast(this); return; case LinearGradientClass: - delete toCSSLinearGradientValue(this); + delete downcast(this); return; case RadialGradientClass: - delete toCSSRadialGradientValue(this); + delete downcast(this); return; case CrossfadeClass: - delete toCSSCrossfadeValue(this); + delete downcast(this); return; case ImageClass: - delete toCSSImageValue(this); + delete downcast(this); return; case InheritedClass: - delete toCSSInheritedValue(this); + delete downcast(this); return; case InitialClass: - delete toCSSInitialValue(this); + delete downcast(this); + return; + case UnsetClass: + delete downcast(this); return; - case GridTemplateClass: - delete toCSSGridTemplateValue(this); + case RevertClass: + delete downcast(this); + return; + case GridAutoRepeatClass: + delete downcast(this); + return; + case GridLineNamesClass: + delete downcast(this); + return; + case GridTemplateAreasClass: + delete downcast(this); return; case PrimitiveClass: - delete toCSSPrimitiveValue(this); + delete downcast(this); return; case ReflectClass: - delete toCSSReflectValue(this); + delete downcast(this); return; case ShadowClass: - delete toCSSShadowValue(this); + delete downcast(this); return; case CubicBezierTimingFunctionClass: - delete toCSSCubicBezierTimingFunctionValue(this); + delete downcast(this); return; case StepsTimingFunctionClass: - delete toCSSStepsTimingFunctionValue(this); + delete downcast(this); + return; + case SpringTimingFunctionClass: + delete downcast(this); return; case UnicodeRangeClass: - delete toCSSUnicodeRangeValue(this); + delete downcast(this); return; case ValueListClass: - delete toCSSValueList(this); - return; - case WebKitCSSTransformClass: - delete toWebKitCSSTransformValue(this); + delete downcast(this); return; case LineBoxContainClass: - delete toCSSLineBoxContainValue(this); + delete downcast(this); return; case CalculationClass: - delete toCSSCalcValue(this); + delete downcast(this); return; -#if ENABLE(CSS_IMAGE_SET) case ImageSetClass: - delete toCSSImageSetValue(this); + delete downcast(this); return; -#endif -#if ENABLE(CSS_FILTERS) case FilterImageClass: - delete toCSSFilterImageValue(this); + delete downcast(this); return; - case WebKitCSSFilterClass: - delete toWebKitCSSFilterValue(this); +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + case AnimationTriggerScrollClass: + delete downcast(this); return; #endif -#if ENABLE(SVG) - case SVGColorClass: - delete toSVGColor(this); + case CSSContentDistributionClass: + delete downcast(this); return; - case SVGPaintClass: - delete toSVGPaint(this); + case CustomPropertyClass: + delete downcast(this); + return; + case CustomIdentClass: + delete downcast(this); + return; + case VariableReferenceClass: + delete downcast(this); + return; + case PendingSubstitutionValueClass: + delete downcast(this); return; -#endif } ASSERT_NOT_REACHED(); } -PassRefPtr CSSValue::cloneForCSSOM() const +Ref CSSValue::createDeprecatedCSSOMWrapper() const { - switch (classType()) { - case PrimitiveClass: - return toCSSPrimitiveValue(this)->cloneForCSSOM(); - case ValueListClass: - return toCSSValueList(this)->cloneForCSSOM(); - case ImageClass: - case CursorImageClass: - return toCSSImageValue(this)->cloneForCSSOM(); -#if ENABLE(CSS_FILTERS) - case WebKitCSSFilterClass: - return toWebKitCSSFilterValue(this)->cloneForCSSOM(); -#endif - case WebKitCSSTransformClass: - return toWebKitCSSTransformValue(this)->cloneForCSSOM(); -#if ENABLE(CSS_IMAGE_SET) - case ImageSetClass: - return toCSSImageSetValue(this)->cloneForCSSOM(); -#endif -#if ENABLE(SVG) - case SVGColorClass: - return toSVGColor(this)->cloneForCSSOM(); - case SVGPaintClass: - return toSVGPaint(this)->cloneForCSSOM(); -#endif - default: - ASSERT(!isSubtypeExposedToCSSOM()); - return TextCloneCSSValue::create(classType(), cssText()); - } + if (isImageValue() || isCursorImageValue()) + return downcast(this)->createDeprecatedCSSOMWrapper(); + if (isPrimitiveValue()) + return DeprecatedCSSOMPrimitiveValue::create(downcast(*this)); + if (isValueList()) + return DeprecatedCSSOMValueList::create(downcast(*this)); + return DeprecatedCSSOMComplexValue::create(*this); +} + +bool CSSValue::treatAsInheritedValue(CSSPropertyID propertyID) const +{ + return classType() == InheritedClass || (classType() == UnsetClass && CSSProperty::isInheritedProperty(propertyID)); +} + +bool CSSValue::treatAsInitialValue(CSSPropertyID propertyID) const +{ + return classType() == InitialClass || (classType() == UnsetClass && !CSSProperty::isInheritedProperty(propertyID)); } } diff --git a/Source/WebCore/css/CSSValue.h b/Source/WebCore/css/CSSValue.h index 942b793df..47c62087e 100644 --- a/Source/WebCore/css/CSSValue.h +++ b/Source/WebCore/css/CSSValue.h @@ -18,24 +18,25 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSValue_h -#define CSSValue_h +#pragma once -#include "ExceptionCode.h" +#include "ExceptionOr.h" #include "URLHash.h" +#include #include #include #include +#include namespace WebCore { +class CSSCustomPropertyValue; +class CachedResource; +class DeprecatedCSSOMValue; class StyleSheetContents; - -// FIXME: The current CSSValue and subclasses should be turned into internal types (StyleValue). -// The few subtypes that are actually exposed in CSSOM can be seen in the cloneForCSSOM() function. -// They should be handled by separate wrapper classes. -// Please don't expose more CSSValue types to the web. +enum CSSPropertyID : uint16_t; + class CSSValue : public RefCounted { public: enum Type { @@ -43,8 +44,9 @@ public: CSS_PRIMITIVE_VALUE = 1, CSS_VALUE_LIST = 2, CSS_CUSTOM = 3, - CSS_INITIAL = 4 - + CSS_INITIAL = 4, + CSS_UNSET = 5, + CSS_REVERT = 6 }; // Override RefCounted's deref() to ensure operator delete is called on @@ -56,9 +58,7 @@ public: } Type cssValueType() const; - String cssText() const; - void setCssText(const String&, ExceptionCode&) { } // FIXME: Not implemented. bool isPrimitiveValue() const { return m_classType == PrimitiveClass; } bool isValueList() const { return m_classType >= ValueListClass; } @@ -71,56 +71,58 @@ public: bool isCanvasValue() const { return m_classType == CanvasClass; } bool isCrossfadeValue() const { return m_classType == CrossfadeClass; } bool isCursorImageValue() const { return m_classType == CursorImageClass; } + bool isCustomPropertyValue() const { return m_classType == CustomPropertyClass; } bool isFunctionValue() const { return m_classType == FunctionClass; } bool isFontFeatureValue() const { return m_classType == FontFeatureClass; } +#if ENABLE(VARIATION_FONTS) + bool isFontVariationValue() const { return m_classType == FontVariationClass; } +#endif bool isFontFaceSrcValue() const { return m_classType == FontFaceSrcClass; } bool isFontValue() const { return m_classType == FontClass; } bool isImageGeneratorValue() const { return m_classType >= CanvasClass && m_classType <= RadialGradientClass; } bool isGradientValue() const { return m_classType >= LinearGradientClass && m_classType <= RadialGradientClass; } -#if ENABLE(CSS_IMAGE_SET) + bool isNamedImageValue() const { return m_classType == NamedImageClass; } bool isImageSetValue() const { return m_classType == ImageSetClass; } -#endif bool isImageValue() const { return m_classType == ImageClass; } bool isImplicitInitialValue() const; bool isInheritedValue() const { return m_classType == InheritedClass; } bool isInitialValue() const { return m_classType == InitialClass; } + bool isUnsetValue() const { return m_classType == UnsetClass; } + bool isRevertValue() const { return m_classType == RevertClass; } + bool treatAsInitialValue(CSSPropertyID) const; + bool treatAsInheritedValue(CSSPropertyID) const; bool isLinearGradientValue() const { return m_classType == LinearGradientClass; } bool isRadialGradientValue() const { return m_classType == RadialGradientClass; } bool isReflectValue() const { return m_classType == ReflectClass; } bool isShadowValue() const { return m_classType == ShadowClass; } bool isCubicBezierTimingFunctionValue() const { return m_classType == CubicBezierTimingFunctionClass; } bool isStepsTimingFunctionValue() const { return m_classType == StepsTimingFunctionClass; } - bool isWebKitCSSTransformValue() const { return m_classType == WebKitCSSTransformClass; } + bool isSpringTimingFunctionValue() const { return m_classType == SpringTimingFunctionClass; } bool isLineBoxContainValue() const { return m_classType == LineBoxContainClass; } bool isCalcValue() const {return m_classType == CalculationClass; } -#if ENABLE(CSS_FILTERS) bool isFilterImageValue() const { return m_classType == FilterImageClass; } - bool isWebKitCSSFilterValue() const { return m_classType == WebKitCSSFilterClass; } -#endif // ENABLE(CSS_FILTERS) - bool isGridTemplateValue() const { return m_classType == GridTemplateClass; } -#if ENABLE(SVG) - bool isSVGColor() const { return m_classType == SVGColorClass || m_classType == SVGPaintClass; } - bool isSVGPaint() const { return m_classType == SVGPaintClass; } -#endif + bool isContentDistributionValue() const { return m_classType == CSSContentDistributionClass; } + bool isGridAutoRepeatValue() const { return m_classType == GridAutoRepeatClass; } + bool isGridTemplateAreasValue() const { return m_classType == GridTemplateAreasClass; } + bool isGridLineNamesValue() const { return m_classType == GridLineNamesClass; } bool isUnicodeRangeValue() const { return m_classType == UnicodeRangeClass; } - bool isCSSOMSafe() const { return m_isCSSOMSafe; } - bool isSubtypeExposedToCSSOM() const - { - return isPrimitiveValue() -#if ENABLE(SVG) - || isSVGColor() +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + bool isAnimationTriggerScrollValue() const { return m_classType == AnimationTriggerScrollClass; } #endif - || isValueList(); - } - PassRefPtr cloneForCSSOM() const; + bool isCustomIdentValue() const { return m_classType == CustomIdentClass; } + bool isVariableReferenceValue() const { return m_classType == VariableReferenceClass; } + bool isPendingSubstitutionValue() const { return m_classType == PendingSubstitutionValueClass; } + + bool hasVariableReferences() const { return isVariableReferenceValue() || isPendingSubstitutionValue(); } - void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; + Ref createDeprecatedCSSOMWrapper() const; - bool hasFailedOrCanceledSubresources() const; + bool traverseSubresources(const std::function& handler) const; bool equals(const CSSValue&) const; + bool operator==(const CSSValue& other) const { return equals(other); } protected: @@ -134,51 +136,62 @@ protected: // Image generator classes. CanvasClass, + NamedImageClass, CrossfadeClass, -#if ENABLE(CSS_FILTERS) FilterImageClass, -#endif LinearGradientClass, RadialGradientClass, // Timing function classes. CubicBezierTimingFunctionClass, StepsTimingFunctionClass, + SpringTimingFunctionClass, // Other class types. AspectRatioClass, BorderImageSliceClass, FontFeatureClass, +#if ENABLE(VARIATION_FONTS) + FontVariationClass, +#endif FontClass, FontFaceSrcClass, FunctionClass, InheritedClass, InitialClass, + UnsetClass, + RevertClass, ReflectClass, ShadowClass, UnicodeRangeClass, LineBoxContainClass, CalculationClass, - GridTemplateClass, -#if ENABLE(SVG) - SVGColorClass, - SVGPaintClass, + GridTemplateAreasClass, +#if ENABLE(CSS_ANIMATIONS_LEVEL_2) + AnimationTriggerScrollClass, #endif - // List class types must appear after ValueListClass. + CSSContentDistributionClass, + + CustomIdentClass, + + CustomPropertyClass, + VariableReferenceClass, + PendingSubstitutionValueClass, + + // List class types must appear after ValueListClass. Note CSSFunctionValue + // is deliberately excluded, since we don't want it exposed to the CSS OM + // as a list. ValueListClass, -#if ENABLE(CSS_IMAGE_SET) ImageSetClass, -#endif -#if ENABLE(CSS_FILTERS) - WebKitCSSFilterClass, -#endif - WebKitCSSTransformClass, + GridLineNamesClass, + GridAutoRepeatClass, // Do not append non-list class types here. }; +public: static const size_t ValueListSeparatorBits = 2; enum ValueListSeparator { SpaceSeparator, @@ -186,12 +199,11 @@ protected: SlashSeparator }; +protected: ClassType classType() const { return static_cast(m_classType); } - explicit CSSValue(ClassType classType, bool isCSSOMSafe = false) - : m_isCSSOMSafe(isCSSOMSafe) - , m_isTextClone(false) - , m_primitiveUnitType(0) + explicit CSSValue(ClassType classType) + : m_primitiveUnitType(0) , m_hasCachedCSSText(false) , m_isQuirkValue(false) , m_valueListSeparator(SpaceSeparator) @@ -205,16 +217,14 @@ protected: ~CSSValue() { } private: - void destroy(); + WEBCORE_EXPORT void destroy(); protected: - unsigned m_isCSSOMSafe : 1; - unsigned m_isTextClone : 1; // The bits in this section are only used by specific subclasses but kept here // to maximize struct packing. // CSSPrimitiveValue bits: - unsigned m_primitiveUnitType : 7; // CSSPrimitiveValue::UnitTypes + unsigned m_primitiveUnitType : 7; // CSSPrimitiveValue::UnitType mutable unsigned m_hasCachedCSSText : 1; unsigned m_isQuirkValue : 1; @@ -222,19 +232,21 @@ protected: private: unsigned m_classType : ClassTypeBits; // ClassType + +friend class CSSValueList; }; template -inline bool compareCSSValueVector(const Vector>& firstVector, const Vector>& secondVector) +inline bool compareCSSValueVector(const Vector>& firstVector, const Vector>& secondVector) { size_t size = firstVector.size(); if (size != secondVector.size()) return false; - for (size_t i = 0; i < size; i++) { - const RefPtr& firstPtr = firstVector[i]; - const RefPtr& secondPtr = secondVector[i]; - if (firstPtr == secondPtr || (firstPtr && secondPtr && firstPtr->equals(*secondPtr))) + for (size_t i = 0; i < size; ++i) { + auto& firstPtr = firstVector[i]; + auto& secondPtr = secondVector[i]; + if (firstPtr.ptr() == secondPtr.ptr() || firstPtr->equals(secondPtr)) continue; return false; } @@ -250,12 +262,14 @@ inline bool compareCSSValuePtr(const RefPtr& first, const RefPtr inline bool compareCSSValue(const Ref& first, const Ref& second) { - return first.get().equals(second.get()); + return first.get().equals(second); } -#define CSS_VALUE_TYPE_CASTS(ToValueTypeName, predicate) \ - TYPE_CASTS_BASE(ToValueTypeName, CSSValue, value, value->predicate, value.predicate) +typedef HashMap> CustomPropertyValueMap; } // namespace WebCore -#endif // CSSValue_h +#define SPECIALIZE_TYPE_TRAITS_CSS_VALUE(ToValueTypeName, predicate) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ + static bool isType(const WebCore::CSSValue& value) { return value.predicate; } \ +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/css/CSSValue.idl b/Source/WebCore/css/CSSValue.idl deleted file mode 100644 index f7f766c17..000000000 --- a/Source/WebCore/css/CSSValue.idl +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -[ - CustomToJSObject, - CustomIsReachable, - JSCustomFinalize, - ObjCPolymorphic, - ImplementationLacksVTable -] interface CSSValue { - - // UnitTypes - const unsigned short CSS_INHERIT = 0; - const unsigned short CSS_PRIMITIVE_VALUE = 1; - const unsigned short CSS_VALUE_LIST = 2; - const unsigned short CSS_CUSTOM = 3; - - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString cssText; - - readonly attribute unsigned short cssValueType; - -}; - diff --git a/Source/WebCore/css/CSSValueKeywords.in b/Source/WebCore/css/CSSValueKeywords.in index 261344db4..8f260c4bd 100644 --- a/Source/WebCore/css/CSSValueKeywords.in +++ b/Source/WebCore/css/CSSValueKeywords.in @@ -3,6 +3,9 @@ // inherit initial +unset +revert + // // CSS_PROP_OUTLINE_STYLE // CSS_PROP_BORDER_TOP_STYLE @@ -45,6 +48,9 @@ small-caption -apple-system-short-footnote -apple-system-short-caption1 -apple-system-tall-body +-apple-system-title1 +-apple-system-title2 +-apple-system-title3 #endif // This has to go after the -apple-system versions. @@ -64,15 +70,53 @@ all //normal small-caps -// -webkit-font-variant-ligatures: +// font-variant-ligatures: // -// normal common-ligatures no-common-ligatures discretionary-ligatures no-discretionary-ligatures historical-ligatures no-historical-ligatures +contextual +no-contextual + +// font-variant-caps +// +// FIXME: Unify this with plain font-variant +// small-caps +all-small-caps +petite-caps +all-petite-caps +unicase +titling-caps + +// font-variant-numeric +// +lining-nums +oldstyle-nums +proportional-nums +tabular-nums +diagonal-fractions +stacked-fractions +ordinal +slashed-zero + +// font-variant-alternates +// +historical-forms + +// font-variant-east-asian +// +jis78 +jis83 +jis90 +jis04 +simplified +traditional +full-width +proportional-width +ruby // // CSS_PROP_FONT_WEIGHT: @@ -101,8 +145,10 @@ large x-large xx-large -webkit-xxx-large +-webkit-ruby-text smaller larger + // // CSS_PROP_FONT_STRETCH: // @@ -160,6 +206,7 @@ buttonface buttonhighlight buttonshadow buttontext +activebuttontext captiontext graytext highlight @@ -180,6 +227,16 @@ threedshadow window windowframe windowtext +-apple-wireless-playback-target-active +-apple-system-blue +-apple-system-brown +-apple-system-gray +-apple-system-green +-apple-system-orange +-apple-system-pink +-apple-system-purple +-apple-system-red +-apple-system-yellow -webkit-focus-ring-color currentcolor // @@ -244,10 +301,7 @@ justify //auto //none inter-word -inter-ideograph -inter-cluster distribute -kashida // // CSS_PROP_LIST_STYLE_POSITION: // @@ -345,7 +399,6 @@ katakana-iroha inline block list-item -run-in compact inline-block table @@ -360,10 +413,13 @@ table-cell table-caption -webkit-box -webkit-inline-box +flex -webkit-flex +inline-flex -webkit-inline-flex --webkit-grid --webkit-inline-grid +contents +grid +inline-grid //none // // CSS_PROP_CURSOR: @@ -382,8 +438,8 @@ alias progress no-drop not-allowed --webkit-zoom-in --webkit-zoom-out +zoom-in +zoom-out e-resize ne-resize nw-resize @@ -404,6 +460,8 @@ help all-scroll -webkit-grab -webkit-grabbing +-webkit-zoom-in +-webkit-zoom-out // none // // CSS_PROP_CURSOR_VISIBILITY: @@ -452,6 +510,7 @@ hand hide higher invert +inverted -webkit-isolate -webkit-isolate-override -webkit-plaintext @@ -464,7 +523,6 @@ line-through local loud lower --webkit-marquee mix no-close-quote no-open-quote @@ -486,6 +544,7 @@ thin underline wavy ink +objects -webkit-nowrap // CSS3 Values @@ -528,6 +587,7 @@ flex-end // center space-between space-around +space-evenly // stretch // CSS_PROP_ALIGN_ITEMS / CSS_PROP_ALIGN_SELF @@ -535,14 +595,37 @@ space-around // flex-end // center // baseline +last-baseline // stretch // CSS_PROP_JUSTIFY_CONTENT +// start +// end // flex-start // flex-end // center // space-between // space-around +// space-evenly +// stretch + +// CSS_PROP_JUSTIFY_ITEMS / CSS_PROP_JUSTIFY_SELF +// auto +// stretch +// baseline +// last-baseline +// center +// start +// end +self-start +self-end +// flex-start +// flex-end +// left +// right +unsafe +safe +legacy // CSS_PROP_FLEX_FLOW row @@ -639,6 +722,7 @@ skip-white-space // CSS_PROP_WORD_BREAK // break-all +keep-all // // CSS_PROP_WORD_WRAP @@ -670,31 +754,32 @@ button button-bevel default-button inner-spin-button --webkit-input-speech-button listbox listitem +media-controls-background +media-controls-dark-bar-background +media-controls-fullscreen-background +media-controls-light-bar-background +media-current-time-display media-enter-fullscreen-button media-exit-fullscreen-button media-fullscreen-volume-slider media-fullscreen-volume-slider-thumb media-mute-button -media-play-button media-overlay-play-button +media-play-button +media-return-to-realtime-button +media-rewind-button media-seek-back-button media-seek-forward-button -media-rewind-button -media-return-to-realtime-button -media-toggle-closed-captions-button media-slider media-sliderthumb -media-volume-slider-container +media-time-remaining-display +media-toggle-closed-captions-button media-volume-slider -media-volume-sliderthumb +media-volume-slider-container media-volume-slider-mute-button -media-controls-background -media-controls-fullscreen-background -media-current-time-display -media-time-remaining-display +media-volume-sliderthumb menulist menulist-button menulist-text @@ -718,8 +803,16 @@ relevancy-level-indicator continuous-capacity-level-indicator discrete-capacity-level-indicator rating-level-indicator +#if defined(ENABLE_SERVICE_CONTROLS) && ENABLE_SERVICE_CONTROLS +image-controls-button +#endif +#if defined(ENABLE_APPLE_PAY) && ENABLE_APPLE_PAY +-apple-pay-button +#endif textarea -// An appearance value that should not be accepted by the parser: +#if defined(ENABLE_ATTACHMENT_ELEMENT) && ENABLE_ATTACHMENT_ELEMENT +attachment +#endif caps-lock-indicator // @@ -742,11 +835,28 @@ content-box padding padding-box -// CSS_SHAPES +// +// Variables Implementation +// +var +-internal-variable-value + +// +// CSS_PROP_BREAK_BEFORE/AFTER/INSIDE +// +avoid-column +avoid-page +avoid-region +page +recto +region +verso + +// CSS Shapes margin-box // clip-path -bounding-box +view-box // // background-size @@ -871,10 +981,6 @@ geometricPrecision economy exact -// -webkit-color-correction -//default -sRGB - #if defined(ENABLE_VIEW_MODE_CSS_MEDIA) && ENABLE_VIEW_MODE_CSS_MEDIA // (-webkit-view-mode:) media feature: floating @@ -919,6 +1025,7 @@ horizontal-bt // -webkit-ruby-position after before +inter-character // -webkit-text-emphasis-position over @@ -948,66 +1055,71 @@ sideways sideways-right upright vertical-right +mixed // -webkit-line-box-contain font glyphs inline-box +initial-letter replaced -// -webkit-font-feature-settings +// font-feature-settings on off // image-rendering // auto -// optimizeSpeed -optimizeQuality +// optimizeSpeed (deprecated) +optimizeQuality // ( deprecated) +crisp-edges +pixelated -webkit-crisp-edges -webkit-optimize-contrast -// -webkit-shape-inside -// -webkit-shape-outside +// shape-outside nonzero evenodd -outside-shape at // closest-side // farthest-side +#if defined(ENABLE_CSS_SCROLL_SNAP) +// -webkit-scroll-snap-points-x +// -webkit-scroll-snap-points-y +elements + +// -webkit-scroll-snap-type +mandatory +proximity +x +y +#endif + // -webkit-region-fragment // auto break -// -webkit-wrap-flow -// auto -// both -// left -// right -maximum -// clear - -// -webkit-wrap-through wrap -// none // -webkit-line-align edges -#if (defined(ENABLE_SVG) && ENABLE_SVG) || (defined(ENABLE_CSS3_TEXT) && ENABLE_CSS3_TEXT) alphabetic -#endif // position -#if defined(ENABLE_CSS_STICKY_POSITION) && ENABLE_CSS_STICKY_POSITION -webkit-sticky -#endif // CSS_STICKY_POSITION // (pointer:) media feature // none coarse fine +// (hover:) media feature. +// none +hover +on-demand + // blend modes // normal multiply @@ -1025,6 +1137,12 @@ hue saturation color luminosity +// plus-darker +// plus-lighter + +// isolation +// auto +isolate // object-fit // fill @@ -1033,6 +1151,99 @@ luminosity // none scale-down +// background-image, etc. +container-scroll +cross-fade +image-set +linear-gradient +radial-gradient +repeating-linear-gradient +repeating-radial-gradient +-webkit-canvas +-webkit-cross-fade +-webkit-gradient +-webkit-linear-gradient +-webkit-radial-gradient +-webkit-repeating-linear-gradient +-webkit-repeating-radial-gradient +-webkit-image-set +-webkit-named-image +filter +-webkit-filter +dashboard-region + +// deprecated gradients +from +to +color-stop +radial + +// content +attr +counter +counters + +// clip +rect + +// shapes +polygon + +// @font-face src +format + +// (-webkit-)filter +// invert +grayscale +sepia +saturate +hue-rotate +opacity +brightness +contrast +blur +drop-shadow +url +cubic-bezier +spring +steps + +// colors +rgb +rgba +hsl +hsla +//color + +// transform +matrix +matrix3d +perspective +rotate +rotateX +rotateY +rotateZ +rotate3d +scale +scaleX +scaleY +scaleZ +scale3d +skew +skewX +skewY +translate +translateX +translateY +translateZ +translate3d + +// motion path +path + +calc +-webkit-calc + #if defined(ENABLE_CSS_IMAGE_RESOLUTION) && ENABLE_CSS_IMAGE_RESOLUTION from-image snap @@ -1042,9 +1253,23 @@ snap -webkit-paged-x -webkit-paged-y -// -webkit-grid-{column-start|column-end|row-start|row-end} +// paint-order +// normal +// fill +// stroke +markers + +// grid-{column-start|column-end|row-start|row-end} span +// grid-template-{columns|rows} +minmax +fit-content + +// grid-auto-flow +auto-flow +dense + #if defined(ENABLE_CSS3_TEXT) && ENABLE_CSS3_TEXT // text-indent -webkit-each-line @@ -1053,3 +1278,58 @@ span // -webkit-column-fill balance + +// -webkit-aspect-ratio +from-dimensions +from-intrinsic + +#if defined(ENABLE_CSS_TRAILING_WORD) && ENABLE_CSS_TRAILING_WORD +// -apple-trailing-word +-webkit-partially-balanced +#endif + +#if defined(ENABLE_APPLE_PAY) && ENABLE_APPLE_PAY +// -apple-pay-button-style +white-outline + +// -apple-pay-button-type +plain +buy +set-up +donate +#endif + +// font-synthesis +weight +style + +// will-change +scroll-position +//contents + +#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS +// touch-action +manipulation +#endif + +// hanging-punctuation +allow-end +first +force-end +last + +// color-gamut +p3 +rec2020 + +// color() function +sRGB +display-p3 + +// prefers-reduced-motion +reduce +no-preference + +// auto-repeat +auto-fill +auto-fit diff --git a/Source/WebCore/css/CSSValueList.cpp b/Source/WebCore/css/CSSValueList.cpp index 4b459603b..b6f65b77a 100644 --- a/Source/WebCore/css/CSSValueList.cpp +++ b/Source/WebCore/css/CSSValueList.cpp @@ -21,8 +21,10 @@ #include "config.h" #include "CSSValueList.h" -#include "CSSParserValues.h" -#include +#include "CSSCustomPropertyValue.h" +#include "CSSFunctionValue.h" +#include "CSSPrimitiveValue.h" +#include "DeprecatedCSSOMValue.h" #include namespace WebCore { @@ -39,40 +41,31 @@ CSSValueList::CSSValueList(ValueListSeparator listSeparator) m_valueListSeparator = listSeparator; } -CSSValueList::CSSValueList(CSSParserValueList& parserValues) - : CSSValue(ValueListClass) -{ - m_valueListSeparator = SpaceSeparator; - m_values.reserveInitialCapacity(parserValues.size()); - for (unsigned i = 0, size = parserValues.size(); i < size; ++i) - m_values.uncheckedAppend(parserValues.valueAt(i)->createCSSValue()); -} - -bool CSSValueList::removeAll(CSSValue* val) +bool CSSValueList::removeAll(CSSValue* value) { - bool found = false; - for (size_t index = 0; index < m_values.size(); index++) { - RefPtr& value = m_values.at(index); - if (value && val && value->equals(*val)) { - m_values.remove(index); - found = true; - } - } + // FIXME: Why even take a pointer? + if (!value) + return false; - return found; + return m_values.removeAllMatching([value](auto& current) { + return current->equals(*value); + }) > 0; } bool CSSValueList::hasValue(CSSValue* val) const { - for (size_t index = 0; index < m_values.size(); index++) { - const RefPtr& value = m_values.at(index); - if (value && val && value->equals(*val)) + // FIXME: Why even take a pointer? + if (!val) + return false; + + for (unsigned i = 0, size = m_values.size(); i < size; ++i) { + if (m_values[i].get().equals(*val)) return true; } return false; } -PassRefPtr CSSValueList::copy() +Ref CSSValueList::copy() { RefPtr newList; switch (m_valueListSeparator) { @@ -88,9 +81,9 @@ PassRefPtr CSSValueList::copy() default: ASSERT_NOT_REACHED(); } - for (size_t index = 0; index < m_values.size(); index++) - newList->append(m_values[index]); - return newList.release(); + for (auto& value : m_values) + newList->append(value.get()); + return newList.releaseNonNull(); } String CSSValueList::customCSSText() const @@ -111,11 +104,10 @@ String CSSValueList::customCSSText() const ASSERT_NOT_REACHED(); } - unsigned size = m_values.size(); - for (unsigned i = 0; i < size; i++) { + for (auto& value : m_values) { if (!result.isEmpty()) result.append(separator); - result.append(m_values[i]->cssText()); + result.append(value.get().cssText()); } return result.toString(); @@ -123,7 +115,17 @@ String CSSValueList::customCSSText() const bool CSSValueList::equals(const CSSValueList& other) const { - return m_valueListSeparator == other.m_valueListSeparator && compareCSSValueVector(m_values, other.m_values); + if (m_valueListSeparator != other.m_valueListSeparator) + return false; + + if (m_values.size() != other.m_values.size()) + return false; + + for (unsigned i = 0, size = m_values.size(); i < size; ++i) { + if (!m_values[i].get().equals(other.m_values[i])) + return false; + } + return true; } bool CSSValueList::equals(const CSSValue& other) const @@ -131,38 +133,16 @@ bool CSSValueList::equals(const CSSValue& other) const if (m_values.size() != 1) return false; - const RefPtr& value = m_values[0]; - return value && value->equals(other); -} - -void CSSValueList::addSubresourceStyleURLs(ListHashSet& urls, const StyleSheetContents* styleSheet) const -{ - size_t size = m_values.size(); - for (size_t i = 0; i < size; ++i) - m_values[i]->addSubresourceStyleURLs(urls, styleSheet); + return m_values[0].get().equals(other); } -bool CSSValueList::hasFailedOrCanceledSubresources() const +bool CSSValueList::traverseSubresources(const std::function& handler) const { for (unsigned i = 0; i < m_values.size(); ++i) { - if (m_values[i]->hasFailedOrCanceledSubresources()) + if (m_values[i].get().traverseSubresources(handler)) return true; } return false; } -CSSValueList::CSSValueList(const CSSValueList& cloneFrom) - : CSSValue(cloneFrom.classType(), /* isCSSOMSafe */ true) -{ - m_valueListSeparator = cloneFrom.m_valueListSeparator; - m_values.resize(cloneFrom.m_values.size()); - for (unsigned i = 0; i < m_values.size(); ++i) - m_values[i] = cloneFrom.m_values[i]->cloneForCSSOM(); -} - -PassRefPtr CSSValueList::cloneForCSSOM() const -{ - return adoptRef(new CSSValueList(*this)); -} - } // namespace WebCore diff --git a/Source/WebCore/css/CSSValueList.h b/Source/WebCore/css/CSSValueList.h index fa82a9ad0..b3300affe 100644 --- a/Source/WebCore/css/CSSValueList.h +++ b/Source/WebCore/css/CSSValueList.h @@ -18,99 +18,79 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSValueList_h -#define CSSValueList_h +#pragma once #include "CSSValue.h" -#include #include namespace WebCore { +class CSSCustomPropertyValue; +struct CSSParserValue; class CSSParserValueList; class CSSValueList : public CSSValue { public: - static PassRef createCommaSeparated() + typedef Vector, 4>::iterator iterator; + typedef Vector, 4>::const_iterator const_iterator; + + static Ref createCommaSeparated() { return adoptRef(*new CSSValueList(CommaSeparator)); } - static PassRef createSpaceSeparated() + static Ref createSpaceSeparated() { return adoptRef(*new CSSValueList(SpaceSeparator)); } - static PassRef createSlashSeparated() + static Ref createSlashSeparated() { return adoptRef(*new CSSValueList(SlashSeparator)); } - static PassRef createFromParserValueList(CSSParserValueList& list) - { - return adoptRef(*new CSSValueList(list)); - } size_t length() const { return m_values.size(); } - CSSValue* item(size_t index) { return index < m_values.size() ? m_values[index].get() : 0; } - const CSSValue* item(size_t index) const { return index < m_values.size() ? m_values[index].get() : 0; } - CSSValue* itemWithoutBoundsCheck(size_t index) { return m_values[index].get(); } - const CSSValue* itemWithoutBoundsCheck(size_t index) const { ASSERT(index < m_values.size()); return m_values[index].get(); } - - void append(PassRefPtr value) { m_values.append(value); } - void prepend(PassRefPtr value) { m_values.insert(0, value); } + CSSValue* item(size_t index) { return index < m_values.size() ? m_values[index].ptr() : nullptr; } + const CSSValue* item(size_t index) const { return index < m_values.size() ? m_values[index].ptr() : nullptr; } + CSSValue* itemWithoutBoundsCheck(size_t index) { return m_values[index].ptr(); } + const CSSValue* itemWithoutBoundsCheck(size_t index) const { ASSERT(index < m_values.size()); return m_values[index].ptr(); } + + const_iterator begin() const { return m_values.begin(); } + const_iterator end() const { return m_values.end(); } + iterator begin() { return m_values.begin(); } + iterator end() { return m_values.end(); } + + void append(Ref&&); + void prepend(Ref&&); bool removeAll(CSSValue*); bool hasValue(CSSValue*) const; - PassRefPtr copy(); + Ref copy(); String customCSSText() const; bool equals(const CSSValueList&) const; bool equals(const CSSValue&) const; - void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; + bool traverseSubresources(const std::function& handler) const; - bool hasFailedOrCanceledSubresources() const; - - PassRefPtr cloneForCSSOM() const; + unsigned separator() const { return m_valueListSeparator; } protected: CSSValueList(ClassType, ValueListSeparator); - CSSValueList(const CSSValueList& cloneFrom); private: explicit CSSValueList(ValueListSeparator); - explicit CSSValueList(CSSParserValueList&); - Vector, 4> m_values; + Vector, 4> m_values; }; -CSS_VALUE_TYPE_CASTS(CSSValueList, isValueList()) +inline void CSSValueList::append(Ref&& value) +{ + m_values.append(WTFMove(value)); +} -// Objects of this class are intended to be stack-allocated and scoped to a single function. -// Please take care not to pass these around as they do hold onto a raw pointer. -class CSSValueListInspector { -public: - CSSValueListInspector(CSSValue* value) : m_list((value && value->isValueList()) ? toCSSValueList(value) : 0) { } - CSSValue* item(size_t index) const { ASSERT_WITH_SECURITY_IMPLICATION(index < length()); return m_list->itemWithoutBoundsCheck(index); } - CSSValue* first() const { return item(0); } - CSSValue* second() const { return item(1); } - size_t length() const { return m_list ? m_list->length() : 0; } -private: - CSSValueList* m_list; -}; +inline void CSSValueList::prepend(Ref&& value) +{ + m_values.insert(0, WTFMove(value)); +} -// Wrapper that can be used to iterate over any CSSValue. Non-list values and 0 behave as zero-length lists. -// Objects of this class are intended to be stack-allocated and scoped to a single function. -// Please take care not to pass these around as they do hold onto a raw pointer. -class CSSValueListIterator { -public: - CSSValueListIterator(CSSValue* value) : m_inspector(value), m_position(0) { } - bool hasMore() const { return m_position < m_inspector.length(); } - CSSValue* value() const { return m_inspector.item(m_position); } - bool isPrimitiveValue() const { return value()->isPrimitiveValue(); } - void advance() { m_position++; ASSERT(m_position <= m_inspector.length());} - size_t index() const { return m_position; } -private: - CSSValueListInspector m_inspector; - size_t m_position; -}; } // namespace WebCore -#endif // CSSValueList_h +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSValueList, isValueList()) diff --git a/Source/WebCore/css/CSSValueList.idl b/Source/WebCore/css/CSSValueList.idl deleted file mode 100644 index d6e3e7961..000000000 --- a/Source/WebCore/css/CSSValueList.idl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Introduced in DOM Level 2: -[ - ImplementationLacksVTable, -] interface CSSValueList : CSSValue { - readonly attribute unsigned long length; - getter CSSValue item([Default=Undefined] optional unsigned long index); -}; - diff --git a/Source/WebCore/css/CSSValuePool.cpp b/Source/WebCore/css/CSSValuePool.cpp index 115bd9ba2..6f424c3c3 100644 --- a/Source/WebCore/css/CSSValuePool.cpp +++ b/Source/WebCore/css/CSSValuePool.cpp @@ -27,68 +27,78 @@ #include "CSSValuePool.h" #include "CSSParser.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSStyleSheet.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" namespace WebCore { -CSSValuePool& cssValuePool() +CSSValuePool& CSSValuePool::singleton() { - DEFINE_STATIC_LOCAL(CSSValuePool, pool, ()); + static NeverDestroyed pool; return pool; } CSSValuePool::CSSValuePool() - : m_inheritedValue(CSSInheritedValue::create()) - , m_implicitInitialValue(CSSInitialValue::createImplicit()) - , m_explicitInitialValue(CSSInitialValue::createExplicit()) - , m_colorTransparent(CSSPrimitiveValue::createColor(Color::transparent)) - , m_colorWhite(CSSPrimitiveValue::createColor(Color::white)) - , m_colorBlack(CSSPrimitiveValue::createColor(Color::black)) { + m_inheritedValue.construct(); + m_implicitInitialValue.construct(true); + m_explicitInitialValue.construct(false); + m_unsetValue.construct(); + m_revertValue.construct(); + + m_transparentColor.construct(Color(Color::transparent)); + m_whiteColor.construct(Color(Color::white)); + m_blackColor.construct(Color(Color::black)); + + for (unsigned i = 0; i < numCSSValueKeywords; ++i) + m_identifierValues[i].construct(static_cast(i)); + + for (unsigned i = 0; i < (maximumCacheableIntegerValue + 1); ++i) { + m_pixelValues[i].construct(i, CSSPrimitiveValue::CSS_PX); + m_percentValues[i].construct(i, CSSPrimitiveValue::CSS_PERCENTAGE); + m_numberValues[i].construct(i, CSSPrimitiveValue::CSS_NUMBER); + } } -PassRef CSSValuePool::createIdentifierValue(CSSValueID ident) +Ref CSSValuePool::createIdentifierValue(CSSValueID ident) { - if (!ident) - return CSSPrimitiveValue::createIdentifier(ident); - - RELEASE_ASSERT(ident > 0 && ident < numCSSValueKeywords); - if (!m_identifierValueCache[ident]) - m_identifierValueCache[ident] = CSSPrimitiveValue::createIdentifier(ident); - return *m_identifierValueCache[ident]; + RELEASE_ASSERT(ident >= 0 && ident < numCSSValueKeywords); + return m_identifierValues[ident].get(); } -PassRef CSSValuePool::createIdentifierValue(CSSPropertyID ident) +Ref CSSValuePool::createIdentifierValue(CSSPropertyID ident) { return CSSPrimitiveValue::createIdentifier(ident); } -PassRef CSSValuePool::createColorValue(unsigned rgbValue) +Ref CSSValuePool::createColorValue(const Color& color) { // These are the empty and deleted values of the hash table. - if (rgbValue == Color::transparent) - return m_colorTransparent.get(); - if (rgbValue == Color::white) - return m_colorWhite.get(); + if (color == Color::transparent) + return m_transparentColor.get(); + if (color == Color::white) + return m_whiteColor.get(); // Just because it is common. - if (rgbValue == Color::black) - return m_colorBlack.get(); + if (color == Color::black) + return m_blackColor.get(); // Remove one entry at random if the cache grows too large. const int maximumColorCacheSize = 512; if (m_colorValueCache.size() >= maximumColorCacheSize) m_colorValueCache.remove(m_colorValueCache.begin()); - ColorValueCache::AddResult entry = m_colorValueCache.add(rgbValue, nullptr); + ColorValueCache::AddResult entry = m_colorValueCache.add(color, nullptr); if (entry.isNewEntry) - entry.iterator->value = CSSPrimitiveValue::createColor(rgbValue); + entry.iterator->value = CSSPrimitiveValue::create(color); return *entry.iterator->value; } -PassRef CSSValuePool::createValue(double value, CSSPrimitiveValue::UnitTypes type) +Ref CSSValuePool::createValue(double value, CSSPrimitiveValue::UnitType type) { + ASSERT(std::isfinite(value)); + if (value < 0 || value > maximumCacheableIntegerValue) return CSSPrimitiveValue::create(value, type); @@ -96,35 +106,33 @@ PassRef CSSValuePool::createValue(double value, CSSPrimitiveV if (value != intValue) return CSSPrimitiveValue::create(value, type); - RefPtr* cache; switch (type) { case CSSPrimitiveValue::CSS_PX: - cache = m_pixelValueCache; - break; + return m_pixelValues[intValue].get(); case CSSPrimitiveValue::CSS_PERCENTAGE: - cache = m_percentValueCache; - break; + return m_percentValues[intValue].get(); case CSSPrimitiveValue::CSS_NUMBER: - cache = m_numberValueCache; - break; + return m_numberValues[intValue].get(); default: return CSSPrimitiveValue::create(value, type); } - - if (!cache[intValue]) - cache[intValue] = CSSPrimitiveValue::create(value, type); - return *cache[intValue]; } -PassRef CSSValuePool::createFontFamilyValue(const String& familyName) +Ref CSSValuePool::createFontFamilyValue(const String& familyName, FromSystemFontID fromSystemFontID) { - RefPtr& value = m_fontFamilyValueCache.add(familyName, nullptr).iterator->value; + // Remove one entry at random if the cache grows too large. + const int maximumFontFamilyCacheSize = 128; + if (m_fontFamilyValueCache.size() >= maximumFontFamilyCacheSize) + m_fontFamilyValueCache.remove(m_fontFamilyValueCache.begin()); + + bool isFromSystemID = fromSystemFontID == FromSystemFontID::Yes; + RefPtr& value = m_fontFamilyValueCache.add({familyName, isFromSystemID}, nullptr).iterator->value; if (!value) - value = CSSPrimitiveValue::create(familyName, CSSPrimitiveValue::CSS_STRING); + value = CSSPrimitiveValue::create(CSSFontFamily{familyName, isFromSystemID}); return *value; } -PassRefPtr CSSValuePool::createFontFaceValue(const AtomicString& string) +RefPtr CSSValuePool::createFontFaceValue(const AtomicString& string) { // Remove one entry at random if the cache grows too large. const int maximumFontFaceCacheSize = 128; @@ -132,8 +140,13 @@ PassRefPtr CSSValuePool::createFontFaceValue(const AtomicString& s m_fontFaceValueCache.remove(m_fontFaceValueCache.begin()); RefPtr& value = m_fontFaceValueCache.add(string, nullptr).iterator->value; - if (!value) - value = CSSParser::parseFontFaceValue(string); + if (value) + return value; + + RefPtr result = CSSParser::parseSingleValue(CSSPropertyFontFamily, string); + if (!result || !result->isValueList()) + return value; + value = static_pointer_cast(result); return value; } @@ -142,15 +155,6 @@ void CSSValuePool::drain() m_colorValueCache.clear(); m_fontFaceValueCache.clear(); m_fontFamilyValueCache.clear(); - - for (int i = 0; i < numCSSValueKeywords; ++i) - m_identifierValueCache[i] = 0; - - for (int i = 0; i < maximumCacheableIntegerValue; ++i) { - m_pixelValueCache[i] = 0; - m_percentValueCache[i] = 0; - m_numberValueCache[i] = 0; - } } } diff --git a/Source/WebCore/css/CSSValuePool.h b/Source/WebCore/css/CSSValuePool.h index 44b00a9c7..c5d2d8bda 100644 --- a/Source/WebCore/css/CSSValuePool.h +++ b/Source/WebCore/css/CSSValuePool.h @@ -23,15 +23,20 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CSSValuePool_h -#define CSSValuePool_h +#pragma once +#include "CSSFontFamily.h" #include "CSSInheritedValue.h" #include "CSSInitialValue.h" #include "CSSPrimitiveValue.h" #include "CSSPropertyNames.h" +#include "CSSRevertValue.h" +#include "CSSUnsetValue.h" #include "CSSValueKeywords.h" +#include "ColorHash.h" +#include #include +#include #include #include @@ -39,57 +44,61 @@ namespace WebCore { class CSSValueList; +enum class FromSystemFontID { No, Yes }; + class CSSValuePool { WTF_MAKE_FAST_ALLOCATED; public: - PassRefPtr createFontFaceValue(const AtomicString&); - PassRef createFontFamilyValue(const String&); - PassRef createInheritedValue() { return m_inheritedValue.get(); } - PassRef createImplicitInitialValue() { return m_implicitInitialValue.get(); } - PassRef createExplicitInitialValue() { return m_explicitInitialValue.get(); } - PassRef createIdentifierValue(CSSValueID identifier); - PassRef createIdentifierValue(CSSPropertyID identifier); - PassRef createColorValue(unsigned rgbValue); - PassRef createValue(double value, CSSPrimitiveValue::UnitTypes); - PassRef createValue(const String& value, CSSPrimitiveValue::UnitTypes type) { return CSSPrimitiveValue::create(value, type); } - PassRef createValue(const Length& value, const RenderStyle* style) { return CSSPrimitiveValue::create(value, style); } - PassRef createValue(const LengthSize& value) { return CSSPrimitiveValue::create(value); } - template static PassRef createValue(T value) { return CSSPrimitiveValue::create(value); } + static CSSValuePool& singleton(); + + RefPtr createFontFaceValue(const AtomicString&); + Ref createFontFamilyValue(const String&, FromSystemFontID = FromSystemFontID::No); + Ref createInheritedValue() { return m_inheritedValue.get(); } + Ref createImplicitInitialValue() { return m_implicitInitialValue.get(); } + Ref createExplicitInitialValue() { return m_explicitInitialValue.get(); } + Ref createUnsetValue() { return m_unsetValue.get(); } + Ref createRevertValue() { return m_revertValue.get(); } + Ref createIdentifierValue(CSSValueID identifier); + Ref createIdentifierValue(CSSPropertyID identifier); + Ref createColorValue(const Color&); + Ref createValue(double value, CSSPrimitiveValue::UnitType); + Ref createValue(const String& value, CSSPrimitiveValue::UnitType type) { return CSSPrimitiveValue::create(value, type); } + Ref createValue(const Length& value, const RenderStyle& style) { return CSSPrimitiveValue::create(value, style); } + Ref createValue(const LengthSize& value, const RenderStyle& style) { return CSSPrimitiveValue::create(value, style); } + template static Ref createValue(T&& value) { return CSSPrimitiveValue::create(std::forward(value)); } void drain(); private: CSSValuePool(); - Ref m_inheritedValue; - Ref m_implicitInitialValue; - Ref m_explicitInitialValue; - - RefPtr m_identifierValueCache[numCSSValueKeywords]; - - typedef HashMap> ColorValueCache; + typedef HashMap> ColorValueCache; ColorValueCache m_colorValueCache; - Ref m_colorTransparent; - Ref m_colorWhite; - Ref m_colorBlack; - - static const int maximumCacheableIntegerValue = 255; - - RefPtr m_pixelValueCache[maximumCacheableIntegerValue + 1]; - RefPtr m_percentValueCache[maximumCacheableIntegerValue + 1]; - RefPtr m_numberValueCache[maximumCacheableIntegerValue + 1]; typedef HashMap> FontFaceValueCache; FontFaceValueCache m_fontFaceValueCache; - typedef HashMap> FontFamilyValueCache; + typedef HashMap, RefPtr> FontFamilyValueCache; FontFamilyValueCache m_fontFamilyValueCache; - friend CSSValuePool& cssValuePool(); -}; + friend class WTF::NeverDestroyed; + + LazyNeverDestroyed m_inheritedValue; + LazyNeverDestroyed m_implicitInitialValue; + LazyNeverDestroyed m_explicitInitialValue; + LazyNeverDestroyed m_unsetValue; + LazyNeverDestroyed m_revertValue; -CSSValuePool& cssValuePool() PURE_FUNCTION; + LazyNeverDestroyed m_transparentColor; + LazyNeverDestroyed m_whiteColor; + LazyNeverDestroyed m_blackColor; -} + static const int maximumCacheableIntegerValue = 255; + + LazyNeverDestroyed m_pixelValues[maximumCacheableIntegerValue + 1]; + LazyNeverDestroyed m_percentValues[maximumCacheableIntegerValue + 1]; + LazyNeverDestroyed m_numberValues[maximumCacheableIntegerValue + 1]; + LazyNeverDestroyed m_identifierValues[numCSSValueKeywords]; +}; -#endif +} // namespace WebCore diff --git a/Source/WebCore/css/CSSVariableData.cpp b/Source/WebCore/css/CSSVariableData.cpp new file mode 100644 index 000000000..4dcebf012 --- /dev/null +++ b/Source/WebCore/css/CSSVariableData.cpp @@ -0,0 +1,182 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "CSSVariableData.h" + +#include "CSSCustomPropertyValue.h" +#include "CSSParser.h" +#include "CSSParserTokenRange.h" +#include +#include +#include + +namespace WebCore { + +template void CSSVariableData::updateTokens(const CSSParserTokenRange& range) +{ + const CharacterType* currentOffset = m_backingString.characters(); + for (const CSSParserToken& token : range) { + if (token.hasStringBacking()) { + unsigned length = token.value().length(); + StringView string(currentOffset, length); + m_tokens.append(token.copyWithUpdatedString(string)); + currentOffset += length; + } else + m_tokens.append(token); + } + ASSERT(currentOffset == m_backingString.characters() + m_backingString.length()); +} + +bool CSSVariableData::operator==(const CSSVariableData& other) const +{ + return tokens() == other.tokens(); +} + +void CSSVariableData::consumeAndUpdateTokens(const CSSParserTokenRange& range) +{ + StringBuilder stringBuilder; + CSSParserTokenRange localRange = range; + + while (!localRange.atEnd()) { + CSSParserToken token = localRange.consume(); + if (token.hasStringBacking()) + stringBuilder.append(token.value()); + } + m_backingString = stringBuilder.toString(); + if (m_backingString.is8Bit()) + updateTokens(range); + else + updateTokens(range); +} + +CSSVariableData::CSSVariableData(const CSSParserTokenRange& range, bool needsVariableResolution) + : m_needsVariableResolution(needsVariableResolution) +{ + ASSERT(!range.atEnd()); + consumeAndUpdateTokens(range); +} + +bool CSSVariableData::checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap& customProperties, HashSet& seenProperties, HashSet& invalidProperties) const +{ + if (invalidProperties.contains(name)) + return false; + + HashSet newSeenProperties = seenProperties; + newSeenProperties.add(name); + + bool valid = checkVariablesForCyclesWithRange(m_tokens, customProperties, newSeenProperties, invalidProperties); + if (!valid) + invalidProperties.add(name); + + return valid; +} + +bool CSSVariableData::checkVariablesForCyclesWithRange(CSSParserTokenRange range, CustomPropertyValueMap& customProperties, HashSet& seenProperties, HashSet& invalidProperties) const +{ + while (!range.atEnd()) { + if (range.peek().functionId() == CSSValueVar) { + CSSParserTokenRange block = range.consumeBlock(); + + block.consumeWhitespace(); + ASSERT(block.peek().type() == IdentToken); + AtomicString variableName = block.consumeIncludingWhitespace().value().toAtomicString(); + ASSERT(block.atEnd() || block.peek().type() == CommaToken); + if (seenProperties.contains(variableName)) + return false; + + RefPtr value = customProperties.get(variableName); + if (value && value->containsVariables() && !value->checkVariablesForCycles(variableName, customProperties, seenProperties, invalidProperties)) + return false; + + if (range.peek().type() == CommaToken) { + // Fallback. + range.consume(); + return checkVariablesForCyclesWithRange(block, customProperties, seenProperties, invalidProperties); + } + } else + range.consume(); + } + return true; +} + +bool CSSVariableData::resolveVariableFallback(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector& result) const +{ + if (range.atEnd()) + return false; + ASSERT(range.peek().type() == CommaToken); + range.consume(); + return resolveTokenRange(customProperties, range, result); +} + +bool CSSVariableData::resolveVariableReference(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector& result) const +{ + range.consumeWhitespace(); + ASSERT(range.peek().type() == IdentToken); + AtomicString variableName = range.consumeIncludingWhitespace().value().toAtomicString(); + ASSERT(range.atEnd() || (range.peek().type() == CommaToken)); + + RefPtr property = customProperties.get(variableName); + if (!property || !property->value()) + return resolveVariableFallback(customProperties, range, result); + + if (property->containsVariables()) { + // FIXME: Avoid doing this work more than once. + RefPtr resolvedData = property->value()->resolveVariableReferences(customProperties); + if (!resolvedData) + return false; + result.appendVector(resolvedData->tokens()); + } else + result.appendVector(property->value()->tokens()); + + return true; +} + +RefPtr CSSVariableData::resolveVariableReferences(const CustomPropertyValueMap& customProperties) const +{ + Vector resolvedTokens; + CSSParserTokenRange range = m_tokens; + if (!resolveTokenRange(customProperties, range, resolvedTokens)) + return nullptr; + return CSSVariableData::createResolved(resolvedTokens, *this); +} + +bool CSSVariableData::resolveTokenRange(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector& result) const +{ + bool success = true; + while (!range.atEnd()) { + if (range.peek().functionId() == CSSValueVar) + success &= resolveVariableReference(customProperties, range.consumeBlock(), result); + else + result.append(range.consume()); + } + return success; +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSVariableData.h b/Source/WebCore/css/CSSVariableData.h new file mode 100644 index 000000000..3f76ee3f9 --- /dev/null +++ b/Source/WebCore/css/CSSVariableData.h @@ -0,0 +1,94 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "CSSParserToken.h" +#include "CSSParserTokenRange.h" +#include + +namespace WebCore { + +class CSSParserTokenRange; + +class CSSVariableData : public RefCounted { + WTF_MAKE_NONCOPYABLE(CSSVariableData); + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(const CSSParserTokenRange& range, bool needsVariableResolution = true) + { + return adoptRef(*new CSSVariableData(range, needsVariableResolution)); + } + + static Ref createResolved(const Vector& resolvedTokens, const CSSVariableData& unresolvedData) + { + return adoptRef(*new CSSVariableData(resolvedTokens, unresolvedData.m_backingString)); + } + + CSSParserTokenRange tokenRange() { return m_tokens; } + + const Vector& tokens() const { return m_tokens; } + + bool operator==(const CSSVariableData& other) const; + + bool needsVariableResolution() const { return m_needsVariableResolution; } + + bool checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap&, HashSet& seenProperties, HashSet& invalidProperties) const; + + RefPtr resolveVariableReferences(const CustomPropertyValueMap& customProperties) const; + bool resolveTokenRange(const CustomPropertyValueMap&, CSSParserTokenRange, Vector&) const; + +private: + CSSVariableData(const CSSParserTokenRange&, bool needsVariableResolution); + + // We can safely copy the tokens (which have raw pointers to substrings) because + // StylePropertySets contain references to CSSCustomPropertyValues, which + // point to the unresolved CSSVariableData values that own the backing strings + // this will potentially reference. + CSSVariableData(const Vector& resolvedTokens, String backingString) + : m_backingString(backingString) + , m_tokens(resolvedTokens) + , m_needsVariableResolution(false) + { } + + void consumeAndUpdateTokens(const CSSParserTokenRange&); + template void updateTokens(const CSSParserTokenRange&); + + bool checkVariablesForCyclesWithRange(CSSParserTokenRange, CustomPropertyValueMap&, HashSet& seenProperties, HashSet& invalidProperties) const; + bool resolveVariableReference(const CustomPropertyValueMap&, CSSParserTokenRange, Vector&) const; + bool resolveVariableFallback(const CustomPropertyValueMap&, CSSParserTokenRange, Vector&) const; + + String m_backingString; + Vector m_tokens; + const bool m_needsVariableResolution; + + // FIXME-NEWPARSER: We want to cache StyleProperties once we support @apply. +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSVariableReferenceValue.cpp b/Source/WebCore/css/CSSVariableReferenceValue.cpp new file mode 100644 index 000000000..2af521822 --- /dev/null +++ b/Source/WebCore/css/CSSVariableReferenceValue.cpp @@ -0,0 +1,50 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "CSSVariableReferenceValue.h" + +namespace WebCore { + +String CSSVariableReferenceValue::customCSSText() const +{ + if (!m_serialized) { + m_serialized = true; + m_stringValue = m_data->tokenRange().serialize(); + } + return m_stringValue; +} + +bool CSSVariableReferenceValue::checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap& customProperties, HashSet& seenProperties, HashSet& invalidProperties) const +{ + ASSERT(m_data); + return m_data->checkVariablesForCycles(name, customProperties, seenProperties, invalidProperties); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/CSSVariableReferenceValue.h b/Source/WebCore/css/CSSVariableReferenceValue.h new file mode 100644 index 000000000..537f78a66 --- /dev/null +++ b/Source/WebCore/css/CSSVariableReferenceValue.h @@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright (C) 2016 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "CSSValue.h" +#include "CSSVariableData.h" +#include + +namespace WebCore { + +class CSSVariableReferenceValue : public CSSValue { +public: + static Ref create(Ref&& data) + { + return adoptRef(*new CSSVariableReferenceValue(WTFMove(data))); + } + + CSSVariableData* variableDataValue() const + { + return m_data.get(); + } + + bool equals(const CSSVariableReferenceValue& other) const { return m_data == other.m_data; } + String customCSSText() const; + + bool checkVariablesForCycles(const AtomicString& name, CustomPropertyValueMap&, HashSet& seenProperties, HashSet& invalidProperties) const; + +private: + CSSVariableReferenceValue(Ref&& data) + : CSSValue(VariableReferenceClass) + , m_data(WTFMove(data)) + { + } + + RefPtr m_data; + mutable String m_stringValue; + mutable bool m_serialized { false }; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSVariableReferenceValue, isVariableReferenceValue()) diff --git a/Source/WebCore/css/Counter.h b/Source/WebCore/css/Counter.h index 205bf8bbe..76c3baee5 100644 --- a/Source/WebCore/css/Counter.h +++ b/Source/WebCore/css/Counter.h @@ -18,30 +18,33 @@ * Boston, MA 02110-1301, USA. */ -#ifndef Counter_h -#define Counter_h +#pragma once #include "CSSPrimitiveValue.h" #include namespace WebCore { -class Counter : public RefCounted { +class Counter final : public RefCounted { public: - static PassRefPtr create(PassRefPtr identifier, PassRefPtr listStyle, PassRefPtr separator) + static Ref create(Ref&& identifier, Ref&& listStyle, Ref&& separator) { - return adoptRef(new Counter(identifier, listStyle, separator)); + return adoptRef(*new Counter(WTFMove(identifier), WTFMove(listStyle), WTFMove(separator))); } - String identifier() const { return m_identifier ? m_identifier->getStringValue() : String(); } - String listStyle() const { return m_listStyle ? m_listStyle->getStringValue() : String(); } - String separator() const { return m_separator ? m_separator->getStringValue() : String(); } + String identifier() const { return m_identifier->stringValue(); } + String listStyle() const { return m_listStyle->stringValue(); } + String separator() const { return m_separator->stringValue(); } - CSSValueID listStyleIdent() const { return m_listStyle ? m_listStyle->getValueID() : CSSValueInvalid; } + const CSSPrimitiveValue& identifierValue() const { return m_identifier; } + const CSSPrimitiveValue& listStyleValue() const { return m_listStyle; } + const CSSPrimitiveValue& separatorValue() const { return m_separator; } + + CSSValueID listStyleIdent() const { return m_listStyle->valueID(); } - void setIdentifier(PassRefPtr identifier) { m_identifier = identifier; } - void setListStyle(PassRefPtr listStyle) { m_listStyle = listStyle; } - void setSeparator(PassRefPtr separator) { m_separator = separator; } + void setIdentifier(Ref&& identifier) { m_identifier = WTFMove(identifier); } + void setListStyle(Ref&& listStyle) { m_listStyle = WTFMove(listStyle); } + void setSeparator(Ref&& separator) { m_separator = WTFMove(separator); } bool equals(const Counter& other) const { @@ -49,27 +52,18 @@ public: && listStyle() == other.listStyle() && separator() == other.separator(); } - - PassRefPtr cloneForCSSOM() const - { - return create(m_identifier ? m_identifier->cloneForCSSOM() : 0 - , m_listStyle ? m_listStyle->cloneForCSSOM() : 0 - , m_separator ? m_separator->cloneForCSSOM() : 0); - } private: - Counter(PassRefPtr identifier, PassRefPtr listStyle, PassRefPtr separator) - : m_identifier(identifier) - , m_listStyle(listStyle) - , m_separator(separator) + Counter(Ref&& identifier, Ref&& listStyle, Ref&& separator) + : m_identifier(WTFMove(identifier)) + , m_listStyle(WTFMove(listStyle)) + , m_separator(WTFMove(separator)) { } - RefPtr m_identifier; // string - RefPtr m_listStyle; // ident - RefPtr m_separator; // string + Ref m_identifier; // string + Ref m_listStyle; // ident + Ref m_separator; // string }; } // namespace WebCore - -#endif // Counter_h diff --git a/Source/WebCore/css/Counter.idl b/Source/WebCore/css/Counter.idl deleted file mode 100644 index aff8b5670..000000000 --- a/Source/WebCore/css/Counter.idl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -// Introduced in DOM Level 2: -[ - ImplementationLacksVTable -] interface Counter { - readonly attribute DOMString identifier; - readonly attribute DOMString listStyle; - readonly attribute DOMString separator; -}; - diff --git a/Source/WebCore/css/DOMCSSNamespace.cpp b/Source/WebCore/css/DOMCSSNamespace.cpp new file mode 100644 index 000000000..c6aa786ed --- /dev/null +++ b/Source/WebCore/css/DOMCSSNamespace.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of Motorola Mobility Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DOMCSSNamespace.h" + +#include "CSSMarkup.h" +#include "CSSParser.h" +#include "CSSPropertyParser.h" +#include "StyleProperties.h" +#include +#include + +namespace WebCore { + +static String valueWithoutImportant(const String& value) +{ + if (!value.endsWith("important", false)) + return value; + + String newValue = value; + int bangIndex = newValue.length() - 9 - 1; + if (newValue[bangIndex] == ' ') + bangIndex--; + newValue = newValue.left(bangIndex); + + return newValue; +} + +bool DOMCSSNamespace::supports(Document& document, const String& property, const String& value) +{ + CSSPropertyID propertyID = cssPropertyID(property.stripWhiteSpace()); + + if (propertyID == CSSPropertyInvalid) + return false; + + // CSSParser::parseValue() won't work correctly if !important is present, + // so just get rid of it. It doesn't matter to supports() if it's actually + // there or not, provided how it's specified in the value is correct. + String normalizedValue = value.stripWhiteSpace().simplifyWhiteSpace(); + normalizedValue = valueWithoutImportant(normalizedValue); + + if (normalizedValue.isEmpty()) + return false; + + auto dummyStyle = MutableStyleProperties::create(); + return CSSParser::parseValue(dummyStyle, propertyID, normalizedValue, false, document) != CSSParser::ParseResult::Error; +} + +bool DOMCSSNamespace::supports(Document& document, const String& conditionText) +{ + CSSParserContext context(document); + CSSParser parser(context); + return parser.parseSupportsCondition(conditionText); +} + +String DOMCSSNamespace::escape(const String& ident) +{ + StringBuilder builder; + serializeIdentifier(ident, builder); + return builder.toString(); +} + +} diff --git a/Source/WebCore/css/DOMCSSNamespace.h b/Source/WebCore/css/DOMCSSNamespace.h new file mode 100644 index 000000000..3b2e3870d --- /dev/null +++ b/Source/WebCore/css/DOMCSSNamespace.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of Motorola Mobility Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace WebCore { + +class Document; + +class DOMCSSNamespace final : public RefCounted { +public: + static bool supports(Document&, const String& property, const String& value); + static bool supports(Document&, const String& conditionText); + static String escape(const String& ident); +}; + +} diff --git a/Source/WebCore/css/DOMCSSNamespace.idl b/Source/WebCore/css/DOMCSSNamespace.idl new file mode 100644 index 000000000..1f2d371f2 --- /dev/null +++ b/Source/WebCore/css/DOMCSSNamespace.idl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of Motorola Mobility Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + InterfaceName=CSS, + ImplementationLacksVTable, +] interface DOMCSSNamespace { + [CallWith=Document] static boolean supports(DOMString property, DOMString value); + [CallWith=Document] static boolean supports(DOMString conditionText); + static DOMString escape(DOMString ident); +}; diff --git a/Source/WebCore/css/DOMWindowCSS.cpp b/Source/WebCore/css/DOMWindowCSS.cpp deleted file mode 100644 index c3827a8a5..000000000 --- a/Source/WebCore/css/DOMWindowCSS.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * 3. Neither the name of Motorola Mobility Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DOMWindowCSS.h" - -#if ENABLE(CSS3_CONDITIONAL_RULES) - -#include "CSSParser.h" -#include "StyleProperties.h" -#include - -namespace WebCore { - -PassRefPtr DOMWindowCSS::create() -{ - return adoptRef(new DOMWindowCSS()); -} - -static String valueWithoutImportant(const String& value) -{ - if (!value.endsWith("important", false)) - return value; - - String newValue = value; - int bangIndex = newValue.length() - 9 - 1; - if (newValue[bangIndex] == ' ') - bangIndex--; - newValue = newValue.left(bangIndex); - - return newValue; -} - -bool DOMWindowCSS::supports(const String& property, const String& value) const -{ - CSSPropertyID propertyID = cssPropertyID(property.stripWhiteSpace()); - - if (propertyID == CSSPropertyInvalid) - return false; - - // CSSParser::parseValue() won't work correctly if !important is present, - // so just get rid of it. It doesn't matter to supports() if it's actually - // there or not, provided how it's specified in the value is correct. - String normalizedValue = value.stripWhiteSpace().simplifyWhiteSpace(); - normalizedValue = valueWithoutImportant(normalizedValue); - - if (normalizedValue.isEmpty()) - return false; - - RefPtr dummyStyle = MutableStyleProperties::create(); - return CSSParser::parseValue(dummyStyle.get(), propertyID, normalizedValue, false, CSSStrictMode, 0); -} - -bool DOMWindowCSS::supports(const String& conditionText) const -{ - CSSParserContext context(CSSStrictMode); - CSSParser parser(context); - return parser.parseSupportsCondition(conditionText); -} - -} - -#endif diff --git a/Source/WebCore/css/DOMWindowCSS.h b/Source/WebCore/css/DOMWindowCSS.h deleted file mode 100644 index 7070ae6a9..000000000 --- a/Source/WebCore/css/DOMWindowCSS.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * 3. Neither the name of Motorola Mobility Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DOMWindowCSS_h -#define DOMWindowCSS_h - -#if ENABLE(CSS3_CONDITIONAL_RULES) - -#include -#include -#include - -namespace WebCore { - -class DOMWindowCSS : public RefCounted { -public: - static PassRefPtr create(); - - bool supports(const String& property, const String& value) const; - bool supports(const String& conditionText) const; - -private: - DOMWindowCSS() - { - } -}; - -} - -#endif // ENABLE(CSS3_CONDITIONAL_RULES) - -#endif diff --git a/Source/WebCore/css/DOMWindowCSS.idl b/Source/WebCore/css/DOMWindowCSS.idl deleted file mode 100644 index 4a0d4edba..000000000 --- a/Source/WebCore/css/DOMWindowCSS.idl +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2012 Motorola Mobility Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * 3. Neither the name of Motorola Mobility Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - NoInterfaceObject, - InterfaceName=CSS, - Conditional=CSS3_CONDITIONAL_RULES, -] interface DOMWindowCSS { - - boolean supports(DOMString property, DOMString value); - boolean supports(DOMString conditionText); - -}; - diff --git a/Source/WebCore/css/DashboardRegion.h b/Source/WebCore/css/DashboardRegion.h index 5b5f0bd2e..a811d8f73 100644 --- a/Source/WebCore/css/DashboardRegion.h +++ b/Source/WebCore/css/DashboardRegion.h @@ -18,18 +18,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef DashboardRegion_h -#define DashboardRegion_h - -#include "Rect.h" +#pragma once #if ENABLE(DASHBOARD_SUPPORT) +#include "Rect.h" + namespace WebCore { -class DashboardRegion : public RectBase, public RefCounted { +class DashboardRegion final : public RectBase, public RefCounted { public: - static PassRefPtr create() { return adoptRef(new DashboardRegion); } + static Ref create() { return adoptRef(*new DashboardRegion); } bool equals(const DashboardRegion& other) const { return m_label == other.m_label && m_geometryType == other.m_geometryType @@ -47,8 +46,6 @@ private: DashboardRegion() : m_isCircle(false), m_isRectangle(false) { } }; -} // namespace - -#endif +} // namespace WebCore #endif diff --git a/Source/WebCore/css/DeprecatedCSSOMCounter.h b/Source/WebCore/css/DeprecatedCSSOMCounter.h new file mode 100644 index 000000000..942f2695c --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMCounter.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Counter.h" +#include "DeprecatedCSSOMPrimitiveValue.h" +#include +#include + +namespace WebCore { + +class DeprecatedCSSOMCounter final : public RefCounted { +public: + static Ref create(const Counter& counter) { return adoptRef(*new DeprecatedCSSOMCounter(counter)); } + + String identifier() const { return m_identifier->stringValue(); } + String listStyle() const { return m_listStyle->stringValue(); } + String separator() const { return m_separator->stringValue(); } + +private: + DeprecatedCSSOMCounter(const Counter& counter) + : m_identifier(counter.identifierValue().createDeprecatedCSSOMPrimitiveWrapper()) + , m_listStyle(counter.listStyleValue().createDeprecatedCSSOMPrimitiveWrapper()) + , m_separator(counter.separatorValue().createDeprecatedCSSOMPrimitiveWrapper()) + { + } + + Ref m_identifier; + Ref m_listStyle; + Ref m_separator; +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/DeprecatedCSSOMCounter.idl b/Source/WebCore/css/DeprecatedCSSOMCounter.idl new file mode 100644 index 000000000..f6fcdec72 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMCounter.idl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +[ + ExportToWrappedFunction, + ImplementationLacksVTable, + InterfaceName=Counter +] interface DeprecatedCSSOMCounter { + readonly attribute DOMString identifier; + readonly attribute DOMString listStyle; + readonly attribute DOMString separator; +}; diff --git a/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.cpp b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.cpp new file mode 100644 index 000000000..cceb46787 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DeprecatedCSSOMPrimitiveValue.h" + +#include "DeprecatedCSSOMCounter.h" +#include "DeprecatedCSSOMRGBColor.h" +#include "DeprecatedCSSOMRect.h" +#include "ExceptionCode.h" + +namespace WebCore { + +// FIXME: For now these still call into CSSPrimitiveValue, but as we refactor into subclasses +// such as StyleCounterValue, StyleRectValue, and StyleColorValue, these methods will get +// more complicated. + + +unsigned short DeprecatedCSSOMPrimitiveValue::primitiveType() const +{ + return m_value->primitiveType(); +} + +ExceptionOr DeprecatedCSSOMPrimitiveValue::setFloatValue(unsigned short unitType, double floatValue) +{ + return m_value->setFloatValue(unitType, floatValue); +} + +ExceptionOr DeprecatedCSSOMPrimitiveValue::getFloatValue(unsigned short unitType) const +{ + return m_value->getFloatValue(unitType); +} + +ExceptionOr DeprecatedCSSOMPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue) +{ + return m_value->setStringValue(stringType, stringValue); +} + +ExceptionOr DeprecatedCSSOMPrimitiveValue::getStringValue() const +{ + return m_value->getStringValue(); +} + +ExceptionOr> DeprecatedCSSOMPrimitiveValue::getCounterValue() const +{ + ExceptionOr counter = m_value->getCounterValue(); + if (counter.hasException()) + return Exception { INVALID_ACCESS_ERR }; + return DeprecatedCSSOMCounter::create(counter.releaseReturnValue()); +} + +ExceptionOr> DeprecatedCSSOMPrimitiveValue::getRectValue() const +{ + ExceptionOr rect = m_value->getRectValue(); + if (rect.hasException()) + return Exception { INVALID_ACCESS_ERR }; + return DeprecatedCSSOMRect::create(rect.releaseReturnValue()); +} + +ExceptionOr> DeprecatedCSSOMPrimitiveValue::getRGBColorValue() const +{ + ExceptionOr> color = m_value->getRGBColorValue(); + if (color.hasException()) + return Exception { INVALID_ACCESS_ERR }; + return DeprecatedCSSOMRGBColor::create(color.releaseReturnValue()); +} + +} diff --git a/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.h b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.h new file mode 100644 index 000000000..65e54b475 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSPrimitiveValue.h" +#include "DeprecatedCSSOMValue.h" + +namespace WebCore { + +class DeprecatedCSSOMCounter; +class DeprecatedCSSOMRGBColor; +class DeprecatedCSSOMRect; + +class DeprecatedCSSOMPrimitiveValue : public DeprecatedCSSOMValue { +public: + // Only expose what's in the IDL file. + enum UnitType { + CSS_UNKNOWN = 0, + CSS_NUMBER = 1, + CSS_PERCENTAGE = 2, + CSS_EMS = 3, + CSS_EXS = 4, + CSS_PX = 5, + CSS_CM = 6, + CSS_MM = 7, + CSS_IN = 8, + CSS_PT = 9, + CSS_PC = 10, + CSS_DEG = 11, + CSS_RAD = 12, + CSS_GRAD = 13, + CSS_MS = 14, + CSS_S = 15, + CSS_HZ = 16, + CSS_KHZ = 17, + CSS_DIMENSION = 18, + CSS_STRING = 19, + CSS_URI = 20, + CSS_IDENT = 21, + CSS_ATTR = 22, + CSS_COUNTER = 23, + CSS_RECT = 24, + CSS_RGBCOLOR = 25, + CSS_VW = 26, + CSS_VH = 27, + CSS_VMIN = 28, + CSS_VMAX = 29 + }; + + static Ref create(const CSSPrimitiveValue& value) + { + return adoptRef(*new DeprecatedCSSOMPrimitiveValue(value)); + } + + bool equals(const DeprecatedCSSOMPrimitiveValue& other) const { return m_value->equals(other.m_value); } + unsigned cssValueType() const { return m_value->cssValueType(); } + String cssText() const { return m_value->cssText(); } + + // FIXME: Eventually these will contain more code and not just call through to + // CSSPrimitiveValue. + WEBCORE_EXPORT unsigned short primitiveType() const; + WEBCORE_EXPORT ExceptionOr setFloatValue(unsigned short unitType, double); + WEBCORE_EXPORT ExceptionOr getFloatValue(unsigned short unitType) const; + WEBCORE_EXPORT ExceptionOr setStringValue(unsigned short stringType, const String&); + WEBCORE_EXPORT ExceptionOr getStringValue() const; + WEBCORE_EXPORT ExceptionOr> getCounterValue() const; + WEBCORE_EXPORT ExceptionOr> getRectValue() const; + WEBCORE_EXPORT ExceptionOr> getRGBColorValue() const; + + String stringValue() const { return m_value->stringValue(); } + +protected: + DeprecatedCSSOMPrimitiveValue(const CSSPrimitiveValue& value) + : DeprecatedCSSOMValue(DeprecatedPrimitiveValueClass) + , m_value(const_cast(value)) + { + } + +private: + Ref m_value; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSSOM_VALUE(DeprecatedCSSOMPrimitiveValue, isPrimitiveValue()) diff --git a/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.idl b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.idl new file mode 100644 index 000000000..1a530ebc9 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMPrimitiveValue.idl @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006, 2008 Apple 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +[ + ImplementationLacksVTable, + InterfaceName=CSSPrimitiveValue +] interface DeprecatedCSSOMPrimitiveValue : DeprecatedCSSOMValue { + // UnitTypes + const unsigned short CSS_UNKNOWN = 0; + const unsigned short CSS_NUMBER = 1; + const unsigned short CSS_PERCENTAGE = 2; + const unsigned short CSS_EMS = 3; + const unsigned short CSS_EXS = 4; + const unsigned short CSS_PX = 5; + const unsigned short CSS_CM = 6; + const unsigned short CSS_MM = 7; + const unsigned short CSS_IN = 8; + const unsigned short CSS_PT = 9; + const unsigned short CSS_PC = 10; + const unsigned short CSS_DEG = 11; + const unsigned short CSS_RAD = 12; + const unsigned short CSS_GRAD = 13; + const unsigned short CSS_MS = 14; + const unsigned short CSS_S = 15; + const unsigned short CSS_HZ = 16; + const unsigned short CSS_KHZ = 17; + const unsigned short CSS_DIMENSION = 18; + const unsigned short CSS_STRING = 19; + const unsigned short CSS_URI = 20; + const unsigned short CSS_IDENT = 21; + const unsigned short CSS_ATTR = 22; + const unsigned short CSS_COUNTER = 23; + const unsigned short CSS_RECT = 24; + const unsigned short CSS_RGBCOLOR = 25; + const unsigned short CSS_VW = 26; + const unsigned short CSS_VH = 27; + const unsigned short CSS_VMIN = 28; + const unsigned short CSS_VMAX = 29; + + readonly attribute unsigned short primitiveType; + + [MayThrowException] void setFloatValue(optional unsigned short unitType = 0, optional unrestricted float floatValue = NaN); + [MayThrowException] unrestricted float getFloatValue(optional unsigned short unitType = 0); + + [MayThrowException] void setStringValue(optional unsigned short stringType = 0, optional DOMString stringValue); + [MayThrowException] DOMString getStringValue(); + + [MayThrowException] DeprecatedCSSOMCounter getCounterValue(); + [MayThrowException] DeprecatedCSSOMRect getRectValue(); + [MayThrowException] DeprecatedCSSOMRGBColor getRGBColorValue(); +}; diff --git a/Source/WebCore/css/DeprecatedCSSOMRGBColor.h b/Source/WebCore/css/DeprecatedCSSOMRGBColor.h new file mode 100644 index 000000000..155e87892 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMRGBColor.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "DeprecatedCSSOMPrimitiveValue.h" +#include "RGBColor.h" +#include +#include + +namespace WebCore { + +class DeprecatedCSSOMRGBColor final : public RefCounted { +public: + static Ref create(const RGBColor& color) { return adoptRef(*new DeprecatedCSSOMRGBColor(color)); } + + DeprecatedCSSOMPrimitiveValue* red() { return m_red.get(); } + DeprecatedCSSOMPrimitiveValue* green() { return m_green.get(); } + DeprecatedCSSOMPrimitiveValue* blue() { return m_blue.get(); } + DeprecatedCSSOMPrimitiveValue* alpha() { return m_alpha.get(); } + + Color color() const { return Color(m_rgbColor); } + +private: + DeprecatedCSSOMRGBColor(const RGBColor& color) + : m_rgbColor(color.rgbColor()) + { + // Red + unsigned value = (m_rgbColor >> 16) & 0xFF; + auto result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); + m_red = result->createDeprecatedCSSOMPrimitiveWrapper(); + + // Green + value = (m_rgbColor >> 8) & 0xFF; + result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); + m_green = result->createDeprecatedCSSOMPrimitiveWrapper(); + + // Blue + value = m_rgbColor & 0xFF; + result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); + m_blue = result->createDeprecatedCSSOMPrimitiveWrapper(); + + // Alpha + float alphaValue = static_cast((m_rgbColor >> 24) & 0xFF) / 0xFF; + result = CSSPrimitiveValue::create(alphaValue, CSSPrimitiveValue::CSS_NUMBER); + m_alpha = result->createDeprecatedCSSOMPrimitiveWrapper(); + } + + RGBA32 m_rgbColor; + RefPtr m_red; + RefPtr m_green; + RefPtr m_blue; + RefPtr m_alpha; +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/DeprecatedCSSOMRGBColor.idl b/Source/WebCore/css/DeprecatedCSSOMRGBColor.idl new file mode 100644 index 000000000..499351f0c --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMRGBColor.idl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +[ + ExportToWrappedFunction, + ImplementationLacksVTable, + InterfaceName=RGBColor +] interface DeprecatedCSSOMRGBColor { + readonly attribute DeprecatedCSSOMPrimitiveValue red; + readonly attribute DeprecatedCSSOMPrimitiveValue green; + readonly attribute DeprecatedCSSOMPrimitiveValue blue; + + readonly attribute DeprecatedCSSOMPrimitiveValue alpha; +}; diff --git a/Source/WebCore/css/DeprecatedCSSOMRect.h b/Source/WebCore/css/DeprecatedCSSOMRect.h new file mode 100644 index 000000000..517681460 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMRect.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "DeprecatedCSSOMPrimitiveValue.h" +#include "Rect.h" +#include +#include + +namespace WebCore { + +class DeprecatedCSSOMRect final : public RefCounted { +public: + static Ref create(const Rect& rect) { return adoptRef(*new DeprecatedCSSOMRect(rect)); } + + DeprecatedCSSOMPrimitiveValue* top() const { return m_top.get(); } + DeprecatedCSSOMPrimitiveValue* right() const { return m_right.get(); } + DeprecatedCSSOMPrimitiveValue* bottom() const { return m_bottom.get(); } + DeprecatedCSSOMPrimitiveValue* left() const { return m_left.get(); } + +private: + DeprecatedCSSOMRect(const Rect& rect) + { + if (rect.top()) + m_top = rect.top()->createDeprecatedCSSOMPrimitiveWrapper(); + if (rect.right()) + m_right = rect.right()->createDeprecatedCSSOMPrimitiveWrapper(); + if (rect.bottom()) + m_bottom = rect.bottom()->createDeprecatedCSSOMPrimitiveWrapper(); + if (rect.left()) + m_left = rect.left()->createDeprecatedCSSOMPrimitiveWrapper(); + } + + RefPtr m_top; + RefPtr m_right; + RefPtr m_bottom; + RefPtr m_left; +}; + +} // namespace WebCore diff --git a/Source/WebCore/css/DeprecatedCSSOMRect.idl b/Source/WebCore/css/DeprecatedCSSOMRect.idl new file mode 100644 index 000000000..a658e13b1 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMRect.idl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006, 2007 Apple 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +[ + ExportToWrappedFunction, + ImplementationLacksVTable, + InterfaceName=Rect +] interface DeprecatedCSSOMRect { + readonly attribute DeprecatedCSSOMPrimitiveValue top; + readonly attribute DeprecatedCSSOMPrimitiveValue right; + readonly attribute DeprecatedCSSOMPrimitiveValue bottom; + readonly attribute DeprecatedCSSOMPrimitiveValue left; +}; diff --git a/Source/WebCore/css/DeprecatedCSSOMValue.cpp b/Source/WebCore/css/DeprecatedCSSOMValue.cpp new file mode 100644 index 000000000..bde01b9b8 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValue.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DeprecatedCSSOMValue.h" + +#include "DeprecatedCSSOMPrimitiveValue.h" +#include "DeprecatedCSSOMValueList.h" + +namespace WebCore { + +template +inline static bool compareCSSOMValues(const DeprecatedCSSOMValue& first, const DeprecatedCSSOMValue& second) +{ + return static_cast(first).equals(static_cast(second)); +} + +bool DeprecatedCSSOMValue::equals(const DeprecatedCSSOMValue& other) const +{ + if (m_classType == other.m_classType) { + switch (m_classType) { + case DeprecatedComplexValueClass: + return compareCSSOMValues(*this, other); + case DeprecatedPrimitiveValueClass: + return compareCSSOMValues(*this, other); + case DeprecatedValueListClass: + return compareCSSOMValues(*this, other); + } + } + return false; +} + +void DeprecatedCSSOMValue::destroy() +{ + switch (classType()) { + case DeprecatedComplexValueClass: { + delete downcast(this); + return; + } + case DeprecatedPrimitiveValueClass: { + delete downcast(this); + return; + } + case DeprecatedValueListClass: { + delete downcast(this); + return; + } + } + ASSERT_NOT_REACHED(); + delete this; +} + +unsigned DeprecatedCSSOMValue::cssValueType() const +{ + switch (m_classType) { + case DeprecatedComplexValueClass: + return downcast(*this).cssValueType(); + case DeprecatedPrimitiveValueClass: + return downcast(*this).cssValueType(); + case DeprecatedValueListClass: + return downcast(*this).cssValueType(); + } + ASSERT_NOT_REACHED(); + return CSS_CUSTOM; +} + +String DeprecatedCSSOMValue::cssText() const +{ + switch (m_classType) { + case DeprecatedComplexValueClass: + return downcast(*this).cssText(); + case DeprecatedPrimitiveValueClass: + return downcast(*this).cssText(); + case DeprecatedValueListClass: + return downcast(*this).cssText(); + } + ASSERT_NOT_REACHED(); + return ""; +} + +} diff --git a/Source/WebCore/css/DeprecatedCSSOMValue.h b/Source/WebCore/css/DeprecatedCSSOMValue.h new file mode 100644 index 000000000..7340624fe --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValue.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValue.h" +#include "ExceptionOr.h" +#include +#include +#include +#include +#include +#include + +namespace WebCore { + +class DeprecatedCSSOMValue : public RefCounted { +public: + // Exactly match the IDL. No reason to add anything if it's not in the IDL. + enum Type { + CSS_INHERIT = 0, + CSS_PRIMITIVE_VALUE = 1, + CSS_VALUE_LIST = 2, + CSS_CUSTOM = 3 + }; + + // Override RefCounted's deref() to ensure operator delete is called on + // the appropriate subclass type. + void deref() + { + if (derefBase()) + destroy(); + } + + WEBCORE_EXPORT unsigned cssValueType() const; + + WEBCORE_EXPORT String cssText() const; + ExceptionOr setCssText(const String&) { return { }; } // Will never implement. + + bool equals(const DeprecatedCSSOMValue& other) const; + bool operator==(const DeprecatedCSSOMValue& other) const { return equals(other); } + + bool isComplexValue() const { return m_classType == DeprecatedComplexValueClass; } + bool isPrimitiveValue() const { return m_classType == DeprecatedPrimitiveValueClass; } + bool isValueList() const { return m_classType == DeprecatedValueListClass; } + +protected: + static const size_t ClassTypeBits = 2; + enum DeprecatedClassType { + DeprecatedComplexValueClass, + DeprecatedPrimitiveValueClass, + DeprecatedValueListClass + }; + + DeprecatedClassType classType() const { return static_cast(m_classType); } + + DeprecatedCSSOMValue(DeprecatedClassType classType) + : m_classType(classType) + { + } + + // NOTE: This class is non-virtual for memory and performance reasons. + // Don't go making it virtual again unless you know exactly what you're doing! + ~DeprecatedCSSOMValue() { } + +private: + WEBCORE_EXPORT void destroy(); + +protected: + unsigned m_valueListSeparator : CSSValue::ValueListSeparatorBits; + +private: + unsigned m_classType : ClassTypeBits; // ClassType +}; + +class DeprecatedCSSOMComplexValue : public DeprecatedCSSOMValue { +public: + static Ref create(const CSSValue& value) + { + return adoptRef(*new DeprecatedCSSOMComplexValue(value)); + } + + bool equals(const DeprecatedCSSOMComplexValue& other) const { return m_value->equals(other.m_value); } + String cssText() const { return m_value->cssText(); } + + unsigned cssValueType() const { return m_value->cssValueType(); } + +protected: + DeprecatedCSSOMComplexValue(const CSSValue& value) + : DeprecatedCSSOMValue(DeprecatedComplexValueClass) + , m_value(const_cast(value)) + { + } + +private: + Ref m_value; +}; + +} // namespace WebCore + +#define SPECIALIZE_TYPE_TRAITS_CSSOM_VALUE(ToValueTypeName, predicate) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ +static bool isType(const WebCore::DeprecatedCSSOMValue& value) { return value.predicate; } \ +SPECIALIZE_TYPE_TRAITS_END() + +SPECIALIZE_TYPE_TRAITS_CSSOM_VALUE(DeprecatedCSSOMComplexValue, isComplexValue()) + + diff --git a/Source/WebCore/css/DeprecatedCSSOMValue.idl b/Source/WebCore/css/DeprecatedCSSOMValue.idl new file mode 100644 index 000000000..31f4f0dfb --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValue.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +[ + CustomIsReachable, + CustomToJSObject, + ExportToWrappedFunction, + ImplementationLacksVTable, + JSCustomFinalize, + InterfaceName=CSSValue +] interface DeprecatedCSSOMValue { + // UnitTypes + const unsigned short CSS_INHERIT = 0; + const unsigned short CSS_PRIMITIVE_VALUE = 1; + const unsigned short CSS_VALUE_LIST = 2; + const unsigned short CSS_CUSTOM = 3; + + [SetterMayThrowException] attribute DOMString? cssText; + + readonly attribute unsigned short cssValueType; +}; diff --git a/Source/WebCore/css/DeprecatedCSSOMValueList.cpp b/Source/WebCore/css/DeprecatedCSSOMValueList.cpp new file mode 100644 index 000000000..47feadd23 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValueList.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DeprecatedCSSOMValueList.h" + +#include + +namespace WebCore { + +bool DeprecatedCSSOMValueList::equals(const DeprecatedCSSOMValueList& other) const +{ + if (m_valueListSeparator != other.m_valueListSeparator) + return false; + + if (m_values.size() != other.m_values.size()) + return false; + + for (unsigned i = 0, size = m_values.size(); i < size; ++i) { + if (!m_values[i].get().equals(other.m_values[i])) + return false; + } + return true; +} + +String DeprecatedCSSOMValueList::cssText() const +{ + StringBuilder result; + String separator; + switch (m_valueListSeparator) { + case CSSValue::SpaceSeparator: + separator = ASCIILiteral(" "); + break; + case CSSValue::CommaSeparator: + separator = ASCIILiteral(", "); + break; + case CSSValue::SlashSeparator: + separator = ASCIILiteral(" / "); + break; + default: + ASSERT_NOT_REACHED(); + } + + for (auto& value : m_values) { + if (!result.isEmpty()) + result.append(separator); + result.append(value.get().cssText()); + } + + return result.toString(); +} + +} diff --git a/Source/WebCore/css/DeprecatedCSSOMValueList.h b/Source/WebCore/css/DeprecatedCSSOMValueList.h new file mode 100644 index 000000000..bad0e7c11 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValueList.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSValueList.h" +#include "DeprecatedCSSOMValue.h" + +namespace WebCore { + +class DeprecatedCSSOMValueList : public DeprecatedCSSOMValue { +public: + static Ref create(const CSSValueList& value) + { + return adoptRef(*new DeprecatedCSSOMValueList(value)); + } + + bool equals(const DeprecatedCSSOMValueList& other) const; + unsigned cssValueType() const { return CSS_VALUE_LIST; } + String cssText() const; + + size_t length() const { return m_values.size(); } + DeprecatedCSSOMValue* item(size_t index) { return index < m_values.size() ? m_values[index].ptr() : nullptr; } + const DeprecatedCSSOMValue* item(size_t index) const { return index < m_values.size() ? m_values[index].ptr() : nullptr; } + +protected: + DeprecatedCSSOMValueList(const CSSValueList& value) + : DeprecatedCSSOMValue(DeprecatedValueListClass) + { + m_valueListSeparator = value.separator(); + m_values.reserveInitialCapacity(value.length()); + for (unsigned i = 0, size = value.length(); i < size; ++i) + m_values.uncheckedAppend(value.itemWithoutBoundsCheck(i)->createDeprecatedCSSOMWrapper()); + } + +private: + Vector, 4> m_values; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_CSSOM_VALUE(DeprecatedCSSOMValueList, isValueList()) diff --git a/Source/WebCore/css/DeprecatedCSSOMValueList.idl b/Source/WebCore/css/DeprecatedCSSOMValueList.idl new file mode 100644 index 000000000..f21588379 --- /dev/null +++ b/Source/WebCore/css/DeprecatedCSSOMValueList.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Introduced in DOM Level 2: +[ + ImplementationLacksVTable, + InterfaceName=CSSValueList +] interface DeprecatedCSSOMValueList : DeprecatedCSSOMValue { + readonly attribute unsigned long length; + getter DeprecatedCSSOMValue item(unsigned long index); +}; + diff --git a/Source/WebCore/css/DeprecatedStyleBuilder.cpp b/Source/WebCore/css/DeprecatedStyleBuilder.cpp deleted file mode 100644 index dca4b61a4..000000000 --- a/Source/WebCore/css/DeprecatedStyleBuilder.cpp +++ /dev/null @@ -1,2624 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. - * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DeprecatedStyleBuilder.h" - -#include "BasicShapeFunctions.h" -#include "BasicShapes.h" -#include "CSSAspectRatioValue.h" -#include "CSSCalculationValue.h" -#include "CSSCursorImageValue.h" -#include "CSSPrimitiveValue.h" -#include "CSSPrimitiveValueMappings.h" -#include "CSSToStyleMap.h" -#include "CSSValueList.h" -#include "ClipPathOperation.h" -#include "CursorList.h" -#include "Document.h" -#include "Element.h" -#include "Frame.h" -#include "Pair.h" -#include "Rect.h" -#include "RenderStyle.h" -#include "RenderView.h" -#include "Settings.h" -#include "StyleFontSizeFunctions.h" -#include "StyleResolver.h" -#include - -#if ENABLE(CSS_SHAPES) -#include "ShapeValue.h" -#endif - -namespace WebCore { - -enum ExpandValueBehavior {SuppressValue = 0, ExpandValue}; -template -class ApplyPropertyExpanding { -public: - - template - static inline void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - if (id == CSSPropertyInvalid) - return; - - const DeprecatedStyleBuilder& table = DeprecatedStyleBuilder::sharedStyleBuilder(); - const PropertyHandler& handler = table.propertyHandler(id); - if (handler.isValid()) - handler.applyInheritValue(propertyID, styleResolver); - } - - static void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - applyInheritValue(propertyID, styleResolver); - applyInheritValue(propertyID, styleResolver); - applyInheritValue(propertyID, styleResolver); - applyInheritValue(propertyID, styleResolver); - applyInheritValue(propertyID, styleResolver); - } - - template - static inline void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - if (id == CSSPropertyInvalid) - return; - - const DeprecatedStyleBuilder& table = DeprecatedStyleBuilder::sharedStyleBuilder(); - const PropertyHandler& handler = table.propertyHandler(id); - if (handler.isValid()) - handler.applyInitialValue(propertyID, styleResolver); - } - - static void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - applyInitialValue(propertyID, styleResolver); - applyInitialValue(propertyID, styleResolver); - applyInitialValue(propertyID, styleResolver); - applyInitialValue(propertyID, styleResolver); - applyInitialValue(propertyID, styleResolver); - } - - template - static inline void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (id == CSSPropertyInvalid) - return; - - const DeprecatedStyleBuilder& table = DeprecatedStyleBuilder::sharedStyleBuilder(); - const PropertyHandler& handler = table.propertyHandler(id); - if (handler.isValid()) - handler.applyValue(propertyID, styleResolver, value); - } - - static void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!expandValue) - return; - - applyValue(propertyID, styleResolver, value); - applyValue(propertyID, styleResolver, value); - applyValue(propertyID, styleResolver, value); - applyValue(propertyID, styleResolver, value); - applyValue(propertyID, styleResolver, value); - } - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -template -class ApplyPropertyDefaultBase { -public: - static void setValue(RenderStyle* style, SetterType value) { (style->*setterFunction)(value); } - static GetterType value(RenderStyle* style) { return (style->*getterFunction)(); } - static InitialType initial() { return (*initialFunction)(); } - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) { setValue(styleResolver->style(), value(styleResolver->parentStyle())); } - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) { setValue(styleResolver->style(), initial()); } - static void applyValue(CSSPropertyID, StyleResolver*, CSSValue*) { } - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -template -class ApplyPropertyDefault { -public: - static void setValue(RenderStyle* style, SetterType value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isPrimitiveValue()) - setValue(styleResolver->style(), *toCSSPrimitiveValue(value)); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template -class ApplyPropertyNumber { -public: - static void setValue(RenderStyle* style, NumberType value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == idMapsToMinusOne) - setValue(styleResolver->style(), -1); - else - setValue(styleResolver->style(), primitiveValue->getValue(CSSPrimitiveValue::CSS_NUMBER)); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template ), StyleImage* (*initialFunction)(), CSSPropertyID property> -class ApplyPropertyStyleImage { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) { (styleResolver->style()->*setterFunction)(styleResolver->styleImage(property, value)); } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase, setterFunction, StyleImage*, initialFunction>::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -enum AutoValueType {Number = 0, ComputeLength}; -template -class ApplyPropertyAuto { -public: - static void setValue(RenderStyle* style, T value) { (style->*setterFunction)(value); } - static T value(RenderStyle* style) { return (style->*getterFunction)(); } - static bool hasAuto(RenderStyle* style) { return (style->*hasAutoFunction)(); } - static void setAuto(RenderStyle* style) { (style->*setAutoFunction)(); } - - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - if (hasAuto(styleResolver->parentStyle())) - setAuto(styleResolver->style()); - else - setValue(styleResolver->style(), value(styleResolver->parentStyle())); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) { setAuto(styleResolver->style()); } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == autoIdentity) - setAuto(styleResolver->style()); - else if (valueType == Number) - setValue(styleResolver->style(), *primitiveValue); - else if (valueType == ComputeLength) - setValue(styleResolver->style(), primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyClip { -private: - static Length convertToLength(StyleResolver* styleResolver, CSSPrimitiveValue* value) - { - return value->convertToLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()); - } -public: - static void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - RenderStyle* parentStyle = styleResolver->parentStyle(); - if (!parentStyle->hasClip()) - return applyInitialValue(propertyID, styleResolver); - styleResolver->style()->setClip(parentStyle->clipTop(), parentStyle->clipRight(), parentStyle->clipBottom(), parentStyle->clipLeft()); - styleResolver->style()->setHasClip(true); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setClip(Length(), Length(), Length(), Length()); - styleResolver->style()->setHasClip(false); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - if (Rect* rect = primitiveValue->getRectValue()) { - Length top = convertToLength(styleResolver, rect->top()); - Length right = convertToLength(styleResolver, rect->right()); - Length bottom = convertToLength(styleResolver, rect->bottom()); - Length left = convertToLength(styleResolver, rect->left()); - styleResolver->style()->setClip(top, right, bottom, left); - styleResolver->style()->setHasClip(true); - } else if (primitiveValue->getValueID() == CSSValueAuto) { - styleResolver->style()->setClip(Length(), Length(), Length(), Length()); - styleResolver->style()->setHasClip(false); - } - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -enum ColorInherit {NoInheritFromParent = 0, InheritFromParent}; -Color defaultInitialColor(); -Color defaultInitialColor() { return Color(); } -template -class ApplyPropertyColor { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - // Visited link style can never explicitly inherit from parent visited link style so no separate getters are needed. - Color color = (styleResolver->parentStyle()->*getterFunction)(); - applyColorValue(styleResolver, color.isValid() ? color : (styleResolver->parentStyle()->*defaultFunction)()); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - applyColorValue(styleResolver, initialFunction()); - } - - static void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (inheritColorFromParent && primitiveValue->getValueID() == CSSValueCurrentcolor) - applyInheritValue(propertyID, styleResolver); - else { - if (styleResolver->applyPropertyToRegularStyle()) - (styleResolver->style()->*setterFunction)(styleResolver->colorFromPrimitiveValue(primitiveValue)); - if (styleResolver->applyPropertyToVisitedLinkStyle()) - (styleResolver->style()->*visitedLinkSetterFunction)(styleResolver->colorFromPrimitiveValue(primitiveValue, /* forVisitedLink */ true)); - } - } - - static void applyColorValue(StyleResolver* styleResolver, const Color& color) - { - if (styleResolver->applyPropertyToRegularStyle()) - (styleResolver->style()->*setterFunction)(color); - if (styleResolver->applyPropertyToVisitedLinkStyle()) - (styleResolver->style()->*visitedLinkSetterFunction)(color); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -template -class ApplyPropertyDirection { -public: - static void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) - { - ApplyPropertyDefault::applyValue(propertyID, styleResolver, value); - Element* element = styleResolver->element(); - if (element && styleResolver->element() == element->document().documentElement()) - element->document().setDirectionSetOnDocumentElement(true); - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefault::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -enum LengthAuto { AutoDisabled = 0, AutoEnabled }; -enum LengthLegacyIntrinsic { LegacyIntrinsicDisabled = 0, LegacyIntrinsicEnabled }; -enum LengthIntrinsic { IntrinsicDisabled = 0, IntrinsicEnabled }; -enum LengthNone { NoneDisabled = 0, NoneEnabled }; -enum LengthUndefined { UndefinedDisabled = 0, UndefinedEnabled }; -template -class ApplyPropertyLength { -public: - static void setValue(RenderStyle* style, Length value) { (style->*setterFunction)(std::move(value)); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (noneEnabled && primitiveValue->getValueID() == CSSValueNone) { - if (noneUndefined) - setValue(styleResolver->style(), Length(Undefined)); - else - setValue(styleResolver->style(), Length()); - } - if (legacyIntrinsicEnabled) { - if (primitiveValue->getValueID() == CSSValueIntrinsic) - setValue(styleResolver->style(), Length(Intrinsic)); - else if (primitiveValue->getValueID() == CSSValueMinIntrinsic) - setValue(styleResolver->style(), Length(MinIntrinsic)); - } - if (intrinsicEnabled) { - if (primitiveValue->getValueID() == CSSValueWebkitMinContent) - setValue(styleResolver->style(), Length(MinContent)); - else if (primitiveValue->getValueID() == CSSValueWebkitMaxContent) - setValue(styleResolver->style(), Length(MaxContent)); - else if (primitiveValue->getValueID() == CSSValueWebkitFillAvailable) - setValue(styleResolver->style(), Length(FillAvailable)); - else if (primitiveValue->getValueID() == CSSValueWebkitFitContent) - setValue(styleResolver->style(), Length(FitContent)); - } - - if (autoEnabled && primitiveValue->getValueID() == CSSValueAuto) - setValue(styleResolver->style(), Length()); - else if (primitiveValue->isLength()) { - Length length = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()); - length.setQuirk(primitiveValue->isQuirkValue()); - setValue(styleResolver->style(), length); - } else if (primitiveValue->isPercentage()) - setValue(styleResolver->style(), Length(primitiveValue->getDoubleValue(), Percent)); - else if (primitiveValue->isCalculatedPercentageWithLength()) - setValue(styleResolver->style(), Length(primitiveValue->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()))); - else if (primitiveValue->isViewportPercentageLength()) - setValue(styleResolver->style(), primitiveValue->viewportPercentageLength()); - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -enum StringIdentBehavior { NothingMapsToNull = 0, MapNoneToNull, MapAutoToNull }; -template -class ApplyPropertyString { -public: - static void setValue(RenderStyle* style, const AtomicString& value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if ((identBehavior == MapNoneToNull && primitiveValue->getValueID() == CSSValueNone) - || (identBehavior == MapAutoToNull && primitiveValue->getValueID() == CSSValueAuto)) - setValue(styleResolver->style(), nullAtom); - else - setValue(styleResolver->style(), primitiveValue->getStringValue()); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template -class ApplyPropertyBorderRadius { -public: - static void setValue(RenderStyle* style, LengthSize value) { (style->*setterFunction)(std::move(value)); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Pair* pair = primitiveValue->getPairValue(); - if (!pair || !pair->first() || !pair->second()) - return; - - Length radiusWidth; - Length radiusHeight; - if (pair->first()->isPercentage()) - radiusWidth = Length(pair->first()->getDoubleValue(), Percent); - else if (pair->first()->isViewportPercentageLength()) - radiusWidth = Length(styleResolver->viewportPercentageValue(*pair->first(), pair->first()->getIntValue()), Fixed); - else if (pair->first()->isCalculatedPercentageWithLength()) - radiusWidth = Length((pair->first()->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()))); - else - radiusWidth = pair->first()->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()); - if (pair->second()->isPercentage()) - radiusHeight = Length(pair->second()->getDoubleValue(), Percent); - else if (pair->second()->isViewportPercentageLength()) - radiusHeight = Length(styleResolver->viewportPercentageValue(*pair->second(), pair->second()->getIntValue()), Fixed); - else if (pair->second()->isCalculatedPercentageWithLength()) - radiusHeight = Length((pair->second()->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()))); - else - radiusHeight = pair->second()->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()); - int width = radiusWidth.value(); - int height = radiusHeight.value(); - if (width < 0 || height < 0) - return; - if (!width) - radiusHeight = radiusWidth; // Null out the other value. - else if (!height) - radiusWidth = radiusHeight; // Null out the other value. - - LengthSize size(radiusWidth, radiusHeight); - setValue(styleResolver->style(), size); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template -struct FillLayerAccessorTypes { - typedef T Setter; - typedef T Getter; - typedef T InitialGetter; -}; - -template <> -struct FillLayerAccessorTypes { - typedef PassRefPtr Setter; - typedef StyleImage* Getter; - typedef StyleImage* InitialGetter; -}; - -template<> -struct FillLayerAccessorTypes -{ - typedef Length Setter; - typedef const Length& Getter; - typedef Length InitialGetter; -}; - -template ::Getter (FillLayer::*getFunction)() const, - void (FillLayer::*setFunction)(typename FillLayerAccessorTypes::Setter), - void (FillLayer::*clearFunction)(), - typename FillLayerAccessorTypes::InitialGetter (*initialFunction)(EFillLayerType), - void (CSSToStyleMap::*mapFillFunction)(CSSPropertyID, FillLayer*, CSSValue*)> -class ApplyPropertyFillLayer { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - // Check for no-op before copying anything. - if (*(styleResolver->parentStyle()->*layersFunction)() == *(styleResolver->style()->*layersFunction)()) - return; - - FillLayer* currChild = (styleResolver->style()->*accessLayersFunction)(); - FillLayer* prevChild = 0; - const FillLayer* currParent = (styleResolver->parentStyle()->*layersFunction)(); - while (currParent && (currParent->*testFunction)()) { - if (!currChild) { - /* Need to make a new layer.*/ - currChild = new FillLayer(fillLayerType); - prevChild->setNext(currChild); - } - (currChild->*setFunction)((currParent->*getFunction)()); - prevChild = currChild; - currChild = prevChild->next(); - currParent = currParent->next(); - } - - while (currChild) { - /* Reset any remaining layers to not have the property set. */ - (currChild->*clearFunction)(); - currChild = currChild->next(); - } - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - // Check for (single-layer) no-op before clearing anything. - const FillLayer& layers = *(styleResolver->style()->*layersFunction)(); - bool firstLayerHasValue = (layers.*testFunction)(); - if (!layers.next() && (!firstLayerHasValue || (layers.*getFunction)() == (*initialFunction)(fillLayerType))) - return; - - FillLayer* currChild = (styleResolver->style()->*accessLayersFunction)(); - (currChild->*setFunction)((*initialFunction)(fillLayerType)); - for (currChild = currChild->next(); currChild; currChild = currChild->next()) - (currChild->*clearFunction)(); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - FillLayer* currChild = (styleResolver->style()->*accessLayersFunction)(); - FillLayer* prevChild = 0; - if (value->isValueList() -#if ENABLE(CSS_IMAGE_SET) - && !value->isImageSetValue() -#endif - ) { - /* Walk each value and put it into a layer, creating new layers as needed. */ - CSSValueList* valueList = toCSSValueList(value); - for (unsigned int i = 0; i < valueList->length(); i++) { - if (!currChild) { - /* Need to make a new layer to hold this value */ - currChild = new FillLayer(fillLayerType); - prevChild->setNext(currChild); - } - (styleResolver->styleMap()->*mapFillFunction)(propertyId, currChild, valueList->itemWithoutBoundsCheck(i)); - prevChild = currChild; - currChild = currChild->next(); - } - } else { - (styleResolver->styleMap()->*mapFillFunction)(propertyId, currChild, value); - currChild = currChild->next(); - } - while (currChild) { - /* Reset all remaining layers to not have the property set. */ - (currChild->*clearFunction)(); - currChild = currChild->next(); - } - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -enum ComputeLengthNormal {NormalDisabled = 0, NormalEnabled}; -enum ComputeLengthThickness {ThicknessDisabled = 0, ThicknessEnabled}; -enum ComputeLengthSVGZoom {SVGZoomDisabled = 0, SVGZoomEnabled}; -template -class ApplyPropertyComputeLength { -public: - static void setValue(RenderStyle* style, T value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - // note: CSSPropertyLetter/WordSpacing right now sets to zero if it's not a primitive value for some reason... - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - CSSValueID ident = primitiveValue->getValueID(); - T length; - if (normalEnabled && ident == CSSValueNormal) { - length = 0; - } else if (thicknessEnabled && ident == CSSValueThin) { - length = 1; - } else if (thicknessEnabled && ident == CSSValueMedium) { - length = 3; - } else if (thicknessEnabled && ident == CSSValueThick) { - length = 5; - } else if (ident == CSSValueInvalid) { - float zoom = (svgZoomEnabled && styleResolver->useSVGZoomRules()) ? 1.0f : styleResolver->style()->effectiveZoom(); - - // Any original result that was >= 1 should not be allowed to fall below 1. - // This keeps border lines from vanishing. - length = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), zoom); - if (zoom < 1.0f && length < 1.0) { - T originalLength = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), 1.0); - if (originalLength >= 1.0) - length = 1.0; - } - if (primitiveValue->isViewportPercentageLength()) - length = styleResolver->viewportPercentageValue(*primitiveValue, length); - } else { - ASSERT_NOT_REACHED(); - length = 0; - } - - setValue(styleResolver->style(), length); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template -class ApplyPropertyFont { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->fontDescription(); - (fontDescription.*setterFunction)((styleResolver->parentFontDescription().*getterFunction)()); - styleResolver->setFontDescription(fontDescription); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->fontDescription(); - (fontDescription.*setterFunction)(initialValue); - styleResolver->setFontDescription(fontDescription); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - FontDescription fontDescription = styleResolver->fontDescription(); - (fontDescription.*setterFunction)(*primitiveValue); - styleResolver->setFontDescription(fontDescription); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyFontFamily { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->style()->fontDescription(); - FontDescription parentFontDescription = styleResolver->parentStyle()->fontDescription(); - - fontDescription.setGenericFamily(parentFontDescription.genericFamily()); - fontDescription.setFamilies(parentFontDescription.families()); - fontDescription.setIsSpecifiedFont(parentFontDescription.isSpecifiedFont()); - styleResolver->setFontDescription(fontDescription); - return; - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->style()->fontDescription(); - FontDescription initialDesc = FontDescription(); - - // We need to adjust the size to account for the generic family change from monospace to non-monospace. - if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize()) - styleResolver->setFontSize(fontDescription, Style::fontSizeForKeyword(CSSValueXxSmall + fontDescription.keywordSize() - 1, false, styleResolver->document())); - fontDescription.setGenericFamily(initialDesc.genericFamily()); - if (!initialDesc.firstFamily().isEmpty()) - fontDescription.setFamilies(initialDesc.families()); - - styleResolver->setFontDescription(fontDescription); - return; - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isValueList()) - return; - - auto& valueList = toCSSValueList(*value); - - FontDescription fontDescription = styleResolver->style()->fontDescription(); - // Before mapping in a new font-family property, we should reset the generic family. - bool oldFamilyUsedFixedDefaultSize = fontDescription.useFixedDefaultSize(); - fontDescription.setGenericFamily(FontDescription::NoFamily); - - Vector families; - families.reserveInitialCapacity(valueList.length()); - - for (unsigned i = 0; i < valueList.length(); ++i) { - CSSValue* item = valueList.item(i); - if (!item->isPrimitiveValue()) - continue; - CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item); - AtomicString face; - if (contentValue->isString()) - face = contentValue->getStringValue(); - else if (Settings* settings = styleResolver->document().settings()) { - switch (contentValue->getValueID()) { - case CSSValueWebkitBody: - face = settings->standardFontFamily(); - break; - case CSSValueSerif: - face = serifFamily; - fontDescription.setGenericFamily(FontDescription::SerifFamily); - break; - case CSSValueSansSerif: - face = sansSerifFamily; - fontDescription.setGenericFamily(FontDescription::SansSerifFamily); - break; - case CSSValueCursive: - face = cursiveFamily; - fontDescription.setGenericFamily(FontDescription::CursiveFamily); - break; - case CSSValueFantasy: - face = fantasyFamily; - fontDescription.setGenericFamily(FontDescription::FantasyFamily); - break; - case CSSValueMonospace: - face = monospaceFamily; - fontDescription.setGenericFamily(FontDescription::MonospaceFamily); - break; - case CSSValueWebkitPictograph: - face = pictographFamily; - fontDescription.setGenericFamily(FontDescription::PictographFamily); - break; - default: - break; - } - } - - if (face.isEmpty()) - continue; - if (families.isEmpty()) - fontDescription.setIsSpecifiedFont(fontDescription.genericFamily() == FontDescription::NoFamily); - families.uncheckedAppend(face); - } - - if (families.isEmpty()) - return; - fontDescription.setFamilies(families); - - if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize) - styleResolver->setFontSize(fontDescription, Style::fontSizeForKeyword(CSSValueXxSmall + fontDescription.keywordSize() - 1, !oldFamilyUsedFixedDefaultSize, styleResolver->document())); - - styleResolver->setFontDescription(fontDescription); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyFontSize { -private: - // When the CSS keyword "larger" is used, this function will attempt to match within the keyword - // table, and failing that, will simply multiply by 1.2. - static float largerFontSize(float size) - { - // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale up to - // the next size level. - return size * 1.2f; - } - - // Like the previous function, but for the keyword "smaller". - static float smallerFontSize(float size) - { - // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale down to - // the next size level. - return size / 1.2f; - } -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - float size = styleResolver->parentStyle()->fontDescription().specifiedSize(); - - if (size < 0) - return; - - FontDescription fontDescription = styleResolver->style()->fontDescription(); - fontDescription.setKeywordSize(styleResolver->parentStyle()->fontDescription().keywordSize()); - styleResolver->setFontSize(fontDescription, size); - styleResolver->setFontDescription(fontDescription); - return; - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->style()->fontDescription(); - float size = Style::fontSizeForKeyword(CSSValueMedium, fontDescription.useFixedDefaultSize(), styleResolver->document()); - - if (size < 0) - return; - - fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); - styleResolver->setFontSize(fontDescription, size); - styleResolver->setFontDescription(fontDescription); - return; - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - FontDescription fontDescription = styleResolver->style()->fontDescription(); - fontDescription.setKeywordSize(0); - float parentSize = 0; - bool parentIsAbsoluteSize = false; - float size = 0; - - if (styleResolver->parentStyle()) { - parentSize = styleResolver->parentStyle()->fontDescription().specifiedSize(); - parentIsAbsoluteSize = styleResolver->parentStyle()->fontDescription().isAbsoluteSize(); - } - - if (CSSValueID ident = primitiveValue->getValueID()) { - // Keywords are being used. - switch (ident) { - case CSSValueXxSmall: - case CSSValueXSmall: - case CSSValueSmall: - case CSSValueMedium: - case CSSValueLarge: - case CSSValueXLarge: - case CSSValueXxLarge: - case CSSValueWebkitXxxLarge: - size = Style::fontSizeForKeyword(ident, fontDescription.useFixedDefaultSize(), styleResolver->document()); - fontDescription.setKeywordSize(ident - CSSValueXxSmall + 1); - break; - case CSSValueLarger: - size = largerFontSize(parentSize); - break; - case CSSValueSmaller: - size = smallerFontSize(parentSize); - break; - default: - return; - } - - fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && (ident == CSSValueLarger || ident == CSSValueSmaller)); - } else { - fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize - || !(primitiveValue->isPercentage() || primitiveValue->isFontRelativeLength())); - if (primitiveValue->isLength()) - size = primitiveValue->computeLength(styleResolver->parentStyle(), styleResolver->rootElementStyle(), 1.0, true); - else if (primitiveValue->isPercentage()) - size = (primitiveValue->getFloatValue() * parentSize) / 100.0f; - else if (primitiveValue->isCalculatedPercentageWithLength()) - size = primitiveValue->cssCalcValue()->toCalcValue(styleResolver->parentStyle(), styleResolver->rootElementStyle())->evaluate(parentSize); - else if (primitiveValue->isViewportPercentageLength()) - size = valueForLength(primitiveValue->viewportPercentageLength(), 0, styleResolver->document().renderView()); - else - return; - } - - if (size < 0) - return; - - // Overly large font sizes will cause crashes on some platforms (such as Windows). - // Cap font size here to make sure that doesn't happen. - size = std::min(maximumAllowedFontSize, size); - - styleResolver->setFontSize(fontDescription, size); - styleResolver->setFontDescription(fontDescription); - return; - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyFontWeight { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - FontDescription fontDescription = styleResolver->fontDescription(); - switch (primitiveValue->getValueID()) { - case CSSValueInvalid: - ASSERT_NOT_REACHED(); - break; - case CSSValueBolder: - fontDescription.setWeight(fontDescription.bolderWeight()); - break; - case CSSValueLighter: - fontDescription.setWeight(fontDescription.lighterWeight()); - break; - default: - fontDescription.setWeight(*primitiveValue); - } - styleResolver->setFontDescription(fontDescription); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyFont::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyFontVariantLigatures { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - const FontDescription& parentFontDescription = styleResolver->parentFontDescription(); - FontDescription fontDescription = styleResolver->fontDescription(); - - fontDescription.setCommonLigaturesState(parentFontDescription.commonLigaturesState()); - fontDescription.setDiscretionaryLigaturesState(parentFontDescription.discretionaryLigaturesState()); - fontDescription.setHistoricalLigaturesState(parentFontDescription.historicalLigaturesState()); - - styleResolver->setFontDescription(fontDescription); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - FontDescription fontDescription = styleResolver->fontDescription(); - - fontDescription.setCommonLigaturesState(FontDescription::NormalLigaturesState); - fontDescription.setDiscretionaryLigaturesState(FontDescription::NormalLigaturesState); - fontDescription.setHistoricalLigaturesState(FontDescription::NormalLigaturesState); - - styleResolver->setFontDescription(fontDescription); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - FontDescription::LigaturesState commonLigaturesState = FontDescription::NormalLigaturesState; - FontDescription::LigaturesState discretionaryLigaturesState = FontDescription::NormalLigaturesState; - FontDescription::LigaturesState historicalLigaturesState = FontDescription::NormalLigaturesState; - - if (value->isValueList()) { - CSSValueList* valueList = toCSSValueList(value); - for (size_t i = 0; i < valueList->length(); ++i) { - CSSValue* item = valueList->itemWithoutBoundsCheck(i); - ASSERT(item->isPrimitiveValue()); - if (item->isPrimitiveValue()) { - switch (toCSSPrimitiveValue(item)->getValueID()) { - case CSSValueNoCommonLigatures: - commonLigaturesState = FontDescription::DisabledLigaturesState; - break; - case CSSValueCommonLigatures: - commonLigaturesState = FontDescription::EnabledLigaturesState; - break; - case CSSValueNoDiscretionaryLigatures: - discretionaryLigaturesState = FontDescription::DisabledLigaturesState; - break; - case CSSValueDiscretionaryLigatures: - discretionaryLigaturesState = FontDescription::EnabledLigaturesState; - break; - case CSSValueNoHistoricalLigatures: - historicalLigaturesState = FontDescription::DisabledLigaturesState; - break; - case CSSValueHistoricalLigatures: - historicalLigaturesState = FontDescription::EnabledLigaturesState; - break; - default: - ASSERT_NOT_REACHED(); - break; - } - } - } - } -#if !ASSERT_DISABLED - else { - ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue()); - ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal); - } -#endif - - FontDescription fontDescription = styleResolver->fontDescription(); - fontDescription.setCommonLigaturesState(commonLigaturesState); - fontDescription.setDiscretionaryLigaturesState(discretionaryLigaturesState); - fontDescription.setHistoricalLigaturesState(historicalLigaturesState); - styleResolver->setFontDescription(fontDescription); - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; - -enum BorderImageType { BorderImage = 0, BorderMask }; -template -class ApplyPropertyBorderImage { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - NinePieceImage image; - if (borderImageType == BorderMask) - image.setMaskDefaults(); - styleResolver->styleMap()->mapNinePieceImage(property, value, image); - (styleResolver->style()->*setterFunction)(image); - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -enum BorderImageModifierType { Outset, Repeat, Slice, Width }; -template -class ApplyPropertyBorderImageModifier { -private: - static inline const NinePieceImage& getValue(RenderStyle* style) { return type == BorderImage ? style->borderImage() : style->maskBoxImage(); } - static inline void setValue(RenderStyle* style, const NinePieceImage& value) { return type == BorderImage ? style->setBorderImage(value) : style->setMaskBoxImage(value); } -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - NinePieceImage image(getValue(styleResolver->style())); - switch (modifier) { - case Outset: - image.copyOutsetFrom(getValue(styleResolver->parentStyle())); - break; - case Repeat: - image.copyRepeatFrom(getValue(styleResolver->parentStyle())); - break; - case Slice: - image.copyImageSlicesFrom(getValue(styleResolver->parentStyle())); - break; - case Width: - image.copyBorderSlicesFrom(getValue(styleResolver->parentStyle())); - break; - } - setValue(styleResolver->style(), image); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - NinePieceImage image(getValue(styleResolver->style())); - switch (modifier) { - case Outset: - image.setOutset(LengthBox(0)); - break; - case Repeat: - image.setHorizontalRule(StretchImageRule); - image.setVerticalRule(StretchImageRule); - break; - case Slice: - // Masks have a different initial value for slices. Preserve the value of 0 for backwards compatibility. - image.setImageSlices(type == BorderImage ? LengthBox(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent)) : LengthBox()); - image.setFill(false); - break; - case Width: - // Masks have a different initial value for widths. They use an 'auto' value rather than trying to fit to the border. - image.setBorderSlices(type == BorderImage ? LengthBox(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative)) : LengthBox()); - break; - } - setValue(styleResolver->style(), image); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - NinePieceImage image(getValue(styleResolver->style())); - switch (modifier) { - case Outset: - image.setOutset(styleResolver->styleMap()->mapNinePieceImageQuad(value)); - break; - case Repeat: - styleResolver->styleMap()->mapNinePieceImageRepeat(value, image); - break; - case Slice: - styleResolver->styleMap()->mapNinePieceImageSlice(value, image); - break; - case Width: - image.setBorderSlices(styleResolver->styleMap()->mapNinePieceImageQuad(value)); - break; - } - setValue(styleResolver->style(), image); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -template ), StyleImage* (*initialFunction)()> -class ApplyPropertyBorderImageSource { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) { (styleResolver->style()->*setterFunction)(styleResolver->styleImage(id, value)); } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase, setterFunction, StyleImage*, initialFunction>::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -enum CounterBehavior {Increment = 0, Reset}; -template -class ApplyPropertyCounter { -public: - static void emptyFunction(CSSPropertyID, StyleResolver*) { } - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - CounterDirectiveMap& map = styleResolver->style()->accessCounterDirectives(); - CounterDirectiveMap& parentMap = styleResolver->parentStyle()->accessCounterDirectives(); - - typedef CounterDirectiveMap::iterator Iterator; - Iterator end = parentMap.end(); - for (Iterator it = parentMap.begin(); it != end; ++it) { - CounterDirectives& directives = map.add(it->key, CounterDirectives()).iterator->value; - if (counterBehavior == Reset) { - directives.inheritReset(it->value); - } else { - directives.inheritIncrement(it->value); - } - } - } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - bool setCounterIncrementToNone = counterBehavior == Increment && value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNone; - - if (!value->isValueList() && !setCounterIncrementToNone) - return; - - CounterDirectiveMap& map = styleResolver->style()->accessCounterDirectives(); - typedef CounterDirectiveMap::iterator Iterator; - - Iterator end = map.end(); - for (Iterator it = map.begin(); it != end; ++it) - if (counterBehavior == Reset) - it->value.clearReset(); - else - it->value.clearIncrement(); - - if (setCounterIncrementToNone) - return; - - CSSValueList* list = toCSSValueList(value); - int length = list ? list->length() : 0; - for (int i = 0; i < length; ++i) { - CSSValue* currValue = list->itemWithoutBoundsCheck(i); - if (!currValue->isPrimitiveValue()) - continue; - - Pair* pair = toCSSPrimitiveValue(currValue)->getPairValue(); - if (!pair || !pair->first() || !pair->second()) - continue; - - AtomicString identifier = static_cast(pair->first())->getStringValue(); - int value = static_cast(pair->second())->getIntValue(); - CounterDirectives& directives = map.add(identifier, CounterDirectives()).iterator->value; - if (counterBehavior == Reset) { - directives.setResetValue(value); - } else { - directives.addIncrementValue(value); - } - } - } - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &emptyFunction, &applyValue); } -}; - - -class ApplyPropertyCursor { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setCursor(styleResolver->parentStyle()->cursor()); - styleResolver->style()->setCursorList(styleResolver->parentStyle()->cursors()); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->clearCursorList(); - styleResolver->style()->setCursor(RenderStyle::initialCursor()); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - styleResolver->style()->clearCursorList(); - if (value->isValueList()) { - CSSValueList* list = toCSSValueList(value); - int len = list->length(); - styleResolver->style()->setCursor(CURSOR_AUTO); - for (int i = 0; i < len; i++) { - CSSValue* item = list->itemWithoutBoundsCheck(i); - if (item->isCursorImageValue()) { - CSSCursorImageValue* image = toCSSCursorImageValue(item); - if (image->updateIfSVGCursorIsUsed(styleResolver->element())) // Elements with SVG cursors are not allowed to share style. - styleResolver->style()->setUnique(); - styleResolver->style()->addCursor(styleResolver->styleImage(CSSPropertyCursor, image), image->hotSpot()); - } else if (item->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item); - if (primitiveValue->isValueID()) - styleResolver->style()->setCursor(*primitiveValue); - } - } - } else if (value->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->isValueID() && styleResolver->style()->cursor() != ECursor(*primitiveValue)) - styleResolver->style()->setCursor(*primitiveValue); - } - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyTextAlign { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - ASSERT(primitiveValue->isValueID()); - - if (primitiveValue->getValueID() != CSSValueWebkitMatchParent) - styleResolver->style()->setTextAlign(*primitiveValue); - else if (styleResolver->parentStyle()->textAlign() == TASTART) - styleResolver->style()->setTextAlign(styleResolver->parentStyle()->isLeftToRightDirection() ? LEFT : RIGHT); - else if (styleResolver->parentStyle()->textAlign() == TAEND) - styleResolver->style()->setTextAlign(styleResolver->parentStyle()->isLeftToRightDirection() ? RIGHT : LEFT); - else - styleResolver->style()->setTextAlign(styleResolver->parentStyle()->textAlign()); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyTextDecoration { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - TextDecoration t = RenderStyle::initialTextDecoration(); - for (CSSValueListIterator i(value); i.hasMore(); i.advance()) { - CSSValue* item = i.value(); - ASSERT_WITH_SECURITY_IMPLICATION(item->isPrimitiveValue()); - t |= *toCSSPrimitiveValue(item); - } - styleResolver->style()->setTextDecoration(t); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -static TextDecorationSkip valueToDecorationSkip(CSSPrimitiveValue& primitiveValue) -{ - ASSERT(primitiveValue.isValueID()); - - switch (primitiveValue.getValueID()) { - case CSSValueNone: - return TextDecorationSkipNone; - case CSSValueInk: - return TextDecorationSkipInk; - default: - break; - } - - ASSERT_NOT_REACHED(); - return TextDecorationSkipNone; -} - -class ApplyPropertyTextDecorationSkip { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isPrimitiveValue()) { - styleResolver->style()->setTextDecorationSkip(valueToDecorationSkip(*toCSSPrimitiveValue(value))); - return; - } - - TextDecorationSkip skip = RenderStyle::initialTextDecorationSkip(); - for (CSSValueListIterator i(value); i.hasMore(); i.advance()) - skip |= valueToDecorationSkip(*toCSSPrimitiveValue(i.value())); - styleResolver->style()->setTextDecorationSkip(skip); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyMarqueeIncrement { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID()) { - switch (primitiveValue->getValueID()) { - case CSSValueSmall: - styleResolver->style()->setMarqueeIncrement(Length(1, Fixed)); // 1px. - break; - case CSSValueNormal: - styleResolver->style()->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default. - break; - case CSSValueLarge: - styleResolver->style()->setMarqueeIncrement(Length(36, Fixed)); // 36px. - break; - default: - break; - } - } else { - Length marqueeLength = styleResolver->convertToIntLength(primitiveValue, styleResolver->style(), styleResolver->rootElementStyle()); - if (!marqueeLength.isUndefined()) - styleResolver->style()->setMarqueeIncrement(marqueeLength); - } - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyLength<&RenderStyle::marqueeIncrement, &RenderStyle::setMarqueeIncrement, &RenderStyle::initialMarqueeIncrement>::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyMarqueeRepetition { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueInfinite) - styleResolver->style()->setMarqueeLoopCount(-1); // -1 means repeat forever. - else if (primitiveValue->isNumber()) - styleResolver->style()->setMarqueeLoopCount(primitiveValue->getIntValue()); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefault::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyMarqueeSpeed { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (CSSValueID ident = primitiveValue->getValueID()) { - switch (ident) { - case CSSValueSlow: - styleResolver->style()->setMarqueeSpeed(500); // 500 msec. - break; - case CSSValueNormal: - styleResolver->style()->setMarqueeSpeed(85); // 85msec. The WinIE default. - break; - case CSSValueFast: - styleResolver->style()->setMarqueeSpeed(10); // 10msec. Super fast. - break; - default: - break; - } - } else if (primitiveValue->isTime()) - styleResolver->style()->setMarqueeSpeed(primitiveValue->computeTime()); - else if (primitiveValue->isNumber()) // For scrollamount support. - styleResolver->style()->setMarqueeSpeed(primitiveValue->getIntValue()); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefault::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyTextUnderlinePosition { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - // This is true if value is 'auto' or 'alphabetic'. - if (value->isPrimitiveValue()) { - TextUnderlinePosition t = *toCSSPrimitiveValue(value); - styleResolver->style()->setTextUnderlinePosition(t); - return; - } - - unsigned t = 0; - for (CSSValueListIterator i(value); i.hasMore(); i.advance()) { - CSSValue* item = i.value(); - ASSERT_WITH_SECURITY_IMPLICATION(item->isPrimitiveValue()); - TextUnderlinePosition t2 = *toCSSPrimitiveValue(item); - t |= t2; - } - styleResolver->style()->setTextUnderlinePosition(static_cast(t)); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyLineHeight { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Length lineHeight; - - if (primitiveValue->getValueID() == CSSValueNormal) - lineHeight = RenderStyle::initialLineHeight(); - else if (primitiveValue->isLength()) { - double multiplier = styleResolver->style()->effectiveZoom(); - if (Frame* frame = styleResolver->document().frame()) - multiplier *= frame->textZoomFactor(); - lineHeight = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), multiplier); - } else if (primitiveValue->isPercentage()) { - // FIXME: percentage should not be restricted to an integer here. - lineHeight = Length((styleResolver->style()->computedFontSize() * primitiveValue->getIntValue()) / 100, Fixed); - } else if (primitiveValue->isNumber()) { - // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent). - lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent); - } else if (primitiveValue->isViewportPercentageLength()) - lineHeight = primitiveValue->viewportPercentageLength(); - else - return; - styleResolver->style()->setLineHeight(lineHeight); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -#if ENABLE(IOS_TEXT_AUTOSIZING) -// FIXME: Share more code with class ApplyPropertyLineHeight. -class ApplyPropertyLineHeightForIOSTextAutosizing { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Length lineHeight; - - if (primitiveValue->getValueID() == CSSValueNormal) - lineHeight = RenderStyle::initialLineHeight(); - else if (primitiveValue->isLength()) { - double multiplier = styleResolver->style()->effectiveZoom(); - if (styleResolver->style()->textSizeAdjust().isNone()) { - if (Frame* frame = styleResolver->document().frame()) - multiplier *= frame->textZoomFactor(); - } - lineHeight = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), multiplier); - if (styleResolver->style()->textSizeAdjust().isPercentage()) - lineHeight = Length(lineHeight.value() * styleResolver->style()->textSizeAdjust().multiplier(), Fixed); - } else if (primitiveValue->isPercentage()) { - // FIXME: percentage should not be restricted to an integer here. - lineHeight = Length((styleResolver->style()->fontSize() * primitiveValue->getIntValue()) / 100, Fixed); - } else if (primitiveValue->isNumber()) { - // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent). - if (styleResolver->style()->textSizeAdjust().isPercentage()) - lineHeight = Length(primitiveValue->getDoubleValue() * styleResolver->style()->textSizeAdjust().multiplier() * 100.0, Percent); - else - lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent); - } else if (primitiveValue->isViewportPercentageLength()) - lineHeight = primitiveValue->viewportPercentageLength(); - else - return; - styleResolver->style()->setLineHeight(lineHeight); - styleResolver->style()->setSpecifiedLineHeight(lineHeight); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setLineHeight(RenderStyle::initialLineHeight()); - styleResolver->style()->setSpecifiedLineHeight(RenderStyle::initialSpecifiedLineHeight()); - } - - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setLineHeight(styleResolver->parentStyle()->lineHeight()); - styleResolver->style()->setSpecifiedLineHeight(styleResolver->parentStyle()->specifiedLineHeight()); - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; -#endif - -class ApplyPropertyWordSpacing { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - Length wordSpacing; - - if (primitiveValue->getValueID() == CSSValueNormal) - wordSpacing = RenderStyle::initialWordSpacing(); - else if (primitiveValue->isLength()) { - double multiplier = styleResolver->style()->effectiveZoom(); - if (Frame* frame = styleResolver->document().frame()) - multiplier *= frame->textZoomFactor(); - wordSpacing = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle(), multiplier); - } else if (primitiveValue->isPercentage()) - wordSpacing = Length(clampTo(primitiveValue->getDoubleValue(), minValueForCssLength, maxValueForCssLength), Percent); - else if (primitiveValue->isNumber()) - wordSpacing = Length(primitiveValue->getDoubleValue(), Fixed); - else if (primitiveValue->isViewportPercentageLength()) - wordSpacing = Length(styleResolver->viewportPercentageValue(*primitiveValue, primitiveValue->getDoubleValue()), Fixed); - else - return; - styleResolver->style()->setWordSpacing(wordSpacing); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyPageSize { -private: - static Length mmLength(double mm) - { - Ref value(CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM)); - return value.get().computeLength(0, 0); - } - static Length inchLength(double inch) - { - Ref value(CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN)); - return value.get().computeLength(0, 0); - } - static bool getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height) - { - DEFINE_STATIC_LOCAL(Length, a5Width, (mmLength(148))); - DEFINE_STATIC_LOCAL(Length, a5Height, (mmLength(210))); - DEFINE_STATIC_LOCAL(Length, a4Width, (mmLength(210))); - DEFINE_STATIC_LOCAL(Length, a4Height, (mmLength(297))); - DEFINE_STATIC_LOCAL(Length, a3Width, (mmLength(297))); - DEFINE_STATIC_LOCAL(Length, a3Height, (mmLength(420))); - DEFINE_STATIC_LOCAL(Length, b5Width, (mmLength(176))); - DEFINE_STATIC_LOCAL(Length, b5Height, (mmLength(250))); - DEFINE_STATIC_LOCAL(Length, b4Width, (mmLength(250))); - DEFINE_STATIC_LOCAL(Length, b4Height, (mmLength(353))); - DEFINE_STATIC_LOCAL(Length, letterWidth, (inchLength(8.5))); - DEFINE_STATIC_LOCAL(Length, letterHeight, (inchLength(11))); - DEFINE_STATIC_LOCAL(Length, legalWidth, (inchLength(8.5))); - DEFINE_STATIC_LOCAL(Length, legalHeight, (inchLength(14))); - DEFINE_STATIC_LOCAL(Length, ledgerWidth, (inchLength(11))); - DEFINE_STATIC_LOCAL(Length, ledgerHeight, (inchLength(17))); - - if (!pageSizeName) - return false; - - switch (pageSizeName->getValueID()) { - case CSSValueA5: - width = a5Width; - height = a5Height; - break; - case CSSValueA4: - width = a4Width; - height = a4Height; - break; - case CSSValueA3: - width = a3Width; - height = a3Height; - break; - case CSSValueB5: - width = b5Width; - height = b5Height; - break; - case CSSValueB4: - width = b4Width; - height = b4Height; - break; - case CSSValueLetter: - width = letterWidth; - height = letterHeight; - break; - case CSSValueLegal: - width = legalWidth; - height = legalHeight; - break; - case CSSValueLedger: - width = ledgerWidth; - height = ledgerHeight; - break; - default: - return false; - } - - if (pageOrientation) { - switch (pageOrientation->getValueID()) { - case CSSValueLandscape: - std::swap(width, height); - break; - case CSSValuePortrait: - // Nothing to do. - break; - default: - return false; - } - } - return true; - } -public: - static void applyInheritValue(CSSPropertyID, StyleResolver*) { } - static void applyInitialValue(CSSPropertyID, StyleResolver*) { } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - styleResolver->style()->resetPageSizeType(); - Length width; - Length height; - PageSizeType pageSizeType = PAGE_SIZE_AUTO; - CSSValueListInspector inspector(value); - switch (inspector.length()) { - case 2: { - // {2} | - if (!inspector.first()->isPrimitiveValue() || !inspector.second()->isPrimitiveValue()) - return; - CSSPrimitiveValue* first = toCSSPrimitiveValue(inspector.first()); - CSSPrimitiveValue* second = toCSSPrimitiveValue(inspector.second()); - if (first->isLength()) { - // {2} - if (!second->isLength()) - return; - width = first->computeLength(styleResolver->style(), styleResolver->rootElementStyle()); - height = second->computeLength(styleResolver->style(), styleResolver->rootElementStyle()); - } else { - // - // The value order is guaranteed. See CSSParser::parseSizeParameter. - if (!getPageSizeFromName(first, second, width, height)) - return; - } - pageSizeType = PAGE_SIZE_RESOLVED; - break; - } - case 1: { - // | auto | | [ portrait | landscape] - if (!inspector.first()->isPrimitiveValue()) - return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inspector.first()); - if (primitiveValue->isLength()) { - // - pageSizeType = PAGE_SIZE_RESOLVED; - width = height = primitiveValue->computeLength(styleResolver->style(), styleResolver->rootElementStyle()); - } else { - switch (primitiveValue->getValueID()) { - case 0: - return; - case CSSValueAuto: - pageSizeType = PAGE_SIZE_AUTO; - break; - case CSSValuePortrait: - pageSizeType = PAGE_SIZE_AUTO_PORTRAIT; - break; - case CSSValueLandscape: - pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE; - break; - default: - // - pageSizeType = PAGE_SIZE_RESOLVED; - if (!getPageSizeFromName(primitiveValue, 0, width, height)) - return; - } - } - break; - } - default: - return; - } - styleResolver->style()->setPageSizeType(pageSizeType); - styleResolver->style()->setPageSize(LengthSize(width, height)); - } - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyTextEmphasisStyle { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setTextEmphasisFill(styleResolver->parentStyle()->textEmphasisFill()); - styleResolver->style()->setTextEmphasisMark(styleResolver->parentStyle()->textEmphasisMark()); - styleResolver->style()->setTextEmphasisCustomMark(styleResolver->parentStyle()->textEmphasisCustomMark()); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setTextEmphasisFill(RenderStyle::initialTextEmphasisFill()); - styleResolver->style()->setTextEmphasisMark(RenderStyle::initialTextEmphasisMark()); - styleResolver->style()->setTextEmphasisCustomMark(RenderStyle::initialTextEmphasisCustomMark()); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isValueList()) { - CSSValueList* list = toCSSValueList(value); - ASSERT(list->length() == 2); - if (list->length() != 2) - return; - for (unsigned i = 0; i < 2; ++i) { - CSSValue* item = list->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) - continue; - - CSSPrimitiveValue* value = toCSSPrimitiveValue(item); - if (value->getValueID() == CSSValueFilled || value->getValueID() == CSSValueOpen) - styleResolver->style()->setTextEmphasisFill(*value); - else - styleResolver->style()->setTextEmphasisMark(*value); - } - styleResolver->style()->setTextEmphasisCustomMark(nullAtom); - return; - } - - if (!value->isPrimitiveValue()) - return; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - if (primitiveValue->isString()) { - styleResolver->style()->setTextEmphasisFill(TextEmphasisFillFilled); - styleResolver->style()->setTextEmphasisMark(TextEmphasisMarkCustom); - styleResolver->style()->setTextEmphasisCustomMark(primitiveValue->getStringValue()); - return; - } - - styleResolver->style()->setTextEmphasisCustomMark(nullAtom); - - if (primitiveValue->getValueID() == CSSValueFilled || primitiveValue->getValueID() == CSSValueOpen) { - styleResolver->style()->setTextEmphasisFill(*primitiveValue); - styleResolver->style()->setTextEmphasisMark(TextEmphasisMarkAuto); - } else { - styleResolver->style()->setTextEmphasisFill(TextEmphasisFillFilled); - styleResolver->style()->setTextEmphasisMark(*primitiveValue); - } - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -static TextEmphasisPosition valueToEmphasisPosition(CSSPrimitiveValue& primitiveValue) -{ - ASSERT(primitiveValue.isValueID()); - - switch (primitiveValue.getValueID()) { - case CSSValueOver: - return TextEmphasisPositionOver; - case CSSValueUnder: - return TextEmphasisPositionUnder; - case CSSValueLeft: - return TextEmphasisPositionLeft; - case CSSValueRight: - return TextEmphasisPositionRight; - default: - break; - } - - ASSERT_NOT_REACHED(); - return RenderStyle::initialTextEmphasisPosition(); -} - -class ApplyPropertyTextEmphasisPosition { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isPrimitiveValue()) { - styleResolver->style()->setTextEmphasisPosition(valueToEmphasisPosition(*toCSSPrimitiveValue(value))); - return; - } - - TextEmphasisPosition position = 0; - for (CSSValueListIterator i(value); i.hasMore(); i.advance()) - position |= valueToEmphasisPosition(*toCSSPrimitiveValue(i.value())); - styleResolver->style()->setTextEmphasisPosition(position); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -template -class ApplyPropertyAnimation { -public: - static void setValue(Animation& animation, T value) { (animation.*setterFunction)(value); } - static T value(const Animation& animation) { return (animation.*getterFunction)(); } - static bool test(const Animation& animation) { return (animation.*testFunction)(); } - static void clear(Animation& animation) { (animation.*clearFunction)(); } - static T initial() { return (*initialFunction)(); } - static void map(StyleResolver* styleResolver, Animation& animation, CSSValue* value) { (styleResolver->styleMap()->*mapFunction)(&animation, value); } - static AnimationList* accessAnimations(RenderStyle* style) { return (style->*animationGetterFunction)(); } - static const AnimationList* animations(RenderStyle* style) { return (style->*immutableAnimationGetterFunction)(); } - - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - AnimationList* list = accessAnimations(styleResolver->style()); - const AnimationList* parentList = animations(styleResolver->parentStyle()); - size_t i = 0, parentSize = parentList ? parentList->size() : 0; - for ( ; i < parentSize && test(parentList->animation(i)); ++i) { - if (list->size() <= i) - list->append(Animation::create()); - setValue(list->animation(i), value(parentList->animation(i))); - list->animation(i).setAnimationMode(parentList->animation(i).animationMode()); - } - - /* Reset any remaining animations to not have the property set. */ - for ( ; i < list->size(); ++i) - clear(list->animation(i)); - } - - static void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - AnimationList* list = accessAnimations(styleResolver->style()); - if (list->isEmpty()) - list->append(Animation::create()); - setValue(list->animation(0), initial()); - if (propertyID == CSSPropertyWebkitTransitionProperty) - list->animation(0).setAnimationMode(Animation::AnimateAll); - for (size_t i = 1; i < list->size(); ++i) - clear(list->animation(i)); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - AnimationList* list = accessAnimations(styleResolver->style()); - size_t childIndex = 0; - if (value->isValueList()) { - /* Walk each value and put it into an animation, creating new animations as needed. */ - for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { - if (childIndex <= list->size()) - list->append(Animation::create()); - map(styleResolver, list->animation(childIndex), i.value()); - ++childIndex; - } - } else { - if (list->isEmpty()) - list->append(Animation::create()); - map(styleResolver, list->animation(childIndex), value); - childIndex = 1; - } - for ( ; childIndex < list->size(); ++childIndex) { - /* Reset all remaining animations to not have the property set. */ - clear(list->animation(childIndex)); - } - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyOutlineStyle { -public: - static void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - ApplyPropertyDefaultBase::applyInheritValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInheritValue(propertyID, styleResolver); - } - - static void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - ApplyPropertyDefaultBase::applyInitialValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInitialValue(propertyID, styleResolver); - } - - static void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) - { - ApplyPropertyDefault::applyValue(propertyID, styleResolver, value); - ApplyPropertyDefault::applyValue(propertyID, styleResolver, value); - } - - static PropertyHandler createHandler() { return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); } -}; - -class ApplyPropertyResize { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - EResize r = RESIZE_NONE; - switch (primitiveValue->getValueID()) { - case 0: - return; - case CSSValueAuto: - if (Settings* settings = styleResolver->document().settings()) - r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE; - break; - default: - r = *primitiveValue; - } - styleResolver->style()->setResize(r); - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyVerticalAlign { -public: - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - if (primitiveValue->getValueID()) - return styleResolver->style()->setVerticalAlign(*primitiveValue); - - styleResolver->style()->setVerticalAlignLength(primitiveValue->convertToLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())); - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -class ApplyPropertyAspectRatio { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - if (!styleResolver->parentStyle()->hasAspectRatio()) - return; - styleResolver->style()->setHasAspectRatio(true); - styleResolver->style()->setAspectRatioDenominator(styleResolver->parentStyle()->aspectRatioDenominator()); - styleResolver->style()->setAspectRatioNumerator(styleResolver->parentStyle()->aspectRatioNumerator()); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setHasAspectRatio(RenderStyle::initialHasAspectRatio()); - styleResolver->style()->setAspectRatioDenominator(RenderStyle::initialAspectRatioDenominator()); - styleResolver->style()->setAspectRatioNumerator(RenderStyle::initialAspectRatioNumerator()); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isAspectRatioValue()) { - styleResolver->style()->setHasAspectRatio(false); - return; - } - CSSAspectRatioValue* aspectRatioValue = toCSSAspectRatioValue(value); - styleResolver->style()->setHasAspectRatio(true); - styleResolver->style()->setAspectRatioDenominator(aspectRatioValue->denominatorValue()); - styleResolver->style()->setAspectRatioNumerator(aspectRatioValue->numeratorValue()); - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; - -class ApplyPropertyZoom { -private: - static void resetEffectiveZoom(StyleResolver* styleResolver) - { - // Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect. - styleResolver->setEffectiveZoom(styleResolver->parentStyle() ? styleResolver->parentStyle()->effectiveZoom() : RenderStyle::initialZoom()); - } - -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - resetEffectiveZoom(styleResolver); - styleResolver->setZoom(styleResolver->parentStyle()->zoom()); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - resetEffectiveZoom(styleResolver); - styleResolver->setZoom(RenderStyle::initialZoom()); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue()); - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - - if (primitiveValue->getValueID() == CSSValueNormal) { - resetEffectiveZoom(styleResolver); - styleResolver->setZoom(RenderStyle::initialZoom()); - } else if (primitiveValue->getValueID() == CSSValueReset) { - styleResolver->setEffectiveZoom(RenderStyle::initialZoom()); - styleResolver->setZoom(RenderStyle::initialZoom()); - } else if (primitiveValue->getValueID() == CSSValueDocument) { - float docZoom = styleResolver->rootElementStyle() ? styleResolver->rootElementStyle()->zoom() : RenderStyle::initialZoom(); - styleResolver->setEffectiveZoom(docZoom); - styleResolver->setZoom(docZoom); - } else if (primitiveValue->isPercentage()) { - resetEffectiveZoom(styleResolver); - if (float percent = primitiveValue->getFloatValue()) - styleResolver->setZoom(percent / 100.0f); - } else if (primitiveValue->isNumber()) { - resetEffectiveZoom(styleResolver); - if (float number = primitiveValue->getFloatValue()) - styleResolver->setZoom(number); - } - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; - -class ApplyPropertyDisplay { -private: - static inline bool isValidDisplayValue(StyleResolver* styleResolver, EDisplay displayPropertyValue) - { -#if ENABLE(SVG) - if (styleResolver->element() && styleResolver->element()->isSVGElement() && styleResolver->style()->styleType() == NOPSEUDO) - return (displayPropertyValue == INLINE || displayPropertyValue == BLOCK || displayPropertyValue == NONE); -#else - UNUSED_PARAM(styleResolver); - UNUSED_PARAM(displayPropertyValue); -#endif - return true; - } -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - EDisplay display = styleResolver->parentStyle()->display(); - if (!isValidDisplayValue(styleResolver, display)) - return; - styleResolver->style()->setDisplay(display); - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setDisplay(RenderStyle::initialDisplay()); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isPrimitiveValue()) - return; - - EDisplay display = *toCSSPrimitiveValue(value); - - if (!isValidDisplayValue(styleResolver, display)) - return; - - styleResolver->style()->setDisplay(display); - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; - -template ), ClipPathOperation* (*initialFunction)()> -class ApplyPropertyClipPath { -public: - static void setValue(RenderStyle* style, PassRefPtr value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isPrimitiveValue()) { - auto& primitiveValue = toCSSPrimitiveValue(*value); - if (primitiveValue.getValueID() == CSSValueNone) - setValue(styleResolver->style(), 0); -#if ENABLE(SVG) - else if (primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_URI) { - String cssURLValue = primitiveValue.getStringValue(); - URL url = styleResolver->document().completeURL(cssURLValue); - // FIXME: It doesn't work with external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=126133) - setValue(styleResolver->style(), ReferenceClipPathOperation::create(cssURLValue, url.fragmentIdentifier())); - } -#endif - return; - } - if (!value->isValueList()) - return; - LayoutBox referenceBox = BoxMissing; - RefPtr operation; - auto& valueList = toCSSValueList(*value); - for (unsigned i = 0; i < valueList.length(); ++i) { - auto& primitiveValue = toCSSPrimitiveValue(*valueList.itemWithoutBoundsCheck(i)); - if (primitiveValue.isShape() && !operation) - operation = ShapeClipPathOperation::create(basicShapeForValue(styleResolver->style(), styleResolver->rootElementStyle(), primitiveValue.getShapeValue())); - else if ((primitiveValue.getValueID() == CSSValueContentBox - || primitiveValue.getValueID() == CSSValueBorderBox - || primitiveValue.getValueID() == CSSValuePaddingBox - || primitiveValue.getValueID() == CSSValueMarginBox - || primitiveValue.getValueID() == CSSValueBoundingBox) - && referenceBox == BoxMissing) - referenceBox = LayoutBox(primitiveValue); - else - return; - } - if (!operation) { - if (referenceBox == BoxMissing) - return; - operation = BoxClipPathOperation::create(referenceBox); - } else - toShapeClipPathOperation(operation.get())->setReferenceBox(referenceBox); - setValue(styleResolver->style(), operation.release()); - } - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase, setterFunction, ClipPathOperation*, initialFunction>::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; - -#if ENABLE(CSS_SHAPES) -template ), ShapeValue* (*initialFunction)()> -class ApplyPropertyShape { -public: - static void setValue(RenderStyle* style, PassRefPtr value) { (style->*setterFunction)(value); } - static void applyValue(CSSPropertyID property, StyleResolver* styleResolver, CSSValue* value) - { - if (value->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); - if (primitiveValue->getValueID() == CSSValueAuto) - setValue(styleResolver->style(), 0); - else if (primitiveValue->getValueID() == CSSValueOutsideShape) - setValue(styleResolver->style(), ShapeValue::createOutsideValue()); - } else if (value->isImageValue() || value->isImageSetValue()) { - RefPtr shape = ShapeValue::createImageValue(styleResolver->styleImage(property, value)); - setValue(styleResolver->style(), shape.release()); - } else if (value->isValueList()) { - RefPtr shape; - LayoutBox layoutBox = BoxMissing; - CSSValueList* valueList = toCSSValueList(value); - for (unsigned i = 0; i < valueList->length(); ++i) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(valueList->itemWithoutBoundsCheck(i)); - if (primitiveValue->isShape()) - shape = basicShapeForValue(styleResolver->style(), styleResolver->rootElementStyle(), primitiveValue->getShapeValue()); - else if (primitiveValue->getValueID() == CSSValueContentBox - || primitiveValue->getValueID() == CSSValueBorderBox - || primitiveValue->getValueID() == CSSValuePaddingBox - || primitiveValue->getValueID() == CSSValueMarginBox) - layoutBox = LayoutBox(*primitiveValue); - else - return; - } - - if (shape) - setValue(styleResolver->style(), ShapeValue::createShapeValue(shape.release(), layoutBox)); - else if (layoutBox != BoxMissing) - setValue(styleResolver->style(), ShapeValue::createLayoutBoxValue(layoutBox)); - - } - } - - static PropertyHandler createHandler() - { - PropertyHandler handler = ApplyPropertyDefaultBase, setterFunction, ShapeValue*, initialFunction>::createHandler(); - return PropertyHandler(handler.inheritFunction(), handler.initialFunction(), &applyValue); - } -}; -#endif - -#if ENABLE(CSS_IMAGE_RESOLUTION) -class ApplyPropertyImageResolution { -public: - static void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - ApplyPropertyDefaultBase::applyInheritValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInheritValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInheritValue(propertyID, styleResolver); - } - - static void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) - { - ApplyPropertyDefaultBase::applyInitialValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInitialValue(propertyID, styleResolver); - ApplyPropertyDefaultBase::applyInitialValue(propertyID, styleResolver); - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isValueList()) - return; - CSSValueList* valueList = toCSSValueList(value); - ImageResolutionSource source = RenderStyle::initialImageResolutionSource(); - ImageResolutionSnap snap = RenderStyle::initialImageResolutionSnap(); - double resolution = RenderStyle::initialImageResolution(); - for (size_t i = 0; i < valueList->length(); i++) { - CSSValue* item = valueList->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) - continue; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item); - if (primitiveValue->getValueID() == CSSValueFromImage) - source = ImageResolutionFromImage; - else if (primitiveValue->getValueID() == CSSValueSnap) - snap = ImageResolutionSnapPixels; - else - resolution = primitiveValue->getDoubleValue(CSSPrimitiveValue::CSS_DPPX); - } - styleResolver->style()->setImageResolutionSource(source); - styleResolver->style()->setImageResolutionSnap(snap); - styleResolver->style()->setImageResolution(resolution); - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; -#endif - -class ApplyPropertyTextIndent { -public: - static void applyInheritValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setTextIndent(styleResolver->parentStyle()->textIndent()); -#if ENABLE(CSS3_TEXT) - styleResolver->style()->setTextIndentLine(styleResolver->parentStyle()->textIndentLine()); - styleResolver->style()->setTextIndentType(styleResolver->parentStyle()->textIndentType()); -#endif - } - - static void applyInitialValue(CSSPropertyID, StyleResolver* styleResolver) - { - styleResolver->style()->setTextIndent(RenderStyle::initialTextIndent()); -#if ENABLE(CSS3_TEXT) - styleResolver->style()->setTextIndentLine(RenderStyle::initialTextIndentLine()); - styleResolver->style()->setTextIndentType(RenderStyle::initialTextIndentType()); -#endif - } - - static void applyValue(CSSPropertyID, StyleResolver* styleResolver, CSSValue* value) - { - if (!value->isValueList()) - return; - - Length lengthOrPercentageValue; -#if ENABLE(CSS3_TEXT) - TextIndentLine textIndentLineValue = RenderStyle::initialTextIndentLine(); - TextIndentType textIndentTypeValue = RenderStyle::initialTextIndentType(); -#endif - CSSValueList* valueList = toCSSValueList(value); - for (size_t i = 0; i < valueList->length(); ++i) { - CSSValue* item = valueList->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) - continue; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item); - if (!primitiveValue->getValueID()) - lengthOrPercentageValue = primitiveValue->convertToLength(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()); -#if ENABLE(CSS3_TEXT) - else if (primitiveValue->getValueID() == CSSValueWebkitEachLine) - textIndentLineValue = TextIndentEachLine; - else if (primitiveValue->getValueID() == CSSValueWebkitHanging) - textIndentTypeValue = TextIndentHanging; -#endif - } - - ASSERT(!lengthOrPercentageValue.isUndefined()); - styleResolver->style()->setTextIndent(lengthOrPercentageValue); -#if ENABLE(CSS3_TEXT) - styleResolver->style()->setTextIndentLine(textIndentLineValue); - styleResolver->style()->setTextIndentType(textIndentTypeValue); -#endif - } - - static PropertyHandler createHandler() - { - return PropertyHandler(&applyInheritValue, &applyInitialValue, &applyValue); - } -}; - -const DeprecatedStyleBuilder& DeprecatedStyleBuilder::sharedStyleBuilder() -{ - DEFINE_STATIC_LOCAL(DeprecatedStyleBuilder, styleBuilderInstance, ()); - return styleBuilderInstance; -} - -DeprecatedStyleBuilder::DeprecatedStyleBuilder() -{ - for (int i = 0; i < numCSSProperties; ++i) - m_propertyMap[i] = PropertyHandler(); - - // Please keep CSS property list in alphabetical order. - setPropertyHandler(CSSPropertyBackgroundAttachment, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundClip, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyBackgroundImage, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundOrigin, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundPositionX, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundPositionY, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundRepeatX, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundRepeatY, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBackgroundSize, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyBorderBottomColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyBorderBottomLeftRadius, ApplyPropertyBorderRadius<&RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius, &RenderStyle::initialBorderRadius>::createHandler()); - setPropertyHandler(CSSPropertyBorderBottomRightRadius, ApplyPropertyBorderRadius<&RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius, &RenderStyle::initialBorderRadius>::createHandler()); - setPropertyHandler(CSSPropertyBorderBottomStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyBorderBottomWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyBorderCollapse, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyBorderImageOutset, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyBorderImageRepeat, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyBorderImageSlice, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyBorderImageSource, ApplyPropertyBorderImageSource::createHandler()); - setPropertyHandler(CSSPropertyBorderImageWidth, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyBorderLeftColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyBorderLeftStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyBorderLeftWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyBorderRightColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyBorderRightStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyBorderRightWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyBorderTopColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyBorderTopLeftRadius, ApplyPropertyBorderRadius<&RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius, &RenderStyle::initialBorderRadius>::createHandler()); - setPropertyHandler(CSSPropertyBorderTopRightRadius, ApplyPropertyBorderRadius<&RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius, &RenderStyle::initialBorderRadius>::createHandler()); - setPropertyHandler(CSSPropertyBorderTopStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyBorderTopWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyBottom, ApplyPropertyLength<&RenderStyle::bottom, &RenderStyle::setBottom, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyBoxSizing, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyCaptionSide, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyClear, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyClip, ApplyPropertyClip::createHandler()); - setPropertyHandler(CSSPropertyColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyCounterIncrement, ApplyPropertyCounter::createHandler()); - setPropertyHandler(CSSPropertyCounterReset, ApplyPropertyCounter::createHandler()); - setPropertyHandler(CSSPropertyCursor, ApplyPropertyCursor::createHandler()); - setPropertyHandler(CSSPropertyDirection, ApplyPropertyDirection<&RenderStyle::direction, &RenderStyle::setDirection, RenderStyle::initialDirection>::createHandler()); - setPropertyHandler(CSSPropertyDisplay, ApplyPropertyDisplay::createHandler()); - setPropertyHandler(CSSPropertyEmptyCells, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyFloat, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyFontFamily, ApplyPropertyFontFamily::createHandler()); - setPropertyHandler(CSSPropertyFontSize, ApplyPropertyFontSize::createHandler()); - setPropertyHandler(CSSPropertyFontStyle, ApplyPropertyFont::createHandler()); - setPropertyHandler(CSSPropertyFontVariant, ApplyPropertyFont::createHandler()); - setPropertyHandler(CSSPropertyFontWeight, ApplyPropertyFontWeight::createHandler()); - setPropertyHandler(CSSPropertyHeight, ApplyPropertyLength<&RenderStyle::height, &RenderStyle::setHeight, &RenderStyle::initialSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicDisabled, NoneDisabled, UndefinedDisabled>::createHandler()); -#if ENABLE(CSS_IMAGE_ORIENTATION) - setPropertyHandler(CSSPropertyImageOrientation, ApplyPropertyDefault::createHandler()); -#endif - setPropertyHandler(CSSPropertyImageRendering, ApplyPropertyDefault::createHandler()); -#if ENABLE(CSS_IMAGE_RESOLUTION) - setPropertyHandler(CSSPropertyImageResolution, ApplyPropertyImageResolution::createHandler()); -#endif - setPropertyHandler(CSSPropertyLeft, ApplyPropertyLength<&RenderStyle::left, &RenderStyle::setLeft, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyLetterSpacing, ApplyPropertyComputeLength::createHandler()); - -#if ENABLE(IOS_TEXT_AUTOSIZING) - setPropertyHandler(CSSPropertyLineHeight, ApplyPropertyLineHeightForIOSTextAutosizing::createHandler()); -#else - setPropertyHandler(CSSPropertyLineHeight, ApplyPropertyLineHeight::createHandler()); -#endif - setPropertyHandler(CSSPropertyListStyleImage, ApplyPropertyStyleImage<&RenderStyle::listStyleImage, &RenderStyle::setListStyleImage, &RenderStyle::initialListStyleImage, CSSPropertyListStyleImage>::createHandler()); - setPropertyHandler(CSSPropertyListStylePosition, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyListStyleType, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyMarginBottom, ApplyPropertyLength<&RenderStyle::marginBottom, &RenderStyle::setMarginBottom, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMarginLeft, ApplyPropertyLength<&RenderStyle::marginLeft, &RenderStyle::setMarginLeft, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMarginRight, ApplyPropertyLength<&RenderStyle::marginRight, &RenderStyle::setMarginRight, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMarginTop, ApplyPropertyLength<&RenderStyle::marginTop, &RenderStyle::setMarginTop, &RenderStyle::initialMargin, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMaxHeight, ApplyPropertyLength<&RenderStyle::maxHeight, &RenderStyle::setMaxHeight, &RenderStyle::initialMaxSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicDisabled, NoneEnabled, UndefinedEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMaxWidth, ApplyPropertyLength<&RenderStyle::maxWidth, &RenderStyle::setMaxWidth, &RenderStyle::initialMaxSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicEnabled, NoneEnabled, UndefinedEnabled>::createHandler()); - setPropertyHandler(CSSPropertyMinHeight, ApplyPropertyLength<&RenderStyle::minHeight, &RenderStyle::setMinHeight, &RenderStyle::initialMinSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicDisabled>::createHandler()); - setPropertyHandler(CSSPropertyMinWidth, ApplyPropertyLength<&RenderStyle::minWidth, &RenderStyle::setMinWidth, &RenderStyle::initialMinSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicEnabled>::createHandler()); - setPropertyHandler(CSSPropertyObjectFit, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyOpacity, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyOrphans, ApplyPropertyAuto::createHandler()); - setPropertyHandler(CSSPropertyOutlineColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyOutlineOffset, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyOutlineStyle, ApplyPropertyOutlineStyle::createHandler()); - setPropertyHandler(CSSPropertyOutlineWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyOverflowWrap, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyOverflowX, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyOverflowY, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyPaddingBottom, ApplyPropertyLength<&RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom, &RenderStyle::initialPadding>::createHandler()); - setPropertyHandler(CSSPropertyPaddingLeft, ApplyPropertyLength<&RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft, &RenderStyle::initialPadding>::createHandler()); - setPropertyHandler(CSSPropertyPaddingRight, ApplyPropertyLength<&RenderStyle::paddingRight, &RenderStyle::setPaddingRight, &RenderStyle::initialPadding>::createHandler()); - setPropertyHandler(CSSPropertyPaddingTop, ApplyPropertyLength<&RenderStyle::paddingTop, &RenderStyle::setPaddingTop, &RenderStyle::initialPadding>::createHandler()); - setPropertyHandler(CSSPropertyPageBreakAfter, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyPageBreakBefore, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyPageBreakInside, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyPointerEvents, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyPosition, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyResize, ApplyPropertyResize::createHandler()); - setPropertyHandler(CSSPropertyRight, ApplyPropertyLength<&RenderStyle::right, &RenderStyle::setRight, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertySize, ApplyPropertyPageSize::createHandler()); - setPropertyHandler(CSSPropertySpeak, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyTableLayout, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyTabSize, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyTextAlign, ApplyPropertyTextAlign::createHandler()); - setPropertyHandler(CSSPropertyTextDecoration, ApplyPropertyTextDecoration::createHandler()); -#if ENABLE(CSS3_TEXT) - setPropertyHandler(CSSPropertyWebkitTextAlignLast, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextJustify, ApplyPropertyDefault::createHandler()); -#endif // CSS3_TEXT - setPropertyHandler(CSSPropertyWebkitTextDecorationLine, ApplyPropertyTextDecoration::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextDecorationStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextDecorationColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextDecorationSkip, ApplyPropertyTextDecorationSkip::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextUnderlinePosition, ApplyPropertyTextUnderlinePosition::createHandler()); - setPropertyHandler(CSSPropertyTextIndent, ApplyPropertyTextIndent::createHandler()); - setPropertyHandler(CSSPropertyTextOverflow, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyTextRendering, ApplyPropertyFont::createHandler()); - setPropertyHandler(CSSPropertyTextTransform, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyTop, ApplyPropertyLength<&RenderStyle::top, &RenderStyle::setTop, &RenderStyle::initialOffset, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyUnicodeBidi, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyVerticalAlign, ApplyPropertyVerticalAlign::createHandler()); - setPropertyHandler(CSSPropertyVisibility, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationDelay, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationDirection, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationDuration, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationFillMode, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationIterationCount, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationName, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationPlayState, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitAnimationTimingFunction, ApplyPropertyAnimation, &Animation::timingFunction, &Animation::setTimingFunction, &Animation::isTimingFunctionSet, &Animation::clearTimingFunction, &Animation::initialAnimationTimingFunction, &CSSToStyleMap::mapAnimationTimingFunction, &RenderStyle::accessAnimations, &RenderStyle::animations>::createHandler()); - setPropertyHandler(CSSPropertyWebkitAppearance, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitAspectRatio, ApplyPropertyAspectRatio::createHandler()); - setPropertyHandler(CSSPropertyWebkitBackfaceVisibility, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBackgroundBlendMode, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitBackgroundClip, CSSPropertyBackgroundClip); - setPropertyHandler(CSSPropertyWebkitBackgroundComposite, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitBackgroundOrigin, CSSPropertyBackgroundOrigin); - setPropertyHandler(CSSPropertyWebkitBackgroundSize, CSSPropertyBackgroundSize); -#if ENABLE(CSS_COMPOSITING) - setPropertyHandler(CSSPropertyWebkitBlendMode, ApplyPropertyDefault::createHandler()); -#endif - setPropertyHandler(CSSPropertyWebkitBorderFit, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBorderHorizontalSpacing, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyWebkitBorderImage, ApplyPropertyBorderImage::createHandler()); - setPropertyHandler(CSSPropertyWebkitBorderVerticalSpacing, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxAlign, ApplyPropertyDefault::createHandler()); -#if ENABLE(CSS_BOX_DECORATION_BREAK) - setPropertyHandler(CSSPropertyWebkitBoxDecorationBreak, ApplyPropertyDefault::createHandler()); -#endif - setPropertyHandler(CSSPropertyWebkitBoxDirection, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxFlex, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxFlexGroup, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxLines, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxOrdinalGroup, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxOrient, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitBoxPack, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColorCorrection, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnAxis, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnBreakAfter, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnBreakBefore, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnBreakInside, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnCount, ApplyPropertyAuto::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnFill, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnGap, ApplyPropertyAuto::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnProgression, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnRuleColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnRuleWidth, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnSpan, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnRuleStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitColumnWidth, ApplyPropertyAuto::createHandler()); -#if ENABLE(CURSOR_VISIBILITY) - setPropertyHandler(CSSPropertyWebkitCursorVisibility, ApplyPropertyDefault::createHandler()); -#endif - setPropertyHandler(CSSPropertyWebkitAlignContent, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitAlignItems, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitAlignSelf, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlexBasis, ApplyPropertyLength<&RenderStyle::flexBasis, &RenderStyle::setFlexBasis, &RenderStyle::initialFlexBasis, AutoEnabled>::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlexDirection, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlexGrow, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlexShrink, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlexWrap, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitGridAutoFlow, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitJustifyContent, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitOrder, ApplyPropertyDefault::createHandler()); -#if ENABLE(CSS_REGIONS) - setPropertyHandler(CSSPropertyWebkitFlowFrom, ApplyPropertyString::createHandler()); - setPropertyHandler(CSSPropertyWebkitFlowInto, ApplyPropertyString::createHandler()); -#endif - setPropertyHandler(CSSPropertyWebkitFontKerning, ApplyPropertyFont::createHandler()); - setPropertyHandler(CSSPropertyWebkitFontSmoothing, ApplyPropertyFont::createHandler()); - setPropertyHandler(CSSPropertyWebkitFontVariantLigatures, ApplyPropertyFontVariantLigatures::createHandler()); - setPropertyHandler(CSSPropertyWebkitHighlight, ApplyPropertyString::createHandler()); - setPropertyHandler(CSSPropertyWebkitHyphenateCharacter, ApplyPropertyString::createHandler()); - setPropertyHandler(CSSPropertyWebkitHyphenateLimitAfter, ApplyPropertyNumber::createHandler()); - setPropertyHandler(CSSPropertyWebkitHyphenateLimitBefore, ApplyPropertyNumber::createHandler()); - setPropertyHandler(CSSPropertyWebkitHyphenateLimitLines, ApplyPropertyNumber::createHandler()); - setPropertyHandler(CSSPropertyWebkitHyphens, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitLineAlign, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitLineBreak, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitLineClamp, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitLineGrid, ApplyPropertyString::createHandler()); - setPropertyHandler(CSSPropertyWebkitLineSnap, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarginAfterCollapse, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarginBeforeCollapse, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarginBottomCollapse, CSSPropertyWebkitMarginAfterCollapse); - setPropertyHandler(CSSPropertyWebkitMarginTopCollapse, CSSPropertyWebkitMarginBeforeCollapse); - setPropertyHandler(CSSPropertyWebkitMarqueeDirection, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarqueeIncrement, ApplyPropertyMarqueeIncrement::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarqueeRepetition, ApplyPropertyMarqueeRepetition::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarqueeSpeed, ApplyPropertyMarqueeSpeed::createHandler()); - setPropertyHandler(CSSPropertyWebkitMarqueeStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImage, ApplyPropertyBorderImage::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImageOutset, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImageRepeat, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImageSlice, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImageSource, ApplyPropertyBorderImageSource::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskBoxImageWidth, ApplyPropertyBorderImageModifier::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskClip, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskComposite, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskImage, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskOrigin, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskPositionX, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskPositionY, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskRepeatX, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskRepeatY, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskSize, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitMaskSourceType, ApplyPropertyFillLayer::createHandler()); - setPropertyHandler(CSSPropertyWebkitNbspMode, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitPerspectiveOrigin, ApplyPropertyExpanding::createHandler()); - setPropertyHandler(CSSPropertyWebkitPerspectiveOriginX, ApplyPropertyLength<&RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX, &RenderStyle::initialPerspectiveOriginX>::createHandler()); - setPropertyHandler(CSSPropertyWebkitPerspectiveOriginY, ApplyPropertyLength<&RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY, &RenderStyle::initialPerspectiveOriginY>::createHandler()); - setPropertyHandler(CSSPropertyWebkitPrintColorAdjust, ApplyPropertyDefault::createHandler()); -#if ENABLE(CSS_REGIONS) - setPropertyHandler(CSSPropertyWebkitRegionBreakAfter, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitRegionBreakBefore, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitRegionBreakInside, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitRegionFragment, ApplyPropertyDefault::createHandler()); -#endif - setPropertyHandler(CSSPropertyWebkitRtlOrdering, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitRubyPosition, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextCombine, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextEmphasisColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextEmphasisPosition, ApplyPropertyTextEmphasisPosition::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextEmphasisStyle, ApplyPropertyTextEmphasisStyle::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextFillColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextSecurity, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTextStrokeColor, ApplyPropertyColor::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransformOriginX, ApplyPropertyLength<&RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX, &RenderStyle::initialTransformOriginX>::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransformOriginY, ApplyPropertyLength<&RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY, &RenderStyle::initialTransformOriginY>::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransformOriginZ, ApplyPropertyComputeLength::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransformStyle, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransitionDelay, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransitionDuration, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransitionProperty, ApplyPropertyAnimation::createHandler()); - setPropertyHandler(CSSPropertyWebkitTransitionTimingFunction, ApplyPropertyAnimation, &Animation::timingFunction, &Animation::setTimingFunction, &Animation::isTimingFunctionSet, &Animation::clearTimingFunction, &Animation::initialAnimationTimingFunction, &CSSToStyleMap::mapAnimationTimingFunction, &RenderStyle::accessTransitions, &RenderStyle::transitions>::createHandler()); - setPropertyHandler(CSSPropertyWebkitUserDrag, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitUserModify, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitUserSelect, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitClipPath, ApplyPropertyClipPath<&RenderStyle::clipPath, &RenderStyle::setClipPath, &RenderStyle::initialClipPath>::createHandler()); - -#if ENABLE(CSS_EXCLUSIONS) - setPropertyHandler(CSSPropertyWebkitWrapFlow, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitWrapThrough, ApplyPropertyDefault::createHandler()); -#endif -#if ENABLE(CSS_SHAPES) - setPropertyHandler(CSSPropertyWebkitShapeMargin, ApplyPropertyLength<&RenderStyle::shapeMargin, &RenderStyle::setShapeMargin, &RenderStyle::initialShapeMargin>::createHandler()); - setPropertyHandler(CSSPropertyWebkitShapePadding, ApplyPropertyLength<&RenderStyle::shapePadding, &RenderStyle::setShapePadding, &RenderStyle::initialShapePadding>::createHandler()); - setPropertyHandler(CSSPropertyWebkitShapeImageThreshold, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWebkitShapeInside, ApplyPropertyShape<&RenderStyle::shapeInside, &RenderStyle::setShapeInside, &RenderStyle::initialShapeInside>::createHandler()); - setPropertyHandler(CSSPropertyWebkitShapeOutside, ApplyPropertyShape<&RenderStyle::shapeOutside, &RenderStyle::setShapeOutside, &RenderStyle::initialShapeOutside>::createHandler()); -#endif - setPropertyHandler(CSSPropertyWhiteSpace, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWidows, ApplyPropertyAuto::createHandler()); - setPropertyHandler(CSSPropertyWidth, ApplyPropertyLength<&RenderStyle::width, &RenderStyle::setWidth, &RenderStyle::initialSize, AutoEnabled, LegacyIntrinsicEnabled, IntrinsicEnabled, NoneDisabled, UndefinedDisabled>::createHandler()); - setPropertyHandler(CSSPropertyWordBreak, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyWordSpacing, ApplyPropertyWordSpacing::createHandler()); - - // UAs must treat 'word-wrap' as an alternate name for the 'overflow-wrap' property. So using the same handlers. - setPropertyHandler(CSSPropertyWordWrap, ApplyPropertyDefault::createHandler()); - setPropertyHandler(CSSPropertyZIndex, ApplyPropertyAuto::createHandler()); - setPropertyHandler(CSSPropertyZoom, ApplyPropertyZoom::createHandler()); -} - - -} diff --git a/Source/WebCore/css/DeprecatedStyleBuilder.h b/Source/WebCore/css/DeprecatedStyleBuilder.h deleted file mode 100644 index 258b471cc..000000000 --- a/Source/WebCore/css/DeprecatedStyleBuilder.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DeprecatedStyleBuilder_h -#define DeprecatedStyleBuilder_h - -#include "CSSPropertyNames.h" -#include "StylePropertyShorthand.h" -#include -#include - -namespace WebCore { - -class CSSValue; -class DeprecatedStyleBuilder; -class StyleResolver; - -class PropertyHandler { -public: - typedef void (*InheritFunction)(CSSPropertyID, StyleResolver*); - typedef void (*InitialFunction)(CSSPropertyID, StyleResolver*); - typedef void (*ApplyFunction)(CSSPropertyID, StyleResolver*, CSSValue*); - PropertyHandler() : m_inherit(0), m_initial(0), m_apply(0) { } - PropertyHandler(InheritFunction inherit, InitialFunction initial, ApplyFunction apply) : m_inherit(inherit), m_initial(initial), m_apply(apply) { } - void applyInheritValue(CSSPropertyID propertyID, StyleResolver* styleResolver) const { ASSERT(m_inherit); (*m_inherit)(propertyID, styleResolver); } - void applyInitialValue(CSSPropertyID propertyID, StyleResolver* styleResolver) const { ASSERT(m_initial); (*m_initial)(propertyID, styleResolver); } - void applyValue(CSSPropertyID propertyID, StyleResolver* styleResolver, CSSValue* value) const { ASSERT(m_apply); (*m_apply)(propertyID, styleResolver, value); } - bool isValid() const { return m_inherit && m_initial && m_apply; } - InheritFunction inheritFunction() const { return m_inherit; } - InitialFunction initialFunction() { return m_initial; } - ApplyFunction applyFunction() { return m_apply; } -private: - InheritFunction m_inherit; - InitialFunction m_initial; - ApplyFunction m_apply; -}; - -class DeprecatedStyleBuilder { - WTF_MAKE_NONCOPYABLE(DeprecatedStyleBuilder); WTF_MAKE_FAST_ALLOCATED; -public: - static const DeprecatedStyleBuilder& sharedStyleBuilder(); - - const PropertyHandler& propertyHandler(CSSPropertyID property) const - { - ASSERT(valid(property)); - return m_propertyMap[index(property)]; - } -private: - DeprecatedStyleBuilder(); - static int index(CSSPropertyID property) - { - return property - firstCSSProperty; - } - - static bool valid(CSSPropertyID property) - { - int i = index(property); - return i >= 0 && i < numCSSProperties; - } - - void setPropertyHandler(CSSPropertyID property, const PropertyHandler& handler) - { - ASSERT(valid(property)); - ASSERT(!propertyHandler(property).isValid()); - ASSERT_WITH_MESSAGE(!isExpandedShorthand(property), "Shorthand property id = %d shouldn't be inserted into StyleBuilder. Shorthands should be expanded at parsing time.", property); - m_propertyMap[index(property)] = handler; - } - - void setPropertyHandler(CSSPropertyID newProperty, CSSPropertyID equivalentProperty) - { - ASSERT(valid(newProperty)); - ASSERT(valid(equivalentProperty)); - ASSERT(!propertyHandler(newProperty).isValid()); - ASSERT_WITH_MESSAGE(!isExpandedShorthand(newProperty), "Shorthand property id = %d shouldn't be inserted into StyleBuilder. Shorthands should be expanded at parsing time.", newProperty); - ASSERT_WITH_MESSAGE(!isExpandedShorthand(equivalentProperty), "Shorthand property id = %d shouldn't be inserted into StyleBuilder. Shorthands should be expanded at parsing time.", equivalentProperty); - m_propertyMap[index(newProperty)] = m_propertyMap[index(equivalentProperty)]; - } - - PropertyHandler m_propertyMap[numCSSProperties]; -}; - -} - -#endif // DeprecatedStyleBuilder_h diff --git a/Source/WebCore/css/DocumentRuleSets.cpp b/Source/WebCore/css/DocumentRuleSets.cpp index d0dd37434..b7cefd3ce 100644 --- a/Source/WebCore/css/DocumentRuleSets.cpp +++ b/Source/WebCore/css/DocumentRuleSets.cpp @@ -29,9 +29,8 @@ #include "config.h" #include "DocumentRuleSets.h" -#include "CSSDefaultStyleSheets.h" #include "CSSStyleSheet.h" -#include "DocumentStyleSheetCollection.h" +#include "ExtensionStyleSheets.h" #include "MediaQueryEvaluator.h" #include "StyleResolver.h" #include "StyleSheetContents.h" @@ -40,77 +39,68 @@ namespace WebCore { DocumentRuleSets::DocumentRuleSets() { + m_authorStyle = std::make_unique(); + m_authorStyle->disableAutoShrinkToFit(); } DocumentRuleSets::~DocumentRuleSets() { } -void DocumentRuleSets::initUserStyle(DocumentStyleSheetCollection& styleSheetCollection, const MediaQueryEvaluator& medium, StyleResolver& resolver) +void DocumentRuleSets::initUserStyle(ExtensionStyleSheets& extensionStyleSheets, const MediaQueryEvaluator& medium, StyleResolver& resolver) { - OwnPtr tempUserStyle = RuleSet::create(); - if (CSSStyleSheet* pageUserSheet = styleSheetCollection.pageUserSheet()) - tempUserStyle->addRulesFromSheet(&pageUserSheet->contents(), medium, &resolver); - collectRulesFromUserStyleSheets(styleSheetCollection.injectedUserStyleSheets(), *tempUserStyle, medium, resolver); - collectRulesFromUserStyleSheets(styleSheetCollection.documentUserStyleSheets(), *tempUserStyle, medium, resolver); + auto tempUserStyle = std::make_unique(); + if (CSSStyleSheet* pageUserSheet = extensionStyleSheets.pageUserSheet()) + tempUserStyle->addRulesFromSheet(pageUserSheet->contents(), medium, &resolver); + collectRulesFromUserStyleSheets(extensionStyleSheets.injectedUserStyleSheets(), *tempUserStyle, medium, resolver); + collectRulesFromUserStyleSheets(extensionStyleSheets.documentUserStyleSheets(), *tempUserStyle, medium, resolver); if (tempUserStyle->ruleCount() > 0 || tempUserStyle->pageRules().size() > 0) - m_userStyle = tempUserStyle.release(); + m_userStyle = WTFMove(tempUserStyle); } void DocumentRuleSets::collectRulesFromUserStyleSheets(const Vector>& userSheets, RuleSet& userStyle, const MediaQueryEvaluator& medium, StyleResolver& resolver) { for (unsigned i = 0; i < userSheets.size(); ++i) { ASSERT(userSheets[i]->contents().isUserStyleSheet()); - userStyle.addRulesFromSheet(&userSheets[i]->contents(), medium, &resolver); + userStyle.addRulesFromSheet(userSheets[i]->contents(), medium, &resolver); } } -static PassOwnPtr makeRuleSet(const Vector& rules) +static std::unique_ptr makeRuleSet(const Vector& rules) { size_t size = rules.size(); if (!size) return nullptr; - OwnPtr ruleSet = RuleSet::create(); + auto ruleSet = std::make_unique(); for (size_t i = 0; i < size; ++i) ruleSet->addRule(rules[i].rule, rules[i].selectorIndex, rules[i].hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState); ruleSet->shrinkToFit(); - return ruleSet.release(); + return ruleSet; } void DocumentRuleSets::resetAuthorStyle() { - m_authorStyle = RuleSet::create(); + m_isAuthorStyleDefined = true; + m_authorStyle = std::make_unique(); m_authorStyle->disableAutoShrinkToFit(); } -void DocumentRuleSets::appendAuthorStyleSheets(unsigned firstNew, const Vector>& styleSheets, MediaQueryEvaluator* medium, InspectorCSSOMWrappers& inspectorCSSOMWrappers, bool isViewSource, StyleResolver* resolver) +void DocumentRuleSets::appendAuthorStyleSheets(const Vector>& styleSheets, MediaQueryEvaluator* medium, InspectorCSSOMWrappers& inspectorCSSOMWrappers, StyleResolver* resolver) { // This handles sheets added to the end of the stylesheet list only. In other cases the style resolver // needs to be reconstructed. To handle insertions too the rule order numbers would need to be updated. - unsigned size = styleSheets.size(); - for (unsigned i = firstNew; i < size; ++i) { - CSSStyleSheet* cssSheet = styleSheets[i].get(); + for (auto& cssSheet : styleSheets) { ASSERT(!cssSheet->disabled()); - if (cssSheet->mediaQueries() && !medium->eval(cssSheet->mediaQueries(), resolver)) - continue; - StyleSheetContents& sheet = cssSheet->contents(); -#if ENABLE(SHADOW_DOM) - if (const ContainerNode* scope = StyleScopeResolver::scopeFor(cssSheet)) { - // FIXME: Remove a dependency to calling a StyleResolver's member function. - // If we can avoid calling resolver->ensureScopeResolver() here, we don't have to include "StyleResolver.h". - // https://bugs.webkit.org/show_bug.cgi?id=108890 - resolver->ensureScopeResolver()->ensureRuleSetFor(scope)->addRulesFromSheet(&sheet, *medium, resolver, scope); + if (cssSheet->mediaQueries() && !medium->evaluate(*cssSheet->mediaQueries(), resolver)) continue; - } -#endif - m_authorStyle->addRulesFromSheet(&sheet, *medium, resolver); - inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet); + m_authorStyle->addRulesFromSheet(cssSheet->contents(), *medium, resolver); + inspectorCSSOMWrappers.collectFromStyleSheetIfNeeded(cssSheet.get()); } m_authorStyle->shrinkToFit(); - collectFeatures(isViewSource, resolver->scopeResolver()); + collectFeatures(); } -void DocumentRuleSets::collectFeatures(bool isViewSource, StyleScopeResolver* scopeResolver) +void DocumentRuleSets::collectFeatures() const { m_features.clear(); // Collect all ids and rules using sibling selectors (:first-child and similar) @@ -118,18 +108,46 @@ void DocumentRuleSets::collectFeatures(bool isViewSource, StyleScopeResolver* sc // sharing candidates. if (CSSDefaultStyleSheets::defaultStyle) m_features.add(CSSDefaultStyleSheets::defaultStyle->features()); + m_defaultStyleVersionOnFeatureCollection = CSSDefaultStyleSheets::defaultStyleVersion; + if (m_authorStyle) m_features.add(m_authorStyle->features()); - if (isViewSource) - m_features.add(CSSDefaultStyleSheets::viewSourceStyle()->features()); - - if (scopeResolver) - scopeResolver->collectFeaturesTo(m_features); if (m_userStyle) m_features.add(m_userStyle->features()); m_siblingRuleSet = makeRuleSet(m_features.siblingRules); m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules); + + m_ancestorClassRuleSets.clear(); + m_ancestorAttributeRuleSetsForHTML.clear(); + + m_features.shrinkToFit(); +} + +RuleSet* DocumentRuleSets::ancestorClassRules(const AtomicString& className) const +{ + auto addResult = m_ancestorClassRuleSets.add(className, nullptr); + if (addResult.isNewEntry) { + if (auto* rules = m_features.ancestorClassRules.get(className)) + addResult.iterator->value = makeRuleSet(*rules); + } + return addResult.iterator->value.get(); +} + +const DocumentRuleSets::AttributeRules* DocumentRuleSets::ancestorAttributeRulesForHTML(const AtomicString& attributeName) const +{ + auto addResult = m_ancestorAttributeRuleSetsForHTML.add(attributeName, nullptr); + auto& value = addResult.iterator->value; + if (addResult.isNewEntry) { + if (auto* rules = m_features.ancestorAttributeRulesForHTML.get(attributeName)) { + value = std::make_unique(); + value->attributeSelectors.reserveCapacity(rules->selectors.size()); + for (auto* selector : rules->selectors.values()) + value->attributeSelectors.uncheckedAppend(selector); + value->ruleSet = makeRuleSet(rules->features); + } + } + return value.get(); } } // namespace WebCore diff --git a/Source/WebCore/css/DocumentRuleSets.h b/Source/WebCore/css/DocumentRuleSets.h index 00a271938..7cdb889a1 100644 --- a/Source/WebCore/css/DocumentRuleSets.h +++ b/Source/WebCore/css/DocumentRuleSets.h @@ -20,13 +20,13 @@ * */ -#ifndef DocumentRuleSets_h -#define DocumentRuleSets_h +#pragma once +#include "CSSDefaultStyleSheets.h" #include "RuleFeature.h" #include "RuleSet.h" - -#include +#include +#include #include #include @@ -34,38 +34,66 @@ namespace WebCore { class CSSStyleRule; class CSSStyleSheet; -class DocumentStyleSheetCollection; +class ExtensionStyleSheets; class InspectorCSSOMWrappers; class MediaQueryEvaluator; -class RuleSet; -class StyleScopeResolver; class DocumentRuleSets { public: DocumentRuleSets(); ~DocumentRuleSets(); - RuleSet* authorStyle() const { return m_authorStyle.get(); } + + bool isAuthorStyleDefined() const { return m_isAuthorStyleDefined; } + RuleSet& authorStyle() const { return *m_authorStyle.get(); } RuleSet* userStyle() const { return m_userStyle.get(); } - RuleFeatureSet& features() { return m_features; } - const RuleFeatureSet& features() const { return m_features; } + const RuleFeatureSet& features() const; RuleSet* sibling() const { return m_siblingRuleSet.get(); } RuleSet* uncommonAttribute() const { return m_uncommonAttributeRuleSet.get(); } + RuleSet* ancestorClassRules(const AtomicString& className) const; + + struct AttributeRules { + WTF_MAKE_FAST_ALLOCATED; + public: + Vector attributeSelectors; + std::unique_ptr ruleSet; + }; + const AttributeRules* ancestorAttributeRulesForHTML(const AtomicString&) const; - void initUserStyle(DocumentStyleSheetCollection&, const MediaQueryEvaluator&, StyleResolver&); + void initUserStyle(ExtensionStyleSheets&, const MediaQueryEvaluator&, StyleResolver&); void resetAuthorStyle(); - void appendAuthorStyleSheets(unsigned firstNew, const Vector>&, MediaQueryEvaluator*, InspectorCSSOMWrappers&, bool isViewSource, StyleResolver*); + void appendAuthorStyleSheets(const Vector>&, MediaQueryEvaluator*, InspectorCSSOMWrappers&, StyleResolver*); - void collectFeatures(bool isViewSource, StyleScopeResolver*); + RuleFeatureSet& mutableFeatures(); private: + void collectFeatures() const; void collectRulesFromUserStyleSheets(const Vector>&, RuleSet& userStyle, const MediaQueryEvaluator&, StyleResolver&); - OwnPtr m_authorStyle; - OwnPtr m_userStyle; - RuleFeatureSet m_features; - OwnPtr m_siblingRuleSet; - OwnPtr m_uncommonAttributeRuleSet; + + bool m_isAuthorStyleDefined { false }; + std::unique_ptr m_authorStyle; + std::unique_ptr m_userStyle; + + mutable RuleFeatureSet m_features; + mutable unsigned m_defaultStyleVersionOnFeatureCollection { 0 }; + mutable std::unique_ptr m_siblingRuleSet; + mutable std::unique_ptr m_uncommonAttributeRuleSet; + mutable HashMap> m_ancestorClassRuleSets; + mutable HashMap> m_ancestorAttributeRuleSetsForHTML; }; -} // namespace WebCore +inline const RuleFeatureSet& DocumentRuleSets::features() const +{ + if (m_defaultStyleVersionOnFeatureCollection < CSSDefaultStyleSheets::defaultStyleVersion) + collectFeatures(); + return m_features; +} + +// FIXME: There should be just the const version. +inline RuleFeatureSet& DocumentRuleSets::mutableFeatures() +{ + if (m_defaultStyleVersionOnFeatureCollection < CSSDefaultStyleSheets::defaultStyleVersion) + collectFeatures(); + return m_features; +} -#endif // DocumentRuleSets_h +} // namespace WebCore diff --git a/Source/WebCore/css/ElementRuleCollector.cpp b/Source/WebCore/css/ElementRuleCollector.cpp index 88f1eff18..8c2039750 100644 --- a/Source/WebCore/css/ElementRuleCollector.cpp +++ b/Source/WebCore/css/ElementRuleCollector.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) - * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov * Copyright (C) 2007, 2008 Eric Seidel * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) @@ -36,15 +36,17 @@ #include "CSSSelectorList.h" #include "CSSValueKeywords.h" #include "HTMLElement.h" -#include "InspectorInstrumentation.h" +#include "HTMLSlotElement.h" +#include "NodeRenderStyle.h" #include "RenderRegion.h" #include "SVGElement.h" -#include "SelectorCheckerFastPath.h" #include "SelectorCompiler.h" +#include "SelectorFilter.h" +#include "ShadowRoot.h" #include "StyleProperties.h" +#include "StyleScope.h" #include "StyledElement.h" - -#include +#include namespace WebCore { @@ -53,7 +55,7 @@ static const StyleProperties& leftToRightDeclaration() static NeverDestroyed> leftToRightDecl(MutableStyleProperties::create()); if (leftToRightDecl.get()->isEmpty()) leftToRightDecl.get()->setProperty(CSSPropertyDirection, CSSValueLtr); - return leftToRightDecl.get().get(); + return leftToRightDecl.get(); } static const StyleProperties& rightToLeftDeclaration() @@ -61,51 +63,72 @@ static const StyleProperties& rightToLeftDeclaration() static NeverDestroyed> rightToLeftDecl(MutableStyleProperties::create()); if (rightToLeftDecl.get()->isEmpty()) rightToLeftDecl.get()->setProperty(CSSPropertyDirection, CSSValueRtl); - return rightToLeftDecl.get().get(); + return rightToLeftDecl.get(); } class MatchRequest { public: - MatchRequest(RuleSet* ruleSet, bool includeEmptyRules = false) + MatchRequest(const RuleSet* ruleSet, bool includeEmptyRules = false, Style::ScopeOrdinal styleScopeOrdinal = Style::ScopeOrdinal::Element) : ruleSet(ruleSet) , includeEmptyRules(includeEmptyRules) + , styleScopeOrdinal(styleScopeOrdinal) { } const RuleSet* ruleSet; const bool includeEmptyRules; + Style::ScopeOrdinal styleScopeOrdinal; }; +ElementRuleCollector::ElementRuleCollector(const Element& element, const DocumentRuleSets& ruleSets, const SelectorFilter* selectorFilter) + : m_element(element) + , m_authorStyle(ruleSets.authorStyle()) + , m_userStyle(ruleSets.userStyle()) + , m_selectorFilter(selectorFilter) +{ + ASSERT(!m_selectorFilter || m_selectorFilter->parentStackIsConsistent(element.parentNode())); +} + +ElementRuleCollector::ElementRuleCollector(const Element& element, const RuleSet& authorStyle, const SelectorFilter* selectorFilter) + : m_element(element) + , m_authorStyle(authorStyle) + , m_selectorFilter(selectorFilter) +{ + ASSERT(!m_selectorFilter || m_selectorFilter->parentStackIsConsistent(element.parentNode())); +} + StyleResolver::MatchResult& ElementRuleCollector::matchedResult() { - ASSERT(m_mode == SelectorChecker::ResolvingStyle); + ASSERT(m_mode == SelectorChecker::Mode::ResolvingStyle); return m_result; } -const Vector>& ElementRuleCollector::matchedRuleList() const +const Vector>& ElementRuleCollector::matchedRuleList() const { - ASSERT(m_mode == SelectorChecker::CollectingRules); + ASSERT(m_mode == SelectorChecker::Mode::CollectingRules); return m_matchedRuleList; } -inline void ElementRuleCollector::addMatchedRule(const RuleData* rule) +inline void ElementRuleCollector::addMatchedRule(const RuleData& ruleData, unsigned specificity, Style::ScopeOrdinal styleScopeOrdinal, StyleResolver::RuleRange& ruleRange) { - if (!m_matchedRules) - m_matchedRules = std::make_unique>(); - m_matchedRules->append(rule); + // Update our first/last rule indices in the matched rules array. + ++ruleRange.lastRuleIndex; + if (ruleRange.firstRuleIndex == -1) + ruleRange.firstRuleIndex = ruleRange.lastRuleIndex; + + m_matchedRules.append({ &ruleData, specificity, styleScopeOrdinal }); } -inline void ElementRuleCollector::clearMatchedRules() +void ElementRuleCollector::clearMatchedRules() { - if (!m_matchedRules) - return; - m_matchedRules->clear(); + m_matchedRules.clear(); + m_keepAliveSlottedPseudoElementRules.clear(); } inline void ElementRuleCollector::addElementStyleProperties(const StyleProperties* propertySet, bool isCacheable) { if (!propertySet) return; - m_result.ranges.lastAuthorRule = m_result.matchedProperties.size(); + m_result.ranges.lastAuthorRule = m_result.matchedProperties().size(); if (m_result.ranges.firstAuthorRule == -1) m_result.ranges.firstAuthorRule = m_result.ranges.lastAuthorRule; m_result.addMatchedProperties(*propertySet); @@ -113,75 +136,30 @@ inline void ElementRuleCollector::addElementStyleProperties(const StylePropertie m_result.isCacheable = false; } -class MatchingUARulesScope { -public: - MatchingUARulesScope(); - ~MatchingUARulesScope(); - - static bool isMatchingUARules(); - -private: - static bool m_matchingUARules; -}; - -MatchingUARulesScope::MatchingUARulesScope() -{ - ASSERT(!m_matchingUARules); - m_matchingUARules = true; -} - -MatchingUARulesScope::~MatchingUARulesScope() -{ - m_matchingUARules = false; -} - -inline bool MatchingUARulesScope::isMatchingUARules() -{ - return m_matchingUARules; -} - -bool MatchingUARulesScope::m_matchingUARules = false; - void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { ASSERT(matchRequest.ruleSet); - ASSERT(m_state.element()); - - const StyleResolver::State& state = m_state; - Element* element = state.element(); - const StyledElement* styledElement = state.styledElement(); - const AtomicString& pseudoId = element->shadowPseudoId(); - if (!pseudoId.isEmpty()) { - ASSERT(styledElement); - collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange); - } + ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && m_pseudoStyleRequest.pseudoId != NOPSEUDO), "When in StyleInvalidation or SharingRules, SelectorChecker does not try to match the pseudo ID. While ElementRuleCollector supports matching a particular pseudoId in this case, this would indicate a error at the call site since matching a particular element should be unnecessary."); -#if ENABLE(VIDEO_TRACK) - if (element->isWebVTTElement()) - collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange); -#endif - // Check whether other types of rules are applicable in the current tree scope. Criteria for this: - // a) it's a UA rule - // b) the tree scope allows author rules - // c) the rules comes from a scoped style sheet within the same tree scope - if (!MatchingUARulesScope::isMatchingUARules() - && !element->treeScope().applyAuthorStyles()) - return; + auto* shadowRoot = m_element.containingShadowRoot(); + if (shadowRoot && shadowRoot->mode() == ShadowRootMode::UserAgent) + collectMatchingShadowPseudoElementRules(matchRequest, ruleRange); // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. - if (element->hasID()) - collectMatchingRulesForList(matchRequest.ruleSet->idRules(element->idForStyleResolution().impl()), matchRequest, ruleRange); - if (styledElement && styledElement->hasClass()) { - for (size_t i = 0; i < styledElement->classNames().size(); ++i) - collectMatchingRulesForList(matchRequest.ruleSet->classRules(styledElement->classNames()[i].impl()), matchRequest, ruleRange); + auto& id = m_element.idForStyleResolution(); + if (!id.isNull()) + collectMatchingRulesForList(matchRequest.ruleSet->idRules(id), matchRequest, ruleRange); + if (m_element.hasClass()) { + for (size_t i = 0; i < m_element.classNames().size(); ++i) + collectMatchingRulesForList(matchRequest.ruleSet->classRules(m_element.classNames()[i]), matchRequest, ruleRange); } - if (element->isLink()) + if (m_element.isLink()) collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange); - if (SelectorChecker::matchesFocusPseudoClass(element)) + if (SelectorChecker::matchesFocusPseudoClass(m_element)) collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange); - collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element->localName().impl()), matchRequest, ruleRange); + collectMatchingRulesForList(matchRequest.ruleSet->tagRules(m_element.localName(), m_element.isHTMLElement() && m_element.document().isHTMLDocument()), matchRequest, ruleRange); collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange); } @@ -203,54 +181,149 @@ void ElementRuleCollector::collectMatchingRulesForRegion(const MatchRequest& mat void ElementRuleCollector::sortAndTransferMatchedRules() { - const StyleResolver::State& state = m_state; - - if (!m_matchedRules || m_matchedRules->isEmpty()) + if (m_matchedRules.isEmpty()) return; sortMatchedRules(); - Vector& matchedRules = *m_matchedRules; - if (m_mode == SelectorChecker::CollectingRules) { - for (unsigned i = 0; i < matchedRules.size(); ++i) - m_matchedRuleList.append(matchedRules[i]->rule()); + if (m_mode == SelectorChecker::Mode::CollectingRules) { + for (const MatchedRule& matchedRule : m_matchedRules) + m_matchedRuleList.append(matchedRule.ruleData->rule()); return; } - // Now transfer the set of matched rules over to our list of declarations. - for (unsigned i = 0; i < matchedRules.size(); i++) { - if (state.style() && matchedRules[i]->containsUncommonAttributeSelector()) - state.style()->setUnique(); - m_result.addMatchedProperties(matchedRules[i]->rule()->properties(), matchedRules[i]->rule(), matchedRules[i]->linkMatchType(), matchedRules[i]->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules())); + for (const MatchedRule& matchedRule : m_matchedRules) { + m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(), matchedRule.styleScopeOrdinal); } } void ElementRuleCollector::matchAuthorRules(bool includeEmptyRules) { clearMatchedRules(); - m_result.ranges.lastAuthorRule = m_result.matchedProperties.size() - 1; - if (!m_state.element()) + m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1; + StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange(); + + { + MatchRequest matchRequest(&m_authorStyle, includeEmptyRules); + collectMatchingRules(matchRequest, ruleRange); + collectMatchingRulesForRegion(matchRequest, ruleRange); + } + + auto* parent = m_element.parentElement(); + if (parent && parent->shadowRoot()) + matchSlottedPseudoElementRules(includeEmptyRules, ruleRange); + + if (m_element.shadowRoot()) + matchHostPseudoClassRules(includeEmptyRules, ruleRange); + + if (m_element.isInShadowTree()) + matchAuthorShadowPseudoElementRules(includeEmptyRules, ruleRange); + + sortAndTransferMatchedRules(); +} + +void ElementRuleCollector::matchAuthorShadowPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange) +{ + ASSERT(m_element.isInShadowTree()); + auto& shadowRoot = *m_element.containingShadowRoot(); + if (shadowRoot.mode() != ShadowRootMode::UserAgent) + return; + // Look up shadow pseudo elements also from the host scope author style as they are web-exposed. + auto& hostAuthorRules = Style::Scope::forNode(*shadowRoot.host()).resolver().ruleSets().authorStyle(); + MatchRequest hostAuthorRequest { &hostAuthorRules, includeEmptyRules, Style::ScopeOrdinal::ContainingHost }; + collectMatchingShadowPseudoElementRules(hostAuthorRequest, ruleRange); +} + +void ElementRuleCollector::matchHostPseudoClassRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange) +{ + ASSERT(m_element.shadowRoot()); + + auto& shadowAuthorStyle = m_element.shadowRoot()->styleScope().resolver().ruleSets().authorStyle(); + auto& shadowHostRules = shadowAuthorStyle.hostPseudoClassRules(); + if (shadowHostRules.isEmpty()) return; + SetForScope change(m_isMatchingHostPseudoClass, true); + + MatchRequest hostMatchRequest { nullptr, includeEmptyRules, Style::ScopeOrdinal::Shadow }; + collectMatchingRulesForList(&shadowHostRules, hostMatchRequest, ruleRange); +} + +void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange& ruleRange) +{ + auto* slot = m_element.assignedSlot(); + auto styleScopeOrdinal = Style::ScopeOrdinal::FirstSlot; + + for (; slot; slot = slot->assignedSlot(), ++styleScopeOrdinal) { + auto& styleScope = Style::Scope::forNode(*slot); + if (!styleScope.resolver().ruleSets().isAuthorStyleDefined()) + continue; + // Find out if there are any ::slotted rules in the shadow tree matching the current slot. + // FIXME: This is really part of the slot style and could be cached when resolving it. + ElementRuleCollector collector(*slot, styleScope.resolver().ruleSets().authorStyle(), nullptr); + auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules); + if (!slottedPseudoElementRules) + continue; + // Match in the current scope. + SetForScope change(m_isMatchingSlottedPseudoElements, true); + + MatchRequest scopeMatchRequest(nullptr, includeEmptyRules, styleScopeOrdinal); + collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest, ruleRange); + + m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules)); + } +} + +void ElementRuleCollector::collectMatchingShadowPseudoElementRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) +{ + ASSERT(matchRequest.ruleSet); + ASSERT(m_element.containingShadowRoot()->mode() == ShadowRootMode::UserAgent); + + auto& rules = *matchRequest.ruleSet; +#if ENABLE(VIDEO_TRACK) + // FXIME: WebVTT should not be done by styling UA shadow trees like this. + if (m_element.isWebVTTElement()) + collectMatchingRulesForList(rules.cuePseudoRules(), matchRequest, ruleRange); +#endif + auto& pseudoId = m_element.shadowPseudoId(); + if (!pseudoId.isEmpty()) + collectMatchingRulesForList(rules.shadowPseudoElementRules(pseudoId), matchRequest, ruleRange); +} + +std::unique_ptr ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules) +{ + ASSERT(is(m_element)); + + clearMatchedRules(); + + m_mode = SelectorChecker::Mode::CollectingRules; + // Match global author rules. - MatchRequest matchRequest(m_ruleSets.authorStyle(), includeEmptyRules); + MatchRequest matchRequest(&m_authorStyle, includeEmptyRules); StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange(); - collectMatchingRules(matchRequest, ruleRange); - collectMatchingRulesForRegion(matchRequest, ruleRange); + collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange); - sortAndTransferMatchedRules(); + if (m_matchedRules.isEmpty()) + return { }; + + auto ruleDataVector = std::make_unique(); + ruleDataVector->reserveInitialCapacity(m_matchedRules.size()); + for (auto& matchedRule : m_matchedRules) + ruleDataVector->uncheckedAppend(*matchedRule.ruleData); + + return ruleDataVector; } void ElementRuleCollector::matchUserRules(bool includeEmptyRules) { - if (!m_ruleSets.userStyle()) + if (!m_userStyle) return; clearMatchedRules(); - m_result.ranges.lastUserRule = m_result.matchedProperties.size() - 1; - MatchRequest matchRequest(m_ruleSets.userStyle(), includeEmptyRules); + m_result.ranges.lastUserRule = m_result.matchedProperties().size() - 1; + MatchRequest matchRequest(m_userStyle, includeEmptyRules); StyleResolver::RuleRange ruleRange = m_result.ranges.userRuleRange(); collectMatchingRules(matchRequest, ruleRange); collectMatchingRulesForRegion(matchRequest, ruleRange); @@ -260,8 +333,6 @@ void ElementRuleCollector::matchUserRules(bool includeEmptyRules) void ElementRuleCollector::matchUARules() { - MatchingUARulesScope scope; - // First we match rules from the user agent sheet. if (CSSDefaultStyleSheets::simpleDefaultStyleSheet) m_result.isCacheable = false; @@ -270,155 +341,180 @@ void ElementRuleCollector::matchUARules() matchUARules(userAgentStyleSheet); // In quirks mode, we match rules from the quirks user agent sheet. - if (document().inQuirksMode()) + if (m_element.document().inQuirksMode()) matchUARules(CSSDefaultStyleSheets::defaultQuirksStyle); - - // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet. - if (document().isViewSource()) - matchUARules(CSSDefaultStyleSheets::viewSourceStyle()); } void ElementRuleCollector::matchUARules(RuleSet* rules) { clearMatchedRules(); - m_result.ranges.lastUARule = m_result.matchedProperties.size() - 1; + m_result.ranges.lastUARule = m_result.matchedProperties().size() - 1; StyleResolver::RuleRange ruleRange = m_result.ranges.UARuleRange(); collectMatchingRules(MatchRequest(rules), ruleRange); sortAndTransferMatchedRules(); } -inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, PseudoId& dynamicPseudo) +static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector) +{ + for (; selector; selector = selector->tagHistory()) { + if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) { + if (auto* list = selector->selectorList()) + return list->first(); + break; + } + }; + return nullptr; +} + +inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity) { - const StyleResolver::State& state = m_state; - - bool fastCheckableSelector = ruleData.hasFastCheckableSelector(); - if (fastCheckableSelector) { - // We know this selector does not include any pseudo elements. - if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) - return false; - // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. - // This is limited to HTML only so we don't need to check the namespace. - if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && state.element()->isHTMLElement()) { - if (!ruleData.hasMultipartSelector()) - return true; + // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet. + // This is limited to HTML only so we don't need to check the namespace (because of tag name match). + MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash(); + if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) { + ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "If we match based on the rule hash while collecting for a particular pseudo element ID, we would add incorrect rules for that pseudo element ID. We should never end in ruleMatches() with a pseudo element if the ruleData cannot match any pseudo element."); + + switch (matchBasedOnRuleHash) { + case MatchBasedOnRuleHash::None: + ASSERT_NOT_REACHED(); + break; + case MatchBasedOnRuleHash::Universal: + specificity = 0; + break; + case MatchBasedOnRuleHash::ClassA: + specificity = static_cast(SelectorSpecificityIncrement::ClassA); + break; + case MatchBasedOnRuleHash::ClassB: + specificity = static_cast(SelectorSpecificityIncrement::ClassB); + break; + case MatchBasedOnRuleHash::ClassC: + specificity = static_cast(SelectorSpecificityIncrement::ClassC); + break; } + return true; } #if ENABLE(CSS_SELECTOR_JIT) void* compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress(); if (!compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::NotCompiled) { - JSC::VM* vm = document().scriptExecutionContext()->vm(); + JSC::VM& vm = m_element.document().scriptExecutionContext()->vm(); SelectorCompilationStatus compilationStatus; JSC::MacroAssemblerCodeRef compiledSelectorCodeRef; - compilationStatus = SelectorCompiler::compileSelector(ruleData.selector(), vm, compiledSelectorCodeRef); + compilationStatus = SelectorCompiler::compileSelector(ruleData.selector(), &vm, SelectorCompiler::SelectorContext::RuleCollector, compiledSelectorCodeRef); ruleData.setCompiledSelector(compilationStatus, compiledSelectorCodeRef); compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress(); } - if (compiledSelectorChecker) { - if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) - return false; - if (ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) { - SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus()); - return selectorChecker(state.element()); - } - ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext); - - SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus()); - SelectorCompiler::CheckingContext context; - context.elementStyle = state.style(); - context.resolvingMode = m_mode; - return selectorChecker(state.element(), &context); - } -#endif // ENABLE(CSS_SELECTOR_JIT) + if (compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) { + SelectorCompiler::RuleCollectorSimpleSelectorChecker selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus()); +#if !ASSERT_MSG_DISABLED + unsigned ignoreSpecificity; + ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything."); +#endif +#if CSS_SELECTOR_JIT_PROFILING + ruleData.compiledSelectorUsed(); +#endif + bool selectorMatches = selectorChecker(&m_element, &specificity); - if (fastCheckableSelector) { - if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(state.element(), ruleData.selector()->tagQName())) - return false; - SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), state.element()); - if (!selectorCheckerFastPath.matchesRightmostAttributeSelector()) - return false; + if (selectorMatches && ruleData.containsUncommonAttributeSelector()) + m_didMatchUncommonAttributeSelector = true; - return selectorCheckerFastPath.matches(); + return selectorMatches; } +#endif // ENABLE(CSS_SELECTOR_JIT) - // Slow path. - SelectorChecker selectorChecker(document(), m_mode); - SelectorChecker::SelectorCheckingContext context(ruleData.selector(), state.element(), SelectorChecker::VisitedMatchEnabled); - context.elementStyle = state.style(); + SelectorChecker::CheckingContext context(m_mode); context.pseudoId = m_pseudoStyleRequest.pseudoId; context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; - if (!selectorChecker.match(context, dynamicPseudo)) - return false; - if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.pseudoId != dynamicPseudo) - return false; - return true; + context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass; + + bool selectorMatches; +#if ENABLE(CSS_SELECTOR_JIT) + if (compiledSelectorChecker) { + ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext); + + SelectorCompiler::RuleCollectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus()); + +#if CSS_SELECTOR_JIT_PROFILING + ruleData.compiledSelectorUsed(); +#endif + selectorMatches = selectorChecker(&m_element, &context, &specificity); + } else +#endif // ENABLE(CSS_SELECTOR_JIT) + { + auto* selector = ruleData.selector(); + if (m_isMatchingSlottedPseudoElements) { + selector = findSlottedPseudoElementSelector(ruleData.selector()); + if (!selector) + return false; + } + // Slow path. + SelectorChecker selectorChecker(m_element.document()); + selectorMatches = selectorChecker.match(*selector, m_element, context, specificity); + } + + if (ruleData.containsUncommonAttributeSelector()) { + if (selectorMatches || context.pseudoIDSet) + m_didMatchUncommonAttributeSelector = true; + } + m_matchedPseudoElementIds.merge(context.pseudoIDSet); + m_styleRelations.appendVector(context.styleRelations); + + return selectorMatches; } -void ElementRuleCollector::collectMatchingRulesForList(const Vector* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) +void ElementRuleCollector::collectMatchingRulesForList(const RuleSet::RuleDataVector* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange) { if (!rules) return; - const StyleResolver::State& state = m_state; - for (unsigned i = 0, size = rules->size(); i < size; ++i) { const RuleData& ruleData = rules->data()[i]; - if (m_canUseFastReject && m_selectorFilter.fastRejectSelector(ruleData.descendantSelectorIdentifierHashes())) + + if (!ruleData.canMatchPseudoElement() && m_pseudoStyleRequest.pseudoId != NOPSEUDO) + continue; + + if (m_selectorFilter && m_selectorFilter->fastRejectSelector(ruleData.descendantSelectorIdentifierHashes())) continue; StyleRule* rule = ruleData.rule(); - PseudoId dynamicPseudo = NOPSEUDO; - if (ruleMatches(ruleData, dynamicPseudo)) { - // For SharingRules testing, any match is good enough, we don't care what is matched. - if (m_mode == SelectorChecker::SharingRules) { - addMatchedRule(&ruleData); - break; - } - - // If the rule has no properties to apply, then ignore it in the non-debug mode. - const StyleProperties& properties = rule->properties(); - if (properties.isEmpty() && !matchRequest.includeEmptyRules) - continue; - // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the only reason this is needed. - if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin()) - continue; - // If we're matching normal rules, set a pseudo bit if - // we really just matched a pseudo-element. - if (dynamicPseudo != NOPSEUDO && m_pseudoStyleRequest.pseudoId == NOPSEUDO) { - if (m_mode == SelectorChecker::CollectingRules) - continue; - if (dynamicPseudo < FIRST_INTERNAL_PSEUDOID) - state.style()->setHasPseudoStyle(dynamicPseudo); - } else { - // Update our first/last rule indices in the matched rules array. - ++ruleRange.lastRuleIndex; - if (ruleRange.firstRuleIndex == -1) - ruleRange.firstRuleIndex = ruleRange.lastRuleIndex; - - // Add this rule to our list of matched rules. - addMatchedRule(&ruleData); - continue; - } - } + + // If the rule has no properties to apply, then ignore it in the non-debug mode. + // Note that if we get null back here, it means we have a rule with deferred properties, + // and that means we always have to consider it. + const StyleProperties* properties = rule->propertiesWithoutDeferredParsing(); + if (properties && properties->isEmpty() && !matchRequest.includeEmptyRules) + continue; + + // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the only reason this is needed. + if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin()) + continue; + + unsigned specificity; + if (ruleMatches(ruleData, specificity)) + addMatchedRule(ruleData, specificity, matchRequest.styleScopeOrdinal, ruleRange); } } -static inline bool compareRules(const RuleData* r1, const RuleData* r2) +static inline bool compareRules(MatchedRule r1, MatchedRule r2) { - unsigned specificity1 = r1->specificity(); - unsigned specificity2 = r2->specificity(); - return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2; + // For normal properties the earlier scope wins. This may be reversed by !important which is handled when resolving cascade. + if (r1.styleScopeOrdinal != r2.styleScopeOrdinal) + return r1.styleScopeOrdinal > r2.styleScopeOrdinal; + + if (r1.specificity != r2.specificity) + return r1.specificity < r2.specificity; + + return r1.ruleData->position() < r2.ruleData->position(); } void ElementRuleCollector::sortMatchedRules() { - ASSERT(m_matchedRules); - std::sort(m_matchedRules->begin(), m_matchedRules->end(), compareRules); + std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules); } void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool includeSMILProperties) @@ -430,17 +526,18 @@ void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool inc matchUserRules(false); // Now check author rules, beginning first with presentational attributes mapped from HTML. - if (m_state.styledElement()) { - addElementStyleProperties(m_state.styledElement()->presentationAttributeStyle()); + if (is(m_element)) { + auto& styledElement = downcast(m_element); + addElementStyleProperties(styledElement.presentationAttributeStyle()); // Now we check additional mapped declarations. // Tables and table cells share an additional mapped rule that must be applied // after all attributes, since their mapped style depends on the values of multiple attributes. - addElementStyleProperties(m_state.styledElement()->additionalPresentationAttributeStyle()); + addElementStyleProperties(styledElement.additionalPresentationAttributeStyle()); - if (m_state.styledElement()->isHTMLElement()) { + if (is(styledElement)) { bool isAuto; - TextDirection textDirection = toHTMLElement(m_state.styledElement())->directionalityIfhasDirAutoAttribute(isAuto); + TextDirection textDirection = downcast(styledElement).directionalityIfhasDirAutoAttribute(isAuto); if (isAuto) m_result.addMatchedProperties(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration()); } @@ -450,34 +547,33 @@ void ElementRuleCollector::matchAllRules(bool matchAuthorAndUserStyles, bool inc if (matchAuthorAndUserStyles) matchAuthorRules(false); - // Now check our inline style attribute. - if (matchAuthorAndUserStyles && m_state.styledElement() && m_state.styledElement()->inlineStyle()) { - // Inline style is immutable as long as there is no CSSOM wrapper. - // FIXME: Media control shadow trees seem to have problems with caching. - bool isInlineStyleCacheable = !m_state.styledElement()->inlineStyle()->isMutable() && !m_state.styledElement()->isInShadowTree(); - // FIXME: Constify. - addElementStyleProperties(m_state.styledElement()->inlineStyle(), isInlineStyleCacheable); - } + if (matchAuthorAndUserStyles && is(m_element)) { + auto& styledElement = downcast(m_element); + // Now check our inline style attribute. + if (styledElement.inlineStyle()) { + // Inline style is immutable as long as there is no CSSOM wrapper. + // FIXME: Media control shadow trees seem to have problems with caching. + bool isInlineStyleCacheable = !styledElement.inlineStyle()->isMutable() && !styledElement.isInShadowTree(); + // FIXME: Constify. + addElementStyleProperties(styledElement.inlineStyle(), isInlineStyleCacheable); + } -#if ENABLE(SVG) - // Now check SMIL animation override style. - if (includeSMILProperties && matchAuthorAndUserStyles && m_state.styledElement() && m_state.styledElement()->isSVGElement()) - addElementStyleProperties(toSVGElement(m_state.styledElement())->animatedSMILStyleProperties(), false /* isCacheable */); -#else - UNUSED_PARAM(includeSMILProperties); -#endif + // Now check SMIL animation override style. + if (includeSMILProperties && is(styledElement)) + addElementStyleProperties(downcast(styledElement).animatedSMILStyleProperties(), false /* isCacheable */); + } } -bool ElementRuleCollector::hasAnyMatchingRules(RuleSet* ruleSet) +bool ElementRuleCollector::hasAnyMatchingRules(const RuleSet* ruleSet) { clearMatchedRules(); - m_mode = SelectorChecker::SharingRules; + m_mode = SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements; int firstRuleIndex = -1, lastRuleIndex = -1; StyleResolver::RuleRange ruleRange(firstRuleIndex, lastRuleIndex); collectMatchingRules(MatchRequest(ruleSet), ruleRange); - return m_matchedRules && !m_matchedRules->isEmpty(); + return !m_matchedRules.isEmpty(); } } // namespace WebCore diff --git a/Source/WebCore/css/ElementRuleCollector.h b/Source/WebCore/css/ElementRuleCollector.h index bc735d6cc..3874c8bfb 100644 --- a/Source/WebCore/css/ElementRuleCollector.h +++ b/Source/WebCore/css/ElementRuleCollector.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014 Apple 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 @@ -19,8 +19,7 @@ * */ -#ifndef ElementRuleCollector_h -#define ElementRuleCollector_h +#pragma once #include "MediaQueryEvaluator.h" #include "SelectorChecker.h" @@ -37,23 +36,17 @@ class RenderRegion; class RuleData; class RuleSet; class SelectorFilter; -class StyleScopeResolver; + +struct MatchedRule { + const RuleData* ruleData; + unsigned specificity; + Style::ScopeOrdinal styleScopeOrdinal; +}; class ElementRuleCollector { public: - ElementRuleCollector(StyleResolver* styleResolver, const StyleResolver::State& state) - : m_state(state) - , m_ruleSets(styleResolver->ruleSets()) - , m_selectorFilter(styleResolver->selectorFilter()) - , m_scopeResolver(styleResolver->scopeResolver()) - , m_isPrintStyle(false) - , m_regionForStyling(0) - , m_pseudoStyleRequest(NOPSEUDO) - , m_sameOriginOnly(false) - , m_mode(SelectorChecker::ResolvingStyle) - , m_canUseFastReject(m_selectorFilter.parentStackIsConsistent(state.parentNode())) - { - } + ElementRuleCollector(const Element&, const DocumentRuleSets&, const SelectorFilter*); + ElementRuleCollector(const Element&, const RuleSet& authorStyle, const SelectorFilter*); void matchAllRules(bool matchAuthorAndUserStyles, bool includeSMILProperties); void matchUARules(); @@ -63,50 +56,64 @@ public: void setMode(SelectorChecker::Mode mode) { m_mode = mode; } void setPseudoStyleRequest(const PseudoStyleRequest& request) { m_pseudoStyleRequest = request; } void setSameOriginOnly(bool f) { m_sameOriginOnly = f; } - void setRegionForStyling(RenderRegion* regionForStyling) { m_regionForStyling = regionForStyling; } + void setRegionForStyling(const RenderRegion* regionForStyling) { m_regionForStyling = regionForStyling; } void setMedium(const MediaQueryEvaluator* medium) { m_isPrintStyle = medium->mediaTypeMatchSpecific("print"); } - bool hasAnyMatchingRules(RuleSet*); + bool hasAnyMatchingRules(const RuleSet*); StyleResolver::MatchResult& matchedResult(); - const Vector>& matchedRuleList() const; + const Vector>& matchedRuleList() const; + + bool hasMatchedRules() const { return !m_matchedRules.isEmpty(); } + void clearMatchedRules(); + + const PseudoIdSet& matchedPseudoElementIds() const { return m_matchedPseudoElementIds; } + const Style::Relations& styleRelations() const { return m_styleRelations; } + bool didMatchUncommonAttributeSelector() const { return m_didMatchUncommonAttributeSelector; } private: - Document& document() { return m_state.document(); } void addElementStyleProperties(const StyleProperties*, bool isCacheable = true); void matchUARules(RuleSet*); + void matchAuthorShadowPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange&); + void matchHostPseudoClassRules(bool includeEmptyRules, StyleResolver::RuleRange&); + void matchSlottedPseudoElementRules(bool includeEmptyRules, StyleResolver::RuleRange&); + + void collectMatchingShadowPseudoElementRules(const MatchRequest&, StyleResolver::RuleRange&); + std::unique_ptr collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules); void collectMatchingRules(const MatchRequest&, StyleResolver::RuleRange&); void collectMatchingRulesForRegion(const MatchRequest&, StyleResolver::RuleRange&); - void collectMatchingRulesForList(const Vector*, const MatchRequest&, StyleResolver::RuleRange&); - bool ruleMatches(const RuleData&, PseudoId&); + void collectMatchingRulesForList(const RuleSet::RuleDataVector*, const MatchRequest&, StyleResolver::RuleRange&); + bool ruleMatches(const RuleData&, unsigned &specificity); void sortMatchedRules(); void sortAndTransferMatchedRules(); - void addMatchedRule(const RuleData*); - void clearMatchedRules(); + void addMatchedRule(const RuleData&, unsigned specificity, Style::ScopeOrdinal, StyleResolver::RuleRange&); - const StyleResolver::State& m_state; - DocumentRuleSets& m_ruleSets; - SelectorFilter& m_selectorFilter; - StyleScopeResolver* m_scopeResolver; + const Element& m_element; + const RuleSet& m_authorStyle; + const RuleSet* m_userStyle { nullptr }; + const SelectorFilter* m_selectorFilter { nullptr }; - bool m_isPrintStyle; - RenderRegion* m_regionForStyling; - PseudoStyleRequest m_pseudoStyleRequest; - bool m_sameOriginOnly; - SelectorChecker::Mode m_mode; - bool m_canUseFastReject; + bool m_isPrintStyle { false }; + const RenderRegion* m_regionForStyling { nullptr }; + PseudoStyleRequest m_pseudoStyleRequest { NOPSEUDO }; + bool m_sameOriginOnly { false }; + SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle }; + bool m_isMatchingSlottedPseudoElements { false }; + bool m_isMatchingHostPseudoClass { false }; + Vector> m_keepAliveSlottedPseudoElementRules; - std::unique_ptr> m_matchedRules; + Vector m_matchedRules; // Output. - Vector> m_matchedRuleList; + Vector> m_matchedRuleList; + bool m_didMatchUncommonAttributeSelector { false }; StyleResolver::MatchResult m_result; + Style::Relations m_styleRelations; + PseudoIdSet m_matchedPseudoElementIds; }; } // namespace WebCore - -#endif // ElementRuleCollector_h diff --git a/Source/WebCore/css/FontFace.cpp b/Source/WebCore/css/FontFace.cpp new file mode 100644 index 000000000..6fb77c07a --- /dev/null +++ b/Source/WebCore/css/FontFace.cpp @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontFace.h" + +#include "CSSFontFaceSource.h" +#include "CSSFontFeatureValue.h" +#include "CSSParser.h" +#include "CSSUnicodeRangeValue.h" +#include "CSSValueList.h" +#include "CSSValuePool.h" +#include "Document.h" +#include "FontVariantBuilder.h" +#include "JSFontFace.h" +#include "StyleProperties.h" +#include +#include +#include + +namespace WebCore { + +static bool populateFontFaceWithArrayBuffer(CSSFontFace& fontFace, Ref&& arrayBufferView) +{ + auto source = std::make_unique(fontFace, String(), nullptr, nullptr, WTFMove(arrayBufferView)); + fontFace.adoptSource(WTFMove(source)); + return false; +} + +ExceptionOr> FontFace::create(Document& document, const String& family, Source&& source, const Descriptors& descriptors) +{ + auto result = adoptRef(*new FontFace(document.fontSelector())); + + bool dataRequiresAsynchronousLoading = true; + + auto setFamilyResult = result->setFamily(family); + if (setFamilyResult.hasException()) + return setFamilyResult.releaseException(); + + auto sourceConversionResult = WTF::switchOn(source, + [&] (String& string) -> ExceptionOr { + auto value = FontFace::parseString(string, CSSPropertySrc); + if (!is(value.get())) + return Exception { SYNTAX_ERR }; + CSSFontFace::appendSources(result->backing(), downcast(*value), &document, false); + return { }; + }, + [&] (RefPtr& arrayBufferView) -> ExceptionOr { + dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull()); + return { }; + }, + [&] (RefPtr& arrayBuffer) -> ExceptionOr { + unsigned byteLength = arrayBuffer->byteLength(); + auto arrayBufferView = JSC::Uint8Array::create(WTFMove(arrayBuffer), 0, byteLength); + dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull()); + return { }; + } + ); + + if (sourceConversionResult.hasException()) + return sourceConversionResult.releaseException(); + + // These ternaries match the default strings inside the FontFaceDescriptors dictionary inside FontFace.idl. + auto setStyleResult = result->setStyle(descriptors.style.isEmpty() ? ASCIILiteral("normal") : descriptors.style); + if (setStyleResult.hasException()) + return setStyleResult.releaseException(); + auto setWeightResult = result->setWeight(descriptors.weight.isEmpty() ? ASCIILiteral("normal") : descriptors.weight); + if (setWeightResult.hasException()) + return setWeightResult.releaseException(); + auto setStretchResult = result->setStretch(descriptors.stretch.isEmpty() ? ASCIILiteral("normal") : descriptors.stretch); + if (setStretchResult.hasException()) + return setStretchResult.releaseException(); + auto setUnicodeRangeResult = result->setUnicodeRange(descriptors.unicodeRange.isEmpty() ? ASCIILiteral("U+0-10FFFF") : descriptors.unicodeRange); + if (setUnicodeRangeResult.hasException()) + return setUnicodeRangeResult.releaseException(); + auto setVariantResult = result->setVariant(descriptors.variant.isEmpty() ? ASCIILiteral("normal") : descriptors.variant); + if (setVariantResult.hasException()) + return setVariantResult.releaseException(); + auto setFeatureSettingsResult = result->setFeatureSettings(descriptors.featureSettings.isEmpty() ? ASCIILiteral("normal") : descriptors.featureSettings); + if (setFeatureSettingsResult.hasException()) + return setFeatureSettingsResult.releaseException(); + + if (!dataRequiresAsynchronousLoading) { + result->backing().load(); + ASSERT(result->backing().status() == CSSFontFace::Status::Success); + } + + return WTFMove(result); +} + +Ref FontFace::create(CSSFontFace& face) +{ + return adoptRef(*new FontFace(face)); +} + +FontFace::FontFace(CSSFontSelector& fontSelector) + : m_weakPtrFactory(this) + , m_backing(CSSFontFace::create(&fontSelector, nullptr, this)) +{ + m_backing->addClient(*this); +} + +FontFace::FontFace(CSSFontFace& face) + : m_weakPtrFactory(this) + , m_backing(face) +{ + m_backing->addClient(*this); +} + +FontFace::~FontFace() +{ + m_backing->removeClient(*this); +} + +WeakPtr FontFace::createWeakPtr() const +{ + return m_weakPtrFactory.createWeakPtr(); +} + +RefPtr FontFace::parseString(const String& string, CSSPropertyID propertyID) +{ + // FIXME: Should use the Document to get the right parsing mode. + return CSSParser::parseFontFaceDescriptor(propertyID, string, HTMLStandardMode); +} + +ExceptionOr FontFace::setFamily(const String& family) +{ + if (family.isEmpty()) + return Exception { SYNTAX_ERR }; + + bool success = false; + if (auto value = parseString(family, CSSPropertyFontFamily)) + success = m_backing->setFamilies(*value); + if (!success) + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr FontFace::setStyle(const String& style) +{ + if (style.isEmpty()) + return Exception { SYNTAX_ERR }; + + bool success = false; + if (auto value = parseString(style, CSSPropertyFontStyle)) + success = m_backing->setStyle(*value); + if (!success) + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr FontFace::setWeight(const String& weight) +{ + if (weight.isEmpty()) + return Exception { SYNTAX_ERR }; + + bool success = false; + if (auto value = parseString(weight, CSSPropertyFontWeight)) + success = m_backing->setWeight(*value); + if (!success) + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr FontFace::setStretch(const String&) +{ + // We don't support font-stretch. Swallow the call. + return { }; +} + +ExceptionOr FontFace::setUnicodeRange(const String& unicodeRange) +{ + if (unicodeRange.isEmpty()) + return Exception { SYNTAX_ERR }; + + bool success = false; + if (auto value = parseString(unicodeRange, CSSPropertyUnicodeRange)) + success = m_backing->setUnicodeRange(*value); + if (!success) + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr FontFace::setVariant(const String& variant) +{ + if (variant.isEmpty()) + return Exception { SYNTAX_ERR }; + + auto style = MutableStyleProperties::create(); + auto result = CSSParser::parseValue(style, CSSPropertyFontVariant, variant, true, HTMLStandardMode); + if (result == CSSParser::ParseResult::Error) + return Exception { SYNTAX_ERR }; + + // FIXME: Would be much better to stage the new settings and set them all at once + // instead of this dance where we make a backup and revert to it if something fails. + FontVariantSettings backup = m_backing->variantSettings(); + + auto normal = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); + bool success = true; + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantLigatures)) + success &= m_backing->setVariantLigatures(*value); + else + m_backing->setVariantLigatures(normal); + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantPosition)) + success &= m_backing->setVariantPosition(*value); + else + m_backing->setVariantPosition(normal); + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantCaps)) + success &= m_backing->setVariantCaps(*value); + else + m_backing->setVariantCaps(normal); + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantNumeric)) + success &= m_backing->setVariantNumeric(*value); + else + m_backing->setVariantNumeric(normal); + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantAlternates)) + success &= m_backing->setVariantAlternates(*value); + else + m_backing->setVariantAlternates(normal); + + if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantEastAsian)) + success &= m_backing->setVariantEastAsian(*value); + else + m_backing->setVariantEastAsian(normal); + + if (!success) { + m_backing->setVariantSettings(backup); + return Exception { SYNTAX_ERR }; + } + + return { }; +} + +ExceptionOr FontFace::setFeatureSettings(const String& featureSettings) +{ + if (featureSettings.isEmpty()) + return Exception { SYNTAX_ERR }; + + auto value = parseString(featureSettings, CSSPropertyFontFeatureSettings); + if (!value) + return Exception { SYNTAX_ERR }; + m_backing->setFeatureSettings(*value); + return { }; +} + +String FontFace::family() const +{ + m_backing->updateStyleIfNeeded(); + return m_backing->families()->cssText(); +} + +String FontFace::style() const +{ + m_backing->updateStyleIfNeeded(); + switch (m_backing->traitsMask() & FontStyleMask) { + case FontStyleNormalMask: + return String("normal", String::ConstructFromLiteral); + case FontStyleItalicMask: + return String("italic", String::ConstructFromLiteral); + } + ASSERT_NOT_REACHED(); + return String("normal", String::ConstructFromLiteral); +} + +String FontFace::weight() const +{ + m_backing->updateStyleIfNeeded(); + switch (m_backing->traitsMask() & FontWeightMask) { + case FontWeight100Mask: + return String("100", String::ConstructFromLiteral); + case FontWeight200Mask: + return String("200", String::ConstructFromLiteral); + case FontWeight300Mask: + return String("300", String::ConstructFromLiteral); + case FontWeight400Mask: + return String("normal", String::ConstructFromLiteral); + case FontWeight500Mask: + return String("500", String::ConstructFromLiteral); + case FontWeight600Mask: + return String("600", String::ConstructFromLiteral); + case FontWeight700Mask: + return String("bold", String::ConstructFromLiteral); + case FontWeight800Mask: + return String("800", String::ConstructFromLiteral); + case FontWeight900Mask: + return String("900", String::ConstructFromLiteral); + } + ASSERT_NOT_REACHED(); + return String("normal", String::ConstructFromLiteral); +} + +String FontFace::stretch() const +{ + return ASCIILiteral("normal"); +} + +String FontFace::unicodeRange() const +{ + m_backing->updateStyleIfNeeded(); + if (!m_backing->ranges().size()) + return ASCIILiteral("U+0-10FFFF"); + RefPtr values = CSSValueList::createCommaSeparated(); + for (auto& range : m_backing->ranges()) + values->append(CSSUnicodeRangeValue::create(range.from, range.to)); + return values->cssText(); +} + +String FontFace::variant() const +{ + m_backing->updateStyleIfNeeded(); + return computeFontVariant(m_backing->variantSettings())->cssText(); +} + +String FontFace::featureSettings() const +{ + m_backing->updateStyleIfNeeded(); + if (!m_backing->featureSettings().size()) + return ASCIILiteral("normal"); + RefPtr list = CSSValueList::createCommaSeparated(); + for (auto& feature : m_backing->featureSettings()) + list->append(CSSFontFeatureValue::create(FontTag(feature.tag()), feature.value())); + return list->cssText(); +} + +auto FontFace::status() const -> LoadStatus +{ + switch (m_backing->status()) { + case CSSFontFace::Status::Pending: + return LoadStatus::Unloaded; + case CSSFontFace::Status::Loading: + return LoadStatus::Loading; + case CSSFontFace::Status::TimedOut: + return LoadStatus::Error; + case CSSFontFace::Status::Success: + return LoadStatus::Loaded; + case CSSFontFace::Status::Failure: + return LoadStatus::Error; + } + ASSERT_NOT_REACHED(); + return LoadStatus::Error; +} + +void FontFace::adopt(CSSFontFace& newFace) +{ + m_backing->removeClient(*this); + m_backing = newFace; + m_backing->addClient(*this); + newFace.setWrapper(*this); +} + +void FontFace::fontStateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState) +{ + ASSERT_UNUSED(face, &face == m_backing.ptr()); + switch (newState) { + case CSSFontFace::Status::Loading: + // We still need to resolve promises when loading completes, even if all references to use have fallen out of scope. + ref(); + break; + case CSSFontFace::Status::TimedOut: + break; + case CSSFontFace::Status::Success: + if (m_promise) + std::exchange(m_promise, std::nullopt)->resolve(*this); + deref(); + return; + case CSSFontFace::Status::Failure: + if (m_promise) + std::exchange(m_promise, std::nullopt)->reject(NETWORK_ERR); + deref(); + return; + case CSSFontFace::Status::Pending: + ASSERT_NOT_REACHED(); + return; + } +} + +void FontFace::registerLoaded(Promise&& promise) +{ + ASSERT(!m_promise); + switch (m_backing->status()) { + case CSSFontFace::Status::Loading: + case CSSFontFace::Status::Pending: + m_promise = WTFMove(promise); + return; + case CSSFontFace::Status::Success: + promise.resolve(*this); + return; + case CSSFontFace::Status::TimedOut: + case CSSFontFace::Status::Failure: + promise.reject(NETWORK_ERR); + return; + } +} + +void FontFace::load() +{ + m_backing->load(); +} + +} diff --git a/Source/WebCore/css/FontFace.h b/Source/WebCore/css/FontFace.h new file mode 100644 index 000000000..0b06ce977 --- /dev/null +++ b/Source/WebCore/css/FontFace.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007, 2008, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSFontFace.h" +#include "CSSPropertyNames.h" +#include "JSDOMPromise.h" +#include +#include + +namespace JSC { +class ArrayBuffer; +class ArrayBufferView; +} + +namespace WebCore { + +class FontFace final : public RefCounted, private CSSFontFace::Client { +public: + struct Descriptors { + String style; + String weight; + String stretch; + String unicodeRange; + String variant; + String featureSettings; + }; + + using Source = Variant, RefPtr>; + static ExceptionOr> create(Document&, const String& family, Source&&, const Descriptors&); + static Ref create(CSSFontFace&); + virtual ~FontFace(); + + ExceptionOr setFamily(const String&); + ExceptionOr setStyle(const String&); + ExceptionOr setWeight(const String&); + ExceptionOr setStretch(const String&); + ExceptionOr setUnicodeRange(const String&); + ExceptionOr setVariant(const String&); + ExceptionOr setFeatureSettings(const String&); + + String family() const; + String style() const; + String weight() const; + String stretch() const; + String unicodeRange() const; + String variant() const; + String featureSettings() const; + + enum class LoadStatus { Unloaded, Loading, Loaded, Error }; + LoadStatus status() const; + + using Promise = DOMPromise>; + std::optional& promise() { return m_promise; } + void registerLoaded(Promise&&); + + void adopt(CSSFontFace&); + + void load(); + + CSSFontFace& backing() { return m_backing; } + + static RefPtr parseString(const String&, CSSPropertyID); + + void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) final; + + WeakPtr createWeakPtr() const; + + void ref() final { RefCounted::ref(); } + void deref() final { RefCounted::deref(); } + +private: + explicit FontFace(CSSFontSelector&); + explicit FontFace(CSSFontFace&); + + WeakPtrFactory m_weakPtrFactory; + Ref m_backing; + std::optional m_promise; +}; + +} diff --git a/Source/WebCore/css/FontFace.idl b/Source/WebCore/css/FontFace.idl new file mode 100644 index 000000000..3995c95cc --- /dev/null +++ b/Source/WebCore/css/FontFace.idl @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +typedef (ArrayBuffer or ArrayBufferView) BinaryData; + +enum FontFaceLoadStatus { + "unloaded", + "loading", + "loaded", + "error" +}; + +dictionary FontFaceDescriptors { + DOMString style = "normal"; + DOMString weight = "normal"; + DOMString stretch = "normal"; + DOMString unicodeRange = "U+0-10FFFF"; + DOMString variant = "normal"; + DOMString featureSettings = "normal"; +}; + +[ + ConstructorCallWith=Document, + ConstructorMayThrowException, + Constructor(DOMString family, (DOMString or BinaryData) source, optional FontFaceDescriptors descriptors) +] interface FontFace { + [SetterMayThrowException] attribute DOMString family; + [SetterMayThrowException] attribute DOMString style; + [SetterMayThrowException] attribute DOMString weight; + [SetterMayThrowException] attribute DOMString stretch; + [SetterMayThrowException] attribute DOMString unicodeRange; + [SetterMayThrowException] attribute DOMString variant; + [SetterMayThrowException] attribute DOMString featureSettings; + + readonly attribute FontFaceLoadStatus status; + + [Custom] Promise load(); + [CachedAttribute, CustomGetter] readonly attribute Promise loaded; +}; diff --git a/Source/WebCore/css/FontFaceSet.cpp b/Source/WebCore/css/FontFaceSet.cpp new file mode 100644 index 000000000..5b5268b7f --- /dev/null +++ b/Source/WebCore/css/FontFaceSet.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontFaceSet.h" + +#include "Document.h" +#include "ExceptionCodeDescription.h" +#include "FontFace.h" +#include "JSDOMBinding.h" +#include "JSDOMCoreException.h" +#include "JSFontFace.h" +#include "JSFontFaceSet.h" + +namespace WebCore { + +Ref FontFaceSet::create(Document& document, const Vector>& initialFaces) +{ + Ref result = adoptRef(*new FontFaceSet(document, initialFaces)); + result->suspendIfNeeded(); + return result; +} + +Ref FontFaceSet::create(Document& document, CSSFontFaceSet& backing) +{ + Ref result = adoptRef(*new FontFaceSet(document, backing)); + result->suspendIfNeeded(); + return result; +} + +FontFaceSet::FontFaceSet(Document& document, const Vector>& initialFaces) + : ActiveDOMObject(&document) + , m_backing(CSSFontFaceSet::create()) +{ + m_backing->addClient(*this); + for (auto& face : initialFaces) + add(*face); +} + +FontFaceSet::FontFaceSet(Document& document, CSSFontFaceSet& backing) + : ActiveDOMObject(&document) + , m_backing(backing) +{ + m_backing->addClient(*this); +} + +FontFaceSet::~FontFaceSet() +{ + m_backing->removeClient(*this); +} + +FontFaceSet::Iterator::Iterator(FontFaceSet& set) + : m_target(set) +{ +} + +RefPtr FontFaceSet::Iterator::next() +{ + if (m_index == m_target->size()) + return nullptr; + return m_target->backing()[m_index++].wrapper(); +} + +FontFaceSet::PendingPromise::PendingPromise(LoadPromise&& promise) + : promise(WTFMove(promise)) +{ +} + +FontFaceSet::PendingPromise::~PendingPromise() +{ +} + +bool FontFaceSet::has(FontFace& face) const +{ + return m_backing->hasFace(face.backing()); +} + +size_t FontFaceSet::size() const +{ + return m_backing->faceCount(); +} + +FontFaceSet& FontFaceSet::add(FontFace& face) +{ + if (!m_backing->hasFace(face.backing())) + m_backing->add(face.backing()); + return *this; +} + +bool FontFaceSet::remove(FontFace& face) +{ + bool result = m_backing->hasFace(face.backing()); + if (result) + m_backing->remove(face.backing()); + return result; +} + +void FontFaceSet::clear() +{ + while (m_backing->faceCount()) + m_backing->remove(m_backing.get()[0]); +} + +void FontFaceSet::load(const String& font, const String& text, LoadPromise&& promise) +{ + auto matchingFacesResult = m_backing->matchingFaces(font, text); + if (matchingFacesResult.hasException()) { + promise.reject(matchingFacesResult.releaseException()); + return; + } + auto matchingFaces = matchingFacesResult.releaseReturnValue(); + + if (matchingFaces.isEmpty()) { + promise.resolve({ }); + return; + } + + for (auto& face : matchingFaces) + face.get().load(); + + for (auto& face : matchingFaces) { + if (face.get().status() == CSSFontFace::Status::Failure) { + promise.reject(NETWORK_ERR); + return; + } + } + + auto pendingPromise = PendingPromise::create(WTFMove(promise)); + bool waiting = false; + + for (auto& face : matchingFaces) { + pendingPromise->faces.append(face.get().wrapper()); + if (face.get().status() == CSSFontFace::Status::Success) + continue; + waiting = true; + ASSERT(face.get().existingWrapper()); + m_pendingPromises.add(face.get().existingWrapper(), Vector>()).iterator->value.append(pendingPromise.copyRef()); + } + + if (!waiting) + pendingPromise->promise.resolve(pendingPromise->faces); +} + +ExceptionOr FontFaceSet::check(const String& family, const String& text) +{ + return m_backing->check(family, text); +} + +void FontFaceSet::registerReady(ReadyPromise&& promise) +{ + ASSERT(!m_promise); + if (m_isReady) { + promise.resolve(*this); + return; + } + m_promise = WTFMove(promise); +} + +auto FontFaceSet::status() const -> LoadStatus +{ + switch (m_backing->status()) { + case CSSFontFaceSet::Status::Loading: + return LoadStatus::Loading; + case CSSFontFaceSet::Status::Loaded: + return LoadStatus::Loaded; + } + ASSERT_NOT_REACHED(); + return LoadStatus::Loaded; +} + +bool FontFaceSet::canSuspendForDocumentSuspension() const +{ + return m_backing->status() == CSSFontFaceSet::Status::Loaded; +} + +void FontFaceSet::startedLoading() +{ + // FIXME: Fire a "loading" event asynchronously. + m_isReady = false; +} + +void FontFaceSet::completedLoading() +{ + if (m_promise) + std::exchange(m_promise, std::nullopt)->resolve(*this); + m_isReady = true; +} + +void FontFaceSet::faceFinished(CSSFontFace& face, CSSFontFace::Status newStatus) +{ + if (!face.existingWrapper()) + return; + + auto iterator = m_pendingPromises.find(face.existingWrapper()); + if (iterator == m_pendingPromises.end()) + return; + + for (auto& pendingPromise : iterator->value) { + if (pendingPromise->hasReachedTerminalState) + continue; + if (newStatus == CSSFontFace::Status::Success) { + if (pendingPromise->hasOneRef()) { + pendingPromise->promise.resolve(pendingPromise->faces); + pendingPromise->hasReachedTerminalState = true; + } + } else { + ASSERT(newStatus == CSSFontFace::Status::Failure); + pendingPromise->promise.reject(NETWORK_ERR); + pendingPromise->hasReachedTerminalState = true; + } + } + + m_pendingPromises.remove(iterator); +} + +} diff --git a/Source/WebCore/css/FontFaceSet.h b/Source/WebCore/css/FontFaceSet.h new file mode 100644 index 000000000..fa8fe2a1c --- /dev/null +++ b/Source/WebCore/css/FontFaceSet.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ActiveDOMObject.h" +#include "CSSFontFaceSet.h" +#include "EventTarget.h" +#include "JSDOMPromise.h" + +namespace WebCore { + +class DOMCoreException; + +class FontFaceSet final : public RefCounted, private CSSFontFaceSetClient, public EventTargetWithInlineData, private ActiveDOMObject { +public: + static Ref create(Document&, const Vector>& initialFaces); + static Ref create(Document&, CSSFontFaceSet& backing); + virtual ~FontFaceSet(); + + bool has(FontFace&) const; + size_t size() const; + FontFaceSet& add(FontFace&); + bool remove(FontFace&); + void clear(); + + using LoadPromise = DOMPromise>>; + void load(const String& font, const String& text, LoadPromise&&); + ExceptionOr check(const String& font, const String& text); + + enum class LoadStatus { Loading, Loaded }; + LoadStatus status() const; + + using ReadyPromise = DOMPromise>; + void registerReady(ReadyPromise&&); + + CSSFontFaceSet& backing() { return m_backing; } + + class Iterator { + public: + explicit Iterator(FontFaceSet&); + RefPtr next(); + + private: + Ref m_target; + size_t m_index { 0 }; // FIXME: There needs to be a mechanism to handle when fonts are added or removed from the middle of the FontFaceSet. + }; + Iterator createIterator() { return Iterator(*this); } + + using RefCounted::ref; + using RefCounted::deref; + +private: + struct PendingPromise : RefCounted { + static Ref create(LoadPromise&& promise) + { + return adoptRef(*new PendingPromise(WTFMove(promise))); + } + ~PendingPromise(); + + private: + PendingPromise(LoadPromise&&); + + public: + Vector> faces; + LoadPromise promise; + bool hasReachedTerminalState { false }; + }; + + FontFaceSet(Document&, const Vector>&); + FontFaceSet(Document&, CSSFontFaceSet&); + + // CSSFontFaceSetClient + void startedLoading() final; + void completedLoading() final; + void faceFinished(CSSFontFace&, CSSFontFace::Status) final; + + // ActiveDOMObject + const char* activeDOMObjectName() const final { return "FontFaceSet"; } + bool canSuspendForDocumentSuspension() const final; + + // EventTarget + EventTargetInterface eventTargetInterface() const final { return FontFaceSetEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } + + Ref m_backing; + HashMap, Vector>> m_pendingPromises; + std::optional m_promise; + bool m_isReady { true }; +}; + +} diff --git a/Source/WebCore/css/FontFaceSet.idl b/Source/WebCore/css/FontFaceSet.idl new file mode 100644 index 000000000..c4a5ec783 --- /dev/null +++ b/Source/WebCore/css/FontFaceSet.idl @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +enum FontFaceSetLoadStatus { + "loading", + "loaded" +}; + +[ + ConstructorCallWith=Document, + Constructor(sequence initialFaces), +] interface FontFaceSet : EventTarget { + boolean has(FontFace font); + + // FIXME: We should add support for the setlike declaration. + iterable; + + readonly attribute long size; + + FontFaceSet add(FontFace font); + [ImplementedAs=remove] boolean delete(FontFace font); + void clear(); + + attribute EventHandler onloading; + attribute EventHandler onloadingdone; + attribute EventHandler onloadingerror; + + Promise> load(DOMString font, optional DOMString text = " "); + [MayThrowException] boolean check(DOMString font, optional DOMString text = " "); + + [CustomGetter, CachedAttribute] readonly attribute Promise ready; + readonly attribute FontFaceSetLoadStatus status; +}; diff --git a/Source/WebCore/css/FontLoader.cpp b/Source/WebCore/css/FontLoader.cpp deleted file mode 100644 index e766f7a5f..000000000 --- a/Source/WebCore/css/FontLoader.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#include "config.h" -#include "FontLoader.h" - -#if ENABLE(FONT_LOAD_EVENTS) - -#include "CSSFontFaceLoadEvent.h" -#include "CSSFontFaceSource.h" -#include "CSSFontSelector.h" -#include "CSSParser.h" -#include "CSSSegmentedFontFace.h" -#include "Dictionary.h" -#include "Document.h" -#include "FrameView.h" -#include "StyleProperties.h" -#include "StyleResolver.h" - -namespace WebCore { - -static const int defaultFontSize = 10; -static const char* const defaultFontFamily = "sans-serif"; - -class LoadFontCallback : public CSSSegmentedFontFace::LoadFontCallback { -public: - static PassRefPtr create(int numLoading, PassRefPtr loadCallback, PassRefPtr errorCallback) - { - return adoptRef(new LoadFontCallback(numLoading, loadCallback, errorCallback)); - } - - static PassRefPtr createFromParams(const Dictionary& params, const FontFamily& family) - { - RefPtr onsuccess; - RefPtr onerror; - params.get("onsuccess", onsuccess); - params.get("onerror", onerror); - if (!onsuccess && !onerror) - return 0; - int numFamilies = 0; - for (const FontFamily* f = &family; f; f = f->next()) - numFamilies++; - return LoadFontCallback::create(numFamilies, onsuccess, onerror); - } - - virtual void notifyLoaded() override; - virtual void notifyError() override; -private: - LoadFontCallback(int numLoading, PassRefPtr loadCallback, PassRefPtr errorCallback) - : m_numLoading(numLoading) - , m_errorOccured(false) - , m_loadCallback(loadCallback) - , m_errorCallback(errorCallback) - { } - - int m_numLoading; - bool m_errorOccured; - RefPtr m_loadCallback; - RefPtr m_errorCallback; -}; - -void LoadFontCallback::notifyLoaded() -{ - m_numLoading--; - if (m_numLoading) - return; - - if (m_errorOccured) { - if (m_errorCallback) - m_errorCallback->handleEvent(); - } else { - if (m_loadCallback) - m_loadCallback->handleEvent(); - } -} - -void LoadFontCallback::notifyError() -{ - m_errorOccured = true; - notifyLoaded(); -} - -FontLoader::FontLoader(Document* document) - : ActiveDOMObject(document) - , m_document(document) - , m_loadingCount(0) -{ - suspendIfNeeded(); -} - -FontLoader::~FontLoader() -{ -} - -EventTargetData* FontLoader::eventTargetData() -{ - return &m_eventTargetData; -} - -EventTargetData& FontLoader::ensureEventTargetData() -{ - return m_eventTargetData; -} - -EventTargetInterface FontLoader::eventTargetInterface() const -{ - return FontLoaderEventTargetInterfaceType; -} - -ScriptExecutionContext* FontLoader::scriptExecutionContext() const -{ - return ActiveDOMObject::scriptExecutionContext(); -} - -void FontLoader::didLayout() -{ - firePendingEvents(); - loadingDone(); -} - -void FontLoader::scheduleEvent(PassRefPtr event) -{ - if (FrameView* view = m_document->view()) { - if (view->isInLayout()) { - m_pendingEvents.append(event); - return; - } - } - firePendingEvents(); - dispatchEvent(event); -} - -void FontLoader::firePendingEvents() -{ - if (m_pendingEvents.isEmpty()) - return; - - Vector > pendingEvents; - m_pendingEvents.swap(pendingEvents); - for (size_t index = 0; index < pendingEvents.size(); ++index) - dispatchEvent(pendingEvents[index].release()); -} - -void FontLoader::beginFontLoading(CSSFontFaceRule* rule) -{ - ++m_loadingCount; - if (m_loadingCount == 1 && !m_loadingDoneEvent) - scheduleEvent(CSSFontFaceLoadEvent::createForFontFaceRule(eventNames().loadingEvent, rule)); - scheduleEvent(CSSFontFaceLoadEvent::createForFontFaceRule(eventNames().loadstartEvent, rule)); -} - -void FontLoader::fontLoaded(CSSFontFaceRule* rule) -{ - ASSERT(m_loadingCount > 0); - scheduleEvent(CSSFontFaceLoadEvent::createForFontFaceRule(eventNames().loadEvent, rule)); - - --m_loadingCount; - if (!m_loadingCount) - m_loadingDoneEvent = CSSFontFaceLoadEvent::createForFontFaceRule(eventNames().loadingdoneEvent, rule); -} - -void FontLoader::loadError(CSSFontFaceRule* rule, CSSFontFaceSource* source) -{ - ASSERT(m_loadingCount > 0); - - // FIXME: We should report NetworkError in case of timeout, etc. - String errorName = (source && source->isDecodeError()) ? "InvalidFontDataError" : ExceptionCodeDescription(NOT_FOUND_ERR).name; - scheduleEvent(CSSFontFaceLoadEvent::createForError(rule, DOMError::create(errorName))); - --m_loadingCount; - if (!m_loadingCount) - m_loadingDoneEvent = CSSFontFaceLoadEvent::createForFontFaceRule(eventNames().loadingdoneEvent, rule); -} - -void FontLoader::notifyWhenFontsReady(PassRefPtr callback) -{ - m_callbacks.append(callback); - loadingDone(); -} - -void FontLoader::loadingDone() -{ - if (loading()) - return; - if (!m_loadingDoneEvent && m_callbacks.isEmpty()) - return; - - if (FrameView* view = m_document->view()) { - if (view->isInLayout() || view->needsLayout()) - return; - m_document->updateStyleIfNeeded(); - if (view->needsLayout()) - return; - } - - if (m_loadingDoneEvent) - dispatchEvent(m_loadingDoneEvent.release()); - - if (!m_callbacks.isEmpty()) { - Vector > callbacks; - m_callbacks.swap(callbacks); - for (size_t index = 0; index < callbacks.size(); ++index) - callbacks[index]->handleEvent(); - } -} - -void FontLoader::loadFont(const Dictionary& params) -{ - // FIXME: The text member of params is ignored. - String fontString; - if (!params.get("font", fontString)) - return; - Font font; - if (!resolveFontStyle(fontString, font)) - return; - RefPtr callback = LoadFontCallback::createFromParams(params, font.family()); - - for (const FontFamily* f = &font.family(); f; f = f->next()) { - CSSSegmentedFontFace* face = m_document->ensureStyleResolver()->fontSelector()->getFontFace(font.fontDescription(), f->family()); - if (!face) { - if (callback) - callback->notifyError(); - continue; - } - face->loadFont(font.fontDescription(), callback); - } -} - -bool FontLoader::checkFont(const String& fontString, const String&) -{ - // FIXME: The second parameter (text) is ignored. - Font font; - if (!resolveFontStyle(fontString, font)) - return false; - for (const FontFamily* f = &font.family(); f; f = f->next()) { - CSSSegmentedFontFace* face = m_document->ensureStyleResolver()->fontSelector()->getFontFace(font.fontDescription(), f->family()); - if (!face || !face->checkFont()) - return false; - } - return true; -} - -static void applyPropertyToCurrentStyle(StyleResolver* styleResolver, CSSPropertyID id, const RefPtr& parsedStyle) -{ - styleResolver->applyPropertyToCurrentStyle(id, parsedStyle->getPropertyCSSValue(id).get()); -} - -bool FontLoader::resolveFontStyle(const String& fontString, Font& font) -{ - // Interpret fontString in the same way as the 'font' attribute of CanvasRenderingContext2D. - RefPtr parsedStyle = MutableStyleProperties::create(); - CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0); - if (parsedStyle->isEmpty()) - return false; - - String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); - if (fontValue == "inherit" || fontValue == "initial") - return false; - - RefPtr style = RenderStyle::create(); - - FontFamily fontFamily; - fontFamily.setFamily(defaultFontFamily); - - FontDescription defaultFontDescription; - defaultFontDescription.setFamily(fontFamily); - defaultFontDescription.setSpecifiedSize(defaultFontSize); - defaultFontDescription.setComputedSize(defaultFontSize); - - style->setFontDescription(defaultFontDescription); - - style->font().update(style->font().fontSelector()); - - // Now map the font property longhands into the style. - StyleResolver* styleResolver = m_document->ensureStyleResolver(); - styleResolver->applyPropertyToStyle(CSSPropertyFontFamily, parsedStyle->getPropertyCSSValue(CSSPropertyFontFamily).get(), style.get()); - applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontStyle, parsedStyle); - applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontVariant, parsedStyle); - applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontWeight, parsedStyle); - - // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call, - // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122). - // The updateFont() calls below update the fontMetrics and ensure the proper setting of font-size and line-height. - styleResolver->updateFont(); - applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontSize, parsedStyle); - styleResolver->updateFont(); - applyPropertyToCurrentStyle(styleResolver, CSSPropertyLineHeight, parsedStyle); - - font = style->font(); - font.update(styleResolver->fontSelector()); - return true; -} - -} // namespace WebCore - -#endif // ENABLE(FONT_LOAD_EVENTS) diff --git a/Source/WebCore/css/FontLoader.h b/Source/WebCore/css/FontLoader.h deleted file mode 100644 index 945dd2167..000000000 --- a/Source/WebCore/css/FontLoader.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#if ENABLE(FONT_LOAD_EVENTS) - -#ifndef FontLoader_h -#define FontLoader_h - -#include "ActiveDOMObject.h" -#include "EventListener.h" -#include "EventNames.h" -#include "EventTarget.h" -#include "VoidCallback.h" -#include -#include -#include - -namespace WebCore { - -class CachedFont; -class CSSFontFaceRule; -class CSSFontFaceSource; -class Dictionary; -class Document; -class Event; -class Font; -class ScriptExecutionContext; - -class FontLoader : public RefCounted, public ActiveDOMObject, public EventTarget { -public: - static PassRefPtr create(Document* document) - { - return adoptRef(new FontLoader(document)); - } - virtual ~FontLoader(); - - DEFINE_ATTRIBUTE_EVENT_LISTENER(loading); - DEFINE_ATTRIBUTE_EVENT_LISTENER(loadingdone); - DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); - DEFINE_ATTRIBUTE_EVENT_LISTENER(load); - DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - - bool checkFont(const String&, const String&); - void loadFont(const Dictionary&); - void notifyWhenFontsReady(PassRefPtr); - - bool loading() const { return m_loadingCount > 0; } - - virtual ScriptExecutionContext* scriptExecutionContext() const; - virtual EventTargetInterface eventTargetInterface() const; - - using RefCounted::ref; - using RefCounted::deref; - - Document* document() const { return m_document; } - - void didLayout(); - void beginFontLoading(CSSFontFaceRule*); - void fontLoaded(CSSFontFaceRule*); - void loadError(CSSFontFaceRule*, CSSFontFaceSource*); - void loadingDone(); - -private: - FontLoader(Document*); - - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } - virtual EventTargetData* eventTargetData() override; - virtual EventTargetData& ensureEventTargetData() override; - - void scheduleEvent(PassRefPtr); - void firePendingEvents(); - bool resolveFontStyle(const String&, Font&); - - Document* m_document; - EventTargetData m_eventTargetData; - unsigned m_loadingCount; - Vector> m_pendingEvents; - Vector> m_callbacks; - RefPtr m_loadingDoneEvent; -}; - -} // namespace WebCore - -#endif // FontLoader_h -#endif // ENABLE(FONT_LOAD_EVENTS) diff --git a/Source/WebCore/css/FontLoader.idl b/Source/WebCore/css/FontLoader.idl deleted file mode 100644 index a8190b8ce..000000000 --- a/Source/WebCore/css/FontLoader.idl +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - NoInterfaceObject, - Conditional=FONT_LOAD_EVENTS, - ActiveDOMObject, - EventTarget, - GenerateIsReachable=ImplDocument, -] interface FontLoader { - - attribute EventListener onloading; - attribute EventListener onloadingdone; - attribute EventListener onloadstart; - attribute EventListener onload; - attribute EventListener onerror; - - boolean checkFont(DOMString font, [Default=NullString] optional DOMString text); - void loadFont(Dictionary params); - void notifyWhenFontsReady(VoidCallback callback); - readonly attribute boolean loading; - - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event evt); -}; diff --git a/Source/WebCore/css/FontVariantBuilder.cpp b/Source/WebCore/css/FontVariantBuilder.cpp new file mode 100644 index 000000000..54648ae11 --- /dev/null +++ b/Source/WebCore/css/FontVariantBuilder.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontVariantBuilder.h" + +#include "CSSPrimitiveValue.h" +#include "CSSValueList.h" +#include "CSSValuePool.h" +#include "TextFlags.h" + +namespace WebCore { + +FontVariantLigaturesValues extractFontVariantLigatures(const CSSValue& value) +{ + FontVariantLigatures common = FontVariantLigatures::Normal; + FontVariantLigatures discretionary = FontVariantLigatures::Normal; + FontVariantLigatures historical = FontVariantLigatures::Normal; + FontVariantLigatures contextualAlternates = FontVariantLigatures::Normal; + + if (is(value)) { + for (auto& item : downcast(value)) { + switch (downcast(item.get()).valueID()) { + case CSSValueNoCommonLigatures: + common = FontVariantLigatures::No; + break; + case CSSValueCommonLigatures: + common = FontVariantLigatures::Yes; + break; + case CSSValueNoDiscretionaryLigatures: + discretionary = FontVariantLigatures::No; + break; + case CSSValueDiscretionaryLigatures: + discretionary = FontVariantLigatures::Yes; + break; + case CSSValueNoHistoricalLigatures: + historical = FontVariantLigatures::No; + break; + case CSSValueHistoricalLigatures: + historical = FontVariantLigatures::Yes; + break; + case CSSValueContextual: + contextualAlternates = FontVariantLigatures::Yes; + break; + case CSSValueNoContextual: + contextualAlternates = FontVariantLigatures::No; + break; + default: + ASSERT_NOT_REACHED(); + break; + } + } + } else if (is(value)) { + switch (downcast(value).valueID()) { + case CSSValueNormal: + break; + case CSSValueNone: + common = FontVariantLigatures::No; + discretionary = FontVariantLigatures::No; + historical = FontVariantLigatures::No; + contextualAlternates = FontVariantLigatures::No; + break; + default: + ASSERT_NOT_REACHED(); + break; + } + } + + return FontVariantLigaturesValues(common, discretionary, historical, contextualAlternates); +} + +FontVariantNumericValues extractFontVariantNumeric(const CSSValue& value) +{ + FontVariantNumericFigure figure = FontVariantNumericFigure::Normal; + FontVariantNumericSpacing spacing = FontVariantNumericSpacing::Normal; + FontVariantNumericFraction fraction = FontVariantNumericFraction::Normal; + FontVariantNumericOrdinal ordinal = FontVariantNumericOrdinal::Normal; + FontVariantNumericSlashedZero slashedZero = FontVariantNumericSlashedZero::Normal; + + if (is(value)) { + for (auto& item : downcast(value)) { + switch (downcast(item.get()).valueID()) { + 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: + ASSERT_NOT_REACHED(); + break; + } + } + } else if (is(value)) + ASSERT(downcast(value).valueID() == CSSValueNormal); + + return FontVariantNumericValues(figure, spacing, fraction, ordinal, slashedZero); +} + +FontVariantEastAsianValues extractFontVariantEastAsian(const CSSValue& value) +{ + FontVariantEastAsianVariant variant = FontVariantEastAsianVariant::Normal; + FontVariantEastAsianWidth width = FontVariantEastAsianWidth::Normal; + FontVariantEastAsianRuby ruby = FontVariantEastAsianRuby::Normal; + + if (is(value)) { + for (auto& item : downcast(value)) { + switch (downcast(item.get()).valueID()) { + 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: + ASSERT_NOT_REACHED(); + break; + } + } + } else if (is(value)) + ASSERT(downcast(value).valueID() == CSSValueNormal); + + return FontVariantEastAsianValues(variant, width, ruby); +} + +Ref computeFontVariant(const FontVariantSettings& variantSettings) +{ + if (variantSettings.isAllNormal()) + return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); + + auto list = CSSValueList::createSpaceSeparated(); + + switch (variantSettings.commonLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueCommonLigatures)); + break; + case FontVariantLigatures::No: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoCommonLigatures)); + break; + } + + switch (variantSettings.discretionaryLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiscretionaryLigatures)); + break; + case FontVariantLigatures::No: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoDiscretionaryLigatures)); + break; + } + + switch (variantSettings.historicalLigatures) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalLigatures)); + break; + case FontVariantLigatures::No: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoHistoricalLigatures)); + break; + } + + switch (variantSettings.contextualAlternates) { + case FontVariantLigatures::Normal: + break; + case FontVariantLigatures::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueContextual)); + break; + case FontVariantLigatures::No: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueNoContextual)); + break; + } + + switch (variantSettings.position) { + case FontVariantPosition::Normal: + break; + case FontVariantPosition::Subscript: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueSub)); + break; + case FontVariantPosition::Superscript: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueSuper)); + break; + } + + switch (variantSettings.caps) { + case FontVariantCaps::Normal: + break; + case FontVariantCaps::Small: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueSmallCaps)); + break; + case FontVariantCaps::AllSmall: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueAllSmallCaps)); + break; + case FontVariantCaps::Petite: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValuePetiteCaps)); + break; + case FontVariantCaps::AllPetite: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueAllPetiteCaps)); + break; + case FontVariantCaps::Unicase: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueUnicase)); + break; + case FontVariantCaps::Titling: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueTitlingCaps)); + break; + } + + switch (variantSettings.numericFigure) { + case FontVariantNumericFigure::Normal: + break; + case FontVariantNumericFigure::LiningNumbers: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueLiningNums)); + break; + case FontVariantNumericFigure::OldStyleNumbers: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueOldstyleNums)); + break; + } + + switch (variantSettings.numericSpacing) { + case FontVariantNumericSpacing::Normal: + break; + case FontVariantNumericSpacing::ProportionalNumbers: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalNums)); + break; + case FontVariantNumericSpacing::TabularNumbers: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueTabularNums)); + break; + } + + switch (variantSettings.numericFraction) { + case FontVariantNumericFraction::Normal: + break; + case FontVariantNumericFraction::DiagonalFractions: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueDiagonalFractions)); + break; + case FontVariantNumericFraction::StackedFractions: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueStackedFractions)); + break; + } + + switch (variantSettings.numericOrdinal) { + case FontVariantNumericOrdinal::Normal: + break; + case FontVariantNumericOrdinal::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueOrdinal)); + break; + } + + switch (variantSettings.numericSlashedZero) { + case FontVariantNumericSlashedZero::Normal: + break; + case FontVariantNumericSlashedZero::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueSlashedZero)); + break; + } + + switch (variantSettings.alternates) { + case FontVariantAlternates::Normal: + break; + case FontVariantAlternates::HistoricalForms: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueHistoricalForms)); + break; + } + + switch (variantSettings.eastAsianVariant) { + case FontVariantEastAsianVariant::Normal: + break; + case FontVariantEastAsianVariant::Jis78: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis78)); + break; + case FontVariantEastAsianVariant::Jis83: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis83)); + break; + case FontVariantEastAsianVariant::Jis90: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis90)); + break; + case FontVariantEastAsianVariant::Jis04: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueJis04)); + break; + case FontVariantEastAsianVariant::Simplified: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueSimplified)); + break; + case FontVariantEastAsianVariant::Traditional: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueTraditional)); + break; + } + + switch (variantSettings.eastAsianWidth) { + case FontVariantEastAsianWidth::Normal: + break; + case FontVariantEastAsianWidth::Full: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueFullWidth)); + break; + case FontVariantEastAsianWidth::Proportional: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueProportionalWidth)); + break; + } + + switch (variantSettings.eastAsianRuby) { + case FontVariantEastAsianRuby::Normal: + break; + case FontVariantEastAsianRuby::Yes: + list.get().append(CSSValuePool::singleton().createIdentifierValue(CSSValueRuby)); + break; + } + + return WTFMove(list); +} + +} + diff --git a/Source/WebCore/css/FontVariantBuilder.h b/Source/WebCore/css/FontVariantBuilder.h new file mode 100644 index 000000000..691a699a3 --- /dev/null +++ b/Source/WebCore/css/FontVariantBuilder.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace WebCore { + +class CSSValue; +struct FontVariantSettings; +struct FontVariantLigaturesValues; +struct FontVariantNumericValues; +struct FontVariantEastAsianValues; + +FontVariantLigaturesValues extractFontVariantLigatures(const CSSValue&); +FontVariantNumericValues extractFontVariantNumeric(const CSSValue&); +FontVariantEastAsianValues extractFontVariantEastAsian(const CSSValue&); + +Ref computeFontVariant(const FontVariantSettings&); + +} // namespace WebCore diff --git a/Source/WebCore/css/InspectorCSSOMWrappers.cpp b/Source/WebCore/css/InspectorCSSOMWrappers.cpp index 042e44e2c..674c0ab6b 100644 --- a/Source/WebCore/css/InspectorCSSOMWrappers.cpp +++ b/Source/WebCore/css/InspectorCSSOMWrappers.cpp @@ -30,14 +30,15 @@ #include "InspectorCSSOMWrappers.h" #include "CSSDefaultStyleSheets.h" -#include "CSSHostRule.h" #include "CSSImportRule.h" #include "CSSMediaRule.h" +#include "CSSNamespaceRule.h" #include "CSSRule.h" #include "CSSStyleRule.h" #include "CSSStyleSheet.h" #include "CSSSupportsRule.h" -#include "DocumentStyleSheetCollection.h" +#include "ExtensionStyleSheets.h" +#include "StyleScope.h" #include "StyleSheetContents.h" #include "WebKitCSSRegionRule.h" @@ -59,28 +60,21 @@ void InspectorCSSOMWrappers::collect(ListType* listType) CSSRule* cssRule = listType->item(i); switch (cssRule->type()) { case CSSRule::IMPORT_RULE: - collect(static_cast(cssRule)->styleSheet()); + collect(downcast(*cssRule).styleSheet()); break; case CSSRule::MEDIA_RULE: - collect(static_cast(cssRule)); + collect(downcast(cssRule)); break; -#if ENABLE(CSS3_CONDITIONAL_RULES) case CSSRule::SUPPORTS_RULE: - collect(static_cast(cssRule)); + collect(downcast(cssRule)); break; -#endif #if ENABLE(CSS_REGIONS) case CSSRule::WEBKIT_REGION_RULE: - collect(static_cast(cssRule)); - break; -#endif -#if ENABLE(SHADOW_DOM) - case CSSRule::HOST_RULE: - collect(static_cast(cssRule)); + collect(downcast(cssRule)); break; #endif case CSSRule::STYLE_RULE: - m_styleRuleToCSSOMWrapperMap.add(static_cast(cssRule)->styleRule(), static_cast(cssRule)); + m_styleRuleToCSSOMWrapperMap.add(&downcast(*cssRule).styleRule(), downcast(cssRule)); break; default: break; @@ -88,43 +82,56 @@ void InspectorCSSOMWrappers::collect(ListType* listType) } } -void InspectorCSSOMWrappers::collectFromStyleSheetContents(HashSet>& sheetWrapperSet, StyleSheetContents* styleSheet) +void InspectorCSSOMWrappers::collectFromStyleSheetContents(StyleSheetContents* styleSheet) { if (!styleSheet) return; RefPtr styleSheetWrapper = CSSStyleSheet::create(*styleSheet); - sheetWrapperSet.add(styleSheetWrapper); + m_styleSheetCSSOMWrapperSet.add(styleSheetWrapper); collect(styleSheetWrapper.get()); } void InspectorCSSOMWrappers::collectFromStyleSheets(const Vector>& sheets) { - for (unsigned i = 0; i < sheets.size(); ++i) - collect(sheets[i].get()); + for (auto& sheet : sheets) + collect(sheet.get()); } -void InspectorCSSOMWrappers::collectFromDocumentStyleSheetCollection(DocumentStyleSheetCollection& styleSheetCollection) +void InspectorCSSOMWrappers::maybeCollectFromStyleSheets(const Vector>& sheets) { - collectFromStyleSheets(styleSheetCollection.activeAuthorStyleSheets()); - collect(styleSheetCollection.pageUserSheet()); - collectFromStyleSheets(styleSheetCollection.injectedUserStyleSheets()); - collectFromStyleSheets(styleSheetCollection.documentUserStyleSheets()); + for (auto& sheet : sheets) { + if (!m_styleSheetCSSOMWrapperSet.contains(sheet.get())) { + m_styleSheetCSSOMWrapperSet.add(sheet); + collect(sheet.get()); + } + } } -CSSStyleRule* InspectorCSSOMWrappers::getWrapperForRuleInSheets(StyleRule* rule, DocumentStyleSheetCollection& styleSheetCollection) +void InspectorCSSOMWrappers::collectDocumentWrappers(ExtensionStyleSheets& extensionStyleSheets) { if (m_styleRuleToCSSOMWrapperMap.isEmpty()) { - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::simpleDefaultStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::defaultStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::quirksStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::svgStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::mathMLStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::mediaControlsStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::fullscreenStyleSheet); - collectFromStyleSheetContents(m_styleSheetCSSOMWrapperSet, CSSDefaultStyleSheets::plugInsStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::simpleDefaultStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::defaultStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::quirksStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::svgStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::mathMLStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::mediaControlsStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::fullscreenStyleSheet); + collectFromStyleSheetContents(CSSDefaultStyleSheets::plugInsStyleSheet); - collectFromDocumentStyleSheetCollection(styleSheetCollection); + collect(extensionStyleSheets.pageUserSheet()); + collectFromStyleSheets(extensionStyleSheets.injectedUserStyleSheets()); + collectFromStyleSheets(extensionStyleSheets.documentUserStyleSheets()); } +} + +void InspectorCSSOMWrappers::collectScopeWrappers(Style::Scope& styleScope) +{ + maybeCollectFromStyleSheets(styleScope.activeStyleSheets()); +} + +CSSStyleRule* InspectorCSSOMWrappers::getWrapperForRuleInSheets(StyleRule* rule) +{ return m_styleRuleToCSSOMWrapperMap.get(rule); } diff --git a/Source/WebCore/css/InspectorCSSOMWrappers.h b/Source/WebCore/css/InspectorCSSOMWrappers.h index fc9652d1a..ace93dac8 100644 --- a/Source/WebCore/css/InspectorCSSOMWrappers.h +++ b/Source/WebCore/css/InspectorCSSOMWrappers.h @@ -20,8 +20,7 @@ * */ -#ifndef InspectorCSSOMWrappers_h -#define InspectorCSSOMWrappers_h +#pragma once #include #include @@ -33,29 +32,33 @@ namespace WebCore { class CSSStyleRule; class CSSStyleSheet; -class DocumentStyleSheetCollection; +class ExtensionStyleSheets; class StyleRule; class StyleSheetContents; +namespace Style { +class Scope; +} + class InspectorCSSOMWrappers { public: // WARNING. This will construct CSSOM wrappers for all style rules and cache them in a map for significant memory cost. // It is here to support inspector. Don't use for any regular engine functions. - CSSStyleRule* getWrapperForRuleInSheets(StyleRule*, DocumentStyleSheetCollection&); + CSSStyleRule* getWrapperForRuleInSheets(StyleRule*); void collectFromStyleSheetIfNeeded(CSSStyleSheet*); + void collectDocumentWrappers(ExtensionStyleSheets&); + void collectScopeWrappers(Style::Scope&); private: template void collect(ListType*); - void collectFromStyleSheetContents(HashSet>& sheetWrapperSet, StyleSheetContents*); + void collectFromStyleSheetContents(StyleSheetContents*); void collectFromStyleSheets(const Vector>&); - void collectFromDocumentStyleSheetCollection(DocumentStyleSheetCollection&); + void maybeCollectFromStyleSheets(const Vector>&); HashMap> m_styleRuleToCSSOMWrapperMap; HashSet> m_styleSheetCSSOMWrapperSet; }; } // namespace WebCore - -#endif // InspectorCSSOMWrappers_h diff --git a/Source/WebCore/css/LengthFunctions.cpp b/Source/WebCore/css/LengthFunctions.cpp index adba10081..68fffdeb9 100644 --- a/Source/WebCore/css/LengthFunctions.cpp +++ b/Source/WebCore/css/LengthFunctions.cpp @@ -24,57 +24,27 @@ #include "config.h" #include "LengthFunctions.h" -#include "LayoutUnit.h" -#include "Length.h" -#include "RenderView.h" +#include "FloatSize.h" +#include "LayoutSize.h" +#include "LengthSize.h" namespace WebCore { -int minimumIntValueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) +int intValueForLength(const Length& length, LayoutUnit maximumValue) { - return static_cast(minimumValueForLength(length, maximumValue, renderView, roundPercentages)); + return static_cast(valueForLength(length, maximumValue)); } -int intValueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) -{ - return static_cast(valueForLength(length, maximumValue, renderView, roundPercentages)); -} - -LayoutUnit minimumValueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) +LayoutUnit valueForLength(const Length& length, LayoutUnit maximumValue) { switch (length.type()) { case Fixed: - return length.value(); case Percent: - if (roundPercentages) - return static_cast(round(maximumValue * length.percent() / 100.0f)); - // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack. - return static_cast(static_cast(maximumValue * length.percent() / 100.0f)); case Calculated: - return length.nonNanCalculatedValue(maximumValue); - case ViewportPercentageWidth: - if (renderView) - return static_cast(renderView->viewportSize().width() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageHeight: - if (renderView) - return static_cast(renderView->viewportSize().height() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageMin: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::min(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; - case ViewportPercentageMax: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::max(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; + return minimumValueForLength(length, maximumValue); case FillAvailable: case Auto: - return 0; + return maximumValue; case Relative: case Intrinsic: case MinIntrinsic: @@ -89,67 +59,24 @@ LayoutUnit minimumValueForLength(const Length& length, LayoutUnit maximumValue, return 0; } -LayoutUnit valueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView, bool roundPercentages) +LayoutSize sizeForLengthSize(const LengthSize& length, const LayoutSize& maximumValue) { - switch (length.type()) { - case Fixed: - case Percent: - case Calculated: - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: - return minimumValueForLength(length, maximumValue, renderView, roundPercentages); - case FillAvailable: - case Auto: - return maximumValue; - case Relative: - case Intrinsic: - case MinIntrinsic: - case MinContent: - case MaxContent: - case FitContent: - case Undefined: - ASSERT_NOT_REACHED(); - return 0; - } - ASSERT_NOT_REACHED(); - return 0; + return { valueForLength(length.width, maximumValue.width()), valueForLength(length.height, maximumValue.height()) }; } // FIXME: when subpixel layout is supported this copy of floatValueForLength() can be removed. See bug 71143. -float floatValueForLength(const Length& length, LayoutUnit maximumValue, RenderView* renderView) +float floatValueForLength(const Length& length, LayoutUnit maximumValue) { switch (length.type()) { case Fixed: - return length.getFloatValue(); + return length.value(); case Percent: return static_cast(maximumValue * length.percent() / 100.0f); case FillAvailable: case Auto: return static_cast(maximumValue); case Calculated: - return length.nonNanCalculatedValue(maximumValue); - case ViewportPercentageWidth: - if (renderView) - return static_cast(renderView->viewportSize().width() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageHeight: - if (renderView) - return static_cast(renderView->viewportSize().height() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageMin: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::min(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; - case ViewportPercentageMax: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::max(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; + return length.nonNanCalculatedValue(maximumValue); case Relative: case Intrinsic: case MinIntrinsic: @@ -164,11 +91,11 @@ float floatValueForLength(const Length& length, LayoutUnit maximumValue, RenderV return 0; } -float floatValueForLength(const Length& length, float maximumValue, RenderView* renderView) +float floatValueForLength(const Length& length, float maximumValue) { switch (length.type()) { case Fixed: - return length.getFloatValue(); + return length.value(); case Percent: return static_cast(maximumValue * length.percent() / 100.0f); case FillAvailable: @@ -176,26 +103,6 @@ float floatValueForLength(const Length& length, float maximumValue, RenderView* return static_cast(maximumValue); case Calculated: return length.nonNanCalculatedValue(maximumValue); - case ViewportPercentageWidth: - if (renderView) - return static_cast(renderView->viewportSize().width() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageHeight: - if (renderView) - return static_cast(renderView->viewportSize().height() * length.viewportPercentageLength() / 100.0f); - return 0; - case ViewportPercentageMin: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::min(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; - case ViewportPercentageMax: - if (renderView) { - IntSize viewportSize = renderView->viewportSize(); - return static_cast(std::max(viewportSize.width(), viewportSize.height()) * length.viewportPercentageLength() / 100.0f); - } - return 0; case Relative: case Intrinsic: case MinIntrinsic: @@ -210,4 +117,9 @@ float floatValueForLength(const Length& length, float maximumValue, RenderView* return 0; } +FloatSize floatSizeForLengthSize(const LengthSize& lengthSize, const FloatSize& boxSize) +{ + return { floatValueForLength(lengthSize.width, boxSize.width()), floatValueForLength(lengthSize.height, boxSize.height()) }; +} + } // namespace WebCore diff --git a/Source/WebCore/css/LengthFunctions.h b/Source/WebCore/css/LengthFunctions.h index 9fcf2ef06..1c4e050da 100644 --- a/Source/WebCore/css/LengthFunctions.h +++ b/Source/WebCore/css/LengthFunctions.h @@ -1,6 +1,6 @@ /* Copyright (C) 1999 Lars Knoll (knoll@kde.org) - Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + Copyright (C) 2006-2017 Apple Inc. All rights reserved. Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com) Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. Copyright (C) 2012 Motorola Mobility, Inc. All rights reserved. @@ -21,22 +21,58 @@ Boston, MA 02110-1301, USA. */ -#ifndef LengthFunctions_h -#define LengthFunctions_h +#pragma once + +#include "LayoutUnit.h" +#include "Length.h" namespace WebCore { -class LayoutUnit; +class FloatSize; +class LayoutSize; class RenderView; + struct Length; +struct LengthSize; -int minimumIntValueForLength(const Length&, LayoutUnit maximumValue, RenderView* = 0, bool roundPercentages = false); -int intValueForLength(const Length&, LayoutUnit maximumValue, RenderView* = 0, bool roundPercentages = false); -LayoutUnit minimumValueForLength(const Length&, LayoutUnit maximumValue, RenderView* = 0, bool roundPercentages = false); -LayoutUnit valueForLength(const Length&, LayoutUnit maximumValue, RenderView* = 0, bool roundPercentages = false); -float floatValueForLength(const Length&, LayoutUnit maximumValue, RenderView* = 0); -float floatValueForLength(const Length&, float maximumValue, RenderView* = 0); +int minimumIntValueForLength(const Length&, LayoutUnit maximumValue); +int intValueForLength(const Length&, LayoutUnit maximumValue); +LayoutUnit minimumValueForLength(const Length&, LayoutUnit maximumValue); +WEBCORE_EXPORT LayoutUnit valueForLength(const Length&, LayoutUnit maximumValue); +LayoutSize sizeForLengthSize(const LengthSize&, const LayoutSize& maximumValue); +float floatValueForLength(const Length&, LayoutUnit maximumValue); +WEBCORE_EXPORT float floatValueForLength(const Length&, float maximumValue); +FloatSize floatSizeForLengthSize(const LengthSize&, const FloatSize&); -} // namespace WebCore +inline LayoutUnit minimumValueForLength(const Length& length, LayoutUnit maximumValue) +{ + switch (length.type()) { + case Fixed: + return length.value(); + case Percent: + // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack. + return LayoutUnit(static_cast(maximumValue * length.percent() / 100.0f)); + case Calculated: + return length.nonNanCalculatedValue(maximumValue); + case FillAvailable: + case Auto: + return 0; + case Relative: + case Intrinsic: + case MinIntrinsic: + case MinContent: + case MaxContent: + case FitContent: + case Undefined: + break; + } + ASSERT_NOT_REACHED(); + return 0; +} -#endif // LengthFunctions_h +inline int minimumIntValueForLength(const Length& length, LayoutUnit maximumValue) +{ + return static_cast(minimumValueForLength(length, maximumValue)); +} + +} // namespace WebCore diff --git a/Source/WebCore/css/MediaFeatureNames.cpp b/Source/WebCore/css/MediaFeatureNames.cpp index 73a0ba351..18430c90c 100644 --- a/Source/WebCore/css/MediaFeatureNames.cpp +++ b/Source/WebCore/css/MediaFeatureNames.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Apple Computer, Inc. + * Copyright (C) 2005 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -30,8 +30,7 @@ namespace WebCore { namespace MediaFeatureNames { -#define DEFINE_MEDIAFEATURE_GLOBAL(name, str) \ - DEFINE_GLOBAL(AtomicString, name##MediaFeature, str) +#define DEFINE_MEDIAFEATURE_GLOBAL(name, string) DEFINE_GLOBAL(AtomicString, name) CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(DEFINE_MEDIAFEATURE_GLOBAL) #undef DEFINE_MEDIAFEATURE_GLOBAL @@ -39,10 +38,9 @@ void init() { static bool initialized; if (!initialized) { - // Use placement new to initialize the globals. - + // Use placement new to initialize the globals. AtomicString::init(); -#define INITIALIZE_GLOBAL(name, str) new (NotNull, (void*)&name##MediaFeature) AtomicString(str, AtomicString::ConstructFromLiteral); +#define INITIALIZE_GLOBAL(name, string) new (NotNull, (void*)&name) AtomicString(string, AtomicString::ConstructFromLiteral); CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(INITIALIZE_GLOBAL) #undef INITIALIZE_GLOBAL initialized = true; diff --git a/Source/WebCore/css/MediaFeatureNames.h b/Source/WebCore/css/MediaFeatureNames.h index 1c9ef009a..664d34f1b 100644 --- a/Source/WebCore/css/MediaFeatureNames.h +++ b/Source/WebCore/css/MediaFeatureNames.h @@ -17,76 +17,79 @@ * Boston, MA 02110-1301, USA. * */ -#ifndef MediaFeatureNames_h -#define MediaFeatureNames_h -#include +#pragma once -namespace WebCore { - namespace MediaFeatureNames { +#include #if ENABLE(VIEW_MODE_CSS_MEDIA) -#define CSS_MEDIAQUERY_VIEW_MODE(macro) macro(view_mode, "-webkit-view-mode") +#define CSS_MEDIAQUERY_VIEW_MODE(macro) macro(viewMode, "-webkit-view-mode") #else #define CSS_MEDIAQUERY_VIEW_MODE(macro) #endif #define CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(macro) \ + macro(animation, "-webkit-animation") \ + macro(anyHover, "any-hover") \ + macro(anyPointer, "any-pointer") \ + macro(aspectRatio, "aspect-ratio") \ macro(color, "color") \ - macro(color_index, "color-index") \ + macro(colorGamut, "color-gamut") \ + macro(colorIndex, "color-index") \ + macro(deviceAspectRatio, "device-aspect-ratio") \ + macro(deviceHeight, "device-height") \ + macro(devicePixelRatio, "-webkit-device-pixel-ratio") \ + macro(deviceWidth, "device-width") \ macro(grid, "grid") \ - macro(monochrome, "monochrome") \ macro(height, "height") \ macro(hover, "hover") \ - macro(width, "width") \ + macro(invertedColors, "inverted-colors") \ + macro(maxAspectRatio, "max-aspect-ratio") \ + macro(maxColor, "max-color") \ + macro(maxColorIndex, "max-color-index") \ + macro(maxDeviceAspectRatio, "max-device-aspect-ratio") \ + macro(maxDeviceHeight, "max-device-height") \ + macro(maxDevicePixelRatio, "-webkit-max-device-pixel-ratio") \ + macro(maxDeviceWidth, "max-device-width") \ + macro(maxHeight, "max-height") \ + macro(maxMonochrome, "max-monochrome") \ + macro(maxResolution, "max-resolution") \ + macro(maxWidth, "max-width") \ + macro(minAspectRatio, "min-aspect-ratio") \ + macro(minColor, "min-color") \ + macro(minColorIndex, "min-color-index") \ + macro(minDeviceAspectRatio, "min-device-aspect-ratio") \ + macro(minDeviceHeight, "min-device-height") \ + macro(minDevicePixelRatio, "-webkit-min-device-pixel-ratio") \ + macro(minDeviceWidth, "min-device-width") \ + macro(minHeight, "min-height") \ + macro(minMonochrome, "min-monochrome") \ + macro(minResolution, "min-resolution") \ + macro(minWidth, "min-width") \ + macro(monochrome, "monochrome") \ macro(orientation, "orientation") \ - macro(aspect_ratio, "aspect-ratio") \ - macro(device_aspect_ratio, "device-aspect-ratio") \ - macro(device_pixel_ratio, "-webkit-device-pixel-ratio") \ - macro(device_height, "device-height") \ - macro(device_width, "device-width") \ - macro(max_color, "max-color") \ - macro(max_color_index, "max-color-index") \ - macro(max_aspect_ratio, "max-aspect-ratio") \ - macro(max_device_aspect_ratio, "max-device-aspect-ratio") \ - macro(max_device_pixel_ratio, "-webkit-max-device-pixel-ratio") \ - macro(max_device_height, "max-device-height") \ - macro(max_device_width, "max-device-width") \ - macro(max_height, "max-height") \ - macro(max_monochrome, "max-monochrome") \ - macro(max_width, "max-width") \ - macro(max_resolution, "max-resolution") \ - macro(min_color, "min-color") \ - macro(min_color_index, "min-color-index") \ - macro(min_aspect_ratio, "min-aspect-ratio") \ - macro(min_device_aspect_ratio, "min-device-aspect-ratio") \ - macro(min_device_pixel_ratio, "-webkit-min-device-pixel-ratio") \ - macro(min_device_height, "min-device-height") \ - macro(min_device_width, "min-device-width") \ - macro(min_height, "min-height") \ - macro(min_monochrome, "min-monochrome") \ - macro(min_width, "min-width") \ - macro(min_resolution, "min-resolution") \ macro(pointer, "pointer") \ + macro(prefersReducedMotion, "prefers-reduced-motion") \ macro(resolution, "resolution") \ - macro(transform_2d, "-webkit-transform-2d") \ - macro(transform_3d, "-webkit-transform-3d") \ + macro(transform2d, "-webkit-transform-2d") \ + macro(transform3d, "-webkit-transform-3d") \ macro(transition, "-webkit-transition") \ - macro(animation, "-webkit-animation") \ - macro(video_playable_inline, "-webkit-video-playable-inline") \ + macro(videoPlayableInline, "-webkit-video-playable-inline") \ + macro(width, "width") \ CSS_MEDIAQUERY_VIEW_MODE(macro) // end of macro +namespace WebCore { +namespace MediaFeatureNames { + #ifndef CSS_MEDIAQUERY_NAMES_HIDE_GLOBALS - #define CSS_MEDIAQUERY_NAMES_DECLARE(name, str) extern const AtomicString name##MediaFeature; +#define CSS_MEDIAQUERY_NAMES_DECLARE(name, string) extern const AtomicString name; CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(CSS_MEDIAQUERY_NAMES_DECLARE) - #undef CSS_MEDIAQUERY_NAMES_DECLARE +#undef CSS_MEDIAQUERY_NAMES_DECLARE #endif - void init(); + void init(); - } // namespace MediaFeatureNames +} // namespace MediaFeatureNames } // namespace WebCore - -#endif // MediaFeatureNames_h diff --git a/Source/WebCore/css/MediaList.cpp b/Source/WebCore/css/MediaList.cpp index 20f928d4f..e73a47e58 100644 --- a/Source/WebCore/css/MediaList.cpp +++ b/Source/WebCore/css/MediaList.cpp @@ -17,20 +17,22 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "MediaList.h" #include "CSSImportRule.h" #include "CSSParser.h" #include "CSSStyleSheet.h" -#include "Console.h" #include "DOMWindow.h" #include "Document.h" #include "ExceptionCode.h" +#include "HTMLParserIdioms.h" #include "MediaFeatureNames.h" #include "MediaQuery.h" -#include "MediaQueryExp.h" +#include "MediaQueryParser.h" #include "ScriptableDocumentParser.h" +#include #include namespace WebCore { @@ -63,169 +65,119 @@ namespace WebCore { * throw SYNTAX_ERR exception. */ -MediaQuerySet::MediaQuerySet() - : m_fallbackToDescriptor(false) - , m_lastLine(0) +Ref MediaQuerySet::create(const String& mediaString) { + if (mediaString.isEmpty()) + return MediaQuerySet::create(); + + return MediaQueryParser::parseMediaQuerySet(mediaString).releaseNonNull(); } -MediaQuerySet::MediaQuerySet(const String& mediaString, bool fallbackToDescriptor) - : m_fallbackToDescriptor(fallbackToDescriptor) - , m_lastLine(0) +MediaQuerySet::MediaQuerySet() + : m_lastLine(0) { - bool success = parse(mediaString); - // FIXME: parsing can fail. The problem with failing constructor is that - // we would need additional flag saying MediaList is not valid - // Parse can fail only when fallbackToDescriptor == false, i.e when HTML4 media descriptor - // forward-compatible syntax is not in use. - // DOMImplementationCSS seems to mandate that media descriptors are used - // for both html and svg, even though svg:style doesn't use media descriptors - // Currently the only places where parsing can fail are - // creating , creating css media / import rules from js - - // FIXME: This doesn't make much sense. - if (!success) - parse("invalid"); } MediaQuerySet::MediaQuerySet(const MediaQuerySet& o) - : RefCounted() - , m_fallbackToDescriptor(o.m_fallbackToDescriptor) + : RefCounted() , m_lastLine(o.m_lastLine) - , m_queries(o.m_queries.size()) + , m_queries(o.m_queries) { - for (unsigned i = 0; i < m_queries.size(); ++i) - m_queries[i] = o.m_queries[i]->copy(); } MediaQuerySet::~MediaQuerySet() { } -static String parseMediaDescriptor(const String& string) +bool MediaQuerySet::set(const String& mediaString) { - // http://www.w3.org/TR/REC-html40/types.html#type-media-descriptors - // "Each entry is truncated just before the first character that isn't a - // US ASCII letter [a-zA-Z] (ISO 10646 hex 41-5a, 61-7a), digit [0-9] (hex 30-39), - // or hyphen (hex 2d)." - unsigned length = string.length(); - unsigned i = 0; - for (; i < length; ++i) { - unsigned short c = string[i]; - if (! ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '1' && c <= '9') - || (c == '-'))) - break; - } - return string.left(i); -} - -bool MediaQuerySet::parse(const String& mediaString) -{ - CSSParser parser(CSSStrictMode); - - Vector> result; - Vector list; - mediaString.split(',', list); - for (unsigned i = 0; i < list.size(); ++i) { - String medium = list[i].stripWhiteSpace(); - if (medium.isEmpty()) { - if (!m_fallbackToDescriptor) - return false; - continue; - } - OwnPtr mediaQuery = parser.parseMediaQuery(medium); - if (!mediaQuery) { - if (!m_fallbackToDescriptor) - return false; - String mediaDescriptor = parseMediaDescriptor(medium); - if (mediaDescriptor.isNull()) - continue; - mediaQuery = adoptPtr(new MediaQuery(MediaQuery::None, mediaDescriptor, nullptr)); - } - result.append(mediaQuery.release()); - } - // ",,,," falls straight through, but is not valid unless fallback - if (!m_fallbackToDescriptor && list.isEmpty()) { - String strippedMediaString = mediaString.stripWhiteSpace(); - if (!strippedMediaString.isEmpty()) - return false; - } - m_queries.swap(result); + auto result = create(mediaString); + m_queries.swap(result->m_queries); return true; } bool MediaQuerySet::add(const String& queryString) { - CSSParser parser(CSSStrictMode); - - OwnPtr parsedQuery = parser.parseMediaQuery(queryString); - if (!parsedQuery && m_fallbackToDescriptor) { - String medium = parseMediaDescriptor(queryString); - if (!medium.isNull()) - parsedQuery = adoptPtr(new MediaQuery(MediaQuery::None, medium, nullptr)); + // To "parse a media query" for a given string means to follow "the parse + // a media query list" steps and return "null" if more than one media query + // is returned, or else the returned media query. + auto result = create(queryString); + + // Only continue if exactly one media query is found, as described above. + if (result->m_queries.size() != 1) + return true; + + // If comparing with any of the media queries in the collection of media + // queries returns true terminate these steps. + for (size_t i = 0; i < m_queries.size(); ++i) { + if (m_queries[i] == result->m_queries[0]) + return true; } - if (!parsedQuery) - return false; - - m_queries.append(parsedQuery.release()); + + m_queries.append(result->m_queries[0]); return true; } bool MediaQuerySet::remove(const String& queryStringToRemove) { - CSSParser parser(CSSStrictMode); - - OwnPtr parsedQuery = parser.parseMediaQuery(queryStringToRemove); - if (!parsedQuery && m_fallbackToDescriptor) { - String medium = parseMediaDescriptor(queryStringToRemove); - if (!medium.isNull()) - parsedQuery = adoptPtr(new MediaQuery(MediaQuery::None, medium, nullptr)); - } - if (!parsedQuery) - return false; + // To "parse a media query" for a given string means to follow "the parse + // a media query list" steps and return "null" if more than one media query + // is returned, or else the returned media query. + auto result = create(queryStringToRemove); - for (size_t i = 0; i < m_queries.size(); ++i) { - MediaQuery* query = m_queries[i].get(); - if (*query == *parsedQuery) { + // Only continue if exactly one media query is found, as described above. + if (result->m_queries.size() != 1) + return true; + + // Remove any media query from the collection of media queries for which + // comparing with the media query returns true. + bool found = false; + + // Using signed int here, since for the first value, --i will result in -1. + for (int i = 0; i < (int)m_queries.size(); ++i) { + if (m_queries[i] == result->m_queries[0]) { m_queries.remove(i); - return true; + --i; + found = true; } } - return false; + + return found; } -void MediaQuerySet::addMediaQuery(PassOwnPtr mediaQuery) +void MediaQuerySet::addMediaQuery(MediaQuery&& mediaQuery) { - m_queries.append(mediaQuery); + m_queries.append(WTFMove(mediaQuery)); } String MediaQuerySet::mediaText() const { StringBuilder text; - - bool first = true; - for (size_t i = 0; i < m_queries.size(); ++i) { - if (!first) + bool needComma = false; + for (auto& query : m_queries) { + if (needComma) text.appendLiteral(", "); - else - first = false; - text.append(m_queries[i]->cssText()); + text.append(query.cssText()); + needComma = true; } return text.toString(); } +void MediaQuerySet::shrinkToFit() +{ + m_queries.shrinkToFit(); + for (auto& query : m_queries) + query.shrinkToFit(); +} + MediaList::MediaList(MediaQuerySet* mediaQueries, CSSStyleSheet* parentSheet) : m_mediaQueries(mediaQueries) , m_parentStyleSheet(parentSheet) - , m_parentRule(0) { } MediaList::MediaList(MediaQuerySet* mediaQueries, CSSRule* parentRule) : m_mediaQueries(mediaQueries) - , m_parentStyleSheet(0) , m_parentRule(parentRule) { } @@ -234,52 +186,47 @@ MediaList::~MediaList() { } -void MediaList::setMediaText(const String& value, ExceptionCode& ec) +ExceptionOr MediaList::setMediaText(const String& value) { CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); - - bool success = m_mediaQueries->parse(value); - if (!success) { - ec = SYNTAX_ERR; - return; - } + m_mediaQueries->set(value); if (m_parentStyleSheet) m_parentStyleSheet->didMutate(); + return { }; } String MediaList::item(unsigned index) const { - const Vector>& queries = m_mediaQueries->queryVector(); + auto& queries = m_mediaQueries->queryVector(); if (index < queries.size()) - return queries[index]->cssText(); + return queries[index].cssText(); return String(); } -void MediaList::deleteMedium(const String& medium, ExceptionCode& ec) +ExceptionOr MediaList::deleteMedium(const String& medium) { CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); bool success = m_mediaQueries->remove(medium); - if (!success) { - ec = NOT_FOUND_ERR; - return; - } + if (!success) + return Exception { NOT_FOUND_ERR }; if (m_parentStyleSheet) m_parentStyleSheet->didMutate(); + return { }; } -void MediaList::appendMedium(const String& medium, ExceptionCode& ec) +ExceptionOr MediaList::appendMedium(const String& medium) { CSSStyleSheet::RuleMutationScope mutationScope(m_parentRule); bool success = m_mediaQueries->add(medium); if (!success) { // FIXME: Should this really be INVALID_CHARACTER_ERR? - ec = INVALID_CHARACTER_ERR; - return; + return Exception { INVALID_CHARACTER_ERR }; } if (m_parentStyleSheet) m_parentStyleSheet->didMutate(); + return { }; } void MediaList::reattach(MediaQuerySet* mediaQueries) @@ -289,28 +236,26 @@ void MediaList::reattach(MediaQuerySet* mediaQueries) } #if ENABLE(RESOLUTION_MEDIA_QUERY) -static void addResolutionWarningMessageToConsole(Document* document, const String& serializedExpression, const CSSPrimitiveValue* value) -{ - ASSERT(document); - ASSERT(value); - DEFINE_STATIC_LOCAL(String, mediaQueryMessage, (ASCIILiteral("Consider using 'dppx' units instead of '%replacementUnits%', as in CSS '%replacementUnits%' means dots-per-CSS-%lengthUnit%, not dots-per-physical-%lengthUnit%, so does not correspond to the actual '%replacementUnits%' of a screen. In media query expression: "))); - DEFINE_STATIC_LOCAL(String, mediaValueDPI, (ASCIILiteral("dpi"))); - DEFINE_STATIC_LOCAL(String, mediaValueDPCM, (ASCIILiteral("dpcm"))); - DEFINE_STATIC_LOCAL(String, lengthUnitInch, (ASCIILiteral("inch"))); - DEFINE_STATIC_LOCAL(String, lengthUnitCentimeter, (ASCIILiteral("centimeter"))); +static void addResolutionWarningMessageToConsole(Document& document, const String& serializedExpression, const CSSPrimitiveValue& value) +{ + static NeverDestroyed mediaQueryMessage(ASCIILiteral("Consider using 'dppx' units instead of '%replacementUnits%', as in CSS '%replacementUnits%' means dots-per-CSS-%lengthUnit%, not dots-per-physical-%lengthUnit%, so does not correspond to the actual '%replacementUnits%' of a screen. In media query expression: ")); + static NeverDestroyed mediaValueDPI(ASCIILiteral("dpi")); + static NeverDestroyed mediaValueDPCM(ASCIILiteral("dpcm")); + static NeverDestroyed lengthUnitInch(ASCIILiteral("inch")); + static NeverDestroyed lengthUnitCentimeter(ASCIILiteral("centimeter")); String message; - if (value->isDotsPerInch()) - message = String(mediaQueryMessage).replace("%replacementUnits%", mediaValueDPI).replace("%lengthUnit%", lengthUnitInch); - else if (value->isDotsPerCentimeter()) - message = String(mediaQueryMessage).replace("%replacementUnits%", mediaValueDPCM).replace("%lengthUnit%", lengthUnitCentimeter); + if (value.isDotsPerInch()) + message = mediaQueryMessage.get().replace("%replacementUnits%", mediaValueDPI).replace("%lengthUnit%", lengthUnitInch); + else if (value.isDotsPerCentimeter()) + message = mediaQueryMessage.get().replace("%replacementUnits%", mediaValueDPCM).replace("%lengthUnit%", lengthUnitCentimeter); else ASSERT_NOT_REACHED(); message.append(serializedExpression); - document->addConsoleMessage(CSSMessageSource, DebugMessageLevel, message); + document.addConsoleMessage(MessageSource::CSS, MessageLevel::Debug, message); } void reportMediaQueryWarningIfNeeded(Document* document, const MediaQuerySet* mediaQuerySet) @@ -318,31 +263,23 @@ void reportMediaQueryWarningIfNeeded(Document* document, const MediaQuerySet* me if (!mediaQuerySet || !document) return; - const Vector>& mediaQueries = mediaQuerySet->queryVector(); - const size_t queryCount = mediaQueries.size(); - - if (!queryCount) - return; - - for (size_t i = 0; i < queryCount; ++i) { - const MediaQuery* query = mediaQueries[i].get(); - String mediaType = query->mediaType(); - if (!query->ignored() && !equalIgnoringCase(mediaType, "print")) { - const Vector>& expressions = query->expressions(); - for (size_t j = 0; j < expressions.size(); ++j) { - const MediaQueryExp* exp = expressions.at(j).get(); - if (exp->mediaFeature() == MediaFeatureNames::resolutionMediaFeature || exp->mediaFeature() == MediaFeatureNames::max_resolutionMediaFeature || exp->mediaFeature() == MediaFeatureNames::min_resolutionMediaFeature) { - CSSValue* cssValue = exp->value(); - if (cssValue && cssValue->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssValue); - if (primitiveValue->isDotsPerInch() || primitiveValue->isDotsPerCentimeter()) - addResolutionWarningMessageToConsole(document, mediaQuerySet->mediaText(), primitiveValue); + for (auto& query : mediaQuerySet->queryVector()) { + if (!query.ignored() && !equalLettersIgnoringASCIICase(query.mediaType(), "print")) { + auto& expressions = query.expressions(); + for (auto& expression : expressions) { + if (expression.mediaFeature() == MediaFeatureNames::resolution || expression.mediaFeature() == MediaFeatureNames::maxResolution || expression.mediaFeature() == MediaFeatureNames::minResolution) { + auto* value = expression.value(); + if (is(value)) { + auto& primitiveValue = downcast(*value); + if (primitiveValue.isDotsPerInch() || primitiveValue.isDotsPerCentimeter()) + addResolutionWarningMessageToConsole(*document, mediaQuerySet->mediaText(), primitiveValue); } } } } } } + #endif } diff --git a/Source/WebCore/css/MediaList.h b/Source/WebCore/css/MediaList.h index 74976df48..0bb0a01c6 100644 --- a/Source/WebCore/css/MediaList.h +++ b/Source/WebCore/css/MediaList.h @@ -18,91 +18,83 @@ * Boston, MA 02110-1301, USA. */ -#ifndef MediaList_h -#define MediaList_h +#pragma once -#include "ExceptionCode.h" +#include "ExceptionOr.h" +#include #include -#include -#include #include -#include namespace WebCore { +class CSSParser; class CSSRule; class CSSStyleSheet; class Document; -class MediaList; class MediaQuery; -class MediaQuerySet : public RefCounted { +class MediaQuerySet final : public RefCounted { public: - static PassRefPtr create() + static Ref create() { - return adoptRef(new MediaQuerySet()); + return adoptRef(*new MediaQuerySet); } - static PassRefPtr create(const String& mediaString) - { - return adoptRef(new MediaQuerySet(mediaString, false)); - } - static PassRefPtr createAllowingDescriptionSyntax(const String& mediaString) - { - return adoptRef(new MediaQuerySet(mediaString, true)); - } - ~MediaQuerySet(); - - bool parse(const String&); + + static WEBCORE_EXPORT Ref create(const String& mediaString); + + WEBCORE_EXPORT ~MediaQuerySet(); + + bool set(const String&); bool add(const String&); bool remove(const String&); - void addMediaQuery(PassOwnPtr); + void addMediaQuery(MediaQuery&&); + + const Vector& queryVector() const { return m_queries; } - const Vector>& queryVector() const { return m_queries; } - int lastLine() const { return m_lastLine; } void setLastLine(int lastLine) { m_lastLine = lastLine; } - - String mediaText() const; - PassRefPtr copy() const { return adoptRef(new MediaQuerySet(*this)); } + WEBCORE_EXPORT String mediaText() const; + + Ref copy() const { return adoptRef(*new MediaQuerySet(*this)); } + + void shrinkToFit(); private: MediaQuerySet(); - MediaQuerySet(const String& mediaQuery, bool fallbackToDescription); + WEBCORE_EXPORT MediaQuerySet(const String& mediaQuery); MediaQuerySet(const MediaQuerySet&); - - unsigned m_fallbackToDescriptor : 1; // true if failed media query parsing should fallback to media description parsing. - signed m_lastLine : 31; - Vector> m_queries; + + signed m_lastLine; + Vector m_queries; }; -class MediaList : public RefCounted { +class MediaList final : public RefCounted { public: - static PassRefPtr create(MediaQuerySet* mediaQueries, CSSStyleSheet* parentSheet) + static Ref create(MediaQuerySet* mediaQueries, CSSStyleSheet* parentSheet) { - return adoptRef(new MediaList(mediaQueries, parentSheet)); + return adoptRef(*new MediaList(mediaQueries, parentSheet)); } - static PassRefPtr create(MediaQuerySet* mediaQueries, CSSRule* parentRule) + static Ref create(MediaQuerySet* mediaQueries, CSSRule* parentRule) { - return adoptRef(new MediaList(mediaQueries, parentRule)); + return adoptRef(*new MediaList(mediaQueries, parentRule)); } - ~MediaList(); + WEBCORE_EXPORT ~MediaList(); unsigned length() const { return m_mediaQueries->queryVector().size(); } - String item(unsigned index) const; - void deleteMedium(const String& oldMedium, ExceptionCode&); - void appendMedium(const String& newMedium, ExceptionCode&); + WEBCORE_EXPORT String item(unsigned index) const; + WEBCORE_EXPORT ExceptionOr deleteMedium(const String& oldMedium); + WEBCORE_EXPORT ExceptionOr appendMedium(const String& newMedium); String mediaText() const { return m_mediaQueries->mediaText(); } - void setMediaText(const String&, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr setMediaText(const String&); - // Not part of CSSOM. CSSRule* parentRule() const { return m_parentRule; } CSSStyleSheet* parentStyleSheet() const { return m_parentStyleSheet; } - void clearParentStyleSheet() { ASSERT(m_parentStyleSheet); m_parentStyleSheet = 0; } - void clearParentRule() { ASSERT(m_parentRule); m_parentRule = 0; } + void clearParentStyleSheet() { ASSERT(m_parentStyleSheet); m_parentStyleSheet = nullptr; } + void clearParentRule() { ASSERT(m_parentRule); m_parentRule = nullptr; } const MediaQuerySet* queries() const { return m_mediaQueries.get(); } void reattach(MediaQuerySet*); @@ -113,15 +105,20 @@ private: MediaList(MediaQuerySet*, CSSRule* parentRule); RefPtr m_mediaQueries; - CSSStyleSheet* m_parentStyleSheet; - CSSRule* m_parentRule; + CSSStyleSheet* m_parentStyleSheet { nullptr }; + CSSRule* m_parentRule { nullptr }; }; -#if ENABLE(RESOLUTION_MEDIA_QUERY) // Adds message to inspector console whenever dpi or dpcm values are used for "screen" media. +// FIXME: Seems strange to have this here in this file, and unclear exactly who should call this and when. void reportMediaQueryWarningIfNeeded(Document*, const MediaQuerySet*); -#endif -} // namespace +#if !ENABLE(RESOLUTION_MEDIA_QUERY) + +inline void reportMediaQueryWarningIfNeeded(Document*, const MediaQuerySet*) +{ +} #endif + +} // namespace diff --git a/Source/WebCore/css/MediaList.idl b/Source/WebCore/css/MediaList.idl index fd9169eda..6d6d3c41e 100644 --- a/Source/WebCore/css/MediaList.idl +++ b/Source/WebCore/css/MediaList.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,19 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Introduced in DOM Level 2: [ - JSCustomHeader, + ExportToWrappedFunction, GenerateIsReachable, ImplementationLacksVTable, + JSCustomHeader, ] interface MediaList { - - [TreatNullAs=NullString, TreatReturnedNullStringAs=Null, SetterRaisesException] attribute DOMString mediaText; + [SetterMayThrowException, TreatNullAs=EmptyString] attribute DOMString mediaText; readonly attribute unsigned long length; - [TreatReturnedNullStringAs=Null] getter DOMString item([Default=Undefined] optional unsigned long index); - [RaisesException] void deleteMedium([Default=Undefined] optional DOMString oldMedium); - [RaisesException] void appendMedium([Default=Undefined] optional DOMString newMedium); + getter DOMString? item(unsigned long index); + [MayThrowException] void deleteMedium(DOMString oldMedium); + [MayThrowException] void appendMedium(DOMString newMedium); }; - diff --git a/Source/WebCore/css/MediaQuery.cpp b/Source/WebCore/css/MediaQuery.cpp index 39304d8f8..13d775696 100644 --- a/Source/WebCore/css/MediaQuery.cpp +++ b/Source/WebCore/css/MediaQuery.cpp @@ -16,7 +16,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,7 +29,6 @@ #include "config.h" #include "MediaQuery.h" -#include "MediaQueryExp.h" #include namespace WebCore { @@ -37,86 +36,62 @@ namespace WebCore { // http://dev.w3.org/csswg/cssom/#serialize-a-media-query String MediaQuery::serialize() const { - StringBuilder result; - if (!m_ignored) { - switch (m_restrictor) { - case MediaQuery::Only: - result.append("only "); - break; - case MediaQuery::Not: - result.append("not "); - break; - case MediaQuery::None: - break; - } - - if (m_expressions->isEmpty()) { - result.append(m_mediaType); - return result.toString(); - } - - if (m_mediaType != "all" || m_restrictor != None) { - result.append(m_mediaType); - result.append(" and "); - } - - result.append(m_expressions->at(0)->serialize()); - for (size_t i = 1; i < m_expressions->size(); ++i) { - result.append(" and "); - result.append(m_expressions->at(i)->serialize()); - } - } else { + if (m_ignored) { // If query is invalid, serialized text should turn into "not all". - result.append("not all"); + return ASCIILiteral("not all"); + } + + bool shouldOmitMediaType = false; + StringBuilder result; + switch (m_restrictor) { + case MediaQuery::Only: + result.appendLiteral("only "); + break; + case MediaQuery::Not: + result.appendLiteral("not "); + break; + case MediaQuery::None: + shouldOmitMediaType = !m_expressions.isEmpty() && m_mediaType == "all"; + break; + } + bool needsAnd = false; + if (!shouldOmitMediaType) { + result.append(m_mediaType); + needsAnd = true; + } + for (auto& expression : m_expressions) { + if (needsAnd) + result.appendLiteral(" and "); + result.append(expression.serialize()); + needsAnd = true; } return result.toString(); } -MediaQuery::MediaQuery(Restrictor r, const String& mediaType, PassOwnPtr exprs) - : m_restrictor(r) - , m_mediaType(mediaType.lower()) - , m_expressions(exprs) - , m_ignored(false) +MediaQuery::MediaQuery(Restrictor restrictor, const String& mediaType, Vector&& expressions) + : m_restrictor(restrictor) + , m_mediaType(mediaType.convertToASCIILowercase()) + , m_expressions(WTFMove(expressions)) { - if (!m_expressions) { - m_expressions = adoptPtr(new ExpressionVector); - return; - } - - std::sort(m_expressions->begin(), m_expressions->end(), [](const OwnPtr& a, const OwnPtr& b) { - return codePointCompare(a->serialize(), b->serialize()) < 0; + std::sort(m_expressions.begin(), m_expressions.end(), [](auto& a, auto& b) { + return codePointCompare(a.serialize(), b.serialize()) < 0; }); - // remove all duplicated expressions + // Remove all duplicated expressions. String key; - for (int i = m_expressions->size() - 1; i >= 0; --i) { + for (int i = m_expressions.size() - 1; i >= 0; --i) { - // if not all of the expressions is valid the media query must be ignored. + // If any expression is invalid the media query must be ignored. if (!m_ignored) - m_ignored = !m_expressions->at(i)->isValid(); + m_ignored = !m_expressions[i].isValid(); - if (m_expressions->at(i)->serialize() == key) - m_expressions->remove(i); + if (m_expressions[i].serialize() == key) + m_expressions.remove(i); else - key = m_expressions->at(i)->serialize(); + key = m_expressions[i].serialize(); } } -MediaQuery::MediaQuery(const MediaQuery& o) - : m_restrictor(o.m_restrictor) - , m_mediaType(o.m_mediaType) - , m_expressions(adoptPtr(new ExpressionVector(o.m_expressions->size()))) - , m_ignored(o.m_ignored) - , m_serializationCache(o.m_serializationCache) -{ - for (unsigned i = 0; i < m_expressions->size(); ++i) - (*m_expressions)[i] = o.m_expressions->at(i)->copy(); -} - -MediaQuery::~MediaQuery() -{ -} - // http://dev.w3.org/csswg/cssom/#compare-media-queries bool MediaQuery::operator==(const MediaQuery& other) const { @@ -124,11 +99,10 @@ bool MediaQuery::operator==(const MediaQuery& other) const } // http://dev.w3.org/csswg/cssom/#serialize-a-list-of-media-queries -String MediaQuery::cssText() const +const String& MediaQuery::cssText() const { if (m_serializationCache.isNull()) - const_cast(this)->m_serializationCache = serialize(); - + m_serializationCache = serialize(); return m_serializationCache; } diff --git a/Source/WebCore/css/MediaQuery.h b/Source/WebCore/css/MediaQuery.h index cea7d2007..cf2942e94 100644 --- a/Source/WebCore/css/MediaQuery.h +++ b/Source/WebCore/css/MediaQuery.h @@ -16,7 +16,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,50 +26,39 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaQuery_h -#define MediaQuery_h +#pragma once -#include +#include "MediaQueryExpression.h" #include -#include -#include namespace WebCore { -class MediaQueryExp; class MediaQuery { WTF_MAKE_FAST_ALLOCATED; public: - enum Restrictor { - Only, Not, None - }; + enum Restrictor { Only, Not, None }; - typedef Vector> ExpressionVector; - - MediaQuery(Restrictor, const String& mediaType, PassOwnPtr>> exprs); - ~MediaQuery(); + MediaQuery(Restrictor, const String& mediaType, Vector&&); Restrictor restrictor() const { return m_restrictor; } - const Vector>& expressions() const { return *m_expressions; } - String mediaType() const { return m_mediaType; } - bool operator==(const MediaQuery& other) const; - String cssText() const; + const Vector& expressions() const { return m_expressions; } + const String& mediaType() const { return m_mediaType; } bool ignored() const { return m_ignored; } - PassOwnPtr copy() const { return adoptPtr(new MediaQuery(*this)); } + const String& cssText() const; - private: - MediaQuery(const MediaQuery&); + bool operator==(const MediaQuery& other) const; - Restrictor m_restrictor; - String m_mediaType; - OwnPtr m_expressions; - bool m_ignored; - String m_serializationCache; + void shrinkToFit() { m_expressions.shrinkToFit(); } +private: String serialize() const; + + Restrictor m_restrictor; + String m_mediaType; + Vector m_expressions; + bool m_ignored { false }; + mutable String m_serializationCache; }; } // namespace - -#endif diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp index 1d176edf1..f7027d28a 100644 --- a/Source/WebCore/css/MediaQueryEvaluator.cpp +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -16,7 +16,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,20 +31,16 @@ #include "CSSAspectRatioValue.h" #include "CSSPrimitiveValue.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" -#include "Chrome.h" -#include "ChromeClient.h" -#include "DOMWindow.h" #include "FloatRect.h" #include "FrameView.h" -#include "InspectorInstrumentation.h" #include "IntRect.h" #include "MainFrame.h" #include "MediaFeatureNames.h" #include "MediaList.h" #include "MediaQuery.h" -#include "MediaQueryExp.h" #include "NodeRenderStyle.h" #include "Page.h" #include "PlatformScreen.h" @@ -53,66 +49,66 @@ #include "Screen.h" #include "Settings.h" #include "StyleResolver.h" +#include "Theme.h" #include -#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING) +#if ENABLE(3D_TRANSFORMS) #include "RenderLayerCompositor.h" #endif -#if PLATFORM(IOS) -#include "WebCoreSystemInterface.h" -#endif - namespace WebCore { -using namespace MediaFeatureNames; - enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; -typedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix); -typedef HashMap FunctionMap; -static FunctionMap* gFunctionMap; +typedef bool (*MediaQueryFunction)(CSSValue*, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix); +typedef HashMap MediaQueryFunctionMap; -/* - * FIXME: following media features are not implemented: scan - * - * scan: The "scan" media feature describes the scanning process of - * tv output devices. It's unknown how to retrieve this information from - * the platform - */ +static bool isAccessibilitySettingsDependent(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::invertedColors + || mediaFeature == MediaFeatureNames::maxMonochrome + || mediaFeature == MediaFeatureNames::minMonochrome + || mediaFeature == MediaFeatureNames::monochrome + || mediaFeature == MediaFeatureNames::prefersReducedMotion; +} + +static bool isViewportDependent(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::width + || mediaFeature == MediaFeatureNames::height + || mediaFeature == MediaFeatureNames::minWidth + || mediaFeature == MediaFeatureNames::minHeight + || mediaFeature == MediaFeatureNames::maxWidth + || mediaFeature == MediaFeatureNames::maxHeight + || mediaFeature == MediaFeatureNames::orientation + || mediaFeature == MediaFeatureNames::aspectRatio + || mediaFeature == MediaFeatureNames::minAspectRatio + || mediaFeature == MediaFeatureNames::maxAspectRatio; +} MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) - : m_frame(0) - , m_style(0) - , m_expResult(mediaFeatureResult) + : m_fallbackResult(mediaFeatureResult) { } MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult) : m_mediaType(acceptedMediaType) - , m_frame(0) - , m_style(0) - , m_expResult(mediaFeatureResult) + , m_fallbackResult(mediaFeatureResult) { } -MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style) +MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, const Document& document, const RenderStyle* style) : m_mediaType(acceptedMediaType) - , m_frame(frame) + , m_frame(document.frame()) , m_style(style) - , m_expResult(false) // doesn't matter when we have m_frame and m_style -{ -} - -MediaQueryEvaluator::~MediaQueryEvaluator() { } bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const { return mediaTypeToMatch.isEmpty() - || equalIgnoringCase(mediaTypeToMatch, "all") - || equalIgnoringCase(mediaTypeToMatch, m_mediaType); + || equalLettersIgnoringASCIICase(mediaTypeToMatch, "all") + || equalIgnoringASCIICase(mediaTypeToMatch, m_mediaType); } bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const @@ -120,8 +116,8 @@ bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) c // Like mediaTypeMatch, but without the special cases for "" and "all". ASSERT(mediaTypeToMatch); ASSERT(mediaTypeToMatch[0] != '\0'); - ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all"))); - return equalIgnoringCase(mediaTypeToMatch, m_mediaType); + ASSERT(!equalLettersIgnoringASCIICase(StringView(mediaTypeToMatch), "all")); + return equalIgnoringASCIICase(m_mediaType, mediaTypeToMatch); } static bool applyRestrictor(MediaQuery::Restrictor r, bool value) @@ -129,48 +125,75 @@ static bool applyRestrictor(MediaQuery::Restrictor r, bool value) return r == MediaQuery::Not ? !value : value; } -bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, StyleResolver* styleResolver) const +bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, StyleResolver* styleResolver) const { - if (!querySet) - return true; - - const Vector>& queries = querySet->queryVector(); + auto& queries = querySet.queryVector(); if (!queries.size()) - return true; // empty query list evaluates to true + return true; // Empty query list evaluates to true. - // iterate over queries, stop if any of them eval to true (OR semantics) + // Iterate over queries, stop if any of them eval to true (OR semantics). bool result = false; for (size_t i = 0; i < queries.size() && !result; ++i) { - MediaQuery* query = queries[i].get(); + auto& query = queries[i]; - if (query->ignored()) + if (query.ignored() || (!query.expressions().size() && query.mediaType().isEmpty())) continue; - if (mediaTypeMatch(query->mediaType())) { - const Vector>& expressions = query->expressions(); - // iterate through expressions, stop if any of them eval to false - // (AND semantics) + if (mediaTypeMatch(query.mediaType())) { + auto& expressions = query.expressions(); + // Iterate through expressions, stop if any of them eval to false (AND semantics). size_t j = 0; for (; j < expressions.size(); ++j) { - bool exprResult = eval(expressions.at(j).get()); - if (styleResolver && expressions.at(j)->isViewportDependent()) - styleResolver->addViewportDependentMediaQueryResult(expressions.at(j).get(), exprResult); - if (!exprResult) + bool expressionResult = evaluate(expressions[j]); + if (styleResolver && isViewportDependent(expressions[j].mediaFeature())) + styleResolver->addViewportDependentMediaQueryResult(expressions[j], expressionResult); + if (styleResolver && isAccessibilitySettingsDependent(expressions[j].mediaFeature())) + styleResolver->addAccessibilitySettingsDependentMediaQueryResult(expressions[j], expressionResult); + if (!expressionResult) break; } - // assume true if we are at the end of the list, - // otherwise assume false - result = applyRestrictor(query->restrictor(), expressions.size() == j); + // Assume true if we are at the end of the list, otherwise assume false. + result = applyRestrictor(query.restrictor(), expressions.size() == j); } else - result = applyRestrictor(query->restrictor(), false); + result = applyRestrictor(query.restrictor(), false); } return result; } -template -bool compareValue(T a, T b, MediaFeaturePrefix op) +bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, Vector& results) const +{ + auto& queries = querySet.queryVector(); + if (!queries.size()) + return true; + + bool result = false; + for (size_t i = 0; i < queries.size() && !result; ++i) { + auto& query = queries[i]; + + if (query.ignored()) + continue; + + if (mediaTypeMatch(query.mediaType())) { + auto& expressions = query.expressions(); + size_t j = 0; + for (; j < expressions.size(); ++j) { + bool expressionResult = evaluate(expressions[j]); + if (isViewportDependent(expressions[j].mediaFeature())) + results.append({ expressions[j], expressionResult }); + if (!expressionResult) + break; + } + result = applyRestrictor(query.restrictor(), expressions.size() == j); + } else + result = applyRestrictor(query.restrictor(), false); + } + + return result; +} + +template bool compareValue(T a, U b, MediaFeaturePrefix op) { switch (op) { case MinPrefix: @@ -185,119 +208,162 @@ bool compareValue(T a, T b, MediaFeaturePrefix op) static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op) { - if (value->isAspectRatioValue()) { - CSSAspectRatioValue* aspectRatio = toCSSAspectRatioValue(value); - return compareValue(width * static_cast(aspectRatio->denominatorValue()), height * static_cast(aspectRatio->numeratorValue()), op); - } + if (!is(value)) + return false; + auto& aspectRatio = downcast(*value); + return compareValue(width * aspectRatio.denominatorValue(), height * aspectRatio.numeratorValue(), op); +} - return false; +static std::optional doubleValue(CSSValue* value) +{ + if (!is(value) || !downcast(*value).isNumber()) + return std::nullopt; + return downcast(*value).doubleValue(CSSPrimitiveValue::CSS_NUMBER); } -static bool numberValue(CSSValue* value, float& result) +static bool zeroEvaluate(CSSValue* value, MediaFeaturePrefix op) { - if (value->isPrimitiveValue() - && toCSSPrimitiveValue(value)->isNumber()) { - result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); + auto numericValue = doubleValue(value); + return numericValue && compareValue(0, numericValue.value(), op); +} + +static bool oneEvaluate(CSSValue* value, MediaFeaturePrefix op) +{ + if (!value) return true; - } - return false; + auto numericValue = doubleValue(value); + return numericValue && compareValue(1, numericValue.value(), op); } -static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool colorEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame().view()); - float number; - if (value) - return numberValue(value, number) && compareValue(bitsPerComponent, static_cast(number), op); + int bitsPerComponent = screenDepthPerComponent(frame.mainFrame().view()); + auto numericValue = doubleValue(value); + if (!numericValue) + return bitsPerComponent; + return compareValue(bitsPerComponent, numericValue.value(), op); +} - return bitsPerComponent != 0; +static bool colorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) +{ + // Always return false for indexed display. + return zeroEvaluate(value, op); } -static bool color_indexMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool colorGamutEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - // FIXME: It's unknown how to retrieve the information if the display mode is indexed - // Assume we don't support indexed display. if (!value) + return true; + + switch (downcast(*value).valueID()) { + case CSSValueSRGB: + return true; + case CSSValueP3: + // FIXME: For the moment we just assume any "extended color" display is at least as good as P3. + return screenSupportsExtendedColor(frame.mainFrame().view()); + case CSSValueRec2020: + // FIXME: At some point we should start detecting displays that support more colors. return false; + default: + return false; // Any unknown value should not be considered a match. + } +} + +static bool monochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) +{ + bool isMonochrome; + + if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + isMonochrome = true; + else if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + isMonochrome = false; + else + isMonochrome = screenIsMonochrome(frame.mainFrame().view()); - float number; - return numberValue(value, number) && compareValue(0, static_cast(number), op); + if (!isMonochrome) + return zeroEvaluate(value, op); + return colorEvaluate(value, conversionData, frame, op); } -static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool invertedColorsEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - if (!screenIsMonochrome(frame->page()->mainFrame().view())) { - if (value) { - float number; - return numberValue(value, number) && compareValue(0, static_cast(number), op); - } - return false; - } + bool isInverted; + + if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + isInverted = true; + else if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + isInverted = false; + else + isInverted = screenHasInvertedColors(); - return colorMediaFeatureEval(value, style, frame, op); + if (!value) + return isInverted; + + return downcast(*value).valueID() == (isInverted ? CSSValueInverted : CSSValueNone); } -static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool orientationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - int width = view->layoutWidth(); - int height = view->layoutHeight(); - if (value && value->isPrimitiveValue()) { - const CSSValueID id = toCSSPrimitiveValue(value)->getValueID(); - if (width > height) // Square viewport is portrait. - return CSSValueLandscape == id; - return CSSValuePortrait == id; + auto width = view->layoutWidth(); + auto height = view->layoutHeight(); + + if (!is(value)) { + // Expression (orientation) evaluates to true if width and height >= 0. + return height >= 0 && width >= 0; } - // Expression (orientation) evaluates to true if width and height >= 0. - return height >= 0 && width >= 0; + auto keyword = downcast(*value).valueID(); + if (width > height) // Square viewport is portrait. + return keyword == CSSValueLandscape; + return keyword == CSSValuePortrait; } -static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool aspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); - if (!view) + // ({,min-,max-}aspect-ratio) + // assume if we have a device, its aspect ratio is non-zero + if (!value) return true; - if (value) - return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op); + FrameView* view = frame.view(); + if (!view) + return true; - // ({,min-,max-}aspect-ratio) - // assume if we have a device, its aspect ratio is non-zero - return true; + return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op); } -static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool deviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - return compareAspectRatioValue(value, static_cast(sg.width()), static_cast(sg.height()), op); - } - // ({,min-,max-}device-aspect-ratio) // assume if we have a device, its aspect ratio is non-zero - return true; + if (!value) + return true; + + auto size = screenRect(frame.mainFrame().view()).size(); + return compareAspectRatioValue(value, size.width(), size.height(), op); } -static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) +static bool evaluateResolution(CSSValue* value, Frame& frame, MediaFeaturePrefix op) { // FIXME: Possible handle other media types than 'screen' and 'print'. - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; float deviceScaleFactor = 0; + // This checks the actual media type applied to the document, and we know // this method only got called if this media type matches the one defined // in the query. Thus, if if the document's media type is "print", the // media type of the query will either be "print" or "all". String mediaType = view->mediaType(); - if (equalIgnoringCase(mediaType, "screen")) - deviceScaleFactor = frame->page()->deviceScaleFactor(); - else if (equalIgnoringCase(mediaType, "print")) { + if (equalLettersIgnoringASCIICase(mediaType, "screen")) + deviceScaleFactor = frame.page() ? frame.page()->deviceScaleFactor() : 1; + else if (equalLettersIgnoringASCIICase(mediaType, "print")) { // The resolution of images while printing should not depend on the dpi // of the screen. Until we support proper ways of querying this info // we use 300px which is considered minimum for current printers. @@ -307,22 +373,22 @@ static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) if (!value) return !!deviceScaleFactor; - if (!value->isPrimitiveValue()) + if (!is(value)) return false; - CSSPrimitiveValue* resolution = toCSSPrimitiveValue(value); - return compareValue(deviceScaleFactor, resolution->isNumber() ? resolution->getFloatValue() : resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op); + auto& resolution = downcast(*value); + return compareValue(deviceScaleFactor, resolution.isNumber() ? resolution.floatValue() : resolution.floatValue(CSSPrimitiveValue::CSS_DPPX), op); } -static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool devicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - return (!value || toCSSPrimitiveValue(value)->isNumber()) && evalResolution(value, frame, op); + return (!value || (is(*value) && downcast(*value).isNumber())) && evaluateResolution(value, frame, op); } -static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool resolutionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { #if ENABLE(RESOLUTION_MEDIA_QUERY) - return (!value || toCSSPrimitiveValue(value)->isResolution()) && evalResolution(value, frame, op); + return (!value || (is(*value) && downcast(*value).isResolution())) && evaluateResolution(value, frame, op); #else UNUSED_PARAM(value); UNUSED_PARAM(frame); @@ -331,408 +397,341 @@ static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra #endif } -static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool gridEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - // if output device is bitmap, grid: 0 == true - // assume we have bitmap device - float number; - if (value && numberValue(value, number)) - return compareValue(static_cast(number), 0, op); - return false; + return zeroEvaluate(value, op); } -static bool computeLength(CSSValue* value, bool strict, RenderStyle* style, RenderStyle* rootStyle, int& result) +static bool computeLength(CSSValue* value, bool strict, const CSSToLengthConversionData& conversionData, int& result) { - if (!value->isPrimitiveValue()) + if (!is(value)) return false; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); + auto& primitiveValue = downcast(*value); - if (primitiveValue->isNumber()) { - result = primitiveValue->getIntValue(); + if (primitiveValue.isNumber()) { + result = primitiveValue.intValue(); return !strict || !result; } - if (primitiveValue->isLength()) { - result = primitiveValue->computeLength(style, rootStyle); + if (primitiveValue.isLength()) { + result = primitiveValue.computeLength(conversionData); return true; } return false; } -static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool deviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - long height = sg.height(); - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast(height), length, op); - } // ({,min-,max-}device-height) // assume if we have a device, assume non-zero - return true; + if (!value) + return true; + int length; + auto height = screenRect(frame.mainFrame().view()).height(); + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op); } -static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool deviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - long width = sg.width(); - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast(width), length, op); - } // ({,min-,max-}device-width) // assume if we have a device, assume non-zero - return true; + if (!value) + return true; + int length; + auto width = screenRect(frame.mainFrame().view()).width(); + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op); } -static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool heightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - - if (value) { - int height = view->layoutHeight(); - if (RenderView* renderView = frame->document()->renderView()) - height = adjustForAbsoluteZoom(height, *renderView); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(height, length, op); - } - - return view->layoutHeight() != 0; + int height = view->layoutHeight(); + if (!value) + return height; + if (auto* renderView = frame.document()->renderView()) + height = adjustForAbsoluteZoom(height, *renderView); + int length; + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op); } -static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool widthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - - if (value) { - int width = view->layoutWidth(); - if (RenderView* renderView = frame->document()->renderView()) - width = adjustForAbsoluteZoom(width, *renderView); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(width, length, op); - } - - return view->layoutWidth() != 0; + int width = view->layoutWidth(); + if (!value) + return width; + if (auto* renderView = frame.document()->renderView()) + width = adjustForAbsoluteZoom(width, *renderView); + int length; + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op); } -// rest of the functions are trampolines which set the prefix according to the media feature expression used - -static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return colorMediaFeatureEval(value, style, frame, MinPrefix); + return colorEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return colorMediaFeatureEval(value, style, frame, MaxPrefix); + return colorEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return color_indexMediaFeatureEval(value, style, frame, MinPrefix); + return colorIndexEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return color_indexMediaFeatureEval(value, style, frame, MaxPrefix); + return colorIndexEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return monochromeMediaFeatureEval(value, style, frame, MinPrefix); + return monochromeEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return monochromeMediaFeatureEval(value, style, frame, MaxPrefix); + return monochromeEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return aspectRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return aspectRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return deviceAspectRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceAspectRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return devicePixelRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return devicePixelRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return heightMediaFeatureEval(value, style, frame, MinPrefix); + return heightEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return heightMediaFeatureEval(value, style, frame, MaxPrefix); + return heightEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return widthMediaFeatureEval(value, style, frame, MinPrefix); + return widthEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return widthMediaFeatureEval(value, style, frame, MaxPrefix); + return widthEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_heightMediaFeatureEval(value, style, frame, MinPrefix); + return deviceHeightEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_heightMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceHeightEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_widthMediaFeatureEval(value, style, frame, MinPrefix); + return deviceWidthEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_widthMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceWidthEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return resolutionMediaFeatureEval(value, style, frame, MinPrefix); + return resolutionEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return resolutionMediaFeatureEval(value, style, frame, MaxPrefix); + return resolutionEvaluate(value, conversionData, frame, MaxPrefix); } -static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool animationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool transitionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool transform2dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool transform3dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - bool returnValueIfNoParameter; - int have3dRendering; - -#if ENABLE(3D_RENDERING) - bool threeDEnabled = false; -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* view = frame->contentRenderer()) - threeDEnabled = view->compositor().canRender3DTransforms(); -#endif - - returnValueIfNoParameter = threeDEnabled; - have3dRendering = threeDEnabled ? 1 : 0; +#if ENABLE(3D_TRANSFORMS) + auto* view = frame.contentRenderer(); + return view && view->compositor().canRender3DTransforms() ? oneEvaluate(value, op) : zeroEvaluate(value, op); #else UNUSED_PARAM(frame); - returnValueIfNoParameter = false; - have3dRendering = 0; + return zeroEvaluate(value, op); #endif - - if (value) { - float number; - return numberValue(value, number) && compareValue(have3dRendering, static_cast(number), op); - } - return returnValueIfNoParameter; } #if ENABLE(VIEW_MODE_CSS_MEDIA) -static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) + +static bool viewModeEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - UNUSED_PARAM(op); if (!value) return true; - const int viewModeCSSKeywordID = toCSSPrimitiveValue(value)->getValueID(); - const Page::ViewMode viewMode = frame->page()->viewMode(); - bool result = false; - switch (viewMode) { + auto keyword = downcast(*value).valueID(); + + switch (frame.page()->viewMode()) { case Page::ViewModeWindowed: - result = viewModeCSSKeywordID == CSSValueWindowed; - break; + return keyword == CSSValueWindowed; case Page::ViewModeFloating: - result = viewModeCSSKeywordID == CSSValueFloating; - break; + return keyword == CSSValueFloating; case Page::ViewModeFullscreen: - result = viewModeCSSKeywordID == CSSValueFullscreen; - break; + return keyword == CSSValueFullscreen; case Page::ViewModeMaximized: - result = viewModeCSSKeywordID == CSSValueMaximized; - break; + return keyword == CSSValueMaximized; case Page::ViewModeMinimized: - result = viewModeCSSKeywordID == CSSValueMinimized; - break; + return keyword == CSSValueMinimized; default: - result = false; break; } - return result; + return false; } + #endif // ENABLE(VIEW_MODE_CSS_MEDIA) -// FIXME: Find a better place for this function. Maybe ChromeClient? -static inline bool isRunningOnIPhoneOrIPod() +static bool videoPlayableInlineEvaluate(CSSValue*, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) +{ + return frame.settings().allowsInlineMediaPlayback(); +} + +static bool hoverEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix) { -#if PLATFORM(IOS) - static wkDeviceClass deviceClass = iosDeviceClass(); - return deviceClass == wkDeviceClassiPhone || deviceClass == wkDeviceClassiPod; + if (!is(value)) { +#if ENABLE(TOUCH_EVENTS) + return false; #else - return false; + return true; +#endif + } + + auto keyword = downcast(*value).valueID(); +#if ENABLE(TOUCH_EVENTS) + return keyword == CSSValueNone; +#else + return keyword == CSSValueHover; #endif } -static bool video_playable_inlineMediaFeatureEval(CSSValue*, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool anyHoverEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix) { - return !isRunningOnIPhoneOrIPod() || frame->settings().mediaPlaybackAllowsInline(); + return hoverEvaluate(value, cssToLengthConversionData, frame, prefix); } -enum PointerDeviceType { TouchPointer, MousePointer, NoPointer, UnknownPointer }; - -static PointerDeviceType leastCapablePrimaryPointerDeviceType(Frame* frame) +static bool pointerEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix) { - if (frame->settings().deviceSupportsTouch()) - return TouchPointer; - - // FIXME: We should also try to determine if we know we have a mouse. - // When we do this, we'll also need to differentiate between known not to - // have mouse or touch screen (NoPointer) and unknown (UnknownPointer). - // We could also take into account other preferences like accessibility - // settings to decide which of the available pointers should be considered - // "primary". + if (!is(value)) + return true; - return UnknownPointer; + auto keyword = downcast(*value).valueID(); +#if ENABLE(TOUCH_EVENTS) + return keyword == CSSValueCoarse; +#else + return keyword == CSSValueFine; +#endif } -static bool hoverMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool anyPointerEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix) { - PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); - - // If we're on a port that hasn't explicitly opted into providing pointer device information - // (or otherwise can't be confident in the pointer hardware available), then behave exactly - // as if this feature feature isn't supported. - if (pointer == UnknownPointer) - return false; - - float number = 1; - if (value) { - if (!numberValue(value, number)) - return false; - } - - return (pointer == NoPointer && !number) - || (pointer == TouchPointer && !number) - || (pointer == MousePointer && number == 1); + return pointerEvaluate(value, cssToLengthConversionData, frame, prefix); } -static bool pointerMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); + bool userPrefersReducedMotion = false; - // If we're on a port that hasn't explicitly opted into providing pointer device information - // (or otherwise can't be confident in the pointer hardware available), then behave exactly - // as if this feature feature isn't supported. - if (pointer == UnknownPointer) - return false; + if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + userPrefersReducedMotion = true; + else if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + userPrefersReducedMotion = false; +#if PLATFORM(IOS) || USE(NEW_THEME) + else + userPrefersReducedMotion = platformTheme()->userPrefersReducedMotion(); +#endif if (!value) - return pointer != NoPointer; + return userPrefersReducedMotion; - if (!value->isPrimitiveValue()) - return false; - - const CSSValueID id = toCSSPrimitiveValue(value)->getValueID(); - return (pointer == NoPointer && id == CSSValueNone) - || (pointer == TouchPointer && id == CSSValueCoarse) - || (pointer == MousePointer && id == CSSValueFine); + return downcast(*value).valueID() == (userPrefersReducedMotion ? CSSValueReduce : CSSValueNoPreference); } -// FIXME: Remove unnecessary '&' from the following 'ADD_TO_FUNCTIONMAP' definition -// once we switch to a non-broken Visual Studio compiler. https://bugs.webkit.org/show_bug.cgi?id=121235 -static void createFunctionMap() +// Use this function instead of calling add directly to avoid inlining. +static void add(MediaQueryFunctionMap& map, AtomicStringImpl* key, MediaQueryFunction value) { - // Create the table. - gFunctionMap = new FunctionMap; -#define ADD_TO_FUNCTIONMAP(name, str) \ - gFunctionMap->set(name##MediaFeature.impl(), &name##MediaFeatureEval); - CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); -#undef ADD_TO_FUNCTIONMAP + map.add(key, value); } -bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const +bool MediaQueryEvaluator::evaluate(const MediaQueryExpression& expression) const { if (!m_frame || !m_frame->view() || !m_style) - return m_expResult; + return m_fallbackResult; - if (!expr->isValid()) + if (!expression.isValid()) return false; - if (!gFunctionMap) - createFunctionMap(); + static NeverDestroyed map = [] { + MediaQueryFunctionMap map; +#define ADD_TO_FUNCTIONMAP(name, str) add(map, MediaFeatureNames::name.impl(), name##Evaluate); + CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); +#undef ADD_TO_FUNCTIONMAP + return map; + }(); - // call the media feature evaluation function. Assume no prefix - // and let trampoline functions override the prefix if prefix is - // used - EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); - if (func) - return func(expr->value(), m_style.get(), m_frame, NoPrefix); + auto function = map.get().get(expression.mediaFeature().impl()); + if (!function) + return false; - return false; + Document& document = *m_frame->document(); + if (!document.documentElement()) + return false; + return function(expression.value(), { m_style, document.documentElement()->renderStyle(), document.renderView(), 1, false }, *m_frame, NoPrefix); } } // namespace diff --git a/Source/WebCore/css/MediaQueryEvaluator.h b/Source/WebCore/css/MediaQueryEvaluator.h index c9ea5932f..eae5e947f 100644 --- a/Source/WebCore/css/MediaQueryEvaluator.h +++ b/Source/WebCore/css/MediaQueryEvaluator.h @@ -15,7 +15,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -25,66 +25,56 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaQueryEvaluator_h -#define MediaQueryEvaluator_h +#pragma once -#include +#include "MediaQueryExpression.h" namespace WebCore { + +class Document; class Frame; -class MediaQueryExp; class MediaQuerySet; class RenderStyle; class StyleResolver; -/** - * Class that evaluates css media queries as defined in - * CSS3 Module "Media Queries" (http://www.w3.org/TR/css3-mediaqueries/) - * Special constructors are needed, if simple media queries are to be - * evaluated without knowledge of the medium features. This can happen - * for example when parsing UA stylesheets, if evaluation is done - * right after parsing. - * - * the boolean parameter is used to approximate results of evaluation, if - * the device characteristics are not known. This can be used to prune the loading - * of stylesheets to only those which are probable to match. - */ +struct MediaQueryResult { + MediaQueryExpression expression; + bool result; +}; + +// Some of the constructors are used for cases where the device characteristics are not known. +// These can be used to prune the loading of stylesheets to only those which are not already known to not match. + class MediaQueryEvaluator { - WTF_MAKE_NONCOPYABLE(MediaQueryEvaluator); WTF_MAKE_FAST_ALLOCATED; public: - /** Creates evaluator which evaluates only simple media queries - * Evaluator returns true for "all", and returns value of \mediaFeatureResult - * for any media features - */ + // Creates evaluator which evaluates only simple media queries. + // Evaluator returns true for "all", and returns value of \mediaFeatureResult for any media features. explicit MediaQueryEvaluator(bool mediaFeatureResult = false); - /** Creates evaluator which evaluates only simple media queries - * Evaluator returns true for acceptedMediaType and returns value of \mediafeatureResult - * for any media features - */ + // Creates evaluator which evaluates only simple media queries. + // Evaluator returns true for acceptedMediaType and returns value of \mediaFeatureResult for any media features. MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult = false); - /** Creates evaluator which evaluates full media queries - */ - MediaQueryEvaluator(const String& acceptedMediaType, Frame*, RenderStyle*); - - ~MediaQueryEvaluator(); + // Creates evaluator which evaluates full media queries. + WEBCORE_EXPORT MediaQueryEvaluator(const String& acceptedMediaType, const Document&, const RenderStyle*); bool mediaTypeMatch(const String& mediaTypeToMatch) const; bool mediaTypeMatchSpecific(const char* mediaTypeToMatch) const; - /** Evaluates a list of media queries */ - bool eval(const MediaQuerySet*, StyleResolver* = 0) const; + // Evaluates a list of media queries. + WEBCORE_EXPORT bool evaluate(const MediaQuerySet&, StyleResolver* = nullptr) const; + + // Evaluates media query subexpression, ie "and (media-feature: value)" part. + bool evaluate(const MediaQueryExpression&) const; - /** Evaluates media query subexpression, ie "and (media-feature: value)" part */ - bool eval(const MediaQueryExp*) const; + // Evaluates a list of media queries and fills in a vector with any viewport-dependent results found. + bool evaluate(const MediaQuerySet&, Vector&) const; private: String m_mediaType; - Frame* m_frame; // not owned - RefPtr m_style; - bool m_expResult; + Frame* m_frame { nullptr }; // not owned + const RenderStyle* m_style { nullptr }; + bool m_fallbackResult { false }; }; } // namespace -#endif diff --git a/Source/WebCore/css/MediaQueryExp.cpp b/Source/WebCore/css/MediaQueryExp.cpp deleted file mode 100644 index e9cf1e008..000000000 --- a/Source/WebCore/css/MediaQueryExp.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * CSS Media Query - * - * Copyright (C) 2006 Kimmo Kinnunen . - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MediaQueryExp.h" - -#include "CSSAspectRatioValue.h" -#include "CSSParser.h" -#include "CSSPrimitiveValue.h" -#include "CSSValueList.h" -#include - -namespace WebCore { - -static inline bool featureWithCSSValueID(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if (!value->id) - return false; - - return mediaFeature == MediaFeatureNames::orientationMediaFeature -#if ENABLE(VIEW_MODE_CSS_MEDIA) - || mediaFeature == MediaFeatureNames::view_modeMediaFeature -#endif // ENABLE(VIEW_MODE_CSS_MEDIA) - || mediaFeature == MediaFeatureNames::pointerMediaFeature; -} - -static inline bool featureWithValidPositiveLenghtOrNumber(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if (!(((value->unit >= CSSPrimitiveValue::CSS_EMS && value->unit <= CSSPrimitiveValue::CSS_PC) || value->unit == CSSPrimitiveValue::CSS_REMS) || value->unit == CSSPrimitiveValue::CSS_NUMBER) || value->fValue < 0) - return false; - - return mediaFeature == MediaFeatureNames::heightMediaFeature - || mediaFeature == MediaFeatureNames::max_heightMediaFeature - || mediaFeature == MediaFeatureNames::min_heightMediaFeature - || mediaFeature == MediaFeatureNames::widthMediaFeature - || mediaFeature == MediaFeatureNames::max_widthMediaFeature - || mediaFeature == MediaFeatureNames::min_widthMediaFeature - || mediaFeature == MediaFeatureNames::device_heightMediaFeature - || mediaFeature == MediaFeatureNames::max_device_heightMediaFeature - || mediaFeature == MediaFeatureNames::min_device_heightMediaFeature - || mediaFeature == MediaFeatureNames::device_widthMediaFeature - || mediaFeature == MediaFeatureNames::max_device_widthMediaFeature - || mediaFeature == MediaFeatureNames::min_device_widthMediaFeature; -} - -static inline bool featureWithValidDensity(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if ((value->unit != CSSPrimitiveValue::CSS_DPPX && value->unit != CSSPrimitiveValue::CSS_DPI && value->unit != CSSPrimitiveValue::CSS_DPCM) || value->fValue <= 0) - return false; - - return mediaFeature == MediaFeatureNames::resolutionMediaFeature - || mediaFeature == MediaFeatureNames::max_resolutionMediaFeature - || mediaFeature == MediaFeatureNames::min_resolutionMediaFeature; -} - -static inline bool featureWithPositiveInteger(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if (!value->isInt || value->fValue < 0) - return false; - - return mediaFeature == MediaFeatureNames::colorMediaFeature - || mediaFeature == MediaFeatureNames::max_colorMediaFeature - || mediaFeature == MediaFeatureNames::min_colorMediaFeature - || mediaFeature == MediaFeatureNames::color_indexMediaFeature - || mediaFeature == MediaFeatureNames::max_color_indexMediaFeature - || mediaFeature == MediaFeatureNames::min_color_indexMediaFeature - || mediaFeature == MediaFeatureNames::min_monochromeMediaFeature - || mediaFeature == MediaFeatureNames::max_monochromeMediaFeature; -} - -static inline bool featureWithPositiveNumber(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if (value->unit != CSSPrimitiveValue::CSS_NUMBER || value->fValue < 0) - return false; - - return mediaFeature == MediaFeatureNames::transform_2dMediaFeature - || mediaFeature == MediaFeatureNames::transform_3dMediaFeature - || mediaFeature == MediaFeatureNames::transitionMediaFeature - || mediaFeature == MediaFeatureNames::animationMediaFeature - || mediaFeature == MediaFeatureNames::device_pixel_ratioMediaFeature - || mediaFeature == MediaFeatureNames::max_device_pixel_ratioMediaFeature - || mediaFeature == MediaFeatureNames::min_device_pixel_ratioMediaFeature; -} - -static inline bool featureWithZeroOrOne(const AtomicString& mediaFeature, const CSSParserValue* value) -{ - if (!value->isInt || !(value->fValue == 1 || !value->fValue)) - return false; - - return mediaFeature == MediaFeatureNames::gridMediaFeature - || mediaFeature == MediaFeatureNames::hoverMediaFeature; -} - -static inline bool featureWithAspectRatio(const AtomicString& mediaFeature) -{ - return mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::device_aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::min_aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::max_aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::min_device_aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::max_device_aspect_ratioMediaFeature; -} - -static inline bool featureWithoutValue(const AtomicString& mediaFeature) -{ - // Media features that are prefixed by min/max cannot be used without a value. - return mediaFeature == MediaFeatureNames::monochromeMediaFeature - || mediaFeature == MediaFeatureNames::colorMediaFeature - || mediaFeature == MediaFeatureNames::color_indexMediaFeature - || mediaFeature == MediaFeatureNames::gridMediaFeature - || mediaFeature == MediaFeatureNames::heightMediaFeature - || mediaFeature == MediaFeatureNames::widthMediaFeature - || mediaFeature == MediaFeatureNames::device_heightMediaFeature - || mediaFeature == MediaFeatureNames::device_widthMediaFeature - || mediaFeature == MediaFeatureNames::orientationMediaFeature - || mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::device_aspect_ratioMediaFeature - || mediaFeature == MediaFeatureNames::hoverMediaFeature - || mediaFeature == MediaFeatureNames::transform_2dMediaFeature - || mediaFeature == MediaFeatureNames::transform_3dMediaFeature - || mediaFeature == MediaFeatureNames::transitionMediaFeature - || mediaFeature == MediaFeatureNames::animationMediaFeature -#if ENABLE(VIEW_MODE_CSS_MEDIA) - || mediaFeature == MediaFeatureNames::view_modeMediaFeature -#endif // ENABLE(VIEW_MODE_CSS_MEDIA) - || mediaFeature == MediaFeatureNames::pointerMediaFeature - || mediaFeature == MediaFeatureNames::device_pixel_ratioMediaFeature - || mediaFeature == MediaFeatureNames::resolutionMediaFeature; -} - -inline MediaQueryExp::MediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* valueList) - : m_mediaFeature(mediaFeature) - , m_value(0) - , m_isValid(false) -{ - // Initialize media query expression that must have 1 or more values. - if (valueList) { - if (valueList->size() == 1) { - CSSParserValue* value = valueList->current(); - - // Media features that use CSSValueIDs. - if (featureWithCSSValueID(mediaFeature, value)) - m_value = CSSPrimitiveValue::createIdentifier(value->id); - - // Media features that must have non-negative , ie. dppx, dpi or dpcm. - else if (featureWithValidDensity(mediaFeature, value)) - m_value = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); - - // Media features that must have non-negative or number value. - else if (featureWithValidPositiveLenghtOrNumber(mediaFeature, value)) - m_value = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); - - // Media features that must have non-negative integer value. - else if (featureWithPositiveInteger(mediaFeature, value)) - m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); - - // Media features that must have non-negative number value. - else if (featureWithPositiveNumber(mediaFeature, value)) - m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); - - // Media features that must have (0|1) value. - else if (featureWithZeroOrOne(mediaFeature, value)) - m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); - - m_isValid = m_value; - } else if (valueList->size() == 3 && featureWithAspectRatio(mediaFeature)) { - // Create list of values. - // Currently accepts only /. - // Applicable to device-aspect-ratio and aspec-ratio. - bool isValid = true; - float numeratorValue = 0; - float denominatorValue = 0; - - // The aspect-ratio must be (whitespace)? / (whitespace)? . - for (unsigned i = 0; i < 3; ++i, valueList->next()) { - const CSSParserValue* value = valueList->current(); - if (i != 1 && value->unit == CSSPrimitiveValue::CSS_NUMBER && value->fValue > 0 && value->isInt) { - if (!i) - numeratorValue = value->fValue; - else - denominatorValue = value->fValue; - } else if (i == 1 && value->unit == CSSParserValue::Operator && value->iValue == '/') - continue; - else { - isValid = false; - break; - } - } - - if (isValid) - m_value = CSSAspectRatioValue::create(numeratorValue, denominatorValue); - - m_isValid = m_value; - } - } else if (featureWithoutValue(mediaFeature)) - m_isValid = true; -} - -PassOwnPtr MediaQueryExp::create(const AtomicString& mediaFeature, CSSParserValueList* values) -{ - return adoptPtr(new MediaQueryExp(mediaFeature, values)); -} - -MediaQueryExp::~MediaQueryExp() -{ -} - -String MediaQueryExp::serialize() const -{ - if (!m_serializationCache.isNull()) - return m_serializationCache; - - StringBuilder result; - result.append('('); - result.append(m_mediaFeature.lower()); - if (m_value) { - result.appendLiteral(": "); - result.append(m_value->cssText()); - } - result.append(')'); - - const_cast(this)->m_serializationCache = result.toString(); - return m_serializationCache; -} - -} // namespace diff --git a/Source/WebCore/css/MediaQueryExp.h b/Source/WebCore/css/MediaQueryExp.h deleted file mode 100644 index fd543c041..000000000 --- a/Source/WebCore/css/MediaQueryExp.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * CSS Media Query - * - * Copyright (C) 2006 Kimmo Kinnunen . - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MediaQueryExp_h -#define MediaQueryExp_h - -#include "CSSValue.h" -#include "MediaFeatureNames.h" -#include -#include -#include - -namespace WebCore { -class CSSParserValueList; - -class MediaQueryExp { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassOwnPtr create(const AtomicString& mediaFeature, CSSParserValueList* values); - ~MediaQueryExp(); - - AtomicString mediaFeature() const { return m_mediaFeature; } - - CSSValue* value() const { return m_value.get(); } - - bool operator==(const MediaQueryExp& other) const - { - return (other.m_mediaFeature == m_mediaFeature) - && ((!other.m_value && !m_value) - || (other.m_value && m_value && other.m_value->equals(*m_value))); - } - - bool isValid() const { return m_isValid; } - - bool isViewportDependent() const { return m_mediaFeature == MediaFeatureNames::widthMediaFeature - || m_mediaFeature == MediaFeatureNames::heightMediaFeature - || m_mediaFeature == MediaFeatureNames::min_widthMediaFeature - || m_mediaFeature == MediaFeatureNames::min_heightMediaFeature - || m_mediaFeature == MediaFeatureNames::max_widthMediaFeature - || m_mediaFeature == MediaFeatureNames::max_heightMediaFeature - || m_mediaFeature == MediaFeatureNames::orientationMediaFeature - || m_mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature - || m_mediaFeature == MediaFeatureNames::min_aspect_ratioMediaFeature - || m_mediaFeature == MediaFeatureNames::max_aspect_ratioMediaFeature; } - - String serialize() const; - - PassOwnPtr copy() const { return adoptPtr(new MediaQueryExp(*this)); } - -private: - MediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* values); - - AtomicString m_mediaFeature; - RefPtr m_value; - bool m_isValid; - String m_serializationCache; -}; - -} // namespace - -#endif diff --git a/Source/WebCore/css/MediaQueryExpression.cpp b/Source/WebCore/css/MediaQueryExpression.cpp new file mode 100644 index 000000000..91eb30452 --- /dev/null +++ b/Source/WebCore/css/MediaQueryExpression.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2006 Kimmo Kinnunen . + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MediaQueryExpression.h" + +#include "CSSAspectRatioValue.h" +#include "CSSParser.h" +#include "CSSParserIdioms.h" +#include "CSSParserToken.h" +#include "CSSPrimitiveValue.h" +#include "CSSValueList.h" +#include "MediaFeatureNames.h" +#include + +namespace WebCore { + +static inline bool featureWithValidIdent(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::orientation +#if ENABLE(VIEW_MODE_CSS_MEDIA) + || mediaFeature == MediaFeatureNames::viewMode +#endif + || mediaFeature == MediaFeatureNames::colorGamut + || mediaFeature == MediaFeatureNames::anyHover + || mediaFeature == MediaFeatureNames::anyPointer + || mediaFeature == MediaFeatureNames::hover + || mediaFeature == MediaFeatureNames::invertedColors + || mediaFeature == MediaFeatureNames::pointer + || mediaFeature == MediaFeatureNames::prefersReducedMotion; +} + +static inline bool featureWithValidDensity(const String& mediaFeature, const CSSParserToken& token) +{ + if (!CSSPrimitiveValue::isResolution(static_cast(token.unitType())) || token.numericValue() <= 0) + return false; + + return mediaFeature == MediaFeatureNames::resolution + || mediaFeature == MediaFeatureNames::minResolution + || mediaFeature == MediaFeatureNames::maxResolution; +} + +static inline bool featureWithValidPositiveLength(const String& mediaFeature, const CSSParserToken& token) +{ + if (!(CSSPrimitiveValue::isLength(token.unitType()) || (token.type() == NumberToken && !token.numericValue())) || token.numericValue() < 0) + return false; + + + return mediaFeature == MediaFeatureNames::height + || mediaFeature == MediaFeatureNames::maxHeight + || mediaFeature == MediaFeatureNames::minHeight + || mediaFeature == MediaFeatureNames::width + || mediaFeature == MediaFeatureNames::maxWidth + || mediaFeature == MediaFeatureNames::minWidth + || mediaFeature == MediaFeatureNames::deviceHeight + || mediaFeature == MediaFeatureNames::maxDeviceHeight + || mediaFeature == MediaFeatureNames::minDeviceHeight + || mediaFeature == MediaFeatureNames::deviceWidth + || mediaFeature == MediaFeatureNames::minDeviceWidth + || mediaFeature == MediaFeatureNames::maxDeviceWidth; +} + +static inline bool featureWithPositiveInteger(const String& mediaFeature, const CSSParserToken& token) +{ + if (token.numericValueType() != IntegerValueType || token.numericValue() < 0) + return false; + + return mediaFeature == MediaFeatureNames::color + || mediaFeature == MediaFeatureNames:: maxColor + || mediaFeature == MediaFeatureNames:: minColor + || mediaFeature == MediaFeatureNames::colorIndex + || mediaFeature == MediaFeatureNames::maxColorIndex + || mediaFeature == MediaFeatureNames::minColorIndex + || mediaFeature == MediaFeatureNames::monochrome + || mediaFeature == MediaFeatureNames::maxMonochrome + || mediaFeature == MediaFeatureNames::minMonochrome; +} + +static inline bool featureWithPositiveNumber(const String& mediaFeature, const CSSParserToken& token) +{ + if (token.type() != NumberToken || token.numericValue() < 0) + return false; + + return mediaFeature == MediaFeatureNames::transform3d + || mediaFeature == MediaFeatureNames::devicePixelRatio + || mediaFeature == MediaFeatureNames::maxDevicePixelRatio + || mediaFeature == MediaFeatureNames::minDevicePixelRatio + || mediaFeature == MediaFeatureNames::transition + || mediaFeature == MediaFeatureNames::animation + || mediaFeature == MediaFeatureNames::transform2d; +} + +static inline bool featureWithZeroOrOne(const String& mediaFeature, const CSSParserToken& token) +{ + if (token.numericValueType() != IntegerValueType || !(token.numericValue() == 1 || !token.numericValue())) + return false; + + return mediaFeature == MediaFeatureNames::grid; +} + +static inline bool isAspectRatioFeature(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::aspectRatio + || mediaFeature == MediaFeatureNames::deviceAspectRatio + || mediaFeature == MediaFeatureNames::minAspectRatio + || mediaFeature == MediaFeatureNames::maxAspectRatio + || mediaFeature == MediaFeatureNames::minDeviceAspectRatio + || mediaFeature == MediaFeatureNames::maxDeviceAspectRatio; +} + +static inline bool isFeatureValidWithoutValue(const AtomicString& mediaFeature) +{ + // Media features that are prefixed by min/max cannot be used without a value. + return mediaFeature == MediaFeatureNames::anyHover + || mediaFeature == MediaFeatureNames::anyPointer + || mediaFeature == MediaFeatureNames::monochrome + || mediaFeature == MediaFeatureNames::color + || mediaFeature == MediaFeatureNames::colorIndex + || mediaFeature == MediaFeatureNames::grid + || mediaFeature == MediaFeatureNames::height + || mediaFeature == MediaFeatureNames::width + || mediaFeature == MediaFeatureNames::deviceHeight + || mediaFeature == MediaFeatureNames::deviceWidth + || mediaFeature == MediaFeatureNames::orientation + || mediaFeature == MediaFeatureNames::aspectRatio + || mediaFeature == MediaFeatureNames::deviceAspectRatio + || mediaFeature == MediaFeatureNames::hover + || mediaFeature == MediaFeatureNames::transform2d + || mediaFeature == MediaFeatureNames::transform3d + || mediaFeature == MediaFeatureNames::transition + || mediaFeature == MediaFeatureNames::animation + || mediaFeature == MediaFeatureNames::invertedColors +#if ENABLE(VIEW_MODE_CSS_MEDIA) + || mediaFeature == MediaFeatureNames::viewMode +#endif + || mediaFeature == MediaFeatureNames::pointer + || mediaFeature == MediaFeatureNames::prefersReducedMotion + || mediaFeature == MediaFeatureNames::devicePixelRatio + || mediaFeature == MediaFeatureNames::resolution + || mediaFeature == MediaFeatureNames::videoPlayableInline; +} + +MediaQueryExpression::MediaQueryExpression(const String& feature, const Vector& tokenList) + : m_mediaFeature(feature.convertToASCIILowercase()) + , m_isValid(false) +{ + // Create value for media query expression that must have 1 or more values. + if (!tokenList.size() && isFeatureValidWithoutValue(m_mediaFeature)) { + // Valid, creates a MediaQueryExp with an 'invalid' MediaQueryExpValue + m_isValid = true; + } else if (tokenList.size() == 1) { + CSSParserToken token = tokenList.first(); + if (token.type() == IdentToken) { + CSSValueID ident = token.id(); + if (!featureWithValidIdent(m_mediaFeature)) + return; + m_value = CSSPrimitiveValue::createIdentifier(ident); + m_isValid = true; + } else if (token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken) { + // Check for numeric token types since it is only safe for these types to call numericValue. + if (featureWithValidDensity(m_mediaFeature, token) + || featureWithValidPositiveLength(m_mediaFeature, token)) { + // Media features that must have non-negative , ie. dppx, dpi or dpcm, + // or Media features that must have non-negative or number value. + m_value = CSSPrimitiveValue::create(token.numericValue(), (CSSPrimitiveValue::UnitType) token.unitType()); + m_isValid = true; + } else if (featureWithPositiveInteger(m_mediaFeature, token) + || featureWithPositiveNumber(m_mediaFeature, token) + || featureWithZeroOrOne(m_mediaFeature, token)) { + // Media features that must have non-negative integer value, + // or media features that must have non-negative number value, + // or media features that must have (0|1) value. + m_value = CSSPrimitiveValue::create(token.numericValue(), CSSPrimitiveValue::UnitType::CSS_NUMBER); + m_isValid = true; + } + } + } else if (tokenList.size() == 3 && isAspectRatioFeature(m_mediaFeature)) { + // FIXME: is supposed to allow whitespace around the '/' + // Applicable to device-aspect-ratio and aspect-ratio. + const CSSParserToken& numerator = tokenList[0]; + const CSSParserToken& delimiter = tokenList[1]; + const CSSParserToken& denominator = tokenList[2]; + if (delimiter.type() != DelimiterToken || delimiter.delimiter() != '/') + return; + if (numerator.type() != NumberToken || numerator.numericValue() <= 0 || numerator.numericValueType() != IntegerValueType) + return; + if (denominator.type() != NumberToken || denominator.numericValue() <= 0 || denominator.numericValueType() != IntegerValueType) + return; + + m_value = CSSAspectRatioValue::create(numerator.numericValue(), denominator.numericValue()); + m_isValid = true; + } +} + +String MediaQueryExpression::serialize() const +{ + if (!m_serializationCache.isNull()) + return m_serializationCache; + + StringBuilder result; + result.append('('); + result.append(m_mediaFeature.convertToASCIILowercase()); + if (m_value) { + result.appendLiteral(": "); + result.append(m_value->cssText()); + } + result.append(')'); + + m_serializationCache = result.toString(); + return m_serializationCache; +} + +} // namespace diff --git a/Source/WebCore/css/MediaQueryExpression.h b/Source/WebCore/css/MediaQueryExpression.h new file mode 100644 index 000000000..290d8ea62 --- /dev/null +++ b/Source/WebCore/css/MediaQueryExpression.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006 Kimmo Kinnunen . + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CSSParserToken.h" +#include "CSSValue.h" +#include + +namespace WebCore { + +class MediaQueryExpression { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit MediaQueryExpression(const String& mediaFeature, const Vector& tokenList); + + const AtomicString& mediaFeature() const; + CSSValue* value() const; + + bool isValid() const; + + String serialize() const; + + bool operator==(const MediaQueryExpression&) const; + +private: + AtomicString m_mediaFeature; + RefPtr m_value; + bool m_isValid { false }; + mutable String m_serializationCache; +}; + +inline const AtomicString& MediaQueryExpression::mediaFeature() const +{ + return m_mediaFeature; +} + +inline CSSValue* MediaQueryExpression::value() const +{ + return m_value.get(); +} + +inline bool MediaQueryExpression::operator==(const MediaQueryExpression& other) const +{ + return other.m_mediaFeature == m_mediaFeature + && ((!m_value && !other.m_value) || (m_value && other.m_value && *m_value == *other.m_value)); +} + +inline bool MediaQueryExpression::isValid() const +{ + return m_isValid; +} + +} // namespace diff --git a/Source/WebCore/css/MediaQueryList.cpp b/Source/WebCore/css/MediaQueryList.cpp index 4b121d18b..4010c29c7 100644 --- a/Source/WebCore/css/MediaQueryList.cpp +++ b/Source/WebCore/css/MediaQueryList.cpp @@ -27,18 +27,18 @@ namespace WebCore { -PassRefPtr MediaQueryList::create(PassRefPtr vector, PassRefPtr media, bool matches) +inline MediaQueryList::MediaQueryList(MediaQueryMatcher& matcher, Ref&& media, bool matches) + : m_matcher(matcher) + , m_media(WTFMove(media)) + , m_evaluationRound(m_matcher->evaluationRound()) + , m_changeRound(m_evaluationRound - 1) // Any value that is not the same as m_evaluationRound would do. + , m_matches(matches) { - return adoptRef(new MediaQueryList(vector, media, matches)); } -MediaQueryList::MediaQueryList(PassRefPtr vector, PassRefPtr media, bool matches) - : m_matcher(vector) - , m_media(media) - , m_evaluationRound(m_matcher->evaluationRound()) - , m_changeRound(m_evaluationRound - 1) // m_evaluationRound and m_changeRound initial values must be different. - , m_matches(matches) +Ref MediaQueryList::create(MediaQueryMatcher& matcher, Ref&& media, bool matches) { + return adoptRef(*new MediaQueryList(matcher, WTFMove(media), matches)); } MediaQueryList::~MediaQueryList() @@ -50,26 +50,26 @@ String MediaQueryList::media() const return m_media->mediaText(); } -void MediaQueryList::addListener(PassRefPtr listener) +void MediaQueryList::addListener(RefPtr&& listener) { if (!listener) return; - m_matcher->addListener(listener, this); + m_matcher->addListener(listener.releaseNonNull(), *this); } -void MediaQueryList::removeListener(PassRefPtr listener) +void MediaQueryList::removeListener(RefPtr&& listener) { if (!listener) return; - m_matcher->removeListener(listener.get(), this); + m_matcher->removeListener(*listener, *this); } -void MediaQueryList::evaluate(MediaQueryEvaluator* evaluator, bool& notificationNeeded) +void MediaQueryList::evaluate(MediaQueryEvaluator& evaluator, bool& notificationNeeded) { - if (m_evaluationRound != m_matcher->evaluationRound() && evaluator) - setMatches(evaluator->eval(m_media.get())); + if (m_evaluationRound != m_matcher->evaluationRound()) + setMatches(evaluator.evaluate(m_media.get())); notificationNeeded = m_changeRound == m_matcher->evaluationRound(); } diff --git a/Source/WebCore/css/MediaQueryList.h b/Source/WebCore/css/MediaQueryList.h index 5601ec787..a2f061825 100644 --- a/Source/WebCore/css/MediaQueryList.h +++ b/Source/WebCore/css/MediaQueryList.h @@ -17,8 +17,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef MediaQueryList_h -#define MediaQueryList_h +#pragma once #include #include @@ -36,30 +35,29 @@ class MediaQuerySet; // retrieve the current value of the given media query and to add/remove listeners that // will be called whenever the value of the query changes. -class MediaQueryList : public RefCounted { +class MediaQueryList final : public RefCounted { public: - static PassRefPtr create(PassRefPtr, PassRefPtr, bool); + static Ref create(MediaQueryMatcher&, Ref&&, bool); ~MediaQueryList(); String media() const; bool matches(); - void addListener(PassRefPtr); - void removeListener(PassRefPtr); + void addListener(RefPtr&&); + void removeListener(RefPtr&&); - void evaluate(MediaQueryEvaluator*, bool& notificationNeeded); + void evaluate(MediaQueryEvaluator&, bool& notificationNeeded); private: - MediaQueryList(PassRefPtr, PassRefPtr, bool matches); + MediaQueryList(MediaQueryMatcher&, Ref&&, bool matches); + void setMatches(bool); - RefPtr m_matcher; - RefPtr m_media; + Ref m_matcher; + Ref m_media; unsigned m_evaluationRound; // Indicates if the query has been evaluated after the last style selector change. unsigned m_changeRound; // Used to know if the query has changed in the last style selector change. bool m_matches; }; } - -#endif // MediaQueryList_h diff --git a/Source/WebCore/css/MediaQueryList.idl b/Source/WebCore/css/MediaQueryList.idl index 4b097064c..3dffdcf5c 100644 --- a/Source/WebCore/css/MediaQueryList.idl +++ b/Source/WebCore/css/MediaQueryList.idl @@ -22,6 +22,8 @@ ] interface MediaQueryList { readonly attribute DOMString media; readonly attribute boolean matches; - void addListener([Default=Undefined] optional MediaQueryListListener listener); - void removeListener([Default=Undefined] optional MediaQueryListListener listener); + + // FIXME: The listener parameter should not be optional. + void addListener(optional MediaQueryListListener? listener = null); + void removeListener(optional MediaQueryListListener? listener = null); }; diff --git a/Source/WebCore/css/MediaQueryListListener.h b/Source/WebCore/css/MediaQueryListListener.h index 737d71c2f..4def1fd6f 100644 --- a/Source/WebCore/css/MediaQueryListListener.h +++ b/Source/WebCore/css/MediaQueryListListener.h @@ -17,8 +17,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef MediaQueryListListener_h -#define MediaQueryListListener_h +#pragma once #include @@ -32,7 +31,7 @@ public: JSMediaQueryListListenerType }; - virtual bool queryChanged(MediaQueryList*) = 0; + virtual bool handleEvent(MediaQueryList*) = 0; virtual bool operator==(const MediaQueryListListener&) const = 0; virtual ~MediaQueryListListener() { } @@ -49,5 +48,3 @@ private: }; } // namespace WebCore - -#endif // MediaQueryListListener_h diff --git a/Source/WebCore/css/MediaQueryListListener.idl b/Source/WebCore/css/MediaQueryListListener.idl index 3f169284a..5b6b02713 100644 --- a/Source/WebCore/css/MediaQueryListListener.idl +++ b/Source/WebCore/css/MediaQueryListListener.idl @@ -18,7 +18,6 @@ */ [ - CallbackNeedsOperatorEqual, -] callback interface MediaQueryListListener { - boolean queryChanged([Default=Undefined] optional MediaQueryList list); -}; + CallbackNeedsOperatorEqual +] callback MediaQueryListListener = void (optional MediaQueryList? list = null); + diff --git a/Source/WebCore/css/MediaQueryMatcher.cpp b/Source/WebCore/css/MediaQueryMatcher.cpp index 21849292f..d1a30d37d 100644 --- a/Source/WebCore/css/MediaQueryMatcher.cpp +++ b/Source/WebCore/css/MediaQueryMatcher.cpp @@ -21,42 +21,24 @@ #include "MediaQueryMatcher.h" #include "Document.h" -#include "Element.h" #include "Frame.h" #include "FrameView.h" #include "MediaList.h" #include "MediaQueryEvaluator.h" #include "MediaQueryList.h" #include "MediaQueryListListener.h" +#include "NodeRenderStyle.h" +#include "RenderElement.h" #include "StyleResolver.h" +#include "StyleScope.h" namespace WebCore { -MediaQueryMatcher::Listener::Listener(PassRefPtr listener, PassRefPtr query) - : m_listener(listener) - , m_query(query) +MediaQueryMatcher::MediaQueryMatcher(Document& document) + : m_document(&document) { } -MediaQueryMatcher::Listener::~Listener() -{ -} - -void MediaQueryMatcher::Listener::evaluate(MediaQueryEvaluator* evaluator) -{ - bool notify; - m_query->evaluate(evaluator, notify); - if (notify) - m_listener->queryChanged(m_query.get()); -} - -MediaQueryMatcher::MediaQueryMatcher(Document* document) - : m_document(document) - , m_evaluationRound(1) -{ - ASSERT(m_document); -} - MediaQueryMatcher::~MediaQueryMatcher() { } @@ -64,7 +46,7 @@ MediaQueryMatcher::~MediaQueryMatcher() void MediaQueryMatcher::documentDestroyed() { m_listeners.clear(); - m_document = 0; + m_document = nullptr; } String MediaQueryMatcher::mediaType() const @@ -75,66 +57,55 @@ String MediaQueryMatcher::mediaType() const return m_document->frame()->view()->mediaType(); } -std::unique_ptr MediaQueryMatcher::prepareEvaluator() const +std::unique_ptr MediaQueryMatcher::documentElementUserAgentStyle() const { if (!m_document || !m_document->frame()) return nullptr; - Element* documentElement = m_document->documentElement(); + auto* documentElement = m_document->documentElement(); if (!documentElement) return nullptr; - RefPtr rootStyle = m_document->ensureStyleResolver().styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules); - - return std::make_unique(mediaType(), m_document->frame(), rootStyle.get()); + return m_document->styleScope().resolver().styleForElement(*documentElement, m_document->renderStyle(), nullptr, MatchOnlyUserAgentRules).renderStyle; } -bool MediaQueryMatcher::evaluate(const MediaQuerySet* media) +bool MediaQueryMatcher::evaluate(const MediaQuerySet& media) { - if (!media) + auto style = documentElementUserAgentStyle(); + if (!style) return false; - - std::unique_ptr evaluator = prepareEvaluator(); - return evaluator && evaluator->eval(media); + return MediaQueryEvaluator { mediaType(), *m_document, style.get() }.evaluate(media); } -PassRefPtr MediaQueryMatcher::matchMedia(const String& query) +RefPtr MediaQueryMatcher::matchMedia(const String& query) { if (!m_document) - return 0; - - RefPtr media = MediaQuerySet::create(query); -#if ENABLE(RESOLUTION_MEDIA_QUERY) - // Add warning message to inspector whenever dpi/dpcm values are used for "screen" media. - reportMediaQueryWarningIfNeeded(m_document, media.get()); -#endif - return MediaQueryList::create(this, media, evaluate(media.get())); + return nullptr; + + auto media = MediaQuerySet::create(query); + reportMediaQueryWarningIfNeeded(m_document, media.ptr()); + bool result = evaluate(media.get()); + return MediaQueryList::create(*this, WTFMove(media), result); } -void MediaQueryMatcher::addListener(PassRefPtr listener, PassRefPtr query) +void MediaQueryMatcher::addListener(Ref&& listener, MediaQueryList& query) { if (!m_document) return; - for (size_t i = 0; i < m_listeners.size(); ++i) { - if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) + for (auto& existingListener : m_listeners) { + if (existingListener.listener.get() == listener.get() && existingListener.query.ptr() == &query) return; } - m_listeners.append(std::make_unique(listener, query)); + m_listeners.append(Listener { WTFMove(listener), query }); } -void MediaQueryMatcher::removeListener(MediaQueryListListener* listener, MediaQueryList* query) +void MediaQueryMatcher::removeListener(MediaQueryListListener& listener, MediaQueryList& query) { - if (!m_document) - return; - - for (size_t i = 0; i < m_listeners.size(); ++i) { - if (*m_listeners[i]->listener() == *listener && m_listeners[i]->query() == query) { - m_listeners.remove(i); - return; - } - } + m_listeners.removeFirstMatching([&listener, &query](auto& existingListener) { + return existingListener.listener.get() == listener && existingListener.query.ptr() == &query; + }); } void MediaQueryMatcher::styleResolverChanged() @@ -142,12 +113,22 @@ void MediaQueryMatcher::styleResolverChanged() ASSERT(m_document); ++m_evaluationRound; - std::unique_ptr evaluator = prepareEvaluator(); - if (!evaluator) + + auto style = documentElementUserAgentStyle(); + if (!style) return; - for (size_t i = 0; i < m_listeners.size(); ++i) - m_listeners[i]->evaluate(evaluator.get()); + MediaQueryEvaluator evaluator { mediaType(), *m_document, style.get() }; + Vector listeners; + listeners.reserveInitialCapacity(m_listeners.size()); + for (auto& listener : m_listeners) + listeners.uncheckedAppend({ listener.listener.copyRef(), listener.query.copyRef() }); + for (auto& listener : listeners) { + bool notify; + listener.query->evaluate(evaluator, notify); + if (notify) + listener.listener->handleEvent(listener.query.ptr()); + } } } // namespace WebCore diff --git a/Source/WebCore/css/MediaQueryMatcher.h b/Source/WebCore/css/MediaQueryMatcher.h index 4d549b96a..7510710d9 100644 --- a/Source/WebCore/css/MediaQueryMatcher.h +++ b/Source/WebCore/css/MediaQueryMatcher.h @@ -17,8 +17,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef MediaQueryMatcher_h -#define MediaQueryMatcher_h +#pragma once #include #include @@ -32,56 +31,48 @@ class MediaQueryList; class MediaQueryListListener; class MediaQueryEvaluator; class MediaQuerySet; +class RenderStyle; // MediaQueryMatcher class is responsible for keeping a vector of pairs // MediaQueryList x MediaQueryListListener. It is responsible for evaluating the queries // whenever it is needed and to call the listeners if the corresponding query has changed. -// The listeners must be called in the very same order in which they have been added. +// The listeners must be called in the order in which they were added. -class MediaQueryMatcher : public RefCounted { +class MediaQueryMatcher final : public RefCounted { public: - static PassRefPtr create(Document* document) { return adoptRef(new MediaQueryMatcher(document)); } + static Ref create(Document& document) { return adoptRef(*new MediaQueryMatcher(document)); } ~MediaQueryMatcher(); + void documentDestroyed(); - void addListener(PassRefPtr, PassRefPtr); - void removeListener(MediaQueryListListener*, MediaQueryList*); + void addListener(Ref&&, MediaQueryList&); + void removeListener(MediaQueryListListener&, MediaQueryList&); - PassRefPtr matchMedia(const String&); + RefPtr matchMedia(const String&); unsigned evaluationRound() const { return m_evaluationRound; } - void styleResolverChanged(); - bool evaluate(const MediaQuerySet*); - -private: - class Listener { - public: - Listener(PassRefPtr, PassRefPtr); - ~Listener(); - void evaluate(MediaQueryEvaluator*); + void styleResolverChanged(); - MediaQueryListListener* listener() { return m_listener.get(); } - MediaQueryList* query() { return m_query.get(); } + bool evaluate(const MediaQuerySet&); - private: - RefPtr m_listener; - RefPtr m_query; +private: + struct Listener { + Ref listener; + Ref query; }; - MediaQueryMatcher(Document*); - std::unique_ptr prepareEvaluator() const; + explicit MediaQueryMatcher(Document&); + std::unique_ptr documentElementUserAgentStyle() const; String mediaType() const; Document* m_document; - Vector> m_listeners; + Vector m_listeners; // This value is incremented at style selector changes. // It is used to avoid evaluating queries more then once and to make sure // that a media query result change is notified exactly once. - unsigned m_evaluationRound; + unsigned m_evaluationRound { 1 }; }; } // namespace WebCore - -#endif // MediaQueryMatcher_h diff --git a/Source/WebCore/css/PageRuleCollector.cpp b/Source/WebCore/css/PageRuleCollector.cpp index d7f70403e..b82c88717 100644 --- a/Source/WebCore/css/PageRuleCollector.cpp +++ b/Source/WebCore/css/PageRuleCollector.cpp @@ -37,7 +37,7 @@ namespace WebCore { static inline bool comparePageRules(const StyleRulePage* r1, const StyleRulePage* r2) { - return r1->selector()->specificity() < r2->selector()->specificity(); + return r1->selector()->specificityForPage() < r2->selector()->specificityForPage(); } bool PageRuleCollector::isLeftPage(int pageIndex) const @@ -58,7 +58,7 @@ bool PageRuleCollector::isFirstPage(int pageIndex) const String PageRuleCollector::pageName(int /* pageIndex */) const { // FIXME: Implement page index to page name mapping. - return ""; + return emptyString(); } void PageRuleCollector::matchAllPageRules(int pageIndex) @@ -70,7 +70,8 @@ void PageRuleCollector::matchAllPageRules(int pageIndex) matchPageRules(CSSDefaultStyleSheets::defaultPrintStyle, isLeft, isFirst, page); matchPageRules(m_ruleSets.userStyle(), isLeft, isFirst, page); // Only consider the global author RuleSet for @page rules, as per the HTML5 spec. - matchPageRules(m_ruleSets.authorStyle(), isLeft, isFirst, page); + if (m_ruleSets.isAuthorStyleDefined()) + matchPageRules(&m_ruleSets.authorStyle(), isLeft, isFirst, page); } void PageRuleCollector::matchPageRules(RuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName) @@ -92,18 +93,18 @@ void PageRuleCollector::matchPageRules(RuleSet* rules, bool isLeftPage, bool isF static bool checkPageSelectorComponents(const CSSSelector* selector, bool isLeftPage, bool isFirstPage, const String& pageName) { for (const CSSSelector* component = selector; component; component = component->tagHistory()) { - if (component->m_match == CSSSelector::Tag) { + if (component->match() == CSSSelector::Tag) { const AtomicString& localName = component->tagQName().localName(); if (localName != starAtom && localName != pageName) return false; - } - - CSSSelector::PseudoType pseudoType = component->pseudoType(); - if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage) - || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage) - || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage)) - { - return false; + } else if (component->match() == CSSSelector::PagePseudoClass) { + CSSSelector::PagePseudoClassType pseudoType = component->pagePseudoClassType(); + if ((pseudoType == CSSSelector::PagePseudoClassLeft && !isLeftPage) + || (pseudoType == CSSSelector::PagePseudoClassRight && isLeftPage) + || (pseudoType == CSSSelector::PagePseudoClassFirst && !isFirstPage)) + { + return false; + } } } return true; diff --git a/Source/WebCore/css/PageRuleCollector.h b/Source/WebCore/css/PageRuleCollector.h index 8f5c29a7d..828bc79a2 100644 --- a/Source/WebCore/css/PageRuleCollector.h +++ b/Source/WebCore/css/PageRuleCollector.h @@ -19,12 +19,10 @@ * */ -#ifndef PageRuleCollector_h -#define PageRuleCollector_h +#pragma once #include "DocumentRuleSets.h" #include "StyleResolver.h" -#include #include namespace WebCore { @@ -56,5 +54,3 @@ private: }; } // namespace WebCore - -#endif // PageRuleCollector_h diff --git a/Source/WebCore/css/Pair.h b/Source/WebCore/css/Pair.h index 621187379..2166e2ef1 100644 --- a/Source/WebCore/css/Pair.h +++ b/Source/WebCore/css/Pair.h @@ -1,6 +1,6 @@ /* * (C) 1999-2003 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2015 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,62 +18,56 @@ * Boston, MA 02110-1301, USA. */ -#ifndef Pair_h -#define Pair_h +#pragma once #include -#include "CSSPrimitiveValue.h" -#include -#include namespace WebCore { +class CSSPrimitiveValue; + // A primitive value representing a pair. This is useful for properties like border-radius, background-size/position, // and border-spacing (all of which are space-separated sets of two values). At the moment we are only using it for // border-radius and background-size, but (FIXME) border-spacing and background-position could be converted over to use // it (eliminating some extra -webkit- internal properties). -class Pair : public RefCounted { +class Pair final : public RefCounted { public: - static PassRefPtr create() + enum class IdenticalValueEncoding { + DoNotCoalesce, + Coalesce + }; + + static Ref create(RefPtr&& first, RefPtr&& second) { - return adoptRef(new Pair); + return adoptRef(*new Pair(WTFMove(first), WTFMove(second))); } - static PassRefPtr create(PassRefPtr first, PassRefPtr second) + static Ref create(RefPtr&& first, RefPtr&& second, IdenticalValueEncoding encoding) { - return adoptRef(new Pair(first, second)); + return adoptRef(*new Pair(WTFMove(first), WTFMove(second), encoding)); } virtual ~Pair() { } CSSPrimitiveValue* first() const { return m_first.get(); } CSSPrimitiveValue* second() const { return m_second.get(); } - void setFirst(PassRefPtr first) { m_first = first; } - void setSecond(PassRefPtr second) { m_second = second; } - String cssText() const { - - return generateCSSString(first()->cssText(), second()->cssText()); + String first = this->first()->cssText(); + String second = this->second()->cssText(); + if (m_encoding == IdenticalValueEncoding::Coalesce && first == second) + return first; + return first + ' ' + second; } bool equals(const Pair& other) const { return compareCSSValuePtr(m_first, other.m_first) && compareCSSValuePtr(m_second, other.m_second); } private: - Pair() : m_first(0), m_second(0) { } - Pair(PassRefPtr first, PassRefPtr second) - : m_first(first), m_second(second) { } - - static String generateCSSString(const String& first, const String& second) - { - if (first == second) - return first; - return first + ' ' + second; - } + Pair(RefPtr&& first, RefPtr&& second) : m_first(WTFMove(first)), m_second(WTFMove(second)) { } + Pair(RefPtr&& first, RefPtr&& second, IdenticalValueEncoding encoding) : m_first(WTFMove(first)), m_second(WTFMove(second)), m_encoding(encoding) { } RefPtr m_first; RefPtr m_second; + IdenticalValueEncoding m_encoding { IdenticalValueEncoding::Coalesce }; }; } // namespace - -#endif diff --git a/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp b/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp index 4e97f6915..6e0e1cf0d 100644 --- a/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp +++ b/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp @@ -22,13 +22,17 @@ #include "config.h" #include "PropertySetCSSStyleDeclaration.h" -#include "CSSParser.h" +#include "CSSCustomPropertyValue.h" +#include "CSSPropertyParser.h" +#include "CSSRule.h" #include "CSSStyleSheet.h" +#include "CustomElementReactionQueue.h" #include "HTMLNames.h" #include "InspectorInstrumentation.h" #include "MutationObserverInterestGroup.h" #include "MutationRecord.h" #include "StyleProperties.h" +#include "StyleSheetContents.h" #include "StyledElement.h" namespace WebCore { @@ -50,7 +54,8 @@ public: ASSERT(!s_currentDecl); s_currentDecl = decl; - if (!s_currentDecl->parentElement()) + auto* element = s_currentDecl->parentElement(); + if (!element) return; bool shouldReadOldValue = false; @@ -59,14 +64,16 @@ public: if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested()) shouldReadOldValue = true; - AtomicString oldValue; - if (shouldReadOldValue) - oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr); - - if (m_mutationRecipients) { - AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom; - m_mutation = MutationRecord::createAttributes(*s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue); + if (UNLIKELY(element->isDefinedCustomElement())) { + auto* reactionQueue = element->reactionQueue(); + if (reactionQueue && reactionQueue->observesStyleAttribute()) { + m_customElement = element; + shouldReadOldValue = true; + } } + + if (shouldReadOldValue) + m_oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr); } ~StyleAttributeMutationScope() @@ -75,8 +82,16 @@ public: if (s_scopeCount) return; - if (m_mutation && s_shouldDeliver) - m_mutationRecipients->enqueueMutationRecord(m_mutation); + if (s_shouldDeliver) { + if (m_mutationRecipients) { + auto mutation = MutationRecord::createAttributes(*s_currentDecl->parentElement(), HTMLNames::styleAttr, m_oldValue); + m_mutationRecipients->enqueueMutationRecord(WTFMove(mutation)); + } + if (m_customElement) { + AtomicString newValue = m_customElement->getAttribute(HTMLNames::styleAttr); + CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(*m_customElement, HTMLNames::styleAttr, m_oldValue, newValue); + } + } s_shouldDeliver = false; if (!s_shouldNotifyInspector) { @@ -88,7 +103,7 @@ public: s_currentDecl = 0; s_shouldNotifyInspector = false; if (localCopyStyleDecl->parentElement()) - InspectorInstrumentation::didInvalidateStyleAttr(&localCopyStyleDecl->parentElement()->document(), localCopyStyleDecl->parentElement()); + InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement()->document(), *localCopyStyleDecl->parentElement()); } void enqueueMutationRecord() @@ -107,8 +122,9 @@ private: static bool s_shouldNotifyInspector; static bool s_shouldDeliver; - OwnPtr m_mutationRecipients; - RefPtr m_mutation; + std::unique_ptr m_mutationRecipients; + AtomicString m_oldValue; + RefPtr m_customElement; }; unsigned StyleAttributeMutationScope::s_scopeCount = 0; @@ -136,7 +152,7 @@ unsigned PropertySetCSSStyleDeclaration::length() const String PropertySetCSSStyleDeclaration::item(unsigned i) const { if (i >= m_propertySet->propertyCount()) - return ""; + return String(); return m_propertySet->propertyAt(i).cssName(); } @@ -144,44 +160,56 @@ String PropertySetCSSStyleDeclaration::cssText() const { return m_propertySet->asText(); } - -void PropertySetCSSStyleDeclaration::setCssText(const String& text, ExceptionCode& ec) + +ExceptionOr PropertySetCSSStyleDeclaration::setCssText(const String& text) { StyleAttributeMutationScope mutationScope(this); if (!willMutate()) - return; + return { }; - ec = 0; - // FIXME: Detect syntax errors and set ec. - m_propertySet->parseDeclaration(text, contextStyleSheet()); + bool changed = m_propertySet->parseDeclaration(text, cssParserContext()); - didMutate(PropertyChanged); + didMutate(changed ? PropertyChanged : NoChanges); - mutationScope.enqueueMutationRecord(); + mutationScope.enqueueMutationRecord(); + return { }; } -PassRefPtr PropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName) +RefPtr PropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName) { + if (isCustomPropertyName(propertyName)) { + RefPtr value = m_propertySet->getCustomPropertyCSSValue(propertyName); + if (!value) + return nullptr; + return wrapForDeprecatedCSSOM(value.get()); + } + CSSPropertyID propertyID = cssPropertyID(propertyName); if (!propertyID) - return 0; - return cloneAndCacheForCSSOM(m_propertySet->getPropertyCSSValue(propertyID).get()); + return nullptr; + return wrapForDeprecatedCSSOM(getPropertyCSSValueInternal(propertyID).get()); } -String PropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName) +String PropertySetCSSStyleDeclaration::getPropertyValue(const String& propertyName) { + if (isCustomPropertyName(propertyName)) + return m_propertySet->getCustomPropertyValue(propertyName); + CSSPropertyID propertyID = cssPropertyID(propertyName); if (!propertyID) return String(); - return m_propertySet->getPropertyValue(propertyID); + return getPropertyValueInternal(propertyID); } String PropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName) { + if (isCustomPropertyName(propertyName)) + return m_propertySet->customPropertyIsImportant(propertyName) ? ASCIILiteral("important") : emptyString(); + CSSPropertyID propertyID = cssPropertyID(propertyName); if (!propertyID) return String(); - return m_propertySet->propertyIsImportant(propertyID) ? "important" : ""; + return m_propertySet->propertyIsImportant(propertyID) ? ASCIILiteral("important") : emptyString(); } String PropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName) @@ -200,20 +228,28 @@ bool PropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyNa return m_propertySet->isPropertyImplicit(propertyID); } -void PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode& ec) +ExceptionOr PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority) { StyleAttributeMutationScope mutationScope(this); + CSSPropertyID propertyID = cssPropertyID(propertyName); + if (isCustomPropertyName(propertyName)) + propertyID = CSSPropertyCustom; if (!propertyID) - return; + return { }; if (!willMutate()) - return; + return { }; - bool important = priority.find("important", 0, false) != notFound; + bool important = equalIgnoringASCIICase(priority, "important"); + if (!important && !priority.isEmpty()) + return { }; - ec = 0; - bool changed = m_propertySet->setProperty(propertyID, value, important, contextStyleSheet()); + bool changed; + if (propertyID == CSSPropertyCustom) + changed = m_propertySet->setCustomProperty(propertyName, value, important, cssParserContext()); + else + changed = m_propertySet->setProperty(propertyID, value, important, cssParserContext()); didMutate(changed ? PropertyChanged : NoChanges); @@ -222,67 +258,74 @@ void PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, con // see . mutationScope.enqueueMutationRecord(); } + + return { }; } -String PropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionCode& ec) +ExceptionOr PropertySetCSSStyleDeclaration::removeProperty(const String& propertyName) { StyleAttributeMutationScope mutationScope(this); CSSPropertyID propertyID = cssPropertyID(propertyName); + if (isCustomPropertyName(propertyName)) + propertyID = CSSPropertyCustom; if (!propertyID) return String(); if (!willMutate()) return String(); - ec = 0; String result; - bool changed = m_propertySet->removeProperty(propertyID, &result); + bool changed = propertyID != CSSPropertyCustom ? m_propertySet->removeProperty(propertyID, &result) : m_propertySet->removeCustomProperty(propertyName, &result); didMutate(changed ? PropertyChanged : NoChanges); if (changed) mutationScope.enqueueMutationRecord(); - return result; + return WTFMove(result); } -PassRefPtr PropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID) +RefPtr PropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID) { return m_propertySet->getPropertyCSSValue(propertyID); } String PropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID) -{ - return m_propertySet->getPropertyValue(propertyID); +{ + String value = m_propertySet->getPropertyValue(propertyID); + if (!value.isEmpty()) + return value; + + return String(); } -void PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec) +ExceptionOr PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important) { StyleAttributeMutationScope mutationScope(this); if (!willMutate()) - return; + return false; - ec = 0; - bool changed = m_propertySet->setProperty(propertyID, value, important, contextStyleSheet()); + bool changed = m_propertySet->setProperty(propertyID, value, important, cssParserContext()); didMutate(changed ? PropertyChanged : NoChanges); if (changed) mutationScope.enqueueMutationRecord(); + return changed; } -CSSValue* PropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue) +DeprecatedCSSOMValue* PropertySetCSSStyleDeclaration::wrapForDeprecatedCSSOM(CSSValue* internalValue) { if (!internalValue) return 0; // The map is here to maintain the object identity of the CSSValues over multiple invocations. // FIXME: It is likely that the identity is not important for web compatibility and this code should be removed. - if (!m_cssomCSSValueClones) - m_cssomCSSValueClones = std::make_unique>>(); + if (!m_cssomValueWrappers) + m_cssomValueWrappers = std::make_unique>>(); - RefPtr& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtr()).iterator->value; + RefPtr& clonedValue = m_cssomValueWrappers->add(internalValue, RefPtr()).iterator->value; if (!clonedValue) - clonedValue = internalValue->cloneForCSSOM(); + clonedValue = internalValue->createDeprecatedCSSOMWrapper(); return clonedValue.get(); } @@ -292,7 +335,12 @@ StyleSheetContents* PropertySetCSSStyleDeclaration::contextStyleSheet() const return cssStyleSheet ? &cssStyleSheet->contents() : 0; } -PassRef PropertySetCSSStyleDeclaration::copyProperties() const +CSSParserContext PropertySetCSSStyleDeclaration::cssParserContext() const +{ + return CSSParserContext(m_propertySet->cssParserMode()); +} + +Ref PropertySetCSSStyleDeclaration::copyProperties() const { return m_propertySet->mutableCopy(); } @@ -336,7 +384,7 @@ void StyleRuleCSSStyleDeclaration::didMutate(MutationType type) ASSERT(m_parentRule->parentStyleSheet()); if (type == PropertyChanged) - m_cssomCSSValueClones = nullptr; + m_cssomValueWrappers = nullptr; // Style sheet mutation needs to be signaled even if the change failed. willMutate*/didMutate* must pair. m_parentRule->parentStyleSheet()->didMutateRuleFromCSSStyleDeclaration(); @@ -344,7 +392,16 @@ void StyleRuleCSSStyleDeclaration::didMutate(MutationType type) CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const { - return m_parentRule ? m_parentRule->parentStyleSheet() : 0; + return m_parentRule ? m_parentRule->parentStyleSheet() : nullptr; +} + +CSSParserContext StyleRuleCSSStyleDeclaration::cssParserContext() const +{ + auto* styleSheet = contextStyleSheet(); + if (!styleSheet) + return PropertySetCSSStyleDeclaration::cssParserContext(); + + return styleSheet->parserContext(); } void StyleRuleCSSStyleDeclaration::reattach(MutableStyleProperties& propertySet) @@ -359,19 +416,28 @@ void InlineCSSStyleDeclaration::didMutate(MutationType type) if (type == NoChanges) return; - m_cssomCSSValueClones = nullptr; + m_cssomValueWrappers = nullptr; if (!m_parentElement) return; - m_parentElement->setNeedsStyleRecalc(InlineStyleChange); m_parentElement->invalidateStyleAttribute(); StyleAttributeMutationScope(this).didInvalidateStyleAttr(); } CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const { - return m_parentElement ? &m_parentElement->document().elementSheet() : 0; + return nullptr; +} + +CSSParserContext InlineCSSStyleDeclaration::cssParserContext() const +{ + if (!m_parentElement) + return PropertySetCSSStyleDeclaration::cssParserContext(); + + CSSParserContext context(m_parentElement->document()); + context.mode = m_propertySet->cssParserMode(); + return context; } } // namespace WebCore diff --git a/Source/WebCore/css/PropertySetCSSStyleDeclaration.h b/Source/WebCore/css/PropertySetCSSStyleDeclaration.h index 6741ddddd..564cb1da2 100644 --- a/Source/WebCore/css/PropertySetCSSStyleDeclaration.h +++ b/Source/WebCore/css/PropertySetCSSStyleDeclaration.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,9 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PropertySetCSSStyleDeclaration_h -#define PropertySetCSSStyleDeclaration_h +#pragma once +#include "CSSParserMode.h" #include "CSSStyleDeclaration.h" #include #include @@ -36,6 +36,7 @@ namespace WebCore { class CSSRule; class CSSProperty; class CSSValue; +class DeprecatedCSSOMValue; class MutableStyleProperties; class StyleSheetContents; class StyledElement; @@ -43,93 +44,94 @@ class StyledElement; class PropertySetCSSStyleDeclaration : public CSSStyleDeclaration { public: PropertySetCSSStyleDeclaration(MutableStyleProperties* propertySet) : m_propertySet(propertySet) { } - - virtual StyledElement* parentElement() const { return 0; } + virtual void clearParentElement() { ASSERT_NOT_REACHED(); } + StyleSheetContents* contextStyleSheet() const; - - virtual void ref() override; - virtual void deref() override; + +protected: + enum MutationType { NoChanges, PropertyChanged }; + + virtual CSSParserContext cssParserContext() const; + + MutableStyleProperties* m_propertySet; + std::unique_ptr>> m_cssomValueWrappers; private: - virtual CSSRule* parentRule() const override { return 0; }; - virtual unsigned length() const override; - virtual String item(unsigned index) const override; - virtual PassRefPtr getPropertyCSSValue(const String& propertyName) override; - virtual String getPropertyValue(const String& propertyName) override; - virtual String getPropertyPriority(const String& propertyName) override; - virtual String getPropertyShorthand(const String& propertyName) override; - virtual bool isPropertyImplicit(const String& propertyName) override; - virtual void setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode&) override; - virtual String removeProperty(const String& propertyName, ExceptionCode&) override; - virtual String cssText() const override; - virtual void setCssText(const String&, ExceptionCode&) override; - virtual PassRefPtr getPropertyCSSValueInternal(CSSPropertyID) override; - virtual String getPropertyValueInternal(CSSPropertyID) override; - virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override; + void ref() override; + void deref() override; + + CSSRule* parentRule() const override { return nullptr; } + unsigned length() const final; + String item(unsigned index) const final; + RefPtr getPropertyCSSValue(const String& propertyName) final; + String getPropertyValue(const String& propertyName) final; + String getPropertyPriority(const String& propertyName) final; + String getPropertyShorthand(const String& propertyName) final; + bool isPropertyImplicit(const String& propertyName) final; + ExceptionOr setProperty(const String& propertyName, const String& value, const String& priority) final; + ExceptionOr removeProperty(const String& propertyName) final; + String cssText() const final; + ExceptionOr setCssText(const String&) final; + RefPtr getPropertyCSSValueInternal(CSSPropertyID) final; + String getPropertyValueInternal(CSSPropertyID) final; + ExceptionOr setPropertyInternal(CSSPropertyID, const String& value, bool important) final; - virtual PassRef copyProperties() const override; + Ref copyProperties() const final; - CSSValue* cloneAndCacheForCSSOM(CSSValue*); + DeprecatedCSSOMValue* wrapForDeprecatedCSSOM(CSSValue*); -protected: - enum MutationType { NoChanges, PropertyChanged }; virtual bool willMutate() WARN_UNUSED_RETURN { return true; } virtual void didMutate(MutationType) { } - - MutableStyleProperties* m_propertySet; - std::unique_ptr>> m_cssomCSSValueClones; }; -class StyleRuleCSSStyleDeclaration : public PropertySetCSSStyleDeclaration -{ +class StyleRuleCSSStyleDeclaration final : public PropertySetCSSStyleDeclaration { public: - static PassRefPtr create(MutableStyleProperties& propertySet, CSSRule& parentRule) + static Ref create(MutableStyleProperties& propertySet, CSSRule& parentRule) { - return adoptRef(new StyleRuleCSSStyleDeclaration(propertySet, parentRule)); + return adoptRef(*new StyleRuleCSSStyleDeclaration(propertySet, parentRule)); } virtual ~StyleRuleCSSStyleDeclaration(); - void clearParentRule() { m_parentRule = 0; } + void clearParentRule() { m_parentRule = nullptr; } - virtual void ref() override; - virtual void deref() override; + void ref() final; + void deref() final; void reattach(MutableStyleProperties&); private: StyleRuleCSSStyleDeclaration(MutableStyleProperties&, CSSRule&); - virtual CSSStyleSheet* parentStyleSheet() const override; + CSSStyleSheet* parentStyleSheet() const final; - virtual CSSRule* parentRule() const override { return m_parentRule; } + CSSRule* parentRule() const final { return m_parentRule; } - virtual bool willMutate() override WARN_UNUSED_RETURN; - virtual void didMutate(MutationType) override; + bool willMutate() final WARN_UNUSED_RETURN; + void didMutate(MutationType) final; + CSSParserContext cssParserContext() const final; unsigned m_refCount; CSSRule* m_parentRule; }; -class InlineCSSStyleDeclaration : public PropertySetCSSStyleDeclaration -{ +class InlineCSSStyleDeclaration final : public PropertySetCSSStyleDeclaration { public: InlineCSSStyleDeclaration(MutableStyleProperties* propertySet, StyledElement* parentElement) : PropertySetCSSStyleDeclaration(propertySet) , m_parentElement(parentElement) { } - + private: - virtual CSSStyleSheet* parentStyleSheet() const override; - virtual StyledElement* parentElement() const override { return m_parentElement; } - virtual void clearParentElement() override { m_parentElement = 0; } + CSSStyleSheet* parentStyleSheet() const final; + StyledElement* parentElement() const final { return m_parentElement; } + void clearParentElement() final { m_parentElement = nullptr; } - virtual void didMutate(MutationType) override; + void didMutate(MutationType) final; + CSSParserContext cssParserContext() const final; StyledElement* m_parentElement; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/css/RGBColor.cpp b/Source/WebCore/css/RGBColor.cpp index eeb87c5ad..98aed10c2 100644 --- a/Source/WebCore/css/RGBColor.cpp +++ b/Source/WebCore/css/RGBColor.cpp @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,41 +30,9 @@ namespace WebCore { -PassRefPtr RGBColor::create(unsigned rgbColor) +Ref RGBColor::create(unsigned rgbColor) { - return adoptRef(new RGBColor(rgbColor)); -} - -PassRefPtr RGBColor::red() -{ - unsigned value = (m_rgbColor >> 16) & 0xFF; - RefPtr result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); - result->setCSSOMSafe(); - return result.release(); -} - -PassRefPtr RGBColor::green() -{ - unsigned value = (m_rgbColor >> 8) & 0xFF; - RefPtr result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); - result->setCSSOMSafe(); - return result.release(); -} - -PassRefPtr RGBColor::blue() -{ - unsigned value = m_rgbColor & 0xFF; - RefPtr result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); - result->setCSSOMSafe(); - return result.release(); -} - -PassRefPtr RGBColor::alpha() -{ - float value = static_cast((m_rgbColor >> 24) & 0xFF) / 0xFF; - RefPtr result = CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); - result->setCSSOMSafe(); - return result.release(); + return adoptRef(*new RGBColor(rgbColor)); } } // namespace WebCore diff --git a/Source/WebCore/css/RGBColor.h b/Source/WebCore/css/RGBColor.h index 875eb3715..014c41e03 100644 --- a/Source/WebCore/css/RGBColor.h +++ b/Source/WebCore/css/RGBColor.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,36 +24,30 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RGBColor_h -#define RGBColor_h +#pragma once #include "Color.h" #include namespace WebCore { - class CSSPrimitiveValue; +class CSSPrimitiveValue; - class RGBColor : public RefCounted { - public: - static PassRefPtr create(unsigned rgbColor); +class RGBColor final : public RefCounted { +public: + static Ref create(unsigned rgbColor); - PassRefPtr red(); - PassRefPtr green(); - PassRefPtr blue(); - PassRefPtr alpha(); + Color color() const { return Color(m_rgbColor); } - Color color() const { return Color(m_rgbColor); } + RGBA32 rgbColor() const { return m_rgbColor; } - private: - RGBColor(unsigned rgbColor) - : m_rgbColor(rgbColor) - { - } +private: + RGBColor(unsigned rgbColor) + : m_rgbColor(rgbColor) + { + } - RGBA32 m_rgbColor; - }; + RGBA32 m_rgbColor; +}; } // namespace WebCore - -#endif // RGBColor_h diff --git a/Source/WebCore/css/RGBColor.idl b/Source/WebCore/css/RGBColor.idl deleted file mode 100644 index 16744f425..000000000 --- a/Source/WebCore/css/RGBColor.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -// Introduced in DOM Level 2: -[ - ImplementationLacksVTable -] interface RGBColor { - readonly attribute CSSPrimitiveValue red; - readonly attribute CSSPrimitiveValue green; - readonly attribute CSSPrimitiveValue blue; - - // WebKit extensions -#if !defined(LANGUAGE_JAVASCRIPT) || !LANGUAGE_JAVASCRIPT - readonly attribute CSSPrimitiveValue alpha; -#endif -#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C - readonly attribute Color color; -#endif -}; - diff --git a/Source/WebCore/css/Rect.h b/Source/WebCore/css/Rect.h index ffb20a01e..7f118f6aa 100644 --- a/Source/WebCore/css/Rect.h +++ b/Source/WebCore/css/Rect.h @@ -18,8 +18,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef Rect_h -#define Rect_h +#pragma once #include "CSSPrimitiveValue.h" #include @@ -34,10 +33,10 @@ public: CSSPrimitiveValue* bottom() const { return m_bottom.get(); } CSSPrimitiveValue* left() const { return m_left.get(); } - void setTop(PassRefPtr top) { m_top = top; } - void setRight(PassRefPtr right) { m_right = right; } - void setBottom(PassRefPtr bottom) { m_bottom = bottom; } - void setLeft(PassRefPtr left) { m_left = left; } + void setTop(RefPtr&& top) { m_top = WTFMove(top); } + void setRight(RefPtr&& right) { m_right = WTFMove(right); } + void setBottom(RefPtr&& bottom) { m_bottom = WTFMove(bottom); } + void setLeft(RefPtr&& left) { m_left = WTFMove(left); } bool equals(const RectBase& other) const { @@ -49,14 +48,6 @@ public: protected: RectBase() { } - RectBase(const RectBase& cloneFrom) - : m_top(cloneFrom.m_top ? cloneFrom.m_top->cloneForCSSOM() : 0) - , m_right(cloneFrom.m_right ? cloneFrom.m_right->cloneForCSSOM() : 0) - , m_bottom(cloneFrom.m_bottom ? cloneFrom.m_bottom->cloneForCSSOM() : 0) - , m_left(cloneFrom.m_left ? cloneFrom.m_left->cloneForCSSOM() : 0) - { - } - ~RectBase() { } private: @@ -66,11 +57,9 @@ private: RefPtr m_left; }; -class Rect : public RectBase, public RefCounted { +class Rect final : public RectBase, public RefCounted { public: - static PassRefPtr create() { return adoptRef(new Rect); } - - PassRefPtr cloneForCSSOM() const { return adoptRef(new Rect(*this)); } + static Ref create() { return adoptRef(*new Rect); } String cssText() const { @@ -79,18 +68,15 @@ public: private: Rect() { } - Rect(const Rect& cloneFrom) : RectBase(cloneFrom), RefCounted() { } static String generateCSSString(const String& top, const String& right, const String& bottom, const String& left) { - return "rect(" + top + ' ' + right + ' ' + bottom + ' ' + left + ')'; + return "rect(" + top + ", " + right + ", " + bottom + ", " + left + ')'; } }; -class Quad : public RectBase, public RefCounted { +class Quad final : public RectBase, public RefCounted { public: - static PassRefPtr create() { return adoptRef(new Quad); } - - PassRefPtr cloneForCSSOM() const { return adoptRef(new Quad(*this)); } + static Ref create() { return adoptRef(*new Quad); } String cssText() const { @@ -99,7 +85,6 @@ public: private: Quad() { } - Quad(const Quad& cloneFrom) : RectBase(cloneFrom), RefCounted() { } static String generateCSSString(const String& top, const String& right, const String& bottom, const String& left) { StringBuilder result; @@ -123,5 +108,3 @@ private: }; } // namespace WebCore - -#endif // Rect_h diff --git a/Source/WebCore/css/Rect.idl b/Source/WebCore/css/Rect.idl deleted file mode 100644 index 5013285ed..000000000 --- a/Source/WebCore/css/Rect.idl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -[ - ImplementationLacksVTable -] interface Rect { - readonly attribute CSSPrimitiveValue top; - readonly attribute CSSPrimitiveValue right; - readonly attribute CSSPrimitiveValue bottom; - readonly attribute CSSPrimitiveValue left; -}; - diff --git a/Source/WebCore/css/RuleFeature.cpp b/Source/WebCore/css/RuleFeature.cpp index 93a8ec8f2..133de4866 100644 --- a/Source/WebCore/css/RuleFeature.cpp +++ b/Source/WebCore/css/RuleFeature.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) - * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2005-2012, 2014 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov * Copyright (C) 2007, 2008 Eric Seidel * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) @@ -30,56 +30,144 @@ #include "RuleFeature.h" #include "CSSSelector.h" +#include "CSSSelectorList.h" +#include "RuleSet.h" namespace WebCore { -void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector* selector) +void RuleFeatureSet::recursivelyCollectFeaturesFromSelector(SelectorFeatures& selectorFeatures, const CSSSelector& firstSelector, bool matchesAncestor) { - if (selector->m_match == CSSSelector::Id) - idsInRules.add(selector->value().impl()); - else if (selector->m_match == CSSSelector::Class) - classesInRules.add(selector->value().impl()); - else if (selector->isAttributeSelector()) - attrsInRules.add(selector->attribute().localName().impl()); - switch (selector->pseudoType()) { - case CSSSelector::PseudoFirstLine: - usesFirstLineRules = true; - break; - case CSSSelector::PseudoBefore: - case CSSSelector::PseudoAfter: - usesBeforeAfterRules = true; - break; - default: - break; + const CSSSelector* selector = &firstSelector; + do { + if (selector->match() == CSSSelector::Id) { + idsInRules.add(selector->value()); + if (matchesAncestor) + idsMatchingAncestorsInRules.add(selector->value()); + } else if (selector->match() == CSSSelector::Class) { + classesInRules.add(selector->value()); + if (matchesAncestor) + selectorFeatures.classesMatchingAncestors.append(selector->value()); + } else if (selector->isAttributeSelector()) { + auto& canonicalLocalName = selector->attributeCanonicalLocalName(); + auto& localName = selector->attribute().localName(); + attributeCanonicalLocalNamesInRules.add(canonicalLocalName); + attributeLocalNamesInRules.add(localName); + if (matchesAncestor) + selectorFeatures.attributeSelectorsMatchingAncestors.append(selector); + } else if (selector->match() == CSSSelector::PseudoElement) { + switch (selector->pseudoElementType()) { + case CSSSelector::PseudoElementFirstLine: + usesFirstLineRules = true; + break; + case CSSSelector::PseudoElementFirstLetter: + usesFirstLetterRules = true; + break; + default: + break; + } + } + + if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector()) + selectorFeatures.hasSiblingSelector = true; + + if (const CSSSelectorList* selectorList = selector->selectorList()) { + for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector()) + selectorFeatures.hasSiblingSelector = true; + recursivelyCollectFeaturesFromSelector(selectorFeatures, *subSelector, matchesAncestor); + } + } + if (selector->hasDescendantOrChildRelation()) + matchesAncestor = true; + + selector = selector->tagHistory(); + } while (selector); +} + +static RuleFeatureSet::AttributeRules::SelectorKey makeAttributeSelectorKey(const CSSSelector& selector) +{ + bool caseInsensitive = selector.attributeValueMatchingIsCaseInsensitive(); + unsigned matchAndCase = static_cast(selector.match()) << 1 | (caseInsensitive ? 1 : 0); + return std::make_pair(selector.attributeCanonicalLocalName().impl(), std::make_pair(selector.value().impl(), matchAndCase)); +} + +void RuleFeatureSet::collectFeatures(const RuleData& ruleData) +{ + SelectorFeatures selectorFeatures; + recursivelyCollectFeaturesFromSelector(selectorFeatures, *ruleData.selector()); + if (selectorFeatures.hasSiblingSelector) + siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); + if (ruleData.containsUncommonAttributeSelector()) + uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); + for (auto& className : selectorFeatures.classesMatchingAncestors) { + auto addResult = ancestorClassRules.ensure(className, [] { + return std::make_unique>(); + }); + addResult.iterator->value->append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); + } + for (auto* selector : selectorFeatures.attributeSelectorsMatchingAncestors) { + // Hashing by attributeCanonicalLocalName makes this HTML specific. + auto addResult = ancestorAttributeRulesForHTML.ensure(selector->attributeCanonicalLocalName(), [] { + return std::make_unique(); + }); + auto& rules = *addResult.iterator->value; + rules.features.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); + // Deduplicate selectors. + rules.selectors.add(makeAttributeSelectorKey(*selector), selector); } } void RuleFeatureSet::add(const RuleFeatureSet& other) { - HashSet::const_iterator end = other.idsInRules.end(); - for (HashSet::const_iterator it = other.idsInRules.begin(); it != end; ++it) - idsInRules.add(*it); - end = other.classesInRules.end(); - for (HashSet::const_iterator it = other.classesInRules.begin(); it != end; ++it) - classesInRules.add(*it); - end = other.attrsInRules.end(); - for (HashSet::const_iterator it = other.attrsInRules.begin(); it != end; ++it) - attrsInRules.add(*it); + idsInRules.add(other.idsInRules.begin(), other.idsInRules.end()); + idsMatchingAncestorsInRules.add(other.idsMatchingAncestorsInRules.begin(), other.idsMatchingAncestorsInRules.end()); + classesInRules.add(other.classesInRules.begin(), other.classesInRules.end()); + attributeCanonicalLocalNamesInRules.add(other.attributeCanonicalLocalNamesInRules.begin(), other.attributeCanonicalLocalNamesInRules.end()); + attributeLocalNamesInRules.add(other.attributeLocalNamesInRules.begin(), other.attributeLocalNamesInRules.end()); siblingRules.appendVector(other.siblingRules); uncommonAttributeRules.appendVector(other.uncommonAttributeRules); + for (auto& keyValuePair : other.ancestorClassRules) { + auto addResult = ancestorClassRules.ensure(keyValuePair.key, [] { + return std::make_unique>(); + }); + addResult.iterator->value->appendVector(*keyValuePair.value); + } + for (auto& keyValuePair : other.ancestorAttributeRulesForHTML) { + auto addResult = ancestorAttributeRulesForHTML.ensure(keyValuePair.key, [] { + return std::make_unique(); + }); + auto& rules = *addResult.iterator->value; + rules.features.appendVector(keyValuePair.value->features); + for (auto& selectorPair : keyValuePair.value->selectors) + rules.selectors.add(selectorPair.key, selectorPair.value); + } usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules; - usesBeforeAfterRules = usesBeforeAfterRules || other.usesBeforeAfterRules; + usesFirstLetterRules = usesFirstLetterRules || other.usesFirstLetterRules; } void RuleFeatureSet::clear() { idsInRules.clear(); + idsMatchingAncestorsInRules.clear(); classesInRules.clear(); - attrsInRules.clear(); + attributeCanonicalLocalNamesInRules.clear(); + attributeLocalNamesInRules.clear(); siblingRules.clear(); uncommonAttributeRules.clear(); + ancestorClassRules.clear(); + ancestorAttributeRulesForHTML.clear(); usesFirstLineRules = false; - usesBeforeAfterRules = false; + usesFirstLetterRules = false; +} + +void RuleFeatureSet::shrinkToFit() +{ + siblingRules.shrinkToFit(); + uncommonAttributeRules.shrinkToFit(); + for (auto& rules : ancestorClassRules.values()) + rules->shrinkToFit(); + for (auto& rules : ancestorAttributeRulesForHTML.values()) + rules->features.shrinkToFit(); } } // namespace WebCore diff --git a/Source/WebCore/css/RuleFeature.h b/Source/WebCore/css/RuleFeature.h index 58122e027..d240a850a 100644 --- a/Source/WebCore/css/RuleFeature.h +++ b/Source/WebCore/css/RuleFeature.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2003-2011, 2014 Apple 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 @@ -19,18 +19,19 @@ * */ -#ifndef RuleFeature_h -#define RuleFeature_h +#pragma once +#include "CSSSelector.h" #include #include #include #include +#include namespace WebCore { +class RuleData; class StyleRule; -class CSSSelector; struct RuleFeature { RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin) @@ -45,25 +46,38 @@ struct RuleFeature { }; struct RuleFeatureSet { - RuleFeatureSet() - : usesFirstLineRules(false) - , usesBeforeAfterRules(false) - { } - void add(const RuleFeatureSet&); void clear(); + void shrinkToFit(); + void collectFeatures(const RuleData&); - void collectFeaturesFromSelector(const CSSSelector*); - - HashSet idsInRules; - HashSet classesInRules; - HashSet attrsInRules; + HashSet idsInRules; + HashSet idsMatchingAncestorsInRules; + HashSet classesInRules; + HashSet attributeCanonicalLocalNamesInRules; + HashSet attributeLocalNamesInRules; Vector siblingRules; Vector uncommonAttributeRules; - bool usesFirstLineRules; - bool usesBeforeAfterRules; + HashMap>> ancestorClassRules; + + struct AttributeRules { + WTF_MAKE_FAST_ALLOCATED; + public: + using SelectorKey = std::pair>; + HashMap selectors; + Vector features; + }; + HashMap> ancestorAttributeRulesForHTML; + bool usesFirstLineRules { false }; + bool usesFirstLetterRules { false }; + +private: + struct SelectorFeatures { + bool hasSiblingSelector { false }; + Vector classesMatchingAncestors; + Vector attributeSelectorsMatchingAncestors; + }; + void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, bool matchesAncestor = false); }; } // namespace WebCore - -#endif // RuleFeature_h diff --git a/Source/WebCore/css/RuleSet.cpp b/Source/WebCore/css/RuleSet.cpp index c2752d9d1..9e6b7e93f 100644 --- a/Source/WebCore/css/RuleSet.cpp +++ b/Source/WebCore/css/RuleSet.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) - * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2005-2014 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov * Copyright (C) 2007, 2008 Eric Seidel * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) @@ -30,19 +30,19 @@ #include "RuleSet.h" #include "CSSFontSelector.h" +#include "CSSKeyframesRule.h" #include "CSSSelector.h" #include "CSSSelectorList.h" #include "HTMLNames.h" #include "MediaQueryEvaluator.h" #include "SecurityOrigin.h" #include "SelectorChecker.h" -#include "SelectorCheckerFastPath.h" #include "SelectorFilter.h" #include "StyleResolver.h" #include "StyleRule.h" #include "StyleRuleImport.h" #include "StyleSheetContents.h" -#include "WebKitCSSKeyframesRule.h" +#include "ViewportStyleResolver.h" #if ENABLE(VIDEO_TRACK) #include "TextTrackCue.h" @@ -54,33 +54,46 @@ using namespace HTMLNames; // ----------------------------------------------------------------- -static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector* selector) +static inline MatchBasedOnRuleHash computeMatchBasedOnRuleHash(const CSSSelector& selector) { - ASSERT(selector); - if (selector->m_match == CSSSelector::Tag) { - const AtomicString& selectorNamespace = selector->tagQName().namespaceURI(); - if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI) - return false; - if (selector->relation() == CSSSelector::SubSelector) - return isSelectorMatchingHTMLBasedOnRuleHash(selector->tagHistory()); - return true; + if (selector.tagHistory()) + return MatchBasedOnRuleHash::None; + + if (selector.match() == CSSSelector::Tag) { + const QualifiedName& tagQualifiedName = selector.tagQName(); + const AtomicString& selectorNamespace = tagQualifiedName.namespaceURI(); + if (selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI) { + if (tagQualifiedName == anyQName()) + return MatchBasedOnRuleHash::Universal; + return MatchBasedOnRuleHash::ClassC; + } + return MatchBasedOnRuleHash::None; } - if (SelectorChecker::isCommonPseudoClassSelector(selector)) - return true; - return selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class; + if (SelectorChecker::isCommonPseudoClassSelector(&selector)) + return MatchBasedOnRuleHash::ClassB; + if (selector.match() == CSSSelector::Id) + return MatchBasedOnRuleHash::ClassA; + if (selector.match() == CSSSelector::Class) + return MatchBasedOnRuleHash::ClassB; + return MatchBasedOnRuleHash::None; } -static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector) +static bool selectorCanMatchPseudoElement(const CSSSelector& rootSelector) { - const CSSSelectorList* selectorList = selector->selectorList(); - if (!selectorList) - return false; - for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(selector)) { - for (const CSSSelector* component = selector; component; component = component->tagHistory()) { - if (component->isAttributeSelector()) - return true; + const CSSSelector* selector = &rootSelector; + do { + if (selector->matchesPseudoElement()) + return true; + + if (const CSSSelectorList* selectorList = selector->selectorList()) { + for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (selectorCanMatchPseudoElement(*subSelector)) + return true; + } } - } + + selector = selector->tagHistory(); + } while (selector); return false; } @@ -90,36 +103,45 @@ static inline bool isCommonAttributeSelectorAttribute(const QualifiedName& attri return attribute == typeAttr || attribute == readonlyAttr; } -static inline bool containsUncommonAttributeSelector(const CSSSelector* selector) +static bool containsUncommonAttributeSelector(const CSSSelector& rootSelector, bool matchesRightmostElement) { - for (; selector; selector = selector->tagHistory()) { - // Allow certain common attributes (used in the default style) in the selectors that match the current element. - if (selector->isAttributeSelector() && !isCommonAttributeSelectorAttribute(selector->attribute())) - return true; - if (selectorListContainsUncommonAttributeSelector(selector)) - return true; - if (selector->relation() != CSSSelector::SubSelector) { - selector = selector->tagHistory(); - break; + const CSSSelector* selector = &rootSelector; + do { + if (selector->isAttributeSelector()) { + // FIXME: considering non-rightmost simple selectors is necessary because of the style sharing of cousins. + // It is a primitive solution which disable a lot of style sharing on pages that rely on attributes for styling. + // We should investigate better ways of doing this. + if (!isCommonAttributeSelectorAttribute(selector->attribute()) || !matchesRightmostElement) + return true; } - } - for (; selector; selector = selector->tagHistory()) { - if (selector->isAttributeSelector()) - return true; - if (selectorListContainsUncommonAttributeSelector(selector)) - return true; - } + if (const CSSSelectorList* selectorList = selector->selectorList()) { + for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { + if (containsUncommonAttributeSelector(*subSelector, matchesRightmostElement)) + return true; + } + } + + if (selector->relation() != CSSSelector::Subselector) + matchesRightmostElement = false; + + selector = selector->tagHistory(); + } while (selector); return false; } +static inline bool containsUncommonAttributeSelector(const CSSSelector& rootSelector) +{ + return containsUncommonAttributeSelector(rootSelector, true); +} + static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRuleFlags addRuleFlags, const CSSSelector* selector) { if (addRuleFlags & RuleIsInRegionRule) return PropertyWhitelistRegion; #if ENABLE(VIDEO_TRACK) for (const CSSSelector* component = selector; component; component = component->tagHistory()) { - if (component->pseudoType() == CSSSelector::PseudoCue || (component->m_match == CSSSelector::PseudoElement && component->value() == TextTrackCue::cueShadowPseudoId())) + if (component->match() == CSSSelector::PseudoElement && (component->pseudoElementType() == CSSSelector::PseudoElementCue || component->value() == TextTrackCue::cueShadowPseudoId())) return PropertyWhitelistCue; } #else @@ -131,114 +153,195 @@ static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRule RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, AddRuleFlags addRuleFlags) : m_rule(rule) , m_selectorIndex(selectorIndex) + , m_hasDocumentSecurityOrigin(addRuleFlags & RuleHasDocumentSecurityOrigin) , m_position(position) - , m_hasFastCheckableSelector((addRuleFlags & RuleCanUseFastCheckSelector) && SelectorCheckerFastPath::canUse(selector())) - , m_specificity(selector()->specificity()) - , m_hasMultipartSelector(!!selector()->tagHistory()) - , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector())) - , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector())) + , m_matchBasedOnRuleHash(static_cast(computeMatchBasedOnRuleHash(*selector()))) + , m_canMatchPseudoElement(selectorCanMatchPseudoElement(*selector())) + , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(*selector())) , m_linkMatchType(SelectorChecker::determineLinkMatchType(selector())) - , m_hasDocumentSecurityOrigin(addRuleFlags & RuleHasDocumentSecurityOrigin) , m_propertyWhitelistType(determinePropertyWhitelistType(addRuleFlags, selector())) +#if ENABLE(CSS_SELECTOR_JIT) && CSS_SELECTOR_JIT_PROFILING + , m_compiledSelectorUseCount(0) +#endif { ASSERT(m_position == position); ASSERT(m_selectorIndex == selectorIndex); SelectorFilter::collectIdentifierHashes(selector(), m_descendantSelectorIdentifierHashes, maximumIdentifierCount); } -static void collectFeaturesFromRuleData(RuleFeatureSet& features, const RuleData& ruleData) +RuleSet::RuleSet() { - bool foundSiblingSelector = false; - for (const CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) { - features.collectFeaturesFromSelector(selector); - - if (const CSSSelectorList* selectorList = selector->selectorList()) { - for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { - if (!foundSiblingSelector && selector->isSiblingSelector()) - foundSiblingSelector = true; - features.collectFeaturesFromSelector(subSelector); - } - } else if (!foundSiblingSelector && selector->isSiblingSelector()) - foundSiblingSelector = true; - } - if (foundSiblingSelector) - features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); - if (ruleData.containsUncommonAttributeSelector()) - features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); } - -void RuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, const RuleData& ruleData) + +RuleSet::~RuleSet() +{ +} + +void RuleSet::addToRuleSet(const AtomicString& key, AtomRuleMap& map, const RuleData& ruleData) { - if (!key) + if (key.isNull()) return; - OwnPtr>& rules = map.add(key, nullptr).iterator->value; + auto& rules = map.add(key, nullptr).iterator->value; if (!rules) - rules = adoptPtr(new Vector); + rules = std::make_unique(); rules->append(ruleData); } -bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& ruleData) +static unsigned rulesCountForName(const RuleSet::AtomRuleMap& map, const AtomicString& name) { - if (component->m_match == CSSSelector::Id) { - addToRuleSet(component->value().impl(), m_idRules, ruleData); - return true; - } - if (component->m_match == CSSSelector::Class) { - addToRuleSet(component->value().impl(), m_classRules, ruleData); - return true; - } - if (component->isCustomPseudoElement()) { - addToRuleSet(component->value().impl(), m_shadowPseudoElementRules, ruleData); - return true; - } + if (const auto* rules = map.get(name)) + return rules->size(); + return 0; +} + +void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags) +{ + RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags); + m_features.collectFeatures(ruleData); + + unsigned classBucketSize = 0; + const CSSSelector* idSelector = nullptr; + const CSSSelector* tagSelector = nullptr; + const CSSSelector* classSelector = nullptr; + const CSSSelector* linkSelector = nullptr; + const CSSSelector* focusSelector = nullptr; + const CSSSelector* hostPseudoClassSelector = nullptr; + const CSSSelector* customPseudoElementSelector = nullptr; + const CSSSelector* slottedPseudoElementSelector = nullptr; +#if ENABLE(VIDEO_TRACK) + const CSSSelector* cuePseudoElementSelector = nullptr; +#endif + const CSSSelector* selector = ruleData.selector(); + do { + switch (selector->match()) { + case CSSSelector::Id: + idSelector = selector; + break; + case CSSSelector::Class: { + auto& className = selector->value(); + if (!classSelector) { + classSelector = selector; + classBucketSize = rulesCountForName(m_classRules, className); + } else if (classBucketSize) { + unsigned newClassBucketSize = rulesCountForName(m_classRules, className); + if (newClassBucketSize < classBucketSize) { + classSelector = selector; + classBucketSize = newClassBucketSize; + } + } + break; + } + case CSSSelector::Tag: + if (selector->tagQName().localName() != starAtom) + tagSelector = selector; + break; + case CSSSelector::PseudoElement: + switch (selector->pseudoElementType()) { + case CSSSelector::PseudoElementUserAgentCustom: + case CSSSelector::PseudoElementWebKitCustom: + case CSSSelector::PseudoElementWebKitCustomLegacyPrefixed: + customPseudoElementSelector = selector; + break; + case CSSSelector::PseudoElementSlotted: + slottedPseudoElementSelector = selector; + break; #if ENABLE(VIDEO_TRACK) - if (component->pseudoType() == CSSSelector::PseudoCue) { + case CSSSelector::PseudoElementCue: + cuePseudoElementSelector = selector; + break; +#endif + default: + break; + } + break; + case CSSSelector::PseudoClass: + switch (selector->pseudoClassType()) { + case CSSSelector::PseudoClassLink: + case CSSSelector::PseudoClassVisited: + case CSSSelector::PseudoClassAnyLink: + case CSSSelector::PseudoClassAnyLinkDeprecated: + linkSelector = selector; + break; + case CSSSelector::PseudoClassFocus: + focusSelector = selector; + break; + case CSSSelector::PseudoClassHost: + hostPseudoClassSelector = selector; + break; + default: + break; + } + break; + case CSSSelector::Unknown: + case CSSSelector::Exact: + case CSSSelector::Set: + case CSSSelector::List: + case CSSSelector::Hyphen: + case CSSSelector::Contain: + case CSSSelector::Begin: + case CSSSelector::End: + case CSSSelector::PagePseudoClass: + break; + } + if (selector->relation() != CSSSelector::Subselector) + break; + selector = selector->tagHistory(); + } while (selector); + +#if ENABLE(VIDEO_TRACK) + if (cuePseudoElementSelector) { m_cuePseudoRules.append(ruleData); - return true; + return; } #endif - if (SelectorChecker::isCommonPseudoClassSelector(component)) { - switch (component->pseudoType()) { - case CSSSelector::PseudoLink: - case CSSSelector::PseudoVisited: - case CSSSelector::PseudoAnyLink: - m_linkPseudoClassRules.append(ruleData); - return true; - case CSSSelector::PseudoFocus: - m_focusPseudoClassRules.append(ruleData); - return true; - default: - ASSERT_NOT_REACHED(); - return true; - } + + if (slottedPseudoElementSelector) { + // ::slotted pseudo elements work accross shadow boundary making filtering difficult. + ruleData.disableSelectorFiltering(); + m_slottedPseudoElementRules.append(ruleData); + return; } - if (component->m_match == CSSSelector::Tag) { - // If this is part of a subselector chain, recurse ahead to find a narrower set (ID/class/:pseudo) - if (component->relation() == CSSSelector::SubSelector) { - const CSSSelector* nextComponent = component->tagHistory(); - if (nextComponent->m_match == CSSSelector::Class || nextComponent->m_match == CSSSelector::Id || SelectorChecker::isCommonPseudoClassSelector(nextComponent)) { - if (findBestRuleSetAndAdd(nextComponent, ruleData)) - return true; - } - } - if (component->tagQName().localName() != starAtom) { - addToRuleSet(component->tagQName().localName().impl(), m_tagRules, ruleData); - return true; - } + if (customPseudoElementSelector) { + // FIXME: Custom pseudo elements are handled by the shadow tree's selector filter. It doesn't know about the main DOM. + ruleData.disableSelectorFiltering(); + addToRuleSet(customPseudoElementSelector->value(), m_shadowPseudoElementRules, ruleData); + return; } - return false; -} -void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags) -{ - RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags); - collectFeaturesFromRuleData(m_features, ruleData); + if (hostPseudoClassSelector) { + m_hostPseudoClassRules.append(ruleData); + return; + } + + if (idSelector) { + addToRuleSet(idSelector->value(), m_idRules, ruleData); + return; + } - if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) { - // If we didn't find a specialized map to stick it in, file under universal rules. - m_universalRules.append(ruleData); + if (classSelector) { + addToRuleSet(classSelector->value(), m_classRules, ruleData); + return; } + + if (linkSelector) { + m_linkPseudoClassRules.append(ruleData); + return; + } + + if (focusSelector) { + m_focusPseudoClassRules.append(ruleData); + return; + } + + if (tagSelector) { + addToRuleSet(tagSelector->tagQName().localName(), m_tagLocalNameRules, ruleData); + addToRuleSet(tagSelector->tagLowercaseLocalName(), m_tagLowercaseLocalNameRules, ruleData); + return; + } + + // If we didn't find a specialized map to stick it in, file under universal rules. + m_universalRules.append(ruleData); } void RuleSet::addPageRule(StyleRulePage* rule) @@ -248,7 +351,7 @@ void RuleSet::addPageRule(StyleRulePage* rule) void RuleSet::addRegionRule(StyleRuleRegion* regionRule, bool hasDocumentSecurityOrigin) { - OwnPtr regionRuleSet = RuleSet::create(); + auto regionRuleSet = std::make_unique(); // The region rule set should take into account the position inside the parent rule set. // Otherwise, the rules inside region block might be incorrectly positioned before other similar rules from // the stylesheet that contains the region block. @@ -258,88 +361,63 @@ void RuleSet::addRegionRule(StyleRuleRegion* regionRule, bool hasDocumentSecurit // FIXME: Should this add other types of rules? (i.e. use addChildRules() directly?) const Vector>& childRules = regionRule->childRules(); AddRuleFlags addRuleFlags = hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState; - addRuleFlags = static_cast(addRuleFlags | RuleCanUseFastCheckSelector | RuleIsInRegionRule); - for (unsigned i = 0; i < childRules.size(); ++i) { - StyleRuleBase* regionStylingRule = childRules[i].get(); - if (regionStylingRule->isStyleRule()) - regionRuleSet->addStyleRule(static_cast(regionStylingRule), addRuleFlags); + addRuleFlags = static_cast(addRuleFlags | RuleIsInRegionRule); + for (auto& childRule : childRules) { + if (is(*childRule)) + regionRuleSet->addStyleRule(downcast(childRule.get()), addRuleFlags); } // Update the "global" rule count so that proper order is maintained m_ruleCount = regionRuleSet->m_ruleCount; - m_regionSelectorsAndRuleSets.append(RuleSetSelectorPair(regionRule->selectorList().first(), regionRuleSet.release())); + m_regionSelectorsAndRuleSets.append(RuleSetSelectorPair(regionRule->selectorList().first(), WTFMove(regionRuleSet))); } -void RuleSet::addChildRules(const Vector>& rules, const MediaQueryEvaluator& medium, StyleResolver* resolver, const ContainerNode* scope, bool hasDocumentSecurityOrigin, AddRuleFlags addRuleFlags) +void RuleSet::addChildRules(const Vector>& rules, const MediaQueryEvaluator& medium, StyleResolver* resolver, bool hasDocumentSecurityOrigin, bool isInitiatingElementInUserAgentShadowTree, AddRuleFlags addRuleFlags) { - for (unsigned i = 0; i < rules.size(); ++i) { - StyleRuleBase* rule = rules[i].get(); - - if (rule->isStyleRule()) { - StyleRule* styleRule = static_cast(rule); - addStyleRule(styleRule, addRuleFlags); - } else if (rule->isPageRule()) - addPageRule(static_cast(rule)); - else if (rule->isMediaRule()) { - StyleRuleMedia* mediaRule = static_cast(rule); - if ((!mediaRule->mediaQueries() || medium.eval(mediaRule->mediaQueries(), resolver))) - addChildRules(mediaRule->childRules(), medium, resolver, scope, hasDocumentSecurityOrigin, addRuleFlags); - } else if (rule->isFontFaceRule() && resolver) { + for (auto& rule : rules) { + if (is(*rule)) + addStyleRule(downcast(rule.get()), addRuleFlags); + else if (is(*rule)) + addPageRule(downcast(rule.get())); + else if (is(*rule)) { + auto& mediaRule = downcast(*rule); + if ((!mediaRule.mediaQueries() || medium.evaluate(*mediaRule.mediaQueries(), resolver))) + addChildRules(mediaRule.childRules(), medium, resolver, hasDocumentSecurityOrigin, isInitiatingElementInUserAgentShadowTree, addRuleFlags); + } else if (is(*rule) && resolver) { // Add this font face to our set. - // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment. - if (scope) - continue; - const StyleRuleFontFace* fontFaceRule = static_cast(rule); - resolver->fontSelector()->addFontFaceRule(fontFaceRule); + resolver->document().fontSelector().addFontFaceRule(downcast(*rule.get()), isInitiatingElementInUserAgentShadowTree); resolver->invalidateMatchedPropertiesCache(); - } else if (rule->isKeyframesRule() && resolver) { - // FIXME (BUG 72462): We don't add @keyframe rules of scoped style sheets for the moment. - if (scope) - continue; - resolver->addKeyframeStyle(static_cast(rule)); - } + } else if (is(*rule) && resolver) + resolver->addKeyframeStyle(downcast(*rule)); + else if (is(*rule) && downcast(*rule).conditionIsSupported()) + addChildRules(downcast(*rule).childRules(), medium, resolver, hasDocumentSecurityOrigin, isInitiatingElementInUserAgentShadowTree, addRuleFlags); #if ENABLE(CSS_REGIONS) - else if (rule->isRegionRule() && resolver) { - // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment. - if (scope) - continue; - addRegionRule(static_cast(rule), hasDocumentSecurityOrigin); + else if (is(*rule) && resolver) { + addRegionRule(downcast(rule.get()), hasDocumentSecurityOrigin); } #endif -#if ENABLE(SHADOW_DOM) - else if (rule->isHostRule()) - resolver->addHostRule(static_cast(rule), hasDocumentSecurityOrigin, scope); -#endif #if ENABLE(CSS_DEVICE_ADAPTATION) - else if (rule->isViewportRule() && resolver) { - // @viewport should not be scoped. - if (scope) - continue; - resolver->viewportStyleResolver()->addViewportRule(static_cast(rule)); + else if (is(*rule) && resolver) { + resolver->viewportStyleResolver()->addViewportRule(downcast(rule.get())); } -#endif -#if ENABLE(CSS3_CONDITIONAL_RULES) - else if (rule->isSupportsRule() && static_cast(rule)->conditionIsSupported()) - addChildRules(static_cast(rule)->childRules(), medium, resolver, scope, hasDocumentSecurityOrigin, addRuleFlags); #endif } } -void RuleSet::addRulesFromSheet(StyleSheetContents* sheet, const MediaQueryEvaluator& medium, StyleResolver* resolver, const ContainerNode* scope) +void RuleSet::addRulesFromSheet(StyleSheetContents& sheet, const MediaQueryEvaluator& medium, StyleResolver* resolver) { - ASSERT(sheet); - - const Vector>& importRules = sheet->importRules(); - for (unsigned i = 0; i < importRules.size(); ++i) { - StyleRuleImport* importRule = importRules[i].get(); - if (importRule->styleSheet() && (!importRule->mediaQueries() || medium.eval(importRule->mediaQueries(), resolver))) - addRulesFromSheet(importRule->styleSheet(), medium, resolver, scope); + for (auto& rule : sheet.importRules()) { + if (rule->styleSheet() && (!rule->mediaQueries() || medium.evaluate(*rule->mediaQueries(), resolver))) + addRulesFromSheet(*rule->styleSheet(), medium, resolver); } - bool hasDocumentSecurityOrigin = resolver && resolver->document().securityOrigin()->canRequest(sheet->baseURL()); - AddRuleFlags addRuleFlags = static_cast((hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : 0) | (!scope ? RuleCanUseFastCheckSelector : 0)); + bool hasDocumentSecurityOrigin = resolver && resolver->document().securityOrigin().canRequest(sheet.baseURL()); + AddRuleFlags addRuleFlags = static_cast((hasDocumentSecurityOrigin ? RuleHasDocumentSecurityOrigin : 0)); - addChildRules(sheet->childRules(), medium, resolver, scope, hasDocumentSecurityOrigin, addRuleFlags); + // FIXME: Skip Content Security Policy check when stylesheet is in a user agent shadow tree. + // See . + bool isInitiatingElementInUserAgentShadowTree = false; + addChildRules(sheet.childRules(), medium, resolver, hasDocumentSecurityOrigin, isInitiatingElementInUserAgentShadowTree, addRuleFlags); if (m_autoShrinkToFitEnabled) shrinkToFit(); @@ -351,26 +429,41 @@ void RuleSet::addStyleRule(StyleRule* rule, AddRuleFlags addRuleFlags) addRule(rule, selectorIndex, addRuleFlags); } +bool RuleSet::hasShadowPseudoElementRules() const +{ + if (!m_shadowPseudoElementRules.isEmpty()) + return true; +#if ENABLE(VIDEO_TRACK) + if (!m_cuePseudoRules.isEmpty()) + return true; +#endif + return false; +} + static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map) { - RuleSet::AtomRuleMap::iterator end = map.end(); - for (RuleSet::AtomRuleMap::iterator it = map.begin(); it != end; ++it) - it->value->shrinkToFit(); + for (auto& vector : map.values()) + vector->shrinkToFit(); } void RuleSet::shrinkToFit() { shrinkMapVectorsToFit(m_idRules); shrinkMapVectorsToFit(m_classRules); - shrinkMapVectorsToFit(m_tagRules); + shrinkMapVectorsToFit(m_tagLocalNameRules); + shrinkMapVectorsToFit(m_tagLowercaseLocalNameRules); shrinkMapVectorsToFit(m_shadowPseudoElementRules); m_linkPseudoClassRules.shrinkToFit(); #if ENABLE(VIDEO_TRACK) m_cuePseudoRules.shrinkToFit(); #endif + m_hostPseudoClassRules.shrinkToFit(); + m_slottedPseudoElementRules.shrinkToFit(); m_focusPseudoClassRules.shrinkToFit(); m_universalRules.shrinkToFit(); m_pageRules.shrinkToFit(); + m_features.shrinkToFit(); + m_regionSelectorsAndRuleSets.shrinkToFit(); } } // namespace WebCore diff --git a/Source/WebCore/css/RuleSet.h b/Source/WebCore/css/RuleSet.h index f82be2773..6263cc7f9 100644 --- a/Source/WebCore/css/RuleSet.h +++ b/Source/WebCore/css/RuleSet.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2003-2014 Apple 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 @@ -19,24 +19,23 @@ * */ -#ifndef RuleSet_h -#define RuleSet_h +#pragma once #include "RuleFeature.h" #include "SelectorCompiler.h" #include "StyleRule.h" #include #include -#include #include +#include +#include namespace WebCore { enum AddRuleFlags { RuleHasNoSpecialState = 0, RuleHasDocumentSecurityOrigin = 1, - RuleCanUseFastCheckSelector = 1 << 1, - RuleIsInRegionRule = 1 << 2, + RuleIsInRegionRule = 1 << 1, }; enum PropertyWhitelistType { @@ -50,10 +49,19 @@ enum PropertyWhitelistType { class CSSSelector; class ContainerNode; class MediaQueryEvaluator; +class Node; class StyleResolver; class StyleRuleRegion; class StyleSheetContents; +enum class MatchBasedOnRuleHash : unsigned { + None, + Universal, + ClassA, + ClassB, + ClassC +}; + class RuleData { public: static const unsigned maximumSelectorComponentCount = 8192; @@ -61,22 +69,22 @@ public: RuleData(StyleRule*, unsigned selectorIndex, unsigned position, AddRuleFlags); unsigned position() const { return m_position; } - StyleRule* rule() const { return m_rule; } + StyleRule* rule() const { return m_rule.get(); } const CSSSelector* selector() const { return m_rule->selectorList().selectorAt(m_selectorIndex); } unsigned selectorIndex() const { return m_selectorIndex; } - bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; } - bool hasMultipartSelector() const { return m_hasMultipartSelector; } - bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; } + bool canMatchPseudoElement() const { return m_canMatchPseudoElement; } + MatchBasedOnRuleHash matchBasedOnRuleHash() const { return static_cast(m_matchBasedOnRuleHash); } bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; } - unsigned specificity() const { return m_specificity; } unsigned linkMatchType() const { return m_linkMatchType; } bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; } - PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast(m_propertyWhitelistType); } + PropertyWhitelistType propertyWhitelistType() const { return static_cast(m_propertyWhitelistType); } // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance. static const unsigned maximumIdentifierCount = 4; const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; } + void disableSelectorFiltering() { m_descendantSelectorIdentifierHashes[0] = 0; } + #if ENABLE(CSS_SELECTOR_JIT) SelectorCompilationStatus compilationStatus() const { return m_compilationStatus; } JSC::MacroAssemblerCodeRef compiledSelectorCodeRef() const { return m_compiledSelectorCodeRef; } @@ -85,27 +93,36 @@ public: m_compilationStatus = status; m_compiledSelectorCodeRef = codeRef; } +#if CSS_SELECTOR_JIT_PROFILING + ~RuleData() + { + if (m_compiledSelectorCodeRef.code().executableAddress()) + dataLogF("RuleData compiled selector %d \"%s\"\n", m_compiledSelectorUseCount, selector()->selectorText().utf8().data()); + } + void compiledSelectorUsed() const { m_compiledSelectorUseCount++; } +#endif #endif // ENABLE(CSS_SELECTOR_JIT) private: - StyleRule* m_rule; + RefPtr m_rule; unsigned m_selectorIndex : 13; + unsigned m_hasDocumentSecurityOrigin : 1; // This number was picked fairly arbitrarily. We can probably lower it if we need to. // Some simple testing showed <100,000 RuleData's on large sites. unsigned m_position : 18; - unsigned m_hasFastCheckableSelector : 1; - unsigned m_specificity : 24; - unsigned m_hasMultipartSelector : 1; - unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1; + unsigned m_matchBasedOnRuleHash : 3; + unsigned m_canMatchPseudoElement : 1; unsigned m_containsUncommonAttributeSelector : 1; unsigned m_linkMatchType : 2; // SelectorChecker::LinkMatchMask - unsigned m_hasDocumentSecurityOrigin : 1; unsigned m_propertyWhitelistType : 2; // Use plain array instead of a Vector to minimize memory overhead. unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount]; #if ENABLE(CSS_SELECTOR_JIT) mutable SelectorCompilationStatus m_compilationStatus; mutable JSC::MacroAssemblerCodeRef m_compiledSelectorCodeRef; +#if CSS_SELECTOR_JIT_PROFILING + mutable unsigned m_compiledSelectorUseCount; +#endif #endif // ENABLE(CSS_SELECTOR_JIT) }; @@ -114,6 +131,9 @@ struct SameSizeAsRuleData { unsigned compilationStatus; void* compiledSelectorPointer; void* codeRefPtr; +#if CSS_SELECTOR_JIT_PROFILING + unsigned compiledSelectorUseCount; +#endif #endif // ENABLE(CSS_SELECTOR_JIT) void* a; @@ -128,79 +148,89 @@ class RuleSet { WTF_MAKE_NONCOPYABLE(RuleSet); WTF_MAKE_FAST_ALLOCATED; public: struct RuleSetSelectorPair { - RuleSetSelectorPair(const CSSSelector* selector, PassOwnPtr ruleSet) : selector(selector), ruleSet(ruleSet) { } + RuleSetSelectorPair(const CSSSelector* selector, std::unique_ptr ruleSet) : selector(selector), ruleSet(WTFMove(ruleSet)) { } RuleSetSelectorPair(const RuleSetSelectorPair& pair) : selector(pair.selector), ruleSet(const_cast(&pair)->ruleSet.release()) { } const CSSSelector* selector; - OwnPtr ruleSet; + std::unique_ptr ruleSet; }; - static PassOwnPtr create() { return adoptPtr(new RuleSet); } + RuleSet(); + ~RuleSet(); - typedef HashMap>> AtomRuleMap; + typedef Vector RuleDataVector; + typedef HashMap> AtomRuleMap; - void addRulesFromSheet(StyleSheetContents*, const MediaQueryEvaluator&, StyleResolver* = 0, const ContainerNode* = 0); + void addRulesFromSheet(StyleSheetContents&, const MediaQueryEvaluator&, StyleResolver* = 0); void addStyleRule(StyleRule*, AddRuleFlags); void addRule(StyleRule*, unsigned selectorIndex, AddRuleFlags); void addPageRule(StyleRulePage*); - void addToRuleSet(AtomicStringImpl* key, AtomRuleMap&, const RuleData&); + void addToRuleSet(const AtomicString& key, AtomRuleMap&, const RuleData&); void addRegionRule(StyleRuleRegion*, bool hasDocumentSecurityOrigin); void shrinkToFit(); void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; } const RuleFeatureSet& features() const { return m_features; } - const Vector* idRules(AtomicStringImpl* key) const { return m_idRules.get(key); } - const Vector* classRules(AtomicStringImpl* key) const { return m_classRules.get(key); } - const Vector* tagRules(AtomicStringImpl* key) const { return m_tagRules.get(key); } - const Vector* shadowPseudoElementRules(AtomicStringImpl* key) const { return m_shadowPseudoElementRules.get(key); } - const Vector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; } + const RuleDataVector* idRules(const AtomicString& key) const { return m_idRules.get(key); } + const RuleDataVector* classRules(const AtomicString& key) const { return m_classRules.get(key); } + const RuleDataVector* tagRules(const AtomicString& key, bool isHTMLName) const; + const RuleDataVector* shadowPseudoElementRules(const AtomicString& key) const { return m_shadowPseudoElementRules.get(key); } + const RuleDataVector* linkPseudoClassRules() const { return &m_linkPseudoClassRules; } #if ENABLE(VIDEO_TRACK) - const Vector* cuePseudoRules() const { return &m_cuePseudoRules; } + const RuleDataVector* cuePseudoRules() const { return &m_cuePseudoRules; } #endif - const Vector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; } - const Vector* universalRules() const { return &m_universalRules; } + const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; } + const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; } + const RuleDataVector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; } + const RuleDataVector* universalRules() const { return &m_universalRules; } + const Vector& pageRules() const { return m_pageRules; } const Vector& regionSelectorsAndRuleSets() const { return m_regionSelectorsAndRuleSets; } unsigned ruleCount() const { return m_ruleCount; } -private: - void addChildRules(const Vector>&, const MediaQueryEvaluator& medium, StyleResolver*, const ContainerNode* scope, bool hasDocumentSecurityOrigin, AddRuleFlags); - bool findBestRuleSetAndAdd(const CSSSelector*, RuleData&); + bool hasShadowPseudoElementRules() const; - RuleSet(); +private: + void addChildRules(const Vector>&, const MediaQueryEvaluator& medium, StyleResolver*, bool hasDocumentSecurityOrigin, bool isInitiatingElementInUserAgentShadowTree, AddRuleFlags); AtomRuleMap m_idRules; AtomRuleMap m_classRules; - AtomRuleMap m_tagRules; + AtomRuleMap m_tagLocalNameRules; + AtomRuleMap m_tagLowercaseLocalNameRules; AtomRuleMap m_shadowPseudoElementRules; - Vector m_linkPseudoClassRules; + RuleDataVector m_linkPseudoClassRules; #if ENABLE(VIDEO_TRACK) - Vector m_cuePseudoRules; + RuleDataVector m_cuePseudoRules; #endif - Vector m_focusPseudoClassRules; - Vector m_universalRules; + RuleDataVector m_hostPseudoClassRules; + RuleDataVector m_slottedPseudoElementRules; + RuleDataVector m_focusPseudoClassRules; + RuleDataVector m_universalRules; Vector m_pageRules; - unsigned m_ruleCount; - bool m_autoShrinkToFitEnabled; + unsigned m_ruleCount { 0 }; + bool m_autoShrinkToFitEnabled { true }; RuleFeatureSet m_features; Vector m_regionSelectorsAndRuleSets; }; -inline RuleSet::RuleSet() - : m_ruleCount(0) - , m_autoShrinkToFitEnabled(true) +inline const RuleSet::RuleDataVector* RuleSet::tagRules(const AtomicString& key, bool isHTMLName) const { + const AtomRuleMap* tagRules; + if (isHTMLName) + tagRules = &m_tagLowercaseLocalNameRules; + else + tagRules = &m_tagLocalNameRules; + return tagRules->get(key); } } // namespace WebCore namespace WTF { + // RuleData is simple enough that initializing to 0 and moving with memcpy will totally work. template<> struct VectorTraits : SimpleClassVectorTraits { }; } // namespace WTF - -#endif // RuleSet_h diff --git a/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp b/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp index a204cb96b..8217efb94 100644 --- a/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp +++ b/Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp @@ -19,19 +19,18 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "CSSComputedStyleDeclaration.h" #include "CSSPrimitiveValueMappings.h" #include "CSSPropertyNames.h" +#include "CSSValueList.h" #include "Document.h" +#include "Element.h" #include "RenderStyle.h" -#include "SVGPaint.h" namespace WebCore { -static PassRefPtr glyphOrientationToCSSPrimitiveValue(EGlyphOrientation orientation) +static RefPtr glyphOrientationToCSSPrimitiveValue(EGlyphOrientation orientation) { switch (orientation) { case GO_0DEG: @@ -43,44 +42,55 @@ static PassRefPtr glyphOrientationToCSSPrimitiveValue(EGlyphO case GO_270DEG: return CSSPrimitiveValue::create(270.0f, CSSPrimitiveValue::CSS_DEG); default: - return 0; + return nullptr; } } -static PassRefPtr strokeDashArrayToCSSValueList(const Vector& dashes) +static RefPtr strokeDashArrayToCSSValueList(const Vector& dashes) { if (dashes.isEmpty()) return CSSPrimitiveValue::createIdentifier(CSSValueNone); - RefPtr list = CSSValueList::createCommaSeparated(); - const Vector::const_iterator end = dashes.end(); - for (Vector::const_iterator it = dashes.begin(); it != end; ++it) - list->append(SVGLength::toCSSPrimitiveValue(*it)); + auto list = CSSValueList::createCommaSeparated(); + for (auto& length : dashes) + list->append(SVGLengthValue::toCSSPrimitiveValue(length)); - return list.release(); + return WTFMove(list); } -PassRefPtr ComputedStyleExtractor::adjustSVGPaintForCurrentColor(PassRefPtr newPaint, RenderStyle* style) const +RefPtr ComputedStyleExtractor::adjustSVGPaintForCurrentColor(SVGPaintType paintType, const String& url, const Color& color, const Color& currentColor) const { - RefPtr paint = newPaint; - if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paint->paintType() == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR) - paint->setColor(style->color()); - return paint.release(); + if (paintType >= SVG_PAINTTYPE_URI_NONE) { + RefPtr values = CSSValueList::createSpaceSeparated(); + values->append(CSSPrimitiveValue::create(url, CSSPrimitiveValue::UnitType::CSS_URI)); + if (paintType == SVG_PAINTTYPE_URI_NONE) + values->append(CSSPrimitiveValue::createIdentifier(CSSValueNone)); + else if (paintType == SVG_PAINTTYPE_URI_CURRENTCOLOR) + values->append(CSSPrimitiveValue::create(currentColor)); + else if (paintType == SVG_PAINTTYPE_URI_RGBCOLOR) + values->append(CSSPrimitiveValue::create(color)); + return values; + } + if (paintType == SVG_PAINTTYPE_NONE) + return CSSPrimitiveValue::createIdentifier(CSSValueNone); + if (paintType == SVG_PAINTTYPE_CURRENTCOLOR) + return CSSPrimitiveValue::create(currentColor); + + return CSSPrimitiveValue::create(color); } -PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const +RefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) { - Node* node = m_node.get(); - if (!node) - return 0; + if (!m_element) + return nullptr; // Make sure our layout is up to date before we allow a query on these attributes. if (updateLayout) - node->document().updateLayout(); + m_element->document().updateLayout(); - RenderStyle* style = node->computedStyle(); + auto* style = m_element->computedStyle(); if (!style) - return 0; + return nullptr; const SVGRenderStyle& svgStyle = style->svgStyle(); @@ -103,10 +113,6 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop return CSSPrimitiveValue::create(svgStyle.colorRendering()); case CSSPropertyShapeRendering: return CSSPrimitiveValue::create(svgStyle.shapeRendering()); - case CSSPropertyStrokeLinecap: - return CSSPrimitiveValue::create(svgStyle.capStyle()); - case CSSPropertyStrokeLinejoin: - return CSSPrimitiveValue::create(svgStyle.joinStyle()); case CSSPropertyStrokeMiterlimit: return CSSPrimitiveValue::create(svgStyle.strokeMiterLimit(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyStrokeOpacity: @@ -117,8 +123,6 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop return CSSPrimitiveValue::create(svgStyle.dominantBaseline()); case CSSPropertyTextAnchor: return CSSPrimitiveValue::create(svgStyle.textAnchor()); - case CSSPropertyWritingMode: - return CSSPrimitiveValue::create(svgStyle.writingMode()); case CSSPropertyClipPath: if (!svgStyle.clipperResource().isEmpty()) return CSSPrimitiveValue::create(svgStyle.clipperResource(), CSSPrimitiveValue::CSS_URI); @@ -127,10 +131,6 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop if (!svgStyle.maskerResource().isEmpty()) return CSSPrimitiveValue::create(svgStyle.maskerResource(), CSSPrimitiveValue::CSS_URI); return CSSPrimitiveValue::createIdentifier(CSSValueNone); - case CSSPropertyFilter: - if (!svgStyle.filterResource().isEmpty()) - return CSSPrimitiveValue::create(svgStyle.filterResource(), CSSPrimitiveValue::CSS_URI); - return CSSPrimitiveValue::createIdentifier(CSSValueNone); case CSSPropertyFloodColor: return currentColorOrValidColor(style, svgStyle.floodColor()); case CSSPropertyLightingColor: @@ -138,9 +138,9 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop case CSSPropertyStopColor: return currentColorOrValidColor(style, svgStyle.stopColor()); case CSSPropertyFill: - return adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle.fillPaintType(), svgStyle.fillPaintUri(), svgStyle.fillPaintColor()), style); + return adjustSVGPaintForCurrentColor(svgStyle.fillPaintType(), svgStyle.fillPaintUri(), svgStyle.fillPaintColor(), style->color()); case CSSPropertyKerning: - return SVGLength::toCSSPrimitiveValue(svgStyle.kerning()); + return SVGLengthValue::toCSSPrimitiveValue(svgStyle.kerning()); case CSSPropertyMarkerEnd: if (!svgStyle.markerEndResource().isEmpty()) return CSSPrimitiveValue::create(svgStyle.markerEndResource(), CSSPrimitiveValue::CSS_URI); @@ -154,13 +154,9 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop return CSSPrimitiveValue::create(svgStyle.markerStartResource(), CSSPrimitiveValue::CSS_URI); return CSSPrimitiveValue::createIdentifier(CSSValueNone); case CSSPropertyStroke: - return adjustSVGPaintForCurrentColor(SVGPaint::create(svgStyle.strokePaintType(), svgStyle.strokePaintUri(), svgStyle.strokePaintColor()), style); + return adjustSVGPaintForCurrentColor(svgStyle.strokePaintType(), svgStyle.strokePaintUri(), svgStyle.strokePaintColor(), style->color()); case CSSPropertyStrokeDasharray: return strokeDashArrayToCSSValueList(svgStyle.strokeDashArray()); - case CSSPropertyStrokeDashoffset: - return SVGLength::toCSSPrimitiveValue(svgStyle.strokeDashOffset()); - case CSSPropertyStrokeWidth: - return SVGLength::toCSSPrimitiveValue(svgStyle.strokeWidth()); case CSSPropertyBaselineShift: { switch (svgStyle.baselineShift()) { case BS_BASELINE: @@ -170,10 +166,10 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop case BS_SUB: return CSSPrimitiveValue::createIdentifier(CSSValueSub); case BS_LENGTH: - return SVGLength::toCSSPrimitiveValue(svgStyle.baselineShiftValue()); + return SVGLengthValue::toCSSPrimitiveValue(svgStyle.baselineShiftValue()); } ASSERT_NOT_REACHED(); - return 0; + return nullptr; } case CSSPropertyBufferedRendering: return CSSPrimitiveValue::create(svgStyle.bufferedRendering()); @@ -181,15 +177,15 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop return glyphOrientationToCSSPrimitiveValue(svgStyle.glyphOrientationHorizontal()); case CSSPropertyGlyphOrientationVertical: { if (RefPtr value = glyphOrientationToCSSPrimitiveValue(svgStyle.glyphOrientationVertical())) - return value.release(); + return value; if (svgStyle.glyphOrientationVertical() == GO_AUTO) return CSSPrimitiveValue::createIdentifier(CSSValueAuto); - return 0; + return nullptr; } case CSSPropertyWebkitSvgShadow: - return valueForShadow(svgStyle.shadow(), propertyID, style); + return valueForShadow(svgStyle.shadow(), propertyID, *style); case CSSPropertyVectorEffect: return CSSPrimitiveValue::create(svgStyle.vectorEffect()); case CSSPropertyMaskType: @@ -205,11 +201,7 @@ PassRefPtr ComputedStyleExtractor::svgPropertyValue(CSSPropertyID prop ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propertyID); } LOG_ERROR("unimplemented propertyID: %d", propertyID); - return 0; + return nullptr; } } - -#endif // ENABLE(SVG) - -// vim:ts=4:noet diff --git a/Source/WebCore/css/SVGCSSParser.cpp b/Source/WebCore/css/SVGCSSParser.cpp deleted file mode 100644 index 74f9fb6e3..000000000 --- a/Source/WebCore/css/SVGCSSParser.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/* - Copyright (C) 2008 Eric Seidel - Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann - 2004, 2005, 2007, 2010 Rob Buis - Copyright (C) 2005, 2006 Apple Computer, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" - -#if ENABLE(SVG) -#include "CSSInheritedValue.h" -#include "CSSInitialValue.h" -#include "CSSParser.h" -#include "CSSPropertyNames.h" -#include "CSSValueKeywords.h" -#include "CSSValueList.h" -#include "RenderTheme.h" -#include "SVGPaint.h" - -namespace WebCore { - -bool CSSParser::parseSVGValue(CSSPropertyID propId, bool important) -{ - CSSParserValue* value = m_valueList->current(); - if (!value) - return false; - - CSSValueID id = value->id; - - bool valid_primitive = false; - RefPtr parsedValue; - - switch (propId) { - /* The comment to the right defines all valid value of these - * properties as defined in SVG 1.1, Appendix N. Property index */ - case CSSPropertyAlignmentBaseline: - // auto | baseline | before-edge | text-before-edge | middle | - // central | after-edge | text-after-edge | ideographic | alphabetic | - // hanging | mathematical | inherit - if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle || - (id >= CSSValueBeforeEdge && id <= CSSValueMathematical)) - valid_primitive = true; - break; - - case CSSPropertyBaselineShift: - // baseline | super | sub | | | inherit - if (id == CSSValueBaseline || id == CSSValueSub || - id >= CSSValueSuper) - valid_primitive = true; - else - valid_primitive = validUnit(value, FLength | FPercent, SVGAttributeMode); - break; - - case CSSPropertyDominantBaseline: - // auto | use-script | no-change | reset-size | ideographic | - // alphabetic | hanging | mathematical | central | middle | - // text-after-edge | text-before-edge | inherit - if (id == CSSValueAuto || id == CSSValueMiddle || - (id >= CSSValueUseScript && id <= CSSValueResetSize) || - (id >= CSSValueCentral && id <= CSSValueMathematical)) - valid_primitive = true; - break; - - case CSSPropertyEnableBackground: - // accumulate | new [x] [y] [width] [height] | inherit - if (id == CSSValueAccumulate) // TODO : new - valid_primitive = true; - break; - - case CSSPropertyMarkerStart: - case CSSPropertyMarkerMid: - case CSSPropertyMarkerEnd: - case CSSPropertyMask: - if (id == CSSValueNone) - valid_primitive = true; - else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI); - if (parsedValue) - m_valueList->next(); - } - break; - - case CSSPropertyClipRule: // nonzero | evenodd | inherit - case CSSPropertyFillRule: - if (id == CSSValueNonzero || id == CSSValueEvenodd) - valid_primitive = true; - break; - - case CSSPropertyStrokeMiterlimit: // | inherit - valid_primitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode); - break; - - case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit - if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel) - valid_primitive = true; - break; - - case CSSPropertyStrokeLinecap: // butt | round | square | inherit - if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare) - valid_primitive = true; - break; - - case CSSPropertyStrokeOpacity: // | inherit - case CSSPropertyFillOpacity: - case CSSPropertyStopOpacity: - case CSSPropertyFloodOpacity: - valid_primitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode)); - break; - - case CSSPropertyShapeRendering: - // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit - if (id == CSSValueAuto || id == CSSValueOptimizespeed || - id == CSSValueCrispedges || id == CSSValueGeometricprecision) - valid_primitive = true; - break; - - case CSSPropertyColorRendering: // auto | optimizeSpeed | optimizeQuality | inherit - if (id == CSSValueAuto || id == CSSValueOptimizespeed || - id == CSSValueOptimizequality) - valid_primitive = true; - break; - - case CSSPropertyBufferedRendering: // auto | dynamic | static - if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic) - valid_primitive = true; - break; - - case CSSPropertyColorProfile: // auto | sRGB | | inherit - if (id == CSSValueAuto || id == CSSValueSrgb) - valid_primitive = true; - break; - - case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit - case CSSPropertyColorInterpolationFilters: - if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb) - valid_primitive = true; - break; - - /* Start of supported CSS properties with validation. This is needed for parseShortHand to work - * correctly and allows optimization in applyRule(..) - */ - - case CSSPropertyTextAnchor: // start | middle | end | inherit - if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd) - valid_primitive = true; - break; - - case CSSPropertyGlyphOrientationVertical: // auto | | inherit - if (id == CSSValueAuto) { - valid_primitive = true; - break; - } - FALLTHROUGH; - - case CSSPropertyGlyphOrientationHorizontal: // (restricted to _deg_ per SVG 1.1 spec) | inherit - if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) { - parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG); - - if (parsedValue) - m_valueList->next(); - } - break; - - case CSSPropertyFill: // | inherit - case CSSPropertyStroke: // | inherit - { - if (id == CSSValueNone) - parsedValue = SVGPaint::createNone(); - else if (id == CSSValueCurrentcolor) - parsedValue = SVGPaint::createCurrentColor(); - else if ((id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu) - parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id)); - else if (value->unit == CSSPrimitiveValue::CSS_URI) { - RGBA32 c = Color::transparent; - if (m_valueList->next()) { - if (parseColorFromValue(m_valueList->current(), c)) - parsedValue = SVGPaint::createURIAndColor(value->string, c); - else if (m_valueList->current()->id == CSSValueNone) - parsedValue = SVGPaint::createURIAndNone(value->string); - } - if (!parsedValue) - parsedValue = SVGPaint::createURI(value->string); - } else - parsedValue = parseSVGPaint(); - - if (parsedValue) - m_valueList->next(); - } - break; - - case CSSPropertyStopColor: // TODO : icccolor - case CSSPropertyFloodColor: - case CSSPropertyLightingColor: - if ((id >= CSSValueAqua && id <= CSSValueWindowtext) || - (id >= CSSValueAliceblue && id <= CSSValueYellowgreen)) - parsedValue = SVGColor::createFromString(value->string); - else if (id == CSSValueCurrentcolor) - parsedValue = SVGColor::createCurrentColor(); - else // TODO : svgcolor (iccColor) - parsedValue = parseSVGColor(); - - if (parsedValue) - m_valueList->next(); - - break; - - case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit - if (id == CSSValueNone || id == CSSValueNonScalingStroke) - valid_primitive = true; - break; - - case CSSPropertyWritingMode: - // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit - if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb) - valid_primitive = true; - break; - - case CSSPropertyStrokeWidth: // | inherit - case CSSPropertyStrokeDashoffset: - valid_primitive = validUnit(value, FLength | FPercent, SVGAttributeMode); - break; - case CSSPropertyStrokeDasharray: // none | | inherit - if (id == CSSValueNone) - valid_primitive = true; - else - parsedValue = parseSVGStrokeDasharray(); - - break; - - case CSSPropertyKerning: // auto | normal | | inherit - if (id == CSSValueAuto || id == CSSValueNormal) - valid_primitive = true; - else - valid_primitive = validUnit(value, FLength, SVGAttributeMode); - break; - - case CSSPropertyClipPath: // | none | inherit - case CSSPropertyFilter: - if (id == CSSValueNone) - valid_primitive = true; - else if (value->unit == CSSPrimitiveValue::CSS_URI) { - parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); - if (parsedValue) - m_valueList->next(); - } - break; - case CSSPropertyWebkitSvgShadow: - if (id == CSSValueNone) - valid_primitive = true; - else { - RefPtr shadowValueList = parseShadow(m_valueList.get(), propId); - if (shadowValueList) { - addProperty(propId, shadowValueList.release(), important); - m_valueList->next(); - return true; - } - return false; - } - break; - - case CSSPropertyMaskType: // luminance | alpha | inherit - if (id == CSSValueLuminance || id == CSSValueAlpha) - valid_primitive = true; - break; - - /* shorthand properties */ - case CSSPropertyMarker: - { - ShorthandScope scope(this, propId); - m_implicitShorthand = true; - if (!parseValue(CSSPropertyMarkerStart, important)) - return false; - if (m_valueList->current()) { - rollbackLastProperties(1); - return false; - } - CSSValue* value = m_parsedProperties.last().value(); - addProperty(CSSPropertyMarkerMid, value, important); - addProperty(CSSPropertyMarkerEnd, value, important); - m_implicitShorthand = false; - return true; - } - default: - // If you crash here, it's because you added a css property and are not handling it - // in either this switch statement or the one in CSSParser::parseValue - ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); - return false; - } - - if (valid_primitive) { - if (id != 0) - parsedValue = CSSPrimitiveValue::createIdentifier(id); - else if (value->unit == CSSPrimitiveValue::CSS_STRING) - parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); - else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) - parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); - else if (value->unit >= CSSParserValue::Q_EMS) - parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); - if (isCalculation(value)) { - // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie - // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release()); - m_parsedCalculation.release(); - parsedValue = 0; - } - m_valueList->next(); - } - if (!parsedValue || (m_valueList->current() && !inShorthand())) - return false; - - addProperty(propId, parsedValue.release(), important); - return true; -} - -PassRefPtr CSSParser::parseSVGStrokeDasharray() -{ - RefPtr ret = CSSValueList::createCommaSeparated(); - CSSParserValue* value = m_valueList->current(); - bool valid_primitive = true; - while (value) { - valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode); - if (!valid_primitive) - break; - if (value->id != 0) - ret->append(CSSPrimitiveValue::createIdentifier(value->id)); - else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) - ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit)); - value = m_valueList->next(); - if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') - value = m_valueList->next(); - } - if (!valid_primitive) - return 0; - return ret.release(); -} - -PassRefPtr CSSParser::parseSVGPaint() -{ - RGBA32 c = Color::transparent; - if (!parseColorFromValue(m_valueList->current(), c)) - return SVGPaint::createUnknown(); - return SVGPaint::createColor(Color(c)); -} - -PassRefPtr CSSParser::parseSVGColor() -{ - RGBA32 c = Color::transparent; - if (!parseColorFromValue(m_valueList->current(), c)) - return 0; - return SVGColor::createFromColor(Color(c)); -} - -} - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/css/SVGCSSPropertyNames.in b/Source/WebCore/css/SVGCSSPropertyNames.in deleted file mode 100644 index a34189f70..000000000 --- a/Source/WebCore/css/SVGCSSPropertyNames.in +++ /dev/null @@ -1,58 +0,0 @@ -// -// SVG CSS property names -// - -#if defined(ENABLE_SVG) && ENABLE_SVG - -// SVG style props -buffered-rendering -clip-path -clip-rule [Inherited] -mask -// opacity -enable-background -filter -flood-color -flood-opacity -lighting-color -stop-color -stop-opacity -// pointer-events -color-interpolation [Inherited] -color-interpolation-filters [Inherited] -color-profile -color-rendering [Inherited] -fill [Inherited] -fill-opacity [Inherited] -fill-rule [Inherited] -//font-size-adjust -//image-rendering -marker [Inherited] -marker-end [Inherited] -marker-mid [Inherited] -marker-start [Inherited] -mask-type -shape-rendering [Inherited] -stroke [Inherited] -stroke-dasharray [Inherited] -stroke-dashoffset [Inherited] -stroke-linecap [Inherited] -stroke-linejoin [Inherited] -stroke-miterlimit [Inherited] -stroke-opacity [Inherited] -stroke-width [Inherited] -// text-rendering -alignment-baseline -baseline-shift -dominant-baseline -glyph-orientation-horizontal [Inherited] -glyph-orientation-vertical [Inherited] -kerning [Inherited] -text-anchor [Inherited] -vector-effect -writing-mode [Inherited] - --webkit-svg-shadow - -#endif - diff --git a/Source/WebCore/css/SVGCSSStyleSelector.cpp b/Source/WebCore/css/SVGCSSStyleSelector.cpp deleted file mode 100644 index 4a35ad6ee..000000000 --- a/Source/WebCore/css/SVGCSSStyleSelector.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/* - Copyright (C) 2005 Apple Computer, Inc. - Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann - 2004, 2005, 2008 Rob Buis - Copyright (C) 2007 Alexey Proskuryakov - - Based on khtml css code by: - Copyright(C) 1999-2003 Lars Knoll(knoll@kde.org) - (C) 2003 Apple Computer, Inc. - (C) 2004 Allan Sandfeld Jensen(kde@carewolf.com) - (C) 2004 Germain Garand(germain@ebooksfrance.org) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" - -#if ENABLE(SVG) -#include "StyleResolver.h" - -#include "CSSPrimitiveValueMappings.h" -#include "CSSPropertyNames.h" -#include "CSSShadowValue.h" -#include "CSSValueList.h" -#include "Document.h" -#include "SVGColor.h" -#include "SVGElement.h" -#include "SVGNames.h" -#include "SVGPaint.h" -#include "SVGRenderStyle.h" -#include "SVGRenderStyleDefs.h" -#include "SVGURIReference.h" -#include -#include - -#define HANDLE_INHERIT(prop, Prop) \ -if (isInherit) \ -{ \ - svgStyle.set##Prop(state.parentStyle()->svgStyle().prop()); \ - return; \ -} - -#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ -HANDLE_INHERIT(prop, Prop) \ -if (isInitial) { \ - svgStyle.set##Prop(SVGRenderStyle::initial##Prop()); \ - return; \ -} - -namespace WebCore { - -static float roundToNearestGlyphOrientationAngle(float angle) -{ - angle = fabsf(fmodf(angle, 360.0f)); - - if (angle <= 45.0f || angle > 315.0f) - return 0.0f; - else if (angle > 45.0f && angle <= 135.0f) - return 90.0f; - else if (angle > 135.0f && angle <= 225.0f) - return 180.0f; - - return 270.0f; -} - -static int angleToGlyphOrientation(float angle) -{ - angle = roundToNearestGlyphOrientationAngle(angle); - - if (angle == 0.0f) - return GO_0DEG; - else if (angle == 90.0f) - return GO_90DEG; - else if (angle == 180.0f) - return GO_180DEG; - else if (angle == 270.0f) - return GO_270DEG; - - return -1; -} - -static Color colorFromSVGColorCSSValue(SVGColor* svgColor, const Color& fgColor) -{ - Color color; - if (svgColor->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR) - color = fgColor; - else - color = svgColor->color(); - return color; -} - -void StyleResolver::applySVGProperty(CSSPropertyID id, CSSValue* value) -{ - ASSERT(value); - CSSPrimitiveValue* primitiveValue = 0; - if (value->isPrimitiveValue()) - primitiveValue = toCSSPrimitiveValue(value); - - const State& state = m_state; - SVGRenderStyle& svgStyle = state.style()->accessSVGStyle(); - - bool isInherit = state.parentNode() && value->isInheritedValue(); - bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue()); - - // What follows is a list that maps the CSS properties into their - // corresponding front-end RenderStyle values. Shorthands(e.g. border, - // background) occur in this list as well and are only hit when mapping - // "inherit" or "initial" into front-end values. - switch (id) - { - // ident only properties - case CSSPropertyAlignmentBaseline: - { - HANDLE_INHERIT_AND_INITIAL(alignmentBaseline, AlignmentBaseline) - if (!primitiveValue) - break; - - svgStyle.setAlignmentBaseline(*primitiveValue); - break; - } - case CSSPropertyBaselineShift: - { - HANDLE_INHERIT_AND_INITIAL(baselineShift, BaselineShift); - if (!primitiveValue) - break; - - if (primitiveValue->getValueID()) { - switch (primitiveValue->getValueID()) { - case CSSValueBaseline: - svgStyle.setBaselineShift(BS_BASELINE); - break; - case CSSValueSub: - svgStyle.setBaselineShift(BS_SUB); - break; - case CSSValueSuper: - svgStyle.setBaselineShift(BS_SUPER); - break; - default: - break; - } - } else { - svgStyle.setBaselineShift(BS_LENGTH); - svgStyle.setBaselineShiftValue(SVGLength::fromCSSPrimitiveValue(primitiveValue)); - } - - break; - } - case CSSPropertyKerning: - { - HANDLE_INHERIT_AND_INITIAL(kerning, Kerning); - if (primitiveValue) - svgStyle.setKerning(SVGLength::fromCSSPrimitiveValue(primitiveValue)); - break; - } - case CSSPropertyDominantBaseline: - { - HANDLE_INHERIT_AND_INITIAL(dominantBaseline, DominantBaseline) - if (primitiveValue) - svgStyle.setDominantBaseline(*primitiveValue); - break; - } - case CSSPropertyColorInterpolation: - { - HANDLE_INHERIT_AND_INITIAL(colorInterpolation, ColorInterpolation) - if (primitiveValue) - svgStyle.setColorInterpolation(*primitiveValue); - break; - } - case CSSPropertyColorInterpolationFilters: - { - HANDLE_INHERIT_AND_INITIAL(colorInterpolationFilters, ColorInterpolationFilters) - if (primitiveValue) - svgStyle.setColorInterpolationFilters(*primitiveValue); - break; - } - case CSSPropertyColorProfile: - { - // Not implemented. - break; - } - case CSSPropertyColorRendering: - { - HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering) - if (primitiveValue) - svgStyle.setColorRendering(*primitiveValue); - break; - } - case CSSPropertyClipRule: - { - HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule) - if (primitiveValue) - svgStyle.setClipRule(*primitiveValue); - break; - } - case CSSPropertyFillRule: - { - HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule) - if (primitiveValue) - svgStyle.setFillRule(*primitiveValue); - break; - } - case CSSPropertyStrokeLinejoin: - { - HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle) - if (primitiveValue) - svgStyle.setJoinStyle(*primitiveValue); - break; - } - case CSSPropertyShapeRendering: - { - HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) - if (primitiveValue) - svgStyle.setShapeRendering(*primitiveValue); - break; - } - // end of ident only properties - case CSSPropertyFill: - { - if (isInherit) { - const SVGRenderStyle& svgParentStyle = state.parentStyle()->svgStyle(); - svgStyle.setFillPaint(svgParentStyle.fillPaintType(), svgParentStyle.fillPaintColor(), svgParentStyle.fillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - return; - } - if (isInitial) { - svgStyle.setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - return; - } - if (value->isSVGPaint()) { - SVGPaint* svgPaint = toSVGPaint(value); - svgStyle.setFillPaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, state.style()->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - } - break; - } - case CSSPropertyStroke: - { - if (isInherit) { - const SVGRenderStyle& svgParentStyle = state.parentStyle()->svgStyle(); - svgStyle.setStrokePaint(svgParentStyle.strokePaintType(), svgParentStyle.strokePaintColor(), svgParentStyle.strokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - return; - } - if (isInitial) { - svgStyle.setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - return; - } - if (value->isSVGPaint()) { - SVGPaint* svgPaint = toSVGPaint(value); - svgStyle.setStrokePaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, state.style()->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); - } - break; - } - case CSSPropertyStrokeWidth: - { - HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth) - if (primitiveValue) - svgStyle.setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue)); - break; - } - case CSSPropertyStrokeDasharray: - { - HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray) - if (!value->isValueList()) { - svgStyle.setStrokeDashArray(SVGRenderStyle::initialStrokeDashArray()); - break; - } - - CSSValueList* dashes = toCSSValueList(value); - - Vector array; - size_t length = dashes->length(); - for (size_t i = 0; i < length; ++i) { - CSSValue* currValue = dashes->itemWithoutBoundsCheck(i); - if (!currValue->isPrimitiveValue()) - continue; - - CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->itemWithoutBoundsCheck(i)); - array.append(SVGLength::fromCSSPrimitiveValue(dash)); - } - - svgStyle.setStrokeDashArray(array); - break; - } - case CSSPropertyStrokeDashoffset: - { - HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset) - if (primitiveValue) - svgStyle.setStrokeDashOffset(SVGLength::fromCSSPrimitiveValue(primitiveValue)); - break; - } - case CSSPropertyFillOpacity: - { - HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity) - if (!primitiveValue) - return; - - float f = 0.0f; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - f = primitiveValue->getFloatValue() / 100.0f; - else if (type == CSSPrimitiveValue::CSS_NUMBER) - f = primitiveValue->getFloatValue(); - else - return; - - svgStyle.setFillOpacity(f); - break; - } - case CSSPropertyStrokeOpacity: - { - HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity) - if (!primitiveValue) - return; - - float f = 0.0f; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - f = primitiveValue->getFloatValue() / 100.0f; - else if (type == CSSPrimitiveValue::CSS_NUMBER) - f = primitiveValue->getFloatValue(); - else - return; - - svgStyle.setStrokeOpacity(f); - break; - } - case CSSPropertyStopOpacity: - { - HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity) - if (!primitiveValue) - return; - - float f = 0.0f; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - f = primitiveValue->getFloatValue() / 100.0f; - else if (type == CSSPrimitiveValue::CSS_NUMBER) - f = primitiveValue->getFloatValue(); - else - return; - - svgStyle.setStopOpacity(f); - break; - } - case CSSPropertyMarkerStart: - { - HANDLE_INHERIT_AND_INITIAL(markerStartResource, MarkerStartResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setMarkerStartResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyMarkerMid: - { - HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setMarkerMidResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyMarkerEnd: - { - HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setMarkerEndResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyStrokeLinecap: - { - HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle) - if (primitiveValue) - svgStyle.setCapStyle(*primitiveValue); - break; - } - case CSSPropertyStrokeMiterlimit: - { - HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit) - if (!primitiveValue) - return; - - float f = 0.0f; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_NUMBER) - f = primitiveValue->getFloatValue(); - else - return; - - svgStyle.setStrokeMiterLimit(f); - break; - } - case CSSPropertyFilter: - { - HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setFilterResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyMask: - { - HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setMaskerResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyClipPath: - { - HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource) - if (!primitiveValue) - return; - - String s; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) - s = primitiveValue->getStringValue(); - - svgStyle.setClipperResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); - break; - } - case CSSPropertyTextAnchor: - { - HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor) - if (primitiveValue) - svgStyle.setTextAnchor(*primitiveValue); - break; - } - case CSSPropertyWritingMode: - { - HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode) - if (primitiveValue) - svgStyle.setWritingMode(*primitiveValue); - break; - } - case CSSPropertyStopColor: - { - HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor); - if (value->isSVGColor()) - svgStyle.setStopColor(colorFromSVGColorCSSValue(toSVGColor(value), state.style()->color())); - break; - } - case CSSPropertyLightingColor: - { - HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor); - if (value->isSVGColor()) - svgStyle.setLightingColor(colorFromSVGColorCSSValue(toSVGColor(value), state.style()->color())); - break; - } - case CSSPropertyFloodOpacity: - { - HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity) - if (!primitiveValue) - return; - - float f = 0.0f; - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - f = primitiveValue->getFloatValue() / 100.0f; - else if (type == CSSPrimitiveValue::CSS_NUMBER) - f = primitiveValue->getFloatValue(); - else - return; - - svgStyle.setFloodOpacity(f); - break; - } - case CSSPropertyFloodColor: - { - HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor); - if (value->isSVGColor()) - svgStyle.setFloodColor(colorFromSVGColorCSSValue(toSVGColor(value), state.style()->color())); - break; - } - case CSSPropertyGlyphOrientationHorizontal: - { - HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal) - if (!primitiveValue) - return; - - if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { - int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); - ASSERT(orientation != -1); - - svgStyle.setGlyphOrientationHorizontal((EGlyphOrientation) orientation); - } - - break; - } - case CSSPropertyGlyphOrientationVertical: - { - HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical) - if (!primitiveValue) - return; - - if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { - int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); - ASSERT(orientation != -1); - - svgStyle.setGlyphOrientationVertical((EGlyphOrientation) orientation); - } else if (primitiveValue->getValueID() == CSSValueAuto) - svgStyle.setGlyphOrientationVertical(GO_AUTO); - - break; - } - case CSSPropertyEnableBackground: - // Silently ignoring this property for now - // http://bugs.webkit.org/show_bug.cgi?id=6022 - break; - case CSSPropertyWebkitSvgShadow: { - if (isInherit) - return svgStyle.setShadow(adoptPtr(state.parentStyle()->svgStyle().shadow() ? new ShadowData(*state.parentStyle()->svgStyle().shadow()) : 0)); - if (isInitial || primitiveValue) // initial | none - return svgStyle.setShadow(nullptr); - - if (!value->isValueList()) - return; - - CSSValueList* list = toCSSValueList(value); - if (!list->length()) - return; - - CSSValue* firstValue = list->itemWithoutBoundsCheck(0); - if (!firstValue->isShadowValue()) - return; - CSSShadowValue* item = toCSSShadowValue(firstValue); - IntPoint location(item->x->computeLength(state.style(), state.rootElementStyle()), - item->y->computeLength(state.style(), state.rootElementStyle())); - int blur = item->blur ? item->blur->computeLength(state.style(), state.rootElementStyle()) : 0; - Color color; - if (item->color) - color = colorFromPrimitiveValue(item->color.get()); - - // -webkit-svg-shadow does should not have a spread or style - ASSERT(!item->spread); - ASSERT(!item->style); - - OwnPtr shadowData = adoptPtr(new ShadowData(location, blur, 0, Normal, false, color.isValid() ? color : Color::transparent)); - svgStyle.setShadow(shadowData.release()); - return; - } - case CSSPropertyVectorEffect: { - HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect) - if (!primitiveValue) - break; - - svgStyle.setVectorEffect(*primitiveValue); - break; - } - case CSSPropertyBufferedRendering: { - HANDLE_INHERIT_AND_INITIAL(bufferedRendering, BufferedRendering) - if (!primitiveValue) - break; - - svgStyle.setBufferedRendering(*primitiveValue); - break; - } - case CSSPropertyMaskType: { - HANDLE_INHERIT_AND_INITIAL(maskType, MaskType) - if (!primitiveValue) - break; - - svgStyle.setMaskType(*primitiveValue); - break; - } - default: - // If you crash here, it's because you added a css property and are not handling it - // in either this switch statement or the one in StyleResolver::applyProperty - ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id); - return; - } -} - -} - -#endif diff --git a/Source/WebCore/css/SVGCSSValueKeywords.in b/Source/WebCore/css/SVGCSSValueKeywords.in index 773052c78..82a986dc0 100644 --- a/Source/WebCore/css/SVGCSSValueKeywords.in +++ b/Source/WebCore/css/SVGCSSValueKeywords.in @@ -124,6 +124,7 @@ pink plum powderblue // purple +rebeccapurple // red rosybrown royalblue @@ -211,7 +212,7 @@ linearRGB // CSS_PROP_SHAPE_RENDERING //auto //optimizeSpeed -crispEdges +crispedges //geometricPrecision // CSS_PROP_STROKE diff --git a/Source/WebCore/css/SelectorChecker.cpp b/Source/WebCore/css/SelectorChecker.cpp index 17d32009e..4b27d9540 100644 --- a/Source/WebCore/css/SelectorChecker.cpp +++ b/Source/WebCore/css/SelectorChecker.cpp @@ -2,12 +2,13 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) - * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2005-2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Alexey Proskuryakov * Copyright (C) 2007, 2008 Eric Seidel * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (c) 2011, Code Aurora Forum. All rights reserved. * Copyright (C) Research In Motion Limited 2011. All rights reserved. + * Copyright (C) 2014 Yusuke Suzuki * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,71 +33,104 @@ #include "CSSSelectorList.h" #include "Document.h" #include "ElementTraversal.h" -#include "FocusController.h" #include "Frame.h" #include "FrameSelection.h" -#include "HTMLAnchorElement.h" #include "HTMLDocument.h" -#include "HTMLFrameElementBase.h" -#include "HTMLInputElement.h" #include "HTMLNames.h" -#include "HTMLOptGroupElement.h" -#include "HTMLOptionElement.h" -#include "HTMLProgressElement.h" -#include "HTMLStyleElement.h" -#include "InsertionPoint.h" +#include "HTMLParserIdioms.h" +#include "HTMLSlotElement.h" #include "InspectorInstrumentation.h" -#include "NodeRenderStyle.h" #include "Page.h" #include "RenderElement.h" -#include "RenderScrollbar.h" -#include "RenderStyle.h" -#include "ScrollableArea.h" -#include "ScrollbarTheme.h" +#include "SelectorCheckerTestFunctions.h" #include "ShadowRoot.h" #include "StyledElement.h" #include "Text.h" -#if ENABLE(VIDEO_TRACK) -#include "WebVTTElement.h" -#endif - namespace WebCore { using namespace HTMLNames; - -static inline bool isFirstChildElement(const Element* element) + +enum class VisitedMatchType : unsigned char { + Disabled, Enabled +}; + +struct SelectorChecker::LocalContext { + LocalContext(const CSSSelector& selector, const Element& element, VisitedMatchType visitedMatchType, PseudoId pseudoId) + : selector(&selector) + , element(&element) + , visitedMatchType(visitedMatchType) + , firstSelectorOfTheFragment(&selector) + , pseudoId(pseudoId) + { } + + const CSSSelector* selector; + const Element* element; + VisitedMatchType visitedMatchType; + const CSSSelector* firstSelectorOfTheFragment; + PseudoId pseudoId; + bool isMatchElement { true }; + bool inFunctionalPseudoClass { false }; + bool pseudoElementEffective { true }; + bool hasScrollbarPseudo { false }; + bool hasSelectionPseudo { false }; + bool mayMatchHostPseudoClass { false }; + +}; + +static inline void addStyleRelation(SelectorChecker::CheckingContext& checkingContext, const Element& element, Style::Relation::Type type, unsigned value = 1) +{ + ASSERT(value == 1 || type == Style::Relation::NthChildIndex || type == Style::Relation::AffectedByEmpty); + if (checkingContext.resolvingMode != SelectorChecker::Mode::ResolvingStyle) + return; + if (type == Style::Relation::AffectsNextSibling && !checkingContext.styleRelations.isEmpty()) { + auto& last = checkingContext.styleRelations.last(); + if (last.type == Style::Relation::AffectsNextSibling && last.element == element.nextElementSibling()) { + ++last.value; + last.element = &element; + return; + } + } + checkingContext.styleRelations.append({ element, type, value }); +} + +static inline bool isFirstChildElement(const Element& element) { return !ElementTraversal::previousSibling(element); } -static inline bool isLastChildElement(const Element* element) +static inline bool isLastChildElement(const Element& element) { return !ElementTraversal::nextSibling(element); } -static inline bool isFirstOfType(const Element* element, const QualifiedName& type) +static inline bool isFirstOfType(SelectorChecker::CheckingContext& checkingContext, const Element& element, const QualifiedName& type) { - for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) { + for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { + addStyleRelation(checkingContext, *sibling, Style::Relation::AffectsNextSibling); + if (sibling->hasTagName(type)) return false; } return true; } -static inline bool isLastOfType(const Element* element, const QualifiedName& type) +static inline bool isLastOfType(const Element& element, const QualifiedName& type) { - for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(sibling)) { + for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) { if (sibling->hasTagName(type)) return false; } return true; } -static inline int countElementsBefore(const Element* element) +static inline int countElementsBefore(SelectorChecker::CheckingContext& checkingContext, const Element& element) { int count = 0; - for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) { + for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { + + addStyleRelation(checkingContext, *sibling, Style::Relation::AffectsNextSibling); + unsigned index = sibling->childIndex(); if (index) { count += index; @@ -107,200 +141,352 @@ static inline int countElementsBefore(const Element* element) return count; } -static inline int countElementsOfTypeBefore(const Element* element, const QualifiedName& type) +static inline int countElementsOfTypeBefore(SelectorChecker::CheckingContext& checkingContext, const Element& element, const QualifiedName& type) { int count = 0; - for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) { + for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { + addStyleRelation(checkingContext, *sibling, Style::Relation::AffectsNextSibling); + if (sibling->hasTagName(type)) ++count; } return count; } -static inline int countElementsAfter(const Element* element) +static inline int countElementsAfter(const Element& element) { int count = 0; - for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(sibling)) + for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) ++count; return count; } -static inline int countElementsOfTypeAfter(const Element* element, const QualifiedName& type) +static inline int countElementsOfTypeAfter(const Element& element, const QualifiedName& type) { int count = 0; - for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(sibling)) { + for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) { if (sibling->hasTagName(type)) ++count; } return count; } -SelectorChecker::SelectorChecker(Document& document, Mode mode) +SelectorChecker::SelectorChecker(Document& document) : m_strictParsing(!document.inQuirksMode()) , m_documentIsHTML(document.isHTMLDocument()) - , m_mode(mode) { } +bool SelectorChecker::match(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const +{ + specificity = 0; + + LocalContext context(selector, element, checkingContext.resolvingMode == SelectorChecker::Mode::QueryingRules ? VisitedMatchType::Disabled : VisitedMatchType::Enabled, checkingContext.pseudoId); + + if (checkingContext.isMatchingHostPseudoClass) { + ASSERT(element.shadowRoot()); + context.mayMatchHostPseudoClass = true; + } + + PseudoIdSet pseudoIdSet; + MatchResult result = matchRecursively(checkingContext, context, pseudoIdSet, specificity); + if (result.match != Match::SelectorMatches) + return false; + if (checkingContext.pseudoId != NOPSEUDO && !pseudoIdSet.has(checkingContext.pseudoId)) + return false; + + if (checkingContext.pseudoId == NOPSEUDO && pseudoIdSet) { + PseudoIdSet publicPseudoIdSet = pseudoIdSet & PseudoIdSet::fromMask(PUBLIC_PSEUDOID_MASK); + if (checkingContext.resolvingMode == Mode::ResolvingStyle && publicPseudoIdSet) + checkingContext.pseudoIDSet = publicPseudoIdSet; + + // When ignoring virtual pseudo elements, the context's pseudo should also be NOPSEUDO but that does + // not cause a failure. + return checkingContext.resolvingMode == Mode::CollectingRulesIgnoringVirtualPseudoElements || result.matchType == MatchType::Element; + } + return true; +} + +bool SelectorChecker::matchHostPseudoClass(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const +{ + ASSERT(element.shadowRoot()); + ASSERT(selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost); + + specificity = selector.simpleSelectorSpecificity(); + + if (auto* selectorList = selector.selectorList()) { + LocalContext context(*selectorList->first(), element, VisitedMatchType::Enabled, NOPSEUDO); + context.inFunctionalPseudoClass = true; + context.pseudoElementEffective = false; + PseudoIdSet ignoreDynamicPseudo; + unsigned subselectorSpecificity = 0; + if (matchRecursively(checkingContext, context, ignoreDynamicPseudo, subselectorSpecificity).match != Match::SelectorMatches) + return false; + specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity); + } + return true; +} + +inline static bool hasScrollbarPseudoElement(const PseudoIdSet& dynamicPseudoIdSet) +{ + PseudoIdSet scrollbarIdSet = { SCROLLBAR, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER }; + if (dynamicPseudoIdSet & scrollbarIdSet) + return true; + + // RESIZER does not always have a scrollbar but it is a scrollbar-like pseudo element + // because it can have more than one pseudo element. + return dynamicPseudoIdSet.has(RESIZER); +} + +static SelectorChecker::LocalContext localContextForParent(const SelectorChecker::LocalContext& context) +{ + SelectorChecker::LocalContext updatedContext(context); + // Disable :visited matching when we see the first link. + if (context.element->isLink()) + updatedContext.visitedMatchType = VisitedMatchType::Disabled; + + updatedContext.isMatchElement = false; + + if (updatedContext.mayMatchHostPseudoClass) { + updatedContext.element = nullptr; + return updatedContext; + } + + // Move to the shadow host if matching :host and the parent is the shadow root. + if (context.selector->match() == CSSSelector::PseudoClass && context.selector->pseudoClassType() == CSSSelector::PseudoClassHost && is(context.element->parentNode())) { + updatedContext.element = downcast(*context.element->parentNode()).host(); + updatedContext.mayMatchHostPseudoClass = true; + return updatedContext; + } + + updatedContext.element = context.element->parentElement(); + return updatedContext; +} + // Recursive check of selectors and combinators // It can return 4 different values: // * SelectorMatches - the selector matches the element e // * SelectorFailsLocally - the selector fails for the element e // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e -SelectorChecker::Match SelectorChecker::matchRecursively(const SelectorCheckingContext& context, PseudoId& dynamicPseudo) const +SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, unsigned& specificity) const { + MatchType matchType = MatchType::Element; + // The first selector has to match. - if (!checkOne(context)) - return SelectorFailsLocally; + if (!checkOne(checkingContext, context, dynamicPseudoIdSet, matchType, specificity)) + return MatchResult::fails(Match::SelectorFailsLocally); - if (context.selector->m_match == CSSSelector::PseudoElement) { + if (context.selector->match() == CSSSelector::PseudoElement) { if (context.selector->isCustomPseudoElement()) { + // In functional pseudo class, custom pseudo elements are always disabled. + // FIXME: We should accept custom pseudo elements inside :matches(). + if (context.inFunctionalPseudoClass) + return MatchResult::fails(Match::SelectorFailsCompletely); if (ShadowRoot* root = context.element->containingShadowRoot()) { if (context.element->shadowPseudoId() != context.selector->value()) - return SelectorFailsLocally; + return MatchResult::fails(Match::SelectorFailsLocally); - if (context.selector->pseudoType() == CSSSelector::PseudoWebKitCustomElement && root->type() != ShadowRoot::UserAgentShadowRoot) - return SelectorFailsLocally; + if (context.selector->isWebKitCustomPseudoElement() && root->mode() != ShadowRootMode::UserAgent) + return MatchResult::fails(Match::SelectorFailsLocally); } else - return SelectorFailsLocally; + return MatchResult::fails(Match::SelectorFailsLocally); } else { - if ((!context.elementStyle && m_mode == ResolvingStyle) || m_mode == QueryingRules) - return SelectorFailsLocally; + if (!context.pseudoElementEffective) + return MatchResult::fails(Match::SelectorFailsCompletely); + + if (checkingContext.resolvingMode == Mode::QueryingRules) + return MatchResult::fails(Match::SelectorFailsCompletely); - PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoType()); - if (pseudoId == FIRST_LETTER) - context.element->document().styleSheetCollection().setUsesFirstLetterRules(true); + PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoElementType()); if (pseudoId != NOPSEUDO) - dynamicPseudo = pseudoId; + dynamicPseudoIdSet.add(pseudoId); + matchType = MatchType::VirtualPseudoElementOnly; } } // The rest of the selectors has to match - CSSSelector::Relation relation = context.selector->relation(); + auto relation = context.selector->relation(); // Prepare next selector - const CSSSelector* historySelector = context.selector->tagHistory(); - if (!historySelector) - return SelectorMatches; + const CSSSelector* leftSelector = context.selector->tagHistory(); + if (!leftSelector) + return MatchResult::matches(matchType); - SelectorCheckingContext nextContext(context); - nextContext.selector = historySelector; + LocalContext nextContext(context); + nextContext.selector = leftSelector; - PseudoId ignoreDynamicPseudo = NOPSEUDO; - if (relation != CSSSelector::SubSelector) { + if (relation != CSSSelector::Subselector) { // Bail-out if this selector is irrelevant for the pseudoId - if (context.pseudoId != NOPSEUDO && context.pseudoId != dynamicPseudo) - return SelectorFailsCompletely; + if (context.pseudoId != NOPSEUDO && !dynamicPseudoIdSet.has(context.pseudoId)) + return MatchResult::fails(Match::SelectorFailsCompletely); - // Disable :visited matching when we see the first link or try to match anything else than an ancestors. - if (!context.isSubSelector && (context.element->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child))) - nextContext.visitedMatchType = VisitedMatchDisabled; + // Disable :visited matching when we try to match anything else than an ancestors. + if (!context.selector->hasDescendantOrChildRelation()) + nextContext.visitedMatchType = VisitedMatchType::Disabled; nextContext.pseudoId = NOPSEUDO; + // Virtual pseudo element is only effective in the rightmost fragment. + nextContext.pseudoElementEffective = false; + nextContext.isMatchElement = false; } switch (relation) { - case CSSSelector::Descendant: - nextContext.element = context.element->parentElement(); - nextContext.isSubSelector = false; - nextContext.elementStyle = 0; - for (; nextContext.element; nextContext.element = nextContext.element->parentElement()) { - Match match = this->matchRecursively(nextContext, ignoreDynamicPseudo); - if (match == SelectorMatches || match == SelectorFailsCompletely) - return match; + case CSSSelector::DescendantSpace: +#if ENABLE(CSS_SELECTORS_LEVEL4) + case CSSSelector::DescendantDoubleChild: +#endif + nextContext = localContextForParent(nextContext); + nextContext.firstSelectorOfTheFragment = nextContext.selector; + for (; nextContext.element; nextContext = localContextForParent(nextContext)) { + PseudoIdSet ignoreDynamicPseudo; + unsigned descendantsSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, descendantsSpecificity); + ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, descendantsSpecificity); + + if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely) + return MatchResult::updateWithMatchType(result, matchType); } - return SelectorFailsCompletely; + return MatchResult::fails(Match::SelectorFailsCompletely); case CSSSelector::Child: - nextContext.element = context.element->parentElement(); - if (!nextContext.element) - return SelectorFailsCompletely; - nextContext.isSubSelector = false; - nextContext.elementStyle = 0; - return matchRecursively(nextContext, ignoreDynamicPseudo); + { + nextContext = localContextForParent(nextContext); + if (!nextContext.element) + return MatchResult::fails(Match::SelectorFailsCompletely); + nextContext.firstSelectorOfTheFragment = nextContext.selector; + PseudoIdSet ignoreDynamicPseudo; + unsigned childSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, childSpecificity); + ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, childSpecificity); + + if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely) + return MatchResult::updateWithMatchType(result, matchType); + return MatchResult::fails(Match::SelectorFailsAllSiblings); + } case CSSSelector::DirectAdjacent: - if (m_mode == ResolvingStyle) { - if (Element* parentElement = context.element->parentElement()) - parentElement->setChildrenAffectedByDirectAdjacentRules(); - } - nextContext.element = context.element->previousElementSibling(); - if (!nextContext.element) - return SelectorFailsAllSiblings; - nextContext.isSubSelector = false; - nextContext.elementStyle = 0; - return matchRecursively(nextContext, ignoreDynamicPseudo); + { + addStyleRelation(checkingContext, *context.element, Style::Relation::AffectedByPreviousSibling); - case CSSSelector::IndirectAdjacent: - if (m_mode == ResolvingStyle) { - if (Element* parentElement = context.element->parentElement()) - parentElement->setChildrenAffectedByForwardPositionalRules(); + Element* previousElement = context.element->previousElementSibling(); + if (!previousElement) + return MatchResult::fails(Match::SelectorFailsAllSiblings); + + addStyleRelation(checkingContext, *previousElement, Style::Relation::AffectsNextSibling); + + nextContext.element = previousElement; + nextContext.firstSelectorOfTheFragment = nextContext.selector; + PseudoIdSet ignoreDynamicPseudo; + unsigned adjacentSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, adjacentSpecificity); + ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, adjacentSpecificity); + + return MatchResult::updateWithMatchType(result, matchType); } + case CSSSelector::IndirectAdjacent: + addStyleRelation(checkingContext, *context.element, Style::Relation::AffectedByPreviousSibling); + nextContext.element = context.element->previousElementSibling(); - nextContext.isSubSelector = false; - nextContext.elementStyle = 0; + nextContext.firstSelectorOfTheFragment = nextContext.selector; for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) { - Match match = this->matchRecursively(nextContext, ignoreDynamicPseudo); - if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) - return match; + addStyleRelation(checkingContext, *nextContext.element, Style::Relation::AffectsNextSibling); + + PseudoIdSet ignoreDynamicPseudo; + unsigned indirectAdjacentSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, indirectAdjacentSpecificity); + ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, indirectAdjacentSpecificity); + + if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsAllSiblings || result.match == Match::SelectorFailsCompletely) + return MatchResult::updateWithMatchType(result, matchType); }; - return SelectorFailsAllSiblings; - - case CSSSelector::SubSelector: - // a selector is invalid if something follows a pseudo-element - // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else) - // to follow the pseudo elements. - nextContext.hasScrollbarPseudo = dynamicPseudo != NOPSEUDO && (context.scrollbar || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER); - nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION; - if ((context.elementStyle || m_mode == CollectingRules || m_mode == QueryingRules) && dynamicPseudo != NOPSEUDO - && !nextContext.hasSelectionPseudo - && !(nextContext.hasScrollbarPseudo && nextContext.selector->m_match == CSSSelector::PseudoClass)) - return SelectorFailsCompletely; - nextContext.isSubSelector = true; - return matchRecursively(nextContext, dynamicPseudo); + return MatchResult::fails(Match::SelectorFailsAllSiblings); + case CSSSelector::Subselector: + { + // a selector is invalid if something follows a pseudo-element + // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else) + // to follow the pseudo elements. + nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudoIdSet); + nextContext.hasSelectionPseudo = dynamicPseudoIdSet.has(SELECTION); + if ((context.isMatchElement || checkingContext.resolvingMode == Mode::CollectingRules) && dynamicPseudoIdSet + && !nextContext.hasSelectionPseudo + && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass)) + return MatchResult::fails(Match::SelectorFailsCompletely); + + unsigned subselectorSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, dynamicPseudoIdSet, subselectorSpecificity); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity); + + return MatchResult::updateWithMatchType(result, matchType); + } case CSSSelector::ShadowDescendant: { Element* shadowHostNode = context.element->shadowHost(); if (!shadowHostNode) - return SelectorFailsCompletely; + return MatchResult::fails(Match::SelectorFailsCompletely); nextContext.element = shadowHostNode; - nextContext.isSubSelector = false; - nextContext.elementStyle = 0; - return matchRecursively(nextContext, ignoreDynamicPseudo); + nextContext.firstSelectorOfTheFragment = nextContext.selector; + PseudoIdSet ignoreDynamicPseudo; + unsigned shadowDescendantSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity); + + if (result.match == Match::SelectorMatches) + specificity = CSSSelector::addSpecificities(specificity, shadowDescendantSpecificity); + + return MatchResult::updateWithMatchType(result, matchType); } } + ASSERT_NOT_REACHED(); - return SelectorFailsCompletely; + return MatchResult::fails(Match::SelectorFailsCompletely); } static bool attributeValueMatches(const Attribute& attribute, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive) { const AtomicString& value = attribute.value(); - if (value.isNull()) - return false; + ASSERT(!value.isNull()); switch (match) { + case CSSSelector::Set: + break; case CSSSelector::Exact: - if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value)) + if (caseSensitive ? selectorValue != value : !equalIgnoringASCIICase(selectorValue, value)) return false; break; case CSSSelector::List: { - // Ignore empty selectors or selectors containing spaces - if (selectorValue.contains(' ') || selectorValue.isEmpty()) + // Ignore empty selectors or selectors containing spaces. + if (selectorValue.isEmpty() || selectorValue.find(isHTMLSpace) != notFound) return false; unsigned startSearchAt = 0; while (true) { - size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive); + size_t foundPos; + if (caseSensitive) + foundPos = value.find(selectorValue, startSearchAt); + else + foundPos = value.findIgnoringASCIICase(selectorValue, startSearchAt); if (foundPos == notFound) return false; - if (!foundPos || value[foundPos - 1] == ' ') { + if (!foundPos || isHTMLSpace(value[foundPos - 1])) { unsigned endStr = foundPos + selectorValue.length(); - if (endStr == value.length() || value[endStr] == ' ') + if (endStr == value.length() || isHTMLSpace(value[endStr])) break; // We found a match. } @@ -309,561 +495,685 @@ static bool attributeValueMatches(const Attribute& attribute, CSSSelector::Match } break; } - case CSSSelector::Contain: - if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmpty()) + case CSSSelector::Contain: { + bool valueContainsSelectorValue; + if (caseSensitive) + valueContainsSelectorValue = value.contains(selectorValue); + else + valueContainsSelectorValue = value.containsIgnoringASCIICase(selectorValue); + + if (!valueContainsSelectorValue || selectorValue.isEmpty()) return false; + break; + } case CSSSelector::Begin: - if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) + if (selectorValue.isEmpty()) return false; + if (caseSensitive) { + if (!value.startsWith(selectorValue)) + return false; + } else { + if (!value.startsWithIgnoringASCIICase(selectorValue)) + return false; + } break; case CSSSelector::End: - if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty()) + if (selectorValue.isEmpty()) return false; + if (caseSensitive) { + if (!value.endsWith(selectorValue)) + return false; + } else { + if (!value.endsWithIgnoringASCIICase(selectorValue)) + return false; + } break; case CSSSelector::Hyphen: if (value.length() < selectorValue.length()) return false; - if (!value.startsWith(selectorValue, caseSensitive)) - return false; + if (caseSensitive) { + if (!value.startsWith(selectorValue)) + return false; + } else { + if (!value.startsWithIgnoringASCIICase(selectorValue)) + return false; + } // It they start the same, check for exact match or following '-': if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-') return false; break; - case CSSSelector::PseudoClass: - case CSSSelector::PseudoElement: default: - break; + ASSERT_NOT_REACHED(); + return false; } return true; } -static bool anyAttributeMatches(Element* element, const CSSSelector* selector, const QualifiedName& selectorAttr, bool caseSensitive) +static bool anyAttributeMatches(const Element& element, const CSSSelector& selector, const QualifiedName& selectorAttr, bool caseSensitive) { - ASSERT(element->hasAttributesWithoutUpdate()); - for (const Attribute& attribute : element->attributesIterator()) { - if (!attribute.matches(selectorAttr.prefix(), element->isHTMLElement() ? selector->attributeCanonicalLocalName() : selectorAttr.localName(), selectorAttr.namespaceURI())) + ASSERT(element.hasAttributesWithoutUpdate()); + for (const Attribute& attribute : element.attributesIterator()) { + if (!attribute.matches(selectorAttr.prefix(), element.isHTMLElement() ? selector.attributeCanonicalLocalName() : selectorAttr.localName(), selectorAttr.namespaceURI())) continue; - if (attributeValueMatches(attribute, static_cast(selector->m_match), selector->value(), caseSensitive)) + if (attributeValueMatches(attribute, selector.match(), selector.value(), caseSensitive)) return true; } return false; } -bool SelectorChecker::checkOne(const SelectorCheckingContext& context) const +bool SelectorChecker::attributeSelectorMatches(const Element& element, const QualifiedName& attributeName, const AtomicString& attributeValue, const CSSSelector& selector) { - Element* const & element = context.element; - const CSSSelector* const & selector = context.selector; - ASSERT(element); - ASSERT(selector); + ASSERT(selector.isAttributeSelector()); + auto& selectorAttribute = selector.attribute(); + auto& selectorName = element.isHTMLElement() ? selector.attributeCanonicalLocalName() : selectorAttribute.localName(); + if (!Attribute::nameMatchesFilter(attributeName, selectorAttribute.prefix(), selectorName, selectorAttribute.namespaceURI())) + return false; + bool caseSensitive = true; + if (selector.attributeValueMatchingIsCaseInsensitive()) + caseSensitive = false; + else if (element.document().isHTMLDocument() && element.isHTMLElement() && !HTMLDocument::isCaseSensitiveAttribute(selector.attribute())) + caseSensitive = false; + return attributeValueMatches(Attribute(attributeName, attributeValue), selector.match(), selector.value(), caseSensitive); +} - if (selector->m_match == CSSSelector::Tag) - return SelectorChecker::tagMatches(element, selector->tagQName()); +static bool canMatchHoverOrActiveInQuirksMode(const SelectorChecker::LocalContext& context) +{ + // For quirks mode, follow this: http://quirks.spec.whatwg.org/#the-:active-and-:hover-quirk + // In quirks mode, a compound selector 'selector' that matches the following conditions must not match elements that would not also match the ':any-link' selector. + // + // selector uses the ':active' or ':hover' pseudo-classes. + // selector does not use a type selector. + // selector does not use an attribute selector. + // selector does not use an ID selector. + // selector does not use a class selector. + // selector does not use a pseudo-class selector other than ':active' and ':hover'. + // selector does not use a pseudo-element selector. + // selector is not part of an argument to a functional pseudo-class or pseudo-element. + if (context.inFunctionalPseudoClass) + return true; - if (selector->m_match == CSSSelector::Class) - return element->hasClass() && element->classNames().contains(selector->value()); + for (const CSSSelector* selector = context.firstSelectorOfTheFragment; selector; selector = selector->tagHistory()) { + switch (selector->match()) { + case CSSSelector::Tag: + if (selector->tagQName() != anyQName()) + return true; + break; + case CSSSelector::PseudoClass: { + CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType(); + if (pseudoClassType != CSSSelector::PseudoClassHover && pseudoClassType != CSSSelector::PseudoClassActive) + return true; + break; + } + case CSSSelector::Id: + case CSSSelector::Class: + case CSSSelector::Exact: + case CSSSelector::Set: + case CSSSelector::List: + case CSSSelector::Hyphen: + case CSSSelector::Contain: + case CSSSelector::Begin: + case CSSSelector::End: + case CSSSelector::PagePseudoClass: + case CSSSelector::PseudoElement: + return true; + case CSSSelector::Unknown: + ASSERT_NOT_REACHED(); + break; + } - if (selector->m_match == CSSSelector::Id) - return element->hasID() && element->idForStyleResolution() == selector->value(); + auto relation = selector->relation(); + if (relation == CSSSelector::ShadowDescendant) + return true; - if (selector->isAttributeSelector()) { - if (!element->hasAttributes()) + if (relation != CSSSelector::Subselector) return false; + } + return false; +} + +static inline bool tagMatches(const Element& element, const CSSSelector& simpleSelector) +{ + const QualifiedName& tagQName = simpleSelector.tagQName(); + + if (tagQName == anyQName()) + return true; + + const AtomicString& localName = (element.isHTMLElement() && element.document().isHTMLDocument()) ? simpleSelector.tagLowercaseLocalName() : tagQName.localName(); + + if (localName != starAtom && localName != element.localName()) + return false; + const AtomicString& namespaceURI = tagQName.namespaceURI(); + return namespaceURI == starAtom || namespaceURI == element.namespaceURI(); +} + +bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, MatchType& matchType, unsigned& specificity) const +{ + const Element& element = *context.element; + const CSSSelector& selector = *context.selector; - const QualifiedName& attr = selector->attribute(); - bool caseSensitive = !m_documentIsHTML || HTMLDocument::isCaseSensitiveAttribute(attr); + specificity = CSSSelector::addSpecificities(specificity, selector.simpleSelectorSpecificity()); - if (!anyAttributeMatches(element, selector, attr, caseSensitive)) + if (context.mayMatchHostPseudoClass) { + // :host doesn't combine with anything except pseudo elements. + bool isHostPseudoClass = selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost; + bool isPseudoElement = selector.match() == CSSSelector::PseudoElement; + if (!isHostPseudoClass && !isPseudoElement) return false; } - if (selector->m_match == CSSSelector::PseudoClass) { - // Handle :not up front. - if (selector->pseudoType() == CSSSelector::PseudoNot) { - const CSSSelectorList* selectorList = selector->selectorList(); + if (selector.match() == CSSSelector::Tag) + return tagMatches(element, selector); - // FIXME: We probably should fix the parser and make it never produce :not rules with missing selector list. - if (!selectorList) - return false; + if (selector.match() == CSSSelector::Class) + return element.hasClass() && element.classNames().contains(selector.value()); - SelectorCheckingContext subContext(context); - subContext.isSubSelector = true; - for (subContext.selector = selectorList->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) { - // :not cannot nest. I don't really know why this is a - // restriction in CSS3, but it is, so let's honor it. - // the parser enforces that this never occurs - ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot); - // We select between :visited and :link when applying. We don't know which one applied (or not) yet. - if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled)) - return true; - if (!checkOne(subContext)) - return true; + if (selector.match() == CSSSelector::Id) { + ASSERT(!selector.value().isNull()); + return element.idForStyleResolution() == selector.value(); + } + + if (selector.isAttributeSelector()) { + if (!element.hasAttributes()) + return false; + + const QualifiedName& attr = selector.attribute(); + bool caseSensitive = true; + if (selector.attributeValueMatchingIsCaseInsensitive()) + caseSensitive = false; + else if (m_documentIsHTML && element.isHTMLElement() && !HTMLDocument::isCaseSensitiveAttribute(attr)) + caseSensitive = false; + + return anyAttributeMatches(element, selector, attr, caseSensitive); + } + + if (selector.match() == CSSSelector::PseudoClass) { + // Handle :not up front. + if (selector.pseudoClassType() == CSSSelector::PseudoClassNot) { + const CSSSelectorList* selectorList = selector.selectorList(); + + for (const CSSSelector* subselector = selectorList->first(); subselector; subselector = CSSSelectorList::next(subselector)) { + LocalContext subcontext(context); + subcontext.inFunctionalPseudoClass = true; + subcontext.pseudoElementEffective = false; + subcontext.selector = subselector; + subcontext.firstSelectorOfTheFragment = selectorList->first(); + PseudoIdSet ignoreDynamicPseudo; + + unsigned ignoredSpecificity; + if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches) { + ASSERT(!ignoreDynamicPseudo); + return false; + } } - } else if (context.hasScrollbarPseudo) { + return true; + } + if (context.hasScrollbarPseudo) { // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each - // (since there are no elements involved). - return checkScrollbarPseudoClass(context, &element->document(), selector); - } else if (context.hasSelectionPseudo) { - if (selector->pseudoType() == CSSSelector::PseudoWindowInactive) - return !element->document().page()->focusController().isActive(); + // (since there are no elements involved except with window-inactive). + return checkScrollbarPseudoClass(checkingContext, element, selector); } // Normal element pseudo class checking. - switch (selector->pseudoType()) { + switch (selector.pseudoClassType()) { // Pseudo classes: - case CSSSelector::PseudoNot: + case CSSSelector::PseudoClassNot: break; // Already handled up above. - case CSSSelector::PseudoEmpty: + case CSSSelector::PseudoClassEmpty: { bool result = true; - for (Node* n = element->firstChild(); n; n = n->nextSibling()) { - if (n->isElementNode()) { + for (Node* node = element.firstChild(); node; node = node->nextSibling()) { + if (is(*node)) { result = false; break; } - if (n->isTextNode()) { - Text* textNode = toText(n); - if (!textNode->data().isEmpty()) { + if (is(*node)) { + Text& textNode = downcast(*node); + if (!textNode.data().isEmpty()) { result = false; break; } } } - if (m_mode == ResolvingStyle) { - element->setStyleAffectedByEmpty(); - if (context.elementStyle) - context.elementStyle->setEmptyState(result); - else if (element->renderStyle() && (element->document().styleSheetCollection().usesSiblingRules() || element->renderStyle()->unique())) - element->renderStyle()->setEmptyState(result); - } + addStyleRelation(checkingContext, *context.element, Style::Relation::AffectedByEmpty, result); + return result; } - case CSSSelector::PseudoFirstChild: + case CSSSelector::PseudoClassFirstChild: // first-child matches the first child that is an element - if (Element* parentElement = element->parentElement()) { - bool result = isFirstChildElement(element); - if (m_mode == ResolvingStyle) { - RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); - parentElement->setChildrenAffectedByFirstChildRules(); - if (result && childStyle) - childStyle->setFirstChildState(); - } - return result; + if (const Element* parentElement = element.parentElement()) { + bool isFirstChild = isFirstChildElement(element); + if (isFirstChild) + addStyleRelation(checkingContext, element, Style::Relation::FirstChild); + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByFirstChildRules); + return isFirstChild; } break; - case CSSSelector::PseudoFirstOfType: + case CSSSelector::PseudoClassFirstOfType: // first-of-type matches the first element of its type - if (Element* parentElement = element->parentElement()) { - bool result = isFirstOfType(element, element->tagQName()); - if (m_mode == ResolvingStyle) - parentElement->setChildrenAffectedByForwardPositionalRules(); - return result; + if (element.parentElement()) { + addStyleRelation(checkingContext, element, Style::Relation::AffectedByPreviousSibling); + return isFirstOfType(checkingContext, element, element.tagQName()); } break; - case CSSSelector::PseudoLastChild: + case CSSSelector::PseudoClassLastChild: // last-child matches the last child that is an element - if (Element* parentElement = element->parentElement()) { - bool result = parentElement->isFinishedParsingChildren() && isLastChildElement(element); - if (m_mode == ResolvingStyle) { - RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); - parentElement->setChildrenAffectedByLastChildRules(); - if (result && childStyle) - childStyle->setLastChildState(); - } - return result; + if (const Element* parentElement = element.parentElement()) { + bool isLastChild = parentElement->isFinishedParsingChildren() && isLastChildElement(element); + if (isLastChild) + addStyleRelation(checkingContext, element, Style::Relation::LastChild); + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByLastChildRules); + return isLastChild; } break; - case CSSSelector::PseudoLastOfType: + case CSSSelector::PseudoClassLastOfType: // last-of-type matches the last element of its type - if (Element* parentElement = element->parentElement()) { - if (m_mode == ResolvingStyle) - parentElement->setChildrenAffectedByBackwardPositionalRules(); + if (Element* parentElement = element.parentElement()) { + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules); if (!parentElement->isFinishedParsingChildren()) return false; - return isLastOfType(element, element->tagQName()); + return isLastOfType(element, element.tagQName()); } break; - case CSSSelector::PseudoOnlyChild: - if (Element* parentElement = element->parentElement()) { + case CSSSelector::PseudoClassOnlyChild: + if (Element* parentElement = element.parentElement()) { bool firstChild = isFirstChildElement(element); bool onlyChild = firstChild && parentElement->isFinishedParsingChildren() && isLastChildElement(element); - if (m_mode == ResolvingStyle) { - RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); - parentElement->setChildrenAffectedByFirstChildRules(); - parentElement->setChildrenAffectedByLastChildRules(); - if (firstChild && childStyle) - childStyle->setFirstChildState(); - if (onlyChild && childStyle) - childStyle->setLastChildState(); - } + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByFirstChildRules); + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByLastChildRules); + if (firstChild) + addStyleRelation(checkingContext, element, Style::Relation::FirstChild); + if (onlyChild) + addStyleRelation(checkingContext, element, Style::Relation::LastChild); return onlyChild; } break; - case CSSSelector::PseudoOnlyOfType: + case CSSSelector::PseudoClassOnlyOfType: // FIXME: This selector is very slow. - if (Element* parentElement = element->parentElement()) { - if (m_mode == ResolvingStyle) { - parentElement->setChildrenAffectedByForwardPositionalRules(); - parentElement->setChildrenAffectedByBackwardPositionalRules(); - } + if (Element* parentElement = element.parentElement()) { + addStyleRelation(checkingContext, element, Style::Relation::AffectedByPreviousSibling); + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules); if (!parentElement->isFinishedParsingChildren()) return false; - return isFirstOfType(element, element->tagQName()) && isLastOfType(element, element->tagQName()); + return isFirstOfType(checkingContext, element, element.tagQName()) && isLastOfType(element, element.tagQName()); } break; - case CSSSelector::PseudoNthChild: - if (!selector->parseNth()) + case CSSSelector::PseudoClassMatches: + { + bool hasMatchedAnything = false; + unsigned maxSpecificity = 0; + + MatchType localMatchType = MatchType::VirtualPseudoElementOnly; + for (const CSSSelector* subselector = selector.selectorList()->first(); subselector; subselector = CSSSelectorList::next(subselector)) { + LocalContext subcontext(context); + subcontext.inFunctionalPseudoClass = true; + subcontext.pseudoElementEffective = context.pseudoElementEffective; + subcontext.selector = subselector; + subcontext.firstSelectorOfTheFragment = subselector; + PseudoIdSet localDynamicPseudoIdSet; + unsigned localSpecificity = 0; + MatchResult result = matchRecursively(checkingContext, subcontext, localDynamicPseudoIdSet, localSpecificity); + if (result.match == Match::SelectorMatches) { + maxSpecificity = std::max(maxSpecificity, localSpecificity); + + if (result.matchType == MatchType::Element) + localMatchType = MatchType::Element; + + dynamicPseudoIdSet.merge(localDynamicPseudoIdSet); + hasMatchedAnything = true; + } + } + if (hasMatchedAnything) { + matchType = localMatchType; + specificity = CSSSelector::addSpecificities(specificity, maxSpecificity); + } + return hasMatchedAnything; + } + case CSSSelector::PseudoClassPlaceholderShown: + if (is(element)) { + addStyleRelation(checkingContext, element, Style::Relation::Unique); + return downcast(element).isPlaceholderVisible(); + } + return false; + case CSSSelector::PseudoClassNthChild: + if (!selector.parseNth()) break; - if (Element* parentElement = element->parentElement()) { - int count = 1 + countElementsBefore(element); - if (m_mode == ResolvingStyle) { - RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle(); - element->setChildIndex(count); - if (childStyle) - childStyle->setUnique(); - parentElement->setChildrenAffectedByForwardPositionalRules(); + if (element.parentElement()) { + if (const CSSSelectorList* selectorList = selector.selectorList()) { + unsigned selectorListSpecificity; + if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity)) + return false; + specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity); + } + + addStyleRelation(checkingContext, element, Style::Relation::AffectedByPreviousSibling); + + int count = 1; + if (const CSSSelectorList* selectorList = selector.selectorList()) { + for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { + addStyleRelation(checkingContext, *sibling, Style::Relation::AffectsNextSibling); + + unsigned ignoredSpecificity; + if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) + ++count; + } + } else { + count += countElementsBefore(checkingContext, element); + addStyleRelation(checkingContext, element, Style::Relation::NthChildIndex, count); } - if (selector->matchNth(count)) + if (selector.matchNth(count)) return true; } break; - case CSSSelector::PseudoNthOfType: - if (!selector->parseNth()) + case CSSSelector::PseudoClassNthOfType: + if (!selector.parseNth()) break; - if (Element* parentElement = element->parentElement()) { - int count = 1 + countElementsOfTypeBefore(element, element->tagQName()); - if (m_mode == ResolvingStyle) - parentElement->setChildrenAffectedByForwardPositionalRules(); - if (selector->matchNth(count)) + if (element.parentElement()) { + addStyleRelation(checkingContext, element, Style::Relation::AffectedByPreviousSibling); + + int count = 1 + countElementsOfTypeBefore(checkingContext, element, element.tagQName()); + if (selector.matchNth(count)) return true; } break; - case CSSSelector::PseudoNthLastChild: - if (!selector->parseNth()) + case CSSSelector::PseudoClassNthLastChild: + if (!selector.parseNth()) break; - if (Element* parentElement = element->parentElement()) { - if (m_mode == ResolvingStyle) - parentElement->setChildrenAffectedByBackwardPositionalRules(); + if (Element* parentElement = element.parentElement()) { + if (const CSSSelectorList* selectorList = selector.selectorList()) { + unsigned selectorListSpecificity; + if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity)) + return false; + specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity); + + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules); + } else + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules); + if (!parentElement->isFinishedParsingChildren()) return false; - int count = 1 + countElementsAfter(element); - if (selector->matchNth(count)) + + int count = 1; + if (const CSSSelectorList* selectorList = selector.selectorList()) { + for (Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) { + unsigned ignoredSpecificity; + if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) + ++count; + } + } else + count += countElementsAfter(element); + + if (selector.matchNth(count)) return true; } break; - case CSSSelector::PseudoNthLastOfType: - if (!selector->parseNth()) + case CSSSelector::PseudoClassNthLastOfType: + if (!selector.parseNth()) break; - if (Element* parentElement = element->parentElement()) { - if (m_mode == ResolvingStyle) - parentElement->setChildrenAffectedByBackwardPositionalRules(); + if (Element* parentElement = element.parentElement()) { + addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules); + if (!parentElement->isFinishedParsingChildren()) return false; - int count = 1 + countElementsOfTypeAfter(element, element->tagQName()); - if (selector->matchNth(count)) + int count = 1 + countElementsOfTypeAfter(element, element.tagQName()); + if (selector.matchNth(count)) return true; } break; - case CSSSelector::PseudoTarget: - if (element == element->document().cssTarget()) + case CSSSelector::PseudoClassTarget: + if (&element == element.document().cssTarget()) return true; break; - case CSSSelector::PseudoAny: + case CSSSelector::PseudoClassAny: { - SelectorCheckingContext subContext(context); - subContext.isSubSelector = true; - PseudoId ignoreDynamicPseudo = NOPSEUDO; - for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) { - if (matchRecursively(subContext, ignoreDynamicPseudo) == SelectorMatches) + LocalContext subcontext(context); + subcontext.inFunctionalPseudoClass = true; + subcontext.pseudoElementEffective = false; + for (subcontext.selector = selector.selectorList()->first(); subcontext.selector; subcontext.selector = CSSSelectorList::next(subcontext.selector)) { + subcontext.firstSelectorOfTheFragment = subcontext.selector; + PseudoIdSet ignoreDynamicPseudo; + unsigned ingoredSpecificity = 0; + if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ingoredSpecificity).match == Match::SelectorMatches) return true; } } break; - case CSSSelector::PseudoAutofill: - if (!element->isFormControlElement()) - break; - if (HTMLInputElement* inputElement = element->toInputElement()) - return inputElement->isAutofilled(); - break; - case CSSSelector::PseudoAnyLink: - case CSSSelector::PseudoLink: + case CSSSelector::PseudoClassAutofill: + return isAutofilled(element); + case CSSSelector::PseudoClassAnyLink: + case CSSSelector::PseudoClassAnyLinkDeprecated: + case CSSSelector::PseudoClassLink: // :visited and :link matches are separated later when applying the style. Here both classes match all links... - return element->isLink(); - case CSSSelector::PseudoVisited: + return element.isLink(); + case CSSSelector::PseudoClassVisited: // ...except if :visited matching is disabled for ancestor/sibling matching. - return element->isLink() && context.visitedMatchType == VisitedMatchEnabled; - case CSSSelector::PseudoDrag: - if (m_mode == ResolvingStyle) { - if (context.elementStyle) - context.elementStyle->setAffectedByDrag(); - else - element->setChildrenAffectedByDrag(); - } - if (element->renderer() && element->renderer()->isDragging()) + // Inside functional pseudo class except for :not, :visited never matches. + if (context.inFunctionalPseudoClass) + return false; + return element.isLink() && context.visitedMatchType == VisitedMatchType::Enabled; + case CSSSelector::PseudoClassDrag: + addStyleRelation(checkingContext, element, Style::Relation::AffectedByDrag); + + if (element.renderer() && element.renderer()->isDragging()) return true; break; - case CSSSelector::PseudoFocus: + case CSSSelector::PseudoClassFocus: return matchesFocusPseudoClass(element); - case CSSSelector::PseudoHover: - // If we're in quirks mode, then hover should never match anchors with no - // href and *:hover should not match anything. This is important for sites like wsj.com. - if (m_strictParsing || context.isSubSelector || element->isLink()) { - if (m_mode == ResolvingStyle) { - if (context.elementStyle) - context.elementStyle->setAffectedByHover(); - else - element->setChildrenAffectedByHover(); - } - if (element->hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoHover)) + case CSSSelector::PseudoClassFocusWithin: + addStyleRelation(checkingContext, element, Style::Relation::AffectedByFocusWithin); + return element.hasFocusWithin(); + case CSSSelector::PseudoClassHover: + if (m_strictParsing || element.isLink() || canMatchHoverOrActiveInQuirksMode(context)) { + addStyleRelation(checkingContext, element, Style::Relation::AffectedByHover); + + // See the comment in generateElementIsHovered() in SelectorCompiler. + if (checkingContext.resolvingMode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && !context.isMatchElement) return true; - } - break; - case CSSSelector::PseudoActive: - // If we're in quirks mode, then :active should never match anchors with no - // href and *:active should not match anything. - if (m_strictParsing || context.isSubSelector || element->isLink()) { - if (m_mode == ResolvingStyle) { - if (context.elementStyle) - context.elementStyle->setAffectedByActive(); - else - element->setChildrenAffectedByActive(); - } - if (element->active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoActive)) + + if (element.hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassHover)) return true; } break; - case CSSSelector::PseudoEnabled: - if (element->isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element)) - return !element->isDisabledFormControl(); - break; - case CSSSelector::PseudoFullPageMedia: - return element->document().isMediaDocument(); - break; - case CSSSelector::PseudoDefault: - return element->isDefaultButtonForForm(); - case CSSSelector::PseudoDisabled: - if (element->isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element)) - return element->isDisabledFormControl(); - break; - case CSSSelector::PseudoReadOnly: - return element->matchesReadOnlyPseudoClass(); - case CSSSelector::PseudoReadWrite: - return element->matchesReadWritePseudoClass(); - case CSSSelector::PseudoOptional: - return element->isOptionalFormControl(); - case CSSSelector::PseudoRequired: - return element->isRequiredFormControl(); - case CSSSelector::PseudoValid: - element->document().setContainsValidityStyleRules(); - return element->willValidate() && element->isValidFormControlElement(); - case CSSSelector::PseudoInvalid: - element->document().setContainsValidityStyleRules(); - return element->willValidate() && !element->isValidFormControlElement(); - case CSSSelector::PseudoChecked: - { - // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that - // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just - // obey the CSS spec here in the test for matching the pseudo. - HTMLInputElement* inputElement = element->toInputElement(); - if (inputElement && inputElement->shouldAppearChecked() && !inputElement->shouldAppearIndeterminate()) - return true; - if (isHTMLOptionElement(element) && toHTMLOptionElement(element)->selected()) + case CSSSelector::PseudoClassActive: + if (m_strictParsing || element.isLink() || canMatchHoverOrActiveInQuirksMode(context)) { + addStyleRelation(checkingContext, element, Style::Relation::AffectedByActive); + + if (element.active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassActive)) return true; - break; } - case CSSSelector::PseudoIndeterminate: - return element->shouldAppearIndeterminate(); - case CSSSelector::PseudoRoot: - if (element == element->document().documentElement()) + break; + case CSSSelector::PseudoClassEnabled: + return matchesEnabledPseudoClass(element); + case CSSSelector::PseudoClassFullPageMedia: + return isMediaDocument(element); + case CSSSelector::PseudoClassDefault: + return matchesDefaultPseudoClass(element); + case CSSSelector::PseudoClassDisabled: + return matchesDisabledPseudoClass(element); + case CSSSelector::PseudoClassReadOnly: + return matchesReadOnlyPseudoClass(element); + case CSSSelector::PseudoClassReadWrite: + return matchesReadWritePseudoClass(element); + case CSSSelector::PseudoClassOptional: + return isOptionalFormControl(element); + case CSSSelector::PseudoClassRequired: + return isRequiredFormControl(element); + case CSSSelector::PseudoClassValid: + return isValid(element); + case CSSSelector::PseudoClassInvalid: + return isInvalid(element); + case CSSSelector::PseudoClassChecked: + return isChecked(element); + case CSSSelector::PseudoClassIndeterminate: + return matchesIndeterminatePseudoClass(element); + case CSSSelector::PseudoClassRoot: + if (&element == element.document().documentElement()) return true; break; - case CSSSelector::PseudoLang: + case CSSSelector::PseudoClassLang: { - AtomicString value; -#if ENABLE(VIDEO_TRACK) - if (element->isWebVTTElement()) - value = toWebVTTElement(element)->language(); - else -#endif - value = element->computeInheritedLanguage(); - const AtomicString& argument = selector->argument(); - if (value.isEmpty() || !value.startsWith(argument, false)) - break; - if (value.length() != argument.length() && value[argument.length()] != '-') - break; - return true; + ASSERT(selector.langArgumentList() && !selector.langArgumentList()->isEmpty()); + return matchesLangPseudoClass(element, *selector.langArgumentList()); } #if ENABLE(FULLSCREEN_API) - case CSSSelector::PseudoFullScreen: - // While a Document is in the fullscreen state, and the document's current fullscreen - // element is an element in the document, the 'full-screen' pseudoclass applies to - // that element. Also, an