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 | |
46 | namespace WebCore { |
47 | |
48 | CSSToStyleMap::CSSToStyleMap(StyleResolver* resolver) |
49 | : m_resolver(resolver) |
50 | { |
51 | } |
52 | |
53 | RenderStyle* CSSToStyleMap::style() const |
54 | { |
55 | return m_resolver->style(); |
56 | } |
57 | |
58 | const RenderStyle* CSSToStyleMap::rootElementStyle() const |
59 | { |
60 | return m_resolver->rootElementStyle(); |
61 | } |
62 | |
63 | bool CSSToStyleMap::useSVGZoomRules() const |
64 | { |
65 | return m_resolver->useSVGZoomRules(); |
66 | } |
67 | |
68 | RefPtr<StyleImage> CSSToStyleMap::styleImage(CSSValue& value) |
69 | { |
70 | return m_resolver->styleImage(value); |
71 | } |
72 | |
73 | void 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 | |
98 | void 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 | |
111 | void 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 | |
124 | void 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 | |
137 | void 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 | |
150 | void 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 | |
160 | void 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 | |
173 | void 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 | |
186 | static 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 | |
196 | void 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 | |
224 | void 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 | |
248 | void 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 | |
272 | void 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 | |
299 | void 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 | |
312 | void 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 | |
340 | void 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 | |
353 | void 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 | |
381 | void 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 | |
398 | void 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 | |
415 | void 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 | |
429 | void 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 | |
461 | void 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 | |
509 | void 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 | |
557 | void 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 | |
590 | LengthBox 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 | |
635 | void 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 | |