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