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 blink {
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(FillLayer * layer,CSSValue * value) const55 void CSSToStyleMap::mapFillAttachment(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(FillLayer * layer,CSSValue * value) const81 void CSSToStyleMap::mapFillClip(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(FillLayer * layer,CSSValue * value) const95 void CSSToStyleMap::mapFillComposite(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(FillLayer * layer,CSSValue * value) const109 void CSSToStyleMap::mapFillBlendMode(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(FillLayer * layer,CSSValue * value) const123 void CSSToStyleMap::mapFillOrigin(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(FillLayer * layer,CSSValue * value)138 void CSSToStyleMap::mapFillImage(FillLayer* layer, CSSValue* value)
139 {
140 if (value->isInitialValue()) {
141 layer->setImage(FillLayer::initialFillImage(layer->type()));
142 return;
143 }
144
145 CSSPropertyID property = layer->type() == BackgroundFillLayer ? CSSPropertyBackgroundImage : CSSPropertyWebkitMaskImage;
146 layer->setImage(styleImage(property, value));
147 }
148
mapFillRepeatX(FillLayer * layer,CSSValue * value) const149 void CSSToStyleMap::mapFillRepeatX(FillLayer* layer, CSSValue* value) const
150 {
151 if (value->isInitialValue()) {
152 layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type()));
153 return;
154 }
155
156 if (!value->isPrimitiveValue())
157 return;
158
159 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
160 layer->setRepeatX(*primitiveValue);
161 }
162
mapFillRepeatY(FillLayer * layer,CSSValue * value) const163 void CSSToStyleMap::mapFillRepeatY(FillLayer* layer, CSSValue* value) const
164 {
165 if (value->isInitialValue()) {
166 layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type()));
167 return;
168 }
169
170 if (!value->isPrimitiveValue())
171 return;
172
173 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
174 layer->setRepeatY(*primitiveValue);
175 }
176
mapFillSize(FillLayer * layer,CSSValue * value) const177 void CSSToStyleMap::mapFillSize(FillLayer* layer, CSSValue* value) const
178 {
179 if (value->isInitialValue()) {
180 layer->setSizeType(FillLayer::initialFillSizeType(layer->type()));
181 layer->setSizeLength(FillLayer::initialFillSizeLength(layer->type()));
182 return;
183 }
184
185 if (!value->isPrimitiveValue())
186 return;
187
188 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
189 if (primitiveValue->getValueID() == CSSValueContain)
190 layer->setSizeType(Contain);
191 else if (primitiveValue->getValueID() == CSSValueCover)
192 layer->setSizeType(Cover);
193 else
194 layer->setSizeType(SizeLength);
195
196 LengthSize b = FillLayer::initialFillSizeLength(layer->type());
197
198 if (primitiveValue->getValueID() == CSSValueContain || primitiveValue->getValueID() == CSSValueCover) {
199 layer->setSizeLength(b);
200 return;
201 }
202
203 Length firstLength;
204 Length secondLength;
205
206 if (Pair* pair = primitiveValue->getPairValue()) {
207 firstLength = pair->first()->convertToLength<AnyConversion>(cssToLengthConversionData());
208 secondLength = pair->second()->convertToLength<AnyConversion>(cssToLengthConversionData());
209 } else {
210 firstLength = primitiveValue->convertToLength<AnyConversion>(cssToLengthConversionData());
211 secondLength = Length();
212 }
213
214 b.setWidth(firstLength);
215 b.setHeight(secondLength);
216 layer->setSizeLength(b);
217 }
218
mapFillXPosition(FillLayer * layer,CSSValue * value) const219 void CSSToStyleMap::mapFillXPosition(FillLayer* layer, CSSValue* value) const
220 {
221 if (value->isInitialValue()) {
222 layer->setXPosition(FillLayer::initialFillXPosition(layer->type()));
223 return;
224 }
225
226 if (!value->isPrimitiveValue())
227 return;
228
229 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
230 Pair* pair = primitiveValue->getPairValue();
231 if (pair)
232 primitiveValue = pair->second();
233
234 Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
235
236 layer->setXPosition(length);
237 if (pair)
238 layer->setBackgroundXOrigin(*(pair->first()));
239 }
240
mapFillYPosition(FillLayer * layer,CSSValue * value) const241 void CSSToStyleMap::mapFillYPosition(FillLayer* layer, CSSValue* value) const
242 {
243 if (value->isInitialValue()) {
244 layer->setYPosition(FillLayer::initialFillYPosition(layer->type()));
245 return;
246 }
247
248 if (!value->isPrimitiveValue())
249 return;
250
251 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
252 Pair* pair = primitiveValue->getPairValue();
253 if (pair)
254 primitiveValue = pair->second();
255
256 Length length = primitiveValue->convertToLength<FixedConversion | PercentConversion>(cssToLengthConversionData());
257
258 layer->setYPosition(length);
259 if (pair)
260 layer->setBackgroundYOrigin(*(pair->first()));
261 }
262
mapFillMaskSourceType(FillLayer * layer,CSSValue * value) const263 void CSSToStyleMap::mapFillMaskSourceType(FillLayer* layer, CSSValue* value) const
264 {
265 EMaskSourceType type = FillLayer::initialFillMaskSourceType(layer->type());
266 if (value->isInitialValue()) {
267 layer->setMaskSourceType(type);
268 return;
269 }
270
271 if (!value->isPrimitiveValue())
272 return;
273
274 switch (toCSSPrimitiveValue(value)->getValueID()) {
275 case CSSValueAlpha:
276 type = MaskAlpha;
277 break;
278 case CSSValueLuminance:
279 type = MaskLuminance;
280 break;
281 case CSSValueAuto:
282 break;
283 default:
284 ASSERT_NOT_REACHED();
285 }
286
287 layer->setMaskSourceType(type);
288 }
289
mapAnimationDelay(CSSValue * value)290 double CSSToStyleMap::mapAnimationDelay(CSSValue* value)
291 {
292 if (value->isInitialValue())
293 return CSSTimingData::initialDelay();
294 return toCSSPrimitiveValue(value)->computeSeconds();
295 }
296
mapAnimationDirection(CSSValue * value)297 Timing::PlaybackDirection CSSToStyleMap::mapAnimationDirection(CSSValue* value)
298 {
299 if (value->isInitialValue())
300 return CSSAnimationData::initialDirection();
301
302 switch (toCSSPrimitiveValue(value)->getValueID()) {
303 case CSSValueNormal:
304 return Timing::PlaybackDirectionNormal;
305 case CSSValueAlternate:
306 return Timing::PlaybackDirectionAlternate;
307 case CSSValueReverse:
308 return Timing::PlaybackDirectionReverse;
309 case CSSValueAlternateReverse:
310 return Timing::PlaybackDirectionAlternateReverse;
311 default:
312 ASSERT_NOT_REACHED();
313 return CSSAnimationData::initialDirection();
314 }
315 }
316
mapAnimationDuration(CSSValue * value)317 double CSSToStyleMap::mapAnimationDuration(CSSValue* value)
318 {
319 if (value->isInitialValue())
320 return CSSTimingData::initialDuration();
321 return toCSSPrimitiveValue(value)->computeSeconds();
322 }
323
mapAnimationFillMode(CSSValue * value)324 Timing::FillMode CSSToStyleMap::mapAnimationFillMode(CSSValue* value)
325 {
326 if (value->isInitialValue())
327 return CSSAnimationData::initialFillMode();
328
329 switch (toCSSPrimitiveValue(value)->getValueID()) {
330 case CSSValueNone:
331 return Timing::FillModeNone;
332 case CSSValueForwards:
333 return Timing::FillModeForwards;
334 case CSSValueBackwards:
335 return Timing::FillModeBackwards;
336 case CSSValueBoth:
337 return Timing::FillModeBoth;
338 default:
339 ASSERT_NOT_REACHED();
340 return CSSAnimationData::initialFillMode();
341 }
342 }
343
mapAnimationIterationCount(CSSValue * value)344 double CSSToStyleMap::mapAnimationIterationCount(CSSValue* value)
345 {
346 if (value->isInitialValue())
347 return CSSAnimationData::initialIterationCount();
348 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
349 if (primitiveValue->getValueID() == CSSValueInfinite)
350 return std::numeric_limits<double>::infinity();
351 return primitiveValue->getFloatValue();
352 }
353
mapAnimationName(CSSValue * value)354 AtomicString CSSToStyleMap::mapAnimationName(CSSValue* value)
355 {
356 if (value->isInitialValue())
357 return CSSAnimationData::initialName();
358 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
359 if (primitiveValue->getValueID() == CSSValueNone)
360 return CSSAnimationData::initialName();
361 return AtomicString(primitiveValue->getStringValue());
362 }
363
mapAnimationPlayState(CSSValue * value)364 EAnimPlayState CSSToStyleMap::mapAnimationPlayState(CSSValue* value)
365 {
366 if (value->isInitialValue())
367 return CSSAnimationData::initialPlayState();
368 if (toCSSPrimitiveValue(value)->getValueID() == CSSValuePaused)
369 return AnimPlayStatePaused;
370 ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueRunning);
371 return AnimPlayStatePlaying;
372 }
373
mapAnimationProperty(CSSValue * value)374 CSSTransitionData::TransitionProperty CSSToStyleMap::mapAnimationProperty(CSSValue* value)
375 {
376 if (value->isInitialValue())
377 return CSSTransitionData::initialProperty();
378 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
379 if (primitiveValue->isString())
380 return CSSTransitionData::TransitionProperty(primitiveValue->getStringValue());
381 if (primitiveValue->getValueID() == CSSValueAll)
382 return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionAll);
383 if (primitiveValue->getValueID() == CSSValueNone)
384 return CSSTransitionData::TransitionProperty(CSSTransitionData::TransitionNone);
385 return CSSTransitionData::TransitionProperty(primitiveValue->getPropertyID());
386 }
387
mapAnimationTimingFunction(CSSValue * value,bool allowStepMiddle)388 PassRefPtr<TimingFunction> CSSToStyleMap::mapAnimationTimingFunction(CSSValue* value, bool allowStepMiddle)
389 {
390 // FIXME: We should probably only call into this function with a valid
391 // single timing function value which isn't initial or inherit. We can
392 // currently get into here with initial since the parser expands unset
393 // properties in shorthands to initial.
394
395 if (value->isPrimitiveValue()) {
396 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
397 switch (primitiveValue->getValueID()) {
398 case CSSValueLinear:
399 return LinearTimingFunction::shared();
400 case CSSValueEase:
401 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease);
402 case CSSValueEaseIn:
403 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
404 case CSSValueEaseOut:
405 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
406 case CSSValueEaseInOut:
407 return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut);
408 case CSSValueStepStart:
409 return StepsTimingFunction::preset(StepsTimingFunction::Start);
410 case CSSValueStepMiddle:
411 if (allowStepMiddle)
412 return StepsTimingFunction::preset(StepsTimingFunction::Middle);
413 return CSSTimingData::initialTimingFunction();
414 case CSSValueStepEnd:
415 return StepsTimingFunction::preset(StepsTimingFunction::End);
416 default:
417 ASSERT_NOT_REACHED();
418 return CSSTimingData::initialTimingFunction();
419 }
420 }
421
422 if (value->isCubicBezierTimingFunctionValue()) {
423 CSSCubicBezierTimingFunctionValue* cubicTimingFunction = toCSSCubicBezierTimingFunctionValue(value);
424 return CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2());
425 }
426
427 if (value->isInitialValue())
428 return CSSTimingData::initialTimingFunction();
429
430 CSSStepsTimingFunctionValue* stepsTimingFunction = toCSSStepsTimingFunctionValue(value);
431 if (stepsTimingFunction->stepAtPosition() == StepsTimingFunction::Middle && !allowStepMiddle)
432 return CSSTimingData::initialTimingFunction();
433 return StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtPosition());
434 }
435
mapNinePieceImage(RenderStyle * mutableStyle,CSSPropertyID property,CSSValue * value,NinePieceImage & image)436 void CSSToStyleMap::mapNinePieceImage(RenderStyle* mutableStyle, CSSPropertyID property, CSSValue* value, NinePieceImage& image)
437 {
438 // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
439 if (!value || !value->isValueList())
440 return;
441
442 // Retrieve the border image value.
443 CSSValueList* borderImage = toCSSValueList(value);
444
445 // Set the image (this kicks off the load).
446 CSSPropertyID imageProperty;
447 if (property == CSSPropertyWebkitBorderImage)
448 imageProperty = CSSPropertyBorderImageSource;
449 else if (property == CSSPropertyWebkitMaskBoxImage)
450 imageProperty = CSSPropertyWebkitMaskBoxImageSource;
451 else
452 imageProperty = property;
453
454 for (unsigned i = 0 ; i < borderImage->length() ; ++i) {
455 CSSValue* current = borderImage->item(i);
456
457 if (current->isImageValue() || current->isImageGeneratorValue() || current->isImageSetValue())
458 image.setImage(styleImage(imageProperty, current));
459 else if (current->isBorderImageSliceValue())
460 mapNinePieceImageSlice(current, image);
461 else if (current->isValueList()) {
462 CSSValueList* slashList = toCSSValueList(current);
463 size_t length = slashList->length();
464 // Map in the image slices.
465 if (length && slashList->item(0)->isBorderImageSliceValue())
466 mapNinePieceImageSlice(slashList->item(0), image);
467
468 // Map in the border slices.
469 if (length > 1)
470 image.setBorderSlices(mapNinePieceImageQuad(slashList->item(1)));
471
472 // Map in the outset.
473 if (length > 2)
474 image.setOutset(mapNinePieceImageQuad(slashList->item(2)));
475 } else if (current->isPrimitiveValue()) {
476 // Set the appropriate rules for stretch/round/repeat of the slices.
477 mapNinePieceImageRepeat(current, image);
478 }
479 }
480
481 if (property == CSSPropertyWebkitBorderImage) {
482 // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
483 // also set the border widths. We don't need to worry about percentages, since we don't even support
484 // those on real borders yet.
485 if (image.borderSlices().top().isLength() && image.borderSlices().top().length().isFixed())
486 mutableStyle->setBorderTopWidth(image.borderSlices().top().length().value());
487 if (image.borderSlices().right().isLength() && image.borderSlices().right().length().isFixed())
488 mutableStyle->setBorderRightWidth(image.borderSlices().right().length().value());
489 if (image.borderSlices().bottom().isLength() && image.borderSlices().bottom().length().isFixed())
490 mutableStyle->setBorderBottomWidth(image.borderSlices().bottom().length().value());
491 if (image.borderSlices().left().isLength() && image.borderSlices().left().length().isFixed())
492 mutableStyle->setBorderLeftWidth(image.borderSlices().left().length().value());
493 }
494 }
495
mapNinePieceImageSlice(CSSValue * value,NinePieceImage & image) const496 void CSSToStyleMap::mapNinePieceImageSlice(CSSValue* value, NinePieceImage& image) const
497 {
498 if (!value || !value->isBorderImageSliceValue())
499 return;
500
501 // Retrieve the border image value.
502 CSSBorderImageSliceValue* borderImageSlice = toCSSBorderImageSliceValue(value);
503
504 // Set up a length box to represent our image slices.
505 LengthBox box;
506 Quad* slices = borderImageSlice->slices();
507 if (slices->top()->isPercentage())
508 box.m_top = Length(slices->top()->getDoubleValue(), Percent);
509 else
510 box.m_top = Length(slices->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
511 if (slices->bottom()->isPercentage())
512 box.m_bottom = Length(slices->bottom()->getDoubleValue(), Percent);
513 else
514 box.m_bottom = Length((int)slices->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
515 if (slices->left()->isPercentage())
516 box.m_left = Length(slices->left()->getDoubleValue(), Percent);
517 else
518 box.m_left = Length(slices->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
519 if (slices->right()->isPercentage())
520 box.m_right = Length(slices->right()->getDoubleValue(), Percent);
521 else
522 box.m_right = Length(slices->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
523 image.setImageSlices(box);
524
525 // Set our fill mode.
526 image.setFill(borderImageSlice->m_fill);
527 }
528
toBorderImageLength(CSSPrimitiveValue & value,const CSSToLengthConversionData & conversionData)529 static BorderImageLength toBorderImageLength(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData)
530 {
531 if (value.isNumber())
532 return value.getDoubleValue();
533 if (value.isPercentage())
534 return Length(value.getDoubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
535 if (value.getValueID() != CSSValueAuto)
536 return value.computeLength<Length>(conversionData);
537 return Length(Auto);
538 }
539
mapNinePieceImageQuad(CSSValue * value) const540 BorderImageLengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue* value) const
541 {
542 if (!value || !value->isPrimitiveValue())
543 return BorderImageLengthBox(Length(Auto));
544
545 Quad* slices = toCSSPrimitiveValue(value)->getQuadValue();
546
547 // Set up a border image length box to represent our image slices.
548 return BorderImageLengthBox(
549 toBorderImageLength(*slices->top(), cssToLengthConversionData()),
550 toBorderImageLength(*slices->right(), cssToLengthConversionData()),
551 toBorderImageLength(*slices->bottom(), cssToLengthConversionData()),
552 toBorderImageLength(*slices->left(), cssToLengthConversionData()));
553 }
554
mapNinePieceImageRepeat(CSSValue * value,NinePieceImage & image) const555 void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue* value, NinePieceImage& image) const
556 {
557 if (!value || !value->isPrimitiveValue())
558 return;
559
560 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
561 Pair* pair = primitiveValue->getPairValue();
562 if (!pair || !pair->first() || !pair->second())
563 return;
564
565 CSSValueID firstIdentifier = pair->first()->getValueID();
566 CSSValueID secondIdentifier = pair->second()->getValueID();
567
568 ENinePieceImageRule horizontalRule;
569 switch (firstIdentifier) {
570 case CSSValueStretch:
571 horizontalRule = StretchImageRule;
572 break;
573 case CSSValueRound:
574 horizontalRule = RoundImageRule;
575 break;
576 case CSSValueSpace:
577 horizontalRule = SpaceImageRule;
578 break;
579 default: // CSSValueRepeat
580 horizontalRule = RepeatImageRule;
581 break;
582 }
583 image.setHorizontalRule(horizontalRule);
584
585 ENinePieceImageRule verticalRule;
586 switch (secondIdentifier) {
587 case CSSValueStretch:
588 verticalRule = StretchImageRule;
589 break;
590 case CSSValueRound:
591 verticalRule = RoundImageRule;
592 break;
593 case CSSValueSpace:
594 verticalRule = SpaceImageRule;
595 break;
596 default: // CSSValueRepeat
597 verticalRule = RepeatImageRule;
598 break;
599 }
600 image.setVerticalRule(verticalRule);
601 }
602
603 };
604