1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
6 
7 #include "third_party/blink/renderer/core/css/basic_shape_functions.h"
8 #include "third_party/blink/renderer/core/css/css_border_image.h"
9 #include "third_party/blink/renderer/core/css/css_border_image_slice_value.h"
10 #include "third_party/blink/renderer/core/css/css_color_value.h"
11 #include "third_party/blink/renderer/core/css/css_counter_value.h"
12 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
13 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
14 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
15 #include "third_party/blink/renderer/core/css/css_function_value.h"
16 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
17 #include "third_party/blink/renderer/core/css/css_grid_line_names_value.h"
18 #include "third_party/blink/renderer/core/css/css_initial_value.h"
19 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
20 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
21 #include "third_party/blink/renderer/core/css/css_quad_value.h"
22 #include "third_party/blink/renderer/core/css/css_reflect_value.h"
23 #include "third_party/blink/renderer/core/css/css_shadow_value.h"
24 #include "third_party/blink/renderer/core/css/css_string_value.h"
25 #include "third_party/blink/renderer/core/css/css_timing_function_value.h"
26 #include "third_party/blink/renderer/core/css/css_uri_value.h"
27 #include "third_party/blink/renderer/core/css/css_value.h"
28 #include "third_party/blink/renderer/core/css/css_value_list.h"
29 #include "third_party/blink/renderer/core/css/css_value_pair.h"
30 #include "third_party/blink/renderer/core/css/cssom/cross_thread_color_value.h"
31 #include "third_party/blink/renderer/core/css/cssom/cross_thread_keyword_value.h"
32 #include "third_party/blink/renderer/core/css/cssom/cross_thread_unit_value.h"
33 #include "third_party/blink/renderer/core/css/cssom/cross_thread_unparsed_value.h"
34 #include "third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h"
35 #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h"
36 #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h"
37 #include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h"
38 #include "third_party/blink/renderer/core/css/cssom/css_unsupported_color_value.h"
39 #include "third_party/blink/renderer/core/css/style_color.h"
40 #include "third_party/blink/renderer/core/layout/layout_block.h"
41 #include "third_party/blink/renderer/core/layout/layout_box.h"
42 #include "third_party/blink/renderer/core/layout/layout_grid.h"
43 #include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
44 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
45 #include "third_party/blink/renderer/core/style/style_svg_resource.h"
46 #include "third_party/blink/renderer/core/style_property_shorthand.h"
47 #include "third_party/blink/renderer/core/svg_element_type_helpers.h"
48 #include "third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h"
49 #include "third_party/blink/renderer/platform/transforms/matrix_transform_operation.h"
50 #include "third_party/blink/renderer/platform/transforms/perspective_transform_operation.h"
51 #include "third_party/blink/renderer/platform/transforms/skew_transform_operation.h"
52 
53 namespace blink {
54 
55 // TODO(rjwright): make this const
ZoomAdjustedPixelValueForLength(const Length & length,const ComputedStyle & style)56 CSSValue* ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
57     const Length& length,
58     const ComputedStyle& style) {
59   if (length.IsFixed())
60     return ZoomAdjustedPixelValue(length.Value(), style);
61   return CSSValue::Create(length, style.EffectiveZoom());
62 }
63 
ValueForPosition(const LengthPoint & position,const ComputedStyle & style)64 CSSValue* ComputedStyleUtils::ValueForPosition(const LengthPoint& position,
65                                                const ComputedStyle& style) {
66   DCHECK_EQ(position.X().IsAuto(), position.Y().IsAuto());
67   if (position.X().IsAuto())
68     return CSSIdentifierValue::Create(CSSValueID::kAuto);
69 
70   return MakeGarbageCollected<CSSValuePair>(
71       ZoomAdjustedPixelValueForLength(position.X(), style),
72       ZoomAdjustedPixelValueForLength(position.Y(), style),
73       CSSValuePair::kKeepIdenticalValues);
74 }
75 
ValueForOffset(const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)76 CSSValue* ComputedStyleUtils::ValueForOffset(const ComputedStyle& style,
77                                              const LayoutObject* layout_object,
78                                              bool allow_visited_style) {
79   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
80   if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
81     CSSValue* position = ValueForPosition(style.OffsetPosition(), style);
82     auto* position_identifier_value = DynamicTo<CSSIdentifierValue>(position);
83     if (!position_identifier_value)
84       list->Append(*position);
85     else
86       DCHECK(position_identifier_value->GetValueID() == CSSValueID::kAuto);
87   }
88 
89   static const CSSProperty* longhands[3] = {&GetCSSPropertyOffsetPath(),
90                                             &GetCSSPropertyOffsetDistance(),
91                                             &GetCSSPropertyOffsetRotate()};
92   for (const CSSProperty* longhand : longhands) {
93     const CSSValue* value = longhand->CSSValueFromComputedStyle(
94         style, layout_object, allow_visited_style);
95     DCHECK(value);
96     list->Append(*value);
97   }
98 
99   if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
100     CSSValue* anchor = ValueForPosition(style.OffsetAnchor(), style);
101     auto* anchor_identifier_value = DynamicTo<CSSIdentifierValue>(anchor);
102     if (!anchor_identifier_value) {
103       // Add a slash before anchor.
104       CSSValueList* result = CSSValueList::CreateSlashSeparated();
105       result->Append(*list);
106       result->Append(*anchor);
107       return result;
108     }
109     DCHECK(anchor_identifier_value->GetValueID() == CSSValueID::kAuto);
110   }
111   return list;
112 }
113 
CurrentColorOrValidColor(const ComputedStyle & style,const StyleColor & color)114 CSSValue* ComputedStyleUtils::CurrentColorOrValidColor(
115     const ComputedStyle& style,
116     const StyleColor& color) {
117   // This function does NOT look at visited information, so that computed style
118   // doesn't expose that.
119   return cssvalue::CSSColorValue::Create(color.Resolve(style.GetColor()).Rgb());
120 }
121 
BorderSideColor(const ComputedStyle & style,const StyleColor & color,EBorderStyle border_style,bool visited_link)122 const blink::Color ComputedStyleUtils::BorderSideColor(
123     const ComputedStyle& style,
124     const StyleColor& color,
125     EBorderStyle border_style,
126     bool visited_link) {
127   if (!color.IsCurrentColor())
128     return color.GetColor();
129   // FIXME: Treating styled borders with initial color differently causes
130   // problems, see crbug.com/316559, crbug.com/276231
131   if (!visited_link && (border_style == EBorderStyle::kInset ||
132                         border_style == EBorderStyle::kOutset ||
133                         border_style == EBorderStyle::kRidge ||
134                         border_style == EBorderStyle::kGroove))
135     return blink::Color(238, 238, 238);
136   return visited_link ? style.InternalVisitedColor() : style.GetColor();
137 }
138 
BackgroundImageOrWebkitMaskImage(const ComputedStyle & style,bool allow_visited_style,const FillLayer & fill_layer)139 const CSSValue* ComputedStyleUtils::BackgroundImageOrWebkitMaskImage(
140     const ComputedStyle& style,
141     bool allow_visited_style,
142     const FillLayer& fill_layer) {
143   CSSValueList* list = CSSValueList::CreateCommaSeparated();
144   const FillLayer* curr_layer = &fill_layer;
145   for (; curr_layer; curr_layer = curr_layer->Next()) {
146     if (curr_layer->GetImage()) {
147       list->Append(*curr_layer->GetImage()->ComputedCSSValue(
148           style, allow_visited_style));
149     } else {
150       list->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
151     }
152   }
153   return list;
154 }
155 
ValueForFillSize(const FillSize & fill_size,const ComputedStyle & style)156 const CSSValue* ComputedStyleUtils::ValueForFillSize(
157     const FillSize& fill_size,
158     const ComputedStyle& style) {
159   if (fill_size.type == EFillSizeType::kContain)
160     return CSSIdentifierValue::Create(CSSValueID::kContain);
161 
162   if (fill_size.type == EFillSizeType::kCover)
163     return CSSIdentifierValue::Create(CSSValueID::kCover);
164 
165   if (fill_size.size.Height().IsAuto()) {
166     return ZoomAdjustedPixelValueForLength(fill_size.size.Width(), style);
167   }
168 
169   return MakeGarbageCollected<CSSValuePair>(
170       ZoomAdjustedPixelValueForLength(fill_size.size.Width(), style),
171       ZoomAdjustedPixelValueForLength(fill_size.size.Height(), style),
172       CSSValuePair::kKeepIdenticalValues);
173 }
174 
BackgroundImageOrWebkitMaskSize(const ComputedStyle & style,const FillLayer & fill_layer)175 const CSSValue* ComputedStyleUtils::BackgroundImageOrWebkitMaskSize(
176     const ComputedStyle& style,
177     const FillLayer& fill_layer) {
178   CSSValueList* list = CSSValueList::CreateCommaSeparated();
179   const FillLayer* curr_layer = &fill_layer;
180   for (; curr_layer; curr_layer = curr_layer->Next())
181     list->Append(*ValueForFillSize(curr_layer->Size(), style));
182   return list;
183 }
184 
CreatePositionListForLayer(const CSSProperty & property,const FillLayer & layer,const ComputedStyle & style)185 const CSSValueList* ComputedStyleUtils::CreatePositionListForLayer(
186     const CSSProperty& property,
187     const FillLayer& layer,
188     const ComputedStyle& style) {
189   CSSValueList* position_list = CSSValueList::CreateSpaceSeparated();
190   if (layer.IsBackgroundXOriginSet()) {
191     DCHECK(property.IDEquals(CSSPropertyID::kBackgroundPosition) ||
192            property.IDEquals(CSSPropertyID::kWebkitMaskPosition));
193     position_list->Append(
194         *CSSIdentifierValue::Create(layer.BackgroundXOrigin()));
195   }
196   position_list->Append(
197       *ZoomAdjustedPixelValueForLength(layer.PositionX(), style));
198   if (layer.IsBackgroundYOriginSet()) {
199     DCHECK(property.IDEquals(CSSPropertyID::kBackgroundPosition) ||
200            property.IDEquals(CSSPropertyID::kWebkitMaskPosition));
201     position_list->Append(
202         *CSSIdentifierValue::Create(layer.BackgroundYOrigin()));
203   }
204   position_list->Append(
205       *ZoomAdjustedPixelValueForLength(layer.PositionY(), style));
206   return position_list;
207 }
208 
ValueForFillRepeat(EFillRepeat x_repeat,EFillRepeat y_repeat)209 const CSSValue* ComputedStyleUtils::ValueForFillRepeat(EFillRepeat x_repeat,
210                                                        EFillRepeat y_repeat) {
211   // For backwards compatibility, if both values are equal, just return one of
212   // them. And if the two values are equivalent to repeat-x or repeat-y, just
213   // return the shorthand.
214   if (x_repeat == y_repeat)
215     return CSSIdentifierValue::Create(x_repeat);
216   if (x_repeat == EFillRepeat::kRepeatFill &&
217       y_repeat == EFillRepeat::kNoRepeatFill)
218     return CSSIdentifierValue::Create(CSSValueID::kRepeatX);
219   if (x_repeat == EFillRepeat::kNoRepeatFill &&
220       y_repeat == EFillRepeat::kRepeatFill)
221     return CSSIdentifierValue::Create(CSSValueID::kRepeatY);
222 
223   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
224   list->Append(*CSSIdentifierValue::Create(x_repeat));
225   list->Append(*CSSIdentifierValue::Create(y_repeat));
226   return list;
227 }
228 
ValuesForBackgroundShorthand(const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)229 const CSSValueList* ComputedStyleUtils::ValuesForBackgroundShorthand(
230     const ComputedStyle& style,
231     const LayoutObject* layout_object,
232     bool allow_visited_style) {
233   CSSValueList* result = CSSValueList::CreateCommaSeparated();
234   const FillLayer* curr_layer = &style.BackgroundLayers();
235   for (; curr_layer; curr_layer = curr_layer->Next()) {
236     CSSValueList* list = CSSValueList::CreateSlashSeparated();
237     CSSValueList* before_slash = CSSValueList::CreateSpaceSeparated();
238     if (!curr_layer->Next()) {  // color only for final layer
239       const CSSValue* value =
240           GetCSSPropertyBackgroundColor().CSSValueFromComputedStyle(
241               style, layout_object, allow_visited_style);
242       DCHECK(value);
243       before_slash->Append(*value);
244     }
245     before_slash->Append(curr_layer->GetImage()
246                              ? *curr_layer->GetImage()->ComputedCSSValue(
247                                    style, allow_visited_style)
248                              : *CSSIdentifierValue::Create(CSSValueID::kNone));
249     before_slash->Append(
250         *ValueForFillRepeat(curr_layer->RepeatX(), curr_layer->RepeatY()));
251     before_slash->Append(*CSSIdentifierValue::Create(curr_layer->Attachment()));
252     before_slash->Append(*CreatePositionListForLayer(
253         GetCSSPropertyBackgroundPosition(), *curr_layer, style));
254     list->Append(*before_slash);
255     CSSValueList* after_slash = CSSValueList::CreateSpaceSeparated();
256     after_slash->Append(*ValueForFillSize(curr_layer->Size(), style));
257     after_slash->Append(*CSSIdentifierValue::Create(curr_layer->Origin()));
258     after_slash->Append(*CSSIdentifierValue::Create(curr_layer->Clip()));
259     list->Append(*after_slash);
260     result->Append(*list);
261   }
262   return result;
263 }
264 
BackgroundRepeatOrWebkitMaskRepeat(const FillLayer * curr_layer)265 const CSSValue* ComputedStyleUtils::BackgroundRepeatOrWebkitMaskRepeat(
266     const FillLayer* curr_layer) {
267   CSSValueList* list = CSSValueList::CreateCommaSeparated();
268   for (; curr_layer; curr_layer = curr_layer->Next()) {
269     list->Append(
270         *ValueForFillRepeat(curr_layer->RepeatX(), curr_layer->RepeatY()));
271   }
272   return list;
273 }
274 
BackgroundPositionOrWebkitMaskPosition(const CSSProperty & resolved_property,const ComputedStyle & style,const FillLayer * curr_layer)275 const CSSValue* ComputedStyleUtils::BackgroundPositionOrWebkitMaskPosition(
276     const CSSProperty& resolved_property,
277     const ComputedStyle& style,
278     const FillLayer* curr_layer) {
279   CSSValueList* list = CSSValueList::CreateCommaSeparated();
280   for (; curr_layer; curr_layer = curr_layer->Next()) {
281     list->Append(
282         *CreatePositionListForLayer(resolved_property, *curr_layer, style));
283   }
284   return list;
285 }
286 
BackgroundPositionXOrWebkitMaskPositionX(const ComputedStyle & style,const FillLayer * curr_layer)287 const CSSValue* ComputedStyleUtils::BackgroundPositionXOrWebkitMaskPositionX(
288     const ComputedStyle& style,
289     const FillLayer* curr_layer) {
290   CSSValueList* list = CSSValueList::CreateCommaSeparated();
291   for (; curr_layer; curr_layer = curr_layer->Next()) {
292     const Length& from_edge = curr_layer->PositionX();
293     if (curr_layer->BackgroundXOrigin() == BackgroundEdgeOrigin::kRight) {
294       // TODO(crbug.com/610627): This should use two-value syntax once the
295       // parser accepts it.
296       list->Append(*ZoomAdjustedPixelValueForLength(
297           from_edge.SubtractFromOneHundredPercent(), style));
298     } else {
299       list->Append(*ZoomAdjustedPixelValueForLength(from_edge, style));
300     }
301   }
302   return list;
303 }
304 
BackgroundPositionYOrWebkitMaskPositionY(const ComputedStyle & style,const FillLayer * curr_layer)305 const CSSValue* ComputedStyleUtils::BackgroundPositionYOrWebkitMaskPositionY(
306     const ComputedStyle& style,
307     const FillLayer* curr_layer) {
308   CSSValueList* list = CSSValueList::CreateCommaSeparated();
309   for (; curr_layer; curr_layer = curr_layer->Next()) {
310     const Length& from_edge = curr_layer->PositionY();
311     if (curr_layer->BackgroundYOrigin() == BackgroundEdgeOrigin::kBottom) {
312       // TODO(crbug.com/610627): This should use two-value syntax once the
313       // parser accepts it.
314       list->Append(*ZoomAdjustedPixelValueForLength(
315           from_edge.SubtractFromOneHundredPercent(), style));
316     } else {
317       list->Append(*ZoomAdjustedPixelValueForLength(from_edge, style));
318     }
319   }
320   return list;
321 }
322 
323 cssvalue::CSSBorderImageSliceValue*
ValueForNinePieceImageSlice(const NinePieceImage & image)324 ComputedStyleUtils::ValueForNinePieceImageSlice(const NinePieceImage& image) {
325   // Create the slices.
326   CSSPrimitiveValue* top = nullptr;
327   CSSPrimitiveValue* right = nullptr;
328   CSSPrimitiveValue* bottom = nullptr;
329   CSSPrimitiveValue* left = nullptr;
330 
331   // TODO(alancutter): Make this code aware of calc lengths.
332   if (image.ImageSlices().Top().IsPercentOrCalc()) {
333     top = CSSNumericLiteralValue::Create(
334         image.ImageSlices().Top().Value(),
335         CSSPrimitiveValue::UnitType::kPercentage);
336   } else {
337     top = CSSNumericLiteralValue::Create(image.ImageSlices().Top().Value(),
338                                          CSSPrimitiveValue::UnitType::kNumber);
339   }
340 
341   if (image.ImageSlices().Right() == image.ImageSlices().Top() &&
342       image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
343       image.ImageSlices().Left() == image.ImageSlices().Top()) {
344     right = top;
345     bottom = top;
346     left = top;
347   } else {
348     if (image.ImageSlices().Right().IsPercentOrCalc()) {
349       right = CSSNumericLiteralValue::Create(
350           image.ImageSlices().Right().Value(),
351           CSSPrimitiveValue::UnitType::kPercentage);
352     } else {
353       right =
354           CSSNumericLiteralValue::Create(image.ImageSlices().Right().Value(),
355                                          CSSPrimitiveValue::UnitType::kNumber);
356     }
357 
358     if (image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
359         image.ImageSlices().Right() == image.ImageSlices().Left()) {
360       bottom = top;
361       left = right;
362     } else {
363       if (image.ImageSlices().Bottom().IsPercentOrCalc()) {
364         bottom = CSSNumericLiteralValue::Create(
365             image.ImageSlices().Bottom().Value(),
366             CSSPrimitiveValue::UnitType::kPercentage);
367       } else {
368         bottom = CSSNumericLiteralValue::Create(
369             image.ImageSlices().Bottom().Value(),
370             CSSPrimitiveValue::UnitType::kNumber);
371       }
372 
373       if (image.ImageSlices().Left() == image.ImageSlices().Right()) {
374         left = right;
375       } else {
376         if (image.ImageSlices().Left().IsPercentOrCalc()) {
377           left = CSSNumericLiteralValue::Create(
378               image.ImageSlices().Left().Value(),
379               CSSPrimitiveValue::UnitType::kPercentage);
380         } else {
381           left = CSSNumericLiteralValue::Create(
382               image.ImageSlices().Left().Value(),
383               CSSPrimitiveValue::UnitType::kNumber);
384         }
385       }
386     }
387   }
388 
389   return MakeGarbageCollected<cssvalue::CSSBorderImageSliceValue>(
390       MakeGarbageCollected<CSSQuadValue>(top, right, bottom, left,
391                                          CSSQuadValue::kSerializeAsQuad),
392       image.Fill());
393 }
394 
ValueForBorderImageLength(const BorderImageLength & border_image_length,const ComputedStyle & style)395 CSSValue* ValueForBorderImageLength(
396     const BorderImageLength& border_image_length,
397     const ComputedStyle& style) {
398   if (border_image_length.IsNumber()) {
399     return CSSNumericLiteralValue::Create(border_image_length.Number(),
400                                           CSSPrimitiveValue::UnitType::kNumber);
401   }
402   return CSSValue::Create(border_image_length.length(), style.EffectiveZoom());
403 }
404 
ValueForNinePieceImageQuad(const BorderImageLengthBox & box,const ComputedStyle & style)405 CSSQuadValue* ComputedStyleUtils::ValueForNinePieceImageQuad(
406     const BorderImageLengthBox& box,
407     const ComputedStyle& style) {
408   // Create the slices.
409   CSSValue* top = nullptr;
410   CSSValue* right = nullptr;
411   CSSValue* bottom = nullptr;
412   CSSValue* left = nullptr;
413 
414   top = ValueForBorderImageLength(box.Top(), style);
415 
416   if (box.Right() == box.Top() && box.Bottom() == box.Top() &&
417       box.Left() == box.Top()) {
418     right = top;
419     bottom = top;
420     left = top;
421   } else {
422     right = ValueForBorderImageLength(box.Right(), style);
423 
424     if (box.Bottom() == box.Top() && box.Right() == box.Left()) {
425       bottom = top;
426       left = right;
427     } else {
428       bottom = ValueForBorderImageLength(box.Bottom(), style);
429 
430       if (box.Left() == box.Right())
431         left = right;
432       else
433         left = ValueForBorderImageLength(box.Left(), style);
434     }
435   }
436   return MakeGarbageCollected<CSSQuadValue>(top, right, bottom, left,
437                                             CSSQuadValue::kSerializeAsQuad);
438 }
439 
ValueForRepeatRule(int rule)440 CSSValueID ValueForRepeatRule(int rule) {
441   switch (rule) {
442     case kRepeatImageRule:
443       return CSSValueID::kRepeat;
444     case kRoundImageRule:
445       return CSSValueID::kRound;
446     case kSpaceImageRule:
447       return CSSValueID::kSpace;
448     default:
449       return CSSValueID::kStretch;
450   }
451 }
452 
ValueForNinePieceImageRepeat(const NinePieceImage & image)453 CSSValue* ComputedStyleUtils::ValueForNinePieceImageRepeat(
454     const NinePieceImage& image) {
455   CSSIdentifierValue* horizontal_repeat = nullptr;
456   CSSIdentifierValue* vertical_repeat = nullptr;
457 
458   horizontal_repeat =
459       CSSIdentifierValue::Create(ValueForRepeatRule(image.HorizontalRule()));
460   if (image.HorizontalRule() == image.VerticalRule()) {
461     vertical_repeat = horizontal_repeat;
462   } else {
463     vertical_repeat =
464         CSSIdentifierValue::Create(ValueForRepeatRule(image.VerticalRule()));
465   }
466   return MakeGarbageCollected<CSSValuePair>(horizontal_repeat, vertical_repeat,
467                                             CSSValuePair::kDropIdenticalValues);
468 }
469 
ValueForNinePieceImage(const NinePieceImage & image,const ComputedStyle & style,bool allow_visited_style)470 CSSValue* ComputedStyleUtils::ValueForNinePieceImage(
471     const NinePieceImage& image,
472     const ComputedStyle& style,
473     bool allow_visited_style) {
474   if (!image.HasImage())
475     return CSSIdentifierValue::Create(CSSValueID::kNone);
476 
477   // Image first.
478   CSSValue* image_value = nullptr;
479   if (image.GetImage()) {
480     image_value =
481         image.GetImage()->ComputedCSSValue(style, allow_visited_style);
482   }
483 
484   // Create the image slice.
485   cssvalue::CSSBorderImageSliceValue* image_slices =
486       ValueForNinePieceImageSlice(image);
487 
488   // Create the border area slices.
489   CSSValue* border_slices =
490       ValueForNinePieceImageQuad(image.BorderSlices(), style);
491 
492   // Create the border outset.
493   CSSValue* outset = ValueForNinePieceImageQuad(image.Outset(), style);
494 
495   // Create the repeat rules.
496   CSSValue* repeat = ValueForNinePieceImageRepeat(image);
497 
498   return CreateBorderImageValue(image_value, image_slices, border_slices,
499                                 outset, repeat);
500 }
501 
ValueForReflection(const StyleReflection * reflection,const ComputedStyle & style,bool allow_visited_style)502 CSSValue* ComputedStyleUtils::ValueForReflection(
503     const StyleReflection* reflection,
504     const ComputedStyle& style,
505     bool allow_visited_style) {
506   if (!reflection)
507     return CSSIdentifierValue::Create(CSSValueID::kNone);
508 
509   CSSPrimitiveValue* offset = nullptr;
510   // TODO(alancutter): Make this work correctly for calc lengths.
511   if (reflection->Offset().IsPercentOrCalc()) {
512     offset = CSSNumericLiteralValue::Create(
513         reflection->Offset().Percent(),
514         CSSPrimitiveValue::UnitType::kPercentage);
515   } else {
516     offset = ZoomAdjustedPixelValue(reflection->Offset().Value(), style);
517   }
518 
519   CSSIdentifierValue* direction = nullptr;
520   switch (reflection->Direction()) {
521     case kReflectionBelow:
522       direction = CSSIdentifierValue::Create(CSSValueID::kBelow);
523       break;
524     case kReflectionAbove:
525       direction = CSSIdentifierValue::Create(CSSValueID::kAbove);
526       break;
527     case kReflectionLeft:
528       direction = CSSIdentifierValue::Create(CSSValueID::kLeft);
529       break;
530     case kReflectionRight:
531       direction = CSSIdentifierValue::Create(CSSValueID::kRight);
532       break;
533   }
534 
535   return MakeGarbageCollected<cssvalue::CSSReflectValue>(
536       direction, offset,
537       ValueForNinePieceImage(reflection->Mask(), style, allow_visited_style));
538 }
539 
MinWidthOrMinHeightAuto(const ComputedStyle & style)540 CSSValue* ComputedStyleUtils::MinWidthOrMinHeightAuto(
541     const ComputedStyle& style) {
542   if (style.IsFlexOrGridOrCustomItem() && !style.IsEnsuredInDisplayNone())
543     return CSSIdentifierValue::Create(CSSValueID::kAuto);
544   return ZoomAdjustedPixelValue(0, style);
545 }
546 
ValueForPositionOffset(const ComputedStyle & style,const CSSProperty & property,const LayoutObject * layout_object)547 CSSValue* ComputedStyleUtils::ValueForPositionOffset(
548     const ComputedStyle& style,
549     const CSSProperty& property,
550     const LayoutObject* layout_object) {
551   std::pair<const Length*, const Length*> positions;
552   bool is_horizontal_property;
553   switch (property.PropertyID()) {
554     case CSSPropertyID::kLeft:
555       positions = std::make_pair(&style.Left(), &style.Right());
556       is_horizontal_property = true;
557       break;
558     case CSSPropertyID::kRight:
559       positions = std::make_pair(&style.Right(), &style.Left());
560       is_horizontal_property = true;
561       break;
562     case CSSPropertyID::kTop:
563       positions = std::make_pair(&style.Top(), &style.Bottom());
564       is_horizontal_property = false;
565       break;
566     case CSSPropertyID::kBottom:
567       positions = std::make_pair(&style.Bottom(), &style.Top());
568       is_horizontal_property = false;
569       break;
570     default:
571       NOTREACHED();
572       return nullptr;
573   }
574   DCHECK(positions.first && positions.second);
575 
576   const Length& offset = *positions.first;
577   const Length& opposite = *positions.second;
578 
579   if (offset.IsPercentOrCalc() && layout_object && layout_object->IsBox() &&
580       layout_object->IsPositioned()) {
581     LayoutUnit containing_block_size;
582     if (layout_object->IsStickyPositioned()) {
583       const LayoutBox& enclosing_scrollport_box =
584           ToLayoutBox(layout_object)->EnclosingScrollportBox();
585       bool use_inline_size = is_horizontal_property ==
586                              enclosing_scrollport_box.IsHorizontalWritingMode();
587       containing_block_size =
588           use_inline_size ? enclosing_scrollport_box.ContentLogicalWidth()
589                           : enclosing_scrollport_box.ContentLogicalHeight();
590     } else {
591       containing_block_size =
592           is_horizontal_property ==
593                   layout_object->ContainingBlock()->IsHorizontalWritingMode()
594               ? ToLayoutBox(layout_object)
595                     ->ContainingBlockLogicalWidthForContent()
596               : ToLayoutBox(layout_object)
597                     ->ContainingBlockLogicalHeightForGetComputedStyle();
598     }
599 
600     return ZoomAdjustedPixelValue(ValueForLength(offset, containing_block_size),
601                                   style);
602   }
603 
604   if (offset.IsAuto() && layout_object) {
605     // If the property applies to a positioned element and the resolved value of
606     // the display property is not none, the resolved value is the used value.
607     // Position offsets have special meaning for position sticky so we return
608     // auto when offset.isAuto() on a sticky position object:
609     // https://crbug.com/703816.
610     if (layout_object->IsRelPositioned()) {
611       // If e.g. left is auto and right is not auto, then left's computed value
612       // is negative right. So we get the opposite length unit and see if it is
613       // auto.
614       if (opposite.IsAuto()) {
615         return CSSNumericLiteralValue::Create(
616             0, CSSPrimitiveValue::UnitType::kPixels);
617       }
618 
619       if (opposite.IsPercentOrCalc()) {
620         if (layout_object->IsBox()) {
621           LayoutUnit containing_block_size =
622               is_horizontal_property == layout_object->ContainingBlock()
623                                             ->IsHorizontalWritingMode()
624                   ? ToLayoutBox(layout_object)
625                         ->ContainingBlockLogicalWidthForContent()
626                   : ToLayoutBox(layout_object)
627                         ->ContainingBlockLogicalHeightForGetComputedStyle();
628           return ZoomAdjustedPixelValue(
629               -FloatValueForLength(opposite, containing_block_size), style);
630         }
631         // FIXME:  fall back to auto for position:relative, display:inline
632         return CSSIdentifierValue::Create(CSSValueID::kAuto);
633       }
634 
635       // Length doesn't provide operator -, so multiply by -1.
636       Length negated_opposite = opposite;
637       negated_opposite *= -1.f;
638       return ZoomAdjustedPixelValueForLength(negated_opposite, style);
639     }
640 
641     if (layout_object->IsOutOfFlowPositioned() && layout_object->IsBox()) {
642       // For fixed and absolute positioned elements, the top, left, bottom, and
643       // right are defined relative to the corresponding sides of the containing
644       // block.
645       LayoutBlock* container = layout_object->ContainingBlock();
646       const LayoutBox* layout_box = ToLayoutBox(layout_object);
647 
648       // clientOffset is the distance from this object's border edge to the
649       // container's padding edge. Thus it includes margins which we subtract
650       // below.
651       const LayoutSize client_offset =
652           layout_box->LocationOffset() -
653           LayoutSize(container->ClientLeft(), container->ClientTop());
654       LayoutUnit position;
655 
656       switch (property.PropertyID()) {
657         case CSSPropertyID::kLeft:
658           position = client_offset.Width() - layout_box->MarginLeft();
659           break;
660         case CSSPropertyID::kTop:
661           position = client_offset.Height() - layout_box->MarginTop();
662           break;
663         case CSSPropertyID::kRight:
664           position = container->ClientWidth() - layout_box->MarginRight() -
665                      (layout_box->OffsetWidth() + client_offset.Width());
666           break;
667         case CSSPropertyID::kBottom:
668           position = container->ClientHeight() - layout_box->MarginBottom() -
669                      (layout_box->OffsetHeight() + client_offset.Height());
670           break;
671         default:
672           NOTREACHED();
673       }
674       return ZoomAdjustedPixelValue(position, style);
675     }
676   }
677 
678   if (offset.IsAuto())
679     return CSSIdentifierValue::Create(CSSValueID::kAuto);
680 
681   return ZoomAdjustedPixelValueForLength(offset, style);
682 }
683 
ValueForItemPositionWithOverflowAlignment(const StyleSelfAlignmentData & data)684 CSSValueList* ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment(
685     const StyleSelfAlignmentData& data) {
686   CSSValueList* result = CSSValueList::CreateSpaceSeparated();
687   if (data.PositionType() == ItemPositionType::kLegacy)
688     result->Append(*CSSIdentifierValue::Create(CSSValueID::kLegacy));
689   if (data.GetPosition() == ItemPosition::kBaseline) {
690     result->Append(*MakeGarbageCollected<CSSValuePair>(
691         CSSIdentifierValue::Create(CSSValueID::kBaseline),
692         CSSIdentifierValue::Create(CSSValueID::kBaseline),
693         CSSValuePair::kDropIdenticalValues));
694   } else if (data.GetPosition() == ItemPosition::kLastBaseline) {
695     result->Append(*MakeGarbageCollected<CSSValuePair>(
696         CSSIdentifierValue::Create(CSSValueID::kLast),
697         CSSIdentifierValue::Create(CSSValueID::kBaseline),
698         CSSValuePair::kDropIdenticalValues));
699   } else {
700     if (data.GetPosition() >= ItemPosition::kCenter &&
701         data.Overflow() != OverflowAlignment::kDefault)
702       result->Append(*CSSIdentifierValue::Create(data.Overflow()));
703     if (data.GetPosition() == ItemPosition::kLegacy)
704       result->Append(*CSSIdentifierValue::Create(CSSValueID::kNormal));
705     else
706       result->Append(*CSSIdentifierValue::Create(data.GetPosition()));
707   }
708   DCHECK_LE(result->length(), 2u);
709   return result;
710 }
711 
712 CSSValueList*
ValueForContentPositionAndDistributionWithOverflowAlignment(const StyleContentAlignmentData & data)713 ComputedStyleUtils::ValueForContentPositionAndDistributionWithOverflowAlignment(
714     const StyleContentAlignmentData& data) {
715   CSSValueList* result = CSSValueList::CreateSpaceSeparated();
716   // Handle content-distribution values
717   if (data.Distribution() != ContentDistributionType::kDefault)
718     result->Append(*CSSIdentifierValue::Create(data.Distribution()));
719 
720   // Handle content-position values (either as fallback or actual value)
721   switch (data.GetPosition()) {
722     case ContentPosition::kNormal:
723       // Handle 'normal' value, not valid as content-distribution fallback.
724       if (data.Distribution() == ContentDistributionType::kDefault) {
725         result->Append(*CSSIdentifierValue::Create(CSSValueID::kNormal));
726       }
727       break;
728     case ContentPosition::kLastBaseline:
729       result->Append(*MakeGarbageCollected<CSSValuePair>(
730           CSSIdentifierValue::Create(CSSValueID::kLast),
731           CSSIdentifierValue::Create(CSSValueID::kBaseline),
732           CSSValuePair::kDropIdenticalValues));
733       break;
734     default:
735       // Handle overflow-alignment (only allowed for content-position values)
736       if ((data.GetPosition() >= ContentPosition::kCenter ||
737            data.Distribution() != ContentDistributionType::kDefault) &&
738           data.Overflow() != OverflowAlignment::kDefault)
739         result->Append(*CSSIdentifierValue::Create(data.Overflow()));
740       result->Append(*CSSIdentifierValue::Create(data.GetPosition()));
741   }
742 
743   DCHECK_GT(result->length(), 0u);
744   DCHECK_LE(result->length(), 3u);
745   return result;
746 }
747 
ValueForLineHeight(const ComputedStyle & style)748 CSSValue* ComputedStyleUtils::ValueForLineHeight(const ComputedStyle& style) {
749   const Length& length = style.LineHeight();
750   if (length.IsNegative())
751     return CSSIdentifierValue::Create(CSSValueID::kNormal);
752 
753   return ZoomAdjustedPixelValue(
754       FloatValueForLength(length, style.GetFontDescription().ComputedSize()),
755       style);
756 }
757 
ComputedValueForLineHeight(const ComputedStyle & style)758 CSSValue* ComputedStyleUtils::ComputedValueForLineHeight(
759     const ComputedStyle& style) {
760   const Length& length = style.LineHeight();
761   if (length.IsNegative())
762     return CSSIdentifierValue::Create(CSSValueID::kNormal);
763 
764   if (length.IsPercent()) {
765     return CSSNumericLiteralValue::Create(length.GetFloatValue() / 100.0,
766                                           CSSPrimitiveValue::UnitType::kNumber);
767   } else {
768     return ZoomAdjustedPixelValue(
769         FloatValueForLength(length, style.GetFontDescription().ComputedSize()),
770         style);
771   }
772 }
773 
IdentifierForFamily(const AtomicString & family)774 CSSValueID IdentifierForFamily(const AtomicString& family) {
775   if (family == font_family_names::kWebkitCursive)
776     return CSSValueID::kCursive;
777   if (family == font_family_names::kWebkitFantasy)
778     return CSSValueID::kFantasy;
779   if (family == font_family_names::kWebkitMonospace)
780     return CSSValueID::kMonospace;
781   if (family == font_family_names::kWebkitSansSerif)
782     return CSSValueID::kSansSerif;
783   if (family == font_family_names::kWebkitSerif)
784     return CSSValueID::kSerif;
785   return CSSValueID::kInvalid;
786 }
787 
ValueForFamily(const AtomicString & family)788 CSSValue* ValueForFamily(const AtomicString& family) {
789   CSSValueID family_identifier = IdentifierForFamily(family);
790   if (IsValidCSSValueID(family_identifier))
791     return CSSIdentifierValue::Create(family_identifier);
792   return CSSFontFamilyValue::Create(family.GetString());
793 }
794 
ValueForFontFamily(const ComputedStyle & style)795 CSSValueList* ComputedStyleUtils::ValueForFontFamily(
796     const ComputedStyle& style) {
797   const FontFamily& first_family = style.GetFontDescription().Family();
798   CSSValueList* list = CSSValueList::CreateCommaSeparated();
799   for (const FontFamily* family = &first_family; family;
800        family = family->Next())
801     list->Append(*ValueForFamily(family->Family()));
802   return list;
803 }
804 
ValueForFontSize(const ComputedStyle & style)805 CSSPrimitiveValue* ComputedStyleUtils::ValueForFontSize(
806     const ComputedStyle& style) {
807   return ZoomAdjustedPixelValue(style.GetFontDescription().ComputedSize(),
808                                 style);
809 }
810 
ValueForFontStretch(const ComputedStyle & style)811 CSSPrimitiveValue* ComputedStyleUtils::ValueForFontStretch(
812     const ComputedStyle& style) {
813   return CSSNumericLiteralValue::Create(
814       style.GetFontDescription().Stretch(),
815       CSSPrimitiveValue::UnitType::kPercentage);
816 }
817 
ValueForFontStyle(const ComputedStyle & style)818 CSSValue* ComputedStyleUtils::ValueForFontStyle(const ComputedStyle& style) {
819   FontSelectionValue angle = style.GetFontDescription().Style();
820   if (angle == NormalSlopeValue()) {
821     return CSSIdentifierValue::Create(CSSValueID::kNormal);
822   }
823 
824   if (angle == ItalicSlopeValue()) {
825     return CSSIdentifierValue::Create(CSSValueID::kItalic);
826   }
827 
828   // The spec says: 'The lack of a number represents an angle of
829   // "20deg"', but since we compute that to 'italic' (handled above),
830   // we don't perform any special treatment of that value here.
831   CSSValueList* oblique_values = CSSValueList::CreateSpaceSeparated();
832   oblique_values->Append(*CSSNumericLiteralValue::Create(
833       angle, CSSPrimitiveValue::UnitType::kDegrees));
834   return MakeGarbageCollected<cssvalue::CSSFontStyleRangeValue>(
835       *CSSIdentifierValue::Create(CSSValueID::kOblique), *oblique_values);
836 }
837 
ValueForFontWeight(const ComputedStyle & style)838 CSSNumericLiteralValue* ComputedStyleUtils::ValueForFontWeight(
839     const ComputedStyle& style) {
840   return CSSNumericLiteralValue::Create(style.GetFontDescription().Weight(),
841                                         CSSPrimitiveValue::UnitType::kNumber);
842 }
843 
ValueForFontVariantCaps(const ComputedStyle & style)844 CSSIdentifierValue* ComputedStyleUtils::ValueForFontVariantCaps(
845     const ComputedStyle& style) {
846   FontDescription::FontVariantCaps variant_caps =
847       style.GetFontDescription().VariantCaps();
848   switch (variant_caps) {
849     case FontDescription::kCapsNormal:
850       return CSSIdentifierValue::Create(CSSValueID::kNormal);
851     case FontDescription::kSmallCaps:
852       return CSSIdentifierValue::Create(CSSValueID::kSmallCaps);
853     case FontDescription::kAllSmallCaps:
854       return CSSIdentifierValue::Create(CSSValueID::kAllSmallCaps);
855     case FontDescription::kPetiteCaps:
856       return CSSIdentifierValue::Create(CSSValueID::kPetiteCaps);
857     case FontDescription::kAllPetiteCaps:
858       return CSSIdentifierValue::Create(CSSValueID::kAllPetiteCaps);
859     case FontDescription::kUnicase:
860       return CSSIdentifierValue::Create(CSSValueID::kUnicase);
861     case FontDescription::kTitlingCaps:
862       return CSSIdentifierValue::Create(CSSValueID::kTitlingCaps);
863     default:
864       NOTREACHED();
865       return nullptr;
866   }
867 }
868 
ValueForFontVariantLigatures(const ComputedStyle & style)869 CSSValue* ComputedStyleUtils::ValueForFontVariantLigatures(
870     const ComputedStyle& style) {
871   FontDescription::LigaturesState common_ligatures_state =
872       style.GetFontDescription().CommonLigaturesState();
873   FontDescription::LigaturesState discretionary_ligatures_state =
874       style.GetFontDescription().DiscretionaryLigaturesState();
875   FontDescription::LigaturesState historical_ligatures_state =
876       style.GetFontDescription().HistoricalLigaturesState();
877   FontDescription::LigaturesState contextual_ligatures_state =
878       style.GetFontDescription().ContextualLigaturesState();
879   if (common_ligatures_state == FontDescription::kNormalLigaturesState &&
880       discretionary_ligatures_state == FontDescription::kNormalLigaturesState &&
881       historical_ligatures_state == FontDescription::kNormalLigaturesState &&
882       contextual_ligatures_state == FontDescription::kNormalLigaturesState)
883     return CSSIdentifierValue::Create(CSSValueID::kNormal);
884 
885   if (common_ligatures_state == FontDescription::kDisabledLigaturesState &&
886       discretionary_ligatures_state ==
887           FontDescription::kDisabledLigaturesState &&
888       historical_ligatures_state == FontDescription::kDisabledLigaturesState &&
889       contextual_ligatures_state == FontDescription::kDisabledLigaturesState)
890     return CSSIdentifierValue::Create(CSSValueID::kNone);
891 
892   CSSValueList* value_list = CSSValueList::CreateSpaceSeparated();
893   if (common_ligatures_state != FontDescription::kNormalLigaturesState) {
894     value_list->Append(*CSSIdentifierValue::Create(
895         common_ligatures_state == FontDescription::kDisabledLigaturesState
896             ? CSSValueID::kNoCommonLigatures
897             : CSSValueID::kCommonLigatures));
898   }
899   if (discretionary_ligatures_state != FontDescription::kNormalLigaturesState) {
900     value_list->Append(*CSSIdentifierValue::Create(
901         discretionary_ligatures_state ==
902                 FontDescription::kDisabledLigaturesState
903             ? CSSValueID::kNoDiscretionaryLigatures
904             : CSSValueID::kDiscretionaryLigatures));
905   }
906   if (historical_ligatures_state != FontDescription::kNormalLigaturesState) {
907     value_list->Append(*CSSIdentifierValue::Create(
908         historical_ligatures_state == FontDescription::kDisabledLigaturesState
909             ? CSSValueID::kNoHistoricalLigatures
910             : CSSValueID::kHistoricalLigatures));
911   }
912   if (contextual_ligatures_state != FontDescription::kNormalLigaturesState) {
913     value_list->Append(*CSSIdentifierValue::Create(
914         contextual_ligatures_state == FontDescription::kDisabledLigaturesState
915             ? CSSValueID::kNoContextual
916             : CSSValueID::kContextual));
917   }
918   return value_list;
919 }
920 
ValueForFontVariantNumeric(const ComputedStyle & style)921 CSSValue* ComputedStyleUtils::ValueForFontVariantNumeric(
922     const ComputedStyle& style) {
923   FontVariantNumeric variant_numeric =
924       style.GetFontDescription().VariantNumeric();
925   if (variant_numeric.IsAllNormal())
926     return CSSIdentifierValue::Create(CSSValueID::kNormal);
927 
928   CSSValueList* value_list = CSSValueList::CreateSpaceSeparated();
929   if (variant_numeric.NumericFigureValue() !=
930       FontVariantNumeric::kNormalFigure) {
931     value_list->Append(*CSSIdentifierValue::Create(
932         variant_numeric.NumericFigureValue() == FontVariantNumeric::kLiningNums
933             ? CSSValueID::kLiningNums
934             : CSSValueID::kOldstyleNums));
935   }
936   if (variant_numeric.NumericSpacingValue() !=
937       FontVariantNumeric::kNormalSpacing) {
938     value_list->Append(*CSSIdentifierValue::Create(
939         variant_numeric.NumericSpacingValue() ==
940                 FontVariantNumeric::kProportionalNums
941             ? CSSValueID::kProportionalNums
942             : CSSValueID::kTabularNums));
943   }
944   if (variant_numeric.NumericFractionValue() !=
945       FontVariantNumeric::kNormalFraction) {
946     value_list->Append(*CSSIdentifierValue::Create(
947         variant_numeric.NumericFractionValue() ==
948                 FontVariantNumeric::kDiagonalFractions
949             ? CSSValueID::kDiagonalFractions
950             : CSSValueID::kStackedFractions));
951   }
952   if (variant_numeric.OrdinalValue() == FontVariantNumeric::kOrdinalOn)
953     value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kOrdinal));
954   if (variant_numeric.SlashedZeroValue() == FontVariantNumeric::kSlashedZeroOn)
955     value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kSlashedZero));
956 
957   return value_list;
958 }
959 
ValueForFontStretchAsKeyword(const ComputedStyle & style)960 CSSIdentifierValue* ValueForFontStretchAsKeyword(const ComputedStyle& style) {
961   FontSelectionValue stretch_value = style.GetFontDescription().Stretch();
962   CSSValueID value_id = CSSValueID::kInvalid;
963   if (stretch_value == UltraCondensedWidthValue())
964     value_id = CSSValueID::kUltraCondensed;
965   if (stretch_value == UltraCondensedWidthValue())
966     value_id = CSSValueID::kUltraCondensed;
967   if (stretch_value == ExtraCondensedWidthValue())
968     value_id = CSSValueID::kExtraCondensed;
969   if (stretch_value == CondensedWidthValue())
970     value_id = CSSValueID::kCondensed;
971   if (stretch_value == SemiCondensedWidthValue())
972     value_id = CSSValueID::kSemiCondensed;
973   if (stretch_value == NormalWidthValue())
974     value_id = CSSValueID::kNormal;
975   if (stretch_value == SemiExpandedWidthValue())
976     value_id = CSSValueID::kSemiExpanded;
977   if (stretch_value == ExpandedWidthValue())
978     value_id = CSSValueID::kExpanded;
979   if (stretch_value == ExtraExpandedWidthValue())
980     value_id = CSSValueID::kExtraExpanded;
981   if (stretch_value == UltraExpandedWidthValue())
982     value_id = CSSValueID::kUltraExpanded;
983 
984   if (IsValidCSSValueID(value_id))
985     return CSSIdentifierValue::Create(value_id);
986   return nullptr;
987 }
988 
ValueForFontVariantEastAsian(const ComputedStyle & style)989 CSSValue* ComputedStyleUtils::ValueForFontVariantEastAsian(
990     const ComputedStyle& style) {
991   FontVariantEastAsian east_asian =
992       style.GetFontDescription().VariantEastAsian();
993   if (east_asian.IsAllNormal())
994     return CSSIdentifierValue::Create(CSSValueID::kNormal);
995 
996   CSSValueList* value_list = CSSValueList::CreateSpaceSeparated();
997   switch (east_asian.Form()) {
998     case FontVariantEastAsian::kNormalForm:
999       break;
1000     case FontVariantEastAsian::kJis78:
1001       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kJis78));
1002       break;
1003     case FontVariantEastAsian::kJis83:
1004       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kJis83));
1005       break;
1006     case FontVariantEastAsian::kJis90:
1007       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kJis90));
1008       break;
1009     case FontVariantEastAsian::kJis04:
1010       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kJis04));
1011       break;
1012     case FontVariantEastAsian::kSimplified:
1013       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kSimplified));
1014       break;
1015     case FontVariantEastAsian::kTraditional:
1016       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kTraditional));
1017       break;
1018     default:
1019       NOTREACHED();
1020   }
1021   switch (east_asian.Width()) {
1022     case FontVariantEastAsian::kNormalWidth:
1023       break;
1024     case FontVariantEastAsian::kFullWidth:
1025       value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kFullWidth));
1026       break;
1027     case FontVariantEastAsian::kProportionalWidth:
1028       value_list->Append(
1029           *CSSIdentifierValue::Create(CSSValueID::kProportionalWidth));
1030       break;
1031     default:
1032       NOTREACHED();
1033   }
1034   if (east_asian.Ruby())
1035     value_list->Append(*CSSIdentifierValue::Create(CSSValueID::kRuby));
1036   return value_list;
1037 }
1038 
ValueForFont(const ComputedStyle & style)1039 CSSValue* ComputedStyleUtils::ValueForFont(const ComputedStyle& style) {
1040   auto AppendIfNotNormal = [](CSSValueList* list, const CSSValue& value) {
1041     auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1042     if (identifier_value &&
1043         identifier_value->GetValueID() == CSSValueID::kNormal) {
1044       return;
1045     }
1046 
1047     list->Append(value);
1048   };
1049 
1050   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1051   AppendIfNotNormal(list, *ValueForFontStyle(style));
1052 
1053   // Check that non-initial font-variant subproperties are not conflicting with
1054   // this serialization.
1055   CSSValue* ligatures_value = ValueForFontVariantLigatures(style);
1056   CSSValue* numeric_value = ValueForFontVariantNumeric(style);
1057   CSSValue* east_asian_value = ValueForFontVariantEastAsian(style);
1058   // FIXME: Use DataEquivalent<CSSValue>(...) once http://crbug.com/729447 is
1059   // resolved.
1060   if (!DataEquivalent(ligatures_value,
1061                       static_cast<CSSValue*>(
1062                           CSSIdentifierValue::Create(CSSValueID::kNormal))) ||
1063       !DataEquivalent(numeric_value,
1064                       static_cast<CSSValue*>(
1065                           CSSIdentifierValue::Create(CSSValueID::kNormal))) ||
1066       !DataEquivalent(east_asian_value,
1067                       static_cast<CSSValue*>(
1068                           CSSIdentifierValue::Create(CSSValueID::kNormal))))
1069     return nullptr;
1070 
1071   if (!ValueForFontStretchAsKeyword(style))
1072     return nullptr;
1073 
1074   CSSIdentifierValue* caps_value = ValueForFontVariantCaps(style);
1075   if (caps_value->GetValueID() != CSSValueID::kNormal &&
1076       caps_value->GetValueID() != CSSValueID::kSmallCaps)
1077     return nullptr;
1078   AppendIfNotNormal(list, *caps_value);
1079 
1080   {
1081     CSSNumericLiteralValue* font_weight = ValueForFontWeight(style);
1082     if (font_weight->DoubleValue() != NormalWeightValue())
1083       list->Append(*font_weight);
1084   }
1085 
1086   AppendIfNotNormal(list, *ValueForFontStretchAsKeyword(style));
1087 
1088   {
1089     CSSValue* line_height = ValueForLineHeight(style);
1090     auto* identifier_line_height = DynamicTo<CSSIdentifierValue>(line_height);
1091     if (identifier_line_height &&
1092         identifier_line_height->GetValueID() == CSSValueID::kNormal) {
1093       list->Append(*ValueForFontSize(style));
1094     } else {
1095       // Add a slash between size and line-height.
1096       CSSValueList* size_and_line_height = CSSValueList::CreateSlashSeparated();
1097       size_and_line_height->Append(*ValueForFontSize(style));
1098       size_and_line_height->Append(*line_height);
1099 
1100       list->Append(*size_and_line_height);
1101     }
1102   }
1103 
1104   list->Append(*ValueForFontFamily(style));
1105 
1106   return list;
1107 }
1108 
SpecifiedValueForGridTrackBreadth(const GridLength & track_breadth,const ComputedStyle & style)1109 CSSValue* SpecifiedValueForGridTrackBreadth(const GridLength& track_breadth,
1110                                             const ComputedStyle& style) {
1111   if (!track_breadth.IsLength()) {
1112     return CSSNumericLiteralValue::Create(
1113         track_breadth.Flex(), CSSPrimitiveValue::UnitType::kFraction);
1114   }
1115 
1116   const Length& track_breadth_length = track_breadth.length();
1117   if (track_breadth_length.IsAuto())
1118     return CSSIdentifierValue::Create(CSSValueID::kAuto);
1119   return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
1120       track_breadth_length, style);
1121 }
1122 
SpecifiedValueForGridTrackSize(const GridTrackSize & track_size,const ComputedStyle & style)1123 CSSValue* ComputedStyleUtils::SpecifiedValueForGridTrackSize(
1124     const GridTrackSize& track_size,
1125     const ComputedStyle& style) {
1126   switch (track_size.GetType()) {
1127     case kLengthTrackSizing:
1128       return SpecifiedValueForGridTrackBreadth(track_size.MinTrackBreadth(),
1129                                                style);
1130     case kMinMaxTrackSizing: {
1131       if (track_size.MinTrackBreadth().IsAuto() &&
1132           track_size.MaxTrackBreadth().IsFlex()) {
1133         return CSSNumericLiteralValue::Create(
1134             track_size.MaxTrackBreadth().Flex(),
1135             CSSPrimitiveValue::UnitType::kFraction);
1136       }
1137 
1138       auto* min_max_track_breadths =
1139           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kMinmax);
1140       min_max_track_breadths->Append(*SpecifiedValueForGridTrackBreadth(
1141           track_size.MinTrackBreadth(), style));
1142       min_max_track_breadths->Append(*SpecifiedValueForGridTrackBreadth(
1143           track_size.MaxTrackBreadth(), style));
1144       return min_max_track_breadths;
1145     }
1146     case kFitContentTrackSizing: {
1147       auto* fit_content_track_breadth =
1148           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kFitContent);
1149       fit_content_track_breadth->Append(*SpecifiedValueForGridTrackBreadth(
1150           track_size.FitContentTrackBreadth(), style));
1151       return fit_content_track_breadth;
1152     }
1153   }
1154   NOTREACHED();
1155   return nullptr;
1156 }
1157 
1158 class OrderedNamedLinesCollector {
1159   STACK_ALLOCATED();
1160 
1161  public:
OrderedNamedLinesCollector(const ComputedStyle & style,bool is_row_axis)1162   OrderedNamedLinesCollector(const ComputedStyle& style, bool is_row_axis)
1163       : ordered_named_grid_lines_(is_row_axis
1164                                       ? style.OrderedNamedGridColumnLines()
1165                                       : style.OrderedNamedGridRowLines()),
1166         ordered_named_auto_repeat_grid_lines_(
1167             is_row_axis ? style.AutoRepeatOrderedNamedGridColumnLines()
1168                         : style.AutoRepeatOrderedNamedGridRowLines()) {}
1169   virtual ~OrderedNamedLinesCollector() = default;
1170 
IsEmpty() const1171   bool IsEmpty() const {
1172     return ordered_named_grid_lines_.IsEmpty() &&
1173            ordered_named_auto_repeat_grid_lines_.IsEmpty();
1174   }
1175   virtual void CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue&,
1176                                         size_t index) const;
1177 
1178  protected:
1179   enum NamedLinesType { kNamedLines, kAutoRepeatNamedLines };
1180   void AppendLines(cssvalue::CSSGridLineNamesValue&,
1181                    size_t index,
1182                    NamedLinesType) const;
1183 
1184   const OrderedNamedGridLines& ordered_named_grid_lines_;
1185   const OrderedNamedGridLines& ordered_named_auto_repeat_grid_lines_;
1186   DISALLOW_COPY_AND_ASSIGN(OrderedNamedLinesCollector);
1187 };
1188 
1189 class OrderedNamedLinesCollectorInsideRepeat
1190     : public OrderedNamedLinesCollector {
1191  public:
OrderedNamedLinesCollectorInsideRepeat(const ComputedStyle & style,bool is_row_axis)1192   OrderedNamedLinesCollectorInsideRepeat(const ComputedStyle& style,
1193                                          bool is_row_axis)
1194       : OrderedNamedLinesCollector(style, is_row_axis) {}
1195   void CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue&,
1196                                 size_t index) const override;
1197 };
1198 
1199 class OrderedNamedLinesCollectorInGridLayout
1200     : public OrderedNamedLinesCollector {
1201  public:
OrderedNamedLinesCollectorInGridLayout(const ComputedStyle & style,bool is_row_axis,size_t auto_repeat_tracks_count,size_t auto_repeat_track_list_length)1202   OrderedNamedLinesCollectorInGridLayout(const ComputedStyle& style,
1203                                          bool is_row_axis,
1204                                          size_t auto_repeat_tracks_count,
1205                                          size_t auto_repeat_track_list_length)
1206       : OrderedNamedLinesCollector(style, is_row_axis),
1207         insertion_point_(is_row_axis
1208                              ? style.GridAutoRepeatColumnsInsertionPoint()
1209                              : style.GridAutoRepeatRowsInsertionPoint()),
1210         auto_repeat_total_tracks_(auto_repeat_tracks_count),
1211         auto_repeat_track_list_length_(auto_repeat_track_list_length) {}
1212   void CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue&,
1213                                 size_t index) const override;
1214 
1215  private:
1216   size_t insertion_point_;
1217   size_t auto_repeat_total_tracks_;
1218   size_t auto_repeat_track_list_length_;
1219 };
1220 
1221 // RJW
AppendLines(cssvalue::CSSGridLineNamesValue & line_names_value,size_t index,NamedLinesType type) const1222 void OrderedNamedLinesCollector::AppendLines(
1223     cssvalue::CSSGridLineNamesValue& line_names_value,
1224     size_t index,
1225     NamedLinesType type) const {
1226   auto iter = type == kNamedLines
1227                   ? ordered_named_grid_lines_.find(index)
1228                   : ordered_named_auto_repeat_grid_lines_.find(index);
1229   auto end_iter = type == kNamedLines
1230                       ? ordered_named_grid_lines_.end()
1231                       : ordered_named_auto_repeat_grid_lines_.end();
1232   if (iter == end_iter)
1233     return;
1234 
1235   for (auto line_name : iter->value) {
1236     line_names_value.Append(
1237         *MakeGarbageCollected<CSSCustomIdentValue>(AtomicString(line_name)));
1238   }
1239 }
1240 
CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue & line_names_value,size_t i) const1241 void OrderedNamedLinesCollector::CollectLineNamesForIndex(
1242     cssvalue::CSSGridLineNamesValue& line_names_value,
1243     size_t i) const {
1244   DCHECK(!IsEmpty());
1245   AppendLines(line_names_value, i, kNamedLines);
1246 }
1247 
CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue & line_names_value,size_t i) const1248 void OrderedNamedLinesCollectorInsideRepeat::CollectLineNamesForIndex(
1249     cssvalue::CSSGridLineNamesValue& line_names_value,
1250     size_t i) const {
1251   DCHECK(!IsEmpty());
1252   AppendLines(line_names_value, i, kAutoRepeatNamedLines);
1253 }
1254 
1255 // RJW
CollectLineNamesForIndex(cssvalue::CSSGridLineNamesValue & line_names_value,size_t i) const1256 void OrderedNamedLinesCollectorInGridLayout::CollectLineNamesForIndex(
1257     cssvalue::CSSGridLineNamesValue& line_names_value,
1258     size_t i) const {
1259   DCHECK(!IsEmpty());
1260   if (auto_repeat_track_list_length_ == 0LU || i < insertion_point_) {
1261     AppendLines(line_names_value, i, kNamedLines);
1262     return;
1263   }
1264 
1265   DCHECK(auto_repeat_total_tracks_);
1266 
1267   if (i > insertion_point_ + auto_repeat_total_tracks_) {
1268     AppendLines(line_names_value, i - (auto_repeat_total_tracks_ - 1),
1269                 kNamedLines);
1270     return;
1271   }
1272 
1273   if (i == insertion_point_) {
1274     AppendLines(line_names_value, i, kNamedLines);
1275     AppendLines(line_names_value, 0, kAutoRepeatNamedLines);
1276     return;
1277   }
1278 
1279   if (i == insertion_point_ + auto_repeat_total_tracks_) {
1280     AppendLines(line_names_value, auto_repeat_track_list_length_,
1281                 kAutoRepeatNamedLines);
1282     AppendLines(line_names_value, insertion_point_ + 1, kNamedLines);
1283     return;
1284   }
1285 
1286   size_t auto_repeat_index_in_first_repetition =
1287       (i - insertion_point_) % auto_repeat_track_list_length_;
1288   if (!auto_repeat_index_in_first_repetition && i > insertion_point_) {
1289     AppendLines(line_names_value, auto_repeat_track_list_length_,
1290                 kAutoRepeatNamedLines);
1291   }
1292   AppendLines(line_names_value, auto_repeat_index_in_first_repetition,
1293               kAutoRepeatNamedLines);
1294 }
1295 
AddValuesForNamedGridLinesAtIndex(OrderedNamedLinesCollector & collector,size_t i,CSSValueList & list)1296 void AddValuesForNamedGridLinesAtIndex(OrderedNamedLinesCollector& collector,
1297                                        size_t i,
1298                                        CSSValueList& list) {
1299   if (collector.IsEmpty())
1300     return;
1301 
1302   auto* line_names = MakeGarbageCollected<cssvalue::CSSGridLineNamesValue>();
1303   collector.CollectLineNamesForIndex(*line_names, i);
1304   if (line_names->length())
1305     list.Append(*line_names);
1306 }
1307 
ValueForGridTrackSizeList(GridTrackSizingDirection direction,const ComputedStyle & style)1308 CSSValue* ComputedStyleUtils::ValueForGridTrackSizeList(
1309     GridTrackSizingDirection direction,
1310     const ComputedStyle& style) {
1311   const Vector<GridTrackSize>& auto_track_sizes =
1312       direction == kForColumns ? style.GridAutoColumns() : style.GridAutoRows();
1313 
1314   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1315   for (auto& track_size : auto_track_sizes) {
1316     list->Append(*SpecifiedValueForGridTrackSize(track_size, style));
1317   }
1318   return list;
1319 }
1320 
1321 template <typename T, typename F>
PopulateGridTrackList(CSSValueList * list,OrderedNamedLinesCollector & collector,const Vector<T> & tracks,F getTrackSize,wtf_size_t start,wtf_size_t end,size_t offset=0)1322 void PopulateGridTrackList(CSSValueList* list,
1323                            OrderedNamedLinesCollector& collector,
1324                            const Vector<T>& tracks,
1325                            F getTrackSize,
1326                            wtf_size_t start,
1327                            wtf_size_t end,
1328                            size_t offset = 0) {
1329   DCHECK_LE(end, tracks.size());
1330   for (wtf_size_t i = start; i < end; ++i) {
1331     AddValuesForNamedGridLinesAtIndex(collector, i + offset, *list);
1332     list->Append(*getTrackSize(tracks[i]));
1333   }
1334   AddValuesForNamedGridLinesAtIndex(collector, end + offset, *list);
1335 }
1336 
1337 template <typename T, typename F>
PopulateGridTrackList(CSSValueList * list,OrderedNamedLinesCollector & collector,const Vector<T> & tracks,F getTrackSize)1338 void PopulateGridTrackList(CSSValueList* list,
1339                            OrderedNamedLinesCollector& collector,
1340                            const Vector<T>& tracks,
1341                            F getTrackSize) {
1342   PopulateGridTrackList<T>(list, collector, tracks, getTrackSize, 0,
1343                            tracks.size());
1344 }
1345 
ValueForGridTrackList(GridTrackSizingDirection direction,const LayoutObject * layout_object,const ComputedStyle & style)1346 CSSValue* ComputedStyleUtils::ValueForGridTrackList(
1347     GridTrackSizingDirection direction,
1348     const LayoutObject* layout_object,
1349     const ComputedStyle& style) {
1350   bool is_row_axis = direction == kForColumns;
1351   const Vector<GridTrackSize>& track_sizes =
1352       is_row_axis ? style.GridTemplateColumns() : style.GridTemplateRows();
1353   const Vector<GridTrackSize>& auto_repeat_track_sizes =
1354       is_row_axis ? style.GridAutoRepeatColumns() : style.GridAutoRepeatRows();
1355   bool is_layout_grid = layout_object && layout_object->IsLayoutGrid();
1356 
1357   // Handle the 'none' case.
1358   bool track_list_is_empty =
1359       track_sizes.IsEmpty() && auto_repeat_track_sizes.IsEmpty();
1360   if (is_layout_grid && track_list_is_empty) {
1361     // For grids we should consider every listed track, whether implicitly or
1362     // explicitly created. Empty grids have a sole grid line per axis.
1363     auto& positions = is_row_axis
1364                           ? ToLayoutGrid(layout_object)->ColumnPositions()
1365                           : ToLayoutGrid(layout_object)->RowPositions();
1366     track_list_is_empty = positions.size() == 1;
1367   }
1368 
1369   if (track_list_is_empty)
1370     return CSSIdentifierValue::Create(CSSValueID::kNone);
1371 
1372   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1373 
1374   // If the element is a grid container, the resolved value is the used value,
1375   // specifying track sizes in pixels and expanding the repeat() notation.
1376   if (is_layout_grid) {
1377     const auto* grid = ToLayoutGrid(layout_object);
1378     OrderedNamedLinesCollectorInGridLayout collector(
1379         style, is_row_axis, grid->AutoRepeatCountForDirection(direction),
1380         auto_repeat_track_sizes.size());
1381     PopulateGridTrackList(
1382         list, collector, grid->TrackSizesForComputedStyle(direction),
1383         [&](const LayoutUnit& v) { return ZoomAdjustedPixelValue(v, style); });
1384     return list;
1385   }
1386 
1387   // Otherwise, the resolved value is the computed value, preserving repeat().
1388   OrderedNamedLinesCollector collector(style, is_row_axis);
1389   auto getTrackSize = [&](const GridTrackSize& v) {
1390     return SpecifiedValueForGridTrackSize(v, style);
1391   };
1392 
1393   if (auto_repeat_track_sizes.IsEmpty()) {
1394     // If there's no auto repeat(), just add all the line names and track sizes.
1395     PopulateGridTrackList(list, collector, track_sizes, getTrackSize);
1396     return list;
1397   }
1398 
1399   // Add the line names and track sizes that precede the auto repeat().
1400   size_t auto_repeat_insertion_point =
1401       is_row_axis ? style.GridAutoRepeatColumnsInsertionPoint()
1402                   : style.GridAutoRepeatRowsInsertionPoint();
1403   PopulateGridTrackList(list, collector, track_sizes, getTrackSize, 0,
1404                         auto_repeat_insertion_point);
1405 
1406   // Add a CSSGridAutoRepeatValue with the contents of the auto repeat().
1407   AutoRepeatType auto_repeat_type = is_row_axis
1408                                         ? style.GridAutoRepeatColumnsType()
1409                                         : style.GridAutoRepeatRowsType();
1410   CSSValueList* repeated_values =
1411       MakeGarbageCollected<cssvalue::CSSGridAutoRepeatValue>(
1412           auto_repeat_type == AutoRepeatType::kAutoFill ? CSSValueID::kAutoFill
1413                                                         : CSSValueID::kAutoFit);
1414   OrderedNamedLinesCollectorInsideRepeat repeat_collector(style, is_row_axis);
1415   PopulateGridTrackList(repeated_values, repeat_collector,
1416                         auto_repeat_track_sizes, getTrackSize);
1417   list->Append(*repeated_values);
1418 
1419   // Add the line names and track sizes that follow the auto repeat().
1420   PopulateGridTrackList(list, collector, track_sizes, getTrackSize,
1421                         auto_repeat_insertion_point, track_sizes.size(), 1);
1422   return list;
1423 }
1424 
ValueForGridPosition(const GridPosition & position)1425 CSSValue* ComputedStyleUtils::ValueForGridPosition(
1426     const GridPosition& position) {
1427   if (position.IsAuto())
1428     return CSSIdentifierValue::Create(CSSValueID::kAuto);
1429 
1430   if (position.IsNamedGridArea())
1431     return MakeGarbageCollected<CSSCustomIdentValue>(position.NamedGridLine());
1432 
1433   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1434   if (position.IsSpan()) {
1435     list->Append(*CSSIdentifierValue::Create(CSSValueID::kSpan));
1436     list->Append(*CSSNumericLiteralValue::Create(
1437         position.SpanPosition(), CSSPrimitiveValue::UnitType::kNumber));
1438   } else {
1439     list->Append(*CSSNumericLiteralValue::Create(
1440         position.IntegerPosition(), CSSPrimitiveValue::UnitType::kNumber));
1441   }
1442 
1443   if (!position.NamedGridLine().IsNull()) {
1444     list->Append(
1445         *MakeGarbageCollected<CSSCustomIdentValue>(position.NamedGridLine()));
1446   }
1447   return list;
1448 }
1449 
IsSVGObjectWithWidthAndHeight(const LayoutObject & layout_object)1450 static bool IsSVGObjectWithWidthAndHeight(const LayoutObject& layout_object) {
1451   DCHECK(layout_object.IsSVGChild());
1452   return layout_object.IsSVGImage() || layout_object.IsSVGForeignObject() ||
1453          (layout_object.IsSVGShape() &&
1454           IsA<SVGRectElement>(layout_object.GetNode()));
1455 }
1456 
UsedBoxSize(const LayoutObject & layout_object)1457 FloatSize ComputedStyleUtils::UsedBoxSize(const LayoutObject& layout_object) {
1458   if (layout_object.IsSVGChild() &&
1459       IsSVGObjectWithWidthAndHeight(layout_object)) {
1460     FloatSize size(layout_object.ObjectBoundingBox().Size());
1461     // The object bounding box does not have zoom applied. Multiply with zoom
1462     // here since we'll divide by it when we produce the CSS value.
1463     size.Scale(layout_object.StyleRef().EffectiveZoom());
1464     return size;
1465   }
1466   if (!layout_object.IsBox())
1467     return FloatSize();
1468   const LayoutBox& box = ToLayoutBox(layout_object);
1469   return FloatSize(box.StyleRef().BoxSizing() == EBoxSizing::kBorderBox
1470                        ? box.BorderBoxRect().Size()
1471                        : box.ComputedCSSContentBoxRect().Size());
1472 }
1473 
RenderTextDecorationFlagsToCSSValue(TextDecoration text_decoration)1474 CSSValue* ComputedStyleUtils::RenderTextDecorationFlagsToCSSValue(
1475     TextDecoration text_decoration) {
1476   // Blink value is ignored.
1477   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1478   if (EnumHasFlags(text_decoration, TextDecoration::kUnderline))
1479     list->Append(*CSSIdentifierValue::Create(CSSValueID::kUnderline));
1480   if (EnumHasFlags(text_decoration, TextDecoration::kOverline))
1481     list->Append(*CSSIdentifierValue::Create(CSSValueID::kOverline));
1482   if (EnumHasFlags(text_decoration, TextDecoration::kLineThrough))
1483     list->Append(*CSSIdentifierValue::Create(CSSValueID::kLineThrough));
1484 
1485   if (!list->length())
1486     return CSSIdentifierValue::Create(CSSValueID::kNone);
1487   return list;
1488 }
1489 
ValueForTextDecorationStyle(ETextDecorationStyle text_decoration_style)1490 CSSValue* ComputedStyleUtils::ValueForTextDecorationStyle(
1491     ETextDecorationStyle text_decoration_style) {
1492   switch (text_decoration_style) {
1493     case ETextDecorationStyle::kSolid:
1494       return CSSIdentifierValue::Create(CSSValueID::kSolid);
1495     case ETextDecorationStyle::kDouble:
1496       return CSSIdentifierValue::Create(CSSValueID::kDouble);
1497     case ETextDecorationStyle::kDotted:
1498       return CSSIdentifierValue::Create(CSSValueID::kDotted);
1499     case ETextDecorationStyle::kDashed:
1500       return CSSIdentifierValue::Create(CSSValueID::kDashed);
1501     case ETextDecorationStyle::kWavy:
1502       return CSSIdentifierValue::Create(CSSValueID::kWavy);
1503   }
1504 
1505   NOTREACHED();
1506   return CSSInitialValue::Create();
1507 }
1508 
ValueForTextDecorationSkipInk(ETextDecorationSkipInk text_decoration_skip_ink)1509 CSSValue* ComputedStyleUtils::ValueForTextDecorationSkipInk(
1510     ETextDecorationSkipInk text_decoration_skip_ink) {
1511   if (text_decoration_skip_ink == ETextDecorationSkipInk::kNone)
1512     return CSSIdentifierValue::Create(CSSValueID::kNone);
1513   return CSSIdentifierValue::Create(CSSValueID::kAuto);
1514 }
1515 
TouchActionFlagsToCSSValue(TouchAction touch_action)1516 CSSValue* ComputedStyleUtils::TouchActionFlagsToCSSValue(
1517     TouchAction touch_action) {
1518   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1519   if (touch_action == TouchAction::kAuto) {
1520     list->Append(*CSSIdentifierValue::Create(CSSValueID::kAuto));
1521   } else if (touch_action == TouchAction::kNone) {
1522     list->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
1523   } else if (touch_action == TouchAction::kManipulation) {
1524     list->Append(*CSSIdentifierValue::Create(CSSValueID::kManipulation));
1525   } else {
1526     if ((touch_action & TouchAction::kPanX) == TouchAction::kPanX)
1527       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanX));
1528     else if ((touch_action & TouchAction::kPanLeft) != TouchAction::kNone)
1529       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanLeft));
1530     else if ((touch_action & TouchAction::kPanRight) != TouchAction::kNone)
1531       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanRight));
1532     if ((touch_action & TouchAction::kPanY) == TouchAction::kPanY)
1533       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanY));
1534     else if ((touch_action & TouchAction::kPanUp) != TouchAction::kNone)
1535       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanUp));
1536     else if ((touch_action & TouchAction::kPanDown) != TouchAction::kNone)
1537       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanDown));
1538 
1539     if ((touch_action & TouchAction::kPinchZoom) == TouchAction::kPinchZoom)
1540       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPinchZoom));
1541   }
1542 
1543   DCHECK(list->length());
1544   return list;
1545 }
1546 
ValueForWillChange(const Vector<CSSPropertyID> & will_change_properties,bool will_change_contents,bool will_change_scroll_position)1547 CSSValue* ComputedStyleUtils::ValueForWillChange(
1548     const Vector<CSSPropertyID>& will_change_properties,
1549     bool will_change_contents,
1550     bool will_change_scroll_position) {
1551   CSSValueList* list = CSSValueList::CreateCommaSeparated();
1552   if (will_change_contents)
1553     list->Append(*CSSIdentifierValue::Create(CSSValueID::kContents));
1554   if (will_change_scroll_position)
1555     list->Append(*CSSIdentifierValue::Create(CSSValueID::kScrollPosition));
1556   for (wtf_size_t i = 0; i < will_change_properties.size(); ++i) {
1557     list->Append(
1558         *MakeGarbageCollected<CSSCustomIdentValue>(will_change_properties[i]));
1559   }
1560   if (!list->length())
1561     list->Append(*CSSIdentifierValue::Create(CSSValueID::kAuto));
1562   return list;
1563 }
1564 
ValueForAnimationDelay(const CSSTimingData * timing_data)1565 CSSValue* ComputedStyleUtils::ValueForAnimationDelay(
1566     const CSSTimingData* timing_data) {
1567   CSSValueList* list = CSSValueList::CreateCommaSeparated();
1568   if (timing_data) {
1569     for (wtf_size_t i = 0; i < timing_data->DelayList().size(); ++i) {
1570       list->Append(*CSSNumericLiteralValue::Create(
1571           timing_data->DelayList()[i], CSSPrimitiveValue::UnitType::kSeconds));
1572     }
1573   } else {
1574     list->Append(*CSSNumericLiteralValue::Create(
1575         CSSTimingData::InitialDelay(), CSSPrimitiveValue::UnitType::kSeconds));
1576   }
1577   return list;
1578 }
1579 
ValueForAnimationDirection(Timing::PlaybackDirection direction)1580 CSSValue* ComputedStyleUtils::ValueForAnimationDirection(
1581     Timing::PlaybackDirection direction) {
1582   switch (direction) {
1583     case Timing::PlaybackDirection::NORMAL:
1584       return CSSIdentifierValue::Create(CSSValueID::kNormal);
1585     case Timing::PlaybackDirection::ALTERNATE_NORMAL:
1586       return CSSIdentifierValue::Create(CSSValueID::kAlternate);
1587     case Timing::PlaybackDirection::REVERSE:
1588       return CSSIdentifierValue::Create(CSSValueID::kReverse);
1589     case Timing::PlaybackDirection::ALTERNATE_REVERSE:
1590       return CSSIdentifierValue::Create(CSSValueID::kAlternateReverse);
1591     default:
1592       NOTREACHED();
1593       return nullptr;
1594   }
1595 }
1596 
ValueForAnimationDuration(const CSSTimingData * timing_data)1597 CSSValue* ComputedStyleUtils::ValueForAnimationDuration(
1598     const CSSTimingData* timing_data) {
1599   CSSValueList* list = CSSValueList::CreateCommaSeparated();
1600   if (timing_data) {
1601     for (wtf_size_t i = 0; i < timing_data->DurationList().size(); ++i) {
1602       list->Append(*CSSNumericLiteralValue::Create(
1603           timing_data->DurationList()[i],
1604           CSSPrimitiveValue::UnitType::kSeconds));
1605     }
1606   } else {
1607     list->Append(
1608         *CSSNumericLiteralValue::Create(CSSTimingData::InitialDuration(),
1609                                         CSSPrimitiveValue::UnitType::kSeconds));
1610   }
1611   return list;
1612 }
1613 
ValueForAnimationFillMode(Timing::FillMode fill_mode)1614 CSSValue* ComputedStyleUtils::ValueForAnimationFillMode(
1615     Timing::FillMode fill_mode) {
1616   switch (fill_mode) {
1617     case Timing::FillMode::NONE:
1618       return CSSIdentifierValue::Create(CSSValueID::kNone);
1619     case Timing::FillMode::FORWARDS:
1620       return CSSIdentifierValue::Create(CSSValueID::kForwards);
1621     case Timing::FillMode::BACKWARDS:
1622       return CSSIdentifierValue::Create(CSSValueID::kBackwards);
1623     case Timing::FillMode::BOTH:
1624       return CSSIdentifierValue::Create(CSSValueID::kBoth);
1625     default:
1626       NOTREACHED();
1627       return nullptr;
1628   }
1629 }
1630 
ValueForAnimationIterationCount(double iteration_count)1631 CSSValue* ComputedStyleUtils::ValueForAnimationIterationCount(
1632     double iteration_count) {
1633   if (iteration_count == std::numeric_limits<double>::infinity())
1634     return CSSIdentifierValue::Create(CSSValueID::kInfinite);
1635   return CSSNumericLiteralValue::Create(iteration_count,
1636                                         CSSPrimitiveValue::UnitType::kNumber);
1637 }
1638 
ValueForAnimationPlayState(EAnimPlayState play_state)1639 CSSValue* ComputedStyleUtils::ValueForAnimationPlayState(
1640     EAnimPlayState play_state) {
1641   if (play_state == EAnimPlayState::kPlaying)
1642     return CSSIdentifierValue::Create(CSSValueID::kRunning);
1643   DCHECK_EQ(play_state, EAnimPlayState::kPaused);
1644   return CSSIdentifierValue::Create(CSSValueID::kPaused);
1645 }
1646 
CreateTimingFunctionValue(const TimingFunction * timing_function)1647 CSSValue* ComputedStyleUtils::CreateTimingFunctionValue(
1648     const TimingFunction* timing_function) {
1649   switch (timing_function->GetType()) {
1650     case TimingFunction::Type::CUBIC_BEZIER: {
1651       const auto* bezier_timing_function =
1652           To<CubicBezierTimingFunction>(timing_function);
1653       if (bezier_timing_function->GetEaseType() !=
1654           CubicBezierTimingFunction::EaseType::CUSTOM) {
1655         CSSValueID value_id = CSSValueID::kInvalid;
1656         switch (bezier_timing_function->GetEaseType()) {
1657           case CubicBezierTimingFunction::EaseType::EASE:
1658             value_id = CSSValueID::kEase;
1659             break;
1660           case CubicBezierTimingFunction::EaseType::EASE_IN:
1661             value_id = CSSValueID::kEaseIn;
1662             break;
1663           case CubicBezierTimingFunction::EaseType::EASE_OUT:
1664             value_id = CSSValueID::kEaseOut;
1665             break;
1666           case CubicBezierTimingFunction::EaseType::EASE_IN_OUT:
1667             value_id = CSSValueID::kEaseInOut;
1668             break;
1669           default:
1670             NOTREACHED();
1671             return nullptr;
1672         }
1673         return CSSIdentifierValue::Create(value_id);
1674       }
1675       return MakeGarbageCollected<cssvalue::CSSCubicBezierTimingFunctionValue>(
1676           bezier_timing_function->X1(), bezier_timing_function->Y1(),
1677           bezier_timing_function->X2(), bezier_timing_function->Y2());
1678     }
1679 
1680     case TimingFunction::Type::STEPS: {
1681       const auto* steps_timing_function =
1682           To<StepsTimingFunction>(timing_function);
1683       StepsTimingFunction::StepPosition position =
1684           steps_timing_function->GetStepPosition();
1685       int steps = steps_timing_function->NumberOfSteps();
1686 
1687       // Canonical form of step timing function is step(n, type) or step(n) even
1688       // if initially parsed as step-start or step-end.
1689       return MakeGarbageCollected<cssvalue::CSSStepsTimingFunctionValue>(
1690           steps, position);
1691     }
1692 
1693     default:
1694       return CSSIdentifierValue::Create(CSSValueID::kLinear);
1695   }
1696 }
1697 
ValueForAnimationTimingFunction(const CSSTimingData * timing_data)1698 CSSValue* ComputedStyleUtils::ValueForAnimationTimingFunction(
1699     const CSSTimingData* timing_data) {
1700   CSSValueList* list = CSSValueList::CreateCommaSeparated();
1701   if (timing_data) {
1702     for (wtf_size_t i = 0; i < timing_data->TimingFunctionList().size(); ++i) {
1703       list->Append(*CreateTimingFunctionValue(
1704           timing_data->TimingFunctionList()[i].get()));
1705     }
1706   } else {
1707     list->Append(*CreateTimingFunctionValue(
1708         CSSTimingData::InitialTimingFunction().get()));
1709   }
1710   return list;
1711 }
1712 
ValuesForBorderRadiusCorner(const LengthSize & radius,const ComputedStyle & style)1713 CSSValueList* ComputedStyleUtils::ValuesForBorderRadiusCorner(
1714     const LengthSize& radius,
1715     const ComputedStyle& style) {
1716   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1717   if (radius.Width().IsPercent()) {
1718     list->Append(*CSSNumericLiteralValue::Create(
1719         radius.Width().Percent(), CSSPrimitiveValue::UnitType::kPercentage));
1720   } else {
1721     list->Append(*ZoomAdjustedPixelValueForLength(radius.Width(), style));
1722   }
1723   if (radius.Height().IsPercent()) {
1724     list->Append(*CSSNumericLiteralValue::Create(
1725         radius.Height().Percent(), CSSPrimitiveValue::UnitType::kPercentage));
1726   } else {
1727     list->Append(*ZoomAdjustedPixelValueForLength(radius.Height(), style));
1728   }
1729   return list;
1730 }
1731 
ValueForBorderRadiusCorner(const LengthSize & radius,const ComputedStyle & style)1732 CSSValue* ComputedStyleUtils::ValueForBorderRadiusCorner(
1733     const LengthSize& radius,
1734     const ComputedStyle& style) {
1735   return MakeGarbageCollected<CSSValuePair>(
1736       ZoomAdjustedPixelValueForLength(radius.Width(), style),
1737       ZoomAdjustedPixelValueForLength(radius.Height(), style),
1738       CSSValuePair::kDropIdenticalValues);
1739 }
1740 
ValueForMatrixTransform(const TransformationMatrix & transform_param,const ComputedStyle & style)1741 CSSValue* ComputedStyleUtils::ValueForMatrixTransform(
1742     const TransformationMatrix& transform_param,
1743     const ComputedStyle& style) {
1744   // Take TransformationMatrix by reference and then copy it because VC++
1745   // doesn't guarantee alignment of function parameters.
1746   TransformationMatrix transform = transform_param;
1747   CSSFunctionValue* transform_value = nullptr;
1748   transform.Zoom(1 / style.EffectiveZoom());
1749   if (transform.IsAffine()) {
1750     transform_value =
1751         MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kMatrix);
1752 
1753     transform_value->Append(*CSSNumericLiteralValue::Create(
1754         transform.A(), CSSPrimitiveValue::UnitType::kNumber));
1755     transform_value->Append(*CSSNumericLiteralValue::Create(
1756         transform.B(), CSSPrimitiveValue::UnitType::kNumber));
1757     transform_value->Append(*CSSNumericLiteralValue::Create(
1758         transform.C(), CSSPrimitiveValue::UnitType::kNumber));
1759     transform_value->Append(*CSSNumericLiteralValue::Create(
1760         transform.D(), CSSPrimitiveValue::UnitType::kNumber));
1761     transform_value->Append(*CSSNumericLiteralValue::Create(
1762         transform.E(), CSSPrimitiveValue::UnitType::kNumber));
1763     transform_value->Append(*CSSNumericLiteralValue::Create(
1764         transform.F(), CSSPrimitiveValue::UnitType::kNumber));
1765   } else {
1766     transform_value =
1767         MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kMatrix3d);
1768 
1769     transform_value->Append(*CSSNumericLiteralValue::Create(
1770         transform.M11(), CSSPrimitiveValue::UnitType::kNumber));
1771     transform_value->Append(*CSSNumericLiteralValue::Create(
1772         transform.M12(), CSSPrimitiveValue::UnitType::kNumber));
1773     transform_value->Append(*CSSNumericLiteralValue::Create(
1774         transform.M13(), CSSPrimitiveValue::UnitType::kNumber));
1775     transform_value->Append(*CSSNumericLiteralValue::Create(
1776         transform.M14(), CSSPrimitiveValue::UnitType::kNumber));
1777 
1778     transform_value->Append(*CSSNumericLiteralValue::Create(
1779         transform.M21(), CSSPrimitiveValue::UnitType::kNumber));
1780     transform_value->Append(*CSSNumericLiteralValue::Create(
1781         transform.M22(), CSSPrimitiveValue::UnitType::kNumber));
1782     transform_value->Append(*CSSNumericLiteralValue::Create(
1783         transform.M23(), CSSPrimitiveValue::UnitType::kNumber));
1784     transform_value->Append(*CSSNumericLiteralValue::Create(
1785         transform.M24(), CSSPrimitiveValue::UnitType::kNumber));
1786 
1787     transform_value->Append(*CSSNumericLiteralValue::Create(
1788         transform.M31(), CSSPrimitiveValue::UnitType::kNumber));
1789     transform_value->Append(*CSSNumericLiteralValue::Create(
1790         transform.M32(), CSSPrimitiveValue::UnitType::kNumber));
1791     transform_value->Append(*CSSNumericLiteralValue::Create(
1792         transform.M33(), CSSPrimitiveValue::UnitType::kNumber));
1793     transform_value->Append(*CSSNumericLiteralValue::Create(
1794         transform.M34(), CSSPrimitiveValue::UnitType::kNumber));
1795 
1796     transform_value->Append(*CSSNumericLiteralValue::Create(
1797         transform.M41(), CSSPrimitiveValue::UnitType::kNumber));
1798     transform_value->Append(*CSSNumericLiteralValue::Create(
1799         transform.M42(), CSSPrimitiveValue::UnitType::kNumber));
1800     transform_value->Append(*CSSNumericLiteralValue::Create(
1801         transform.M43(), CSSPrimitiveValue::UnitType::kNumber));
1802     transform_value->Append(*CSSNumericLiteralValue::Create(
1803         transform.M44(), CSSPrimitiveValue::UnitType::kNumber));
1804   }
1805 
1806   return transform_value;
1807 }
1808 
1809 // We collapse functions like translateX into translate, since we will reify
1810 // them as a translate anyway.
ValueForTransformOperation(const TransformOperation & operation,float zoom)1811 CSSValue* ComputedStyleUtils::ValueForTransformOperation(
1812     const TransformOperation& operation,
1813     float zoom) {
1814   switch (operation.GetType()) {
1815     case TransformOperation::kScaleX:
1816     case TransformOperation::kScaleY:
1817     case TransformOperation::kScaleZ:
1818     case TransformOperation::kScale:
1819     case TransformOperation::kScale3D: {
1820       const auto& scale = To<ScaleTransformOperation>(operation);
1821       CSSFunctionValue* result = MakeGarbageCollected<CSSFunctionValue>(
1822           operation.Is3DOperation() ? CSSValueID::kScale3d
1823                                     : CSSValueID::kScale);
1824       result->Append(*CSSNumericLiteralValue::Create(
1825           scale.X(), CSSPrimitiveValue::UnitType::kNumber));
1826       result->Append(*CSSNumericLiteralValue::Create(
1827           scale.Y(), CSSPrimitiveValue::UnitType::kNumber));
1828       if (operation.Is3DOperation()) {
1829         result->Append(*CSSNumericLiteralValue::Create(
1830             scale.Z(), CSSPrimitiveValue::UnitType::kNumber));
1831       }
1832       return result;
1833     }
1834     case TransformOperation::kTranslateX:
1835     case TransformOperation::kTranslateY:
1836     case TransformOperation::kTranslateZ:
1837     case TransformOperation::kTranslate:
1838     case TransformOperation::kTranslate3D: {
1839       const auto& translate = To<TranslateTransformOperation>(operation);
1840       CSSFunctionValue* result = MakeGarbageCollected<CSSFunctionValue>(
1841           operation.Is3DOperation() ? CSSValueID::kTranslate3d
1842                                     : CSSValueID::kTranslate);
1843       result->Append(*CSSPrimitiveValue::CreateFromLength(translate.X(), zoom));
1844       result->Append(*CSSPrimitiveValue::CreateFromLength(translate.Y(), zoom));
1845       if (operation.Is3DOperation()) {
1846         // Since this is pixel length, we must unzoom (CreateFromLength above
1847         // does the division internally).
1848         result->Append(*CSSNumericLiteralValue::Create(
1849             translate.Z() / zoom, CSSPrimitiveValue::UnitType::kPixels));
1850       }
1851       return result;
1852     }
1853     case TransformOperation::kRotateX:
1854     case TransformOperation::kRotateY:
1855     case TransformOperation::kRotate3D: {
1856       const auto& rotate = To<RotateTransformOperation>(operation);
1857       CSSFunctionValue* result =
1858           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kRotate3d);
1859       result->Append(*CSSNumericLiteralValue::Create(
1860           rotate.X(), CSSPrimitiveValue::UnitType::kNumber));
1861       result->Append(*CSSNumericLiteralValue::Create(
1862           rotate.Y(), CSSPrimitiveValue::UnitType::kNumber));
1863       result->Append(*CSSNumericLiteralValue::Create(
1864           rotate.Z(), CSSPrimitiveValue::UnitType::kNumber));
1865       result->Append(*CSSNumericLiteralValue::Create(
1866           rotate.Angle(), CSSPrimitiveValue::UnitType::kDegrees));
1867       return result;
1868     }
1869     case TransformOperation::kRotate: {
1870       const auto& rotate = To<RotateTransformOperation>(operation);
1871       auto* result =
1872           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kRotate);
1873       result->Append(*CSSNumericLiteralValue::Create(
1874           rotate.Angle(), CSSPrimitiveValue::UnitType::kDegrees));
1875       return result;
1876     }
1877     case TransformOperation::kSkewX: {
1878       const auto& skew = To<SkewTransformOperation>(operation);
1879       auto* result = MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kSkewX);
1880       result->Append(*CSSNumericLiteralValue::Create(
1881           skew.AngleX(), CSSPrimitiveValue::UnitType::kDegrees));
1882       return result;
1883     }
1884     case TransformOperation::kSkewY: {
1885       const auto& skew = To<SkewTransformOperation>(operation);
1886       auto* result = MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kSkewY);
1887       result->Append(*CSSNumericLiteralValue::Create(
1888           skew.AngleY(), CSSPrimitiveValue::UnitType::kDegrees));
1889       return result;
1890     }
1891     case TransformOperation::kSkew: {
1892       const auto& skew = To<SkewTransformOperation>(operation);
1893       auto* result = MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kSkew);
1894       result->Append(*CSSNumericLiteralValue::Create(
1895           skew.AngleX(), CSSPrimitiveValue::UnitType::kDegrees));
1896       result->Append(*CSSNumericLiteralValue::Create(
1897           skew.AngleY(), CSSPrimitiveValue::UnitType::kDegrees));
1898       return result;
1899     }
1900     case TransformOperation::kPerspective: {
1901       const auto& perspective = To<PerspectiveTransformOperation>(operation);
1902       auto* result =
1903           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kPerspective);
1904       result->Append(*CSSNumericLiteralValue::Create(
1905           perspective.Perspective() / zoom,
1906           CSSPrimitiveValue::UnitType::kPixels));
1907       return result;
1908     }
1909     case TransformOperation::kMatrix: {
1910       const auto& matrix = To<MatrixTransformOperation>(operation).Matrix();
1911       auto* result =
1912           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kMatrix);
1913       // CSS matrix values are returned in column-major order.
1914       double values[6] = {matrix.A(), matrix.B(),  //
1915                           matrix.C(), matrix.D(),  //
1916                           // E and F are pixel lengths so unzoom
1917                           matrix.E() / zoom, matrix.F() / zoom};
1918       for (double value : values) {
1919         result->Append(*CSSNumericLiteralValue::Create(
1920             value, CSSPrimitiveValue::UnitType::kNumber));
1921       }
1922       return result;
1923     }
1924     case TransformOperation::kMatrix3D: {
1925       const auto& matrix = To<Matrix3DTransformOperation>(operation).Matrix();
1926       CSSFunctionValue* result =
1927           MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kMatrix3d);
1928       // CSS matrix values are returned in column-major order.
1929       double values[16] = {
1930           // Note that the transformation matrix operates on (Length^3 * R).
1931           // Each column contains 3 scalars followed by a reciprocal length
1932           // (with a value in 1/px) which must be unzoomed accordingly.
1933           matrix.M11(), matrix.M12(), matrix.M13(), matrix.M14() * zoom,
1934           matrix.M21(), matrix.M22(), matrix.M23(), matrix.M24() * zoom,
1935           matrix.M31(), matrix.M32(), matrix.M33(), matrix.M34() * zoom,
1936           // Last column has 3 pixel lengths and a scalar
1937           matrix.M41() / zoom, matrix.M42() / zoom, matrix.M43() / zoom,
1938           matrix.M44()};
1939       for (double value : values) {
1940         result->Append(*CSSNumericLiteralValue::Create(
1941             value, CSSPrimitiveValue::UnitType::kNumber));
1942       }
1943       return result;
1944     }
1945     case TransformOperation::kInterpolated:
1946       // TODO(816803): The computed value in this case is not fully spec'd
1947       // See https://github.com/w3c/css-houdini-drafts/issues/425
1948       return CSSIdentifierValue::Create(CSSValueID::kNone);
1949     default:
1950       // The remaining operations are unsupported.
1951       NOTREACHED();
1952       return CSSIdentifierValue::Create(CSSValueID::kNone);
1953   }
1954 }
1955 
ReferenceBoxForTransform(const LayoutObject & layout_object,UsePixelSnappedBox pixel_snap_box)1956 FloatRect ComputedStyleUtils::ReferenceBoxForTransform(
1957     const LayoutObject& layout_object,
1958     UsePixelSnappedBox pixel_snap_box) {
1959   if (layout_object.IsSVGChild())
1960     return TransformHelper::ComputeReferenceBox(layout_object);
1961   if (layout_object.IsBox()) {
1962     const auto& layout_box = ToLayoutBox(layout_object);
1963     if (pixel_snap_box == kUsePixelSnappedBox)
1964       return FloatRect(layout_box.PixelSnappedBorderBoxRect());
1965     return FloatRect(layout_box.BorderBoxRect());
1966   }
1967   return FloatRect();
1968 }
1969 
ComputedTransform(const LayoutObject * layout_object,const ComputedStyle & style)1970 CSSValue* ComputedStyleUtils::ComputedTransform(
1971     const LayoutObject* layout_object,
1972     const ComputedStyle& style) {
1973   if (!layout_object || !style.HasTransform())
1974     return CSSIdentifierValue::Create(CSSValueID::kNone);
1975 
1976   FloatRect reference_box = ReferenceBoxForTransform(*layout_object);
1977 
1978   TransformationMatrix transform;
1979   style.ApplyTransform(transform, reference_box,
1980                        ComputedStyle::kExcludeTransformOrigin,
1981                        ComputedStyle::kExcludeMotionPath,
1982                        ComputedStyle::kExcludeIndependentTransformProperties);
1983 
1984   // FIXME: Need to print out individual functions
1985   // (https://bugs.webkit.org/show_bug.cgi?id=23924)
1986   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
1987   list->Append(*ValueForMatrixTransform(transform, style));
1988 
1989   return list;
1990 }
1991 
CreateTransitionPropertyValue(const CSSTransitionData::TransitionProperty & property)1992 CSSValue* ComputedStyleUtils::CreateTransitionPropertyValue(
1993     const CSSTransitionData::TransitionProperty& property) {
1994   if (property.property_type == CSSTransitionData::kTransitionNone)
1995     return CSSIdentifierValue::Create(CSSValueID::kNone);
1996   if (property.property_type == CSSTransitionData::kTransitionUnknownProperty)
1997     return MakeGarbageCollected<CSSCustomIdentValue>(property.property_string);
1998   DCHECK_EQ(property.property_type,
1999             CSSTransitionData::kTransitionKnownProperty);
2000   return MakeGarbageCollected<CSSCustomIdentValue>(
2001       CSSUnresolvedProperty::Get(property.unresolved_property)
2002           .GetPropertyNameAtomicString());
2003 }
2004 
ValueForTransitionProperty(const CSSTransitionData * transition_data)2005 CSSValue* ComputedStyleUtils::ValueForTransitionProperty(
2006     const CSSTransitionData* transition_data) {
2007   CSSValueList* list = CSSValueList::CreateCommaSeparated();
2008   if (transition_data) {
2009     for (wtf_size_t i = 0; i < transition_data->PropertyList().size(); ++i) {
2010       list->Append(
2011           *CreateTransitionPropertyValue(transition_data->PropertyList()[i]));
2012     }
2013   } else {
2014     list->Append(*CSSIdentifierValue::Create(CSSValueID::kAll));
2015   }
2016   return list;
2017 }
2018 
ValueForQuoteType(const QuoteType quote_type)2019 CSSValueID ValueForQuoteType(const QuoteType quote_type) {
2020   switch (quote_type) {
2021     case QuoteType::kNoOpen:
2022       return CSSValueID::kNoOpenQuote;
2023     case QuoteType::kNoClose:
2024       return CSSValueID::kNoCloseQuote;
2025     case QuoteType::kClose:
2026       return CSSValueID::kCloseQuote;
2027     case QuoteType::kOpen:
2028       return CSSValueID::kOpenQuote;
2029   }
2030   NOTREACHED();
2031   return CSSValueID::kInvalid;
2032 }
2033 
ValueForContentData(const ComputedStyle & style,bool allow_visited_style)2034 CSSValue* ComputedStyleUtils::ValueForContentData(const ComputedStyle& style,
2035                                                   bool allow_visited_style) {
2036   if (style.ContentPreventsBoxGeneration())
2037     return CSSIdentifierValue::Create(CSSValueID::kNone);
2038   if (style.ContentBehavesAsNormal())
2039     return CSSIdentifierValue::Create(CSSValueID::kNormal);
2040 
2041   CSSValueList* outer_list = CSSValueList::CreateSlashSeparated();
2042   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2043 
2044   // Alternative text optionally specified after a forward slash appearing after
2045   // the last content list item.
2046   CSSStringValue* alt_text = nullptr;
2047   for (const ContentData* content_data = style.GetContentData(); content_data;
2048        content_data = content_data->Next()) {
2049     if (content_data->IsCounter()) {
2050       const CounterContent* counter =
2051           To<CounterContentData>(content_data)->Counter();
2052       DCHECK(counter);
2053       auto* identifier =
2054           MakeGarbageCollected<CSSCustomIdentValue>(counter->Identifier());
2055       auto* separator =
2056           MakeGarbageCollected<CSSStringValue>(counter->Separator());
2057       CSSValueID list_style_ident = CSSValueID::kNone;
2058       if (counter->ListStyle() != EListStyleType::kNone) {
2059         // TODO(sashab): Change this to use a converter instead of
2060         // CSSPrimitiveValueMappings.
2061         list_style_ident =
2062             CSSIdentifierValue::Create(counter->ListStyle())->GetValueID();
2063       }
2064       CSSIdentifierValue* list_style =
2065           CSSIdentifierValue::Create(list_style_ident);
2066       list->Append(*MakeGarbageCollected<cssvalue::CSSCounterValue>(
2067           identifier, list_style, separator));
2068     } else if (content_data->IsImage()) {
2069       const StyleImage* image = To<ImageContentData>(content_data)->GetImage();
2070       DCHECK(image);
2071       list->Append(*image->ComputedCSSValue(style, allow_visited_style));
2072     } else if (content_data->IsText()) {
2073       list->Append(*MakeGarbageCollected<CSSStringValue>(
2074           To<TextContentData>(content_data)->GetText()));
2075     } else if (content_data->IsQuote()) {
2076       const QuoteType quote_type = To<QuoteContentData>(content_data)->Quote();
2077       list->Append(*CSSIdentifierValue::Create(ValueForQuoteType(quote_type)));
2078     } else if (content_data->IsAltText()) {
2079       alt_text = MakeGarbageCollected<CSSStringValue>(
2080           To<AltTextContentData>(content_data)->GetText());
2081     } else {
2082       NOTREACHED();
2083     }
2084   }
2085   DCHECK(list->length());
2086 
2087   outer_list->Append(*list);
2088   if (alt_text)
2089     outer_list->Append(*alt_text);
2090   return outer_list;
2091 }
2092 
ValueForCounterDirectives(const ComputedStyle & style,bool is_increment)2093 CSSValue* ComputedStyleUtils::ValueForCounterDirectives(
2094     const ComputedStyle& style,
2095     bool is_increment) {
2096   const CounterDirectiveMap* map = style.GetCounterDirectives();
2097   if (!map)
2098     return CSSIdentifierValue::Create(CSSValueID::kNone);
2099 
2100   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2101   for (const auto& item : *map) {
2102     bool is_valid_counter_value =
2103         is_increment ? item.value.IsIncrement() : item.value.IsReset();
2104     if (!is_valid_counter_value)
2105       continue;
2106 
2107     list->Append(*MakeGarbageCollected<CSSCustomIdentValue>(item.key));
2108     int32_t number =
2109         is_increment ? item.value.IncrementValue() : item.value.ResetValue();
2110     list->Append(*CSSNumericLiteralValue::Create(
2111         (double)number, CSSPrimitiveValue::UnitType::kInteger));
2112   }
2113 
2114   if (!list->length())
2115     return CSSIdentifierValue::Create(CSSValueID::kNone);
2116 
2117   return list;
2118 }
2119 
ValueForShape(const ComputedStyle & style,bool allow_visited_style,ShapeValue * shape_value)2120 CSSValue* ComputedStyleUtils::ValueForShape(const ComputedStyle& style,
2121                                             bool allow_visited_style,
2122                                             ShapeValue* shape_value) {
2123   if (!shape_value)
2124     return CSSIdentifierValue::Create(CSSValueID::kNone);
2125   if (shape_value->GetType() == ShapeValue::kBox)
2126     return CSSIdentifierValue::Create(shape_value->CssBox());
2127   if (shape_value->GetType() == ShapeValue::kImage) {
2128     if (shape_value->GetImage()) {
2129       return shape_value->GetImage()->ComputedCSSValue(style,
2130                                                        allow_visited_style);
2131     }
2132     return CSSIdentifierValue::Create(CSSValueID::kNone);
2133   }
2134 
2135   DCHECK_EQ(shape_value->GetType(), ShapeValue::kShape);
2136 
2137   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2138   list->Append(*ValueForBasicShape(style, shape_value->Shape()));
2139   if (shape_value->CssBox() != CSSBoxType::kMissing)
2140     list->Append(*CSSIdentifierValue::Create(shape_value->CssBox()));
2141   return list;
2142 }
2143 
ValueForBorderRadiusShorthand(const ComputedStyle & style)2144 CSSValueList* ComputedStyleUtils::ValueForBorderRadiusShorthand(
2145     const ComputedStyle& style) {
2146   CSSValueList* list = CSSValueList::CreateSlashSeparated();
2147 
2148   bool show_horizontal_bottom_left = style.BorderTopRightRadius().Width() !=
2149                                      style.BorderBottomLeftRadius().Width();
2150   bool show_horizontal_bottom_right =
2151       show_horizontal_bottom_left || (style.BorderBottomRightRadius().Width() !=
2152                                       style.BorderTopLeftRadius().Width());
2153   bool show_horizontal_top_right =
2154       show_horizontal_bottom_right || (style.BorderTopRightRadius().Width() !=
2155                                        style.BorderTopLeftRadius().Width());
2156 
2157   bool show_vertical_bottom_left = style.BorderTopRightRadius().Height() !=
2158                                    style.BorderBottomLeftRadius().Height();
2159   bool show_vertical_bottom_right =
2160       show_vertical_bottom_left || (style.BorderBottomRightRadius().Height() !=
2161                                     style.BorderTopLeftRadius().Height());
2162   bool show_vertical_top_right =
2163       show_vertical_bottom_right || (style.BorderTopRightRadius().Height() !=
2164                                      style.BorderTopLeftRadius().Height());
2165 
2166   CSSValueList* top_left_radius =
2167       ValuesForBorderRadiusCorner(style.BorderTopLeftRadius(), style);
2168   CSSValueList* top_right_radius =
2169       ValuesForBorderRadiusCorner(style.BorderTopRightRadius(), style);
2170   CSSValueList* bottom_right_radius =
2171       ValuesForBorderRadiusCorner(style.BorderBottomRightRadius(), style);
2172   CSSValueList* bottom_left_radius =
2173       ValuesForBorderRadiusCorner(style.BorderBottomLeftRadius(), style);
2174 
2175   CSSValueList* horizontal_radii = CSSValueList::CreateSpaceSeparated();
2176   horizontal_radii->Append(top_left_radius->Item(0));
2177   if (show_horizontal_top_right)
2178     horizontal_radii->Append(top_right_radius->Item(0));
2179   if (show_horizontal_bottom_right)
2180     horizontal_radii->Append(bottom_right_radius->Item(0));
2181   if (show_horizontal_bottom_left)
2182     horizontal_radii->Append(bottom_left_radius->Item(0));
2183 
2184   list->Append(*horizontal_radii);
2185 
2186   CSSValueList* vertical_radii = CSSValueList::CreateSpaceSeparated();
2187   vertical_radii->Append(top_left_radius->Item(1));
2188   if (show_vertical_top_right)
2189     vertical_radii->Append(top_right_radius->Item(1));
2190   if (show_vertical_bottom_right)
2191     vertical_radii->Append(bottom_right_radius->Item(1));
2192   if (show_vertical_bottom_left)
2193     vertical_radii->Append(bottom_left_radius->Item(1));
2194 
2195   if (!vertical_radii->Equals(To<CSSValueList>(list->Item(0))))
2196     list->Append(*vertical_radii);
2197 
2198   return list;
2199 }
2200 
StrokeDashArrayToCSSValueList(const SVGDashArray & dashes,const ComputedStyle & style)2201 CSSValue* ComputedStyleUtils::StrokeDashArrayToCSSValueList(
2202     const SVGDashArray& dashes,
2203     const ComputedStyle& style) {
2204   if (dashes.data.IsEmpty())
2205     return CSSIdentifierValue::Create(CSSValueID::kNone);
2206 
2207   CSSValueList* list = CSSValueList::CreateCommaSeparated();
2208   for (const Length& dash_length : dashes.data) {
2209     list->Append(*ZoomAdjustedPixelValueForLength(dash_length, style));
2210   }
2211 
2212   return list;
2213 }
2214 
AdjustSVGPaintForCurrentColor(const SVGPaint & paint,const Color & current_color)2215 CSSValue* ComputedStyleUtils::AdjustSVGPaintForCurrentColor(
2216     const SVGPaint& paint,
2217     const Color& current_color) {
2218   if (paint.type >= SVG_PAINTTYPE_URI_NONE) {
2219     CSSValueList* values = CSSValueList::CreateSpaceSeparated();
2220     values->Append(
2221         *MakeGarbageCollected<cssvalue::CSSURIValue>(paint.GetUrl()));
2222     if (paint.type == SVG_PAINTTYPE_URI_NONE)
2223       values->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
2224     else if (paint.type == SVG_PAINTTYPE_URI_CURRENTCOLOR)
2225       values->Append(*cssvalue::CSSColorValue::Create(current_color.Rgb()));
2226     else if (paint.type == SVG_PAINTTYPE_URI_RGBCOLOR)
2227       values->Append(*cssvalue::CSSColorValue::Create(paint.GetColor().Rgb()));
2228     return values;
2229   }
2230   if (paint.type == SVG_PAINTTYPE_NONE)
2231     return CSSIdentifierValue::Create(CSSValueID::kNone);
2232   if (paint.type == SVG_PAINTTYPE_CURRENTCOLOR)
2233     return cssvalue::CSSColorValue::Create(current_color.Rgb());
2234 
2235   return cssvalue::CSSColorValue::Create(paint.GetColor().Rgb());
2236 }
2237 
ValueForSVGResource(const StyleSVGResource * resource)2238 CSSValue* ComputedStyleUtils::ValueForSVGResource(
2239     const StyleSVGResource* resource) {
2240   if (resource)
2241     return MakeGarbageCollected<cssvalue::CSSURIValue>(resource->Url());
2242   return CSSIdentifierValue::Create(CSSValueID::kNone);
2243 }
2244 
ValueForShadowData(const ShadowData & shadow,const ComputedStyle & style,bool use_spread)2245 CSSValue* ComputedStyleUtils::ValueForShadowData(const ShadowData& shadow,
2246                                                  const ComputedStyle& style,
2247                                                  bool use_spread) {
2248   CSSPrimitiveValue* x = ZoomAdjustedPixelValue(shadow.X(), style);
2249   CSSPrimitiveValue* y = ZoomAdjustedPixelValue(shadow.Y(), style);
2250   CSSPrimitiveValue* blur = ZoomAdjustedPixelValue(shadow.Blur(), style);
2251   CSSPrimitiveValue* spread =
2252       use_spread ? ZoomAdjustedPixelValue(shadow.Spread(), style) : nullptr;
2253   CSSIdentifierValue* shadow_style =
2254       shadow.Style() == kNormal
2255           ? nullptr
2256           : CSSIdentifierValue::Create(CSSValueID::kInset);
2257   CSSValue* color = CurrentColorOrValidColor(style, shadow.GetColor());
2258   return MakeGarbageCollected<CSSShadowValue>(x, y, blur, spread, shadow_style,
2259                                               color);
2260 }
2261 
ValueForShadowList(const ShadowList * shadow_list,const ComputedStyle & style,bool use_spread)2262 CSSValue* ComputedStyleUtils::ValueForShadowList(const ShadowList* shadow_list,
2263                                                  const ComputedStyle& style,
2264                                                  bool use_spread) {
2265   if (!shadow_list)
2266     return CSSIdentifierValue::Create(CSSValueID::kNone);
2267 
2268   CSSValueList* list = CSSValueList::CreateCommaSeparated();
2269   wtf_size_t shadow_count = shadow_list->Shadows().size();
2270   for (wtf_size_t i = 0; i < shadow_count; ++i) {
2271     list->Append(
2272         *ValueForShadowData(shadow_list->Shadows()[i], style, use_spread));
2273   }
2274   return list;
2275 }
2276 
ValueForFilter(const ComputedStyle & style,const FilterOperations & filter_operations)2277 CSSValue* ComputedStyleUtils::ValueForFilter(
2278     const ComputedStyle& style,
2279     const FilterOperations& filter_operations) {
2280   if (filter_operations.Operations().IsEmpty())
2281     return CSSIdentifierValue::Create(CSSValueID::kNone);
2282 
2283   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2284 
2285   CSSFunctionValue* filter_value = nullptr;
2286 
2287   for (const auto& operation : filter_operations.Operations()) {
2288     FilterOperation* filter_operation = operation.Get();
2289     switch (filter_operation->GetType()) {
2290       case FilterOperation::REFERENCE:
2291         filter_value = MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kUrl);
2292         filter_value->Append(*MakeGarbageCollected<CSSStringValue>(
2293             To<ReferenceFilterOperation>(filter_operation)->Url()));
2294         break;
2295       case FilterOperation::GRAYSCALE:
2296         filter_value =
2297             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kGrayscale);
2298         filter_value->Append(*CSSNumericLiteralValue::Create(
2299             To<BasicColorMatrixFilterOperation>(filter_operation)->Amount(),
2300             CSSPrimitiveValue::UnitType::kNumber));
2301         break;
2302       case FilterOperation::SEPIA:
2303         filter_value =
2304             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kSepia);
2305         filter_value->Append(*CSSNumericLiteralValue::Create(
2306             To<BasicColorMatrixFilterOperation>(filter_operation)->Amount(),
2307             CSSPrimitiveValue::UnitType::kNumber));
2308         break;
2309       case FilterOperation::SATURATE:
2310         filter_value =
2311             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kSaturate);
2312         filter_value->Append(*CSSNumericLiteralValue::Create(
2313             To<BasicColorMatrixFilterOperation>(filter_operation)->Amount(),
2314             CSSPrimitiveValue::UnitType::kNumber));
2315         break;
2316       case FilterOperation::HUE_ROTATE:
2317         filter_value =
2318             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kHueRotate);
2319         filter_value->Append(*CSSNumericLiteralValue::Create(
2320             To<BasicColorMatrixFilterOperation>(filter_operation)->Amount(),
2321             CSSPrimitiveValue::UnitType::kDegrees));
2322         break;
2323       case FilterOperation::INVERT:
2324         filter_value =
2325             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kInvert);
2326         filter_value->Append(*CSSNumericLiteralValue::Create(
2327             To<BasicComponentTransferFilterOperation>(filter_operation)
2328                 ->Amount(),
2329             CSSPrimitiveValue::UnitType::kNumber));
2330         break;
2331       case FilterOperation::OPACITY:
2332         filter_value =
2333             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kOpacity);
2334         filter_value->Append(*CSSNumericLiteralValue::Create(
2335             To<BasicComponentTransferFilterOperation>(filter_operation)
2336                 ->Amount(),
2337             CSSPrimitiveValue::UnitType::kNumber));
2338         break;
2339       case FilterOperation::BRIGHTNESS:
2340         filter_value =
2341             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kBrightness);
2342         filter_value->Append(*CSSNumericLiteralValue::Create(
2343             To<BasicComponentTransferFilterOperation>(filter_operation)
2344                 ->Amount(),
2345             CSSPrimitiveValue::UnitType::kNumber));
2346         break;
2347       case FilterOperation::CONTRAST:
2348         filter_value =
2349             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kContrast);
2350         filter_value->Append(*CSSNumericLiteralValue::Create(
2351             To<BasicComponentTransferFilterOperation>(filter_operation)
2352                 ->Amount(),
2353             CSSPrimitiveValue::UnitType::kNumber));
2354         break;
2355       case FilterOperation::BLUR:
2356         filter_value =
2357             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kBlur);
2358         filter_value->Append(*ZoomAdjustedPixelValue(
2359             To<BlurFilterOperation>(filter_operation)->StdDeviation().Value(),
2360             style));
2361         break;
2362       case FilterOperation::DROP_SHADOW: {
2363         const auto& drop_shadow_operation =
2364             To<DropShadowFilterOperation>(*filter_operation);
2365         filter_value =
2366             MakeGarbageCollected<CSSFunctionValue>(CSSValueID::kDropShadow);
2367         // We want our computed style to look like that of a text shadow (has
2368         // neither spread nor inset style).
2369         filter_value->Append(
2370             *ValueForShadowData(drop_shadow_operation.Shadow(), style, false));
2371         break;
2372       }
2373       default:
2374         NOTREACHED();
2375         break;
2376     }
2377     list->Append(*filter_value);
2378   }
2379 
2380   return list;
2381 }
2382 
ValueForScrollSnapType(const cc::ScrollSnapType & type,const ComputedStyle & style)2383 CSSValue* ComputedStyleUtils::ValueForScrollSnapType(
2384     const cc::ScrollSnapType& type,
2385     const ComputedStyle& style) {
2386   if (!type.is_none) {
2387     if (type.strictness == cc::SnapStrictness::kProximity)
2388       return CSSIdentifierValue::Create(type.axis);
2389     return MakeGarbageCollected<CSSValuePair>(
2390         CSSIdentifierValue::Create(type.axis),
2391         CSSIdentifierValue::Create(type.strictness),
2392         CSSValuePair::kDropIdenticalValues);
2393   }
2394   return CSSIdentifierValue::Create(CSSValueID::kNone);
2395 }
2396 
ValueForScrollSnapAlign(const cc::ScrollSnapAlign & align,const ComputedStyle & style)2397 CSSValue* ComputedStyleUtils::ValueForScrollSnapAlign(
2398     const cc::ScrollSnapAlign& align,
2399     const ComputedStyle& style) {
2400   return MakeGarbageCollected<CSSValuePair>(
2401       CSSIdentifierValue::Create(align.alignment_block),
2402       CSSIdentifierValue::Create(align.alignment_inline),
2403       CSSValuePair::kDropIdenticalValues);
2404 }
2405 
2406 // Returns a suitable value for the page-break-(before|after) property, given
2407 // the computed value of the more general break-(before|after) property.
ValueForPageBreakBetween(EBreakBetween break_value)2408 CSSValue* ComputedStyleUtils::ValueForPageBreakBetween(
2409     EBreakBetween break_value) {
2410   switch (break_value) {
2411     case EBreakBetween::kAvoidColumn:
2412     case EBreakBetween::kColumn:
2413     case EBreakBetween::kRecto:
2414     case EBreakBetween::kVerso:
2415     case EBreakBetween::kAvoidPage:
2416       return nullptr;
2417     case EBreakBetween::kPage:
2418       return CSSIdentifierValue::Create(CSSValueID::kAlways);
2419     default:
2420       return CSSIdentifierValue::Create(break_value);
2421   }
2422 }
2423 
2424 // Returns a suitable value for the -webkit-column-break-(before|after)
2425 // property, given the computed value of the more general break-(before|after)
2426 // property.
ValueForWebkitColumnBreakBetween(EBreakBetween break_value)2427 CSSValue* ComputedStyleUtils::ValueForWebkitColumnBreakBetween(
2428     EBreakBetween break_value) {
2429   switch (break_value) {
2430     case EBreakBetween::kAvoidPage:
2431     case EBreakBetween::kLeft:
2432     case EBreakBetween::kPage:
2433     case EBreakBetween::kRecto:
2434     case EBreakBetween::kRight:
2435     case EBreakBetween::kVerso:
2436       return nullptr;
2437     case EBreakBetween::kColumn:
2438       return CSSIdentifierValue::Create(CSSValueID::kAlways);
2439     case EBreakBetween::kAvoidColumn:
2440       return CSSIdentifierValue::Create(CSSValueID::kAvoid);
2441     default:
2442       return CSSIdentifierValue::Create(break_value);
2443   }
2444 }
2445 
2446 // Returns a suitable value for the page-break-inside property, given the
2447 // computed value of the more general break-inside property.
ValueForPageBreakInside(EBreakInside break_value)2448 CSSValue* ComputedStyleUtils::ValueForPageBreakInside(
2449     EBreakInside break_value) {
2450   switch (break_value) {
2451     case EBreakInside::kAvoidColumn:
2452       return nullptr;
2453     case EBreakInside::kAvoidPage:
2454       return CSSIdentifierValue::Create(CSSValueID::kAvoid);
2455     default:
2456       return CSSIdentifierValue::Create(break_value);
2457   }
2458 }
2459 
2460 // Returns a suitable value for the -webkit-column-break-inside property, given
2461 // the computed value of the more general break-inside property.
ValueForWebkitColumnBreakInside(EBreakInside break_value)2462 CSSValue* ComputedStyleUtils::ValueForWebkitColumnBreakInside(
2463     EBreakInside break_value) {
2464   switch (break_value) {
2465     case EBreakInside::kAvoidPage:
2466       return nullptr;
2467     case EBreakInside::kAvoidColumn:
2468       return CSSIdentifierValue::Create(CSSValueID::kAvoid);
2469     default:
2470       return CSSIdentifierValue::Create(break_value);
2471   }
2472 }
2473 
2474 // https://drafts.csswg.org/cssom/#resolved-value
2475 //
2476 // For 'width' and 'height':
2477 //
2478 // If the property applies to the element or pseudo-element and the resolved
2479 // value of the display property is not none or contents, then the resolved
2480 // value is the used value. Otherwise the resolved value is the computed value
2481 // (https://drafts.csswg.org/css-cascade-4/#computed-value).
2482 //
2483 // (Note that the computed value exists even when the property does not apply.)
WidthOrHeightShouldReturnUsedValue(const LayoutObject * object)2484 bool ComputedStyleUtils::WidthOrHeightShouldReturnUsedValue(
2485     const LayoutObject* object) {
2486   // The display property is 'none'.
2487   if (!object)
2488     return false;
2489   // Non-root SVG objects return the resolved value except <image>,
2490   // <rect> and <foreignObject> which return the used value.
2491   if (object->IsSVGChild())
2492     return IsSVGObjectWithWidthAndHeight(*object);
2493   // According to
2494   // http://www.w3.org/TR/CSS2/visudet.html#the-width-property and
2495   // http://www.w3.org/TR/CSS2/visudet.html#the-height-property, the "width" or
2496   // "height" property does not apply to non-atomic inline elements.
2497   return object->IsAtomicInlineLevel() || !object->IsInline();
2498 }
2499 
ValuesForShorthandProperty(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2500 CSSValueList* ComputedStyleUtils::ValuesForShorthandProperty(
2501     const StylePropertyShorthand& shorthand,
2502     const ComputedStyle& style,
2503     const LayoutObject* layout_object,
2504     bool allow_visited_style) {
2505   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2506   for (unsigned i = 0; i < shorthand.length(); ++i) {
2507     const CSSValue* value =
2508         shorthand.properties()[i]->CSSValueFromComputedStyle(
2509             style, layout_object, allow_visited_style);
2510     DCHECK(value);
2511     list->Append(*value);
2512   }
2513   return list;
2514 }
2515 
ValuesForGapShorthand(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2516 CSSValuePair* ComputedStyleUtils::ValuesForGapShorthand(
2517     const StylePropertyShorthand& shorthand,
2518     const ComputedStyle& style,
2519     const LayoutObject* layout_object,
2520     bool allow_visited_style) {
2521   const CSSValue* row_gap_value =
2522       shorthand.properties()[0]->CSSValueFromComputedStyle(style, layout_object,
2523                                                            allow_visited_style);
2524   const CSSValue* column_gap_value =
2525       shorthand.properties()[1]->CSSValueFromComputedStyle(style, layout_object,
2526                                                            allow_visited_style);
2527 
2528   return MakeGarbageCollected<CSSValuePair>(row_gap_value, column_gap_value,
2529                                             CSSValuePair::kDropIdenticalValues);
2530 }
2531 
ValuesForGridShorthand(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2532 CSSValueList* ComputedStyleUtils::ValuesForGridShorthand(
2533     const StylePropertyShorthand& shorthand,
2534     const ComputedStyle& style,
2535     const LayoutObject* layout_object,
2536     bool allow_visited_style) {
2537   CSSValueList* list = CSSValueList::CreateSlashSeparated();
2538   for (unsigned i = 0; i < shorthand.length(); ++i) {
2539     const CSSValue* value =
2540         shorthand.properties()[i]->CSSValueFromComputedStyle(
2541             style, layout_object, allow_visited_style);
2542     DCHECK(value);
2543     list->Append(*value);
2544   }
2545   return list;
2546 }
2547 
ValuesForSidesShorthand(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2548 CSSValueList* ComputedStyleUtils::ValuesForSidesShorthand(
2549     const StylePropertyShorthand& shorthand,
2550     const ComputedStyle& style,
2551     const LayoutObject* layout_object,
2552     bool allow_visited_style) {
2553   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2554   // Assume the properties are in the usual order top, right, bottom, left.
2555   const CSSValue* top_value =
2556       shorthand.properties()[0]->CSSValueFromComputedStyle(style, layout_object,
2557                                                            allow_visited_style);
2558   const CSSValue* right_value =
2559       shorthand.properties()[1]->CSSValueFromComputedStyle(style, layout_object,
2560                                                            allow_visited_style);
2561   const CSSValue* bottom_value =
2562       shorthand.properties()[2]->CSSValueFromComputedStyle(style, layout_object,
2563                                                            allow_visited_style);
2564   const CSSValue* left_value =
2565       shorthand.properties()[3]->CSSValueFromComputedStyle(style, layout_object,
2566                                                            allow_visited_style);
2567 
2568   // All 4 properties must be specified.
2569   if (!top_value || !right_value || !bottom_value || !left_value)
2570     return nullptr;
2571 
2572   bool show_left = !DataEquivalent(right_value, left_value);
2573   bool show_bottom = !DataEquivalent(top_value, bottom_value) || show_left;
2574   bool show_right = !DataEquivalent(top_value, right_value) || show_bottom;
2575 
2576   list->Append(*top_value);
2577   if (show_right)
2578     list->Append(*right_value);
2579   if (show_bottom)
2580     list->Append(*bottom_value);
2581   if (show_left)
2582     list->Append(*left_value);
2583 
2584   return list;
2585 }
2586 
ValuesForInlineBlockShorthand(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2587 CSSValuePair* ComputedStyleUtils::ValuesForInlineBlockShorthand(
2588     const StylePropertyShorthand& shorthand,
2589     const ComputedStyle& style,
2590     const LayoutObject* layout_object,
2591     bool allow_visited_style) {
2592   const CSSValue* start_value =
2593       shorthand.properties()[0]->CSSValueFromComputedStyle(style, layout_object,
2594                                                            allow_visited_style);
2595   const CSSValue* end_value =
2596       shorthand.properties()[1]->CSSValueFromComputedStyle(style, layout_object,
2597                                                            allow_visited_style);
2598   // Both properties must be specified.
2599   if (!start_value || !end_value)
2600     return nullptr;
2601 
2602   auto* pair = MakeGarbageCollected<CSSValuePair>(
2603       start_value, end_value, CSSValuePair::kDropIdenticalValues);
2604   return pair;
2605 }
2606 
ValuesForPlaceShorthand(const StylePropertyShorthand & shorthand,const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2607 CSSValuePair* ComputedStyleUtils::ValuesForPlaceShorthand(
2608     const StylePropertyShorthand& shorthand,
2609     const ComputedStyle& style,
2610     const LayoutObject* layout_object,
2611     bool allow_visited_style) {
2612   const CSSValue* align_value =
2613       shorthand.properties()[0]->CSSValueFromComputedStyle(style, layout_object,
2614                                                            allow_visited_style);
2615   const CSSValue* justify_value =
2616       shorthand.properties()[1]->CSSValueFromComputedStyle(style, layout_object,
2617                                                            allow_visited_style);
2618 
2619   return MakeGarbageCollected<CSSValuePair>(align_value, justify_value,
2620                                             CSSValuePair::kDropIdenticalValues);
2621 }
2622 
ExpandNoneLigaturesValue()2623 static CSSValue* ExpandNoneLigaturesValue() {
2624   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2625   list->Append(*CSSIdentifierValue::Create(CSSValueID::kNoCommonLigatures));
2626   list->Append(
2627       *CSSIdentifierValue::Create(CSSValueID::kNoDiscretionaryLigatures));
2628   list->Append(*CSSIdentifierValue::Create(CSSValueID::kNoHistoricalLigatures));
2629   list->Append(*CSSIdentifierValue::Create(CSSValueID::kNoContextual));
2630   return list;
2631 }
2632 
ValuesForFontVariantProperty(const ComputedStyle & style,const LayoutObject * layout_object,bool allow_visited_style)2633 CSSValue* ComputedStyleUtils::ValuesForFontVariantProperty(
2634     const ComputedStyle& style,
2635     const LayoutObject* layout_object,
2636     bool allow_visited_style) {
2637   enum VariantShorthandCases {
2638     kAllNormal,
2639     kNoneLigatures,
2640     kConcatenateNonNormal
2641   };
2642   StylePropertyShorthand shorthand = fontVariantShorthand();
2643   VariantShorthandCases shorthand_case = kAllNormal;
2644   for (unsigned i = 0; i < shorthand.length(); ++i) {
2645     const CSSValue* value =
2646         shorthand.properties()[i]->CSSValueFromComputedStyle(
2647             style, layout_object, allow_visited_style);
2648 
2649     auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2650     if (shorthand_case == kAllNormal && identifier_value &&
2651         identifier_value->GetValueID() == CSSValueID::kNone &&
2652         shorthand.properties()[i]->IDEquals(
2653             CSSPropertyID::kFontVariantLigatures)) {
2654       shorthand_case = kNoneLigatures;
2655     } else if (!(identifier_value &&
2656                  identifier_value->GetValueID() == CSSValueID::kNormal)) {
2657       shorthand_case = kConcatenateNonNormal;
2658       break;
2659     }
2660   }
2661 
2662   switch (shorthand_case) {
2663     case kAllNormal:
2664       return CSSIdentifierValue::Create(CSSValueID::kNormal);
2665     case kNoneLigatures:
2666       return CSSIdentifierValue::Create(CSSValueID::kNone);
2667     case kConcatenateNonNormal: {
2668       CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2669       for (unsigned i = 0; i < shorthand.length(); ++i) {
2670         const CSSValue* value =
2671             shorthand.properties()[i]->CSSValueFromComputedStyle(
2672                 style, layout_object, allow_visited_style);
2673         DCHECK(value);
2674         auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2675         if (identifier_value &&
2676             identifier_value->GetValueID() == CSSValueID::kNone) {
2677           list->Append(*ExpandNoneLigaturesValue());
2678         } else if (!(identifier_value &&
2679                      identifier_value->GetValueID() == CSSValueID::kNormal)) {
2680           list->Append(*value);
2681         }
2682       }
2683       return list;
2684     }
2685     default:
2686       NOTREACHED();
2687       return nullptr;
2688   }
2689 }
2690 
2691 // Returns up to two values for 'scroll-customization' property. The values
2692 // correspond to the customization values for 'x' and 'y' axes.
ScrollCustomizationFlagsToCSSValue(scroll_customization::ScrollDirection scroll_customization)2693 CSSValue* ComputedStyleUtils::ScrollCustomizationFlagsToCSSValue(
2694     scroll_customization::ScrollDirection scroll_customization) {
2695   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
2696   if (scroll_customization == scroll_customization::kScrollDirectionAuto) {
2697     list->Append(*CSSIdentifierValue::Create(CSSValueID::kAuto));
2698   } else if (scroll_customization ==
2699              scroll_customization::kScrollDirectionNone) {
2700     list->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
2701   } else {
2702     if ((scroll_customization & scroll_customization::kScrollDirectionPanX) ==
2703         scroll_customization::kScrollDirectionPanX)
2704       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanX));
2705     else if (scroll_customization &
2706              scroll_customization::kScrollDirectionPanLeft)
2707       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanLeft));
2708     else if (scroll_customization &
2709              scroll_customization::kScrollDirectionPanRight)
2710       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanRight));
2711     if ((scroll_customization & scroll_customization::kScrollDirectionPanY) ==
2712         scroll_customization::kScrollDirectionPanY)
2713       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanY));
2714     else if (scroll_customization & scroll_customization::kScrollDirectionPanUp)
2715       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanUp));
2716     else if (scroll_customization &
2717              scroll_customization::kScrollDirectionPanDown)
2718       list->Append(*CSSIdentifierValue::Create(CSSValueID::kPanDown));
2719   }
2720 
2721   DCHECK(list->length());
2722   return list;
2723 }
2724 
ValueForGapLength(const GapLength & gap_length,const ComputedStyle & style)2725 CSSValue* ComputedStyleUtils::ValueForGapLength(const GapLength& gap_length,
2726                                                 const ComputedStyle& style) {
2727   if (gap_length.IsNormal())
2728     return CSSIdentifierValue::Create(CSSValueID::kNormal);
2729   return ZoomAdjustedPixelValueForLength(gap_length.GetLength(), style);
2730 }
2731 
2732 std::unique_ptr<CrossThreadStyleValue>
CrossThreadStyleValueFromCSSStyleValue(CSSStyleValue * style_value)2733 ComputedStyleUtils::CrossThreadStyleValueFromCSSStyleValue(
2734     CSSStyleValue* style_value) {
2735   switch (style_value->GetType()) {
2736     case CSSStyleValue::StyleValueType::kKeywordType:
2737       return std::make_unique<CrossThreadKeywordValue>(
2738           To<CSSKeywordValue>(style_value)->value().IsolatedCopy());
2739     case CSSStyleValue::StyleValueType::kUnitType:
2740       return std::make_unique<CrossThreadUnitValue>(
2741           To<CSSUnitValue>(style_value)->value(),
2742           To<CSSUnitValue>(style_value)->GetInternalUnit());
2743     case CSSStyleValue::StyleValueType::kUnsupportedColorType:
2744       return std::make_unique<CrossThreadColorValue>(
2745           To<CSSUnsupportedColorValue>(style_value)->Value());
2746     case CSSStyleValue::StyleValueType::kUnparsedType:
2747       return std::make_unique<CrossThreadUnparsedValue>(
2748           To<CSSUnparsedValue>(style_value)->ToString().IsolatedCopy());
2749     default:
2750       // Make an isolated copy to ensure that it is safe to pass cross thread.
2751       return std::make_unique<CrossThreadUnsupportedValue>(
2752           style_value->toString().IsolatedCopy());
2753   }
2754 }
2755 
2756 }  // namespace blink
2757