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