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