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