Remove excessive include directives from WebCore/css
[WebKit-https.git] / Source / WebCore / css / StyleBuilderConverter.h
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  * Copyright (C) 2014 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #pragma once
28
29 #include "BasicShapeFunctions.h"
30 #include "CSSCalculationValue.h"
31 #include "CSSContentDistributionValue.h"
32 #include "CSSFontFeatureValue.h"
33 #include "CSSFontStyleValue.h"
34 #include "CSSFontVariationValue.h"
35 #include "CSSFunctionValue.h"
36 #include "CSSGridAutoRepeatValue.h"
37 #include "CSSGridLineNamesValue.h"
38 #include "CSSImageGeneratorValue.h"
39 #include "CSSImageSetValue.h"
40 #include "CSSImageValue.h"
41 #include "CSSPrimitiveValue.h"
42 #include "CSSPrimitiveValueMappings.h"
43 #include "CSSReflectValue.h"
44 #include "FontSelectionValueInlines.h"
45 #include "Frame.h"
46 #include "Length.h"
47 #include "Pair.h"
48 #include "QuotesData.h"
49 #include "RuntimeEnabledFeatures.h"
50 #include "SVGURIReference.h"
51 #include "Settings.h"
52 #include "StyleResolver.h"
53 #include "StyleScrollSnapPoints.h"
54 #include "TransformFunctions.h"
55 #include <wtf/Optional.h>
56
57 namespace WebCore {
58
59 // Note that we assume the CSS parser only allows valid CSSValue types.
60 class StyleBuilderConverter {
61 public:
62     static Length convertLength(StyleResolver&, const CSSValue&);
63     static Length convertLengthOrAuto(StyleResolver&, const CSSValue&);
64     static Length convertLengthSizing(StyleResolver&, const CSSValue&);
65     static Length convertLengthMaxSizing(StyleResolver&, const CSSValue&);
66     template<typename T> static T convertComputedLength(StyleResolver&, const CSSValue&);
67     template<typename T> static T convertLineWidth(StyleResolver&, const CSSValue&);
68     static float convertSpacing(StyleResolver&, const CSSValue&);
69     static LengthSize convertRadius(StyleResolver&, const CSSValue&);
70     static LengthPoint convertObjectPosition(StyleResolver&, const CSSValue&);
71     static TextDecoration convertTextDecoration(StyleResolver&, const CSSValue&);
72     template<typename T> static T convertNumber(StyleResolver&, const CSSValue&);
73     template<typename T> static T convertNumberOrAuto(StyleResolver&, const CSSValue&);
74     static short convertWebkitHyphenateLimitLines(StyleResolver&, const CSSValue&);
75     template<CSSPropertyID> static NinePieceImage convertBorderImage(StyleResolver&, CSSValue&);
76     template<CSSPropertyID> static NinePieceImage convertBorderMask(StyleResolver&, CSSValue&);
77     template<CSSPropertyID> static RefPtr<StyleImage> convertStyleImage(StyleResolver&, CSSValue&);
78     static TransformOperations convertTransform(StyleResolver&, const CSSValue&);
79     static String convertString(StyleResolver&, const CSSValue&);
80     static String convertStringOrAuto(StyleResolver&, const CSSValue&);
81     static String convertStringOrNone(StyleResolver&, const CSSValue&);
82     static TextEmphasisPosition convertTextEmphasisPosition(StyleResolver&, const CSSValue&);
83     static ETextAlign convertTextAlign(StyleResolver&, const CSSValue&);
84     static RefPtr<ClipPathOperation> convertClipPath(StyleResolver&, const CSSValue&);
85     static EResize convertResize(StyleResolver&, const CSSValue&);
86     static int convertMarqueeRepetition(StyleResolver&, const CSSValue&);
87     static int convertMarqueeSpeed(StyleResolver&, const CSSValue&);
88     static Ref<QuotesData> convertQuotes(StyleResolver&, const CSSValue&);
89     static TextUnderlinePosition convertTextUnderlinePosition(StyleResolver&, const CSSValue&);
90     static RefPtr<StyleReflection> convertReflection(StyleResolver&, const CSSValue&);
91     static IntSize convertInitialLetter(StyleResolver&, const CSSValue&);
92     static float convertTextStrokeWidth(StyleResolver&, const CSSValue&);
93     static LineBoxContain convertLineBoxContain(StyleResolver&, const CSSValue&);
94     static TextDecorationSkip convertTextDecorationSkip(StyleResolver&, const CSSValue&);
95     static RefPtr<ShapeValue> convertShapeValue(StyleResolver&, CSSValue&);
96 #if ENABLE(CSS_SCROLL_SNAP)
97     static ScrollSnapType convertScrollSnapType(StyleResolver&, const CSSValue&);
98     static ScrollSnapAlign convertScrollSnapAlign(StyleResolver&, const CSSValue&);
99 #endif
100     static GridTrackSize convertGridTrackSize(StyleResolver&, const CSSValue&);
101     static Vector<GridTrackSize> convertGridTrackSizeList(StyleResolver&, const CSSValue&);
102     static std::optional<GridPosition> convertGridPosition(StyleResolver&, const CSSValue&);
103     static GridAutoFlow convertGridAutoFlow(StyleResolver&, const CSSValue&);
104     static std::optional<Length> convertWordSpacing(StyleResolver&, const CSSValue&);
105     static std::optional<float> convertPerspective(StyleResolver&, const CSSValue&);
106     static std::optional<Length> convertMarqueeIncrement(StyleResolver&, const CSSValue&);
107     static std::optional<FilterOperations> convertFilterOperations(StyleResolver&, const CSSValue&);
108 #if PLATFORM(IOS)
109     static bool convertTouchCallout(StyleResolver&, const CSSValue&);
110 #endif
111 #if ENABLE(TOUCH_EVENTS)
112     static Color convertTapHighlightColor(StyleResolver&, const CSSValue&);
113 #endif
114 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
115     static bool convertOverflowScrolling(StyleResolver&, const CSSValue&);
116 #endif
117     static FontFeatureSettings convertFontFeatureSettings(StyleResolver&, const CSSValue&);
118     static FontSelectionValue convertFontWeightFromValue(const CSSValue&);
119     static FontSelectionValue convertFontStretchFromValue(const CSSValue&);
120     static FontSelectionValue convertFontStyleFromValue(const CSSValue&);
121     static FontSelectionValue convertFontWeight(StyleResolver&, const CSSValue&);
122     static FontSelectionValue convertFontStretch(StyleResolver&, const CSSValue&);
123     static FontSelectionValue convertFontStyle(StyleResolver&, const CSSValue&);
124 #if ENABLE(VARIATION_FONTS)
125     static FontVariationSettings convertFontVariationSettings(StyleResolver&, const CSSValue&);
126 #endif
127     static SVGLengthValue convertSVGLengthValue(StyleResolver&, const CSSValue&);
128     static Vector<SVGLengthValue> convertSVGLengthVector(StyleResolver&, const CSSValue&);
129     static Vector<SVGLengthValue> convertStrokeDashArray(StyleResolver&, const CSSValue&);
130     static PaintOrder convertPaintOrder(StyleResolver&, const CSSValue&);
131     static float convertOpacity(StyleResolver&, const CSSValue&);
132     static String convertSVGURIReference(StyleResolver&, const CSSValue&);
133     static Color convertSVGColor(StyleResolver&, const CSSValue&);
134     static StyleSelfAlignmentData convertSelfOrDefaultAlignmentData(StyleResolver&, const CSSValue&);
135     static StyleContentAlignmentData convertContentAlignmentData(StyleResolver&, const CSSValue&);
136     static EGlyphOrientation convertGlyphOrientation(StyleResolver&, const CSSValue&);
137     static EGlyphOrientation convertGlyphOrientationOrAuto(StyleResolver&, const CSSValue&);
138     static std::optional<Length> convertLineHeight(StyleResolver&, const CSSValue&, float multiplier = 1.f);
139     static FontSynthesis convertFontSynthesis(StyleResolver&, const CSSValue&);
140     
141     static BreakBetween convertPageBreakBetween(StyleResolver&, const CSSValue&);
142     static BreakInside convertPageBreakInside(StyleResolver&, const CSSValue&);
143     static BreakBetween convertColumnBreakBetween(StyleResolver&, const CSSValue&);
144     static BreakInside convertColumnBreakInside(StyleResolver&, const CSSValue&);
145 #if ENABLE(CSS_REGIONS)
146     static BreakBetween convertRegionBreakBetween(StyleResolver&, const CSSValue&);
147     static BreakInside convertRegionBreakInside(StyleResolver&, const CSSValue&);
148 #endif
149     
150     static HangingPunctuation convertHangingPunctuation(StyleResolver&, const CSSValue&);
151
152     static Length convertPositionComponentX(StyleResolver&, const CSSValue&);
153     static Length convertPositionComponentY(StyleResolver&, const CSSValue&);
154     
155 private:
156     friend class StyleBuilderCustom;
157
158     static Length convertToRadiusLength(CSSToLengthConversionData&, const CSSPrimitiveValue&);
159     static TextEmphasisPosition valueToEmphasisPosition(const CSSPrimitiveValue&);
160     static TextDecorationSkip valueToDecorationSkip(const CSSPrimitiveValue&);
161 #if ENABLE(CSS_SCROLL_SNAP)
162     static Length parseSnapCoordinate(StyleResolver&, const CSSValue&);
163 #endif
164
165     static Length convertTo100PercentMinusLength(const Length&);
166     template<CSSValueID, CSSValueID> static Length convertPositionComponent(StyleResolver&, const CSSPrimitiveValue&);
167
168     static GridLength createGridTrackBreadth(const CSSPrimitiveValue&, StyleResolver&);
169     static GridTrackSize createGridTrackSize(const CSSValue&, StyleResolver&);
170     struct TracksData;
171     static bool createGridTrackList(const CSSValue&, TracksData&, StyleResolver&);
172     static bool createGridPosition(const CSSValue&, GridPosition&);
173     static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap&, NamedGridLinesMap&, GridTrackSizingDirection);
174     static CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(StyleResolver&);
175 };
176
177 inline Length StyleBuilderConverter::convertLength(StyleResolver& styleResolver, const CSSValue& value)
178 {
179     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
180     CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
181         styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
182         : styleResolver.state().cssToLengthConversionData();
183
184     if (primitiveValue.isLength()) {
185         Length length = primitiveValue.computeLength<Length>(conversionData);
186         length.setHasQuirk(primitiveValue.isQuirkValue());
187         return length;
188     }
189
190     if (primitiveValue.isPercentage())
191         return Length(primitiveValue.doubleValue(), Percent);
192
193     if (primitiveValue.isCalculatedPercentageWithLength())
194         return Length(primitiveValue.cssCalcValue()->createCalculationValue(conversionData));
195
196     ASSERT_NOT_REACHED();
197     return Length(0, Fixed);
198 }
199
200 inline Length StyleBuilderConverter::convertLengthOrAuto(StyleResolver& styleResolver, const CSSValue& value)
201 {
202     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
203         return Length(Auto);
204     return convertLength(styleResolver, value);
205 }
206
207 inline Length StyleBuilderConverter::convertLengthSizing(StyleResolver& styleResolver, const CSSValue& value)
208 {
209     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
210     switch (primitiveValue.valueID()) {
211     case CSSValueInvalid:
212         return convertLength(styleResolver, value);
213     case CSSValueIntrinsic:
214         return Length(Intrinsic);
215     case CSSValueMinIntrinsic:
216         return Length(MinIntrinsic);
217     case CSSValueMinContent:
218     case CSSValueWebkitMinContent:
219         return Length(MinContent);
220     case CSSValueMaxContent:
221     case CSSValueWebkitMaxContent:
222         return Length(MaxContent);
223     case CSSValueWebkitFillAvailable:
224         return Length(FillAvailable);
225     case CSSValueFitContent:
226     case CSSValueWebkitFitContent:
227         return Length(FitContent);
228     case CSSValueAuto:
229         return Length(Auto);
230     default:
231         ASSERT_NOT_REACHED();
232         return Length();
233     }
234 }
235
236 inline Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolver& styleResolver, const CSSValue& value)
237 {
238     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
239         return Length(Undefined);
240     return convertLengthSizing(styleResolver, value);
241 }
242
243 template<typename T>
244 inline T StyleBuilderConverter::convertComputedLength(StyleResolver& styleResolver, const CSSValue& value)
245 {
246     return downcast<CSSPrimitiveValue>(value).computeLength<T>(styleResolver.state().cssToLengthConversionData());
247 }
248
249 template<typename T>
250 inline T StyleBuilderConverter::convertLineWidth(StyleResolver& styleResolver, const CSSValue& value)
251 {
252     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
253     switch (primitiveValue.valueID()) {
254     case CSSValueThin:
255         return 1;
256     case CSSValueMedium:
257         return 3;
258     case CSSValueThick:
259         return 5;
260     case CSSValueInvalid: {
261         // Any original result that was >= 1 should not be allowed to fall below 1.
262         // This keeps border lines from vanishing.
263         T result = convertComputedLength<T>(styleResolver, value);
264         if (styleResolver.state().style()->effectiveZoom() < 1.0f && result < 1.0) {
265             T originalLength = primitiveValue.computeLength<T>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0));
266             if (originalLength >= 1.0)
267                 return 1;
268         }
269         float minimumLineWidth = 1 / styleResolver.document().deviceScaleFactor();
270         if (result > 0 && result < minimumLineWidth)
271             return minimumLineWidth;
272         return floorToDevicePixel(result, styleResolver.document().deviceScaleFactor());
273     }
274     default:
275         ASSERT_NOT_REACHED();
276         return 0;
277     }
278 }
279
280 inline float StyleBuilderConverter::convertSpacing(StyleResolver& styleResolver, const CSSValue& value)
281 {
282     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
283     if (primitiveValue.valueID() == CSSValueNormal)
284         return 0.f;
285
286     CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
287         styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
288         : styleResolver.state().cssToLengthConversionData();
289     return primitiveValue.computeLength<float>(conversionData);
290 }
291
292 inline Length StyleBuilderConverter::convertToRadiusLength(CSSToLengthConversionData& conversionData, const CSSPrimitiveValue& value)
293 {
294     if (value.isPercentage())
295         return Length(value.doubleValue(), Percent);
296     if (value.isCalculatedPercentageWithLength())
297         return Length(value.cssCalcValue()->createCalculationValue(conversionData));
298     return value.computeLength<Length>(conversionData);
299 }
300
301 inline LengthSize StyleBuilderConverter::convertRadius(StyleResolver& styleResolver, const CSSValue& value)
302 {
303     auto* pair = downcast<CSSPrimitiveValue>(value).pairValue();
304     if (!pair || !pair->first() || !pair->second())
305         return { { 0, Fixed }, { 0, Fixed } };
306
307     CSSToLengthConversionData conversionData = styleResolver.state().cssToLengthConversionData();
308     LengthSize radius { convertToRadiusLength(conversionData, *pair->first()), convertToRadiusLength(conversionData, *pair->second()) };
309
310     ASSERT(!radius.width.isNegative());
311     ASSERT(!radius.height.isNegative());
312     if (radius.width.isZero() || radius.height.isZero())
313         return { { 0, Fixed }, { 0, Fixed } };
314
315     return radius;
316 }
317
318 inline Length StyleBuilderConverter::convertTo100PercentMinusLength(const Length& length)
319 {
320     if (length.isPercent())
321         return Length(100 - length.value(), Percent);
322     
323     // Turn this into a calc expression: calc(100% - length)
324     auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
325     auto rhs = std::make_unique<CalcExpressionLength>(length);
326     auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
327     return Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
328 }
329
330 inline Length StyleBuilderConverter::convertPositionComponentX(StyleResolver& styleResolver, const CSSValue& value)
331 {
332     return convertPositionComponent<CSSValueLeft, CSSValueRight>(styleResolver, downcast<CSSPrimitiveValue>(value));
333 }
334
335 inline Length StyleBuilderConverter::convertPositionComponentY(StyleResolver& styleResolver, const CSSValue& value)
336 {
337     return convertPositionComponent<CSSValueTop, CSSValueBottom>(styleResolver, downcast<CSSPrimitiveValue>(value));
338 }
339
340 template<CSSValueID cssValueFor0, CSSValueID cssValueFor100>
341 inline Length StyleBuilderConverter::convertPositionComponent(StyleResolver& styleResolver, const CSSPrimitiveValue& value)
342 {
343     Length length;
344
345     auto* lengthValue = &value;
346     bool relativeToTrailingEdge = false;
347     
348     if (value.isPair()) {
349         auto& first = *value.pairValue()->first();
350         if (first.valueID() == CSSValueRight || first.valueID() == CSSValueBottom)
351             relativeToTrailingEdge = true;
352         lengthValue = value.pairValue()->second();
353     }
354     
355     if (value.isValueID()) {
356         switch (value.valueID()) {
357         case cssValueFor0:
358             return Length(0, Percent);
359         case cssValueFor100:
360             return Length(100, Percent);
361         case CSSValueCenter:
362             return Length(50, Percent);
363         default:
364             ASSERT_NOT_REACHED();
365         }
366     }
367         
368     length = convertLength(styleResolver, *lengthValue);
369
370     if (relativeToTrailingEdge)
371         length = convertTo100PercentMinusLength(length);
372
373     return length;
374 }
375
376 inline LengthPoint StyleBuilderConverter::convertObjectPosition(StyleResolver& styleResolver, const CSSValue& value)
377 {
378     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
379     Pair* pair = primitiveValue.pairValue();
380     if (!pair || !pair->first() || !pair->second())
381         return RenderStyle::initialObjectPosition();
382
383     Length lengthX = convertPositionComponent<CSSValueLeft, CSSValueRight>(styleResolver, *pair->first());
384     Length lengthY = convertPositionComponent<CSSValueTop, CSSValueBottom>(styleResolver, *pair->second());
385
386     return LengthPoint(lengthX, lengthY);
387 }
388
389 inline TextDecoration StyleBuilderConverter::convertTextDecoration(StyleResolver&, const CSSValue& value)
390 {
391     TextDecoration result = RenderStyle::initialTextDecoration();
392     if (is<CSSValueList>(value)) {
393         for (auto& currentValue : downcast<CSSValueList>(value))
394             result |= downcast<CSSPrimitiveValue>(currentValue.get());
395     }
396     return result;
397 }
398
399 template<typename T>
400 inline T StyleBuilderConverter::convertNumber(StyleResolver&, const CSSValue& value)
401 {
402     return downcast<CSSPrimitiveValue>(value).value<T>(CSSPrimitiveValue::CSS_NUMBER);
403 }
404
405 template<typename T>
406 inline T StyleBuilderConverter::convertNumberOrAuto(StyleResolver& styleResolver, const CSSValue& value)
407 {
408     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
409         return -1;
410     return convertNumber<T>(styleResolver, value);
411 }
412
413 inline short StyleBuilderConverter::convertWebkitHyphenateLimitLines(StyleResolver&, const CSSValue& value)
414 {
415     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
416     if (primitiveValue.valueID() == CSSValueNoLimit)
417         return -1;
418     return primitiveValue.value<short>(CSSPrimitiveValue::CSS_NUMBER);
419 }
420
421 template<CSSPropertyID property>
422 inline NinePieceImage StyleBuilderConverter::convertBorderImage(StyleResolver& styleResolver, CSSValue& value)
423 {
424     NinePieceImage image;
425     styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
426     return image;
427 }
428
429 template<CSSPropertyID property>
430 inline NinePieceImage StyleBuilderConverter::convertBorderMask(StyleResolver& styleResolver, CSSValue& value)
431 {
432     NinePieceImage image;
433     image.setMaskDefaults();
434     styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
435     return image;
436 }
437
438 template<CSSPropertyID>
439 inline RefPtr<StyleImage> StyleBuilderConverter::convertStyleImage(StyleResolver& styleResolver, CSSValue& value)
440 {
441     return styleResolver.styleImage(value);
442 }
443
444 inline TransformOperations StyleBuilderConverter::convertTransform(StyleResolver& styleResolver, const CSSValue& value)
445 {
446     TransformOperations operations;
447     transformsForValue(value, styleResolver.state().cssToLengthConversionData(), operations);
448     return operations;
449 }
450
451 inline String StyleBuilderConverter::convertString(StyleResolver&, const CSSValue& value)
452 {
453     return downcast<CSSPrimitiveValue>(value).stringValue();
454 }
455
456 inline String StyleBuilderConverter::convertStringOrAuto(StyleResolver& styleResolver, const CSSValue& value)
457 {
458     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
459         return nullAtom;
460     return convertString(styleResolver, value);
461 }
462
463 inline String StyleBuilderConverter::convertStringOrNone(StyleResolver& styleResolver, const CSSValue& value)
464 {
465     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
466         return nullAtom;
467     return convertString(styleResolver, value);
468 }
469
470 inline TextEmphasisPosition StyleBuilderConverter::valueToEmphasisPosition(const CSSPrimitiveValue& primitiveValue)
471 {
472     ASSERT(primitiveValue.isValueID());
473
474     switch (primitiveValue.valueID()) {
475     case CSSValueOver:
476         return TextEmphasisPositionOver;
477     case CSSValueUnder:
478         return TextEmphasisPositionUnder;
479     case CSSValueLeft:
480         return TextEmphasisPositionLeft;
481     case CSSValueRight:
482         return TextEmphasisPositionRight;
483     default:
484         break;
485     }
486
487     ASSERT_NOT_REACHED();
488     return RenderStyle::initialTextEmphasisPosition();
489 }
490
491 inline TextEmphasisPosition StyleBuilderConverter::convertTextEmphasisPosition(StyleResolver&, const CSSValue& value)
492 {
493     if (is<CSSPrimitiveValue>(value))
494         return valueToEmphasisPosition(downcast<CSSPrimitiveValue>(value));
495
496     TextEmphasisPosition position = 0;
497     for (auto& currentValue : downcast<CSSValueList>(value))
498         position |= valueToEmphasisPosition(downcast<CSSPrimitiveValue>(currentValue.get()));
499     return position;
500 }
501
502 inline ETextAlign StyleBuilderConverter::convertTextAlign(StyleResolver& styleResolver, const CSSValue& value)
503 {
504     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
505     ASSERT(primitiveValue.isValueID());
506
507     if (primitiveValue.valueID() != CSSValueWebkitMatchParent)
508         return primitiveValue;
509
510     auto* parentStyle = styleResolver.parentStyle();
511     if (parentStyle->textAlign() == TASTART)
512         return parentStyle->isLeftToRightDirection() ? LEFT : RIGHT;
513     if (parentStyle->textAlign() == TAEND)
514         return parentStyle->isLeftToRightDirection() ? RIGHT : LEFT;
515     return parentStyle->textAlign();
516 }
517
518 inline RefPtr<ClipPathOperation> StyleBuilderConverter::convertClipPath(StyleResolver& styleResolver, const CSSValue& value)
519 {
520     if (is<CSSPrimitiveValue>(value)) {
521         auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
522         if (primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_URI) {
523             String cssURLValue = primitiveValue.stringValue();
524             URL url = styleResolver.document().completeURL(cssURLValue);
525             // FIXME: It doesn't work with external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=126133)
526             return ReferenceClipPathOperation::create(cssURLValue, url.fragmentIdentifier());
527         }
528         ASSERT(primitiveValue.valueID() == CSSValueNone);
529         return nullptr;
530     }
531
532     CSSBoxType referenceBox = BoxMissing;
533     RefPtr<ClipPathOperation> operation;
534
535     for (auto& currentValue : downcast<CSSValueList>(value)) {
536         auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
537         if (primitiveValue.isShape()) {
538             ASSERT(!operation);
539             operation = ShapeClipPathOperation::create(basicShapeForValue(styleResolver.state().cssToLengthConversionData(), *primitiveValue.shapeValue()));
540         } else {
541             ASSERT(primitiveValue.valueID() == CSSValueContentBox
542                 || primitiveValue.valueID() == CSSValueBorderBox
543                 || primitiveValue.valueID() == CSSValuePaddingBox
544                 || primitiveValue.valueID() == CSSValueMarginBox
545                 || primitiveValue.valueID() == CSSValueFill
546                 || primitiveValue.valueID() == CSSValueStroke
547                 || primitiveValue.valueID() == CSSValueViewBox);
548             ASSERT(referenceBox == BoxMissing);
549             referenceBox = primitiveValue;
550         }
551     }
552     if (operation)
553         downcast<ShapeClipPathOperation>(*operation).setReferenceBox(referenceBox);
554     else {
555         ASSERT(referenceBox != BoxMissing);
556         operation = BoxClipPathOperation::create(referenceBox);
557     }
558
559     return operation;
560 }
561
562 inline EResize StyleBuilderConverter::convertResize(StyleResolver& styleResolver, const CSSValue& value)
563 {
564     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
565
566     EResize resize = RESIZE_NONE;
567     if (primitiveValue.valueID() == CSSValueAuto)
568         resize = styleResolver.settings().textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
569     else
570         resize = primitiveValue;
571
572     return resize;
573 }
574
575 inline int StyleBuilderConverter::convertMarqueeRepetition(StyleResolver&, const CSSValue& value)
576 {
577     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
578     if (primitiveValue.valueID() == CSSValueInfinite)
579         return -1; // -1 means repeat forever.
580
581     ASSERT(primitiveValue.isNumber());
582     return primitiveValue.intValue();
583 }
584
585 inline int StyleBuilderConverter::convertMarqueeSpeed(StyleResolver&, const CSSValue& value)
586 {
587     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
588     int speed = 85;
589     if (CSSValueID ident = primitiveValue.valueID()) {
590         switch (ident) {
591         case CSSValueSlow:
592             speed = 500; // 500 msec.
593             break;
594         case CSSValueNormal:
595             speed = 85; // 85msec. The WinIE default.
596             break;
597         case CSSValueFast:
598             speed = 10; // 10msec. Super fast.
599             break;
600         default:
601             ASSERT_NOT_REACHED();
602             break;
603         }
604     } else if (primitiveValue.isTime())
605         speed = primitiveValue.computeTime<int, CSSPrimitiveValue::Milliseconds>();
606     else {
607         // For scrollamount support.
608         ASSERT(primitiveValue.isNumber());
609         speed = primitiveValue.intValue();
610     }
611     return speed;
612 }
613
614 inline Ref<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolver&, const CSSValue& value)
615 {
616     if (is<CSSPrimitiveValue>(value)) {
617         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
618         return QuotesData::create(Vector<std::pair<String, String>>());
619     }
620
621     auto& list = downcast<CSSValueList>(value);
622     Vector<std::pair<String, String>> quotes;
623     quotes.reserveInitialCapacity(list.length() / 2);
624     for (unsigned i = 0; i < list.length(); i += 2) {
625         const CSSValue* first = list.itemWithoutBoundsCheck(i);
626         // item() returns null if out of bounds so this is safe.
627         const CSSValue* second = list.item(i + 1);
628         if (!second)
629             break;
630         String startQuote = downcast<CSSPrimitiveValue>(*first).stringValue();
631         String endQuote = downcast<CSSPrimitiveValue>(*second).stringValue();
632         quotes.append(std::make_pair(startQuote, endQuote));
633     }
634     return QuotesData::create(quotes);
635 }
636
637 inline TextUnderlinePosition StyleBuilderConverter::convertTextUnderlinePosition(StyleResolver&, const CSSValue& value)
638 {
639     // This is true if value is 'auto' or 'alphabetic'.
640     if (is<CSSPrimitiveValue>(value))
641         return downcast<CSSPrimitiveValue>(value);
642
643     unsigned combinedPosition = 0;
644     for (auto& currentValue : downcast<CSSValueList>(value)) {
645         TextUnderlinePosition position = downcast<CSSPrimitiveValue>(currentValue.get());
646         combinedPosition |= position;
647     }
648     return static_cast<TextUnderlinePosition>(combinedPosition);
649 }
650
651 inline RefPtr<StyleReflection> StyleBuilderConverter::convertReflection(StyleResolver& styleResolver, const CSSValue& value)
652 {
653     if (is<CSSPrimitiveValue>(value)) {
654         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
655         return nullptr;
656     }
657
658     auto& reflectValue = downcast<CSSReflectValue>(value);
659
660     auto reflection = StyleReflection::create();
661     reflection->setDirection(reflectValue.direction());
662     reflection->setOffset(reflectValue.offset().convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData()));
663
664     NinePieceImage mask;
665     mask.setMaskDefaults();
666     styleResolver.styleMap()->mapNinePieceImage(CSSPropertyWebkitBoxReflect, reflectValue.mask(), mask);
667     reflection->setMask(mask);
668
669     return WTFMove(reflection);
670 }
671
672 inline IntSize StyleBuilderConverter::convertInitialLetter(StyleResolver&, const CSSValue& value)
673 {
674     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
675
676     if (primitiveValue.valueID() == CSSValueNormal)
677         return IntSize();
678
679     Pair* pair = primitiveValue.pairValue();
680     ASSERT(pair);
681     ASSERT(pair->first());
682     ASSERT(pair->second());
683
684     return IntSize(pair->first()->intValue(), pair->second()->intValue());
685 }
686
687 inline float StyleBuilderConverter::convertTextStrokeWidth(StyleResolver& styleResolver, const CSSValue& value)
688 {
689     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
690
691     float width = 0;
692     switch (primitiveValue.valueID()) {
693     case CSSValueThin:
694     case CSSValueMedium:
695     case CSSValueThick: {
696         double result = 1.0 / 48;
697         if (primitiveValue.valueID() == CSSValueMedium)
698             result *= 3;
699         else if (primitiveValue.valueID() == CSSValueThick)
700             result *= 5;
701         Ref<CSSPrimitiveValue> emsValue(CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS));
702         width = convertComputedLength<float>(styleResolver, emsValue);
703         break;
704     }
705     case CSSValueInvalid: {
706         width = convertComputedLength<float>(styleResolver, primitiveValue);
707         break;
708     }
709     default:
710         ASSERT_NOT_REACHED();
711         return 0;
712     }
713
714     return width;
715 }
716
717 inline LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolver&, const CSSValue& value)
718 {
719     if (is<CSSPrimitiveValue>(value)) {
720         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
721         return LineBoxContainNone;
722     }
723
724     return downcast<CSSLineBoxContainValue>(value).value();
725 }
726
727 inline TextDecorationSkip StyleBuilderConverter::valueToDecorationSkip(const CSSPrimitiveValue& primitiveValue)
728 {
729     ASSERT(primitiveValue.isValueID());
730
731     switch (primitiveValue.valueID()) {
732     case CSSValueAuto:
733         return TextDecorationSkipAuto;
734     case CSSValueNone:
735         return TextDecorationSkipNone;
736     case CSSValueInk:
737         return TextDecorationSkipInk;
738     case CSSValueObjects:
739         return TextDecorationSkipObjects;
740     default:
741         break;
742     }
743
744     ASSERT_NOT_REACHED();
745     return TextDecorationSkipNone;
746 }
747
748 inline TextDecorationSkip StyleBuilderConverter::convertTextDecorationSkip(StyleResolver&, const CSSValue& value)
749 {
750     if (is<CSSPrimitiveValue>(value))
751         return valueToDecorationSkip(downcast<CSSPrimitiveValue>(value));
752
753     TextDecorationSkip skip = TextDecorationSkipNone;
754     for (auto& currentValue : downcast<CSSValueList>(value))
755         skip |= valueToDecorationSkip(downcast<CSSPrimitiveValue>(currentValue.get()));
756     return skip;
757 }
758
759 static inline bool isImageShape(const CSSValue& value)
760 {
761     return is<CSSImageValue>(value) || is<CSSImageSetValue>(value) || is<CSSImageGeneratorValue>(value);
762 }
763
764 inline RefPtr<ShapeValue> StyleBuilderConverter::convertShapeValue(StyleResolver& styleResolver, CSSValue& value)
765 {
766     if (is<CSSPrimitiveValue>(value)) {
767         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
768         return nullptr;
769     }
770
771     if (isImageShape(value))
772         return ShapeValue::create(styleResolver.styleImage(value).releaseNonNull());
773
774     RefPtr<BasicShape> shape;
775     CSSBoxType referenceBox = BoxMissing;
776     for (auto& currentValue : downcast<CSSValueList>(value)) {
777         auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
778         if (primitiveValue.isShape())
779             shape = basicShapeForValue(styleResolver.state().cssToLengthConversionData(), *primitiveValue.shapeValue());
780         else if (primitiveValue.valueID() == CSSValueContentBox
781             || primitiveValue.valueID() == CSSValueBorderBox
782             || primitiveValue.valueID() == CSSValuePaddingBox
783             || primitiveValue.valueID() == CSSValueMarginBox)
784             referenceBox = primitiveValue;
785         else {
786             ASSERT_NOT_REACHED();
787             return nullptr;
788         }
789     }
790
791     if (shape)
792         return ShapeValue::create(shape.releaseNonNull(), referenceBox);
793
794     if (referenceBox != BoxMissing)
795         return ShapeValue::create(referenceBox);
796
797     ASSERT_NOT_REACHED();
798     return nullptr;
799 }
800
801 #if ENABLE(CSS_SCROLL_SNAP)
802
803 inline ScrollSnapType StyleBuilderConverter::convertScrollSnapType(StyleResolver&, const CSSValue& value)
804 {
805     ScrollSnapType type;
806     auto& values = downcast<CSSValueList>(value);
807     auto& firstValue = downcast<CSSPrimitiveValue>(*values.item(0));
808     if (values.length() == 2) {
809         type.axis = firstValue;
810         type.strictness = downcast<CSSPrimitiveValue>(*values.item(1));
811         return type;
812     }
813
814     switch (firstValue.valueID()) {
815     case CSSValueNone:
816     case CSSValueMandatory:
817     case CSSValueProximity:
818         type.strictness = firstValue;
819         break;
820     default:
821         type.axis = firstValue;
822         type.strictness = ScrollSnapStrictness::Proximity;
823         break;
824     }
825     return type;
826 }
827
828 inline ScrollSnapAlign StyleBuilderConverter::convertScrollSnapAlign(StyleResolver&, const CSSValue& value)
829 {
830     auto& values = downcast<CSSValueList>(value);
831     ScrollSnapAlign alignment;
832     alignment.x = downcast<CSSPrimitiveValue>(*values.item(0));
833     if (values.length() == 1)
834         alignment.y = alignment.x;
835     else
836         alignment.y = downcast<CSSPrimitiveValue>(*values.item(1));
837     return alignment;
838 }
839
840 #endif
841
842 inline GridLength StyleBuilderConverter::createGridTrackBreadth(const CSSPrimitiveValue& primitiveValue, StyleResolver& styleResolver)
843 {
844     if (primitiveValue.valueID() == CSSValueMinContent || primitiveValue.valueID() == CSSValueWebkitMinContent)
845         return Length(MinContent);
846
847     if (primitiveValue.valueID() == CSSValueMaxContent || primitiveValue.valueID() == CSSValueWebkitMaxContent)
848         return Length(MaxContent);
849
850     // Fractional unit.
851     if (primitiveValue.isFlex())
852         return GridLength(primitiveValue.doubleValue());
853
854     return primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | AutoConversion>(styleResolver.state().cssToLengthConversionData());
855 }
856
857 inline GridTrackSize StyleBuilderConverter::createGridTrackSize(const CSSValue& value, StyleResolver& styleResolver)
858 {
859     if (is<CSSPrimitiveValue>(value))
860         return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(value), styleResolver));
861
862     ASSERT(is<CSSFunctionValue>(value));
863     const auto& function = downcast<CSSFunctionValue>(value);
864
865     if (function.length() == 1)
866         return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), styleResolver), FitContentTrackSizing);
867
868     ASSERT_WITH_SECURITY_IMPLICATION(function.length() == 2);
869     GridLength minTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), styleResolver));
870     GridLength maxTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(1)), styleResolver));
871     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
872 }
873
874 static void createGridLineNamesList(const CSSValue& value, unsigned currentNamedGridLine, NamedGridLinesMap& namedGridLines, OrderedNamedGridLinesMap& orderedNamedGridLines)
875 {
876     ASSERT(value.isGridLineNamesValue());
877
878     for (auto& namedGridLineValue : downcast<CSSGridLineNamesValue>(value)) {
879         String namedGridLine = downcast<CSSPrimitiveValue>(namedGridLineValue.get()).stringValue();
880         auto result = namedGridLines.add(namedGridLine, Vector<unsigned>());
881         result.iterator->value.append(currentNamedGridLine);
882         auto orderedResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
883         orderedResult.iterator->value.append(namedGridLine);
884     }
885 }
886
887 struct StyleBuilderConverter::TracksData {
888     WTF_MAKE_NONCOPYABLE(TracksData); WTF_MAKE_FAST_ALLOCATED;
889 public:
890     TracksData() = default;
891
892     Vector<GridTrackSize> m_trackSizes;
893     NamedGridLinesMap m_namedGridLines;
894     OrderedNamedGridLinesMap m_orderedNamedGridLines;
895     Vector<GridTrackSize> m_autoRepeatTrackSizes;
896     NamedGridLinesMap m_autoRepeatNamedGridLines;
897     OrderedNamedGridLinesMap m_autoRepeatOrderedNamedGridLines;
898     unsigned m_autoRepeatInsertionPoint { RenderStyle::initialGridAutoRepeatInsertionPoint() };
899     AutoRepeatType m_autoRepeatType { RenderStyle::initialGridAutoRepeatType() };
900 };
901
902 inline bool StyleBuilderConverter::createGridTrackList(const CSSValue& value, TracksData& tracksData, StyleResolver& styleResolver)
903 {
904     // Handle 'none'.
905     if (is<CSSPrimitiveValue>(value))
906         return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone;
907
908     if (!is<CSSValueList>(value))
909         return false;
910
911     unsigned currentNamedGridLine = 0;
912     for (auto& currentValue : downcast<CSSValueList>(value)) {
913         if (is<CSSGridLineNamesValue>(currentValue.get())) {
914             createGridLineNamesList(currentValue.get(), currentNamedGridLine, tracksData.m_namedGridLines, tracksData.m_orderedNamedGridLines);
915             continue;
916         }
917
918         if (is<CSSGridAutoRepeatValue>(currentValue)) {
919             ASSERT(tracksData.m_autoRepeatTrackSizes.isEmpty());
920             unsigned autoRepeatIndex = 0;
921             CSSValueID autoRepeatID = downcast<CSSGridAutoRepeatValue>(currentValue.get()).autoRepeatID();
922             ASSERT(autoRepeatID == CSSValueAutoFill || autoRepeatID == CSSValueAutoFit);
923             tracksData.m_autoRepeatType = autoRepeatID == CSSValueAutoFill ? AutoFill : AutoFit;
924             for (auto& autoRepeatValue : downcast<CSSValueList>(currentValue.get())) {
925                 if (is<CSSGridLineNamesValue>(autoRepeatValue.get())) {
926                     createGridLineNamesList(autoRepeatValue.get(), autoRepeatIndex, tracksData.m_autoRepeatNamedGridLines, tracksData.m_autoRepeatOrderedNamedGridLines);
927                     continue;
928                 }
929                 ++autoRepeatIndex;
930                 tracksData.m_autoRepeatTrackSizes.append(createGridTrackSize(autoRepeatValue.get(), styleResolver));
931             }
932             tracksData.m_autoRepeatInsertionPoint = currentNamedGridLine++;
933             continue;
934         }
935
936         ++currentNamedGridLine;
937         tracksData.m_trackSizes.append(createGridTrackSize(currentValue, styleResolver));
938     }
939
940     // The parser should have rejected any <track-list> without any <track-size> as
941     // this is not conformant to the syntax.
942     ASSERT(!tracksData.m_trackSizes.isEmpty() || !tracksData.m_autoRepeatTrackSizes.isEmpty());
943     return true;
944 }
945
946 inline bool StyleBuilderConverter::createGridPosition(const CSSValue& value, GridPosition& position)
947 {
948     // We accept the specification's grammar:
949     // auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
950     if (is<CSSPrimitiveValue>(value)) {
951         auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
952         // We translate <ident> to <string> during parsing as it makes handling it simpler.
953         if (primitiveValue.isString()) {
954             position.setNamedGridArea(primitiveValue.stringValue());
955             return true;
956         }
957
958         ASSERT(primitiveValue.valueID() == CSSValueAuto);
959         return true;
960     }
961
962     auto& values = downcast<CSSValueList>(value);
963     ASSERT(values.length());
964
965     auto it = values.begin();
966     const CSSPrimitiveValue* currentValue = &downcast<CSSPrimitiveValue>(it->get());
967     bool isSpanPosition = false;
968     if (currentValue->valueID() == CSSValueSpan) {
969         isSpanPosition = true;
970         ++it;
971         currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
972     }
973
974     int gridLineNumber = 0;
975     if (currentValue && currentValue->isNumber()) {
976         gridLineNumber = currentValue->intValue();
977         ++it;
978         currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
979     }
980
981     String gridLineName;
982     if (currentValue && currentValue->isString()) {
983         gridLineName = currentValue->stringValue();
984         ++it;
985     }
986
987     ASSERT(it == values.end());
988     if (isSpanPosition)
989         position.setSpanPosition(gridLineNumber ? gridLineNumber : 1, gridLineName);
990     else
991         position.setExplicitPosition(gridLineNumber, gridLineName);
992
993     return true;
994 }
995
996 inline void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
997 {
998     for (auto& area : namedGridAreas) {
999         GridSpan areaSpan = direction == ForRows ? area.value.rows : area.value.columns;
1000         {
1001             auto& startVector = namedGridLines.add(area.key + "-start", Vector<unsigned>()).iterator->value;
1002             startVector.append(areaSpan.startLine());
1003             std::sort(startVector.begin(), startVector.end());
1004         }
1005         {
1006             auto& endVector = namedGridLines.add(area.key + "-end", Vector<unsigned>()).iterator->value;
1007             endVector.append(areaSpan.endLine());
1008             std::sort(endVector.begin(), endVector.end());
1009         }
1010     }
1011 }
1012
1013 inline Vector<GridTrackSize> StyleBuilderConverter::convertGridTrackSizeList(StyleResolver& styleResolver, const CSSValue& value)
1014 {
1015     ASSERT(value.isValueList());
1016     auto& valueList = downcast<CSSValueList>(value);
1017     Vector<GridTrackSize> trackSizes;
1018     trackSizes.reserveInitialCapacity(valueList.length());
1019     for (auto& currValue : valueList) {
1020         ASSERT(!currValue->isGridLineNamesValue());
1021         ASSERT(!currValue->isGridAutoRepeatValue());
1022         trackSizes.uncheckedAppend(convertGridTrackSize(styleResolver, currValue));
1023     }
1024     return trackSizes;
1025 }
1026
1027 inline GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolver& styleResolver, const CSSValue& value)
1028 {
1029     return createGridTrackSize(value, styleResolver);
1030 }
1031
1032 inline std::optional<GridPosition> StyleBuilderConverter::convertGridPosition(StyleResolver&, const CSSValue& value)
1033 {
1034     GridPosition gridPosition;
1035     if (createGridPosition(value, gridPosition))
1036         return gridPosition;
1037     return std::nullopt;
1038 }
1039
1040 inline GridAutoFlow StyleBuilderConverter::convertGridAutoFlow(StyleResolver&, const CSSValue& value)
1041 {
1042     auto& list = downcast<CSSValueList>(value);
1043     if (!list.length())
1044         return RenderStyle::initialGridAutoFlow();
1045
1046     auto& first = downcast<CSSPrimitiveValue>(*list.item(0));
1047     auto* second = downcast<CSSPrimitiveValue>(list.item(1));
1048
1049     GridAutoFlow autoFlow = RenderStyle::initialGridAutoFlow();
1050     switch (first.valueID()) {
1051     case CSSValueRow:
1052         if (second && second->valueID() == CSSValueDense)
1053             autoFlow =  AutoFlowRowDense;
1054         else
1055             autoFlow = AutoFlowRow;
1056         break;
1057     case CSSValueColumn:
1058         if (second && second->valueID() == CSSValueDense)
1059             autoFlow = AutoFlowColumnDense;
1060         else
1061             autoFlow = AutoFlowColumn;
1062         break;
1063     case CSSValueDense:
1064         if (second && second->valueID() == CSSValueColumn)
1065             return AutoFlowColumnDense;
1066         return AutoFlowRowDense;
1067     default:
1068         ASSERT_NOT_REACHED();
1069         break;
1070     }
1071
1072     return autoFlow;
1073 }
1074
1075 inline CSSToLengthConversionData StyleBuilderConverter::csstoLengthConversionDataWithTextZoomFactor(StyleResolver& styleResolver)
1076 {
1077     if (auto* frame = styleResolver.document().frame()) {
1078         float textZoomFactor = styleResolver.style()->textZoom() != TextZoomReset ? frame->textZoomFactor() : 1.0f;
1079         return styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(styleResolver.style()->effectiveZoom() * textZoomFactor);
1080     }
1081     return styleResolver.state().cssToLengthConversionData();
1082 }
1083
1084 inline std::optional<Length> StyleBuilderConverter::convertWordSpacing(StyleResolver& styleResolver, const CSSValue& value)
1085 {
1086     std::optional<Length> wordSpacing;
1087     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1088     if (primitiveValue.valueID() == CSSValueNormal)
1089         wordSpacing = RenderStyle::initialWordSpacing();
1090     else if (primitiveValue.isLength())
1091         wordSpacing = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(styleResolver));
1092     else if (primitiveValue.isPercentage())
1093         wordSpacing = Length(clampTo<float>(primitiveValue.doubleValue(), minValueForCssLength, maxValueForCssLength), Percent);
1094     else if (primitiveValue.isNumber())
1095         wordSpacing = Length(primitiveValue.doubleValue(), Fixed);
1096
1097     return wordSpacing;
1098 }
1099
1100 inline std::optional<float> StyleBuilderConverter::convertPerspective(StyleResolver& styleResolver, const CSSValue& value)
1101 {
1102     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1103     if (primitiveValue.valueID() == CSSValueNone)
1104         return 0.f;
1105
1106     float perspective = -1;
1107     if (primitiveValue.isLength())
1108         perspective = primitiveValue.computeLength<float>(styleResolver.state().cssToLengthConversionData());
1109     else if (primitiveValue.isNumber())
1110         perspective = primitiveValue.doubleValue() * styleResolver.state().cssToLengthConversionData().zoom();
1111     else
1112         ASSERT_NOT_REACHED();
1113
1114     return perspective < 0 ? std::optional<float>(std::nullopt) : std::optional<float>(perspective);
1115 }
1116
1117 inline std::optional<Length> StyleBuilderConverter::convertMarqueeIncrement(StyleResolver& styleResolver, const CSSValue& value)
1118 {
1119     std::optional<Length> marqueeLength;
1120     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1121     switch (primitiveValue.valueID()) {
1122     case CSSValueSmall:
1123         marqueeLength = Length(1, Fixed); // 1px.
1124         break;
1125     case CSSValueNormal:
1126         marqueeLength = Length(6, Fixed); // 6px. The WinIE default.
1127         break;
1128     case CSSValueLarge:
1129         marqueeLength = Length(36, Fixed); // 36px.
1130         break;
1131     case CSSValueInvalid: {
1132         Length length = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
1133         if (!length.isUndefined())
1134             marqueeLength = length;
1135         break;
1136     }
1137     default:
1138         break;
1139     }
1140     return marqueeLength;
1141 }
1142
1143 inline std::optional<FilterOperations> StyleBuilderConverter::convertFilterOperations(StyleResolver& styleResolver, const CSSValue& value)
1144 {
1145     FilterOperations operations;
1146     if (styleResolver.createFilterOperations(value, operations))
1147         return operations;
1148     return std::nullopt;
1149 }
1150
1151 inline FontFeatureSettings StyleBuilderConverter::convertFontFeatureSettings(StyleResolver&, const CSSValue& value)
1152 {
1153     if (is<CSSPrimitiveValue>(value)) {
1154         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1155         return { };
1156     }
1157
1158     FontFeatureSettings settings;
1159     for (auto& item : downcast<CSSValueList>(value)) {
1160         auto& feature = downcast<CSSFontFeatureValue>(item.get());
1161         settings.insert(FontFeature(feature.tag(), feature.value()));
1162     }
1163     return settings;
1164 }
1165
1166 inline FontSelectionValue StyleBuilderConverter::convertFontWeightFromValue(const CSSValue& value)
1167 {
1168     ASSERT(is<CSSPrimitiveValue>(value));
1169     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1170
1171     if (primitiveValue.isNumber())
1172         return FontSelectionValue::clampFloat(primitiveValue.floatValue());
1173
1174     ASSERT(primitiveValue.isValueID());
1175     switch (primitiveValue.valueID()) {
1176     case CSSValueNormal:
1177         return normalWeightValue();
1178     case CSSValueBold:
1179     case CSSValueBolder:
1180         return boldWeightValue();
1181     case CSSValueLighter:
1182         return lightWeightValue();
1183     default:
1184         ASSERT_NOT_REACHED();
1185         return normalWeightValue();
1186     }
1187 }
1188
1189 inline FontSelectionValue StyleBuilderConverter::convertFontStretchFromValue(const CSSValue& value)
1190 {
1191     ASSERT(is<CSSPrimitiveValue>(value));
1192     const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1193
1194     if (primitiveValue.isPercentage())
1195         return FontSelectionValue::clampFloat(primitiveValue.floatValue());
1196
1197     ASSERT(primitiveValue.isValueID());
1198     if (auto value = fontStretchValue(primitiveValue.valueID()))
1199         return value.value();
1200     ASSERT_NOT_REACHED();
1201     return normalStretchValue();
1202 }
1203
1204 inline FontSelectionValue StyleBuilderConverter::convertFontStyleFromValue(const CSSValue& value)
1205 {
1206     ASSERT(is<CSSFontStyleValue>(value));
1207     const auto& fontStyleValue = downcast<CSSFontStyleValue>(value);
1208
1209     auto valueID = fontStyleValue.fontStyleValue->valueID();
1210     if (valueID == CSSValueNormal)
1211         return normalItalicValue();
1212     if (valueID == CSSValueItalic)
1213         return italicValue();
1214     ASSERT(valueID == CSSValueOblique);
1215     if (auto* obliqueValue = fontStyleValue.obliqueValue.get())
1216         return FontSelectionValue(obliqueValue->value<float>(CSSPrimitiveValue::CSS_DEG));
1217     return italicValue();
1218 }
1219
1220 inline FontSelectionValue StyleBuilderConverter::convertFontWeight(StyleResolver& styleResolver, const CSSValue& value)
1221 {
1222     ASSERT(is<CSSPrimitiveValue>(value));
1223     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1224     if (primitiveValue.isValueID()) {
1225         auto valueID = primitiveValue.valueID();
1226         if (valueID == CSSValueBolder)
1227             return FontCascadeDescription::bolderWeight(styleResolver.parentStyle()->fontDescription().weight());
1228         if (valueID == CSSValueLighter)
1229             return FontCascadeDescription::lighterWeight(styleResolver.parentStyle()->fontDescription().weight());
1230     }
1231     return convertFontWeightFromValue(value);
1232 }
1233
1234 inline FontSelectionValue StyleBuilderConverter::convertFontStretch(StyleResolver&, const CSSValue& value)
1235 {
1236     return convertFontStretchFromValue(value);
1237 }
1238
1239 #if ENABLE(VARIATION_FONTS)
1240 inline FontVariationSettings StyleBuilderConverter::convertFontVariationSettings(StyleResolver&, const CSSValue& value)
1241 {
1242     if (is<CSSPrimitiveValue>(value)) {
1243         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1244         return { };
1245     }
1246
1247     FontVariationSettings settings;
1248     for (auto& item : downcast<CSSValueList>(value)) {
1249         auto& feature = downcast<CSSFontVariationValue>(item.get());
1250         settings.insert({ feature.tag(), feature.value() });
1251     }
1252     return settings;
1253 }
1254 #endif
1255
1256 #if PLATFORM(IOS)
1257 inline bool StyleBuilderConverter::convertTouchCallout(StyleResolver&, const CSSValue& value)
1258 {
1259     return !equalLettersIgnoringASCIICase(downcast<CSSPrimitiveValue>(value).stringValue(), "none");
1260 }
1261 #endif
1262
1263 #if ENABLE(TOUCH_EVENTS)
1264 inline Color StyleBuilderConverter::convertTapHighlightColor(StyleResolver& styleResolver, const CSSValue& value)
1265 {
1266     return styleResolver.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1267 }
1268 #endif
1269
1270 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1271 inline bool StyleBuilderConverter::convertOverflowScrolling(StyleResolver&, const CSSValue& value)
1272 {
1273     return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueTouch;
1274 }
1275 #endif
1276
1277 inline SVGLengthValue StyleBuilderConverter::convertSVGLengthValue(StyleResolver&, const CSSValue& value)
1278 {
1279     return SVGLengthValue::fromCSSPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1280 }
1281
1282 inline Vector<SVGLengthValue> StyleBuilderConverter::convertSVGLengthVector(StyleResolver& styleResolver, const CSSValue& value)
1283 {
1284     auto& valueList = downcast<CSSValueList>(value);
1285
1286     Vector<SVGLengthValue> svgLengths;
1287     svgLengths.reserveInitialCapacity(valueList.length());
1288     for (auto& item : valueList)
1289         svgLengths.uncheckedAppend(convertSVGLengthValue(styleResolver, item));
1290
1291     return svgLengths;
1292 }
1293
1294 inline Vector<SVGLengthValue> StyleBuilderConverter::convertStrokeDashArray(StyleResolver& styleResolver, const CSSValue& value)
1295 {
1296     if (is<CSSPrimitiveValue>(value)) {
1297         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
1298         return SVGRenderStyle::initialStrokeDashArray();
1299     }
1300
1301     return convertSVGLengthVector(styleResolver, value);
1302 }
1303
1304 inline PaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolver&, const CSSValue& value)
1305 {
1306     if (is<CSSPrimitiveValue>(value)) {
1307         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1308         return PaintOrder::Normal;
1309     }
1310
1311     auto& orderTypeList = downcast<CSSValueList>(value);
1312     switch (downcast<CSSPrimitiveValue>(*orderTypeList.itemWithoutBoundsCheck(0)).valueID()) {
1313     case CSSValueFill:
1314         return orderTypeList.length() > 1 ? PaintOrder::FillMarkers : PaintOrder::Fill;
1315     case CSSValueStroke:
1316         return orderTypeList.length() > 1 ? PaintOrder::StrokeMarkers : PaintOrder::Stroke;
1317     case CSSValueMarkers:
1318         return orderTypeList.length() > 1 ? PaintOrder::MarkersStroke : PaintOrder::Markers;
1319     default:
1320         ASSERT_NOT_REACHED();
1321         return PaintOrder::Normal;
1322     }
1323 }
1324
1325 inline float StyleBuilderConverter::convertOpacity(StyleResolver&, const CSSValue& value)
1326 {
1327     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1328     float opacity = primitiveValue.floatValue();
1329     if (primitiveValue.isPercentage())
1330         opacity /= 100.0f;
1331     return opacity;
1332 }
1333
1334 inline String StyleBuilderConverter::convertSVGURIReference(StyleResolver& styleResolver, const CSSValue& value)
1335 {
1336     String s;
1337     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1338     if (primitiveValue.isURI())
1339         s = primitiveValue.stringValue();
1340
1341     return SVGURIReference::fragmentIdentifierFromIRIString(s, styleResolver.document());
1342 }
1343
1344 inline Color StyleBuilderConverter::convertSVGColor(StyleResolver& styleResolver, const CSSValue& value)
1345 {
1346     return styleResolver.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1347 }
1348
1349 inline StyleSelfAlignmentData StyleBuilderConverter::convertSelfOrDefaultAlignmentData(StyleResolver&, const CSSValue& value)
1350 {
1351     StyleSelfAlignmentData alignmentData = RenderStyle::initialSelfAlignment();
1352     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1353     if (Pair* pairValue = primitiveValue.pairValue()) {
1354         if (pairValue->first()->valueID() == CSSValueLegacy) {
1355             alignmentData.setPositionType(LegacyPosition);
1356             alignmentData.setPosition(*pairValue->second());
1357         } else if (pairValue->first()->valueID() == CSSValueFirst) {
1358             alignmentData.setPosition(ItemPositionBaseline);
1359         } else if (pairValue->first()->valueID() == CSSValueLast) {
1360             alignmentData.setPosition(ItemPositionLastBaseline);
1361         } else {
1362             alignmentData.setPosition(*pairValue->first());
1363             alignmentData.setOverflow(*pairValue->second());
1364         }
1365     } else
1366         alignmentData.setPosition(primitiveValue);
1367     return alignmentData;
1368 }
1369
1370 inline StyleContentAlignmentData StyleBuilderConverter::convertContentAlignmentData(StyleResolver&, const CSSValue& value)
1371 {
1372     StyleContentAlignmentData alignmentData = RenderStyle::initialContentAlignment();
1373     if (RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled()) {
1374         if (!is<CSSContentDistributionValue>(value))
1375             return alignmentData;
1376         auto& contentValue = downcast<CSSContentDistributionValue>(value);
1377         if (contentValue.distribution()->valueID() != CSSValueInvalid)
1378             alignmentData.setDistribution(contentValue.distribution().get());
1379         if (contentValue.position()->valueID() != CSSValueInvalid)
1380             alignmentData.setPosition(contentValue.position().get());
1381         if (contentValue.overflow()->valueID() != CSSValueInvalid)
1382             alignmentData.setOverflow(contentValue.overflow().get());
1383         return alignmentData;
1384     }
1385     if (!is<CSSPrimitiveValue>(value))
1386         return alignmentData;
1387     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1388     switch (primitiveValue.valueID()) {
1389     case CSSValueStretch:
1390     case CSSValueSpaceBetween:
1391     case CSSValueSpaceAround:
1392         alignmentData.setDistribution(primitiveValue);
1393         break;
1394     case CSSValueFlexStart:
1395     case CSSValueFlexEnd:
1396     case CSSValueCenter:
1397         alignmentData.setPosition(primitiveValue);
1398         break;
1399     default:
1400         ASSERT_NOT_REACHED();
1401     }
1402     return alignmentData;
1403 }
1404
1405 inline EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolver&, const CSSValue& value)
1406 {
1407     float angle = fabsf(fmodf(downcast<CSSPrimitiveValue>(value).floatValue(), 360.0f));
1408     if (angle <= 45.0f || angle > 315.0f)
1409         return GO_0DEG;
1410     if (angle > 45.0f && angle <= 135.0f)
1411         return GO_90DEG;
1412     if (angle > 135.0f && angle <= 225.0f)
1413         return GO_180DEG;
1414     return GO_270DEG;
1415 }
1416
1417 inline EGlyphOrientation StyleBuilderConverter::convertGlyphOrientationOrAuto(StyleResolver& styleResolver, const CSSValue& value)
1418 {
1419     if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
1420         return GO_AUTO;
1421     return convertGlyphOrientation(styleResolver, value);
1422 }
1423
1424 inline std::optional<Length> StyleBuilderConverter::convertLineHeight(StyleResolver& styleResolver, const CSSValue& value, float multiplier)
1425 {
1426     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1427     if (primitiveValue.valueID() == CSSValueNormal)
1428         return RenderStyle::initialLineHeight();
1429
1430     if (primitiveValue.isLength()) {
1431         Length length = primitiveValue.computeLength<Length>(StyleBuilderConverter::csstoLengthConversionDataWithTextZoomFactor(styleResolver));
1432         if (multiplier != 1.f)
1433             length = Length(length.value() * multiplier, Fixed);
1434         return length;
1435     }
1436     if (primitiveValue.isPercentage()) {
1437         // FIXME: percentage should not be restricted to an integer here.
1438         return Length((styleResolver.style()->computedFontSize() * primitiveValue.intValue()) / 100, Fixed);
1439     }
1440     if (primitiveValue.isNumber()) {
1441         // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent).
1442         return Length(primitiveValue.doubleValue() * multiplier * 100.0, Percent);
1443     }
1444     return std::nullopt;
1445 }
1446
1447 inline FontSynthesis StyleBuilderConverter::convertFontSynthesis(StyleResolver&, const CSSValue& value)
1448 {
1449     if (is<CSSPrimitiveValue>(value)) {
1450         ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
1451         return FontSynthesisNone;
1452     }
1453
1454     FontSynthesis result = FontSynthesisNone;
1455     ASSERT(is<CSSValueList>(value));
1456     for (const CSSValue& v : downcast<CSSValueList>(value)) {
1457         switch (downcast<CSSPrimitiveValue>(v).valueID()) {
1458         case CSSValueWeight:
1459             result |= FontSynthesisWeight;
1460             break;
1461         case CSSValueStyle:
1462             result |= FontSynthesisStyle;
1463             break;
1464         case CSSValueSmallCaps:
1465             result |= FontSynthesisSmallCaps;
1466             break;
1467         default:
1468             ASSERT_NOT_REACHED();
1469             break;
1470         }
1471     }
1472
1473     return result;
1474 }
1475
1476 inline BreakBetween StyleBuilderConverter::convertPageBreakBetween(StyleResolver&, const CSSValue& value)
1477 {
1478     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1479     if (primitiveValue.valueID() == CSSValueAlways)
1480         return PageBreakBetween;
1481     if (primitiveValue.valueID() == CSSValueAvoid)
1482         return AvoidPageBreakBetween;
1483     return primitiveValue;
1484 }
1485
1486 inline BreakInside StyleBuilderConverter::convertPageBreakInside(StyleResolver&, const CSSValue& value)
1487 {
1488     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1489     if (primitiveValue.valueID() == CSSValueAvoid)
1490         return AvoidPageBreakInside;
1491     return primitiveValue;
1492 }
1493
1494 inline BreakBetween StyleBuilderConverter::convertColumnBreakBetween(StyleResolver&, const CSSValue& value)
1495 {
1496     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1497     if (primitiveValue.valueID() == CSSValueAlways)
1498         return ColumnBreakBetween;
1499     if (primitiveValue.valueID() == CSSValueAvoid)
1500         return AvoidColumnBreakBetween;
1501     return primitiveValue;
1502 }
1503
1504 inline BreakInside StyleBuilderConverter::convertColumnBreakInside(StyleResolver&, const CSSValue& value)
1505 {
1506     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1507     if (primitiveValue.valueID() == CSSValueAvoid)
1508         return AvoidColumnBreakInside;
1509     return primitiveValue;
1510 }
1511
1512 #if ENABLE(CSS_REGIONS)
1513 inline BreakBetween StyleBuilderConverter::convertRegionBreakBetween(StyleResolver&, const CSSValue& value)
1514 {
1515     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1516     if (primitiveValue.valueID() == CSSValueAlways)
1517         return RegionBreakBetween;
1518     if (primitiveValue.valueID() == CSSValueAvoid)
1519         return AvoidRegionBreakBetween;
1520     return primitiveValue;
1521 }
1522
1523 inline BreakInside StyleBuilderConverter::convertRegionBreakInside(StyleResolver&, const CSSValue& value)
1524 {
1525     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1526     if (primitiveValue.valueID() == CSSValueAvoid)
1527         return AvoidRegionBreakInside;
1528     return primitiveValue;
1529 }
1530 #endif
1531
1532 inline HangingPunctuation StyleBuilderConverter::convertHangingPunctuation(StyleResolver&, const CSSValue& value)
1533 {
1534     HangingPunctuation result = RenderStyle::initialHangingPunctuation();
1535     if (is<CSSValueList>(value)) {
1536         for (auto& currentValue : downcast<CSSValueList>(value))
1537             result |= downcast<CSSPrimitiveValue>(currentValue.get());
1538     }
1539     return result;
1540 }
1541
1542 } // namespace WebCore