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
42namespace WebCore {
43
44RenderStyle* CSSToStyleMap::style() const
45{
46    return m_resolver->style();
47}
48
49RenderStyle* CSSToStyleMap::rootElementStyle() const
50{
51    return m_resolver->rootElementStyle();
52}
53
54bool CSSToStyleMap::useSVGZoomRules() const
55{
56    return m_resolver->useSVGZoomRules();
57}
58
59PassRefPtr<StyleImage> CSSToStyleMap::styleImage(CSSPropertyID propertyId, CSSValue* value)
60{
61    return m_resolver->styleImage(propertyId, value);
62}
63
64void 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
90void 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
104void 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
118void 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
132void 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
147void 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
157void 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
171void 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
185void 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->getIdent() == CSSValueContain)
194        layer->setSizeType(Contain);
195    else if (primitiveValue->getIdent() == 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->getIdent() == CSSValueContain || primitiveValue->getIdent() == 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
230void 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
266void 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
302void CSSToStyleMap::mapAnimationDelay(Animation* animation, CSSValue* value)
303{
304    if (value->isInitialValue()) {
305        animation->setDelay(Animation::initialAnimationDelay());
306        return;
307    }
308
309    if (!value->isPrimitiveValue())
310        return;
311
312    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
313    animation->setDelay(primitiveValue->computeTime<double, CSSPrimitiveValue::Seconds>());
314}
315
316void CSSToStyleMap::mapAnimationDirection(Animation* layer, CSSValue* value)
317{
318    if (value->isInitialValue()) {
319        layer->setDirection(Animation::initialAnimationDirection());
320        return;
321    }
322
323    if (!value->isPrimitiveValue())
324        return;
325
326    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
327    switch (primitiveValue->getIdent()) {
328    case CSSValueNormal:
329        layer->setDirection(Animation::AnimationDirectionNormal);
330        break;
331    case CSSValueAlternate:
332        layer->setDirection(Animation::AnimationDirectionAlternate);
333        break;
334    case CSSValueReverse:
335        layer->setDirection(Animation::AnimationDirectionReverse);
336        break;
337    case CSSValueAlternateReverse:
338        layer->setDirection(Animation::AnimationDirectionAlternateReverse);
339        break;
340    }
341}
342
343void CSSToStyleMap::mapAnimationDuration(Animation* animation, CSSValue* value)
344{
345    if (value->isInitialValue()) {
346        animation->setDuration(Animation::initialAnimationDuration());
347        return;
348    }
349
350    if (!value->isPrimitiveValue())
351        return;
352
353    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
354    animation->setDuration(primitiveValue->computeTime<double, CSSPrimitiveValue::Seconds>());
355}
356
357void CSSToStyleMap::mapAnimationFillMode(Animation* layer, CSSValue* value)
358{
359    if (value->isInitialValue()) {
360        layer->setFillMode(Animation::initialAnimationFillMode());
361        return;
362    }
363
364    if (!value->isPrimitiveValue())
365        return;
366
367    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
368    switch (primitiveValue->getIdent()) {
369    case CSSValueNone:
370        layer->setFillMode(AnimationFillModeNone);
371        break;
372    case CSSValueForwards:
373        layer->setFillMode(AnimationFillModeForwards);
374        break;
375    case CSSValueBackwards:
376        layer->setFillMode(AnimationFillModeBackwards);
377        break;
378    case CSSValueBoth:
379        layer->setFillMode(AnimationFillModeBoth);
380        break;
381    }
382}
383
384void CSSToStyleMap::mapAnimationIterationCount(Animation* animation, CSSValue* value)
385{
386    if (value->isInitialValue()) {
387        animation->setIterationCount(Animation::initialAnimationIterationCount());
388        return;
389    }
390
391    if (!value->isPrimitiveValue())
392        return;
393
394    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
395    if (primitiveValue->getIdent() == CSSValueInfinite)
396        animation->setIterationCount(Animation::IterationCountInfinite);
397    else
398        animation->setIterationCount(primitiveValue->getFloatValue());
399}
400
401void CSSToStyleMap::mapAnimationName(Animation* layer, CSSValue* value)
402{
403    if (value->isInitialValue()) {
404        layer->setName(Animation::initialAnimationName());
405        return;
406    }
407
408    if (!value->isPrimitiveValue())
409        return;
410
411    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
412    if (primitiveValue->getIdent() == CSSValueNone)
413        layer->setIsNoneAnimation(true);
414    else
415        layer->setName(primitiveValue->getStringValue());
416}
417
418void CSSToStyleMap::mapAnimationPlayState(Animation* layer, CSSValue* value)
419{
420    if (value->isInitialValue()) {
421        layer->setPlayState(Animation::initialAnimationPlayState());
422        return;
423    }
424
425    if (!value->isPrimitiveValue())
426        return;
427
428    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
429    EAnimPlayState playState = (primitiveValue->getIdent() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying;
430    layer->setPlayState(playState);
431}
432
433void CSSToStyleMap::mapAnimationProperty(Animation* animation, CSSValue* value)
434{
435    if (value->isInitialValue()) {
436        animation->setAnimationMode(Animation::AnimateAll);
437        animation->setProperty(CSSPropertyInvalid);
438        return;
439    }
440
441    if (!value->isPrimitiveValue())
442        return;
443
444    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
445    if (primitiveValue->getIdent() == CSSValueAll) {
446        animation->setAnimationMode(Animation::AnimateAll);
447        animation->setProperty(CSSPropertyInvalid);
448    } else if (primitiveValue->getIdent() == CSSValueNone) {
449        animation->setAnimationMode(Animation::AnimateNone);
450        animation->setProperty(CSSPropertyInvalid);
451    } else {
452        animation->setAnimationMode(Animation::AnimateSingleProperty);
453        animation->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent()));
454    }
455}
456
457void CSSToStyleMap::mapAnimationTimingFunction(Animation* animation, CSSValue* value)
458{
459    if (value->isInitialValue()) {
460        animation->setTimingFunction(Animation::initialAnimationTimingFunction());
461        return;
462    }
463
464    if (value->isPrimitiveValue()) {
465        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
466        switch (primitiveValue->getIdent()) {
467        case CSSValueLinear:
468            animation->setTimingFunction(LinearTimingFunction::create());
469            break;
470        case CSSValueEase:
471            animation->setTimingFunction(CubicBezierTimingFunction::create());
472            break;
473        case CSSValueEaseIn:
474            animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseIn));
475            break;
476        case CSSValueEaseOut:
477            animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseOut));
478            break;
479        case CSSValueEaseInOut:
480            animation->setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseInOut));
481            break;
482        case CSSValueStepStart:
483            animation->setTimingFunction(StepsTimingFunction::create(1, true));
484            break;
485        case CSSValueStepEnd:
486            animation->setTimingFunction(StepsTimingFunction::create(1, false));
487            break;
488        }
489        return;
490    }
491
492    if (value->isCubicBezierTimingFunctionValue()) {
493        CSSCubicBezierTimingFunctionValue* cubicTimingFunction = static_cast<CSSCubicBezierTimingFunctionValue*>(value);
494        animation->setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2()));
495    } else if (value->isStepsTimingFunctionValue()) {
496        CSSStepsTimingFunctionValue* stepsTimingFunction = static_cast<CSSStepsTimingFunctionValue*>(value);
497        animation->setTimingFunction(StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart()));
498    } else if (value->isLinearTimingFunctionValue())
499        animation->setTimingFunction(LinearTimingFunction::create());
500}
501
502void CSSToStyleMap::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image)
503{
504    // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
505    if (!value || !value->isValueList())
506        return;
507
508    // Retrieve the border image value.
509    CSSValueList* borderImage = static_cast<CSSValueList*>(value);
510
511    // Set the image (this kicks off the load).
512    CSSPropertyID imageProperty;
513    if (property == CSSPropertyWebkitBorderImage)
514        imageProperty = CSSPropertyBorderImageSource;
515    else if (property == CSSPropertyWebkitMaskBoxImage)
516        imageProperty = CSSPropertyWebkitMaskBoxImageSource;
517    else
518        imageProperty = property;
519
520    for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
521        CSSValue* current = borderImage->item(i);
522
523        if (current->isImageValue() || current->isImageGeneratorValue()
524#if ENABLE(CSS_IMAGE_SET)
525            || current->isImageSetValue()
526#endif
527            )
528            image.setImage(styleImage(imageProperty, current));
529        else if (current->isBorderImageSliceValue())
530            mapNinePieceImageSlice(current, image);
531        else if (current->isValueList()) {
532            CSSValueList* slashList = static_cast<CSSValueList*>(current);
533            // Map in the image slices.
534            if (slashList->item(0) && slashList->item(0)->isBorderImageSliceValue())
535                mapNinePieceImageSlice(slashList->item(0), image);
536
537            // Map in the border slices.
538            if (slashList->item(1))
539                image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
540
541            // Map in the outset.
542            if (slashList->item(2))
543                image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
544        } else if (current->isPrimitiveValue()) {
545            // Set the appropriate rules for stretch/round/repeat of the slices.
546            mapNinePieceImageRepeat(current, image);
547        }
548    }
549
550    if (property == CSSPropertyWebkitBorderImage) {
551        // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
552        // also set the border widths. We don't need to worry about percentages, since we don't even support
553        // those on real borders yet.
554        if (image.borderSlices().top().isFixed())
555            style()->setBorderTopWidth(image.borderSlices().top().value());
556        if (image.borderSlices().right().isFixed())
557            style()->setBorderRightWidth(image.borderSlices().right().value());
558        if (image.borderSlices().bottom().isFixed())
559            style()->setBorderBottomWidth(image.borderSlices().bottom().value());
560        if (image.borderSlices().left().isFixed())
561            style()->setBorderLeftWidth(image.borderSlices().left().value());
562    }
563}
564
565void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image)
566{
567    if (!value || !value->isBorderImageSliceValue())
568        return;
569
570    // Retrieve the border image value.
571    CSSBorderImageSliceValue* borderImageSlice = static_cast<CSSBorderImageSliceValue*>(value);
572
573    // Set up a length box to represent our image slices.
574    LengthBox box;
575    Quad* slices = borderImageSlice->slices();
576    if (slices->top()->isPercentage())
577        box.m_top = Length(slices->top()->getDoubleValue(), Percent);
578    else
579        box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
580    if (slices->bottom()->isPercentage())
581        box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
582    else
583        box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
584    if (slices->left()->isPercentage())
585        box.m_left = Length(slices->left()->getDoubleValue(), Percent);
586    else
587        box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
588    if (slices->right()->isPercentage())
589        box.m_right = Length(slices->right()->getDoubleValue(), Percent);
590    else
591        box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
592    image.setImageSlices(box);
593
594    // Set our fill mode.
595    image.setFill(borderImageSlice->m_fill);
596}
597
598LengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value)
599{
600    if (!value || !value->isPrimitiveValue())
601        return LengthBox();
602
603    // Get our zoom value.
604    float zoom = useSVGZoomRules() ? 1.0f : style()->effectiveZoom();
605
606    // Retrieve the primitive value.
607    CSSPrimitiveValue* borderWidths = static_cast<CSSPrimitiveValue*>(value);
608
609    // Set up a length box to represent our image slices.
610    LengthBox box; // Defaults to 'auto' so we don't have to handle that explicitly below.
611    Quad* slices = borderWidths->getQuadValue();
612    if (slices->top()->isNumber())
613        box.m_top = Length(slices->top()->getIntValue(), Relative);
614    else if (slices->top()->isPercentage())
615        box.m_top = Length(slices->top()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
616    else if (slices->top()->getIdent() != CSSValueAuto)
617        box.m_top = slices->top()->computeLength<Length>(style(), rootElementStyle(), zoom);
618
619    if (slices->right()->isNumber())
620        box.m_right = Length(slices->right()->getIntValue(), Relative);
621    else if (slices->right()->isPercentage())
622        box.m_right = Length(slices->right()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
623    else if (slices->right()->getIdent() != CSSValueAuto)
624        box.m_right = slices->right()->computeLength<Length>(style(), rootElementStyle(), zoom);
625
626    if (slices->bottom()->isNumber())
627        box.m_bottom = Length(slices->bottom()->getIntValue(), Relative);
628    else if (slices->bottom()->isPercentage())
629        box.m_bottom = Length(slices->bottom()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
630    else if (slices->bottom()->getIdent() != CSSValueAuto)
631        box.m_bottom = slices->bottom()->computeLength<Length>(style(), rootElementStyle(), zoom);
632
633    if (slices->left()->isNumber())
634        box.m_left = Length(slices->left()->getIntValue(), Relative);
635    else if (slices->left()->isPercentage())
636        box.m_left = Length(slices->left()->getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
637    else if (slices->left()->getIdent() != CSSValueAuto)
638        box.m_left = slices->left()->computeLength<Length>(style(), rootElementStyle(), zoom);
639
640    return box;
641}
642
643void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image)
644{
645    if (!value || !value->isPrimitiveValue())
646        return;
647
648    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
649    Pair* pair = primitiveValue->getPairValue();
650    if (!pair || !pair->first() || !pair->second())
651        return;
652
653    int firstIdentifier = pair->first()->getIdent();
654    int secondIdentifier = pair->second()->getIdent();
655
656    ENinePieceImageRule horizontalRule;
657    switch (firstIdentifier) {
658    case CSSValueStretch:
659        horizontalRule = StretchImageRule;
660        break;
661    case CSSValueRound:
662        horizontalRule = RoundImageRule;
663        break;
664    case CSSValueSpace:
665        horizontalRule = SpaceImageRule;
666        break;
667    default: // CSSValueRepeat
668        horizontalRule = RepeatImageRule;
669        break;
670    }
671    image.setHorizontalRule(horizontalRule);
672
673    ENinePieceImageRule verticalRule;
674    switch (secondIdentifier) {
675    case CSSValueStretch:
676        verticalRule = StretchImageRule;
677        break;
678    case CSSValueRound:
679        verticalRule = RoundImageRule;
680        break;
681    case CSSValueSpace:
682        verticalRule = SpaceImageRule;
683        break;
684    default: // CSSValueRepeat
685        verticalRule = RepeatImageRule;
686        break;
687    }
688    image.setVerticalRule(verticalRule);
689}
690
691};
692