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