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