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
6 * rights reserved.
7 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
8 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
9 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
10 * (http://www.torchmobile.com/)
11 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
12 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
28 */
29
30 #include "third_party/blink/renderer/core/css/resolver/css_to_style_map.h"
31
32 #include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
33 #include "third_party/blink/renderer/core/css/css_border_image_slice_value.h"
34 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
35 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
36 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
37 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
38 #include "third_party/blink/renderer/core/css/css_quad_value.h"
39 #include "third_party/blink/renderer/core/css/css_timing_function_value.h"
40 #include "third_party/blink/renderer/core/css/css_value_pair.h"
41 #include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
42 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
43 #include "third_party/blink/renderer/core/css_value_keywords.h"
44 #include "third_party/blink/renderer/core/frame/deprecation.h"
45 #include "third_party/blink/renderer/core/style/border_image_length_box.h"
46 #include "third_party/blink/renderer/core/style/computed_style.h"
47 #include "third_party/blink/renderer/core/style/fill_layer.h"
48
49 namespace blink {
50
MapFillAttachment(StyleResolverState &,FillLayer * layer,const CSSValue & value)51 void CSSToStyleMap::MapFillAttachment(StyleResolverState&,
52 FillLayer* layer,
53 const CSSValue& value) {
54 if (value.IsInitialValue()) {
55 layer->SetAttachment(FillLayer::InitialFillAttachment(layer->GetType()));
56 return;
57 }
58
59 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
60 if (!identifier_value)
61 return;
62
63 switch (identifier_value->GetValueID()) {
64 case CSSValueID::kFixed:
65 layer->SetAttachment(EFillAttachment::kFixed);
66 break;
67 case CSSValueID::kScroll:
68 layer->SetAttachment(EFillAttachment::kScroll);
69 break;
70 case CSSValueID::kLocal:
71 layer->SetAttachment(EFillAttachment::kLocal);
72 break;
73 default:
74 return;
75 }
76 }
77
MapFillClip(StyleResolverState &,FillLayer * layer,const CSSValue & value)78 void CSSToStyleMap::MapFillClip(StyleResolverState&,
79 FillLayer* layer,
80 const CSSValue& value) {
81 if (value.IsInitialValue()) {
82 layer->SetClip(FillLayer::InitialFillClip(layer->GetType()));
83 return;
84 }
85
86 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
87 if (!identifier_value)
88 return;
89
90 layer->SetClip(identifier_value->ConvertTo<EFillBox>());
91 }
92
MapFillComposite(StyleResolverState &,FillLayer * layer,const CSSValue & value)93 void CSSToStyleMap::MapFillComposite(StyleResolverState&,
94 FillLayer* layer,
95 const CSSValue& value) {
96 if (value.IsInitialValue()) {
97 layer->SetComposite(FillLayer::InitialFillComposite(layer->GetType()));
98 return;
99 }
100
101 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
102 if (!identifier_value)
103 return;
104
105 layer->SetComposite(identifier_value->ConvertTo<CompositeOperator>());
106 }
107
MapFillBlendMode(StyleResolverState &,FillLayer * layer,const CSSValue & value)108 void CSSToStyleMap::MapFillBlendMode(StyleResolverState&,
109 FillLayer* layer,
110 const CSSValue& value) {
111 if (value.IsInitialValue()) {
112 layer->SetBlendMode(FillLayer::InitialFillBlendMode(layer->GetType()));
113 return;
114 }
115
116 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
117 if (!identifier_value)
118 return;
119
120 layer->SetBlendMode(identifier_value->ConvertTo<BlendMode>());
121 }
122
MapFillOrigin(StyleResolverState &,FillLayer * layer,const CSSValue & value)123 void CSSToStyleMap::MapFillOrigin(StyleResolverState&,
124 FillLayer* layer,
125 const CSSValue& value) {
126 if (value.IsInitialValue()) {
127 layer->SetOrigin(FillLayer::InitialFillOrigin(layer->GetType()));
128 return;
129 }
130
131 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
132 if (!identifier_value)
133 return;
134
135 layer->SetOrigin(identifier_value->ConvertTo<EFillBox>());
136 }
137
MapFillImage(StyleResolverState & state,FillLayer * layer,const CSSValue & value)138 void CSSToStyleMap::MapFillImage(StyleResolverState& state,
139 FillLayer* layer,
140 const CSSValue& value) {
141 if (value.IsInitialValue()) {
142 layer->SetImage(FillLayer::InitialFillImage(layer->GetType()));
143 return;
144 }
145
146 CSSPropertyID property = layer->GetType() == EFillLayerType::kBackground
147 ? CSSPropertyID::kBackgroundImage
148 : CSSPropertyID::kWebkitMaskImage;
149 layer->SetImage(state.GetStyleImage(
150 property, state.ResolveLightDarkPair(CSSProperty::Get(property), value)));
151 }
152
MapFillRepeatX(StyleResolverState &,FillLayer * layer,const CSSValue & value)153 void CSSToStyleMap::MapFillRepeatX(StyleResolverState&,
154 FillLayer* layer,
155 const CSSValue& value) {
156 if (value.IsInitialValue()) {
157 layer->SetRepeatX(FillLayer::InitialFillRepeatX(layer->GetType()));
158 return;
159 }
160
161 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
162 if (!identifier_value)
163 return;
164
165 layer->SetRepeatX(identifier_value->ConvertTo<EFillRepeat>());
166 }
167
MapFillRepeatY(StyleResolverState &,FillLayer * layer,const CSSValue & value)168 void CSSToStyleMap::MapFillRepeatY(StyleResolverState&,
169 FillLayer* layer,
170 const CSSValue& value) {
171 if (value.IsInitialValue()) {
172 layer->SetRepeatY(FillLayer::InitialFillRepeatY(layer->GetType()));
173 return;
174 }
175
176 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
177 if (!identifier_value)
178 return;
179
180 layer->SetRepeatY(identifier_value->ConvertTo<EFillRepeat>());
181 }
182
MapFillSize(StyleResolverState & state,FillLayer * layer,const CSSValue & value)183 void CSSToStyleMap::MapFillSize(StyleResolverState& state,
184 FillLayer* layer,
185 const CSSValue& value) {
186 if (value.IsInitialValue()) {
187 layer->SetSizeType(FillLayer::InitialFillSizeType(layer->GetType()));
188 layer->SetSizeLength(FillLayer::InitialFillSizeLength(layer->GetType()));
189 return;
190 }
191
192 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
193 if (!identifier_value && !value.IsPrimitiveValue() && !value.IsValuePair())
194 return;
195
196 if (identifier_value &&
197 identifier_value->GetValueID() == CSSValueID::kContain)
198 layer->SetSizeType(EFillSizeType::kContain);
199 else if (identifier_value &&
200 identifier_value->GetValueID() == CSSValueID::kCover)
201 layer->SetSizeType(EFillSizeType::kCover);
202 else
203 layer->SetSizeType(EFillSizeType::kSizeLength);
204
205 LengthSize b = FillLayer::InitialFillSizeLength(layer->GetType());
206
207 if (identifier_value &&
208 (identifier_value->GetValueID() == CSSValueID::kContain ||
209 identifier_value->GetValueID() == CSSValueID::kCover)) {
210 layer->SetSizeLength(b);
211 return;
212 }
213
214 Length first_length;
215 Length second_length;
216
217 if (const auto* pair = DynamicTo<CSSValuePair>(value)) {
218 first_length =
219 StyleBuilderConverter::ConvertLengthOrAuto(state, pair->First());
220 second_length =
221 StyleBuilderConverter::ConvertLengthOrAuto(state, pair->Second());
222 } else {
223 DCHECK(value.IsPrimitiveValue() || value.IsIdentifierValue());
224 first_length = StyleBuilderConverter::ConvertLengthOrAuto(state, value);
225 second_length = Length();
226 }
227
228 b.SetWidth(first_length);
229 b.SetHeight(second_length);
230 layer->SetSizeLength(b);
231 }
232
MapFillPositionX(StyleResolverState & state,FillLayer * layer,const CSSValue & value)233 void CSSToStyleMap::MapFillPositionX(StyleResolverState& state,
234 FillLayer* layer,
235 const CSSValue& value) {
236 if (value.IsInitialValue()) {
237 layer->SetPositionX(FillLayer::InitialFillPositionX(layer->GetType()));
238 return;
239 }
240
241 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
242 if (!identifier_value && !value.IsPrimitiveValue() && !value.IsValuePair())
243 return;
244
245 Length length;
246 auto* pair = DynamicTo<CSSValuePair>(value);
247 if (pair)
248 length = To<CSSPrimitiveValue>(pair->Second())
249 .ConvertToLength(state.CssToLengthConversionData());
250 else
251 length = StyleBuilderConverter::ConvertPositionLength<CSSValueID::kLeft,
252 CSSValueID::kRight>(
253 state, value);
254
255 layer->SetPositionX(length);
256 if (pair) {
257 layer->SetBackgroundXOrigin(To<CSSIdentifierValue>(pair->First())
258 .ConvertTo<BackgroundEdgeOrigin>());
259 }
260 }
261
MapFillPositionY(StyleResolverState & state,FillLayer * layer,const CSSValue & value)262 void CSSToStyleMap::MapFillPositionY(StyleResolverState& state,
263 FillLayer* layer,
264 const CSSValue& value) {
265 if (value.IsInitialValue()) {
266 layer->SetPositionY(FillLayer::InitialFillPositionY(layer->GetType()));
267 return;
268 }
269
270 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
271 if (!identifier_value && !value.IsPrimitiveValue() && !value.IsValuePair())
272 return;
273
274 Length length;
275 auto* pair = DynamicTo<CSSValuePair>(value);
276 if (pair)
277 length = To<CSSPrimitiveValue>(pair->Second())
278 .ConvertToLength(state.CssToLengthConversionData());
279 else
280 length = StyleBuilderConverter::ConvertPositionLength<CSSValueID::kTop,
281 CSSValueID::kBottom>(
282 state, value);
283
284 layer->SetPositionY(length);
285 if (pair) {
286 layer->SetBackgroundYOrigin(To<CSSIdentifierValue>(pair->First())
287 .ConvertTo<BackgroundEdgeOrigin>());
288 }
289 }
290
MapAnimationDelay(const CSSValue & value)291 double CSSToStyleMap::MapAnimationDelay(const CSSValue& value) {
292 if (value.IsInitialValue())
293 return CSSTimingData::InitialDelay();
294 return To<CSSPrimitiveValue>(value).ComputeSeconds();
295 }
296
MapAnimationDirection(const CSSValue & value)297 Timing::PlaybackDirection CSSToStyleMap::MapAnimationDirection(
298 const CSSValue& value) {
299 if (value.IsInitialValue())
300 return CSSAnimationData::InitialDirection();
301
302 switch (To<CSSIdentifierValue>(value).GetValueID()) {
303 case CSSValueID::kNormal:
304 return Timing::PlaybackDirection::NORMAL;
305 case CSSValueID::kAlternate:
306 return Timing::PlaybackDirection::ALTERNATE_NORMAL;
307 case CSSValueID::kReverse:
308 return Timing::PlaybackDirection::REVERSE;
309 case CSSValueID::kAlternateReverse:
310 return Timing::PlaybackDirection::ALTERNATE_REVERSE;
311 default:
312 NOTREACHED();
313 return CSSAnimationData::InitialDirection();
314 }
315 }
316
MapAnimationDuration(const CSSValue & value)317 double CSSToStyleMap::MapAnimationDuration(const CSSValue& value) {
318 if (value.IsInitialValue())
319 return CSSTimingData::InitialDuration();
320 return To<CSSPrimitiveValue>(value).ComputeSeconds();
321 }
322
MapAnimationFillMode(const CSSValue & value)323 Timing::FillMode CSSToStyleMap::MapAnimationFillMode(const CSSValue& value) {
324 if (value.IsInitialValue())
325 return CSSAnimationData::InitialFillMode();
326
327 switch (To<CSSIdentifierValue>(value).GetValueID()) {
328 case CSSValueID::kNone:
329 return Timing::FillMode::NONE;
330 case CSSValueID::kForwards:
331 return Timing::FillMode::FORWARDS;
332 case CSSValueID::kBackwards:
333 return Timing::FillMode::BACKWARDS;
334 case CSSValueID::kBoth:
335 return Timing::FillMode::BOTH;
336 default:
337 NOTREACHED();
338 return CSSAnimationData::InitialFillMode();
339 }
340 }
341
MapAnimationIterationCount(const CSSValue & value)342 double CSSToStyleMap::MapAnimationIterationCount(const CSSValue& value) {
343 if (value.IsInitialValue())
344 return CSSAnimationData::InitialIterationCount();
345 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
346 if (identifier_value &&
347 identifier_value->GetValueID() == CSSValueID::kInfinite)
348 return std::numeric_limits<double>::infinity();
349 return To<CSSPrimitiveValue>(value).GetFloatValue();
350 }
351
MapAnimationName(const CSSValue & value)352 AtomicString CSSToStyleMap::MapAnimationName(const CSSValue& value) {
353 if (value.IsInitialValue())
354 return CSSAnimationData::InitialName();
355 if (auto* custom_ident_value = DynamicTo<CSSCustomIdentValue>(value))
356 return AtomicString(custom_ident_value->Value());
357 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNone);
358 return CSSAnimationData::InitialName();
359 }
360
MapAnimationTimeline(const CSSValue & value)361 StyleNameOrKeyword CSSToStyleMap::MapAnimationTimeline(const CSSValue& value) {
362 if (value.IsInitialValue())
363 return CSSAnimationData::InitialTimeline();
364 if (auto* ident = DynamicTo<CSSIdentifierValue>(value)) {
365 DCHECK(ident->GetValueID() == CSSValueID::kAuto ||
366 ident->GetValueID() == CSSValueID::kNone);
367 return StyleNameOrKeyword(ident->GetValueID());
368 }
369 if (auto* custom_ident = DynamicTo<CSSCustomIdentValue>(value)) {
370 return StyleNameOrKeyword(
371 StyleName(custom_ident->Value(), StyleName::Type::kCustomIdent));
372 }
373 return StyleNameOrKeyword(
374 StyleName(AtomicString(To<CSSStringValue>(value).Value()),
375 StyleName::Type::kString));
376 }
377
MapAnimationPlayState(const CSSValue & value)378 EAnimPlayState CSSToStyleMap::MapAnimationPlayState(const CSSValue& value) {
379 if (value.IsInitialValue())
380 return CSSAnimationData::InitialPlayState();
381 if (To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kPaused)
382 return EAnimPlayState::kPaused;
383 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kRunning);
384 return EAnimPlayState::kPlaying;
385 }
386
MapAnimationProperty(const CSSValue & value)387 CSSTransitionData::TransitionProperty CSSToStyleMap::MapAnimationProperty(
388 const CSSValue& value) {
389 if (value.IsInitialValue())
390 return CSSTransitionData::InitialProperty();
391 if (const auto* custom_ident_value = DynamicTo<CSSCustomIdentValue>(value)) {
392 if (custom_ident_value->IsKnownPropertyID()) {
393 return CSSTransitionData::TransitionProperty(
394 custom_ident_value->ValueAsPropertyID());
395 }
396 return CSSTransitionData::TransitionProperty(custom_ident_value->Value());
397 }
398 if (To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kAll)
399 return CSSTransitionData::InitialProperty();
400 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNone);
401 return CSSTransitionData::TransitionProperty(
402 CSSTransitionData::kTransitionNone);
403 }
404
MapAnimationTimingFunction(const CSSValue & value)405 scoped_refptr<TimingFunction> CSSToStyleMap::MapAnimationTimingFunction(
406 const CSSValue& value) {
407 // FIXME: We should probably only call into this function with a valid
408 // single timing function value which isn't initial or inherit. We can
409 // currently get into here with initial since the parser expands unset
410 // properties in shorthands to initial.
411
412 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
413 switch (identifier_value->GetValueID()) {
414 case CSSValueID::kLinear:
415 return LinearTimingFunction::Shared();
416 case CSSValueID::kEase:
417 return CubicBezierTimingFunction::Preset(
418 CubicBezierTimingFunction::EaseType::EASE);
419 case CSSValueID::kEaseIn:
420 return CubicBezierTimingFunction::Preset(
421 CubicBezierTimingFunction::EaseType::EASE_IN);
422 case CSSValueID::kEaseOut:
423 return CubicBezierTimingFunction::Preset(
424 CubicBezierTimingFunction::EaseType::EASE_OUT);
425 case CSSValueID::kEaseInOut:
426 return CubicBezierTimingFunction::Preset(
427 CubicBezierTimingFunction::EaseType::EASE_IN_OUT);
428 case CSSValueID::kStepStart:
429 return StepsTimingFunction::Preset(
430 StepsTimingFunction::StepPosition::START);
431 case CSSValueID::kStepEnd:
432 return StepsTimingFunction::Preset(
433 StepsTimingFunction::StepPosition::END);
434 default:
435 NOTREACHED();
436 return CSSTimingData::InitialTimingFunction();
437 }
438 }
439
440 if (const auto* cubic_timing_function =
441 DynamicTo<cssvalue::CSSCubicBezierTimingFunctionValue>(value)) {
442 return CubicBezierTimingFunction::Create(
443 cubic_timing_function->X1(), cubic_timing_function->Y1(),
444 cubic_timing_function->X2(), cubic_timing_function->Y2());
445 }
446
447 if (value.IsInitialValue())
448 return CSSTimingData::InitialTimingFunction();
449
450 const auto& steps_timing_function =
451 To<cssvalue::CSSStepsTimingFunctionValue>(value);
452 return StepsTimingFunction::Create(steps_timing_function.NumberOfSteps(),
453 steps_timing_function.GetStepPosition());
454 }
455
MapNinePieceImage(StyleResolverState & state,CSSPropertyID property,const CSSValue & value,NinePieceImage & image)456 void CSSToStyleMap::MapNinePieceImage(StyleResolverState& state,
457 CSSPropertyID property,
458 const CSSValue& value,
459 NinePieceImage& image) {
460 // Retrieve the border image value.
461 const auto* border_image = DynamicTo<CSSValueList>(value);
462
463 // If we're not a value list, then we are "none" and don't need to alter the
464 // empty image at all.
465 if (!border_image)
466 return;
467
468 // Set the image (this kicks off the load).
469 CSSPropertyID image_property;
470 if (property == CSSPropertyID::kWebkitBorderImage)
471 image_property = CSSPropertyID::kBorderImageSource;
472 else if (property == CSSPropertyID::kWebkitMaskBoxImage)
473 image_property = CSSPropertyID::kWebkitMaskBoxImageSource;
474 else
475 image_property = property;
476
477 for (unsigned i = 0; i < border_image->length(); ++i) {
478 const CSSValue& current = border_image->Item(i);
479
480 if (current.IsImageValue() || current.IsImageGeneratorValue() ||
481 current.IsImageSetValue()) {
482 image.SetImage(state.GetStyleImage(image_property, current));
483 } else if (current.IsBorderImageSliceValue()) {
484 MapNinePieceImageSlice(state, current, image);
485 } else if (const auto* slash_list = DynamicTo<CSSValueList>(current)) {
486 size_t length = slash_list->length();
487 // Map in the image slices.
488 if (length && slash_list->Item(0).IsBorderImageSliceValue())
489 MapNinePieceImageSlice(state, slash_list->Item(0), image);
490
491 // Map in the border slices.
492 if (length > 1) {
493 image.SetBorderSlices(
494 MapNinePieceImageQuad(state, slash_list->Item(1)));
495 }
496
497 // Map in the outset.
498 if (length > 2)
499 image.SetOutset(MapNinePieceImageQuad(state, slash_list->Item(2)));
500 } else if (current.IsPrimitiveValue() || current.IsValuePair()) {
501 // Set the appropriate rules for stretch/round/repeat of the slices.
502 MapNinePieceImageRepeat(state, current, image);
503 }
504 }
505
506 if (property == CSSPropertyID::kWebkitBorderImage) {
507 // We have to preserve the legacy behavior of -webkit-border-image and make
508 // the border slices also set the border widths. We don't need to worry
509 // about percentages, since we don't even support those on real borders yet.
510 if (image.BorderSlices().Top().IsLength() &&
511 image.BorderSlices().Top().length().IsFixed())
512 state.Style()->SetBorderTopWidth(
513 image.BorderSlices().Top().length().Value());
514 if (image.BorderSlices().Right().IsLength() &&
515 image.BorderSlices().Right().length().IsFixed())
516 state.Style()->SetBorderRightWidth(
517 image.BorderSlices().Right().length().Value());
518 if (image.BorderSlices().Bottom().IsLength() &&
519 image.BorderSlices().Bottom().length().IsFixed())
520 state.Style()->SetBorderBottomWidth(
521 image.BorderSlices().Bottom().length().Value());
522 if (image.BorderSlices().Left().IsLength() &&
523 image.BorderSlices().Left().length().IsFixed())
524 state.Style()->SetBorderLeftWidth(
525 image.BorderSlices().Left().length().Value());
526 }
527 }
528
ConvertBorderImageSliceSide(const CSSPrimitiveValue & value)529 static Length ConvertBorderImageSliceSide(const CSSPrimitiveValue& value) {
530 if (value.IsPercentage())
531 return Length::Percent(value.GetDoubleValue());
532 return Length::Fixed(round(value.GetDoubleValue()));
533 }
534
MapNinePieceImageSlice(StyleResolverState &,const CSSValue & value,NinePieceImage & image)535 void CSSToStyleMap::MapNinePieceImageSlice(StyleResolverState&,
536 const CSSValue& value,
537 NinePieceImage& image) {
538 if (!IsA<cssvalue::CSSBorderImageSliceValue>(value))
539 return;
540
541 // Retrieve the border image value.
542 const auto& border_image_slice =
543 To<cssvalue::CSSBorderImageSliceValue>(value);
544
545 // Set up a length box to represent our image slices.
546 LengthBox box;
547 const CSSQuadValue& slices = border_image_slice.Slices();
548 box.top_ = ConvertBorderImageSliceSide(To<CSSPrimitiveValue>(*slices.Top()));
549 box.bottom_ =
550 ConvertBorderImageSliceSide(To<CSSPrimitiveValue>(*slices.Bottom()));
551 box.left_ =
552 ConvertBorderImageSliceSide(To<CSSPrimitiveValue>(*slices.Left()));
553 box.right_ =
554 ConvertBorderImageSliceSide(To<CSSPrimitiveValue>(*slices.Right()));
555 image.SetImageSlices(box);
556
557 // Set our fill mode.
558 image.SetFill(border_image_slice.Fill());
559 }
560
ToBorderImageLength(const StyleResolverState & state,const CSSValue & value)561 static BorderImageLength ToBorderImageLength(const StyleResolverState& state,
562 const CSSValue& value) {
563 if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
564 if (primitive_value->IsNumber())
565 return primitive_value->GetDoubleValue();
566 }
567 return StyleBuilderConverter::ConvertLengthOrAuto(state, value);
568 }
569
MapNinePieceImageQuad(StyleResolverState & state,const CSSValue & value)570 BorderImageLengthBox CSSToStyleMap::MapNinePieceImageQuad(
571 StyleResolverState& state,
572 const CSSValue& value) {
573 const auto* slices = DynamicTo<CSSQuadValue>(value);
574 if (!slices)
575 return BorderImageLengthBox(Length::Auto());
576
577 // Set up a border image length box to represent our image slices.
578 return BorderImageLengthBox(ToBorderImageLength(state, *slices->Top()),
579 ToBorderImageLength(state, *slices->Right()),
580 ToBorderImageLength(state, *slices->Bottom()),
581 ToBorderImageLength(state, *slices->Left()));
582 }
583
MapNinePieceImageRepeat(StyleResolverState &,const CSSValue & value,NinePieceImage & image)584 void CSSToStyleMap::MapNinePieceImageRepeat(StyleResolverState&,
585 const CSSValue& value,
586 NinePieceImage& image) {
587 const auto* pair = DynamicTo<CSSValuePair>(value);
588 if (!pair)
589 return;
590
591 CSSValueID first_identifier =
592 To<CSSIdentifierValue>(pair->First()).GetValueID();
593 CSSValueID second_identifier =
594 To<CSSIdentifierValue>(pair->Second()).GetValueID();
595
596 ENinePieceImageRule horizontal_rule;
597 switch (first_identifier) {
598 case CSSValueID::kStretch:
599 horizontal_rule = kStretchImageRule;
600 break;
601 case CSSValueID::kRound:
602 horizontal_rule = kRoundImageRule;
603 break;
604 case CSSValueID::kSpace:
605 horizontal_rule = kSpaceImageRule;
606 break;
607 default: // CSSValueID::kRepeat
608 horizontal_rule = kRepeatImageRule;
609 break;
610 }
611 image.SetHorizontalRule(horizontal_rule);
612
613 ENinePieceImageRule vertical_rule;
614 switch (second_identifier) {
615 case CSSValueID::kStretch:
616 vertical_rule = kStretchImageRule;
617 break;
618 case CSSValueID::kRound:
619 vertical_rule = kRoundImageRule;
620 break;
621 case CSSValueID::kSpace:
622 vertical_rule = kSpaceImageRule;
623 break;
624 default: // CSSValueID::kRepeat
625 vertical_rule = kRepeatImageRule;
626 break;
627 }
628 image.SetVerticalRule(vertical_rule);
629 }
630
631 } // namespace blink
632