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