Get rid of some unnecessary custom StyleBuilder code
[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 "CSSFunctionValue.h"
33 #include "CSSGridLineNamesValue.h"
34 #include "CSSGridTemplateAreasValue.h"
35 #include "CSSImageGeneratorValue.h"
36 #include "CSSImageSetValue.h"
37 #include "CSSImageValue.h"
38 #include "CSSPrimitiveValue.h"
39 #include "CSSReflectValue.h"
40 #include "Frame.h"
41 #include "Length.h"
42 #include "Pair.h"
43 #include "QuotesData.h"
44 #include "Settings.h"
45 #include "StyleResolver.h"
46 #include "TransformFunctions.h"
47
48 namespace WebCore {
49
50 // Note that we assume the CSS parser only allows valid CSSValue types.
51 class StyleBuilderConverter {
52 public:
53     static Length convertLength(StyleResolver&, CSSValue&);
54     static Length convertLengthOrAuto(StyleResolver&, CSSValue&);
55     static Length convertLengthSizing(StyleResolver&, CSSValue&);
56     static Length convertLengthMaxSizing(StyleResolver&, CSSValue&);
57     template <typename T> static T convertComputedLength(StyleResolver&, CSSValue&);
58     template <typename T> static T convertLineWidth(StyleResolver&, CSSValue&);
59     static float convertSpacing(StyleResolver&, CSSValue&);
60     static LengthSize convertRadius(StyleResolver&, CSSValue&);
61     static TextDecoration convertTextDecoration(StyleResolver&, CSSValue&);
62     template <typename T> static T convertNumber(StyleResolver&, CSSValue&);
63     static short convertWebkitHyphenateLimitLines(StyleResolver&, CSSValue&);
64     template <CSSPropertyID property> static NinePieceImage convertBorderImage(StyleResolver&, CSSValue&);
65     template <CSSPropertyID property> static NinePieceImage convertBorderMask(StyleResolver&, CSSValue&);
66     template <CSSPropertyID property> static PassRefPtr<StyleImage> convertStyleImage(StyleResolver&, CSSValue&);
67     static TransformOperations convertTransform(StyleResolver&, CSSValue&);
68     static String convertString(StyleResolver&, CSSValue&);
69     static String convertStringOrAuto(StyleResolver&, CSSValue&);
70     static String convertStringOrNone(StyleResolver&, CSSValue&);
71     static TextEmphasisPosition convertTextEmphasisPosition(StyleResolver&, CSSValue&);
72     static ETextAlign convertTextAlign(StyleResolver&, CSSValue&);
73     static PassRefPtr<ClipPathOperation> convertClipPath(StyleResolver&, CSSValue&);
74     static EResize convertResize(StyleResolver&, CSSValue&);
75     static int convertMarqueeRepetition(StyleResolver&, CSSValue&);
76     static int convertMarqueeSpeed(StyleResolver&, CSSValue&);
77     static PassRefPtr<QuotesData> convertQuotes(StyleResolver&, CSSValue&);
78     static TextUnderlinePosition convertTextUnderlinePosition(StyleResolver&, CSSValue&);
79     static PassRefPtr<StyleReflection> convertReflection(StyleResolver&, CSSValue&);
80     static IntSize convertInitialLetter(StyleResolver&, CSSValue&);
81     static float convertTextStrokeWidth(StyleResolver&, CSSValue&);
82     static LineBoxContain convertLineBoxContain(StyleResolver&, CSSValue&);
83     static TextDecorationSkip convertTextDecorationSkip(StyleResolver&, CSSValue&);
84     static PassRefPtr<ShapeValue> convertShapeValue(StyleResolver&, CSSValue&);
85 #if ENABLE(CSS_GRID_LAYOUT)
86     static bool convertGridTrackSize(StyleResolver&, CSSValue&, GridTrackSize&);
87     static bool convertGridPosition(StyleResolver&, CSSValue&, GridPosition&);
88     static GridAutoFlow convertGridAutoFlow(StyleResolver&, CSSValue&);
89 #endif // ENABLE(CSS_GRID_LAYOUT)
90     static bool convertWordSpacing(StyleResolver&, CSSValue&, Length&);
91     static bool convertPerspective(StyleResolver&, CSSValue&, float&);
92     static bool convertMarqueeIncrement(StyleResolver&, CSSValue&, Length&);
93
94 private:
95     friend class StyleBuilderCustom;
96
97     static Length convertToRadiusLength(CSSToLengthConversionData&, CSSPrimitiveValue&);
98     static TextEmphasisPosition valueToEmphasisPosition(CSSPrimitiveValue&);
99     static TextDecorationSkip valueToDecorationSkip(const CSSPrimitiveValue&);
100 #if ENABLE(CSS_GRID_LAYOUT)
101     static bool createGridTrackBreadth(CSSPrimitiveValue&, StyleResolver&, GridLength&);
102     static bool createGridTrackSize(CSSValue&, GridTrackSize&, StyleResolver&);
103     static bool createGridTrackList(CSSValue&, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap&, OrderedNamedGridLinesMap&, StyleResolver&);
104     static bool createGridPosition(CSSValue&, GridPosition&);
105     static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap&, NamedGridLinesMap&, GridTrackSizingDirection);
106 #endif // ENABLE(CSS_GRID_LAYOUT)
107     static CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(StyleResolver&);
108 };
109
110 inline Length StyleBuilderConverter::convertLength(StyleResolver& styleResolver, CSSValue& value)
111 {
112     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
113     CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
114         styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
115         : styleResolver.state().cssToLengthConversionData();
116
117     if (primitiveValue.isLength()) {
118         Length length = primitiveValue.computeLength<Length>(conversionData);
119         length.setHasQuirk(primitiveValue.isQuirkValue());
120         return length;
121     }
122
123     if (primitiveValue.isPercentage())
124         return Length(primitiveValue.getDoubleValue(), Percent);
125
126     if (primitiveValue.isCalculatedPercentageWithLength())
127         return Length(primitiveValue.cssCalcValue()->createCalculationValue(conversionData));
128
129     ASSERT_NOT_REACHED();
130     return Length(0, Fixed);
131 }
132
133 inline Length StyleBuilderConverter::convertLengthOrAuto(StyleResolver& styleResolver, CSSValue& value)
134 {
135     if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueAuto)
136         return Length(Auto);
137     return convertLength(styleResolver, value);
138 }
139
140 inline Length StyleBuilderConverter::convertLengthSizing(StyleResolver& styleResolver, CSSValue& value)
141 {
142     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
143     switch (primitiveValue.getValueID()) {
144     case CSSValueInvalid:
145         return convertLength(styleResolver, value);
146     case CSSValueIntrinsic:
147         return Length(Intrinsic);
148     case CSSValueMinIntrinsic:
149         return Length(MinIntrinsic);
150     case CSSValueWebkitMinContent:
151         return Length(MinContent);
152     case CSSValueWebkitMaxContent:
153         return Length(MaxContent);
154     case CSSValueWebkitFillAvailable:
155         return Length(FillAvailable);
156     case CSSValueWebkitFitContent:
157         return Length(FitContent);
158     case CSSValueAuto:
159         return Length(Auto);
160     default:
161         ASSERT_NOT_REACHED();
162         return Length();
163     }
164 }
165
166 inline Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolver& styleResolver, CSSValue& value)
167 {
168     if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone)
169         return Length(Undefined);
170     return convertLengthSizing(styleResolver, value);
171 }
172
173 template <typename T>
174 inline T StyleBuilderConverter::convertComputedLength(StyleResolver& styleResolver, CSSValue& value)
175 {
176     return downcast<CSSPrimitiveValue>(value).computeLength<T>(styleResolver.state().cssToLengthConversionData());
177 }
178
179 template <typename T>
180 inline T StyleBuilderConverter::convertLineWidth(StyleResolver& styleResolver, CSSValue& value)
181 {
182     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
183     switch (primitiveValue.getValueID()) {
184     case CSSValueThin:
185         return 1;
186     case CSSValueMedium:
187         return 3;
188     case CSSValueThick:
189         return 5;
190     case CSSValueInvalid: {
191         // Any original result that was >= 1 should not be allowed to fall below 1.
192         // This keeps border lines from vanishing.
193         T result = convertComputedLength<T>(styleResolver, value);
194         if (styleResolver.state().style()->effectiveZoom() < 1.0f && result < 1.0) {
195             T originalLength = primitiveValue.computeLength<T>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0));
196             if (originalLength >= 1.0)
197                 return 1;
198         }
199         return result;
200     }
201     default:
202         ASSERT_NOT_REACHED();
203         return 0;
204     }
205 }
206
207 inline float StyleBuilderConverter::convertSpacing(StyleResolver& styleResolver, CSSValue& value)
208 {
209     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
210     if (primitiveValue.getValueID() == CSSValueNormal)
211         return 0.f;
212
213     CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ?
214         styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
215         : styleResolver.state().cssToLengthConversionData();
216     return primitiveValue.computeLength<float>(conversionData);
217 }
218
219 inline Length StyleBuilderConverter::convertToRadiusLength(CSSToLengthConversionData& conversionData, CSSPrimitiveValue& value)
220 {
221     if (value.isPercentage())
222         return Length(value.getDoubleValue(), Percent);
223     if (value.isCalculatedPercentageWithLength())
224         return Length(value.cssCalcValue()->createCalculationValue(conversionData));
225     return value.computeLength<Length>(conversionData);
226 }
227
228 inline LengthSize StyleBuilderConverter::convertRadius(StyleResolver& styleResolver, CSSValue& value)
229 {
230     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
231     Pair* pair = primitiveValue.getPairValue();
232     if (!pair || !pair->first() || !pair->second())
233         return LengthSize(Length(0, Fixed), Length(0, Fixed));
234
235     CSSToLengthConversionData conversionData = styleResolver.state().cssToLengthConversionData();
236     Length radiusWidth = convertToRadiusLength(conversionData, *pair->first());
237     Length radiusHeight = convertToRadiusLength(conversionData, *pair->second());
238
239     ASSERT(!radiusWidth.isNegative());
240     ASSERT(!radiusHeight.isNegative());
241     if (radiusWidth.isZero() || radiusHeight.isZero())
242         return LengthSize(Length(0, Fixed), Length(0, Fixed));
243
244     return LengthSize(radiusWidth, radiusHeight);
245 }
246
247 inline TextDecoration StyleBuilderConverter::convertTextDecoration(StyleResolver&, CSSValue& value)
248 {
249     TextDecoration result = RenderStyle::initialTextDecoration();
250     if (is<CSSValueList>(value)) {
251         for (auto& currentValue : downcast<CSSValueList>(value))
252             result |= downcast<CSSPrimitiveValue>(currentValue.get());
253     }
254     return result;
255 }
256
257 template <typename T>
258 inline T StyleBuilderConverter::convertNumber(StyleResolver&, CSSValue& value)
259 {
260     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
261     if (primitiveValue.getValueID() == CSSValueAuto)
262         return -1;
263     return primitiveValue.getValue<T>(CSSPrimitiveValue::CSS_NUMBER);
264 }
265
266 inline short StyleBuilderConverter::convertWebkitHyphenateLimitLines(StyleResolver&, CSSValue& value)
267 {
268     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
269     if (primitiveValue.getValueID() == CSSValueNoLimit)
270         return -1;
271     return primitiveValue.getValue<short>(CSSPrimitiveValue::CSS_NUMBER);
272 }
273
274 template <CSSPropertyID property>
275 inline NinePieceImage StyleBuilderConverter::convertBorderImage(StyleResolver& styleResolver, CSSValue& value)
276 {
277     NinePieceImage image;
278     styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
279     return image;
280 }
281
282 template <CSSPropertyID property>
283 inline NinePieceImage StyleBuilderConverter::convertBorderMask(StyleResolver& styleResolver, CSSValue& value)
284 {
285     NinePieceImage image;
286     image.setMaskDefaults();
287     styleResolver.styleMap()->mapNinePieceImage(property, &value, image);
288     return image;
289 }
290
291 template <CSSPropertyID property>
292 inline PassRefPtr<StyleImage> StyleBuilderConverter::convertStyleImage(StyleResolver& styleResolver, CSSValue& value)
293 {
294     return styleResolver.styleImage(property, value);
295 }
296
297 inline TransformOperations StyleBuilderConverter::convertTransform(StyleResolver& styleResolver, CSSValue& value)
298 {
299     TransformOperations operations;
300     transformsForValue(value, styleResolver.state().cssToLengthConversionData(), operations);
301     return operations;
302 }
303
304 inline String StyleBuilderConverter::convertString(StyleResolver&, CSSValue& value)
305 {
306     return downcast<CSSPrimitiveValue>(value).getStringValue();
307 }
308
309 inline String StyleBuilderConverter::convertStringOrAuto(StyleResolver& styleResolver, CSSValue& value)
310 {
311     if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueAuto)
312         return nullAtom;
313     return convertString(styleResolver, value);
314 }
315
316 inline String StyleBuilderConverter::convertStringOrNone(StyleResolver& styleResolver, CSSValue& value)
317 {
318     if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone)
319         return nullAtom;
320     return convertString(styleResolver, value);
321 }
322
323 inline TextEmphasisPosition StyleBuilderConverter::valueToEmphasisPosition(CSSPrimitiveValue& primitiveValue)
324 {
325     ASSERT(primitiveValue.isValueID());
326
327     switch (primitiveValue.getValueID()) {
328     case CSSValueOver:
329         return TextEmphasisPositionOver;
330     case CSSValueUnder:
331         return TextEmphasisPositionUnder;
332     case CSSValueLeft:
333         return TextEmphasisPositionLeft;
334     case CSSValueRight:
335         return TextEmphasisPositionRight;
336     default:
337         break;
338     }
339
340     ASSERT_NOT_REACHED();
341     return RenderStyle::initialTextEmphasisPosition();
342 }
343
344 inline TextEmphasisPosition StyleBuilderConverter::convertTextEmphasisPosition(StyleResolver&, CSSValue& value)
345 {
346     if (is<CSSPrimitiveValue>(value))
347         return valueToEmphasisPosition(downcast<CSSPrimitiveValue>(value));
348
349     TextEmphasisPosition position = 0;
350     for (auto& currentValue : downcast<CSSValueList>(value))
351         position |= valueToEmphasisPosition(downcast<CSSPrimitiveValue>(currentValue.get()));
352     return position;
353 }
354
355 inline ETextAlign StyleBuilderConverter::convertTextAlign(StyleResolver& styleResolver, CSSValue& value)
356 {
357     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
358     ASSERT(primitiveValue.isValueID());
359
360     if (primitiveValue.getValueID() != CSSValueWebkitMatchParent)
361         return primitiveValue;
362
363     auto* parentStyle = styleResolver.parentStyle();
364     if (parentStyle->textAlign() == TASTART)
365         return parentStyle->isLeftToRightDirection() ? LEFT : RIGHT;
366     if (parentStyle->textAlign() == TAEND)
367         return parentStyle->isLeftToRightDirection() ? RIGHT : LEFT;
368     return parentStyle->textAlign();
369 }
370
371 inline PassRefPtr<ClipPathOperation> StyleBuilderConverter::convertClipPath(StyleResolver& styleResolver, CSSValue& value)
372 {
373     if (is<CSSPrimitiveValue>(value)) {
374         auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
375         if (primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_URI) {
376             String cssURLValue = primitiveValue.getStringValue();
377             URL url = styleResolver.document().completeURL(cssURLValue);
378             // FIXME: It doesn't work with external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=126133)
379             return ReferenceClipPathOperation::create(cssURLValue, url.fragmentIdentifier());
380         }
381         ASSERT(primitiveValue.getValueID() == CSSValueNone);
382         return nullptr;
383     }
384
385     CSSBoxType referenceBox = BoxMissing;
386     RefPtr<ClipPathOperation> operation;
387
388     for (auto& currentValue : downcast<CSSValueList>(value)) {
389         auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
390         if (primitiveValue.isShape()) {
391             ASSERT(!operation);
392             operation = ShapeClipPathOperation::create(basicShapeForValue(styleResolver.state().cssToLengthConversionData(), primitiveValue.getShapeValue()));
393         } else {
394             ASSERT(primitiveValue.getValueID() == CSSValueContentBox
395                    || primitiveValue.getValueID() == CSSValueBorderBox
396                    || primitiveValue.getValueID() == CSSValuePaddingBox
397                    || primitiveValue.getValueID() == CSSValueMarginBox
398                    || primitiveValue.getValueID() == CSSValueFill
399                    || primitiveValue.getValueID() == CSSValueStroke
400                    || primitiveValue.getValueID() == CSSValueViewBox);
401             ASSERT(referenceBox == BoxMissing);
402             referenceBox = primitiveValue;
403         }
404     }
405     if (operation)
406         downcast<ShapeClipPathOperation>(*operation).setReferenceBox(referenceBox);
407     else {
408         ASSERT(referenceBox != BoxMissing);
409         operation = BoxClipPathOperation::create(referenceBox);
410     }
411
412     return operation.release();
413 }
414
415 inline EResize StyleBuilderConverter::convertResize(StyleResolver& styleResolver, CSSValue& value)
416 {
417     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
418
419     EResize resize = RESIZE_NONE;
420     if (primitiveValue.getValueID() == CSSValueAuto) {
421         if (Settings* settings = styleResolver.document().settings())
422             resize = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
423     } else
424         resize = primitiveValue;
425
426     return resize;
427 }
428
429 inline int StyleBuilderConverter::convertMarqueeRepetition(StyleResolver&, CSSValue& value)
430 {
431     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
432     if (primitiveValue.getValueID() == CSSValueInfinite)
433         return -1; // -1 means repeat forever.
434
435     ASSERT(primitiveValue.isNumber());
436     return primitiveValue.getIntValue();
437 }
438
439 inline int StyleBuilderConverter::convertMarqueeSpeed(StyleResolver&, CSSValue& value)
440 {
441     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
442     int speed = 85;
443     if (CSSValueID ident = primitiveValue.getValueID()) {
444         switch (ident) {
445         case CSSValueSlow:
446             speed = 500; // 500 msec.
447             break;
448         case CSSValueNormal:
449             speed = 85; // 85msec. The WinIE default.
450             break;
451         case CSSValueFast:
452             speed = 10; // 10msec. Super fast.
453             break;
454         default:
455             ASSERT_NOT_REACHED();
456             break;
457         }
458     } else if (primitiveValue.isTime())
459         speed = primitiveValue.computeTime<int, CSSPrimitiveValue::Milliseconds>();
460     else {
461         // For scrollamount support.
462         ASSERT(primitiveValue.isNumber());
463         speed = primitiveValue.getIntValue();
464     }
465     return speed;
466 }
467
468 inline PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolver&, CSSValue& value)
469 {
470     if (is<CSSPrimitiveValue>(value)) {
471         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone);
472         return QuotesData::create(Vector<std::pair<String, String>>());
473     }
474
475     CSSValueList& list = downcast<CSSValueList>(value);
476     Vector<std::pair<String, String>> quotes;
477     quotes.reserveInitialCapacity(list.length() / 2);
478     for (unsigned i = 0; i < list.length(); i += 2) {
479         CSSValue* first = list.itemWithoutBoundsCheck(i);
480         // item() returns null if out of bounds so this is safe.
481         CSSValue* second = list.item(i + 1);
482         if (!second)
483             break;
484         String startQuote = downcast<CSSPrimitiveValue>(*first).getStringValue();
485         String endQuote = downcast<CSSPrimitiveValue>(*second).getStringValue();
486         quotes.append(std::make_pair(startQuote, endQuote));
487     }
488     return QuotesData::create(quotes);
489 }
490
491 inline TextUnderlinePosition StyleBuilderConverter::convertTextUnderlinePosition(StyleResolver&, CSSValue& value)
492 {
493     // This is true if value is 'auto' or 'alphabetic'.
494     if (is<CSSPrimitiveValue>(value))
495         return downcast<CSSPrimitiveValue>(value);
496
497     unsigned combinedPosition = 0;
498     for (auto& currentValue : downcast<CSSValueList>(value)) {
499         TextUnderlinePosition position = downcast<CSSPrimitiveValue>(currentValue.get());
500         combinedPosition |= position;
501     }
502     return static_cast<TextUnderlinePosition>(combinedPosition);
503 }
504
505 inline PassRefPtr<StyleReflection> StyleBuilderConverter::convertReflection(StyleResolver& styleResolver, CSSValue& value)
506 {
507     if (is<CSSPrimitiveValue>(value)) {
508         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone);
509         return nullptr;
510     }
511
512     CSSReflectValue& reflectValue = downcast<CSSReflectValue>(value);
513
514     RefPtr<StyleReflection> reflection = StyleReflection::create();
515     reflection->setDirection(*reflectValue.direction());
516
517     if (reflectValue.offset())
518         reflection->setOffset(reflectValue.offset()->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData()));
519
520     NinePieceImage mask;
521     mask.setMaskDefaults();
522     styleResolver.styleMap()->mapNinePieceImage(CSSPropertyWebkitBoxReflect, reflectValue.mask(), mask);
523     reflection->setMask(mask);
524
525     return reflection.release();
526 }
527
528 inline IntSize StyleBuilderConverter::convertInitialLetter(StyleResolver&, CSSValue& value)
529 {
530     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
531
532     if (primitiveValue.getValueID() == CSSValueNormal)
533         return IntSize();
534
535     Pair* pair = primitiveValue.getPairValue();
536     ASSERT(pair);
537     ASSERT(pair->first());
538     ASSERT(pair->second());
539
540     return IntSize(pair->first()->getIntValue(), pair->second()->getIntValue());
541 }
542
543 inline float StyleBuilderConverter::convertTextStrokeWidth(StyleResolver& styleResolver, CSSValue& value)
544 {
545     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
546
547     float width = 0;
548     switch (primitiveValue.getValueID()) {
549     case CSSValueThin:
550     case CSSValueMedium:
551     case CSSValueThick: {
552         double result = 1.0 / 48;
553         if (primitiveValue.getValueID() == CSSValueMedium)
554             result *= 3;
555         else if (primitiveValue.getValueID() == CSSValueThick)
556             result *= 5;
557         Ref<CSSPrimitiveValue> emsValue(CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS));
558         width = convertComputedLength<float>(styleResolver, emsValue);
559         break;
560     }
561     case CSSValueInvalid: {
562         width = convertComputedLength<float>(styleResolver, primitiveValue);
563         break;
564     }
565     default:
566         ASSERT_NOT_REACHED();
567         return 0;
568     }
569
570     return width;
571 }
572
573 inline LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolver&, CSSValue& value)
574 {
575     if (is<CSSPrimitiveValue>(value)) {
576         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone);
577         return LineBoxContainNone;
578     }
579
580     return downcast<CSSLineBoxContainValue>(value).value();
581 }
582
583 inline TextDecorationSkip StyleBuilderConverter::valueToDecorationSkip(const CSSPrimitiveValue& primitiveValue)
584 {
585     ASSERT(primitiveValue.isValueID());
586
587     switch (primitiveValue.getValueID()) {
588     case CSSValueAuto:
589         return TextDecorationSkipAuto;
590     case CSSValueNone:
591         return TextDecorationSkipNone;
592     case CSSValueInk:
593         return TextDecorationSkipInk;
594     case CSSValueObjects:
595         return TextDecorationSkipObjects;
596     default:
597         break;
598     }
599
600     ASSERT_NOT_REACHED();
601     return TextDecorationSkipNone;
602 }
603
604 inline TextDecorationSkip StyleBuilderConverter::convertTextDecorationSkip(StyleResolver&, CSSValue& value)
605 {
606     if (is<CSSPrimitiveValue>(value))
607         return valueToDecorationSkip(downcast<CSSPrimitiveValue>(value));
608
609     TextDecorationSkip skip = RenderStyle::initialTextDecorationSkip();
610     for (auto& currentValue : downcast<CSSValueList>(value))
611         skip |= valueToDecorationSkip(downcast<CSSPrimitiveValue>(currentValue.get()));
612     return skip;
613 }
614
615 #if ENABLE(CSS_SHAPES)
616 static inline bool isImageShape(const CSSValue& value)
617 {
618     return is<CSSImageValue>(value)
619 #if ENABLE(CSS_IMAGE_SET)
620         || is<CSSImageSetValue>(value)
621 #endif 
622         || is<CSSImageGeneratorValue>(value);
623 }
624
625 inline PassRefPtr<ShapeValue> StyleBuilderConverter::convertShapeValue(StyleResolver& styleResolver, CSSValue& value)
626 {
627     if (is<CSSPrimitiveValue>(value)) {
628         ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone);
629         return nullptr;
630     }
631
632     if (isImageShape(value))
633         return ShapeValue::createImageValue(styleResolver.styleImage(CSSPropertyWebkitShapeOutside, value));
634
635     RefPtr<BasicShape> shape;
636     CSSBoxType referenceBox = BoxMissing;
637     for (auto& currentValue : downcast<CSSValueList>(value)) {
638         CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
639         if (primitiveValue.isShape())
640             shape = basicShapeForValue(styleResolver.state().cssToLengthConversionData(), primitiveValue.getShapeValue());
641         else if (primitiveValue.getValueID() == CSSValueContentBox
642             || primitiveValue.getValueID() == CSSValueBorderBox
643             || primitiveValue.getValueID() == CSSValuePaddingBox
644             || primitiveValue.getValueID() == CSSValueMarginBox)
645             referenceBox = primitiveValue;
646         else {
647             ASSERT_NOT_REACHED();
648             return nullptr;
649         }
650     }
651
652     if (shape)
653         return ShapeValue::createShapeValue(shape.release(), referenceBox);
654
655     if (referenceBox != BoxMissing)
656         return ShapeValue::createBoxShapeValue(referenceBox);
657
658     ASSERT_NOT_REACHED();
659     return nullptr;
660 }
661 #endif // ENABLE(CSS_SHAPES)
662
663 #if ENABLE(CSS_GRID_LAYOUT)
664 bool StyleBuilderConverter::createGridTrackBreadth(CSSPrimitiveValue& primitiveValue, StyleResolver& styleResolver, GridLength& workingLength)
665 {
666     if (primitiveValue.getValueID() == CSSValueWebkitMinContent) {
667         workingLength = Length(MinContent);
668         return true;
669     }
670
671     if (primitiveValue.getValueID() == CSSValueWebkitMaxContent) {
672         workingLength = Length(MaxContent);
673         return true;
674     }
675
676     if (primitiveValue.isFlex()) {
677         // Fractional unit.
678         workingLength.setFlex(primitiveValue.getDoubleValue());
679         return true;
680     }
681
682     workingLength = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | AutoConversion>(styleResolver.state().cssToLengthConversionData());
683     if (workingLength.length().isUndefined())
684         return false;
685
686     if (primitiveValue.isLength())
687         workingLength.length().setHasQuirk(primitiveValue.isQuirkValue());
688
689     return true;
690 }
691
692 bool StyleBuilderConverter::createGridTrackSize(CSSValue& value, GridTrackSize& trackSize, StyleResolver& styleResolver)
693 {
694     if (is<CSSPrimitiveValue>(value)) {
695         GridLength workingLength;
696         if (!createGridTrackBreadth(downcast<CSSPrimitiveValue>(value), styleResolver, workingLength))
697             return false;
698
699         trackSize.setLength(workingLength);
700         return true;
701     }
702
703     CSSValueList& arguments = *downcast<CSSFunctionValue>(value).arguments();
704     ASSERT_WITH_SECURITY_IMPLICATION(arguments.length() == 2);
705
706     GridLength minTrackBreadth;
707     GridLength maxTrackBreadth;
708     if (!createGridTrackBreadth(downcast<CSSPrimitiveValue>(*arguments.itemWithoutBoundsCheck(0)), styleResolver, minTrackBreadth) || !createGridTrackBreadth(downcast<CSSPrimitiveValue>(*arguments.itemWithoutBoundsCheck(1)), styleResolver, maxTrackBreadth))
709         return false;
710
711     trackSize.setMinMax(minTrackBreadth, maxTrackBreadth);
712     return true;
713 }
714
715 bool StyleBuilderConverter::createGridTrackList(CSSValue& value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLinesMap& orderedNamedGridLines, StyleResolver& styleResolver)
716 {
717     // Handle 'none'.
718     if (is<CSSPrimitiveValue>(value))
719         return downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueNone;
720
721     if (!is<CSSValueList>(value))
722         return false;
723
724     unsigned currentNamedGridLine = 0;
725     for (auto& currentValue : downcast<CSSValueList>(value)) {
726         if (is<CSSGridLineNamesValue>(currentValue.get())) {
727             for (auto& currentGridLineName : downcast<CSSGridLineNamesValue>(currentValue.get())) {
728                 String namedGridLine = downcast<CSSPrimitiveValue>(currentGridLineName.get()).getStringValue();
729                 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<unsigned>());
730                 result.iterator->value.append(currentNamedGridLine);
731                 OrderedNamedGridLinesMap::AddResult orderedResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
732                 orderedResult.iterator->value.append(namedGridLine);
733             }
734             continue;
735         }
736
737         ++currentNamedGridLine;
738         GridTrackSize trackSize;
739         if (!createGridTrackSize(currentValue, trackSize, styleResolver))
740             return false;
741
742         trackSizes.append(trackSize);
743     }
744
745     // The parser should have rejected any <track-list> without any <track-size> as
746     // this is not conformant to the syntax.
747     ASSERT(!trackSizes.isEmpty());
748     return true;
749 }
750
751 bool StyleBuilderConverter::createGridPosition(CSSValue& value, GridPosition& position)
752 {
753     // We accept the specification's grammar:
754     // auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
755     if (is<CSSPrimitiveValue>(value)) {
756         auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
757         // We translate <ident> to <string> during parsing as it makes handling it simpler.
758         if (primitiveValue.isString()) {
759             position.setNamedGridArea(primitiveValue.getStringValue());
760             return true;
761         }
762
763         ASSERT(primitiveValue.getValueID() == CSSValueAuto);
764         return true;
765     }
766
767     auto& values = downcast<CSSValueList>(value);
768     ASSERT(values.length());
769
770     auto it = values.begin();
771     CSSPrimitiveValue* currentValue = &downcast<CSSPrimitiveValue>(it->get());
772     bool isSpanPosition = false;
773     if (currentValue->getValueID() == CSSValueSpan) {
774         isSpanPosition = true;
775         ++it;
776         currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
777     }
778
779     int gridLineNumber = 0;
780     if (currentValue && currentValue->isNumber()) {
781         gridLineNumber = currentValue->getIntValue();
782         ++it;
783         currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
784     }
785
786     String gridLineName;
787     if (currentValue && currentValue->isString()) {
788         gridLineName = currentValue->getStringValue();
789         ++it;
790     }
791
792     ASSERT(it == values.end());
793     if (isSpanPosition)
794         position.setSpanPosition(gridLineNumber ? gridLineNumber : 1, gridLineName);
795     else
796         position.setExplicitPosition(gridLineNumber, gridLineName);
797
798     return true;
799 }
800
801 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
802 {
803     for (auto& area : namedGridAreas) {
804         GridSpan areaSpan = direction == ForRows ? area.value.rows : area.value.columns;
805         {
806             auto& startVector = namedGridLines.add(area.key + "-start", Vector<unsigned>()).iterator->value;
807             startVector.append(areaSpan.resolvedInitialPosition.toInt());
808             std::sort(startVector.begin(), startVector.end());
809         }
810         {
811             auto& endVector = namedGridLines.add(area.key + "-end", Vector<unsigned>()).iterator->value;
812             endVector.append(areaSpan.resolvedFinalPosition.next().toInt());
813             std::sort(endVector.begin(), endVector.end());
814         }
815     }
816 }
817
818 inline bool StyleBuilderConverter::convertGridTrackSize(StyleResolver& styleResolver, CSSValue& value, GridTrackSize& trackSize)
819 {
820     return createGridTrackSize(value, trackSize, styleResolver);
821 }
822
823 inline bool StyleBuilderConverter::convertGridPosition(StyleResolver&, CSSValue& value, GridPosition& gridPosition)
824 {
825     return createGridPosition(value, gridPosition);
826 }
827
828 inline GridAutoFlow StyleBuilderConverter::convertGridAutoFlow(StyleResolver&, CSSValue& value)
829 {
830     auto& list = downcast<CSSValueList>(value);
831     if (!list.length())
832         return RenderStyle::initialGridAutoFlow();
833
834     CSSPrimitiveValue& first = downcast<CSSPrimitiveValue>(*list.item(0));
835     CSSPrimitiveValue* second = downcast<CSSPrimitiveValue>(list.item(1));
836
837     GridAutoFlow autoFlow = RenderStyle::initialGridAutoFlow();
838     switch (first.getValueID()) {
839     case CSSValueRow:
840         if (second && second->getValueID() == CSSValueDense)
841             autoFlow =  AutoFlowRowDense;
842         else
843             autoFlow = AutoFlowRow;
844         break;
845     case CSSValueColumn:
846         if (second && second->getValueID() == CSSValueDense)
847             autoFlow = AutoFlowColumnDense;
848         else
849             autoFlow = AutoFlowColumn;
850         break;
851     default:
852         ASSERT_NOT_REACHED();
853         break;
854     }
855
856     return autoFlow;
857 }
858 #endif // ENABLE(CSS_GRID_LAYOUT)
859
860 inline CSSToLengthConversionData StyleBuilderConverter::csstoLengthConversionDataWithTextZoomFactor(StyleResolver& styleResolver)
861 {
862     if (auto* frame = styleResolver.document().frame())
863         return styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(styleResolver.style()->effectiveZoom() * frame->textZoomFactor());
864
865     return styleResolver.state().cssToLengthConversionData();
866 }
867
868 inline bool StyleBuilderConverter::convertWordSpacing(StyleResolver& styleResolver, CSSValue& value, Length& wordSpacing)
869 {
870     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
871     if (primitiveValue.getValueID() == CSSValueNormal)
872         wordSpacing = RenderStyle::initialWordSpacing();
873     else if (primitiveValue.isLength())
874         wordSpacing = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(styleResolver));
875     else if (primitiveValue.isPercentage())
876         wordSpacing = Length(clampTo<float>(primitiveValue.getDoubleValue(), minValueForCssLength, maxValueForCssLength), Percent);
877     else if (primitiveValue.isNumber())
878         wordSpacing = Length(primitiveValue.getDoubleValue(), Fixed);
879     else
880         return false;
881
882     return true;
883 }
884
885 inline bool StyleBuilderConverter::convertPerspective(StyleResolver& styleResolver, CSSValue& value, float& perspective)
886 {
887     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
888     if (primitiveValue.getValueID() == CSSValueNone) {
889         perspective = 0;
890         return true;
891     }
892
893     if (primitiveValue.isLength())
894         perspective = primitiveValue.computeLength<float>(styleResolver.state().cssToLengthConversionData());
895     else if (primitiveValue.isNumber())
896         perspective = primitiveValue.getDoubleValue() * styleResolver.state().cssToLengthConversionData().zoom();
897     else {
898         ASSERT_NOT_REACHED();
899         return false;
900     }
901
902     return perspective >= 0;
903 }
904
905 inline bool StyleBuilderConverter::convertMarqueeIncrement(StyleResolver& styleResolver, CSSValue& value, Length& marqueeLength)
906 {
907     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
908     switch (primitiveValue.getValueID()) {
909     case CSSValueSmall:
910         marqueeLength = Length(1, Fixed); // 1px.
911         return true;
912     case CSSValueNormal:
913         marqueeLength = Length(6, Fixed); // 6px. The WinIE default.
914         return true;
915     case CSSValueLarge:
916         marqueeLength = Length(36, Fixed); // 36px.
917         return true;
918     case CSSValueInvalid:
919         marqueeLength = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
920         return !marqueeLength.isUndefined();
921     default:
922         break;
923     }
924     return false;
925 }
926
927 } // namespace WebCore
928
929 #endif // StyleBuilderConverter_h