Modernize RenderStyleConstants.h - Part 2
[WebKit-https.git] / Source / WebCore / css / CSSToStyleMap.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "CSSToStyleMap.h"
30
31 #include "Animation.h"
32 #include "CSSAnimationTriggerScrollValue.h"
33 #include "CSSBorderImageSliceValue.h"
34 #include "CSSImageGeneratorValue.h"
35 #include "CSSImageSetValue.h"
36 #include "CSSImageValue.h"
37 #include "CSSPrimitiveValue.h"
38 #include "CSSPrimitiveValueMappings.h"
39 #include "CSSTimingFunctionValue.h"
40 #include "CSSValueKeywords.h"
41 #include "FillLayer.h"
42 #include "Pair.h"
43 #include "Rect.h"
44 #include "StyleBuilderConverter.h"
45 #include "StyleResolver.h"
46
47 namespace WebCore {
48
49 CSSToStyleMap::CSSToStyleMap(StyleResolver* resolver)
50     : m_resolver(resolver)
51 {
52 }
53
54 RenderStyle* CSSToStyleMap::style() const
55 {
56     return m_resolver->style();
57 }
58
59 const RenderStyle* CSSToStyleMap::rootElementStyle() const
60 {
61     return m_resolver->rootElementStyle();
62 }
63
64 bool CSSToStyleMap::useSVGZoomRules() const
65 {
66     return m_resolver->useSVGZoomRules();
67 }
68
69 RefPtr<StyleImage> CSSToStyleMap::styleImage(CSSValue& value)
70 {
71     return m_resolver->styleImage(value);
72 }
73
74 void CSSToStyleMap::mapFillAttachment(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
75 {
76     if (value.treatAsInitialValue(propertyID)) {
77         layer.setAttachment(FillLayer::initialFillAttachment(layer.type()));
78         return;
79     }
80
81     if (!is<CSSPrimitiveValue>(value))
82         return;
83
84     switch (downcast<CSSPrimitiveValue>(value).valueID()) {
85     case CSSValueFixed:
86         layer.setAttachment(FillAttachment::FixedBackground);
87         break;
88     case CSSValueScroll:
89         layer.setAttachment(FillAttachment::ScrollBackground);
90         break;
91     case CSSValueLocal:
92         layer.setAttachment(FillAttachment::LocalBackground);
93         break;
94     default:
95         return;
96     }
97 }
98
99 void CSSToStyleMap::mapFillClip(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
100 {
101     if (value.treatAsInitialValue(propertyID)) {
102         layer.setClip(FillLayer::initialFillClip(layer.type()));
103         return;
104     }
105
106     if (!is<CSSPrimitiveValue>(value))
107         return;
108
109     layer.setClip(downcast<CSSPrimitiveValue>(value));
110 }
111
112 void CSSToStyleMap::mapFillComposite(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
113 {
114     if (value.treatAsInitialValue(propertyID)) {
115         layer.setComposite(FillLayer::initialFillComposite(layer.type()));
116         return;
117     }
118
119     if (!is<CSSPrimitiveValue>(value))
120         return;
121
122     layer.setComposite(downcast<CSSPrimitiveValue>(value));
123 }
124
125 void CSSToStyleMap::mapFillBlendMode(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
126 {
127     if (value.treatAsInitialValue(propertyID)) {
128         layer.setBlendMode(FillLayer::initialFillBlendMode(layer.type()));
129         return;
130     }
131
132     if (!is<CSSPrimitiveValue>(value))
133         return;
134
135     layer.setBlendMode(downcast<CSSPrimitiveValue>(value));
136 }
137
138 void CSSToStyleMap::mapFillOrigin(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
139 {
140     if (value.treatAsInitialValue(propertyID)) {
141         layer.setOrigin(FillLayer::initialFillOrigin(layer.type()));
142         return;
143     }
144
145     if (!is<CSSPrimitiveValue>(value))
146         return;
147
148     layer.setOrigin(downcast<CSSPrimitiveValue>(value));
149 }
150
151 void CSSToStyleMap::mapFillImage(CSSPropertyID propertyID, FillLayer& layer, CSSValue& value)
152 {
153     if (value.treatAsInitialValue(propertyID)) {
154         layer.setImage(FillLayer::initialFillImage(layer.type()));
155         return;
156     }
157
158     layer.setImage(styleImage(value));
159 }
160
161 void CSSToStyleMap::mapFillRepeatX(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
162 {
163     if (value.treatAsInitialValue(propertyID)) {
164         layer.setRepeatX(FillLayer::initialFillRepeatX(layer.type()));
165         return;
166     }
167
168     if (!is<CSSPrimitiveValue>(value))
169         return;
170
171     layer.setRepeatX(downcast<CSSPrimitiveValue>(value));
172 }
173
174 void CSSToStyleMap::mapFillRepeatY(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
175 {
176     if (value.treatAsInitialValue(propertyID)) {
177         layer.setRepeatY(FillLayer::initialFillRepeatY(layer.type()));
178         return;
179     }
180
181     if (!is<CSSPrimitiveValue>(value))
182         return;
183
184     layer.setRepeatY(downcast<CSSPrimitiveValue>(value));
185 }
186
187 static inline bool convertToLengthSize(const CSSPrimitiveValue& primitiveValue, CSSToLengthConversionData conversionData, LengthSize& size)
188 {
189     if (auto* pair = primitiveValue.pairValue()) {
190         size.width = pair->first()->convertToLength<AnyConversion>(conversionData);
191         size.height = pair->second()->convertToLength<AnyConversion>(conversionData);
192     } else
193         size.width = primitiveValue.convertToLength<AnyConversion>(conversionData);
194     return !size.width.isUndefined() && !size.height.isUndefined();
195 }
196
197 void CSSToStyleMap::mapFillSize(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
198 {
199     if (value.treatAsInitialValue(propertyID)) {
200         layer.setSize(FillLayer::initialFillSize(layer.type()));
201         return;
202     }
203
204     if (!is<CSSPrimitiveValue>(value))
205         return;
206
207     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
208     FillSize fillSize;
209     switch (primitiveValue.valueID()) {
210     case CSSValueContain:
211         fillSize.type = FillSizeType::Contain;
212         break;
213     case CSSValueCover:
214         fillSize.type = FillSizeType::Cover;
215         break;
216     default:
217         ASSERT(fillSize.type == FillSizeType::Size);
218         if (!convertToLengthSize(primitiveValue, m_resolver->state().cssToLengthConversionData(), fillSize.size))
219             return;
220         break;
221     }
222     layer.setSize(fillSize);
223 }
224
225 void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
226 {
227     if (value.treatAsInitialValue(propertyID)) {
228         layer.setXPosition(FillLayer::initialFillXPosition(layer.type()));
229         return;
230     }
231
232     if (!is<CSSPrimitiveValue>(value))
233         return;
234
235     auto* primitiveValue = &downcast<CSSPrimitiveValue>(value);
236     Pair* pair = primitiveValue->pairValue();
237     Length length;
238     if (pair) {
239         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionX || propertyID == CSSPropertyWebkitMaskPositionX);
240         length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second());
241     } else
242         length = StyleBuilderConverter::convertPositionComponentX(*m_resolver, value);
243
244     layer.setXPosition(length);
245     if (pair)
246         layer.setBackgroundXOrigin(*pair->first());
247 }
248
249 void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
250 {
251     if (value.treatAsInitialValue(propertyID)) {
252         layer.setYPosition(FillLayer::initialFillYPosition(layer.type()));
253         return;
254     }
255
256     if (!is<CSSPrimitiveValue>(value))
257         return;
258
259     auto* primitiveValue = &downcast<CSSPrimitiveValue>(value);
260     Pair* pair = primitiveValue->pairValue();
261     Length length;
262     if (pair) {
263         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionY || propertyID == CSSPropertyWebkitMaskPositionY);
264         length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second());
265     } else
266         length = StyleBuilderConverter::convertPositionComponentY(*m_resolver, value);
267     
268     layer.setYPosition(length);
269     if (pair)
270         layer.setBackgroundYOrigin(*pair->first());
271 }
272
273 void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
274 {
275     MaskSourceType type = FillLayer::initialFillMaskSourceType(layer.type());
276     if (value.treatAsInitialValue(propertyID)) {
277         layer.setMaskSourceType(type);
278         return;
279     }
280
281     if (!is<CSSPrimitiveValue>(value))
282         return;
283
284     switch (downcast<CSSPrimitiveValue>(value).valueID()) {
285     case CSSValueAlpha:
286         type = MaskSourceType::Alpha;
287         break;
288     case CSSValueLuminance:
289         type = MaskSourceType::Luminance;
290         break;
291     case CSSValueAuto:
292         break;
293     default:
294         ASSERT_NOT_REACHED();
295     }
296
297     layer.setMaskSourceType(type);
298 }
299
300 void CSSToStyleMap::mapAnimationDelay(Animation& animation, const CSSValue& value)
301 {
302     if (value.treatAsInitialValue(CSSPropertyAnimationDelay)) {
303         animation.setDelay(Animation::initialDelay());
304         return;
305     }
306
307     if (!is<CSSPrimitiveValue>(value))
308         return;
309
310     animation.setDelay(downcast<CSSPrimitiveValue>(value).computeTime<double, CSSPrimitiveValue::Seconds>());
311 }
312
313 void CSSToStyleMap::mapAnimationDirection(Animation& layer, const CSSValue& value)
314 {
315     if (value.treatAsInitialValue(CSSPropertyAnimationDirection)) {
316         layer.setDirection(Animation::initialDirection());
317         return;
318     }
319
320     if (!is<CSSPrimitiveValue>(value))
321         return;
322
323     switch (downcast<CSSPrimitiveValue>(value).valueID()) {
324     case CSSValueNormal:
325         layer.setDirection(Animation::AnimationDirectionNormal);
326         break;
327     case CSSValueAlternate:
328         layer.setDirection(Animation::AnimationDirectionAlternate);
329         break;
330     case CSSValueReverse:
331         layer.setDirection(Animation::AnimationDirectionReverse);
332         break;
333     case CSSValueAlternateReverse:
334         layer.setDirection(Animation::AnimationDirectionAlternateReverse);
335         break;
336     default:
337         break;
338     }
339 }
340
341 void CSSToStyleMap::mapAnimationDuration(Animation& animation, const CSSValue& value)
342 {
343     if (value.treatAsInitialValue(CSSPropertyAnimationDuration)) {
344         animation.setDuration(Animation::initialDuration());
345         return;
346     }
347
348     if (!is<CSSPrimitiveValue>(value))
349         return;
350
351     animation.setDuration(downcast<CSSPrimitiveValue>(value).computeTime<double, CSSPrimitiveValue::Seconds>());
352 }
353
354 void CSSToStyleMap::mapAnimationFillMode(Animation& layer, const CSSValue& value)
355 {
356     if (value.treatAsInitialValue(CSSPropertyAnimationFillMode)) {
357         layer.setFillMode(Animation::initialFillMode());
358         return;
359     }
360
361     if (!is<CSSPrimitiveValue>(value))
362         return;
363
364     switch (downcast<CSSPrimitiveValue>(value).valueID()) {
365     case CSSValueNone:
366         layer.setFillMode(AnimationFillMode::None);
367         break;
368     case CSSValueForwards:
369         layer.setFillMode(AnimationFillMode::Forwards);
370         break;
371     case CSSValueBackwards:
372         layer.setFillMode(AnimationFillMode::Backwards);
373         break;
374     case CSSValueBoth:
375         layer.setFillMode(AnimationFillMode::Both);
376         break;
377     default:
378         break;
379     }
380 }
381
382 void CSSToStyleMap::mapAnimationIterationCount(Animation& animation, const CSSValue& value)
383 {
384     if (value.treatAsInitialValue(CSSPropertyAnimationIterationCount)) {
385         animation.setIterationCount(Animation::initialIterationCount());
386         return;
387     }
388
389     if (!is<CSSPrimitiveValue>(value))
390         return;
391
392     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
393     if (primitiveValue.valueID() == CSSValueInfinite)
394         animation.setIterationCount(Animation::IterationCountInfinite);
395     else
396         animation.setIterationCount(primitiveValue.floatValue());
397 }
398
399 void CSSToStyleMap::mapAnimationName(Animation& layer, const CSSValue& value)
400 {
401     if (value.treatAsInitialValue(CSSPropertyAnimationName)) {
402         layer.setName(Animation::initialName());
403         return;
404     }
405
406     if (!is<CSSPrimitiveValue>(value))
407         return;
408
409     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
410     if (primitiveValue.valueID() == CSSValueNone)
411         layer.setIsNoneAnimation(true);
412     else
413         layer.setName(primitiveValue.stringValue(), m_resolver->state().styleScopeOrdinal());
414 }
415
416 void CSSToStyleMap::mapAnimationPlayState(Animation& layer, const CSSValue& value)
417 {
418     if (value.treatAsInitialValue(CSSPropertyAnimationPlayState)) {
419         layer.setPlayState(Animation::initialPlayState());
420         return;
421     }
422
423     if (!is<CSSPrimitiveValue>(value))
424         return;
425
426     AnimationPlayState playState = (downcast<CSSPrimitiveValue>(value).valueID() == CSSValuePaused) ? AnimationPlayState::Paused : AnimationPlayState::Playing;
427     layer.setPlayState(playState);
428 }
429
430 void CSSToStyleMap::mapAnimationProperty(Animation& animation, const CSSValue& value)
431 {
432     if (value.treatAsInitialValue(CSSPropertyAnimation)) {
433         animation.setAnimationMode(Animation::AnimateAll);
434         animation.setProperty(CSSPropertyInvalid);
435         return;
436     }
437
438     if (!is<CSSPrimitiveValue>(value))
439         return;
440
441     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
442     if (primitiveValue.valueID() == CSSValueAll) {
443         animation.setAnimationMode(Animation::AnimateAll);
444         animation.setProperty(CSSPropertyInvalid);
445         return;
446     }
447     if (primitiveValue.valueID() == CSSValueNone) {
448         animation.setAnimationMode(Animation::AnimateNone);
449         animation.setProperty(CSSPropertyInvalid);
450         return;
451     }
452     if (primitiveValue.propertyID() == CSSPropertyInvalid) {
453         animation.setAnimationMode(Animation::AnimateUnknownProperty);
454         animation.setProperty(CSSPropertyInvalid);
455         animation.setUnknownProperty(primitiveValue.stringValue());
456         return;
457     }
458     animation.setAnimationMode(Animation::AnimateSingleProperty);
459     animation.setProperty(primitiveValue.propertyID());
460 }
461
462 void CSSToStyleMap::mapAnimationTimingFunction(Animation& animation, const CSSValue& value)
463 {
464     if (value.treatAsInitialValue(CSSPropertyAnimationTimingFunction)) {
465         animation.setTimingFunction(Animation::initialTimingFunction());
466         return;
467     }
468
469     if (is<CSSPrimitiveValue>(value)) {
470         switch (downcast<CSSPrimitiveValue>(value).valueID()) {
471         case CSSValueLinear:
472             animation.setTimingFunction(LinearTimingFunction::create());
473             break;
474         case CSSValueEase:
475             animation.setTimingFunction(CubicBezierTimingFunction::create());
476             break;
477         case CSSValueEaseIn:
478             animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseIn));
479             break;
480         case CSSValueEaseOut:
481             animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseOut));
482             break;
483         case CSSValueEaseInOut:
484             animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseInOut));
485             break;
486         case CSSValueStepStart:
487             animation.setTimingFunction(StepsTimingFunction::create(1, true));
488             break;
489         case CSSValueStepEnd:
490             animation.setTimingFunction(StepsTimingFunction::create(1, false));
491             break;
492         default:
493             break;
494         }
495         return;
496     }
497
498     if (is<CSSCubicBezierTimingFunctionValue>(value)) {
499         auto& cubicTimingFunction = downcast<CSSCubicBezierTimingFunctionValue>(value);
500         animation.setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction.x1(), cubicTimingFunction.y1(), cubicTimingFunction.x2(), cubicTimingFunction.y2()));
501     } else if (is<CSSStepsTimingFunctionValue>(value)) {
502         auto& stepsTimingFunction = downcast<CSSStepsTimingFunctionValue>(value);
503         animation.setTimingFunction(StepsTimingFunction::create(stepsTimingFunction.numberOfSteps(), stepsTimingFunction.stepAtStart()));
504     } else if (is<CSSFramesTimingFunctionValue>(value)) {
505         auto& framesTimingFunction = downcast<CSSFramesTimingFunctionValue>(value);
506         animation.setTimingFunction(FramesTimingFunction::create(framesTimingFunction.numberOfFrames()));
507     } else if (is<CSSSpringTimingFunctionValue>(value)) {
508         auto& springTimingFunction = downcast<CSSSpringTimingFunctionValue>(value);
509         animation.setTimingFunction(SpringTimingFunction::create(springTimingFunction.mass(), springTimingFunction.stiffness(), springTimingFunction.damping(), springTimingFunction.initialVelocity()));
510     }
511 }
512
513 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
514 void CSSToStyleMap::mapAnimationTrigger(Animation& animation, const CSSValue& value)
515 {
516     if (value.treatAsInitialValue(CSSPropertyWebkitAnimationTrigger)) {
517         animation.setTrigger(Animation::initialTrigger());
518         return;
519     }
520
521     if (value.isPrimitiveValue()) {
522         auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
523         if (primitiveValue.valueID() == CSSValueAuto)
524             animation.setTrigger(AutoAnimationTrigger::create());
525         return;
526     }
527
528     if (value.isAnimationTriggerScrollValue()) {
529         auto& scrollTrigger = downcast<CSSAnimationTriggerScrollValue>(value);
530
531         const CSSPrimitiveValue& startValue = downcast<CSSPrimitiveValue>(scrollTrigger.startValue());
532         Length startLength = startValue.computeLength<Length>(m_resolver->state().cssToLengthConversionData());
533
534         Length endLength;
535         if (scrollTrigger.hasEndValue()) {
536             const CSSPrimitiveValue* endValue = downcast<CSSPrimitiveValue>(scrollTrigger.endValue());
537             endLength = endValue->computeLength<Length>(m_resolver->state().cssToLengthConversionData());
538         }
539
540         animation.setTrigger(ScrollAnimationTrigger::create(startLength, endLength));
541     }
542 }
543 #endif
544
545 void CSSToStyleMap::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image)
546 {
547     // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
548     if (!is<CSSValueList>(value))
549         return;
550
551     // Retrieve the border image value.
552     CSSValueList& borderImage = downcast<CSSValueList>(*value);
553
554     for (auto& current : borderImage) {
555         if (is<CSSImageValue>(current) || is<CSSImageGeneratorValue>(current) || is<CSSImageSetValue>(current))
556             image.setImage(styleImage(current.get()));
557         else if (is<CSSBorderImageSliceValue>(current))
558             mapNinePieceImageSlice(current, image);
559         else if (is<CSSValueList>(current)) {
560             CSSValueList& slashList = downcast<CSSValueList>(current.get());
561             // Map in the image slices.
562             if (is<CSSBorderImageSliceValue>(slashList.item(0)))
563                 mapNinePieceImageSlice(*slashList.item(0), image);
564
565             // Map in the border slices.
566             if (slashList.item(1))
567                 image.setBorderSlices(mapNinePieceImageQuad(*slashList.item(1)));
568
569             // Map in the outset.
570             if (slashList.item(2))
571                 image.setOutset(mapNinePieceImageQuad(*slashList.item(2)));
572         } else if (is<CSSPrimitiveValue>(current)) {
573             // Set the appropriate rules for stretch/round/repeat of the slices.
574             mapNinePieceImageRepeat(current, image);
575         }
576     }
577
578     if (property == CSSPropertyWebkitBorderImage) {
579         // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
580         // also set the border widths. We don't need to worry about percentages, since we don't even support
581         // those on real borders yet.
582         if (image.borderSlices().top().isFixed())
583             style()->setBorderTopWidth(image.borderSlices().top().value());
584         if (image.borderSlices().right().isFixed())
585             style()->setBorderRightWidth(image.borderSlices().right().value());
586         if (image.borderSlices().bottom().isFixed())
587             style()->setBorderBottomWidth(image.borderSlices().bottom().value());
588         if (image.borderSlices().left().isFixed())
589             style()->setBorderLeftWidth(image.borderSlices().left().value());
590     }
591 }
592
593 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue& value, NinePieceImage& image)
594 {
595     if (!is<CSSBorderImageSliceValue>(value))
596         return;
597
598     // Retrieve the border image value.
599     auto& borderImageSlice = downcast<CSSBorderImageSliceValue>(value);
600
601     // Set up a length box to represent our image slices.
602     LengthBox box;
603     Quad* slices = borderImageSlice.slices();
604     if (slices->top()->isPercentage())
605         box.top() = Length(slices->top()->doubleValue(), Percent);
606     else
607         box.top() = Length(slices->top()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
608     if (slices->bottom()->isPercentage())
609         box.bottom() = Length(slices->bottom()->doubleValue(), Percent);
610     else
611         box.bottom() = Length((int)slices->bottom()->floatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
612     if (slices->left()->isPercentage())
613         box.left() = Length(slices->left()->doubleValue(), Percent);
614     else
615         box.left() = Length(slices->left()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
616     if (slices->right()->isPercentage())
617         box.right() = Length(slices->right()->doubleValue(), Percent);
618     else
619         box.right() = Length(slices->right()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
620     image.setImageSlices(box);
621
622     // Set our fill mode.
623     image.setFill(borderImageSlice.m_fill);
624 }
625
626 LengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue& value)
627 {
628     if (!is<CSSPrimitiveValue>(value))
629         return LengthBox();
630
631     // Get our zoom value.
632     CSSToLengthConversionData conversionData = useSVGZoomRules() ? m_resolver->state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f) : m_resolver->state().cssToLengthConversionData();
633
634     // Retrieve the primitive value.
635     auto& borderWidths = downcast<CSSPrimitiveValue>(value);
636
637     // Set up a length box to represent our image slices.
638     LengthBox box; // Defaults to 'auto' so we don't have to handle that explicitly below.
639     Quad* slices = borderWidths.quadValue();
640     if (slices->top()->isNumber())
641         box.top() = Length(slices->top()->intValue(), Relative);
642     else if (slices->top()->isPercentage())
643         box.top() = Length(slices->top()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
644     else if (slices->top()->valueID() != CSSValueAuto)
645         box.top() = slices->top()->computeLength<Length>(conversionData);
646
647     if (slices->right()->isNumber())
648         box.right() = Length(slices->right()->intValue(), Relative);
649     else if (slices->right()->isPercentage())
650         box.right() = Length(slices->right()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
651     else if (slices->right()->valueID() != CSSValueAuto)
652         box.right() = slices->right()->computeLength<Length>(conversionData);
653
654     if (slices->bottom()->isNumber())
655         box.bottom() = Length(slices->bottom()->intValue(), Relative);
656     else if (slices->bottom()->isPercentage())
657         box.bottom() = Length(slices->bottom()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
658     else if (slices->bottom()->valueID() != CSSValueAuto)
659         box.bottom() = slices->bottom()->computeLength<Length>(conversionData);
660
661     if (slices->left()->isNumber())
662         box.left() = Length(slices->left()->intValue(), Relative);
663     else if (slices->left()->isPercentage())
664         box.left() = Length(slices->left()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
665     else if (slices->left()->valueID() != CSSValueAuto)
666         box.left() = slices->left()->computeLength<Length>(conversionData);
667
668     return box;
669 }
670
671 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue& value, NinePieceImage& image)
672 {
673     if (!is<CSSPrimitiveValue>(value))
674         return;
675
676     CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(value);
677     Pair* pair = primitiveValue.pairValue();
678     if (!pair || !pair->first() || !pair->second())
679         return;
680
681     CSSValueID firstIdentifier = pair->first()->valueID();
682     CSSValueID secondIdentifier = pair->second()->valueID();
683
684     ENinePieceImageRule horizontalRule;
685     switch (firstIdentifier) {
686     case CSSValueStretch:
687         horizontalRule = StretchImageRule;
688         break;
689     case CSSValueRound:
690         horizontalRule = RoundImageRule;
691         break;
692     case CSSValueSpace:
693         horizontalRule = SpaceImageRule;
694         break;
695     default: // CSSValueRepeat
696         horizontalRule = RepeatImageRule;
697         break;
698     }
699     image.setHorizontalRule(horizontalRule);
700
701     ENinePieceImageRule verticalRule;
702     switch (secondIdentifier) {
703     case CSSValueStretch:
704         verticalRule = StretchImageRule;
705         break;
706     case CSSValueRound:
707         verticalRule = RoundImageRule;
708         break;
709     case CSSValueSpace:
710         verticalRule = SpaceImageRule;
711         break;
712     default: // CSSValueRepeat
713         verticalRule = RepeatImageRule;
714         break;
715     }
716     image.setVerticalRule(verticalRule);
717 }
718
719 };