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