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