Move more CSS properties to the new StyleBuilder
[WebKit-https.git] / Source / WebCore / css / StyleBuilderCustom.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 StyleBuilderCustom_h
28 #define StyleBuilderCustom_h
29
30 #include "BasicShapeFunctions.h"
31 #include "CSSImageGeneratorValue.h"
32 #include "CSSImageSetValue.h"
33 #include "CSSImageValue.h"
34 #include "Frame.h"
35 #include "StyleResolver.h"
36
37 namespace WebCore {
38
39 // Note that we assume the CSS parser only allows valid CSSValue types.
40 namespace StyleBuilderFunctions {
41
42 inline void applyValueWebkitMarqueeIncrement(StyleResolver& styleResolver, CSSValue& value)
43 {
44     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
45     Length marqueeLength(Undefined);
46     switch (primitiveValue.getValueID()) {
47     case CSSValueSmall:
48         marqueeLength = Length(1, Fixed); // 1px.
49         break;
50     case CSSValueNormal:
51         marqueeLength = Length(6, Fixed); // 6px. The WinIE default.
52         break;
53     case CSSValueLarge:
54         marqueeLength = Length(36, Fixed); // 36px.
55         break;
56     case CSSValueInvalid:
57         marqueeLength = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
58         break;
59     default:
60         break;
61     }
62     if (!marqueeLength.isUndefined())
63         styleResolver.style()->setMarqueeIncrement(marqueeLength);
64 }
65
66 inline void applyValueDirection(StyleResolver& styleResolver, CSSValue& value)
67 {
68     styleResolver.style()->setDirection(downcast<CSSPrimitiveValue>(value));
69
70     Element* element = styleResolver.element();
71     if (element && styleResolver.element() == element->document().documentElement())
72         element->document().setDirectionSetOnDocumentElement(true);
73 }
74
75 inline void resetEffectiveZoom(StyleResolver& styleResolver)
76 {
77     // Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect.
78     styleResolver.setEffectiveZoom(styleResolver.parentStyle() ? styleResolver.parentStyle()->effectiveZoom() : RenderStyle::initialZoom());
79 }
80
81 inline void applyInitialZoom(StyleResolver& styleResolver)
82 {
83     resetEffectiveZoom(styleResolver);
84     styleResolver.setZoom(RenderStyle::initialZoom());
85 }
86
87 inline void applyInheritZoom(StyleResolver& styleResolver)
88 {
89     resetEffectiveZoom(styleResolver);
90     styleResolver.setZoom(styleResolver.parentStyle()->zoom());
91 }
92
93 inline void applyValueZoom(StyleResolver& styleResolver, CSSValue& value)
94 {
95     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
96
97     if (primitiveValue.getValueID() == CSSValueNormal) {
98         resetEffectiveZoom(styleResolver);
99         styleResolver.setZoom(RenderStyle::initialZoom());
100     } else if (primitiveValue.getValueID() == CSSValueReset) {
101         styleResolver.setEffectiveZoom(RenderStyle::initialZoom());
102         styleResolver.setZoom(RenderStyle::initialZoom());
103     } else if (primitiveValue.getValueID() == CSSValueDocument) {
104         float docZoom = styleResolver.rootElementStyle() ? styleResolver.rootElementStyle()->zoom() : RenderStyle::initialZoom();
105         styleResolver.setEffectiveZoom(docZoom);
106         styleResolver.setZoom(docZoom);
107     } else if (primitiveValue.isPercentage()) {
108         resetEffectiveZoom(styleResolver);
109         if (float percent = primitiveValue.getFloatValue())
110             styleResolver.setZoom(percent / 100.0f);
111     } else if (primitiveValue.isNumber()) {
112         resetEffectiveZoom(styleResolver);
113         if (float number = primitiveValue.getFloatValue())
114             styleResolver.setZoom(number);
115     }
116 }
117
118 #if ENABLE(CSS_SHAPES)
119 inline void applyValueWebkitShapeOutside(StyleResolver& styleResolver, CSSValue& value)
120 {
121     if (is<CSSPrimitiveValue>(value)) {
122         // FIXME: Shouldn't this be CSSValueNone?
123         // http://www.w3.org/TR/css-shapes/#shape-outside-property
124         if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueAuto)
125             styleResolver.style()->setShapeOutside(nullptr);
126     } if (is<CSSImageValue>(value) || is<CSSImageGeneratorValue>(value) || is<CSSImageSetValue>(value)) {
127         RefPtr<ShapeValue> shape = ShapeValue::createImageValue(styleResolver.styleImage(CSSPropertyWebkitShapeOutside, value));
128         styleResolver.style()->setShapeOutside(shape.release());
129     } else if (is<CSSValueList>(value)) {
130         RefPtr<BasicShape> shape;
131         CSSBoxType referenceBox = BoxMissing;
132         for (auto& currentValue : downcast<CSSValueList>(value)) {
133             CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
134             if (primitiveValue.isShape())
135                 shape = basicShapeForValue(styleResolver.state().cssToLengthConversionData(), primitiveValue.getShapeValue());
136             else if (primitiveValue.getValueID() == CSSValueContentBox
137                 || primitiveValue.getValueID() == CSSValueBorderBox
138                 || primitiveValue.getValueID() == CSSValuePaddingBox
139                 || primitiveValue.getValueID() == CSSValueMarginBox)
140                 referenceBox = CSSBoxType(primitiveValue);
141             else
142                 return;
143         }
144
145         if (shape)
146             styleResolver.style()->setShapeOutside(ShapeValue::createShapeValue(shape.release(), referenceBox));
147         else if (referenceBox != BoxMissing)
148             styleResolver.style()->setShapeOutside(ShapeValue::createBoxShapeValue(referenceBox));
149     }
150 }
151 #endif // ENABLE(CSS_SHAPES)
152
153 inline Length mmLength(double mm)
154 {
155     Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM));
156     return value.get().computeLength<Length>(CSSToLengthConversionData());
157 }
158 inline Length inchLength(double inch)
159 {
160     Ref<CSSPrimitiveValue> value(CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN));
161     return value.get().computeLength<Length>(CSSToLengthConversionData());
162 }
163 static bool getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height)
164 {
165     static NeverDestroyed<Length> a5Width(mmLength(148));
166     static NeverDestroyed<Length> a5Height(mmLength(210));
167     static NeverDestroyed<Length> a4Width(mmLength(210));
168     static NeverDestroyed<Length> a4Height(mmLength(297));
169     static NeverDestroyed<Length> a3Width(mmLength(297));
170     static NeverDestroyed<Length> a3Height(mmLength(420));
171     static NeverDestroyed<Length> b5Width(mmLength(176));
172     static NeverDestroyed<Length> b5Height(mmLength(250));
173     static NeverDestroyed<Length> b4Width(mmLength(250));
174     static NeverDestroyed<Length> b4Height(mmLength(353));
175     static NeverDestroyed<Length> letterWidth(inchLength(8.5));
176     static NeverDestroyed<Length> letterHeight(inchLength(11));
177     static NeverDestroyed<Length> legalWidth(inchLength(8.5));
178     static NeverDestroyed<Length> legalHeight(inchLength(14));
179     static NeverDestroyed<Length> ledgerWidth(inchLength(11));
180     static NeverDestroyed<Length> ledgerHeight(inchLength(17));
181
182     if (!pageSizeName)
183         return false;
184
185     switch (pageSizeName->getValueID()) {
186     case CSSValueA5:
187         width = a5Width;
188         height = a5Height;
189         break;
190     case CSSValueA4:
191         width = a4Width;
192         height = a4Height;
193         break;
194     case CSSValueA3:
195         width = a3Width;
196         height = a3Height;
197         break;
198     case CSSValueB5:
199         width = b5Width;
200         height = b5Height;
201         break;
202     case CSSValueB4:
203         width = b4Width;
204         height = b4Height;
205         break;
206     case CSSValueLetter:
207         width = letterWidth;
208         height = letterHeight;
209         break;
210     case CSSValueLegal:
211         width = legalWidth;
212         height = legalHeight;
213         break;
214     case CSSValueLedger:
215         width = ledgerWidth;
216         height = ledgerHeight;
217         break;
218     default:
219         return false;
220     }
221
222     if (pageOrientation) {
223         switch (pageOrientation->getValueID()) {
224         case CSSValueLandscape:
225             std::swap(width, height);
226             break;
227         case CSSValuePortrait:
228             // Nothing to do.
229             break;
230         default:
231             return false;
232         }
233     }
234     return true;
235 }
236
237 inline void applyValueVerticalAlign(StyleResolver& styleResolver, CSSValue& value)
238 {
239     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
240     if (primitiveValue.getValueID())
241         styleResolver.style()->setVerticalAlign(primitiveValue);
242     else
243         styleResolver.style()->setVerticalAlignLength(primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData()));
244 }
245
246 #if ENABLE(CSS_IMAGE_RESOLUTION)
247 inline void applyInheritImageResolution(StyleResolver& styleResolver)
248 {
249     styleResolver.style()->setImageResolutionSource(styleResolver.parentStyle()->imageResolutionSource());
250     styleResolver.style()->setImageResolutionSnap(styleResolver.parentStyle()->imageResolutionSnap());
251     styleResolver.style()->setImageResolution(styleResolver.parentStyle()->imageResolution());
252 }
253
254 inline void applyInitialImageResolution(StyleResolver& styleResolver)
255 {
256     styleResolver.style()->setImageResolutionSource(RenderStyle::initialImageResolutionSource());
257     styleResolver.style()->setImageResolutionSnap(RenderStyle::initialImageResolutionSnap());
258     styleResolver.style()->setImageResolution(RenderStyle::initialImageResolution());
259 }
260
261 inline void applyValueImageResolution(StyleResolver& styleResolver, CSSValue& value)
262 {
263     ImageResolutionSource source = RenderStyle::initialImageResolutionSource();
264     ImageResolutionSnap snap = RenderStyle::initialImageResolutionSnap();
265     double resolution = RenderStyle::initialImageResolution();
266     for (auto& item : downcast<CSSValueList>(value)) {
267         CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
268         if (primitiveValue.getValueID() == CSSValueFromImage)
269             source = ImageResolutionFromImage;
270         else if (primitiveValue.getValueID() == CSSValueSnap)
271             snap = ImageResolutionSnapPixels;
272         else
273             resolution = primitiveValue.getDoubleValue(CSSPrimitiveValue::CSS_DPPX);
274     }
275     styleResolver.style()->setImageResolutionSource(source);
276     styleResolver.style()->setImageResolutionSnap(snap);
277     styleResolver.style()->setImageResolution(resolution);
278 }
279 #endif // ENABLE(CSS_IMAGE_RESOLUTION)
280
281 inline void applyInheritSize(StyleResolver&) { }
282 inline void applyInitialSize(StyleResolver&) { }
283 inline void applyValueSize(StyleResolver& styleResolver, CSSValue& value)
284 {
285     styleResolver.style()->resetPageSizeType();
286     Length width;
287     Length height;
288     PageSizeType pageSizeType = PAGE_SIZE_AUTO;
289     if (!is<CSSValueList>(value))
290         return;
291
292     auto& valueList = downcast<CSSValueList>(value);
293     switch (valueList.length()) {
294     case 2: {
295         CSSValue* firstValue = valueList.itemWithoutBoundsCheck(0);
296         CSSValue* secondValue = valueList.itemWithoutBoundsCheck(1);
297         // <length>{2} | <page-size> <orientation>
298         if (!is<CSSPrimitiveValue>(*firstValue) || !is<CSSPrimitiveValue>(*secondValue))
299             return;
300         auto& firstPrimitiveValue = downcast<CSSPrimitiveValue>(*firstValue);
301         auto& secondPrimitiveValue = downcast<CSSPrimitiveValue>(*secondValue);
302         if (firstPrimitiveValue.isLength()) {
303             // <length>{2}
304             if (!secondPrimitiveValue.isLength())
305                 return;
306             CSSToLengthConversionData conversionData = styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f);
307             width = firstPrimitiveValue.computeLength<Length>(conversionData);
308             height = secondPrimitiveValue.computeLength<Length>(conversionData);
309         } else {
310             // <page-size> <orientation>
311             // The value order is guaranteed. See CSSParser::parseSizeParameter.
312             if (!getPageSizeFromName(&firstPrimitiveValue, &secondPrimitiveValue, width, height))
313                 return;
314         }
315         pageSizeType = PAGE_SIZE_RESOLVED;
316         break;
317     }
318     case 1: {
319         CSSValue* value = valueList.itemWithoutBoundsCheck(0);
320         // <length> | auto | <page-size> | [ portrait | landscape]
321         if (!is<CSSPrimitiveValue>(*value))
322             return;
323         auto& primitiveValue = downcast<CSSPrimitiveValue>(*value);
324         if (primitiveValue.isLength()) {
325             // <length>
326             pageSizeType = PAGE_SIZE_RESOLVED;
327             width = height = primitiveValue.computeLength<Length>(styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
328         } else {
329             switch (primitiveValue.getValueID()) {
330             case 0:
331                 return;
332             case CSSValueAuto:
333                 pageSizeType = PAGE_SIZE_AUTO;
334                 break;
335             case CSSValuePortrait:
336                 pageSizeType = PAGE_SIZE_AUTO_PORTRAIT;
337                 break;
338             case CSSValueLandscape:
339                 pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE;
340                 break;
341             default:
342                 // <page-size>
343                 pageSizeType = PAGE_SIZE_RESOLVED;
344                 if (!getPageSizeFromName(&primitiveValue, nullptr, width, height))
345                     return;
346             }
347         }
348         break;
349     }
350     default:
351         return;
352     }
353     styleResolver.style()->setPageSizeType(pageSizeType);
354     styleResolver.style()->setPageSize(LengthSize(width, height));
355 }
356
357 inline void applyInheritTextIndent(StyleResolver& styleResolver)
358 {
359     styleResolver.style()->setTextIndent(styleResolver.parentStyle()->textIndent());
360 #if ENABLE(CSS3_TEXT)
361     styleResolver.style()->setTextIndentLine(styleResolver.parentStyle()->textIndentLine());
362     styleResolver.style()->setTextIndentType(styleResolver.parentStyle()->textIndentType());
363 #endif
364 }
365
366 inline void applyInitialTextIndent(StyleResolver& styleResolver)
367 {
368     styleResolver.style()->setTextIndent(RenderStyle::initialTextIndent());
369 #if ENABLE(CSS3_TEXT)
370     styleResolver.style()->setTextIndentLine(RenderStyle::initialTextIndentLine());
371     styleResolver.style()->setTextIndentType(RenderStyle::initialTextIndentType());
372 #endif
373 }
374
375 inline void applyValueTextIndent(StyleResolver& styleResolver, CSSValue& value)
376 {
377     Length lengthOrPercentageValue;
378 #if ENABLE(CSS3_TEXT)
379     TextIndentLine textIndentLineValue = RenderStyle::initialTextIndentLine();
380     TextIndentType textIndentTypeValue = RenderStyle::initialTextIndentType();
381 #endif
382     for (auto& item : downcast<CSSValueList>(value)) {
383         auto& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
384         if (!primitiveValue.getValueID())
385             lengthOrPercentageValue = primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(styleResolver.state().cssToLengthConversionData());
386 #if ENABLE(CSS3_TEXT)
387         else if (primitiveValue.getValueID() == CSSValueWebkitEachLine)
388             textIndentLineValue = TextIndentEachLine;
389         else if (primitiveValue.getValueID() == CSSValueWebkitHanging)
390             textIndentTypeValue = TextIndentHanging;
391 #endif
392     }
393
394     ASSERT(!lengthOrPercentageValue.isUndefined());
395     styleResolver.style()->setTextIndent(lengthOrPercentageValue);
396 #if ENABLE(CSS3_TEXT)
397     styleResolver.style()->setTextIndentLine(textIndentLineValue);
398     styleResolver.style()->setTextIndentType(textIndentTypeValue);
399 #endif
400 }
401
402 enum BorderImageType { BorderImage, WebkitMaskBoxImage };
403 enum BorderImageModifierType { Outset, Repeat, Slice, Width };
404 template <BorderImageType type, BorderImageModifierType modifier>
405 class ApplyPropertyBorderImageModifier {
406 public:
407     static void applyInheritValue(StyleResolver& styleResolver)
408     {
409         NinePieceImage image(getValue(styleResolver.style()));
410         switch (modifier) {
411         case Outset:
412             image.copyOutsetFrom(getValue(styleResolver.parentStyle()));
413             break;
414         case Repeat:
415             image.copyRepeatFrom(getValue(styleResolver.parentStyle()));
416             break;
417         case Slice:
418             image.copyImageSlicesFrom(getValue(styleResolver.parentStyle()));
419             break;
420         case Width:
421             image.copyBorderSlicesFrom(getValue(styleResolver.parentStyle()));
422             break;
423         }
424         setValue(styleResolver.style(), image);
425     }
426
427     static void applyInitialValue(StyleResolver& styleResolver)
428     {
429         NinePieceImage image(getValue(styleResolver.style()));
430         switch (modifier) {
431         case Outset:
432             image.setOutset(LengthBox(0));
433             break;
434         case Repeat:
435             image.setHorizontalRule(StretchImageRule);
436             image.setVerticalRule(StretchImageRule);
437             break;
438         case Slice:
439             // Masks have a different initial value for slices. Preserve the value of 0 for backwards compatibility.
440             image.setImageSlices(type == BorderImage ? LengthBox(Length(100, Percent), Length(100, Percent), Length(100, Percent), Length(100, Percent)) : LengthBox());
441             image.setFill(false);
442             break;
443         case Width:
444             // Masks have a different initial value for widths. They use an 'auto' value rather than trying to fit to the border.
445             image.setBorderSlices(type == BorderImage ? LengthBox(Length(1, Relative), Length(1, Relative), Length(1, Relative), Length(1, Relative)) : LengthBox());
446             break;
447         }
448         setValue(styleResolver.style(), image);
449     }
450
451     static void applyValue(StyleResolver& styleResolver, CSSValue& value)
452     {
453         NinePieceImage image(getValue(styleResolver.style()));
454         switch (modifier) {
455         case Outset:
456             image.setOutset(styleResolver.styleMap()->mapNinePieceImageQuad(value));
457             break;
458         case Repeat:
459             styleResolver.styleMap()->mapNinePieceImageRepeat(value, image);
460             break;
461         case Slice:
462             styleResolver.styleMap()->mapNinePieceImageSlice(value, image);
463             break;
464         case Width:
465             image.setBorderSlices(styleResolver.styleMap()->mapNinePieceImageQuad(value));
466             break;
467         }
468         setValue(styleResolver.style(), image);
469     }
470
471 private:
472     static inline const NinePieceImage& getValue(RenderStyle* style)
473     {
474         return type == BorderImage ? style->borderImage() : style->maskBoxImage();
475     }
476
477     static inline void setValue(RenderStyle* style, const NinePieceImage& value)
478     {
479         return type == BorderImage ? style->setBorderImage(value) : style->setMaskBoxImage(value);
480     }
481 };
482
483 #define DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(type, modifier) \
484 inline void applyInherit##type##modifier(StyleResolver& styleResolver) \
485 { \
486     ApplyPropertyBorderImageModifier<type, modifier>::applyInheritValue(styleResolver); \
487 } \
488 inline void applyInitial##type##modifier(StyleResolver& styleResolver) \
489 { \
490     ApplyPropertyBorderImageModifier<type, modifier>::applyInitialValue(styleResolver); \
491 } \
492 inline void applyValue##type##modifier(StyleResolver& styleResolver, CSSValue& value) \
493 { \
494     ApplyPropertyBorderImageModifier<type, modifier>::applyValue(styleResolver, value); \
495 }
496
497 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Outset)
498 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Repeat)
499 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Slice)
500 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(BorderImage, Width)
501 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Outset)
502 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Repeat)
503 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Slice)
504 DEFINE_BORDER_IMAGE_MODIFIER_HANDLER(WebkitMaskBoxImage, Width)
505
506 inline CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(StyleResolver& styleResolver)
507 {
508     if (Frame* frame = styleResolver.document().frame())
509         return styleResolver.state().cssToLengthConversionData().copyWithAdjustedZoom(styleResolver.style()->effectiveZoom() * frame->textZoomFactor());
510
511     return styleResolver.state().cssToLengthConversionData();
512 }
513
514 inline bool convertLineHeight(StyleResolver& styleResolver, const CSSValue& value, Length& length, float multiplier = 1.f)
515 {
516     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
517     if (primitiveValue.getValueID() == CSSValueNormal) {
518         length = RenderStyle::initialLineHeight();
519         return true;
520     }
521     if (primitiveValue.isLength()) {
522         length = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(styleResolver));
523         return true;
524     }
525     if (primitiveValue.isPercentage()) {
526         // FIXME: percentage should not be restricted to an integer here.
527         length = Length((styleResolver.style()->computedFontSize() * primitiveValue.getIntValue()) * multiplier / 100, Fixed);
528         return true;
529     }
530     if (primitiveValue.isNumber()) {
531         // FIXME: number and percentage values should produce the same type of Length (ie. Fixed or Percent).
532         length = Length(primitiveValue.getDoubleValue() * multiplier * 100.0, Percent);
533         return true;
534     }
535     return false;
536 }
537
538 inline void applyValueWordSpacing(StyleResolver& styleResolver, CSSValue& value)
539 {
540     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
541
542     Length wordSpacing;
543     if (primitiveValue.getValueID() == CSSValueNormal)
544         wordSpacing = RenderStyle::initialWordSpacing();
545     else if (primitiveValue.isLength())
546         wordSpacing = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(styleResolver));
547     else if (primitiveValue.isPercentage())
548         wordSpacing = Length(clampTo<float>(primitiveValue.getDoubleValue(), minValueForCssLength, maxValueForCssLength), Percent);
549     else if (primitiveValue.isNumber())
550         wordSpacing = Length(primitiveValue.getDoubleValue(), Fixed);
551     else
552         return;
553     styleResolver.style()->setWordSpacing(wordSpacing);
554 }
555
556 #if ENABLE(IOS_TEXT_AUTOSIZING)
557
558 inline void applyInheritLineHeight(StyleResolver& styleResolver)
559 {
560     styleResolver.style()->setLineHeight(styleResolver.parentStyle()->lineHeight());
561     styleResolver.style()->setSpecifiedLineHeight(styleResolver.parentStyle()->specifiedLineHeight());
562 }
563
564 inline void applyInitialLineHeight(StyleResolver& styleResolver)
565 {
566     styleResolver.style()->setLineHeight(RenderStyle::initialLineHeight());
567     styleResolver.style()->setSpecifiedLineHeight(RenderStyle::initialSpecifiedLineHeight());
568 }
569
570 inline void applyValueLineHeight(StyleResolver& styleResolver, CSSValue& value)
571 {
572     Length lineHeight;
573     if (!convertLineHeight(styleResolver, value, lineHeight, styleResolver.style()->textSizeAdjust().multiplier()))
574         return;
575
576     styleResolver.style()->setLineHeight(lineHeight);
577     styleResolver.style()->setSpecifiedLineHeight(lineHeight);
578 }
579
580 #else
581
582 inline void applyValueLineHeight(StyleResolver& styleResolver, CSSValue& value)
583 {
584     Length lineHeight;
585     if (!convertLineHeight(styleResolver, value, lineHeight))
586         return;
587
588     styleResolver.style()->setLineHeight(lineHeight);
589 }
590
591 #endif
592
593 } // namespace StyleBuilderFunctions
594
595 } // namespace WebCore
596
597 #endif // StyleBuilderCustom_h