| /* |
| * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
| * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
| * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. |
| * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
| * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) |
| * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "config.h" |
| #include "core/css/resolver/CSSToStyleMap.h" |
| |
| #include "core/CSSValueKeywords.h" |
| #include "core/animation/css/CSSAnimationData.h" |
| #include "core/css/CSSBorderImageSliceValue.h" |
| #include "core/css/CSSCustomIdentValue.h" |
| #include "core/css/CSSPrimitiveValue.h" |
| #include "core/css/CSSPrimitiveValueMappings.h" |
| #include "core/css/CSSQuadValue.h" |
| #include "core/css/CSSTimingFunctionValue.h" |
| #include "core/css/CSSValuePair.h" |
| #include "core/css/resolver/StyleBuilderConverter.h" |
| #include "core/css/resolver/StyleResolverState.h" |
| #include "core/style/BorderImageLengthBox.h" |
| #include "core/style/FillLayer.h" |
| |
| namespace blink { |
| |
| void CSSToStyleMap::mapFillAttachment(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setAttachment(FillLayer::initialFillAttachment(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| switch (primitiveValue.getValueID()) { |
| case CSSValueFixed: |
| layer->setAttachment(FixedBackgroundAttachment); |
| break; |
| case CSSValueScroll: |
| layer->setAttachment(ScrollBackgroundAttachment); |
| break; |
| case CSSValueLocal: |
| layer->setAttachment(LocalBackgroundAttachment); |
| break; |
| default: |
| return; |
| } |
| } |
| |
| void CSSToStyleMap::mapFillClip(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setClip(FillLayer::initialFillClip(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setClip(primitiveValue.convertTo<EFillBox>()); |
| } |
| |
| void CSSToStyleMap::mapFillComposite(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setComposite(FillLayer::initialFillComposite(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setComposite(primitiveValue.convertTo<CompositeOperator>()); |
| } |
| |
| void CSSToStyleMap::mapFillBlendMode(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setBlendMode(FillLayer::initialFillBlendMode(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setBlendMode(primitiveValue.convertTo<WebBlendMode>()); |
| } |
| |
| void CSSToStyleMap::mapFillOrigin(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setOrigin(FillLayer::initialFillOrigin(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setOrigin(primitiveValue.convertTo<EFillBox>()); |
| } |
| |
| |
| void CSSToStyleMap::mapFillImage(StyleResolverState& state, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setImage(FillLayer::initialFillImage(layer->type())); |
| return; |
| } |
| |
| CSSPropertyID property = layer->type() == BackgroundFillLayer ? CSSPropertyBackgroundImage : CSSPropertyWebkitMaskImage; |
| layer->setImage(state.styleImage(property, value)); |
| } |
| |
| void CSSToStyleMap::mapFillRepeatX(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setRepeatX(primitiveValue.convertTo<EFillRepeat>()); |
| } |
| |
| void CSSToStyleMap::mapFillRepeatY(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| layer->setRepeatY(primitiveValue.convertTo<EFillRepeat>()); |
| } |
| |
| void CSSToStyleMap::mapFillSize(StyleResolverState& state, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setSizeType(FillLayer::initialFillSizeType(layer->type())); |
| layer->setSizeLength(FillLayer::initialFillSizeLength(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue() && !value.isValuePair()) |
| return; |
| |
| if (value.isPrimitiveValue() && toCSSPrimitiveValue(value).getValueID() == CSSValueContain) |
| layer->setSizeType(Contain); |
| else if (value.isPrimitiveValue() && toCSSPrimitiveValue(value).getValueID() == CSSValueCover) |
| layer->setSizeType(Cover); |
| else |
| layer->setSizeType(SizeLength); |
| |
| LengthSize b = FillLayer::initialFillSizeLength(layer->type()); |
| |
| if (value.isPrimitiveValue() && (toCSSPrimitiveValue(value).getValueID() == CSSValueContain || toCSSPrimitiveValue(value).getValueID() == CSSValueCover)) { |
| layer->setSizeLength(b); |
| return; |
| } |
| |
| Length firstLength; |
| Length secondLength; |
| |
| if (value.isValuePair()) { |
| const CSSValuePair& pair = toCSSValuePair(value); |
| firstLength = StyleBuilderConverter::convertLengthOrAuto(state, pair.first()); |
| secondLength = StyleBuilderConverter::convertLengthOrAuto(state, pair.second()); |
| } else { |
| ASSERT(value.isPrimitiveValue()); |
| firstLength = StyleBuilderConverter::convertLengthOrAuto(state, value); |
| secondLength = Length(); |
| } |
| |
| b.setWidth(firstLength); |
| b.setHeight(secondLength); |
| layer->setSizeLength(b); |
| } |
| |
| void CSSToStyleMap::mapFillXPosition(StyleResolverState& state, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setXPosition(FillLayer::initialFillXPosition(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue() && !value.isValuePair()) |
| return; |
| |
| Length length; |
| if (value.isValuePair()) |
| length = toCSSPrimitiveValue(toCSSValuePair(value).second()).convertToLength(state.cssToLengthConversionData()); |
| else |
| length = toCSSPrimitiveValue(value).convertToLength(state.cssToLengthConversionData()); |
| |
| layer->setXPosition(length); |
| if (value.isValuePair()) |
| layer->setBackgroundXOrigin(toCSSPrimitiveValue(toCSSValuePair(value).first()).convertTo<BackgroundEdgeOrigin>()); |
| } |
| |
| void CSSToStyleMap::mapFillYPosition(StyleResolverState& state, FillLayer* layer, const CSSValue& value) |
| { |
| if (value.isInitialValue()) { |
| layer->setYPosition(FillLayer::initialFillYPosition(layer->type())); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue() && !value.isValuePair()) |
| return; |
| |
| Length length; |
| if (value.isValuePair()) |
| length = toCSSPrimitiveValue(toCSSValuePair(value).second()).convertToLength(state.cssToLengthConversionData()); |
| else |
| length = toCSSPrimitiveValue(value).convertToLength(state.cssToLengthConversionData()); |
| |
| layer->setYPosition(length); |
| if (value.isValuePair()) |
| layer->setBackgroundYOrigin(toCSSPrimitiveValue(toCSSValuePair(value).first()).convertTo<BackgroundEdgeOrigin>()); |
| } |
| |
| void CSSToStyleMap::mapFillMaskSourceType(StyleResolverState&, FillLayer* layer, const CSSValue& value) |
| { |
| EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer->type()); |
| if (value.isInitialValue()) { |
| layer->setMaskSourceType(type); |
| return; |
| } |
| |
| if (!value.isPrimitiveValue()) |
| return; |
| |
| switch (toCSSPrimitiveValue(value).getValueID()) { |
| case CSSValueAlpha: |
| type = MaskAlpha; |
| break; |
| case CSSValueLuminance: |
| type = MaskLuminance; |
| break; |
| case CSSValueAuto: |
| break; |
| default: |
| ASSERT_NOT_REACHED(); |
| } |
| |
| layer->setMaskSourceType(type); |
| } |
| |
| double CSSToStyleMap::mapAnimationDelay(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSTimingData::initialDelay(); |
| return toCSSPrimitiveValue(value).computeSeconds(); |
| } |
| |
| Timing::PlaybackDirection CSSToStyleMap::mapAnimationDirection(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSAnimationData::initialDirection(); |
| |
| switch (toCSSPrimitiveValue(value).getValueID()) { |
| case CSSValueNormal: |
| return Timing::PlaybackDirectionNormal; |
| case CSSValueAlternate: |
| return Timing::PlaybackDirectionAlternate; |
| case CSSValueReverse: |
| return Timing::PlaybackDirectionReverse; |
| case CSSValueAlternateReverse: |
| return Timing::PlaybackDirectionAlternateReverse; |
| default: |
| ASSERT_NOT_REACHED(); |
| return CSSAnimationData::initialDirection(); |
| } |
| } |
| |
| double CSSToStyleMap::mapAnimationDuration(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSTimingData::initialDuration(); |
| return toCSSPrimitiveValue(value).computeSeconds(); |
| } |
| |
| Timing::FillMode CSSToStyleMap::mapAnimationFillMode(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSAnimationData::initialFillMode(); |
| |
| switch (toCSSPrimitiveValue(value).getValueID()) { |
| case CSSValueNone: |
| return Timing::FillModeNone; |
| case CSSValueForwards: |
| return Timing::FillModeForwards; |
| case CSSValueBackwards: |
| return Timing::FillModeBackwards; |
| case CSSValueBoth: |
| return Timing::FillModeBoth; |
| default: |
| ASSERT_NOT_REACHED(); |
| return CSSAnimationData::initialFillMode(); |
| } |
| } |
| |
| double CSSToStyleMap::mapAnimationIterationCount(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSAnimationData::initialIterationCount(); |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| if (primitiveValue.getValueID() == CSSValueInfinite) |
| return std::numeric_limits<double>::infinity(); |
| return primitiveValue.getFloatValue(); |
| } |
| |
| AtomicString CSSToStyleMap::mapAnimationName(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSAnimationData::initialName(); |
| if (value.isCustomIdentValue()) |
| return AtomicString(toCSSCustomIdentValue(value).value()); |
| ASSERT(toCSSPrimitiveValue(value).getValueID() == CSSValueNone); |
| return CSSAnimationData::initialName(); |
| } |
| |
| EAnimPlayState CSSToStyleMap::mapAnimationPlayState(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSAnimationData::initialPlayState(); |
| if (toCSSPrimitiveValue(value).getValueID() == CSSValuePaused) |
| return AnimPlayStatePaused; |
| ASSERT(toCSSPrimitiveValue(value).getValueID() == CSSValueRunning); |
| return AnimPlayStatePlaying; |
| } |
| |
| CSSTransitionData::TransitionProperty CSSToStyleMap::mapAnimationProperty(const CSSValue& value) |
| { |
| if (value.isInitialValue()) |
| return CSSTransitionData::initialProperty(); |
| if (value.isCustomIdentValue()) { |
| const CSSCustomIdentValue& customIdentValue = toCSSCustomIdentValue(value); |
| if (customIdentValue.isKnownPropertyID()) |
| return CSSTransitionData::TransitionProperty(customIdentValue.valueAsPropertyID()); |
| return CSSTransitionData::TransitionProperty(customIdentValue.value()); |
| } |
| ASSERT(toCSSPrimitiveValue(value).getValueID() == CSSValueNone); |
| return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionNone); |
| } |
| |
| PassRefPtr<TimingFunction> CSSToStyleMap::mapAnimationTimingFunction(const CSSValue& value, bool allowStepMiddle) |
| { |
| // FIXME: We should probably only call into this function with a valid |
| // single timing function value which isn't initial or inherit. We can |
| // currently get into here with initial since the parser expands unset |
| // properties in shorthands to initial. |
| |
| if (value.isPrimitiveValue()) { |
| const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value); |
| switch (primitiveValue.getValueID()) { |
| case CSSValueLinear: |
| return LinearTimingFunction::shared(); |
| case CSSValueEase: |
| return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease); |
| case CSSValueEaseIn: |
| return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn); |
| case CSSValueEaseOut: |
| return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut); |
| case CSSValueEaseInOut: |
| return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut); |
| case CSSValueStepStart: |
| return StepsTimingFunction::preset(StepsTimingFunction::Start); |
| case CSSValueStepMiddle: |
| if (allowStepMiddle) |
| return StepsTimingFunction::preset(StepsTimingFunction::Middle); |
| return CSSTimingData::initialTimingFunction(); |
| case CSSValueStepEnd: |
| return StepsTimingFunction::preset(StepsTimingFunction::End); |
| default: |
| ASSERT_NOT_REACHED(); |
| return CSSTimingData::initialTimingFunction(); |
| } |
| } |
| |
| if (value.isCubicBezierTimingFunctionValue()) { |
| const CSSCubicBezierTimingFunctionValue& cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value); |
| return CubicBezierTimingFunction::create(cubicTimingFunction.x1(), cubicTimingFunction.y1(), cubicTimingFunction.x2(), cubicTimingFunction.y2()); |
| } |
| |
| if (value.isInitialValue()) |
| return CSSTimingData::initialTimingFunction(); |
| |
| const CSSStepsTimingFunctionValue& stepsTimingFunction = toCSSStepsTimingFunctionValue(value); |
| if (stepsTimingFunction.stepAtPosition() == StepsTimingFunction::Middle && !allowStepMiddle) |
| return CSSTimingData::initialTimingFunction(); |
| return StepsTimingFunction::create(stepsTimingFunction.numberOfSteps(), stepsTimingFunction.stepAtPosition()); |
| } |
| |
| void CSSToStyleMap::mapNinePieceImage(StyleResolverState& state, CSSPropertyID property, const CSSValue& value, NinePieceImage& image) |
| { |
| // If we're not a value list, then we are "none" and don't need to alter the empty image at all. |
| if (!value.isValueList()) |
| return; |
| |
| // Retrieve the border image value. |
| const CSSValueList& borderImage = toCSSValueList(value); |
| |
| // Set the image (this kicks off the load). |
| CSSPropertyID imageProperty; |
| if (property == CSSPropertyWebkitBorderImage) |
| imageProperty = CSSPropertyBorderImageSource; |
| else if (property == CSSPropertyWebkitMaskBoxImage) |
| imageProperty = CSSPropertyWebkitMaskBoxImageSource; |
| else |
| imageProperty = property; |
| |
| for (unsigned i = 0 ; i < borderImage.length() ; ++i) { |
| const CSSValue& current = *borderImage.item(i); |
| |
| if (current.isImageValue() || current.isImageGeneratorValue() || current.isImageSetValue()) { |
| image.setImage(state.styleImage(imageProperty, current)); |
| } else if (current.isBorderImageSliceValue()) { |
| mapNinePieceImageSlice(state, current, image); |
| } else if (current.isValueList()) { |
| const CSSValueList& slashList = toCSSValueList(current); |
| size_t length = slashList.length(); |
| // Map in the image slices. |
| if (length && slashList.item(0)->isBorderImageSliceValue()) |
| mapNinePieceImageSlice(state, *slashList.item(0), image); |
| |
| // Map in the border slices. |
| if (length > 1) |
| image.setBorderSlices(mapNinePieceImageQuad(state, *slashList.item(1))); |
| |
| // Map in the outset. |
| if (length > 2) |
| image.setOutset(mapNinePieceImageQuad(state, *slashList.item(2))); |
| } else if (current.isPrimitiveValue() || current.isValuePair()) { |
| // Set the appropriate rules for stretch/round/repeat of the slices. |
| mapNinePieceImageRepeat(state, current, image); |
| } |
| } |
| |
| if (property == CSSPropertyWebkitBorderImage) { |
| // We have to preserve the legacy behavior of -webkit-border-image and make the border slices |
| // also set the border widths. We don't need to worry about percentages, since we don't even support |
| // those on real borders yet. |
| if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed()) |
| state.style()->setBorderTopWidth(image.borderSlices().top().length().value()); |
| if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed()) |
| state.style()->setBorderRightWidth(image.borderSlices().right().length().value()); |
| if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed()) |
| state.style()->setBorderBottomWidth(image.borderSlices().bottom().length().value()); |
| if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed()) |
| state.style()->setBorderLeftWidth(image.borderSlices().left().length().value()); |
| } |
| } |
| |
| void CSSToStyleMap::mapNinePieceImageSlice(StyleResolverState&, const CSSValue& value, NinePieceImage& image) |
| { |
| if (!value.isBorderImageSliceValue()) |
| return; |
| |
| // Retrieve the border image value. |
| const CSSBorderImageSliceValue& borderImageSlice = toCSSBorderImageSliceValue(value); |
| |
| // Set up a length box to represent our image slices. |
| LengthBox box; |
| CSSQuadValue* slices = borderImageSlice.slices(); |
| if (slices->top()->isPercentage()) |
| box.m_top = Length(slices->top()->getDoubleValue(), Percent); |
| else |
| box.m_top = Length(slices->top()->getIntValue(), Fixed); |
| if (slices->bottom()->isPercentage()) |
| box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent); |
| else |
| box.m_bottom = Length(slices->bottom()->getIntValue(), Fixed); |
| if (slices->left()->isPercentage()) |
| box.m_left = Length(slices->left()->getDoubleValue(), Percent); |
| else |
| box.m_left = Length(slices->left()->getIntValue(), Fixed); |
| if (slices->right()->isPercentage()) |
| box.m_right = Length(slices->right()->getDoubleValue(), Percent); |
| else |
| box.m_right = Length(slices->right()->getIntValue(), Fixed); |
| image.setImageSlices(box); |
| |
| // Set our fill mode. |
| image.setFill(borderImageSlice.m_fill); |
| } |
| |
| static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData) |
| { |
| if (value.isNumber()) |
| return value.getDoubleValue(); |
| if (value.isPercentage()) |
| return Length(value.getDoubleValue(), Percent); |
| if (value.getValueID() != CSSValueAuto) |
| return value.computeLength<Length>(conversionData); |
| return Length(Auto); |
| } |
| |
| BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(StyleResolverState& state, const CSSValue& value) |
| { |
| if (!value.isQuadValue()) |
| return BorderImageLengthBox(Length(Auto)); |
| |
| const CSSQuadValue& slices = toCSSQuadValue(value); |
| |
| // Set up a border image length box to represent our image slices. |
| return BorderImageLengthBox( |
| toBorderImageLength(*slices.top(), state.cssToLengthConversionData()), |
| toBorderImageLength(*slices.right(), state.cssToLengthConversionData()), |
| toBorderImageLength(*slices.bottom(), state.cssToLengthConversionData()), |
| toBorderImageLength(*slices.left(), state.cssToLengthConversionData())); |
| } |
| |
| void CSSToStyleMap::mapNinePieceImageRepeat(StyleResolverState&, const CSSValue& value, NinePieceImage& image) |
| { |
| if (!value.isValuePair()) |
| return; |
| |
| const CSSValuePair& pair = toCSSValuePair(value); |
| CSSValueID firstIdentifier = toCSSPrimitiveValue(pair.first()).getValueID(); |
| CSSValueID secondIdentifier = toCSSPrimitiveValue(pair.second()).getValueID(); |
| |
| ENinePieceImageRule horizontalRule; |
| switch (firstIdentifier) { |
| case CSSValueStretch: |
| horizontalRule = StretchImageRule; |
| break; |
| case CSSValueRound: |
| horizontalRule = RoundImageRule; |
| break; |
| case CSSValueSpace: |
| horizontalRule = SpaceImageRule; |
| break; |
| default: // CSSValueRepeat |
| horizontalRule = RepeatImageRule; |
| break; |
| } |
| image.setHorizontalRule(horizontalRule); |
| |
| ENinePieceImageRule verticalRule; |
| switch (secondIdentifier) { |
| case CSSValueStretch: |
| verticalRule = StretchImageRule; |
| break; |
| case CSSValueRound: |
| verticalRule = RoundImageRule; |
| break; |
| case CSSValueSpace: |
| verticalRule = SpaceImageRule; |
| break; |
| default: // CSSValueRepeat |
| verticalRule = RepeatImageRule; |
| break; |
| } |
| image.setVerticalRule(verticalRule); |
| } |
| |
| }; |