Home | History | Annotate | Download | only in resolver
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) 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 (at) webkit.org>
      7  * Copyright (C) 2007, 2008 Eric Seidel <eric (at) 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 "core/css/resolver/CSSToStyleMap.h"
     30 
     31 #include "core/CSSValueKeywords.h"
     32 #include "core/animation/css/CSSAnimationData.h"
     33 #include "core/css/CSSBorderImageSliceValue.h"
     34 #include "core/css/CSSPrimitiveValue.h"
     35 #include "core/css/CSSPrimitiveValueMappings.h"
     36 #include "core/css/CSSTimingFunctionValue.h"
     37 #include "core/css/Pair.h"
     38 #include "core/css/Rect.h"
     39 #include "core/css/resolver/StyleResolverState.h"
     40 #include "core/rendering/style/BorderImageLengthBox.h"
     41 #include "core/rendering/style/FillLayer.h"
     42 
     43 namespace WebCore {
     44 
     45 const CSSToLengthConversionData& CSSToStyleMap::cssToLengthConversionData() const
     46 {
     47     return m_state.cssToLengthConversionData();
     48 }
     49 
     50 PassRefPtr<StyleImage> CSSToStyleMap::styleImage(CSSPropertyID propertyId, CSSValue* value)
     51 {
     52     return m_elementStyleResources.styleImage(m_state.document(), m_state.document().textLinkColors(), m_state.style()->color(), propertyId, value);
     53 }
     54 
     55 void CSSToStyleMap::mapFillAttachment(CSSPropertyID, FillLayer* layer, CSSValue* value) const
     56 {
     57     if (value->isInitialValue()) {
     58         layer->setAttachment(FillLayer::initialFillAttachment(layer->type()));
     59         return;
     60     }
     61 
     62     if (!value->isPrimitiveValue())
     63         return;
     64 
     65     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     66     switch (primitiveValue->getValueID()) {
     67     case CSSValueFixed:
     68         layer->setAttachment(FixedBackgroundAttachment);
     69         break;
     70     case CSSValueScroll:
     71         layer->setAttachment(ScrollBackgroundAttachment);
     72         break;
     73     case CSSValueLocal:
     74         layer->setAttachment(LocalBackgroundAttachment);
     75         break;
     76     default:
     77         return;
     78     }
     79 }
     80 
     81 void CSSToStyleMap::mapFillClip(CSSPropertyID, FillLayer* layer, CSSValue* value) const
     82 {
     83     if (value->isInitialValue()) {
     84         layer->setClip(FillLayer::initialFillClip(layer->type()));
     85         return;
     86     }
     87 
     88     if (!value->isPrimitiveValue())
     89         return;
     90 
     91     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     92     layer->setClip(*primitiveValue);
     93 }
     94 
     95 void CSSToStyleMap::mapFillComposite(CSSPropertyID, FillLayer* layer, CSSValue* value) const
     96 {
     97     if (value->isInitialValue()) {
     98         layer->setComposite(FillLayer::initialFillComposite(layer->type()));
     99         return;
    100     }
    101 
    102     if (!value->isPrimitiveValue())
    103         return;
    104 
    105     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    106     layer->setComposite(*primitiveValue);
    107 }
    108 
    109 void CSSToStyleMap::mapFillBlendMode(CSSPropertyID, FillLayer* layer, CSSValue* value) const
    110 {
    111     if (value->isInitialValue()) {
    112         layer->setBlendMode(FillLayer::initialFillBlendMode(layer->type()));
    113         return;
    114     }
    115 
    116     if (!value->isPrimitiveValue())
    117         return;
    118 
    119     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    120     layer->setBlendMode(*primitiveValue);
    121 }
    122 
    123 void CSSToStyleMap::mapFillOrigin(CSSPropertyID, FillLayer* layer, CSSValue* value) const
    124 {
    125     if (value->isInitialValue()) {
    126         layer->setOrigin(FillLayer::initialFillOrigin(layer->type()));
    127         return;
    128     }
    129 
    130     if (!value->isPrimitiveValue())
    131         return;
    132 
    133     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    134     layer->setOrigin(*primitiveValue);
    135 }
    136 
    137 
    138 void CSSToStyleMap::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value)
    139 {
    140     if (value->isInitialValue()) {
    141         layer->setImage(FillLayer::initialFillImage(layer->type()));
    142         return;
    143     }
    144 
    145     layer->setImage(styleImage(property, value));
    146 }
    147 
    148 void CSSToStyleMap::mapFillRepeatX(CSSPropertyID, FillLayer* layer, CSSValue* value) const
    149 {
    150     if (value->isInitialValue()) {
    151         layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type()));
    152         return;
    153     }
    154 
    155     if (!value->isPrimitiveValue())
    156         return;
    157 
    158     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    159     layer->setRepeatX(*primitiveValue);
    160 }
    161 
    162 void CSSToStyleMap::mapFillRepeatY(CSSPropertyID, FillLayer* layer, CSSValue* value) const
    163 {
    164     if (value->isInitialValue()) {
    165         layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type()));
    166         return;
    167     }
    168 
    169     if (!value->isPrimitiveValue())
    170         return;
    171 
    172     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    173     layer->setRepeatY(*primitiveValue);
    174 }
    175 
    176 void CSSToStyleMap::mapFillSize(CSSPropertyID, FillLayer* layer, CSSValue* value) const
    177 {
    178     if (value->isInitialValue()) {
    179         layer->setSizeType(FillLayer::initialFillSizeType(layer->type()));
    180         layer->setSizeLength(FillLayer::initialFillSizeLength(layer->type()));
    181         return;
    182     }
    183 
    184     if (!value->isPrimitiveValue())
    185         return;
    186 
    187     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    188     if (primitiveValue->getValueID() == CSSValueContain)
    189         layer->setSizeType(Contain);
    190     else if (primitiveValue->getValueID() == CSSValueCover)
    191         layer->setSizeType(Cover);
    192     else
    193         layer->setSizeType(SizeLength);
    194 
    195     LengthSize b = FillLayer::initialFillSizeLength(layer->type());
    196 
    197     if (primitiveValue->getValueID() == CSSValueContain || primitiveValue->getValueID() == CSSValueCover) {
    198         layer->setSizeLength(b);
    199         return;
    200     }
    201 
    202     Length firstLength;
    203     Length secondLength;
    204 
    205     if (Pair* pair = primitiveValue->getPairValue()) {
    206         firstLength = pair->first()->convertToLength<AnyConversion>(cssToLengthConversionData());
    207         secondLength = pair->second()->convertToLength<AnyConversion>(cssToLengthConversionData());
    208     } else {
    209         firstLength = primitiveValue->convertToLength<AnyConversion>(cssToLengthConversionData());
    210         secondLength = Length();
    211     }
    212 
    213     b.setWidth(firstLength);
    214     b.setHeight(secondLength);
    215     layer->setSizeLength(b);
    216 }
    217 
    218 void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) const
    219 {
    220     if (value->isInitialValue()) {
    221         layer->setXPosition(FillLayer::initialFillXPosition(layer->type()));
    222         return;
    223     }
    224 
    225     if (!value->isPrimitiveValue())
    226         return;
    227 
    228     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    229     Pair* pair = primitiveValue->getPairValue();
    230     if (pair) {
    231         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionX || propertyID == CSSPropertyWebkitMaskPositionX);
    232         primitiveValue = pair->second();
    233     }
    234 
    235     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
    236 
    237     layer->setXPosition(length);
    238     if (pair)
    239         layer->setBackgroundXOrigin(*(pair->first()));
    240 }
    241 
    242 void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer* layer, CSSValue* value) const
    243 {
    244     if (value->isInitialValue()) {
    245         layer->setYPosition(FillLayer::initialFillYPosition(layer->type()));
    246         return;
    247     }
    248 
    249     if (!value->isPrimitiveValue())
    250         return;
    251 
    252     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    253     Pair* pair = primitiveValue->getPairValue();
    254     if (pair) {
    255         ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionY || propertyID == CSSPropertyWebkitMaskPositionY);
    256         primitiveValue = pair->second();
    257     }
    258 
    259     Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
    260 
    261     layer->setYPosition(length);
    262     if (pair)
    263         layer->setBackgroundYOrigin(*(pair->first()));
    264 }
    265 
    266 void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID, FillLayer* layer, CSSValue* value)
    267 {
    268     EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer->type());
    269     if (value->isInitialValue()) {
    270         layer->setMaskSourceType(type);
    271         return;
    272     }
    273 
    274     if (!value->isPrimitiveValue())
    275         return;
    276 
    277     switch (toCSSPrimitiveValue(value)->getValueID()) {
    278     case CSSValueAlpha:
    279         type = MaskAlpha;
    280         break;
    281     case CSSValueLuminance:
    282         type = MaskLuminance;
    283         break;
    284     case CSSValueAuto:
    285         break;
    286     default:
    287         ASSERT_NOT_REACHED();
    288     }
    289 
    290     layer->setMaskSourceType(type);
    291 }
    292 
    293 double CSSToStyleMap::mapAnimationDelay(CSSValue* value)
    294 {
    295     if (value->isInitialValue())
    296         return CSSTimingData::initialDelay();
    297     return toCSSPrimitiveValue(value)->computeTime<double, CSSPrimitiveValue::Seconds>();
    298 }
    299 
    300 Timing::PlaybackDirection CSSToStyleMap::mapAnimationDirection(CSSValue* value)
    301 {
    302     if (value->isInitialValue())
    303         return CSSAnimationData::initialDirection();
    304 
    305     switch (toCSSPrimitiveValue(value)->getValueID()) {
    306     case CSSValueNormal:
    307         return Timing::PlaybackDirectionNormal;
    308     case CSSValueAlternate:
    309         return Timing::PlaybackDirectionAlternate;
    310     case CSSValueReverse:
    311         return Timing::PlaybackDirectionReverse;
    312     case CSSValueAlternateReverse:
    313         return Timing::PlaybackDirectionAlternateReverse;
    314     default:
    315         ASSERT_NOT_REACHED();
    316         return CSSAnimationData::initialDirection();
    317     }
    318 }
    319 
    320 double CSSToStyleMap::mapAnimationDuration(CSSValue* value)
    321 {
    322     if (value->isInitialValue())
    323         return CSSTimingData::initialDuration();
    324     return toCSSPrimitiveValue(value)->computeTime<double, CSSPrimitiveValue::Seconds>();
    325 }
    326 
    327 Timing::FillMode CSSToStyleMap::mapAnimationFillMode(CSSValue* value)
    328 {
    329     if (value->isInitialValue())
    330         return CSSAnimationData::initialFillMode();
    331 
    332     switch (toCSSPrimitiveValue(value)->getValueID()) {
    333     case CSSValueNone:
    334         return Timing::FillModeNone;
    335     case CSSValueForwards:
    336         return Timing::FillModeForwards;
    337     case CSSValueBackwards:
    338         return Timing::FillModeBackwards;
    339     case CSSValueBoth:
    340         return Timing::FillModeBoth;
    341     default:
    342         ASSERT_NOT_REACHED();
    343         return CSSAnimationData::initialFillMode();
    344     }
    345 }
    346 
    347 double CSSToStyleMap::mapAnimationIterationCount(CSSValue* value)
    348 {
    349     if (value->isInitialValue())
    350         return CSSAnimationData::initialIterationCount();
    351     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    352     if (primitiveValue->getValueID() == CSSValueInfinite)
    353         return std::numeric_limits<double>::infinity();
    354     return primitiveValue->getFloatValue();
    355 }
    356 
    357 AtomicString CSSToStyleMap::mapAnimationName(CSSValue* value)
    358 {
    359     if (value->isInitialValue())
    360         return CSSAnimationData::initialName();
    361     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    362     if (primitiveValue->getValueID() == CSSValueNone)
    363         return CSSAnimationData::initialName();
    364     return AtomicString(primitiveValue->getStringValue());
    365 }
    366 
    367 EAnimPlayState CSSToStyleMap::mapAnimationPlayState(CSSValue* value)
    368 {
    369     if (value->isInitialValue())
    370         return CSSAnimationData::initialPlayState();
    371     if (toCSSPrimitiveValue(value)->getValueID() == CSSValuePaused)
    372         return AnimPlayStatePaused;
    373     ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueRunning);
    374     return AnimPlayStatePlaying;
    375 }
    376 
    377 CSSTransitionData::TransitionProperty CSSToStyleMap::mapAnimationProperty(CSSValue* value)
    378 {
    379     if (value->isInitialValue())
    380         return CSSTransitionData::initialProperty();
    381     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    382     if (primitiveValue->isString())
    383         return CSSTransitionData::TransitionProperty(primitiveValue->getStringValue());
    384     if (primitiveValue->getValueID() == CSSValueAll)
    385         return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionAll);
    386     if (primitiveValue->getValueID() == CSSValueNone)
    387         return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionNone);
    388     return CSSTransitionData::TransitionProperty(primitiveValue->getPropertyID());
    389 }
    390 
    391 PassRefPtr<TimingFunction> CSSToStyleMap::mapAnimationTimingFunction(CSSValue* value, bool allowStepMiddle)
    392 {
    393     // FIXME: We should probably only call into this function with a valid
    394     // single timing function value which isn't initial or inherit. We can
    395     // currently get into here with initial since the parser expands unset
    396     // properties in shorthands to initial.
    397 
    398     if (value->isPrimitiveValue()) {
    399         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    400         switch (primitiveValue->getValueID()) {
    401         case CSSValueLinear:
    402             return LinearTimingFunction::shared();
    403         case CSSValueEase:
    404             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease);
    405         case CSSValueEaseIn:
    406             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
    407         case CSSValueEaseOut:
    408             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
    409         case CSSValueEaseInOut:
    410             return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut);
    411         case CSSValueStepStart:
    412             return StepsTimingFunction::preset(StepsTimingFunction::Start);
    413         case CSSValueStepMiddle:
    414             if (allowStepMiddle)
    415                 return StepsTimingFunction::preset(StepsTimingFunction::Middle);
    416             return CSSTimingData::initialTimingFunction();
    417         case CSSValueStepEnd:
    418             return StepsTimingFunction::preset(StepsTimingFunction::End);
    419         default:
    420             ASSERT_NOT_REACHED();
    421             return CSSTimingData::initialTimingFunction();
    422         }
    423     }
    424 
    425     if (value->isCubicBezierTimingFunctionValue()) {
    426         CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value);
    427         return CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2());
    428     }
    429 
    430     if (value->isInitialValue())
    431         return CSSTimingData::initialTimingFunction();
    432 
    433     CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value);
    434     if (stepsTimingFunction->stepAtPosition() == StepsTimingFunction::StepAtMiddle && !allowStepMiddle)
    435         return CSSTimingData::initialTimingFunction();
    436     return StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtPosition());
    437 }
    438 
    439 void CSSToStyleMap::mapNinePieceImage(RenderStyle* mutableStyle, CSSPropertyID property, CSSValue* value, NinePieceImage& image)
    440 {
    441     // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
    442     if (!value || !value->isValueList())
    443         return;
    444 
    445     // Retrieve the border image value.
    446     CSSValueList* borderImage = toCSSValueList(value);
    447 
    448     // Set the image (this kicks off the load).
    449     CSSPropertyID imageProperty;
    450     if (property == CSSPropertyWebkitBorderImage)
    451         imageProperty = CSSPropertyBorderImageSource;
    452     else if (property == CSSPropertyWebkitMaskBoxImage)
    453         imageProperty = CSSPropertyWebkitMaskBoxImageSource;
    454     else
    455         imageProperty = property;
    456 
    457     for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
    458         CSSValue* current = borderImage->item(i);
    459 
    460         if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue())
    461             image.setImage(styleImage(imageProperty, current));
    462         else if (current->isBorderImageSliceValue())
    463             mapNinePieceImageSlice(current, image);
    464         else if (current->isValueList()) {
    465             CSSValueList* slashList = toCSSValueList(current);
    466             // Map in the image slices.
    467             if (slashList->item(0) && slashList->item(0)->isBorderImageSliceValue())
    468                 mapNinePieceImageSlice(slashList->item(0), image);
    469 
    470             // Map in the border slices.
    471             if (slashList->item(1))
    472                 image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
    473 
    474             // Map in the outset.
    475             if (slashList->item(2))
    476                 image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
    477         } else if (current->isPrimitiveValue()) {
    478             // Set the appropriate rules for stretch/round/repeat of the slices.
    479             mapNinePieceImageRepeat(current, image);
    480         }
    481     }
    482 
    483     if (property == CSSPropertyWebkitBorderImage) {
    484         // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
    485         // also set the border widths. We don't need to worry about percentages, since we don't even support
    486         // those on real borders yet.
    487         if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed())
    488             mutableStyle->setBorderTopWidth(image.borderSlices().top().length().value());
    489         if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed())
    490             mutableStyle->setBorderRightWidth(image.borderSlices().right().length().value());
    491         if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed())
    492             mutableStyle->setBorderBottomWidth(image.borderSlices().bottom().length().value());
    493         if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed())
    494             mutableStyle->setBorderLeftWidth(image.borderSlices().left().length().value());
    495     }
    496 }
    497 
    498 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) const
    499 {
    500     if (!value || !value->isBorderImageSliceValue())
    501         return;
    502 
    503     // Retrieve the border image value.
    504     CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value);
    505 
    506     // Set up a length box to represent our image slices.
    507     LengthBox box;
    508     Quad* slices = borderImageSlice->slices();
    509     if (slices->top()->isPercentage())
    510         box.m_top = Length(slices->top()->getDoubleValue(), Percent);
    511     else
    512         box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
    513     if (slices->bottom()->isPercentage())
    514         box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
    515     else
    516         box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
    517     if (slices->left()->isPercentage())
    518         box.m_left = Length(slices->left()->getDoubleValue(), Percent);
    519     else
    520         box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
    521     if (slices->right()->isPercentage())
    522         box.m_right = Length(slices->right()->getDoubleValue(), Percent);
    523     else
    524         box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
    525     image.setImageSlices(box);
    526 
    527     // Set our fill mode.
    528     image.setFill(borderImageSlice->m_fill);
    529 }
    530 
    531 static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData)
    532 {
    533     if (value.isNumber())
    534         return value.getDoubleValue();
    535     if (value.isPercentage())
    536         return Length(value.getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
    537     if (value.getValueID() != CSSValueAuto)
    538         return value.computeLength<Length>(conversionData);
    539     return Length(Auto);
    540 }
    541 
    542 BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) const
    543 {
    544     if (!value || !value->isPrimitiveValue())
    545         return BorderImageLengthBox(Length(Auto));
    546 
    547     Quad* slices = toCSSPrimitiveValue(value)->getQuadValue();
    548 
    549     // Set up a border image length box to represent our image slices.
    550     return BorderImageLengthBox(
    551         toBorderImageLength(*slices->top(), cssToLengthConversionData()),
    552         toBorderImageLength(*slices->right(), cssToLengthConversionData()),
    553         toBorderImageLength(*slices->bottom(), cssToLengthConversionData()),
    554         toBorderImageLength(*slices->left(), cssToLengthConversionData()));
    555 }
    556 
    557 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) const
    558 {
    559     if (!value || !value->isPrimitiveValue())
    560         return;
    561 
    562     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    563     Pair* pair = primitiveValue->getPairValue();
    564     if (!pair || !pair->first() || !pair->second())
    565         return;
    566 
    567     CSSValueID firstIdentifier = pair->first()->getValueID();
    568     CSSValueID secondIdentifier = pair->second()->getValueID();
    569 
    570     ENinePieceImageRule horizontalRule;
    571     switch (firstIdentifier) {
    572     case CSSValueStretch:
    573         horizontalRule = StretchImageRule;
    574         break;
    575     case CSSValueRound:
    576         horizontalRule = RoundImageRule;
    577         break;
    578     case CSSValueSpace:
    579         horizontalRule = SpaceImageRule;
    580         break;
    581     default: // CSSValueRepeat
    582         horizontalRule = RepeatImageRule;
    583         break;
    584     }
    585     image.setHorizontalRule(horizontalRule);
    586 
    587     ENinePieceImageRule verticalRule;
    588     switch (secondIdentifier) {
    589     case CSSValueStretch:
    590         verticalRule = StretchImageRule;
    591         break;
    592     case CSSValueRound:
    593         verticalRule = RoundImageRule;
    594         break;
    595     case CSSValueSpace:
    596         verticalRule = SpaceImageRule;
    597         break;
    598     default: // CSSValueRepeat
    599         verticalRule = RepeatImageRule;
    600         break;
    601     }
    602     image.setVerticalRule(verticalRule);
    603 }
    604 
    605 };
    606