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