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