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