Upstream version 7.36.149.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(), 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->isInitialValue()) {
184         layer->setSizeType(FillLayer::initialFillSizeType(layer->type()));
185         layer->setSizeLength(FillLayer::initialFillSizeLength(layer->type()));
186         return;
187     }
188
189     if (!value->isPrimitiveValue())
190         return;
191
192     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
193     if (primitiveValue->getValueID() == CSSValueContain)
194         layer->setSizeType(Contain);
195     else if (primitiveValue->getValueID() == CSSValueCover)
196         layer->setSizeType(Cover);
197     else
198         layer->setSizeType(SizeLength);
199
200     LengthSize b = FillLayer::initialFillSizeLength(layer->type());
201
202     if (primitiveValue->getValueID() == CSSValueContain || primitiveValue->getValueID() == CSSValueCover) {
203         layer->setSizeLength(b);
204         return;
205     }
206
207     Length firstLength;
208     Length secondLength;
209
210     if (Pair* pair = primitiveValue->getPairValue()) {
211         firstLength = pair->first()->convertToLength<AnyConversion>(cssToLengthConversionData());
212         secondLength = pair->second()->convertToLength<AnyConversion>(cssToLengthConversionData());
213     } else {
214         firstLength = primitiveValue->convertToLength<AnyConversion>(cssToLengthConversionData());
215         secondLength = Length();
216     }
217
218     b.setWidth(firstLength);
219     b.setHeight(secondLength);
220     layer->setSizeLength(b);
221 }
222
223 void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) const
224 {
225     if (value->isInitialValue()) {
226         layer->setXPosition(FillLayer::initialFillXPosition(layer->type()));
227         return;
228     }
229
230     if (!value->isPrimitiveValue())
231         return;
232
233     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
234     Pair* pair = primitiveValue->getPairValue();
235     if (pair) {
236         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionX || propertyID == CSSPropertyWebkitMaskPositionX);
237         primitiveValue = pair->second();
238     }
239
240     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
241
242     layer->setXPosition(length);
243     if (pair)
244         layer->setBackgroundXOrigin(*(pair->first()));
245 }
246
247 void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) const
248 {
249     if (value->isInitialValue()) {
250         layer->setYPosition(FillLayer::initialFillYPosition(layer->type()));
251         return;
252     }
253
254     if (!value->isPrimitiveValue())
255         return;
256
257     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
258     Pair* pair = primitiveValue->getPairValue();
259     if (pair) {
260         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionY || propertyID == CSSPropertyWebkitMaskPositionY);
261         primitiveValue = pair->second();
262     }
263
264     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
265
266     layer->setYPosition(length);
267     if (pair)
268         layer->setBackgroundYOrigin(*(pair->first()));
269 }
270
271 void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID, FillLayer* layer, CSSValue* value)
272 {
273     EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer->type());
274     if (value->isInitialValue()) {
275         layer->setMaskSourceType(type);
276         return;
277     }
278
279     if (!value->isPrimitiveValue())
280         return;
281
282     switch (toCSSPrimitiveValue(value)->getValueID()) {
283     case CSSValueAlpha:
284         type = MaskAlpha;
285         break;
286     case CSSValueLuminance:
287         type = MaskLuminance;
288         break;
289     case CSSValueAuto:
290         break;
291     default:
292         ASSERT_NOT_REACHED();
293     }
294
295     layer->setMaskSourceType(type);
296 }
297
298 void CSSToStyleMap::mapAnimationDelay(CSSAnimationData* animation, CSSValue* value) const
299 {
300     if (value->isInitialValue()) {
301         animation->setDelay(CSSAnimationData::initialAnimationDelay());
302         return;
303     }
304
305     if (!value->isPrimitiveValue())
306         return;
307
308     animation->setDelay(toCSSPrimitiveValue(value)->computeTime<double, CSSPrimitiveValue::Seconds>());
309 }
310
311 void CSSToStyleMap::mapAnimationDirection(CSSAnimationData* layer, CSSValue* value) const
312 {
313     if (value->isInitialValue()) {
314         layer->setDirection(CSSAnimationData::initialAnimationDirection());
315         return;
316     }
317
318     if (!value->isPrimitiveValue())
319         return;
320
321     switch (toCSSPrimitiveValue(value)->getValueID()) {
322     case CSSValueNormal:
323         layer->setDirection(CSSAnimationData::AnimationDirectionNormal);
324         break;
325     case CSSValueAlternate:
326         layer->setDirection(CSSAnimationData::AnimationDirectionAlternate);
327         break;
328     case CSSValueReverse:
329         layer->setDirection(CSSAnimationData::AnimationDirectionReverse);
330         break;
331     case CSSValueAlternateReverse:
332         layer->setDirection(CSSAnimationData::AnimationDirectionAlternateReverse);
333         break;
334     default:
335         break;
336     }
337 }
338
339 void CSSToStyleMap::mapAnimationDuration(CSSAnimationData* animation, CSSValue* value) const
340 {
341     if (value->isInitialValue()) {
342         animation->setDuration(CSSAnimationData::initialAnimationDuration());
343         return;
344     }
345
346     if (!value->isPrimitiveValue())
347         return;
348
349     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
350     animation->setDuration(primitiveValue->computeTime<double, CSSPrimitiveValue::Seconds>());
351 }
352
353 void CSSToStyleMap::mapAnimationFillMode(CSSAnimationData* layer, CSSValue* value) const
354 {
355     if (value->isInitialValue()) {
356         layer->setFillMode(CSSAnimationData::initialAnimationFillMode());
357         return;
358     }
359
360     if (!value->isPrimitiveValue())
361         return;
362
363     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
364     switch (primitiveValue->getValueID()) {
365     case CSSValueNone:
366         layer->setFillMode(AnimationFillModeNone);
367         break;
368     case CSSValueForwards:
369         layer->setFillMode(AnimationFillModeForwards);
370         break;
371     case CSSValueBackwards:
372         layer->setFillMode(AnimationFillModeBackwards);
373         break;
374     case CSSValueBoth:
375         layer->setFillMode(AnimationFillModeBoth);
376         break;
377     default:
378         break;
379     }
380 }
381
382 void CSSToStyleMap::mapAnimationIterationCount(CSSAnimationData* animation, CSSValue* value) const
383 {
384     if (value->isInitialValue()) {
385         animation->setIterationCount(CSSAnimationData::initialAnimationIterationCount());
386         return;
387     }
388
389     if (!value->isPrimitiveValue())
390         return;
391
392     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
393     if (primitiveValue->getValueID() == CSSValueInfinite)
394         animation->setIterationCount(CSSAnimationData::IterationCountInfinite);
395     else
396         animation->setIterationCount(primitiveValue->getFloatValue());
397 }
398
399 void CSSToStyleMap::mapAnimationName(CSSAnimationData* layer, CSSValue* value) const
400 {
401     if (value->isInitialValue()) {
402         layer->setName(CSSAnimationData::initialAnimationName());
403         return;
404     }
405
406     if (!value->isPrimitiveValue())
407         return;
408
409     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
410     if (primitiveValue->getValueID() == CSSValueNone)
411         layer->setIsNoneAnimation(true);
412     else
413         layer->setName(AtomicString(primitiveValue->getStringValue()));
414 }
415
416 void CSSToStyleMap::mapAnimationPlayState(CSSAnimationData* layer, CSSValue* value) const
417 {
418     if (value->isInitialValue()) {
419         layer->setPlayState(CSSAnimationData::initialAnimationPlayState());
420         return;
421     }
422
423     if (!value->isPrimitiveValue())
424         return;
425
426     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
427     EAnimPlayState playState = (primitiveValue->getValueID() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying;
428     layer->setPlayState(playState);
429 }
430
431 void CSSToStyleMap::mapAnimationProperty(CSSAnimationData* animation, CSSValue* value) const
432 {
433     if (value->isInitialValue()) {
434         animation->setAnimationMode(CSSAnimationData::AnimateAll);
435         animation->setProperty(CSSPropertyInvalid);
436         return;
437     }
438
439     if (!value->isPrimitiveValue())
440         return;
441
442     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
443     if (primitiveValue->getValueID() == CSSValueAll) {
444         animation->setAnimationMode(CSSAnimationData::AnimateAll);
445         animation->setProperty(CSSPropertyInvalid);
446     } else if (primitiveValue->getValueID() == CSSValueNone) {
447         animation->setAnimationMode(CSSAnimationData::AnimateNone);
448         animation->setProperty(CSSPropertyInvalid);
449     } else {
450         animation->setAnimationMode(CSSAnimationData::AnimateSingleProperty);
451         animation->setProperty(primitiveValue->getPropertyID());
452     }
453 }
454
455 PassRefPtr<TimingFunction> CSSToStyleMap::animationTimingFunction(CSSValue* value, bool allowInitial)
456 {
457     if (allowInitial && value->isInitialValue()) {
458         return CSSAnimationData::initialAnimationTimingFunction();
459     }
460
461     if (value->isPrimitiveValue()) {
462         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
463         switch (primitiveValue->getValueID()) {
464         case CSSValueLinear:
465             return LinearTimingFunction::shared();
466             break;
467         case CSSValueEase:
468             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease);
469             break;
470         case CSSValueEaseIn:
471             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
472             break;
473         case CSSValueEaseOut:
474             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
475             break;
476         case CSSValueEaseInOut:
477             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut);
478             break;
479         case CSSValueStepStart:
480             return StepsTimingFunction::preset(StepsTimingFunction::Start);
481             break;
482         case CSSValueStepMiddle:
483             return StepsTimingFunction::preset(StepsTimingFunction::Middle);
484             break;
485         case CSSValueStepEnd:
486             return StepsTimingFunction::preset(StepsTimingFunction::End);
487             break;
488         default:
489             break;
490         }
491         return nullptr;
492     }
493
494     if (value->isCubicBezierTimingFunctionValue()) {
495         CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value);
496         return CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2());
497     } else if (value->isStepsTimingFunctionValue()) {
498         CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value);
499         return StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtPosition());
500     }
501
502     return nullptr;
503 }
504
505 void CSSToStyleMap::mapAnimationTimingFunction(CSSAnimationData* animation, CSSValue* value) const
506 {
507     RefPtr<TimingFunction> timingFunction = animationTimingFunction(value, true);
508     if (timingFunction) {
509         // Step middle timing functions are supported up to this point for use in the Web Animations API,
510         // but should not be supported for CSS Animations and Transitions.
511         bool isStepMiddleFunction = (timingFunction->type() == TimingFunction::StepsFunction) && (toStepsTimingFunction(*timingFunction).stepAtPosition() == StepsTimingFunction::StepAtMiddle);
512         if (isStepMiddleFunction)
513             animation->setTimingFunction(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease));
514         else
515             animation->setTimingFunction(timingFunction);
516     }
517 }
518
519 void CSSToStyleMap::mapNinePieceImage(RenderStyle* mutableStyle, CSSPropertyID property, CSSValue* value, NinePieceImage& image)
520 {
521     // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
522     if (!value || !value->isValueList())
523         return;
524
525     // Retrieve the border image value.
526     CSSValueList* borderImage = toCSSValueList(value);
527
528     // Set the image (this kicks off the load).
529     CSSPropertyID imageProperty;
530     if (property == CSSPropertyWebkitBorderImage)
531         imageProperty = CSSPropertyBorderImageSource;
532     else if (property == CSSPropertyWebkitMaskBoxImage)
533         imageProperty = CSSPropertyWebkitMaskBoxImageSource;
534     else
535         imageProperty = property;
536
537     for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
538         CSSValue* current = borderImage->item(i);
539
540         if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue())
541             image.setImage(styleImage(imageProperty, current));
542         else if (current->isBorderImageSliceValue())
543             mapNinePieceImageSlice(current, image);
544         else if (current->isValueList()) {
545             CSSValueList* slashList = toCSSValueList(current);
546             // Map in the image slices.
547             if (slashList->item(0) && slashList->item(0)->isBorderImageSliceValue())
548                 mapNinePieceImageSlice(slashList->item(0), image);
549
550             // Map in the border slices.
551             if (slashList->item(1))
552                 image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
553
554             // Map in the outset.
555             if (slashList->item(2))
556                 image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
557         } else if (current->isPrimitiveValue()) {
558             // Set the appropriate rules for stretch/round/repeat of the slices.
559             mapNinePieceImageRepeat(current, image);
560         }
561     }
562
563     if (property == CSSPropertyWebkitBorderImage) {
564         // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
565         // also set the border widths. We don't need to worry about percentages, since we don't even support
566         // those on real borders yet.
567         if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed())
568             mutableStyle->setBorderTopWidth(image.borderSlices().top().length().value());
569         if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed())
570             mutableStyle->setBorderRightWidth(image.borderSlices().right().length().value());
571         if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed())
572             mutableStyle->setBorderBottomWidth(image.borderSlices().bottom().length().value());
573         if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed())
574             mutableStyle->setBorderLeftWidth(image.borderSlices().left().length().value());
575     }
576 }
577
578 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) const
579 {
580     if (!value || !value->isBorderImageSliceValue())
581         return;
582
583     // Retrieve the border image value.
584     CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value);
585
586     // Set up a length box to represent our image slices.
587     LengthBox box;
588     Quad* slices = borderImageSlice->slices();
589     if (slices->top()->isPercentage())
590         box.m_top = Length(slices->top()->getDoubleValue(), Percent);
591     else
592         box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
593     if (slices->bottom()->isPercentage())
594         box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
595     else
596         box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
597     if (slices->left()->isPercentage())
598         box.m_left = Length(slices->left()->getDoubleValue(), Percent);
599     else
600         box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
601     if (slices->right()->isPercentage())
602         box.m_right = Length(slices->right()->getDoubleValue(), Percent);
603     else
604         box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
605     image.setImageSlices(box);
606
607     // Set our fill mode.
608     image.setFill(borderImageSlice->m_fill);
609 }
610
611 static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData)
612 {
613     if (value.isNumber())
614         return value.getDoubleValue();
615     if (value.isPercentage())
616         return Length(value.getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
617     if (value.getValueID() != CSSValueAuto)
618         return value.computeLength<Length>(conversionData);
619     return Length(Auto);
620 }
621
622 BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) const
623 {
624     if (!value || !value->isPrimitiveValue())
625         return BorderImageLengthBox(Length(Auto));
626
627     float zoom = useSVGZoomRules() ? 1.0f : cssToLengthConversionData().zoom();
628     Quad* slices = toCSSPrimitiveValue(value)->getQuadValue();
629
630     // Set up a border image length box to represent our image slices.
631     const CSSToLengthConversionData& conversionData = cssToLengthConversionData().copyWithAdjustedZoom(zoom);
632     return BorderImageLengthBox(
633         toBorderImageLength(*slices->top(), conversionData),
634         toBorderImageLength(*slices->right(), conversionData),
635         toBorderImageLength(*slices->bottom(), conversionData),
636         toBorderImageLength(*slices->left(), conversionData));
637 }
638
639 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) const
640 {
641     if (!value || !value->isPrimitiveValue())
642         return;
643
644     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
645     Pair* pair = primitiveValue->getPairValue();
646     if (!pair || !pair->first() || !pair->second())
647         return;
648
649     CSSValueID firstIdentifier = pair->first()->getValueID();
650     CSSValueID secondIdentifier = pair->second()->getValueID();
651
652     ENinePieceImageRule horizontalRule;
653     switch (firstIdentifier) {
654     case CSSValueStretch:
655         horizontalRule = StretchImageRule;
656         break;
657     case CSSValueRound:
658         horizontalRule = RoundImageRule;
659         break;
660     case CSSValueSpace:
661         horizontalRule = SpaceImageRule;
662         break;
663     default: // CSSValueRepeat
664         horizontalRule = RepeatImageRule;
665         break;
666     }
667     image.setHorizontalRule(horizontalRule);
668
669     ENinePieceImageRule verticalRule;
670     switch (secondIdentifier) {
671     case CSSValueStretch:
672         verticalRule = StretchImageRule;
673         break;
674     case CSSValueRound:
675         verticalRule = RoundImageRule;
676         break;
677     case CSSValueSpace:
678         verticalRule = SpaceImageRule;
679         break;
680     default: // CSSValueRepeat
681         verticalRule = RepeatImageRule;
682         break;
683     }
684     image.setVerticalRule(verticalRule);
685 }
686
687 };