• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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 
cssToLengthConversionData() const45 const CSSToLengthConversionData& CSSToStyleMap::cssToLengthConversionData() const
46 {
47     return m_state.cssToLengthConversionData();
48 }
49 
styleImage(CSSPropertyID propertyId,CSSValue * value)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 
mapFillAttachment(CSSPropertyID,FillLayer * layer,CSSValue * value) const55 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 
mapFillClip(CSSPropertyID,FillLayer * layer,CSSValue * value) const81 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 
mapFillComposite(CSSPropertyID,FillLayer * layer,CSSValue * value) const95 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 
mapFillBlendMode(CSSPropertyID,FillLayer * layer,CSSValue * value) const109 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 
mapFillOrigin(CSSPropertyID,FillLayer * layer,CSSValue * value) const123 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 
mapFillImage(CSSPropertyID property,FillLayer * layer,CSSValue * value)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 
mapFillRepeatX(CSSPropertyID,FillLayer * layer,CSSValue * value) const148 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 
mapFillRepeatY(CSSPropertyID,FillLayer * layer,CSSValue * value) const162 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 
mapFillSize(CSSPropertyID,FillLayer * layer,CSSValue * value) const176 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 
mapFillXPosition(CSSPropertyID propertyID,FillLayer * layer,CSSValue * value) const218 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 
mapFillYPosition(CSSPropertyID propertyID,FillLayer * layer,CSSValue * value) const242 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 
mapFillMaskSourceType(CSSPropertyID,FillLayer * layer,CSSValue * value)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 
mapAnimationDelay(CSSValue * value)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 
mapAnimationDirection(CSSValue * value)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 
mapAnimationDuration(CSSValue * value)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 
mapAnimationFillMode(CSSValue * value)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 
mapAnimationIterationCount(CSSValue * value)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 
mapAnimationName(CSSValue * value)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 
mapAnimationPlayState(CSSValue * value)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 
mapAnimationProperty(CSSValue * value)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 
mapAnimationTimingFunction(CSSValue * value,bool allowStepMiddle)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 
mapNinePieceImage(RenderStyle * mutableStyle,CSSPropertyID property,CSSValue * value,NinePieceImage & image)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 
mapNinePieceImageSlice(CSSValue * value,NinePieceImage & image) const498 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 
toBorderImageLength(CSSPrimitiveValue & value,const CSSToLengthConversionData & conversionData)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 
mapNinePieceImageQuad(CSSValue * value) const542 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 
mapNinePieceImageRepeat(CSSValue * value,NinePieceImage & image) const557 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