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