95487dd9e665d28c54da95a44c245cbcf6693bbb
[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 void CSSToStyleMap::mapAnimationTimingFunction(CSSAnimationData* animation, CSSValue* value) const
452 {
453     if (value->isInitialValue()) {
454         animation->setTimingFunction(CSSAnimationData::initialAnimationTimingFunction());
455         return;
456     }
457
458     if (value->isPrimitiveValue()) {
459         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
460         switch (primitiveValue->getValueID()) {
461         case CSSValueLinear:
462             animation->setTimingFunction(LinearTimingFunction::create());
463             break;
464         case CSSValueEase:
465             animation->setTimingFunction(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease));
466             break;
467         case CSSValueEaseIn:
468             animation->setTimingFunction(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn));
469             break;
470         case CSSValueEaseOut:
471             animation->setTimingFunction(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut));
472             break;
473         case CSSValueEaseInOut:
474             animation->setTimingFunction(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut));
475             break;
476         case CSSValueStepStart:
477             animation->setTimingFunction(StepsTimingFunction::preset(StepsTimingFunction::Start));
478             break;
479         case CSSValueStepEnd:
480             animation->setTimingFunction(StepsTimingFunction::preset(StepsTimingFunction::End));
481             break;
482         default:
483             break;
484         }
485         return;
486     }
487
488     if (value->isCubicBezierTimingFunctionValue()) {
489         CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value);
490         animation->setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2()));
491     } else if (value->isStepsTimingFunctionValue()) {
492         CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value);
493         animation->setTimingFunction(StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart()));
494     }
495 }
496
497 void CSSToStyleMap::mapNinePieceImage(RenderStyle* mutableStyle, CSSPropertyID property, CSSValue* value, NinePieceImage& image)
498 {
499     // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
500     if (!value || !value->isValueList())
501         return;
502
503     // Retrieve the border image value.
504     CSSValueList* borderImage = toCSSValueList(value);
505
506     // Set the image (this kicks off the load).
507     CSSPropertyID imageProperty;
508     if (property == CSSPropertyWebkitBorderImage)
509         imageProperty = CSSPropertyBorderImageSource;
510     else if (property == CSSPropertyWebkitMaskBoxImage)
511         imageProperty = CSSPropertyWebkitMaskBoxImageSource;
512     else
513         imageProperty = property;
514
515     for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
516         CSSValue* current = borderImage->item(i);
517
518         if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue())
519             image.setImage(styleImage(imageProperty, current));
520         else if (current->isBorderImageSliceValue())
521             mapNinePieceImageSlice(current, image);
522         else if (current->isValueList()) {
523             CSSValueList* slashList = toCSSValueList(current);
524             // Map in the image slices.
525             if (slashList->item(0) && slashList->item(0)->isBorderImageSliceValue())
526                 mapNinePieceImageSlice(slashList->item(0), image);
527
528             // Map in the border slices.
529             if (slashList->item(1))
530                 image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
531
532             // Map in the outset.
533             if (slashList->item(2))
534                 image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
535         } else if (current->isPrimitiveValue()) {
536             // Set the appropriate rules for stretch/round/repeat of the slices.
537             mapNinePieceImageRepeat(current, image);
538         }
539     }
540
541     if (property == CSSPropertyWebkitBorderImage) {
542         // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
543         // also set the border widths. We don't need to worry about percentages, since we don't even support
544         // those on real borders yet.
545         if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed())
546             mutableStyle->setBorderTopWidth(image.borderSlices().top().length().value());
547         if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed())
548             mutableStyle->setBorderRightWidth(image.borderSlices().right().length().value());
549         if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed())
550             mutableStyle->setBorderBottomWidth(image.borderSlices().bottom().length().value());
551         if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed())
552             mutableStyle->setBorderLeftWidth(image.borderSlices().left().length().value());
553     }
554 }
555
556 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) const
557 {
558     if (!value || !value->isBorderImageSliceValue())
559         return;
560
561     // Retrieve the border image value.
562     CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value);
563
564     // Set up a length box to represent our image slices.
565     LengthBox box;
566     Quad* slices = borderImageSlice->slices();
567     if (slices->top()->isPercentage())
568         box.m_top = Length(slices->top()->getDoubleValue(), Percent);
569     else
570         box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
571     if (slices->bottom()->isPercentage())
572         box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
573     else
574         box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
575     if (slices->left()->isPercentage())
576         box.m_left = Length(slices->left()->getDoubleValue(), Percent);
577     else
578         box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
579     if (slices->right()->isPercentage())
580         box.m_right = Length(slices->right()->getDoubleValue(), Percent);
581     else
582         box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
583     image.setImageSlices(box);
584
585     // Set our fill mode.
586     image.setFill(borderImageSlice->m_fill);
587 }
588
589 static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData)
590 {
591     if (value.isNumber())
592         return value.getDoubleValue();
593     if (value.isPercentage())
594         return Length(value.getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
595     if (value.getValueID() != CSSValueAuto)
596         return value.computeLength<Length>(conversionData);
597     return Length(Auto);
598 }
599
600 BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) const
601 {
602     if (!value || !value->isPrimitiveValue())
603         return BorderImageLengthBox(Length(Auto));
604
605     float zoom = useSVGZoomRules() ? 1.0f : cssToLengthConversionData().zoom();
606     Quad* slices = toCSSPrimitiveValue(value)->getQuadValue();
607
608     // Set up a border image length box to represent our image slices.
609     const CSSToLengthConversionData& conversionData = cssToLengthConversionData().copyWithAdjustedZoom(zoom);
610     return BorderImageLengthBox(
611         toBorderImageLength(*slices->top(), conversionData),
612         toBorderImageLength(*slices->right(), conversionData),
613         toBorderImageLength(*slices->bottom(), conversionData),
614         toBorderImageLength(*slices->left(), conversionData));
615 }
616
617 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) const
618 {
619     if (!value || !value->isPrimitiveValue())
620         return;
621
622     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
623     Pair* pair = primitiveValue->getPairValue();
624     if (!pair || !pair->first() || !pair->second())
625         return;
626
627     CSSValueID firstIdentifier = pair->first()->getValueID();
628     CSSValueID secondIdentifier = pair->second()->getValueID();
629
630     ENinePieceImageRule horizontalRule;
631     switch (firstIdentifier) {
632     case CSSValueStretch:
633         horizontalRule = StretchImageRule;
634         break;
635     case CSSValueRound:
636         horizontalRule = RoundImageRule;
637         break;
638     case CSSValueSpace:
639         horizontalRule = SpaceImageRule;
640         break;
641     default: // CSSValueRepeat
642         horizontalRule = RepeatImageRule;
643         break;
644     }
645     image.setHorizontalRule(horizontalRule);
646
647     ENinePieceImageRule verticalRule;
648     switch (secondIdentifier) {
649     case CSSValueStretch:
650         verticalRule = StretchImageRule;
651         break;
652     case CSSValueRound:
653         verticalRule = RoundImageRule;
654         break;
655     case CSSValueSpace:
656         verticalRule = SpaceImageRule;
657         break;
658     default: // CSSValueRepeat
659         verticalRule = RepeatImageRule;
660         break;
661     }
662     image.setVerticalRule(verticalRule);
663 }
664
665 };