1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 */
27
28#include "config.h"
29#include "CSSToStyleMap.h"
30
31#include "Animation.h"
32#include "CSSBorderImageSliceValue.h"
33#include "CSSImageGeneratorValue.h"
34#include "CSSImageSetValue.h"
35#include "CSSImageValue.h"
36#include "CSSPrimitiveValue.h"
37#include "CSSPrimitiveValueMappings.h"
38#include "CSSTimingFunctionValue.h"
39#include "CSSValueKeywords.h"
40#include "FillLayer.h"
41#include "Pair.h"
42#include "Rect.h"
43#include "StyleBuilderConverter.h"
44#include "StyleResolver.h"
45
46namespace WebCore {
47
48CSSToStyleMap::CSSToStyleMap(StyleResolver* resolver)
49 : m_resolver(resolver)
50{
51}
52
53RenderStyle* CSSToStyleMap::style() const
54{
55 return m_resolver->style();
56}
57
58const RenderStyle* CSSToStyleMap::rootElementStyle() const
59{
60 return m_resolver->rootElementStyle();
61}
62
63bool CSSToStyleMap::useSVGZoomRules() const
64{
65 return m_resolver->useSVGZoomRules();
66}
67
68RefPtr<StyleImage> CSSToStyleMap::styleImage(CSSValue& value)
69{
70 return m_resolver->styleImage(value);
71}
72
73void CSSToStyleMap::mapFillAttachment(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
74{
75 if (value.treatAsInitialValue(propertyID)) {
76 layer.setAttachment(FillLayer::initialFillAttachment(layer.type()));
77 return;
78 }
79
80 if (!is<CSSPrimitiveValue>(value))
81 return;
82
83 switch (downcast<CSSPrimitiveValue>(value).valueID()) {
84 case CSSValueFixed:
85 layer.setAttachment(FillAttachment::FixedBackground);
86 break;
87 case CSSValueScroll:
88 layer.setAttachment(FillAttachment::ScrollBackground);
89 break;
90 case CSSValueLocal:
91 layer.setAttachment(FillAttachment::LocalBackground);
92 break;
93 default:
94 return;
95 }
96}
97
98void CSSToStyleMap::mapFillClip(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
99{
100 if (value.treatAsInitialValue(propertyID)) {
101 layer.setClip(FillLayer::initialFillClip(layer.type()));
102 return;
103 }
104
105 if (!is<CSSPrimitiveValue>(value))
106 return;
107
108 layer.setClip(downcast<CSSPrimitiveValue>(value));
109}
110
111void CSSToStyleMap::mapFillComposite(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
112{
113 if (value.treatAsInitialValue(propertyID)) {
114 layer.setComposite(FillLayer::initialFillComposite(layer.type()));
115 return;
116 }
117
118 if (!is<CSSPrimitiveValue>(value))
119 return;
120
121 layer.setComposite(downcast<CSSPrimitiveValue>(value));
122}
123
124void CSSToStyleMap::mapFillBlendMode(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
125{
126 if (value.treatAsInitialValue(propertyID)) {
127 layer.setBlendMode(FillLayer::initialFillBlendMode(layer.type()));
128 return;
129 }
130
131 if (!is<CSSPrimitiveValue>(value))
132 return;
133
134 layer.setBlendMode(downcast<CSSPrimitiveValue>(value));
135}
136
137void CSSToStyleMap::mapFillOrigin(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
138{
139 if (value.treatAsInitialValue(propertyID)) {
140 layer.setOrigin(FillLayer::initialFillOrigin(layer.type()));
141 return;
142 }
143
144 if (!is<CSSPrimitiveValue>(value))
145 return;
146
147 layer.setOrigin(downcast<CSSPrimitiveValue>(value));
148}
149
150void CSSToStyleMap::mapFillImage(CSSPropertyID propertyID, FillLayer& layer, CSSValue& value)
151{
152 if (value.treatAsInitialValue(propertyID)) {
153 layer.setImage(FillLayer::initialFillImage(layer.type()));
154 return;
155 }
156
157 layer.setImage(styleImage(value));
158}
159
160void CSSToStyleMap::mapFillRepeatX(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
161{
162 if (value.treatAsInitialValue(propertyID)) {
163 layer.setRepeatX(FillLayer::initialFillRepeatX(layer.type()));
164 return;
165 }
166
167 if (!is<CSSPrimitiveValue>(value))
168 return;
169
170 layer.setRepeatX(downcast<CSSPrimitiveValue>(value));
171}
172
173void CSSToStyleMap::mapFillRepeatY(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
174{
175 if (value.treatAsInitialValue(propertyID)) {
176 layer.setRepeatY(FillLayer::initialFillRepeatY(layer.type()));
177 return;
178 }
179
180 if (!is<CSSPrimitiveValue>(value))
181 return;
182
183 layer.setRepeatY(downcast<CSSPrimitiveValue>(value));
184}
185
186static inline bool convertToLengthSize(const CSSPrimitiveValue& primitiveValue, CSSToLengthConversionData conversionData, LengthSize& size)
187{
188 if (auto* pair = primitiveValue.pairValue()) {
189 size.width = pair->first()->convertToLength<AnyConversion>(conversionData);
190 size.height = pair->second()->convertToLength<AnyConversion>(conversionData);
191 } else
192 size.width = primitiveValue.convertToLength<AnyConversion>(conversionData);
193 return !size.width.isUndefined() && !size.height.isUndefined();
194}
195
196void CSSToStyleMap::mapFillSize(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
197{
198 if (value.treatAsInitialValue(propertyID)) {
199 layer.setSize(FillLayer::initialFillSize(layer.type()));
200 return;
201 }
202
203 if (!is<CSSPrimitiveValue>(value))
204 return;
205
206 auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
207 FillSize fillSize;
208 switch (primitiveValue.valueID()) {
209 case CSSValueContain:
210 fillSize.type = FillSizeType::Contain;
211 break;
212 case CSSValueCover:
213 fillSize.type = FillSizeType::Cover;
214 break;
215 default:
216 ASSERT(fillSize.type == FillSizeType::Size);
217 if (!convertToLengthSize(primitiveValue, m_resolver->state().cssToLengthConversionData(), fillSize.size))
218 return;
219 break;
220 }
221 layer.setSize(fillSize);
222}
223
224void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
225{
226 if (value.treatAsInitialValue(propertyID)) {
227 layer.setXPosition(FillLayer::initialFillXPosition(layer.type()));
228 return;
229 }
230
231 if (!is<CSSPrimitiveValue>(value))
232 return;
233
234 auto* primitiveValue = &downcast<CSSPrimitiveValue>(value);
235 Pair* pair = primitiveValue->pairValue();
236 Length length;
237 if (pair) {
238 ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionX || propertyID == CSSPropertyWebkitMaskPositionX);
239 length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second());
240 } else
241 length = StyleBuilderConverter::convertPositionComponentX(*m_resolver, value);
242
243 layer.setXPosition(length);
244 if (pair)
245 layer.setBackgroundXOrigin(*pair->first());
246}
247
248void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
249{
250 if (value.treatAsInitialValue(propertyID)) {
251 layer.setYPosition(FillLayer::initialFillYPosition(layer.type()));
252 return;
253 }
254
255 if (!is<CSSPrimitiveValue>(value))
256 return;
257
258 auto* primitiveValue = &downcast<CSSPrimitiveValue>(value);
259 Pair* pair = primitiveValue->pairValue();
260 Length length;
261 if (pair) {
262 ASSERT_UNUSED(propertyID, propertyID == CSSPropertyBackgroundPositionY || propertyID == CSSPropertyWebkitMaskPositionY);
263 length = StyleBuilderConverter::convertLength(*m_resolver, *pair->second());
264 } else
265 length = StyleBuilderConverter::convertPositionComponentY(*m_resolver, value);
266
267 layer.setYPosition(length);
268 if (pair)
269 layer.setBackgroundYOrigin(*pair->first());
270}
271
272void CSSToStyleMap::mapFillMaskSourceType(CSSPropertyID propertyID, FillLayer& layer, const CSSValue& value)
273{
274 MaskSourceType type = FillLayer::initialFillMaskSourceType(layer.type());
275 if (value.treatAsInitialValue(propertyID)) {
276 layer.setMaskSourceType(type);
277 return;
278 }
279
280 if (!is<CSSPrimitiveValue>(value))
281 return;
282
283 switch (downcast<CSSPrimitiveValue>(value).valueID()) {
284 case CSSValueAlpha:
285 type = MaskSourceType::Alpha;
286 break;
287 case CSSValueLuminance:
288 type = MaskSourceType::Luminance;
289 break;
290 case CSSValueAuto:
291 break;
292 default:
293 ASSERT_NOT_REACHED();
294 }
295
296 layer.setMaskSourceType(type);
297}
298
299void CSSToStyleMap::mapAnimationDelay(Animation& animation, const CSSValue& value)
300{
301 if (value.treatAsInitialValue(CSSPropertyAnimationDelay)) {
302 animation.setDelay(Animation::initialDelay());
303 return;
304 }
305
306 if (!is<CSSPrimitiveValue>(value))
307 return;
308
309 animation.setDelay(downcast<CSSPrimitiveValue>(value).computeTime<double, CSSPrimitiveValue::Seconds>());
310}
311
312void CSSToStyleMap::mapAnimationDirection(Animation& layer, const CSSValue& value)
313{
314 if (value.treatAsInitialValue(CSSPropertyAnimationDirection)) {
315 layer.setDirection(Animation::initialDirection());
316 return;
317 }
318
319 if (!is<CSSPrimitiveValue>(value))
320 return;
321
322 switch (downcast<CSSPrimitiveValue>(value).valueID()) {
323 case CSSValueNormal:
324 layer.setDirection(Animation::AnimationDirectionNormal);
325 break;
326 case CSSValueAlternate:
327 layer.setDirection(Animation::AnimationDirectionAlternate);
328 break;
329 case CSSValueReverse:
330 layer.setDirection(Animation::AnimationDirectionReverse);
331 break;
332 case CSSValueAlternateReverse:
333 layer.setDirection(Animation::AnimationDirectionAlternateReverse);
334 break;
335 default:
336 break;
337 }
338}
339
340void CSSToStyleMap::mapAnimationDuration(Animation& animation, const CSSValue& value)
341{
342 if (value.treatAsInitialValue(CSSPropertyAnimationDuration)) {
343 animation.setDuration(Animation::initialDuration());
344 return;
345 }
346
347 if (!is<CSSPrimitiveValue>(value))
348 return;
349
350 animation.setDuration(downcast<CSSPrimitiveValue>(value).computeTime<double, CSSPrimitiveValue::Seconds>());
351}
352
353void CSSToStyleMap::mapAnimationFillMode(Animation& layer, const CSSValue& value)
354{
355 if (value.treatAsInitialValue(CSSPropertyAnimationFillMode)) {
356 layer.setFillMode(Animation::initialFillMode());
357 return;
358 }
359
360 if (!is<CSSPrimitiveValue>(value))
361 return;
362
363 switch (downcast<CSSPrimitiveValue>(value).valueID()) {
364 case CSSValueNone:
365 layer.setFillMode(AnimationFillMode::None);
366 break;
367 case CSSValueForwards:
368 layer.setFillMode(AnimationFillMode::Forwards);
369 break;
370 case CSSValueBackwards:
371 layer.setFillMode(AnimationFillMode::Backwards);
372 break;
373 case CSSValueBoth:
374 layer.setFillMode(AnimationFillMode::Both);
375 break;
376 default:
377 break;
378 }
379}
380
381void CSSToStyleMap::mapAnimationIterationCount(Animation& animation, const CSSValue& value)
382{
383 if (value.treatAsInitialValue(CSSPropertyAnimationIterationCount)) {
384 animation.setIterationCount(Animation::initialIterationCount());
385 return;
386 }
387
388 if (!is<CSSPrimitiveValue>(value))
389 return;
390
391 auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
392 if (primitiveValue.valueID() == CSSValueInfinite)
393 animation.setIterationCount(Animation::IterationCountInfinite);
394 else
395 animation.setIterationCount(primitiveValue.floatValue());
396}
397
398void CSSToStyleMap::mapAnimationName(Animation& layer, const CSSValue& value)
399{
400 if (value.treatAsInitialValue(CSSPropertyAnimationName)) {
401 layer.setName(Animation::initialName());
402 return;
403 }
404
405 if (!is<CSSPrimitiveValue>(value))
406 return;
407
408 auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
409 if (primitiveValue.valueID() == CSSValueNone)
410 layer.setIsNoneAnimation(true);
411 else
412 layer.setName(primitiveValue.stringValue(), m_resolver->state().styleScopeOrdinal());
413}
414
415void CSSToStyleMap::mapAnimationPlayState(Animation& layer, const CSSValue& value)
416{
417 if (value.treatAsInitialValue(CSSPropertyAnimationPlayState)) {
418 layer.setPlayState(Animation::initialPlayState());
419 return;
420 }
421
422 if (!is<CSSPrimitiveValue>(value))
423 return;
424
425 AnimationPlayState playState = (downcast<CSSPrimitiveValue>(value).valueID() == CSSValuePaused) ? AnimationPlayState::Paused : AnimationPlayState::Playing;
426 layer.setPlayState(playState);
427}
428
429void CSSToStyleMap::mapAnimationProperty(Animation& animation, const CSSValue& value)
430{
431 if (value.treatAsInitialValue(CSSPropertyAnimation)) {
432 animation.setAnimationMode(Animation::AnimateAll);
433 animation.setProperty(CSSPropertyInvalid);
434 return;
435 }
436
437 if (!is<CSSPrimitiveValue>(value))
438 return;
439
440 auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
441 if (primitiveValue.valueID() == CSSValueAll) {
442 animation.setAnimationMode(Animation::AnimateAll);
443 animation.setProperty(CSSPropertyInvalid);
444 return;
445 }
446 if (primitiveValue.valueID() == CSSValueNone) {
447 animation.setAnimationMode(Animation::AnimateNone);
448 animation.setProperty(CSSPropertyInvalid);
449 return;
450 }
451 if (primitiveValue.propertyID() == CSSPropertyInvalid) {
452 animation.setAnimationMode(Animation::AnimateUnknownProperty);
453 animation.setProperty(CSSPropertyInvalid);
454 animation.setUnknownProperty(primitiveValue.stringValue());
455 return;
456 }
457 animation.setAnimationMode(Animation::AnimateSingleProperty);
458 animation.setProperty(primitiveValue.propertyID());
459}
460
461void CSSToStyleMap::mapAnimationTimingFunction(Animation& animation, const CSSValue& value)
462{
463 if (value.treatAsInitialValue(CSSPropertyAnimationTimingFunction)) {
464 animation.setTimingFunction(Animation::initialTimingFunction());
465 return;
466 }
467
468 if (is<CSSPrimitiveValue>(value)) {
469 switch (downcast<CSSPrimitiveValue>(value).valueID()) {
470 case CSSValueLinear:
471 animation.setTimingFunction(LinearTimingFunction::create());
472 break;
473 case CSSValueEase:
474 animation.setTimingFunction(CubicBezierTimingFunction::create());
475 break;
476 case CSSValueEaseIn:
477 animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseIn));
478 break;
479 case CSSValueEaseOut:
480 animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseOut));
481 break;
482 case CSSValueEaseInOut:
483 animation.setTimingFunction(CubicBezierTimingFunction::create(CubicBezierTimingFunction::EaseInOut));
484 break;
485 case CSSValueStepStart:
486 animation.setTimingFunction(StepsTimingFunction::create(1, true));
487 break;
488 case CSSValueStepEnd:
489 animation.setTimingFunction(StepsTimingFunction::create(1, false));
490 break;
491 default:
492 break;
493 }
494 return;
495 }
496
497 if (is<CSSCubicBezierTimingFunctionValue>(value)) {
498 auto& cubicTimingFunction = downcast<CSSCubicBezierTimingFunctionValue>(value);
499 animation.setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction.x1(), cubicTimingFunction.y1(), cubicTimingFunction.x2(), cubicTimingFunction.y2()));
500 } else if (is<CSSStepsTimingFunctionValue>(value)) {
501 auto& stepsTimingFunction = downcast<CSSStepsTimingFunctionValue>(value);
502 animation.setTimingFunction(StepsTimingFunction::create(stepsTimingFunction.numberOfSteps(), stepsTimingFunction.stepAtStart()));
503 } else if (is<CSSSpringTimingFunctionValue>(value)) {
504 auto& springTimingFunction = downcast<CSSSpringTimingFunctionValue>(value);
505 animation.setTimingFunction(SpringTimingFunction::create(springTimingFunction.mass(), springTimingFunction.stiffness(), springTimingFunction.damping(), springTimingFunction.initialVelocity()));
506 }
507}
508
509void CSSToStyleMap::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image)
510{
511 // If we're not a value list, then we are "none" and don't need to alter the empty image at all.
512 if (!is<CSSValueList>(value))
513 return;
514
515 // Retrieve the border image value.
516 CSSValueList& borderImage = downcast<CSSValueList>(*value);
517
518 for (auto& current : borderImage) {
519 if (is<CSSImageValue>(current) || is<CSSImageGeneratorValue>(current) || is<CSSImageSetValue>(current))
520 image.setImage(styleImage(current.get()));
521 else if (is<CSSBorderImageSliceValue>(current))
522 mapNinePieceImageSlice(current, image);
523 else if (is<CSSValueList>(current)) {
524 CSSValueList& slashList = downcast<CSSValueList>(current.get());
525 // Map in the image slices.
526 if (is<CSSBorderImageSliceValue>(slashList.item(0)))
527 mapNinePieceImageSlice(*slashList.item(0), image);
528
529 // Map in the border slices.
530 if (slashList.item(1))
531 image.setBorderSlices(mapNinePieceImageQuad(*slashList.item(1)));
532
533 // Map in the outset.
534 if (slashList.item(2))
535 image.setOutset(mapNinePieceImageQuad(*slashList.item(2)));
536 } else if (is<CSSPrimitiveValue>(current)) {
537 // Set the appropriate rules for stretch/round/repeat of the slices.
538 mapNinePieceImageRepeat(current, image);
539 }
540 }
541
542 if (property == CSSPropertyWebkitBorderImage) {
543 // We have to preserve the legacy behavior of -webkit-border-image and make the border slices
544 // also set the border widths. We don't need to worry about percentages, since we don't even support
545 // those on real borders yet.
546 if (image.borderSlices().top().isFixed())
547 style()->setBorderTopWidth(image.borderSlices().top().value());
548 if (image.borderSlices().right().isFixed())
549 style()->setBorderRightWidth(image.borderSlices().right().value());
550 if (image.borderSlices().bottom().isFixed())
551 style()->setBorderBottomWidth(image.borderSlices().bottom().value());
552 if (image.borderSlices().left().isFixed())
553 style()->setBorderLeftWidth(image.borderSlices().left().value());
554 }
555}
556
557void CSSToStyleMap::mapNinePieceImageSlice(CSSValue& value, NinePieceImage& image)
558{
559 if (!is<CSSBorderImageSliceValue>(value))
560 return;
561
562 // Retrieve the border image value.
563 auto& borderImageSlice = downcast<CSSBorderImageSliceValue>(value);
564
565 // Set up a length box to represent our image slices.
566 LengthBox box;
567 Quad* slices = borderImageSlice.slices();
568 if (slices->top()->isPercentage())
569 box.top() = Length(slices->top()->doubleValue(), Percent);
570 else
571 box.top() = Length(slices->top()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
572 if (slices->bottom()->isPercentage())
573 box.bottom() = Length(slices->bottom()->doubleValue(), Percent);
574 else
575 box.bottom() = Length((int)slices->bottom()->floatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
576 if (slices->left()->isPercentage())
577 box.left() = Length(slices->left()->doubleValue(), Percent);
578 else
579 box.left() = Length(slices->left()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
580 if (slices->right()->isPercentage())
581 box.right() = Length(slices->right()->doubleValue(), Percent);
582 else
583 box.right() = Length(slices->right()->intValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
584 image.setImageSlices(box);
585
586 // Set our fill mode.
587 image.setFill(borderImageSlice.m_fill);
588}
589
590LengthBox CSSToStyleMap::mapNinePieceImageQuad(CSSValue& value)
591{
592 if (!is<CSSPrimitiveValue>(value))
593 return LengthBox();
594
595 // Get our zoom value.
596 CSSToLengthConversionData conversionData = useSVGZoomRules() ? m_resolver->state().cssToLengthConversionData().copyWithAdjustedZoom(1.0f) : m_resolver->state().cssToLengthConversionData();
597
598 // Retrieve the primitive value.
599 auto& borderWidths = downcast<CSSPrimitiveValue>(value);
600
601 // Set up a length box to represent our image slices.
602 LengthBox box; // Defaults to 'auto' so we don't have to handle that explicitly below.
603 Quad* slices = borderWidths.quadValue();
604 if (slices->top()->isNumber())
605 box.top() = Length(slices->top()->intValue(), Relative);
606 else if (slices->top()->isPercentage())
607 box.top() = Length(slices->top()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
608 else if (slices->top()->valueID() != CSSValueAuto)
609 box.top() = slices->top()->computeLength<Length>(conversionData);
610
611 if (slices->right()->isNumber())
612 box.right() = Length(slices->right()->intValue(), Relative);
613 else if (slices->right()->isPercentage())
614 box.right() = Length(slices->right()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
615 else if (slices->right()->valueID() != CSSValueAuto)
616 box.right() = slices->right()->computeLength<Length>(conversionData);
617
618 if (slices->bottom()->isNumber())
619 box.bottom() = Length(slices->bottom()->intValue(), Relative);
620 else if (slices->bottom()->isPercentage())
621 box.bottom() = Length(slices->bottom()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
622 else if (slices->bottom()->valueID() != CSSValueAuto)
623 box.bottom() = slices->bottom()->computeLength<Length>(conversionData);
624
625 if (slices->left()->isNumber())
626 box.left() = Length(slices->left()->intValue(), Relative);
627 else if (slices->left()->isPercentage())
628 box.left() = Length(slices->left()->doubleValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
629 else if (slices->left()->valueID() != CSSValueAuto)
630 box.left() = slices->left()->computeLength<Length>(conversionData);
631
632 return box;
633}
634
635void CSSToStyleMap::mapNinePieceImageRepeat(CSSValue& value, NinePieceImage& image)
636{
637 if (!is<CSSPrimitiveValue>(value))
638 return;
639
640 CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(value);
641 Pair* pair = primitiveValue.pairValue();
642 if (!pair || !pair->first() || !pair->second())
643 return;
644
645 CSSValueID firstIdentifier = pair->first()->valueID();
646 CSSValueID secondIdentifier = pair->second()->valueID();
647
648 ENinePieceImageRule horizontalRule;
649 switch (firstIdentifier) {
650 case CSSValueStretch:
651 horizontalRule = StretchImageRule;
652 break;
653 case CSSValueRound:
654 horizontalRule = RoundImageRule;
655 break;
656 case CSSValueSpace:
657 horizontalRule = SpaceImageRule;
658 break;
659 default: // CSSValueRepeat
660 horizontalRule = RepeatImageRule;
661 break;
662 }
663 image.setHorizontalRule(horizontalRule);
664
665 ENinePieceImageRule verticalRule;
666 switch (secondIdentifier) {
667 case CSSValueStretch:
668 verticalRule = StretchImageRule;
669 break;
670 case CSSValueRound:
671 verticalRule = RoundImageRule;
672 break;
673 case CSSValueSpace:
674 verticalRule = SpaceImageRule;
675 break;
676 default: // CSSValueRepeat
677 verticalRule = RepeatImageRule;
678 break;
679 }
680 image.setVerticalRule(verticalRule);
681}
682
683};
684