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