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