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