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