summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/StyleBuilderConverter.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/StyleBuilderConverter.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/css/StyleBuilderConverter.h')
-rw-r--r--Source/WebCore/css/StyleBuilderConverter.h1455
1 files changed, 1455 insertions, 0 deletions
diff --git a/Source/WebCore/css/StyleBuilderConverter.h b/Source/WebCore/css/StyleBuilderConverter.h
new file mode 100644
index 000000000..482f8eb1c
--- /dev/null
+++ b/Source/WebCore/css/StyleBuilderConverter.h
@@ -0,0 +1,1455 @@
+/*
+ * Copyright (C) 2013 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 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 "BasicShapeFunctions.h"
+#include "CSSCalculationValue.h"
+#include "CSSContentDistributionValue.h"
+#include "CSSFontFeatureValue.h"
+#include "CSSFontVariationValue.h"
+#include "CSSFunctionValue.h"
+#include "CSSGridAutoRepeatValue.h"
+#include "CSSGridLineNamesValue.h"
+#include "CSSGridTemplateAreasValue.h"
+#include "CSSImageGeneratorValue.h"
+#include "CSSImageSetValue.h"
+#include "CSSImageValue.h"
+#include "CSSPrimitiveValue.h"
+#include "CSSReflectValue.h"
+#include "Frame.h"
+#include "LayoutUnit.h"
+#include "Length.h"
+#include "Pair.h"
+#include "QuotesData.h"
+#include "RuntimeEnabledFeatures.h"
+#include "SVGURIReference.h"
+#include "Settings.h"
+#include "StyleResolver.h"
+#include "StyleScrollSnapPoints.h"
+#include "TransformFunctions.h"
+#include <wtf/Optional.h>
+
+namespace WebCore {
+
+// Note that we assume the CSS parser only allows valid CSSValue types.
+class StyleBuilderConverter {
+public:
+ static Length convertLength(StyleResolver&, const CSSValue&);
+ static Length convertLengthOrAuto(StyleResolver&, const CSSValue&);
+ static Length convertLengthSizing(StyleResolver&, const CSSValue&);
+ static Length convertLengthMaxSizing(StyleResolver&, const CSSValue&);
+ template<typename T> static T convertComputedLength(StyleResolver&, const CSSValue&);
+ template<typename T> static T convertLineWidth(StyleResolver&, const CSSValue&);
+ static float convertSpacing(StyleResolver&, const CSSValue&);
+ static LengthSize convertRadius(StyleResolver&, const CSSValue&);
+ static LengthPoint convertObjectPosition(StyleResolver&, const CSSValue&);
+ static TextDecoration convertTextDecoration(StyleResolver&, const CSSValue&);
+ template<typename T> static T convertNumber(StyleResolver&, const CSSValue&);
+ template<typename T> static T convertNumberOrAuto(StyleResolver&, const CSSValue&);
+ static short convertWebkitHyphenateLimitLines(StyleResolver&, const CSSValue&);
+ template<CSSPropertyID> static NinePieceImage convertBorderImage(StyleResolver&, CSSValue&);
+ template<CSSPropertyID> static NinePieceImage convertBorderMask(StyleResolver&, CSSValue&);
+ template<CSSPropertyID> static RefPtr<StyleImage> convertStyleImage(StyleResolver&, CSSValue&);
+ static TransformOperations convertTransform(StyleResolver&, const CSSValue&);
+ static String convertString(StyleResolver&, const CSSValue&);
+ static String convertStringOrAuto(StyleResolver&, const CSSValue&);
+ static String convertStringOrNone(StyleResolver&, const CSSValue&);
+ static TextEmphasisPosition convertTextEmphasisPosition(StyleResolver&, const CSSValue&);
+ static ETextAlign convertTextAlign(StyleResolver&, const CSSValue&);
+ static RefPtr<ClipPathOperation> convertClipPath(StyleResolver&, const CSSValue&);
+ static EResize convertResize(StyleResolver&, const CSSValue&);
+ static int convertMarqueeRepetition(StyleResolver&, const CSSValue&);
+ static int convertMarqueeSpeed(StyleResolver&, const CSSValue&);
+ static Ref<QuotesData> convertQuotes(StyleResolver&, const CSSValue&);
+ static TextUnderlinePosition convertTextUnderlinePosition(StyleResolver&, const CSSValue&);
+ static RefPtr<StyleReflection> convertReflection(StyleResolver&, const CSSValue&);
+ static IntSize convertInitialLetter(StyleResolver&, const CSSValue&);
+ static float convertTextStrokeWidth(StyleResolver&, const CSSValue&);
+ static LineBoxContain convertLineBoxContain(StyleResolver&, const CSSValue&);
+ static TextDecorationSkip convertTextDecorationSkip(StyleResolver&, const CSSValue&);
+ static RefPtr<ShapeValue> convertShapeValue(StyleResolver&, CSSValue&);
+#if ENABLE(CSS_SCROLL_SNAP)
+ static ScrollSnapType convertScrollSnapType(StyleResolver&, const CSSValue&);
+ static ScrollSnapAlign convertScrollSnapAlign(StyleResolver&, const CSSValue&);
+#endif
+ static GridTrackSize convertGridTrackSize(StyleResolver&, const CSSValue&);
+ static Vector<GridTrackSize> convertGridTrackSizeList(StyleResolver&, const CSSValue&);
+ static std::optional<GridPosition> convertGridPosition(StyleResolver&, const CSSValue&);
+ static GridAutoFlow convertGridAutoFlow(StyleResolver&, const CSSValue&);
+ static std::optional<Length> convertWordSpacing(StyleResolver&, const CSSValue&);
+ static std::optional<float> convertPerspective(StyleResolver&, const CSSValue&);
+ static std::optional<Length> convertMarqueeIncrement(StyleResolver&, const CSSValue&);
+ static std::optional<FilterOperations> convertFilterOperations(StyleResolver&, const CSSValue&);
+#if PLATFORM(IOS)
+ static bool convertTouchCallout(StyleResolver&, const CSSValue&);
+#endif
+#if ENABLE(TOUCH_EVENTS)
+ static Color convertTapHighlightColor(StyleResolver&, const CSSValue&);
+#endif
+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
+ static bool convertOverflowScrolling(StyleResolver&, const CSSValue&);
+#endif
+ static FontFeatureSettings convertFontFeatureSettings(StyleResolver&, const CSSValue&);
+#if ENABLE(VARIATION_FONTS)
+ static FontVariationSettings convertFontVariationSettings(StyleResolver&, const CSSValue&);
+#endif
+ static SVGLengthValue convertSVGLengthValue(StyleResolver&, const CSSValue&);
+ static Vector<SVGLengthValue> convertSVGLengthVector(StyleResolver&, const CSSValue&);
+ static Vector<SVGLengthValue> convertStrokeDashArray(StyleResolver&, const CSSValue&);
+ static PaintOrder convertPaintOrder(StyleResolver&, const CSSValue&);
+ static float convertOpacity(StyleResolver&, const CSSValue&);
+ static String convertSVGURIReference(StyleResolver&, const CSSValue&);
+ static Color convertSVGColor(StyleResolver&, const CSSValue&);
+ static StyleSelfAlignmentData convertSelfOrDefaultAlignmentData(StyleResolver&, const CSSValue&);
+ static StyleContentAlignmentData convertContentAlignmentData(StyleResolver&, const CSSValue&);
+ static EGlyphOrientation convertGlyphOrientation(StyleResolver&, const CSSValue&);
+ static EGlyphOrientation convertGlyphOrientationOrAuto(StyleResolver&, const CSSValue&);
+ static std::optional<Length> convertLineHeight(StyleResolver&, const CSSValue&, float multiplier = 1.f);
+ static FontSynthesis convertFontSynthesis(StyleResolver&, const CSSValue&);
+
+ static BreakBetween convertPageBreakBetween(StyleResolver&, const CSSValue&);
+ static BreakInside convertPageBreakInside(StyleResolver&, const CSSValue&);
+ static BreakBetween convertColumnBreakBetween(StyleResolver&, const CSSValue&);
+ static BreakInside convertColumnBreakInside(StyleResolver&, const CSSValue&);
+#if ENABLE(CSS_REGIONS)
+ static BreakBetween convertRegionBreakBetween(StyleResolver&, const CSSValue&);
+ static BreakInside convertRegionBreakInside(StyleResolver&, const CSSValue&);
+#endif
+
+ static HangingPunctuation convertHangingPunctuation(StyleResolver&, const CSSValue&);
+
+ static Length convertPositionComponentX(StyleResolver&, const CSSValue&);
+ static Length convertPositionComponentY(StyleResolver&, const CSSValue&);
+
+private:
+ friend class StyleBuilderCustom;
+
+ static Length convertToRadiusLength(CSSToLengthConversionData&, const CSSPrimitiveValue&);
+ static TextEmphasisPosition valueToEmphasisPosition(const CSSPrimitiveValue&);
+ static TextDecorationSkip valueToDecorationSkip(const CSSPrimitiveValue&);
+#if ENABLE(CSS_SCROLL_SNAP)
+ static Length parseSnapCoordinate(StyleResolver&, const CSSValue&);
+#endif
+
+ static Length convertTo100PercentMinusLength(const Length&);
+ template<CSSValueID, CSSValueID> static Length convertPositionComponent(StyleResolver&, const CSSPrimitiveValue&);
+
+ static GridLength createGridTrackBreadth(const CSSPrimitiveValue&, StyleResolver&);
+ static GridTrackSize createGridTrackSize(const CSSValue&, StyleResolver&);
+ struct TracksData;
+ static bool createGridTrackList(const CSSValue&, TracksData&, StyleResolver&);
+ static bool createGridPosition(const CSSValue&, GridPosition&);
+ static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap&, NamedGridLinesMap&, GridTrackSizingDirection);
+ static CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(StyleResolver&);
+};
+
+inline Length StyleBuilderConverter::convertLength(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
+ styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
+ : styleResolver.state().cssToLengthConversionData();
+
+ if (primitiveValue.isLength()) {
+ Length length = primitiveValue.computeLength<Length>(conversionData);
+ length.setHasQuirk(primitiveValue.isQuirkValue());
+ return length;
+ }
+
+ if (primitiveValue.isPercentage())
+ return Length(primitiveValue.doubleValue(), Percent);
+
+ if (primitiveValue.isCalculatedPercentageWithLength())
+ return Length(primitiveValue.cssCalcValue()->createCalculationValue(conversionData));
+
+ ASSERT_NOT_REACHED();
+ return Length(0, Fixed);
+}
+
+inline Length StyleBuilderConverter::convertLengthOrAuto(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
+ return Length(Auto);
+ return convertLength(styleResolver, value);
+}
+
+inline Length StyleBuilderConverter::convertLengthSizing(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ switch (primitiveValue.valueID()) {
+ case CSSValueInvalid:
+ return convertLength(styleResolver, value);
+ case CSSValueIntrinsic:
+ return Length(Intrinsic);
+ case CSSValueMinIntrinsic:
+ return Length(MinIntrinsic);
+ case CSSValueWebkitMinContent:
+ return Length(MinContent);
+ case CSSValueWebkitMaxContent:
+ return Length(MaxContent);
+ case CSSValueWebkitFillAvailable:
+ return Length(FillAvailable);
+ case CSSValueWebkitFitContent:
+ return Length(FitContent);
+ case CSSValueAuto:
+ return Length(Auto);
+ default:
+ ASSERT_NOT_REACHED();
+ return Length();
+ }
+}
+
+inline Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
+ return Length(Undefined);
+ return convertLengthSizing(styleResolver, value);
+}
+
+template<typename T>
+inline T StyleBuilderConverter::convertComputedLength(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return downcast<CSSPrimitiveValue>(value).computeLength<T>(styleResolver.state().cssToLengthConversionData());
+}
+
+template<typename T>
+inline T StyleBuilderConverter::convertLineWidth(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ switch (primitiveValue.valueID()) {
+ case CSSValueThin:
+ return 1;
+ case CSSValueMedium:
+ return 3;
+ case CSSValueThick:
+ return 5;
+ case CSSValueInvalid: {
+ // Any original result that was >= 1 should not be allowed to fall below 1.
+ // This keeps border lines from vanishing.
+ T result = convertComputedLength<T>(styleResolver, value);
+ if (styleResolver.state().style()->effectiveZoom() < 1.0f && result < 1.0) {
+ T originalLength = primitiveValue.computeLength<T>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0));
+ if (originalLength >= 1.0)
+ return 1;
+ }
+ float minimumLineWidth = 1 / styleResolver.document().deviceScaleFactor();
+ if (result > 0 && result < minimumLineWidth)
+ return minimumLineWidth;
+ return floorToDevicePixel(result, styleResolver.document().deviceScaleFactor());
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+inline float StyleBuilderConverter::convertSpacing(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueNormal)
+ return 0.f;
+
+ CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
+ styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
+ : styleResolver.state().cssToLengthConversionData();
+ return primitiveValue.computeLength<float>(conversionData);
+}
+
+inline Length StyleBuilderConverter::convertToRadiusLength(CSSToLengthConversionData& conversionData, const CSSPrimitiveValue& value)
+{
+ if (value.isPercentage())
+ return Length(value.doubleValue(), Percent);
+ if (value.isCalculatedPercentageWithLength())
+ return Length(value.cssCalcValue()->createCalculationValue(conversionData));
+ return value.computeLength<Length>(conversionData);
+}
+
+inline LengthSize StyleBuilderConverter::convertRadius(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto* pair = downcast<CSSPrimitiveValue>(value).pairValue();
+ if (!pair || !pair->first() || !pair->second())
+ return { { 0, Fixed }, { 0, Fixed } };
+
+ CSSToLengthConversionData conversionData = styleResolver.state().cssToLengthConversionData();
+ LengthSize radius { convertToRadiusLength(conversionData, *pair->first()), convertToRadiusLength(conversionData, *pair->second()) };
+
+ ASSERT(!radius.width.isNegative());
+ ASSERT(!radius.height.isNegative());
+ if (radius.width.isZero() || radius.height.isZero())
+ return { { 0, Fixed }, { 0, Fixed } };
+
+ return radius;
+}
+
+inline Length StyleBuilderConverter::convertTo100PercentMinusLength(const Length& length)
+{
+ if (length.isPercent())
+ return Length(100 - length.value(), Percent);
+
+ // Turn this into a calc expression: calc(100% - length)
+ auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
+ auto rhs = std::make_unique<CalcExpressionLength>(length);
+ auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
+ return Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
+}
+
+inline Length StyleBuilderConverter::convertPositionComponentX(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return convertPositionComponent<CSSValueLeft, CSSValueRight>(styleResolver, downcast<CSSPrimitiveValue>(value));
+}
+
+inline Length StyleBuilderConverter::convertPositionComponentY(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return convertPositionComponent<CSSValueTop, CSSValueBottom>(styleResolver, downcast<CSSPrimitiveValue>(value));
+}
+
+template<CSSValueID cssValueFor0, CSSValueID cssValueFor100>
+inline Length StyleBuilderConverter::convertPositionComponent(StyleResolver& styleResolver, const CSSPrimitiveValue& value)
+{
+ Length length;
+
+ auto* lengthValue = &value;
+ bool relativeToTrailingEdge = false;
+
+ if (value.isPair()) {
+ auto& first = *value.pairValue()->first();
+ if (first.valueID() == CSSValueRight || first.valueID() == CSSValueBottom)
+ relativeToTrailingEdge = true;
+ lengthValue = value.pairValue()->second();
+ }
+
+ if (value.isValueID()) {
+ switch (value.valueID()) {
+ case cssValueFor0:
+ return Length(0, Percent);
+ case cssValueFor100:
+ return Length(100, Percent);
+ case CSSValueCenter:
+ return Length(50, Percent);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ length = convertLength(styleResolver, *lengthValue);
+
+ if (relativeToTrailingEdge)
+ length = convertTo100PercentMinusLength(length);
+
+ return length;
+}
+
+inline LengthPoint StyleBuilderConverter::convertObjectPosition(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ Pair* pair = primitiveValue.pairValue();
+ if (!pair || !pair->first() || !pair->second())
+ return RenderStyle::initialObjectPosition();
+
+ Length lengthX = convertPositionComponent<CSSValueLeft, CSSValueRight>(styleResolver, *pair->first());
+ Length lengthY = convertPositionComponent<CSSValueTop, CSSValueBottom>(styleResolver, *pair->second());
+
+ return LengthPoint(lengthX, lengthY);
+}
+
+inline TextDecoration StyleBuilderConverter::convertTextDecoration(StyleResolver&, const CSSValue& value)
+{
+ TextDecoration result = RenderStyle::initialTextDecoration();
+ if (is<CSSValueList>(value)) {
+ for (auto& currentValue : downcast<CSSValueList>(value))
+ result |= downcast<CSSPrimitiveValue>(currentValue.get());
+ }
+ return result;
+}
+
+template<typename T>
+inline T StyleBuilderConverter::convertNumber(StyleResolver&, const CSSValue& value)
+{
+ return downcast<CSSPrimitiveValue>(value).value<T>(CSSPrimitiveValue::CSS_NUMBER);
+}
+
+template<typename T>
+inline T StyleBuilderConverter::convertNumberOrAuto(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
+ return -1;
+ return convertNumber<T>(styleResolver, value);
+}
+
+inline short StyleBuilderConverter::convertWebkitHyphenateLimitLines(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueNoLimit)
+ return -1;
+ return primitiveValue.value<short>(CSSPrimitiveValue::CSS_NUMBER);
+}
+
+template<CSSPropertyID property>
+inline NinePieceImage StyleBuilderConverter::convertBorderImage(StyleResolver& styleResolver, CSSValue& value)
+{
+ NinePieceImage image;
+ styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
+ return image;
+}
+
+template<CSSPropertyID property>
+inline NinePieceImage StyleBuilderConverter::convertBorderMask(StyleResolver& styleResolver, CSSValue& value)
+{
+ NinePieceImage image;
+ image.setMaskDefaults();
+ styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
+ return image;
+}
+
+template<CSSPropertyID>
+inline RefPtr<StyleImage> StyleBuilderConverter::convertStyleImage(StyleResolver& styleResolver, CSSValue& value)
+{
+ return styleResolver.styleImage(value);
+}
+
+inline TransformOperations StyleBuilderConverter::convertTransform(StyleResolver& styleResolver, const CSSValue& value)
+{
+ TransformOperations operations;
+ transformsForValue(value, styleResolver.state().cssToLengthConversionData(), operations);
+ return operations;
+}
+
+inline String StyleBuilderConverter::convertString(StyleResolver&, const CSSValue& value)
+{
+ return downcast<CSSPrimitiveValue>(value).stringValue();
+}
+
+inline String StyleBuilderConverter::convertStringOrAuto(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
+ return nullAtom;
+ return convertString(styleResolver, value);
+}
+
+inline String StyleBuilderConverter::convertStringOrNone(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
+ return nullAtom;
+ return convertString(styleResolver, value);
+}
+
+inline TextEmphasisPosition StyleBuilderConverter::valueToEmphasisPosition(const CSSPrimitiveValue& primitiveValue)
+{
+ ASSERT(primitiveValue.isValueID());
+
+ switch (primitiveValue.valueID()) {
+ case CSSValueOver:
+ return TextEmphasisPositionOver;
+ case CSSValueUnder:
+ return TextEmphasisPositionUnder;
+ case CSSValueLeft:
+ return TextEmphasisPositionLeft;
+ case CSSValueRight:
+ return TextEmphasisPositionRight;
+ default:
+ break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return RenderStyle::initialTextEmphasisPosition();
+}
+
+inline TextEmphasisPosition StyleBuilderConverter::convertTextEmphasisPosition(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value))
+ return valueToEmphasisPosition(downcast<CSSPrimitiveValue>(value));
+
+ TextEmphasisPosition position = 0;
+ for (auto& currentValue : downcast<CSSValueList>(value))
+ position |= valueToEmphasisPosition(downcast<CSSPrimitiveValue>(currentValue.get()));
+ return position;
+}
+
+inline ETextAlign StyleBuilderConverter::convertTextAlign(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ ASSERT(primitiveValue.isValueID());
+
+ if (primitiveValue.valueID() != CSSValueWebkitMatchParent)
+ return primitiveValue;
+
+ auto* parentStyle = styleResolver.parentStyle();
+ if (parentStyle->textAlign() == TASTART)
+ return parentStyle->isLeftToRightDirection() ? LEFT : RIGHT;
+ if (parentStyle->textAlign() == TAEND)
+ return parentStyle->isLeftToRightDirection() ? RIGHT : LEFT;
+ return parentStyle->textAlign();
+}
+
+inline RefPtr<ClipPathOperation> StyleBuilderConverter::convertClipPath(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_URI) {
+ String cssURLValue = primitiveValue.stringValue();
+ 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)
+ return ReferenceClipPathOperation::create(cssURLValue, url.fragmentIdentifier());
+ }
+ ASSERT(primitiveValue.valueID() == CSSValueNone);
+ return nullptr;
+ }
+
+ CSSBoxType referenceBox = BoxMissing;
+ RefPtr<ClipPathOperation> operation;
+
+ for (auto& currentValue : downcast<CSSValueList>(value)) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
+ if (primitiveValue.isShape()) {
+ ASSERT(!operation);
+ operation = ShapeClipPathOperation::create(basicShapeForValue(styleResolver.state().cssToLengthConversionData(), *primitiveValue.shapeValue()));
+ } else {
+ ASSERT(primitiveValue.valueID() == CSSValueContentBox
+ || primitiveValue.valueID() == CSSValueBorderBox
+ || primitiveValue.valueID() == CSSValuePaddingBox
+ || primitiveValue.valueID() == CSSValueMarginBox
+ || primitiveValue.valueID() == CSSValueFill
+ || primitiveValue.valueID() == CSSValueStroke
+ || primitiveValue.valueID() == CSSValueViewBox);
+ ASSERT(referenceBox == BoxMissing);
+ referenceBox = primitiveValue;
+ }
+ }
+ if (operation)
+ downcast<ShapeClipPathOperation>(*operation).setReferenceBox(referenceBox);
+ else {
+ ASSERT(referenceBox != BoxMissing);
+ operation = BoxClipPathOperation::create(referenceBox);
+ }
+
+ return operation;
+}
+
+inline EResize StyleBuilderConverter::convertResize(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+
+ EResize resize = RESIZE_NONE;
+ if (primitiveValue.valueID() == CSSValueAuto)
+ resize = styleResolver.settings().textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
+ else
+ resize = primitiveValue;
+
+ return resize;
+}
+
+inline int StyleBuilderConverter::convertMarqueeRepetition(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueInfinite)
+ return -1; // -1 means repeat forever.
+
+ ASSERT(primitiveValue.isNumber());
+ return primitiveValue.intValue();
+}
+
+inline int StyleBuilderConverter::convertMarqueeSpeed(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ int speed = 85;
+ if (CSSValueID ident = primitiveValue.valueID()) {
+ switch (ident) {
+ case CSSValueSlow:
+ speed = 500; // 500 msec.
+ break;
+ case CSSValueNormal:
+ speed = 85; // 85msec. The WinIE default.
+ break;
+ case CSSValueFast:
+ speed = 10; // 10msec. Super fast.
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (primitiveValue.isTime())
+ speed = primitiveValue.computeTime<int, CSSPrimitiveValue::Milliseconds>();
+ else {
+ // For scrollamount support.
+ ASSERT(primitiveValue.isNumber());
+ speed = primitiveValue.intValue();
+ }
+ return speed;
+}
+
+inline Ref<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return QuotesData::create(Vector<std::pair<String, String>>());
+ }
+
+ auto& list = downcast<CSSValueList>(value);
+ Vector<std::pair<String, String>> quotes;
+ quotes.reserveInitialCapacity(list.length() / 2);
+ for (unsigned i = 0; i < list.length(); i += 2) {
+ const CSSValue* first = list.itemWithoutBoundsCheck(i);
+ // item() returns null if out of bounds so this is safe.
+ const CSSValue* second = list.item(i + 1);
+ if (!second)
+ break;
+ String startQuote = downcast<CSSPrimitiveValue>(*first).stringValue();
+ String endQuote = downcast<CSSPrimitiveValue>(*second).stringValue();
+ quotes.append(std::make_pair(startQuote, endQuote));
+ }
+ return QuotesData::create(quotes);
+}
+
+inline TextUnderlinePosition StyleBuilderConverter::convertTextUnderlinePosition(StyleResolver&, const CSSValue& value)
+{
+ // This is true if value is 'auto' or 'alphabetic'.
+ if (is<CSSPrimitiveValue>(value))
+ return downcast<CSSPrimitiveValue>(value);
+
+ unsigned combinedPosition = 0;
+ for (auto& currentValue : downcast<CSSValueList>(value)) {
+ TextUnderlinePosition position = downcast<CSSPrimitiveValue>(currentValue.get());
+ combinedPosition |= position;
+ }
+ return static_cast<TextUnderlinePosition>(combinedPosition);
+}
+
+inline RefPtr<StyleReflection> StyleBuilderConverter::convertReflection(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return nullptr;
+ }
+
+ auto& reflectValue = downcast<CSSReflectValue>(value);
+
+ auto reflection = StyleReflection::create();
+ reflection->setDirection(reflectValue.direction());
+ reflection->setOffset(reflectValue.offset().convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData()));
+
+ NinePieceImage mask;
+ mask.setMaskDefaults();
+ styleResolver.styleMap()->mapNinePieceImage(CSSPropertyWebkitBoxReflect, reflectValue.mask(), mask);
+ reflection->setMask(mask);
+
+ return WTFMove(reflection);
+}
+
+inline IntSize StyleBuilderConverter::convertInitialLetter(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+
+ if (primitiveValue.valueID() == CSSValueNormal)
+ return IntSize();
+
+ Pair* pair = primitiveValue.pairValue();
+ ASSERT(pair);
+ ASSERT(pair->first());
+ ASSERT(pair->second());
+
+ return IntSize(pair->first()->intValue(), pair->second()->intValue());
+}
+
+inline float StyleBuilderConverter::convertTextStrokeWidth(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+
+ float width = 0;
+ switch (primitiveValue.valueID()) {
+ case CSSValueThin:
+ case CSSValueMedium:
+ case CSSValueThick: {
+ double result = 1.0 / 48;
+ if (primitiveValue.valueID() == CSSValueMedium)
+ result *= 3;
+ else if (primitiveValue.valueID() == CSSValueThick)
+ result *= 5;
+ Ref<CSSPrimitiveValue> emsValue(CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS));
+ width = convertComputedLength<float>(styleResolver, emsValue);
+ break;
+ }
+ case CSSValueInvalid: {
+ width = convertComputedLength<float>(styleResolver, primitiveValue);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+
+ return width;
+}
+
+inline LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return LineBoxContainNone;
+ }
+
+ return downcast<CSSLineBoxContainValue>(value).value();
+}
+
+inline TextDecorationSkip StyleBuilderConverter::valueToDecorationSkip(const CSSPrimitiveValue& primitiveValue)
+{
+ ASSERT(primitiveValue.isValueID());
+
+ switch (primitiveValue.valueID()) {
+ case CSSValueAuto:
+ return TextDecorationSkipAuto;
+ case CSSValueNone:
+ return TextDecorationSkipNone;
+ case CSSValueInk:
+ return TextDecorationSkipInk;
+ case CSSValueObjects:
+ return TextDecorationSkipObjects;
+ default:
+ break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return TextDecorationSkipNone;
+}
+
+inline TextDecorationSkip StyleBuilderConverter::convertTextDecorationSkip(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value))
+ return valueToDecorationSkip(downcast<CSSPrimitiveValue>(value));
+
+ TextDecorationSkip skip = TextDecorationSkipNone;
+ for (auto& currentValue : downcast<CSSValueList>(value))
+ skip |= valueToDecorationSkip(downcast<CSSPrimitiveValue>(currentValue.get()));
+ return skip;
+}
+
+static inline bool isImageShape(const CSSValue& value)
+{
+ return is<CSSImageValue>(value) || is<CSSImageSetValue>(value) || is<CSSImageGeneratorValue>(value);
+}
+
+inline RefPtr<ShapeValue> StyleBuilderConverter::convertShapeValue(StyleResolver& styleResolver, CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return nullptr;
+ }
+
+ if (isImageShape(value))
+ return ShapeValue::create(styleResolver.styleImage(value).releaseNonNull());
+
+ RefPtr<BasicShape> shape;
+ CSSBoxType referenceBox = BoxMissing;
+ for (auto& currentValue : downcast<CSSValueList>(value)) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
+ if (primitiveValue.isShape())
+ shape = basicShapeForValue(styleResolver.state().cssToLengthConversionData(), *primitiveValue.shapeValue());
+ else if (primitiveValue.valueID() == CSSValueContentBox
+ || primitiveValue.valueID() == CSSValueBorderBox
+ || primitiveValue.valueID() == CSSValuePaddingBox
+ || primitiveValue.valueID() == CSSValueMarginBox)
+ referenceBox = primitiveValue;
+ else {
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ }
+
+ if (shape)
+ return ShapeValue::create(shape.releaseNonNull(), referenceBox);
+
+ if (referenceBox != BoxMissing)
+ return ShapeValue::create(referenceBox);
+
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+#if ENABLE(CSS_SCROLL_SNAP)
+
+inline ScrollSnapType StyleBuilderConverter::convertScrollSnapType(StyleResolver&, const CSSValue& value)
+{
+ ScrollSnapType type;
+ auto& values = downcast<CSSValueList>(value);
+ auto& firstValue = downcast<CSSPrimitiveValue>(*values.item(0));
+ if (values.length() == 2) {
+ type.axis = firstValue;
+ type.strictness = downcast<CSSPrimitiveValue>(*values.item(1));
+ return type;
+ }
+
+ switch (firstValue.valueID()) {
+ case CSSValueNone:
+ case CSSValueMandatory:
+ case CSSValueProximity:
+ type.strictness = firstValue;
+ break;
+ default:
+ type.axis = firstValue;
+ type.strictness = ScrollSnapStrictness::Proximity;
+ break;
+ }
+ return type;
+}
+
+inline ScrollSnapAlign StyleBuilderConverter::convertScrollSnapAlign(StyleResolver&, const CSSValue& value)
+{
+ auto& values = downcast<CSSValueList>(value);
+ ScrollSnapAlign alignment;
+ alignment.x = downcast<CSSPrimitiveValue>(*values.item(0));
+ if (values.length() == 1)
+ alignment.y = alignment.x;
+ else
+ alignment.y = downcast<CSSPrimitiveValue>(*values.item(1));
+ return alignment;
+}
+
+#endif
+
+inline GridLength StyleBuilderConverter::createGridTrackBreadth(const CSSPrimitiveValue& primitiveValue, StyleResolver& styleResolver)
+{
+ if (primitiveValue.valueID() == CSSValueWebkitMinContent)
+ return Length(MinContent);
+
+ if (primitiveValue.valueID() == CSSValueWebkitMaxContent)
+ return Length(MaxContent);
+
+ // Fractional unit.
+ if (primitiveValue.isFlex())
+ return GridLength(primitiveValue.doubleValue());
+
+ return primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | AutoConversion>(styleResolver.state().cssToLengthConversionData());
+}
+
+inline GridTrackSize StyleBuilderConverter::createGridTrackSize(const CSSValue& value, StyleResolver& styleResolver)
+{
+ if (is<CSSPrimitiveValue>(value))
+ return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(value), styleResolver));
+
+ ASSERT(is<CSSFunctionValue>(value));
+ const auto& function = downcast<CSSFunctionValue>(value);
+
+ if (function.length() == 1)
+ return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), styleResolver), FitContentTrackSizing);
+
+ ASSERT_WITH_SECURITY_IMPLICATION(function.length() == 2);
+ GridLength minTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), styleResolver));
+ GridLength maxTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(1)), styleResolver));
+ return GridTrackSize(minTrackBreadth, maxTrackBreadth);
+}
+
+static void createGridLineNamesList(const CSSValue& value, unsigned currentNamedGridLine, NamedGridLinesMap& namedGridLines, OrderedNamedGridLinesMap& orderedNamedGridLines)
+{
+ ASSERT(value.isGridLineNamesValue());
+
+ for (auto& namedGridLineValue : downcast<CSSGridLineNamesValue>(value)) {
+ String namedGridLine = downcast<CSSPrimitiveValue>(namedGridLineValue.get()).stringValue();
+ auto result = namedGridLines.add(namedGridLine, Vector<unsigned>());
+ result.iterator->value.append(currentNamedGridLine);
+ auto orderedResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
+ orderedResult.iterator->value.append(namedGridLine);
+ }
+}
+
+struct StyleBuilderConverter::TracksData {
+ WTF_MAKE_NONCOPYABLE(TracksData); WTF_MAKE_FAST_ALLOCATED;
+public:
+ TracksData() = default;
+
+ Vector<GridTrackSize> m_trackSizes;
+ NamedGridLinesMap m_namedGridLines;
+ OrderedNamedGridLinesMap m_orderedNamedGridLines;
+ Vector<GridTrackSize> m_autoRepeatTrackSizes;
+ NamedGridLinesMap m_autoRepeatNamedGridLines;
+ OrderedNamedGridLinesMap m_autoRepeatOrderedNamedGridLines;
+ unsigned m_autoRepeatInsertionPoint { RenderStyle::initialGridAutoRepeatInsertionPoint() };
+ AutoRepeatType m_autoRepeatType { RenderStyle::initialGridAutoRepeatType() };
+};
+
+inline bool StyleBuilderConverter::createGridTrackList(const CSSValue& value, TracksData& tracksData, StyleResolver& styleResolver)
+{
+ // Handle 'none'.
+ if (is<CSSPrimitiveValue>(value))
+ return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone;
+
+ if (!is<CSSValueList>(value))
+ return false;
+
+ unsigned currentNamedGridLine = 0;
+ for (auto& currentValue : downcast<CSSValueList>(value)) {
+ if (is<CSSGridLineNamesValue>(currentValue.get())) {
+ createGridLineNamesList(currentValue.get(), currentNamedGridLine, tracksData.m_namedGridLines, tracksData.m_orderedNamedGridLines);
+ continue;
+ }
+
+ if (is<CSSGridAutoRepeatValue>(currentValue)) {
+ ASSERT(tracksData.m_autoRepeatTrackSizes.isEmpty());
+ unsigned autoRepeatIndex = 0;
+ CSSValueID autoRepeatID = downcast<CSSGridAutoRepeatValue>(currentValue.get()).autoRepeatID();
+ ASSERT(autoRepeatID == CSSValueAutoFill || autoRepeatID == CSSValueAutoFit);
+ tracksData.m_autoRepeatType = autoRepeatID == CSSValueAutoFill ? AutoFill : AutoFit;
+ for (auto& autoRepeatValue : downcast<CSSValueList>(currentValue.get())) {
+ if (is<CSSGridLineNamesValue>(autoRepeatValue.get())) {
+ createGridLineNamesList(autoRepeatValue.get(), autoRepeatIndex, tracksData.m_autoRepeatNamedGridLines, tracksData.m_autoRepeatOrderedNamedGridLines);
+ continue;
+ }
+ ++autoRepeatIndex;
+ tracksData.m_autoRepeatTrackSizes.append(createGridTrackSize(autoRepeatValue.get(), styleResolver));
+ }
+ tracksData.m_autoRepeatInsertionPoint = currentNamedGridLine++;
+ continue;
+ }
+
+ ++currentNamedGridLine;
+ tracksData.m_trackSizes.append(createGridTrackSize(currentValue, styleResolver));
+ }
+
+ // The parser should have rejected any <track-list> without any <track-size> as
+ // this is not conformant to the syntax.
+ ASSERT(!tracksData.m_trackSizes.isEmpty() || !tracksData.m_autoRepeatTrackSizes.isEmpty());
+ return true;
+}
+
+inline bool StyleBuilderConverter::createGridPosition(const CSSValue& value, GridPosition& position)
+{
+ // We accept the specification's grammar:
+ // auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
+ if (is<CSSPrimitiveValue>(value)) {
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ // We translate <ident> to <string> during parsing as it makes handling it simpler.
+ if (primitiveValue.isString()) {
+ position.setNamedGridArea(primitiveValue.stringValue());
+ return true;
+ }
+
+ ASSERT(primitiveValue.valueID() == CSSValueAuto);
+ return true;
+ }
+
+ auto& values = downcast<CSSValueList>(value);
+ ASSERT(values.length());
+
+ auto it = values.begin();
+ const CSSPrimitiveValue* currentValue = &downcast<CSSPrimitiveValue>(it->get());
+ bool isSpanPosition = false;
+ if (currentValue->valueID() == CSSValueSpan) {
+ isSpanPosition = true;
+ ++it;
+ currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
+ }
+
+ int gridLineNumber = 0;
+ if (currentValue && currentValue->isNumber()) {
+ gridLineNumber = currentValue->intValue();
+ ++it;
+ currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
+ }
+
+ String gridLineName;
+ if (currentValue && currentValue->isString()) {
+ gridLineName = currentValue->stringValue();
+ ++it;
+ }
+
+ ASSERT(it == values.end());
+ if (isSpanPosition)
+ position.setSpanPosition(gridLineNumber ? gridLineNumber : 1, gridLineName);
+ else
+ position.setExplicitPosition(gridLineNumber, gridLineName);
+
+ return true;
+}
+
+inline void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
+{
+ for (auto& area : namedGridAreas) {
+ GridSpan areaSpan = direction == ForRows ? area.value.rows : area.value.columns;
+ {
+ auto& startVector = namedGridLines.add(area.key + "-start", Vector<unsigned>()).iterator->value;
+ startVector.append(areaSpan.startLine());
+ std::sort(startVector.begin(), startVector.end());
+ }
+ {
+ auto& endVector = namedGridLines.add(area.key + "-end", Vector<unsigned>()).iterator->value;
+ endVector.append(areaSpan.endLine());
+ std::sort(endVector.begin(), endVector.end());
+ }
+ }
+}
+
+inline Vector<GridTrackSize> StyleBuilderConverter::convertGridTrackSizeList(StyleResolver& styleResolver, const CSSValue& value)
+{
+ ASSERT(value.isValueList());
+ auto& valueList = downcast<CSSValueList>(value);
+ Vector<GridTrackSize> trackSizes;
+ trackSizes.reserveInitialCapacity(valueList.length());
+ for (auto& currValue : valueList) {
+ ASSERT(!currValue->isGridLineNamesValue());
+ ASSERT(!currValue->isGridAutoRepeatValue());
+ trackSizes.uncheckedAppend(convertGridTrackSize(styleResolver, currValue));
+ }
+ return trackSizes;
+}
+
+inline GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return createGridTrackSize(value, styleResolver);
+}
+
+inline std::optional<GridPosition> StyleBuilderConverter::convertGridPosition(StyleResolver&, const CSSValue& value)
+{
+ GridPosition gridPosition;
+ if (createGridPosition(value, gridPosition))
+ return gridPosition;
+ return std::nullopt;
+}
+
+inline GridAutoFlow StyleBuilderConverter::convertGridAutoFlow(StyleResolver&, const CSSValue& value)
+{
+ auto& list = downcast<CSSValueList>(value);
+ if (!list.length())
+ return RenderStyle::initialGridAutoFlow();
+
+ auto& first = downcast<CSSPrimitiveValue>(*list.item(0));
+ auto* second = downcast<CSSPrimitiveValue>(list.item(1));
+
+ GridAutoFlow autoFlow = RenderStyle::initialGridAutoFlow();
+ switch (first.valueID()) {
+ case CSSValueRow:
+ if (second && second->valueID() == CSSValueDense)
+ autoFlow = AutoFlowRowDense;
+ else
+ autoFlow = AutoFlowRow;
+ break;
+ case CSSValueColumn:
+ if (second && second->valueID() == CSSValueDense)
+ autoFlow = AutoFlowColumnDense;
+ else
+ autoFlow = AutoFlowColumn;
+ break;
+ case CSSValueDense:
+ if (second && second->valueID() == CSSValueColumn)
+ return AutoFlowColumnDense;
+ return AutoFlowRowDense;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return autoFlow;
+}
+
+inline CSSToLengthConversionData StyleBuilderConverter::csstoLengthConversionDataWithTextZoomFactor(StyleResolver& styleResolver)
+{
+ if (auto* frame = styleResolver.document().frame()) {
+ float textZoomFactor = styleResolver.style()->textZoom() != TextZoomReset ? frame->textZoomFactor() : 1.0f;
+ return styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(styleResolver.style()->effectiveZoom() * textZoomFactor);
+ }
+ return styleResolver.state().cssToLengthConversionData();
+}
+
+inline std::optional<Length> StyleBuilderConverter::convertWordSpacing(StyleResolver& styleResolver, const CSSValue& value)
+{
+ std::optional<Length> wordSpacing;
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueNormal)
+ wordSpacing = RenderStyle::initialWordSpacing();
+ else if (primitiveValue.isLength())
+ wordSpacing = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(styleResolver));
+ else if (primitiveValue.isPercentage())
+ wordSpacing = Length(clampTo<float>(primitiveValue.doubleValue(), minValueForCssLength, maxValueForCssLength), Percent);
+ else if (primitiveValue.isNumber())
+ wordSpacing = Length(primitiveValue.doubleValue(), Fixed);
+
+ return wordSpacing;
+}
+
+inline std::optional<float> StyleBuilderConverter::convertPerspective(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueNone)
+ return 0.f;
+
+ float perspective = -1;
+ if (primitiveValue.isLength())
+ perspective = primitiveValue.computeLength<float>(styleResolver.state().cssToLengthConversionData());
+ else if (primitiveValue.isNumber())
+ perspective = primitiveValue.doubleValue() * styleResolver.state().cssToLengthConversionData().zoom();
+ else
+ ASSERT_NOT_REACHED();
+
+ return perspective < 0 ? std::optional<float>(std::nullopt) : std::optional<float>(perspective);
+}
+
+inline std::optional<Length> StyleBuilderConverter::convertMarqueeIncrement(StyleResolver& styleResolver, const CSSValue& value)
+{
+ std::optional<Length> marqueeLength;
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ switch (primitiveValue.valueID()) {
+ case CSSValueSmall:
+ marqueeLength = Length(1, Fixed); // 1px.
+ break;
+ case CSSValueNormal:
+ marqueeLength = Length(6, Fixed); // 6px. The WinIE default.
+ break;
+ case CSSValueLarge:
+ marqueeLength = Length(36, Fixed); // 36px.
+ break;
+ case CSSValueInvalid: {
+ Length length = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
+ if (!length.isUndefined())
+ marqueeLength = length;
+ break;
+ }
+ default:
+ break;
+ }
+ return marqueeLength;
+}
+
+inline std::optional<FilterOperations> StyleBuilderConverter::convertFilterOperations(StyleResolver& styleResolver, const CSSValue& value)
+{
+ FilterOperations operations;
+ if (styleResolver.createFilterOperations(value, operations))
+ return operations;
+ return std::nullopt;
+}
+
+inline FontFeatureSettings StyleBuilderConverter::convertFontFeatureSettings(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
+ return { };
+ }
+
+ FontFeatureSettings settings;
+ for (auto& item : downcast<CSSValueList>(value)) {
+ auto& feature = downcast<CSSFontFeatureValue>(item.get());
+ settings.insert(FontFeature(feature.tag(), feature.value()));
+ }
+ return settings;
+}
+
+#if ENABLE(VARIATION_FONTS)
+inline FontVariationSettings StyleBuilderConverter::convertFontVariationSettings(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
+ return { };
+ }
+
+ FontVariationSettings settings;
+ for (auto& item : downcast<CSSValueList>(value)) {
+ auto& feature = downcast<CSSFontVariationValue>(item.get());
+ settings.insert({ feature.tag(), feature.value() });
+ }
+ return settings;
+}
+#endif
+
+#if PLATFORM(IOS)
+inline bool StyleBuilderConverter::convertTouchCallout(StyleResolver&, const CSSValue& value)
+{
+ return !equalLettersIgnoringASCIICase(downcast<CSSPrimitiveValue>(value).stringValue(), "none");
+}
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+inline Color StyleBuilderConverter::convertTapHighlightColor(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return styleResolver.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
+}
+#endif
+
+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
+inline bool StyleBuilderConverter::convertOverflowScrolling(StyleResolver&, const CSSValue& value)
+{
+ return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueTouch;
+}
+#endif
+
+inline SVGLengthValue StyleBuilderConverter::convertSVGLengthValue(StyleResolver&, const CSSValue& value)
+{
+ return SVGLengthValue::fromCSSPrimitiveValue(downcast<CSSPrimitiveValue>(value));
+}
+
+inline Vector<SVGLengthValue> StyleBuilderConverter::convertSVGLengthVector(StyleResolver& styleResolver, const CSSValue& value)
+{
+ auto& valueList = downcast<CSSValueList>(value);
+
+ Vector<SVGLengthValue> svgLengths;
+ svgLengths.reserveInitialCapacity(valueList.length());
+ for (auto& item : valueList)
+ svgLengths.uncheckedAppend(convertSVGLengthValue(styleResolver, item));
+
+ return svgLengths;
+}
+
+inline Vector<SVGLengthValue> StyleBuilderConverter::convertStrokeDashArray(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return SVGRenderStyle::initialStrokeDashArray();
+ }
+
+ return convertSVGLengthVector(styleResolver, value);
+}
+
+inline PaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
+ return PaintOrderNormal;
+ }
+
+ auto& orderTypeList = downcast<CSSValueList>(value);
+ switch (downcast<CSSPrimitiveValue>(*orderTypeList.itemWithoutBoundsCheck(0)).valueID()) {
+ case CSSValueFill:
+ return orderTypeList.length() > 1 ? PaintOrderFillMarkers : PaintOrderFill;
+ case CSSValueStroke:
+ return orderTypeList.length() > 1 ? PaintOrderStrokeMarkers : PaintOrderStroke;
+ case CSSValueMarkers:
+ return orderTypeList.length() > 1 ? PaintOrderMarkersStroke : PaintOrderMarkers;
+ default:
+ ASSERT_NOT_REACHED();
+ return PaintOrderNormal;
+ }
+}
+
+inline float StyleBuilderConverter::convertOpacity(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ float opacity = primitiveValue.floatValue();
+ if (primitiveValue.isPercentage())
+ opacity /= 100.0f;
+ return opacity;
+}
+
+inline String StyleBuilderConverter::convertSVGURIReference(StyleResolver& styleResolver, const CSSValue& value)
+{
+ String s;
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.isURI())
+ s = primitiveValue.stringValue();
+
+ return SVGURIReference::fragmentIdentifierFromIRIString(s, styleResolver.document());
+}
+
+inline Color StyleBuilderConverter::convertSVGColor(StyleResolver& styleResolver, const CSSValue& value)
+{
+ return styleResolver.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
+}
+
+inline StyleSelfAlignmentData StyleBuilderConverter::convertSelfOrDefaultAlignmentData(StyleResolver&, const CSSValue& value)
+{
+ StyleSelfAlignmentData alignmentData = RenderStyle::initialSelfAlignment();
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (Pair* pairValue = primitiveValue.pairValue()) {
+ if (pairValue->first()->valueID() == CSSValueLegacy) {
+ alignmentData.setPositionType(LegacyPosition);
+ alignmentData.setPosition(*pairValue->second());
+ } else {
+ alignmentData.setPosition(*pairValue->first());
+ alignmentData.setOverflow(*pairValue->second());
+ }
+ } else
+ alignmentData.setPosition(primitiveValue);
+ return alignmentData;
+}
+
+inline StyleContentAlignmentData StyleBuilderConverter::convertContentAlignmentData(StyleResolver&, const CSSValue& value)
+{
+ StyleContentAlignmentData alignmentData = RenderStyle::initialContentAlignment();
+ if (RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled()) {
+ if (!is<CSSContentDistributionValue>(value))
+ return alignmentData;
+ auto& contentValue = downcast<CSSContentDistributionValue>(value);
+ if (contentValue.distribution()->valueID() != CSSValueInvalid)
+ alignmentData.setDistribution(contentValue.distribution().get());
+ if (contentValue.position()->valueID() != CSSValueInvalid)
+ alignmentData.setPosition(contentValue.position().get());
+ if (contentValue.overflow()->valueID() != CSSValueInvalid)
+ alignmentData.setOverflow(contentValue.overflow().get());
+ return alignmentData;
+ }
+ if (!is<CSSPrimitiveValue>(value))
+ return alignmentData;
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ switch (primitiveValue.valueID()) {
+ case CSSValueStretch:
+ case CSSValueSpaceBetween:
+ case CSSValueSpaceAround:
+ alignmentData.setDistribution(primitiveValue);
+ break;
+ case CSSValueFlexStart:
+ case CSSValueFlexEnd:
+ case CSSValueCenter:
+ alignmentData.setPosition(primitiveValue);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return alignmentData;
+}
+
+inline EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolver&, const CSSValue& value)
+{
+ float angle = fabsf(fmodf(downcast<CSSPrimitiveValue>(value).floatValue(), 360.0f));
+ if (angle <= 45.0f || angle > 315.0f)
+ return GO_0DEG;
+ if (angle > 45.0f && angle <= 135.0f)
+ return GO_90DEG;
+ if (angle > 135.0f && angle <= 225.0f)
+ return GO_180DEG;
+ return GO_270DEG;
+}
+
+inline EGlyphOrientation StyleBuilderConverter::convertGlyphOrientationOrAuto(StyleResolver& styleResolver, const CSSValue& value)
+{
+ if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
+ return GO_AUTO;
+ return convertGlyphOrientation(styleResolver, value);
+}
+
+inline std::optional<Length> StyleBuilderConverter::convertLineHeight(StyleResolver& styleResolver, const CSSValue& value, float multiplier)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueNormal)
+ return RenderStyle::initialLineHeight();
+
+ if (primitiveValue.isLength()) {
+ Length length = primitiveValue.computeLength<Length>(StyleBuilderConverter::csstoLengthConversionDataWithTextZoomFactor(styleResolver));
+ if (multiplier != 1.f)
+ length = Length(length.value() * multiplier, Fixed);
+ return length;
+ }
+ if (primitiveValue.isPercentage()) {
+ // FIXME: percentage should not be restricted to an integer here.
+ return Length((styleResolver.style()->computedFontSize() * primitiveValue.intValue()) / 100, Fixed);
+ }
+ if (primitiveValue.isNumber()) {
+ // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent).
+ return Length(primitiveValue.doubleValue() * multiplier * 100.0, Percent);
+ }
+ return std::nullopt;
+}
+
+inline FontSynthesis StyleBuilderConverter::convertFontSynthesis(StyleResolver&, const CSSValue& value)
+{
+ if (is<CSSPrimitiveValue>(value)) {
+ ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
+ return FontSynthesisNone;
+ }
+
+ FontSynthesis result = FontSynthesisNone;
+ ASSERT(is<CSSValueList>(value));
+ for (const CSSValue& v : downcast<CSSValueList>(value)) {
+ switch (downcast<CSSPrimitiveValue>(v).valueID()) {
+ case CSSValueWeight:
+ result |= FontSynthesisWeight;
+ break;
+ case CSSValueStyle:
+ result |= FontSynthesisStyle;
+ break;
+ case CSSValueSmallCaps:
+ result |= FontSynthesisSmallCaps;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ return result;
+}
+
+inline BreakBetween StyleBuilderConverter::convertPageBreakBetween(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAlways)
+ return PageBreakBetween;
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidPageBreakBetween;
+ return primitiveValue;
+}
+
+inline BreakInside StyleBuilderConverter::convertPageBreakInside(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidPageBreakInside;
+ return primitiveValue;
+}
+
+inline BreakBetween StyleBuilderConverter::convertColumnBreakBetween(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAlways)
+ return ColumnBreakBetween;
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidColumnBreakBetween;
+ return primitiveValue;
+}
+
+inline BreakInside StyleBuilderConverter::convertColumnBreakInside(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidColumnBreakInside;
+ return primitiveValue;
+}
+
+#if ENABLE(CSS_REGIONS)
+inline BreakBetween StyleBuilderConverter::convertRegionBreakBetween(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAlways)
+ return RegionBreakBetween;
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidRegionBreakBetween;
+ return primitiveValue;
+}
+
+inline BreakInside StyleBuilderConverter::convertRegionBreakInside(StyleResolver&, const CSSValue& value)
+{
+ auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
+ if (primitiveValue.valueID() == CSSValueAvoid)
+ return AvoidRegionBreakInside;
+ return primitiveValue;
+}
+#endif
+
+inline HangingPunctuation StyleBuilderConverter::convertHangingPunctuation(StyleResolver&, const CSSValue& value)
+{
+ HangingPunctuation result = RenderStyle::initialHangingPunctuation();
+ if (is<CSSValueList>(value)) {
+ for (auto& currentValue : downcast<CSSValueList>(value))
+ result |= downcast<CSSPrimitiveValue>(currentValue.get());
+ }
+ return result;
+}
+
+} // namespace WebCore