1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * * Redistributions of source code must retain the above copyright
5 * notice, this list of conditions and the following disclaimer.
6 * * Redistributions in binary form must reproduce the above
7 * copyright notice, this list of conditions and the following disclaimer
8 * in the documentation and/or other materials provided with the
9 * distribution.
10 * * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
28
29 #include <algorithm>
30 #include <utility>
31
32 #include "build/build_config.h"
33 #include "third_party/blink/renderer/core/css/basic_shape_functions.h"
34 #include "third_party/blink/renderer/core/css/css_axis_value.h"
35 #include "third_party/blink/renderer/core/css/css_color_value.h"
36 #include "third_party/blink/renderer/core/css/css_content_distribution_value.h"
37 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
38 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
39 #include "third_party/blink/renderer/core/css/css_font_feature_value.h"
40 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
41 #include "third_party/blink/renderer/core/css/css_font_variation_value.h"
42 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
43 #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
44 #include "third_party/blink/renderer/core/css/css_math_expression_node.h"
45 #include "third_party/blink/renderer/core/css/css_math_function_value.h"
46 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
47 #include "third_party/blink/renderer/core/css/css_path_value.h"
48 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
49 #include "third_party/blink/renderer/core/css/css_quad_value.h"
50 #include "third_party/blink/renderer/core/css/css_reflect_value.h"
51 #include "third_party/blink/renderer/core/css/css_shadow_value.h"
52 #include "third_party/blink/renderer/core/css/css_uri_value.h"
53 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
54 #include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
55 #include "third_party/blink/renderer/core/css/resolver/transform_builder.h"
56 #include "third_party/blink/renderer/core/css/style_engine.h"
57 #include "third_party/blink/renderer/core/frame/local_frame.h"
58 #include "third_party/blink/renderer/core/frame/web_feature.h"
59 #include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
60 #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
61 #include "third_party/blink/renderer/core/style/style_svg_resource.h"
62 #include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h"
63 #include "third_party/blink/renderer/platform/heap/heap.h"
64 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
65 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
66 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
67
68 namespace blink {
69
70 namespace {
71
ConvertGridTrackBreadth(const StyleResolverState & state,const CSSValue & value)72 static GridLength ConvertGridTrackBreadth(const StyleResolverState& state,
73 const CSSValue& value) {
74 // Fractional unit.
75 auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value);
76 if (primitive_value && primitive_value->IsFlex())
77 return GridLength(primitive_value->GetDoubleValue());
78
79 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
80 if (identifier_value) {
81 if (identifier_value->GetValueID() == CSSValueID::kMinContent)
82 return Length::MinContent();
83 if (identifier_value->GetValueID() == CSSValueID::kMaxContent)
84 return Length::MaxContent();
85 }
86
87 return StyleBuilderConverter::ConvertLengthOrAuto(state, value);
88 }
89
90 } // namespace
91
ConvertBoxReflect(StyleResolverState & state,const CSSValue & value)92 scoped_refptr<StyleReflection> StyleBuilderConverter::ConvertBoxReflect(
93 StyleResolverState& state,
94 const CSSValue& value) {
95 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
96 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
97 return ComputedStyleInitialValues::InitialBoxReflect();
98 }
99
100 const auto& reflect_value = To<cssvalue::CSSReflectValue>(value);
101 scoped_refptr<StyleReflection> reflection = StyleReflection::Create();
102 reflection->SetDirection(
103 reflect_value.Direction()->ConvertTo<CSSReflectionDirection>());
104 if (reflect_value.Offset())
105 reflection->SetOffset(reflect_value.Offset()->ConvertToLength(
106 state.CssToLengthConversionData()));
107 if (reflect_value.Mask()) {
108 NinePieceImage mask = NinePieceImage::MaskDefaults();
109 CSSToStyleMap::MapNinePieceImage(state, CSSPropertyID::kWebkitBoxReflect,
110 *reflect_value.Mask(), mask);
111 reflection->SetMask(mask);
112 }
113
114 return reflection;
115 }
116
ConvertColor(StyleResolverState & state,const CSSValue & value,bool for_visited_link)117 Color StyleBuilderConverter::ConvertColor(StyleResolverState& state,
118 const CSSValue& value,
119 bool for_visited_link) {
120 return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
121 value, state.Style()->GetCurrentColor(), state.Style()->UsedColorScheme(),
122 for_visited_link);
123 }
124
ConvertElementReference(StyleResolverState & state,const CSSValue & value)125 scoped_refptr<StyleSVGResource> StyleBuilderConverter::ConvertElementReference(
126 StyleResolverState& state,
127 const CSSValue& value) {
128 const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value);
129 if (!url_value)
130 return nullptr;
131 SVGResource* resource =
132 state.GetElementStyleResources().GetSVGResourceFromValue(
133 state.GetElement().OriginatingTreeScope(), *url_value);
134 return StyleSVGResource::Create(resource, url_value->ValueForSerialization());
135 }
136
ConvertClip(StyleResolverState & state,const CSSValue & value)137 LengthBox StyleBuilderConverter::ConvertClip(StyleResolverState& state,
138 const CSSValue& value) {
139 const CSSQuadValue& rect = To<CSSQuadValue>(value);
140
141 return LengthBox(ConvertLengthOrAuto(state, *rect.Top()),
142 ConvertLengthOrAuto(state, *rect.Right()),
143 ConvertLengthOrAuto(state, *rect.Bottom()),
144 ConvertLengthOrAuto(state, *rect.Left()));
145 }
146
ConvertClipPath(StyleResolverState & state,const CSSValue & value)147 scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
148 StyleResolverState& state,
149 const CSSValue& value) {
150 if (value.IsBasicShapeValue() || value.IsPathValue())
151 return ShapeClipPathOperation::Create(BasicShapeForValue(state, value));
152
153 if (const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value)) {
154 SVGResource* resource =
155 state.GetElementStyleResources().GetSVGResourceFromValue(
156 state.GetElement().OriginatingTreeScope(), *url_value);
157 // TODO(fs): Doesn't work with external SVG references (crbug.com/109212.)
158 return ReferenceClipPathOperation::Create(
159 url_value->ValueForSerialization(), resource);
160 }
161 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
162 DCHECK(identifier_value &&
163 identifier_value->GetValueID() == CSSValueID::kNone);
164 return nullptr;
165 }
166
ConvertFilterOperations(StyleResolverState & state,const CSSValue & value)167 FilterOperations StyleBuilderConverter::ConvertFilterOperations(
168 StyleResolverState& state,
169 const CSSValue& value) {
170 return FilterOperationResolver::CreateFilterOperations(state, value);
171 }
172
ConvertOffscreenFilterOperations(const CSSValue & value,const Font & font)173 FilterOperations StyleBuilderConverter::ConvertOffscreenFilterOperations(
174 const CSSValue& value,
175 const Font& font) {
176 return FilterOperationResolver::CreateOffscreenFilterOperations(value, font);
177 }
178
ConvertGenericFamily(CSSValueID value_id)179 static FontDescription::GenericFamilyType ConvertGenericFamily(
180 CSSValueID value_id) {
181 switch (value_id) {
182 case CSSValueID::kWebkitBody:
183 return FontDescription::kStandardFamily;
184 case CSSValueID::kSerif:
185 return FontDescription::kSerifFamily;
186 case CSSValueID::kSansSerif:
187 return FontDescription::kSansSerifFamily;
188 case CSSValueID::kCursive:
189 return FontDescription::kCursiveFamily;
190 case CSSValueID::kFantasy:
191 return FontDescription::kFantasyFamily;
192 case CSSValueID::kMonospace:
193 return FontDescription::kMonospaceFamily;
194 default:
195 return FontDescription::kNoFamily;
196 }
197 }
198
ConvertFontFamilyName(const CSSValue & value,FontDescription::GenericFamilyType & generic_family,AtomicString & family_name,FontBuilder * font_builder,const Document * document_for_count)199 static bool ConvertFontFamilyName(
200 const CSSValue& value,
201 FontDescription::GenericFamilyType& generic_family,
202 AtomicString& family_name,
203 FontBuilder* font_builder,
204 const Document* document_for_count) {
205 if (auto* font_family_value = DynamicTo<CSSFontFamilyValue>(value)) {
206 generic_family = FontDescription::kNoFamily;
207 family_name = AtomicString(font_family_value->Value());
208 #if defined(OS_MAC)
209 if (family_name == FontCache::LegacySystemFontFamily()) {
210 document_for_count->CountUse(WebFeature::kBlinkMacSystemFont);
211 family_name = font_family_names::kSystemUi;
212 }
213 #endif
214 } else if (font_builder) {
215 generic_family =
216 ConvertGenericFamily(To<CSSIdentifierValue>(value).GetValueID());
217 family_name = font_builder->GenericFontFamilyName(generic_family);
218 }
219
220 return !family_name.IsEmpty();
221 }
222
ConvertFontFamily(const CSSValue & value,FontBuilder * font_builder,const Document * document_for_count)223 FontDescription::FamilyDescription StyleBuilderConverterBase::ConvertFontFamily(
224 const CSSValue& value,
225 FontBuilder* font_builder,
226 const Document* document_for_count) {
227 FontDescription::FamilyDescription desc(FontDescription::kNoFamily);
228 FontFamily* curr_family = nullptr;
229
230 for (auto& family : To<CSSValueList>(value)) {
231 FontDescription::GenericFamilyType generic_family =
232 FontDescription::kNoFamily;
233 AtomicString family_name;
234
235 if (!ConvertFontFamilyName(*family, generic_family, family_name,
236 font_builder, document_for_count))
237 continue;
238
239 if (!curr_family) {
240 curr_family = &desc.family;
241 } else {
242 scoped_refptr<SharedFontFamily> new_family = SharedFontFamily::Create();
243 curr_family->AppendFamily(new_family);
244 curr_family = new_family.get();
245 }
246
247 curr_family->SetFamily(family_name);
248
249 if (generic_family != FontDescription::kNoFamily)
250 desc.generic_family = generic_family;
251 }
252
253 return desc;
254 }
255
ConvertFontFamily(StyleResolverState & state,const CSSValue & value)256 FontDescription::FamilyDescription StyleBuilderConverter::ConvertFontFamily(
257 StyleResolverState& state,
258 const CSSValue& value) {
259 return StyleBuilderConverterBase::ConvertFontFamily(
260 value,
261 state.GetDocument().GetSettings() ? &state.GetFontBuilder() : nullptr,
262 &state.GetDocument());
263 }
264
265 scoped_refptr<FontFeatureSettings>
ConvertFontFeatureSettings(StyleResolverState & state,const CSSValue & value)266 StyleBuilderConverter::ConvertFontFeatureSettings(StyleResolverState& state,
267 const CSSValue& value) {
268 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
269 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNormal)
270 return FontBuilder::InitialFeatureSettings();
271
272 const auto& list = To<CSSValueList>(value);
273 scoped_refptr<FontFeatureSettings> settings = FontFeatureSettings::Create();
274 int len = list.length();
275 for (int i = 0; i < len; ++i) {
276 const auto& feature = To<cssvalue::CSSFontFeatureValue>(list.Item(i));
277 settings->Append(FontFeature(feature.Tag(), feature.Value()));
278 }
279 return settings;
280 }
281
CompareTags(FontVariationAxis a,FontVariationAxis b)282 static bool CompareTags(FontVariationAxis a, FontVariationAxis b) {
283 return a.Tag() < b.Tag();
284 }
285
286 scoped_refptr<FontVariationSettings>
ConvertFontVariationSettings(const StyleResolverState & state,const CSSValue & value)287 StyleBuilderConverter::ConvertFontVariationSettings(
288 const StyleResolverState& state,
289 const CSSValue& value) {
290 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
291 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNormal)
292 return FontBuilder::InitialVariationSettings();
293
294 const auto& list = To<CSSValueList>(value);
295 int len = list.length();
296 HashMap<uint32_t, float> axes;
297 // Use a temporary HashMap to remove duplicate tags, keeping the last
298 // occurrence of each.
299 for (int i = 0; i < len; ++i) {
300 const auto& feature = To<cssvalue::CSSFontVariationValue>(list.Item(i));
301 axes.Set(AtomicStringToFourByteTag(feature.Tag()), feature.Value());
302 }
303 scoped_refptr<FontVariationSettings> settings =
304 FontVariationSettings::Create();
305 for (auto& axis : axes) {
306 settings->Append(FontVariationAxis(axis.key, axis.value));
307 }
308 std::sort(settings->begin(), settings->end(), CompareTags);
309 return settings;
310 }
311
MathScriptScaleFactor(StyleResolverState & state)312 float MathScriptScaleFactor(StyleResolverState& state) {
313 int a = state.ParentStyle()->MathDepth();
314 int b = state.Style()->MathDepth();
315 if (b == a)
316 return 1.0;
317 bool invertScaleFactor = false;
318 if (b < a) {
319 std::swap(a, b);
320 invertScaleFactor = true;
321 }
322
323 // Determine the scale factors from the inherited font.
324 float defaultScaleDown = 0.71;
325 int exponent = b - a;
326 float scaleFactor = 1.0;
327 if (const SimpleFontData* font_data =
328 state.ParentStyle()->GetFont().PrimaryFont()) {
329 HarfBuzzFace* parent_harfbuzz_face =
330 font_data->PlatformData().GetHarfBuzzFace();
331 if (OpenTypeMathSupport::HasMathData(parent_harfbuzz_face)) {
332 float scriptPercentScaleDown =
333 OpenTypeMathSupport::MathConstant(
334 parent_harfbuzz_face,
335 OpenTypeMathSupport::MathConstants::kScriptPercentScaleDown)
336 .value_or(0);
337 // Note: zero can mean both zero for the math constant and the fallback.
338 if (!scriptPercentScaleDown)
339 scriptPercentScaleDown = defaultScaleDown;
340 float scriptScriptPercentScaleDown =
341 OpenTypeMathSupport::MathConstant(
342 parent_harfbuzz_face,
343 OpenTypeMathSupport::MathConstants::kScriptScriptPercentScaleDown)
344 .value_or(0);
345 // Note: zero can mean both zero for the math constant and the fallback.
346 if (!scriptScriptPercentScaleDown)
347 scriptScriptPercentScaleDown = defaultScaleDown * defaultScaleDown;
348 if (a <= 0 && b >= 2) {
349 scaleFactor *= scriptScriptPercentScaleDown;
350 exponent -= 2;
351 } else if (a == 1) {
352 scaleFactor *= scriptScriptPercentScaleDown / scriptPercentScaleDown;
353 exponent--;
354 } else if (b == 1) {
355 scaleFactor *= scriptPercentScaleDown;
356 exponent--;
357 }
358 }
359 }
360 scaleFactor *= pow(defaultScaleDown, exponent);
361 return invertScaleFactor ? 1 / scaleFactor : scaleFactor;
362 }
363
ComputeFontSize(const CSSToLengthConversionData & conversion_data,const CSSPrimitiveValue & primitive_value,const FontDescription::Size & parent_size)364 static float ComputeFontSize(const CSSToLengthConversionData& conversion_data,
365 const CSSPrimitiveValue& primitive_value,
366 const FontDescription::Size& parent_size) {
367 if (primitive_value.IsLength()) {
368 float result = primitive_value.ComputeLength<float>(conversion_data);
369 float font_size_zoom = conversion_data.FontSizeZoom();
370 // TODO(crbug.com/408777): Only accounting for numeric literal value here
371 // will leave calc() without zoom correction.
372 if (primitive_value.IsNumericLiteralValue() && font_size_zoom != 1) {
373 CSSPrimitiveValue::UnitType type =
374 To<CSSNumericLiteralValue>(&primitive_value)->GetType();
375 if (type == CSSPrimitiveValue::UnitType::kChs ||
376 type == CSSPrimitiveValue::UnitType::kExs) {
377 return result / font_size_zoom;
378 }
379 }
380 return result;
381 }
382 if (primitive_value.IsCalculatedPercentageWithLength()) {
383 return To<CSSMathFunctionValue>(primitive_value)
384 .ToCalcValue(conversion_data)
385 ->Evaluate(parent_size.value);
386 }
387
388 NOTREACHED();
389 return 0;
390 }
391
ConvertFontSize(const CSSValue & value,const CSSToLengthConversionData & conversion_data,FontDescription::Size parent_size)392 FontDescription::Size StyleBuilderConverterBase::ConvertFontSize(
393 const CSSValue& value,
394 const CSSToLengthConversionData& conversion_data,
395 FontDescription::Size parent_size) {
396 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
397 CSSValueID value_id = identifier_value->GetValueID();
398 if (FontSizeFunctions::IsValidValueID(value_id)) {
399 return FontDescription::Size(FontSizeFunctions::KeywordSize(value_id),
400 0.0f, false);
401 }
402 if (value_id == CSSValueID::kSmaller)
403 return FontDescription::SmallerSize(parent_size);
404 if (value_id == CSSValueID::kLarger)
405 return FontDescription::LargerSize(parent_size);
406 NOTREACHED();
407 return FontBuilder::InitialSize();
408 }
409
410 const auto& primitive_value = To<CSSPrimitiveValue>(value);
411 if (primitive_value.IsPercentage()) {
412 return FontDescription::Size(
413 0, (primitive_value.GetFloatValue() * parent_size.value / 100.0f),
414 parent_size.is_absolute);
415 }
416
417 // TODO(crbug.com/979895): This is the result of a refactoring, which might
418 // have revealed an existing bug with calculated lengths. Investigate.
419 const bool is_absolute =
420 parent_size.is_absolute || primitive_value.IsMathFunctionValue() ||
421 !To<CSSNumericLiteralValue>(primitive_value).IsFontRelativeLength();
422 return FontDescription::Size(
423 0, ComputeFontSize(conversion_data, primitive_value, parent_size),
424 is_absolute);
425 }
426
ConvertFontSize(StyleResolverState & state,const CSSValue & value)427 FontDescription::Size StyleBuilderConverter::ConvertFontSize(
428 StyleResolverState& state,
429 const CSSValue& value) {
430 // FIXME: Find out when parentStyle could be 0?
431 auto parent_size = state.ParentStyle()
432 ? state.ParentFontDescription().GetSize()
433 : FontDescription::Size(0, 0.0f, false);
434
435 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
436 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kMath) {
437 auto scale_factor = MathScriptScaleFactor(state);
438 state.Style()->SetHasGlyphRelativeUnits();
439 return FontDescription::Size(0, (scale_factor * parent_size.value),
440 parent_size.is_absolute);
441 }
442
443 return StyleBuilderConverterBase::ConvertFontSize(
444 value, state.FontSizeConversionData(), parent_size);
445 }
446
ConvertFontSizeAdjust(StyleResolverState & state,const CSSValue & value)447 float StyleBuilderConverter::ConvertFontSizeAdjust(StyleResolverState& state,
448 const CSSValue& value) {
449 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
450 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNone)
451 return FontBuilder::InitialSizeAdjust();
452
453 const auto& primitive_value = To<CSSPrimitiveValue>(value);
454 DCHECK(primitive_value.IsNumber());
455 return primitive_value.GetFloatValue();
456 }
457
ConvertFontStretch(const blink::CSSValue & value)458 FontSelectionValue StyleBuilderConverterBase::ConvertFontStretch(
459 const blink::CSSValue& value) {
460 if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
461 if (primitive_value->IsPercentage())
462 return clampTo<FontSelectionValue>(primitive_value->GetFloatValue());
463 }
464
465 // TODO(drott) crbug.com/750014: Consider not parsing them as IdentifierValue
466 // any more?
467 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
468 switch (identifier_value->GetValueID()) {
469 case CSSValueID::kUltraCondensed:
470 return UltraCondensedWidthValue();
471 case CSSValueID::kExtraCondensed:
472 return ExtraCondensedWidthValue();
473 case CSSValueID::kCondensed:
474 return CondensedWidthValue();
475 case CSSValueID::kSemiCondensed:
476 return SemiCondensedWidthValue();
477 case CSSValueID::kNormal:
478 return NormalWidthValue();
479 case CSSValueID::kSemiExpanded:
480 return SemiExpandedWidthValue();
481 case CSSValueID::kExpanded:
482 return ExpandedWidthValue();
483 case CSSValueID::kExtraExpanded:
484 return ExtraExpandedWidthValue();
485 case CSSValueID::kUltraExpanded:
486 return UltraExpandedWidthValue();
487 default:
488 break;
489 }
490 }
491 NOTREACHED();
492 return NormalWidthValue();
493 }
494
ConvertFontStretch(blink::StyleResolverState & state,const blink::CSSValue & value)495 FontSelectionValue StyleBuilderConverter::ConvertFontStretch(
496 blink::StyleResolverState& state,
497 const blink::CSSValue& value) {
498 return StyleBuilderConverterBase::ConvertFontStretch(value);
499 }
500
ConvertFontStyle(const CSSValue & value)501 FontSelectionValue StyleBuilderConverterBase::ConvertFontStyle(
502 const CSSValue& value) {
503 DCHECK(!value.IsPrimitiveValue());
504
505 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
506 switch (identifier_value->GetValueID()) {
507 case CSSValueID::kItalic:
508 case CSSValueID::kOblique:
509 return ItalicSlopeValue();
510 case CSSValueID::kNormal:
511 return NormalSlopeValue();
512 default:
513 NOTREACHED();
514 return NormalSlopeValue();
515 }
516 } else if (const auto* style_range_value =
517 DynamicTo<cssvalue::CSSFontStyleRangeValue>(value)) {
518 const CSSValueList* values = style_range_value->GetObliqueValues();
519 CHECK_LT(values->length(), 2u);
520 if (values->length()) {
521 return FontSelectionValue(
522 To<CSSPrimitiveValue>(values->Item(0)).ComputeDegrees());
523 } else {
524 identifier_value = style_range_value->GetFontStyleValue();
525 if (identifier_value->GetValueID() == CSSValueID::kNormal)
526 return NormalSlopeValue();
527 if (identifier_value->GetValueID() == CSSValueID::kItalic ||
528 identifier_value->GetValueID() == CSSValueID::kOblique)
529 return ItalicSlopeValue();
530 }
531 }
532
533 NOTREACHED();
534 return NormalSlopeValue();
535 }
536
ConvertFontStyle(StyleResolverState & state,const CSSValue & value)537 FontSelectionValue StyleBuilderConverter::ConvertFontStyle(
538 StyleResolverState& state,
539 const CSSValue& value) {
540 return StyleBuilderConverterBase::ConvertFontStyle(value);
541 }
542
ConvertFontWeight(const CSSValue & value,FontSelectionValue parent_weight)543 FontSelectionValue StyleBuilderConverterBase::ConvertFontWeight(
544 const CSSValue& value,
545 FontSelectionValue parent_weight) {
546 if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
547 if (primitive_value->IsNumber())
548 return clampTo<FontSelectionValue>(primitive_value->GetFloatValue());
549 }
550
551 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
552 switch (identifier_value->GetValueID()) {
553 case CSSValueID::kNormal:
554 return NormalWeightValue();
555 case CSSValueID::kBold:
556 return BoldWeightValue();
557 case CSSValueID::kBolder:
558 return FontDescription::BolderWeight(parent_weight);
559 case CSSValueID::kLighter:
560 return FontDescription::LighterWeight(parent_weight);
561 default:
562 NOTREACHED();
563 return NormalWeightValue();
564 }
565 }
566 NOTREACHED();
567 return NormalWeightValue();
568 }
569
ConvertFontWeight(StyleResolverState & state,const CSSValue & value)570 FontSelectionValue StyleBuilderConverter::ConvertFontWeight(
571 StyleResolverState& state,
572 const CSSValue& value) {
573 return StyleBuilderConverterBase::ConvertFontWeight(
574 value, state.ParentStyle()->GetFontDescription().Weight());
575 }
576
577 FontDescription::FontVariantCaps
ConvertFontVariantCaps(const CSSValue & value)578 StyleBuilderConverterBase::ConvertFontVariantCaps(const CSSValue& value) {
579 CSSValueID value_id = To<CSSIdentifierValue>(value).GetValueID();
580 switch (value_id) {
581 case CSSValueID::kNormal:
582 return FontDescription::kCapsNormal;
583 case CSSValueID::kSmallCaps:
584 return FontDescription::kSmallCaps;
585 case CSSValueID::kAllSmallCaps:
586 return FontDescription::kAllSmallCaps;
587 case CSSValueID::kPetiteCaps:
588 return FontDescription::kPetiteCaps;
589 case CSSValueID::kAllPetiteCaps:
590 return FontDescription::kAllPetiteCaps;
591 case CSSValueID::kUnicase:
592 return FontDescription::kUnicase;
593 case CSSValueID::kTitlingCaps:
594 return FontDescription::kTitlingCaps;
595 default:
596 return FontDescription::kCapsNormal;
597 }
598 }
599
ConvertFontVariantCaps(StyleResolverState &,const CSSValue & value)600 FontDescription::FontVariantCaps StyleBuilderConverter::ConvertFontVariantCaps(
601 StyleResolverState&,
602 const CSSValue& value) {
603 return StyleBuilderConverterBase::ConvertFontVariantCaps(value);
604 }
605
606 FontDescription::VariantLigatures
ConvertFontVariantLigatures(StyleResolverState &,const CSSValue & value)607 StyleBuilderConverter::ConvertFontVariantLigatures(StyleResolverState&,
608 const CSSValue& value) {
609 if (const auto* value_list = DynamicTo<CSSValueList>(value)) {
610 FontDescription::VariantLigatures ligatures;
611 for (wtf_size_t i = 0; i < value_list->length(); ++i) {
612 const CSSValue& item = value_list->Item(i);
613 switch (To<CSSIdentifierValue>(item).GetValueID()) {
614 case CSSValueID::kNoCommonLigatures:
615 ligatures.common = FontDescription::kDisabledLigaturesState;
616 break;
617 case CSSValueID::kCommonLigatures:
618 ligatures.common = FontDescription::kEnabledLigaturesState;
619 break;
620 case CSSValueID::kNoDiscretionaryLigatures:
621 ligatures.discretionary = FontDescription::kDisabledLigaturesState;
622 break;
623 case CSSValueID::kDiscretionaryLigatures:
624 ligatures.discretionary = FontDescription::kEnabledLigaturesState;
625 break;
626 case CSSValueID::kNoHistoricalLigatures:
627 ligatures.historical = FontDescription::kDisabledLigaturesState;
628 break;
629 case CSSValueID::kHistoricalLigatures:
630 ligatures.historical = FontDescription::kEnabledLigaturesState;
631 break;
632 case CSSValueID::kNoContextual:
633 ligatures.contextual = FontDescription::kDisabledLigaturesState;
634 break;
635 case CSSValueID::kContextual:
636 ligatures.contextual = FontDescription::kEnabledLigaturesState;
637 break;
638 default:
639 NOTREACHED();
640 break;
641 }
642 }
643 return ligatures;
644 }
645
646 if (To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kNone) {
647 return FontDescription::VariantLigatures(
648 FontDescription::kDisabledLigaturesState);
649 }
650
651 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNormal);
652 return FontDescription::VariantLigatures();
653 }
654
ConvertFontVariantNumeric(StyleResolverState &,const CSSValue & value)655 FontVariantNumeric StyleBuilderConverter::ConvertFontVariantNumeric(
656 StyleResolverState&,
657 const CSSValue& value) {
658 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
659 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNormal);
660 return FontVariantNumeric();
661 }
662
663 FontVariantNumeric variant_numeric;
664 for (const CSSValue* feature : To<CSSValueList>(value)) {
665 switch (To<CSSIdentifierValue>(feature)->GetValueID()) {
666 case CSSValueID::kLiningNums:
667 variant_numeric.SetNumericFigure(FontVariantNumeric::kLiningNums);
668 break;
669 case CSSValueID::kOldstyleNums:
670 variant_numeric.SetNumericFigure(FontVariantNumeric::kOldstyleNums);
671 break;
672 case CSSValueID::kProportionalNums:
673 variant_numeric.SetNumericSpacing(
674 FontVariantNumeric::kProportionalNums);
675 break;
676 case CSSValueID::kTabularNums:
677 variant_numeric.SetNumericSpacing(FontVariantNumeric::kTabularNums);
678 break;
679 case CSSValueID::kDiagonalFractions:
680 variant_numeric.SetNumericFraction(
681 FontVariantNumeric::kDiagonalFractions);
682 break;
683 case CSSValueID::kStackedFractions:
684 variant_numeric.SetNumericFraction(
685 FontVariantNumeric::kStackedFractions);
686 break;
687 case CSSValueID::kOrdinal:
688 variant_numeric.SetOrdinal(FontVariantNumeric::kOrdinalOn);
689 break;
690 case CSSValueID::kSlashedZero:
691 variant_numeric.SetSlashedZero(FontVariantNumeric::kSlashedZeroOn);
692 break;
693 default:
694 NOTREACHED();
695 break;
696 }
697 }
698 return variant_numeric;
699 }
700
ConvertFontVariantEastAsian(StyleResolverState &,const CSSValue & value)701 FontVariantEastAsian StyleBuilderConverter::ConvertFontVariantEastAsian(
702 StyleResolverState&,
703 const CSSValue& value) {
704 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
705 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNormal);
706 return FontVariantEastAsian();
707 }
708
709 FontVariantEastAsian variant_east_asian;
710 for (const CSSValue* feature : To<CSSValueList>(value)) {
711 switch (To<CSSIdentifierValue>(feature)->GetValueID()) {
712 case CSSValueID::kJis78:
713 variant_east_asian.SetForm(FontVariantEastAsian::kJis78);
714 break;
715 case CSSValueID::kJis83:
716 variant_east_asian.SetForm(FontVariantEastAsian::kJis83);
717 break;
718 case CSSValueID::kJis90:
719 variant_east_asian.SetForm(FontVariantEastAsian::kJis90);
720 break;
721 case CSSValueID::kJis04:
722 variant_east_asian.SetForm(FontVariantEastAsian::kJis04);
723 break;
724 case CSSValueID::kSimplified:
725 variant_east_asian.SetForm(FontVariantEastAsian::kSimplified);
726 break;
727 case CSSValueID::kTraditional:
728 variant_east_asian.SetForm(FontVariantEastAsian::kTraditional);
729 break;
730 case CSSValueID::kFullWidth:
731 variant_east_asian.SetWidth(FontVariantEastAsian::kFullWidth);
732 break;
733 case CSSValueID::kProportionalWidth:
734 variant_east_asian.SetWidth(FontVariantEastAsian::kProportionalWidth);
735 break;
736 case CSSValueID::kRuby:
737 variant_east_asian.SetRuby(true);
738 break;
739 default:
740 NOTREACHED();
741 break;
742 }
743 }
744 return variant_east_asian;
745 }
746
ConvertSelfOrDefaultAlignmentData(StyleResolverState &,const CSSValue & value)747 StyleSelfAlignmentData StyleBuilderConverter::ConvertSelfOrDefaultAlignmentData(
748 StyleResolverState&,
749 const CSSValue& value) {
750 StyleSelfAlignmentData alignment_data =
751 ComputedStyleInitialValues::InitialAlignSelf();
752 if (const auto* pair = DynamicTo<CSSValuePair>(value)) {
753 if (To<CSSIdentifierValue>(pair->First()).GetValueID() ==
754 CSSValueID::kLegacy) {
755 alignment_data.SetPositionType(ItemPositionType::kLegacy);
756 alignment_data.SetPosition(
757 To<CSSIdentifierValue>(pair->Second()).ConvertTo<ItemPosition>());
758 } else if (To<CSSIdentifierValue>(pair->First()).GetValueID() ==
759 CSSValueID::kFirst) {
760 alignment_data.SetPosition(ItemPosition::kBaseline);
761 } else if (To<CSSIdentifierValue>(pair->First()).GetValueID() ==
762 CSSValueID::kLast) {
763 alignment_data.SetPosition(ItemPosition::kLastBaseline);
764 } else {
765 alignment_data.SetOverflow(
766 To<CSSIdentifierValue>(pair->First()).ConvertTo<OverflowAlignment>());
767 alignment_data.SetPosition(
768 To<CSSIdentifierValue>(pair->Second()).ConvertTo<ItemPosition>());
769 }
770 } else {
771 alignment_data.SetPosition(
772 To<CSSIdentifierValue>(value).ConvertTo<ItemPosition>());
773 }
774 return alignment_data;
775 }
776
ConvertContentAlignmentData(StyleResolverState &,const CSSValue & value)777 StyleContentAlignmentData StyleBuilderConverter::ConvertContentAlignmentData(
778 StyleResolverState&,
779 const CSSValue& value) {
780 StyleContentAlignmentData alignment_data =
781 ComputedStyleInitialValues::InitialContentAlignment();
782 const cssvalue::CSSContentDistributionValue& content_value =
783 To<cssvalue::CSSContentDistributionValue>(value);
784 if (IsValidCSSValueID(content_value.Distribution())) {
785 alignment_data.SetDistribution(
786 CSSIdentifierValue::Create(content_value.Distribution())
787 ->ConvertTo<ContentDistributionType>());
788 }
789 if (IsValidCSSValueID(content_value.Position())) {
790 alignment_data.SetPosition(
791 CSSIdentifierValue::Create(content_value.Position())
792 ->ConvertTo<ContentPosition>());
793 }
794 if (IsValidCSSValueID(content_value.Overflow())) {
795 alignment_data.SetOverflow(
796 CSSIdentifierValue::Create(content_value.Overflow())
797 ->ConvertTo<OverflowAlignment>());
798 }
799
800 return alignment_data;
801 }
802
ConvertGridAutoFlow(StyleResolverState &,const CSSValue & value)803 GridAutoFlow StyleBuilderConverter::ConvertGridAutoFlow(StyleResolverState&,
804 const CSSValue& value) {
805 const auto& list = To<CSSValueList>(value);
806
807 DCHECK_GE(list.length(), 1u);
808 const CSSIdentifierValue& first = To<CSSIdentifierValue>(list.Item(0));
809 const CSSIdentifierValue* second =
810 list.length() == 2 ? &To<CSSIdentifierValue>(list.Item(1)) : nullptr;
811
812 switch (first.GetValueID()) {
813 case CSSValueID::kRow:
814 if (second && second->GetValueID() == CSSValueID::kDense)
815 return kAutoFlowRowDense;
816 return kAutoFlowRow;
817 case CSSValueID::kColumn:
818 if (second && second->GetValueID() == CSSValueID::kDense)
819 return kAutoFlowColumnDense;
820 return kAutoFlowColumn;
821 case CSSValueID::kDense:
822 if (second && second->GetValueID() == CSSValueID::kColumn)
823 return kAutoFlowColumnDense;
824 return kAutoFlowRowDense;
825 default:
826 NOTREACHED();
827 return ComputedStyleInitialValues::InitialGridAutoFlow();
828 }
829 }
830
ConvertGridPosition(StyleResolverState &,const CSSValue & value)831 GridPosition StyleBuilderConverter::ConvertGridPosition(StyleResolverState&,
832 const CSSValue& value) {
833 // We accept the specification's grammar:
834 // 'auto' | [ <integer> || <custom-ident> ] |
835 // [ span && [ <integer> || <custom-ident> ] ] | <custom-ident>
836
837 GridPosition position;
838
839 if (auto* ident_value = DynamicTo<CSSCustomIdentValue>(value)) {
840 position.SetNamedGridArea(ident_value->Value());
841 return position;
842 }
843
844 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
845 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kAuto);
846 return position;
847 }
848
849 const auto& values = To<CSSValueList>(value);
850 DCHECK(values.length());
851
852 bool is_span_position = false;
853 // The specification makes the <integer> optional, in which case it default to
854 // '1'.
855 int grid_line_number = 1;
856 AtomicString grid_line_name;
857
858 auto* it = values.begin();
859 const CSSValue* current_value = it->Get();
860 auto* current_identifier_value = DynamicTo<CSSIdentifierValue>(current_value);
861 if (current_identifier_value &&
862 current_identifier_value->GetValueID() == CSSValueID::kSpan) {
863 is_span_position = true;
864 ++it;
865 current_value = it != values.end() ? it->Get() : nullptr;
866 }
867
868 auto* current_primitive_value = DynamicTo<CSSPrimitiveValue>(current_value);
869 if (current_primitive_value && current_primitive_value->IsNumber()) {
870 grid_line_number = current_primitive_value->GetIntValue();
871 ++it;
872 current_value = it != values.end() ? it->Get() : nullptr;
873 }
874
875 auto* current_ident_value = DynamicTo<CSSCustomIdentValue>(current_value);
876 if (current_ident_value) {
877 grid_line_name = current_ident_value->Value();
878 ++it;
879 }
880
881 DCHECK_EQ(it, values.end());
882 if (is_span_position)
883 position.SetSpanPosition(grid_line_number, grid_line_name);
884 else
885 position.SetExplicitPosition(grid_line_number, grid_line_name);
886
887 return position;
888 }
889
ConvertGridTrackSize(StyleResolverState & state,const CSSValue & value)890 GridTrackSize StyleBuilderConverter::ConvertGridTrackSize(
891 StyleResolverState& state,
892 const CSSValue& value) {
893 if (value.IsPrimitiveValue() || value.IsIdentifierValue())
894 return GridTrackSize(ConvertGridTrackBreadth(state, value));
895
896 auto& function = To<CSSFunctionValue>(value);
897 if (function.FunctionType() == CSSValueID::kFitContent) {
898 SECURITY_DCHECK(function.length() == 1);
899 return GridTrackSize(ConvertGridTrackBreadth(state, function.Item(0)),
900 kFitContentTrackSizing);
901 }
902
903 SECURITY_DCHECK(function.length() == 2);
904 GridLength min_track_breadth(
905 ConvertGridTrackBreadth(state, function.Item(0)));
906 GridLength max_track_breadth(
907 ConvertGridTrackBreadth(state, function.Item(1)));
908 return GridTrackSize(min_track_breadth, max_track_breadth);
909 }
910
ConvertGridLineNamesList(const CSSValue & value,size_t current_named_grid_line,NamedGridLinesMap & named_grid_lines,OrderedNamedGridLines & ordered_named_grid_lines)911 static void ConvertGridLineNamesList(
912 const CSSValue& value,
913 size_t current_named_grid_line,
914 NamedGridLinesMap& named_grid_lines,
915 OrderedNamedGridLines& ordered_named_grid_lines) {
916 DCHECK(value.IsGridLineNamesValue());
917
918 for (auto& named_grid_line_value : To<CSSValueList>(value)) {
919 String named_grid_line =
920 To<CSSCustomIdentValue>(*named_grid_line_value).Value();
921 NamedGridLinesMap::AddResult result =
922 named_grid_lines.insert(named_grid_line, Vector<size_t>());
923 result.stored_value->value.push_back(current_named_grid_line);
924 OrderedNamedGridLines::AddResult ordered_insertion_result =
925 ordered_named_grid_lines.insert(current_named_grid_line,
926 Vector<String>());
927 ordered_insertion_result.stored_value->value.push_back(named_grid_line);
928 }
929 }
930
ConvertGridTrackSizeList(StyleResolverState & state,const CSSValue & value)931 GridTrackList StyleBuilderConverter::ConvertGridTrackSizeList(
932 StyleResolverState& state,
933 const CSSValue& value) {
934 Vector<GridTrackSize> track_sizes;
935 for (auto& curr_value : To<CSSValueList>(value)) {
936 DCHECK(!curr_value->IsGridLineNamesValue());
937 DCHECK(!curr_value->IsGridAutoRepeatValue());
938 DCHECK(!curr_value->IsGridIntegerRepeatValue());
939 track_sizes.push_back(ConvertGridTrackSize(state, *curr_value));
940 }
941
942 return GridTrackList(track_sizes);
943 }
944
ConvertGridTrackList(const CSSValue & value,GridTrackList & track_sizes,NamedGridLinesMap & named_grid_lines,OrderedNamedGridLines & ordered_named_grid_lines,Vector<GridTrackSize> & auto_repeat_track_sizes,NamedGridLinesMap & auto_repeat_named_grid_lines,OrderedNamedGridLines & auto_repeat_ordered_named_grid_lines,size_t & auto_repeat_insertion_point,AutoRepeatType & auto_repeat_type,StyleResolverState & state)945 void StyleBuilderConverter::ConvertGridTrackList(
946 const CSSValue& value,
947 GridTrackList& track_sizes,
948 NamedGridLinesMap& named_grid_lines,
949 OrderedNamedGridLines& ordered_named_grid_lines,
950 Vector<GridTrackSize>& auto_repeat_track_sizes,
951 NamedGridLinesMap& auto_repeat_named_grid_lines,
952 OrderedNamedGridLines& auto_repeat_ordered_named_grid_lines,
953 size_t& auto_repeat_insertion_point,
954 AutoRepeatType& auto_repeat_type,
955 StyleResolverState& state) {
956 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
957 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
958 return;
959 }
960
961 size_t current_named_grid_line = 0;
962 auto convert_line_name_or_track_size = [&](const CSSValue& curr_value) {
963 if (curr_value.IsGridLineNamesValue()) {
964 ConvertGridLineNamesList(curr_value, current_named_grid_line,
965 named_grid_lines, ordered_named_grid_lines);
966 } else {
967 ++current_named_grid_line;
968 track_sizes.LegacyTrackList().push_back(
969 ConvertGridTrackSize(state, curr_value));
970 }
971 };
972
973 for (auto curr_value : To<CSSValueList>(value)) {
974 if (auto* grid_auto_repeat_value =
975 DynamicTo<cssvalue::CSSGridAutoRepeatValue>(curr_value.Get())) {
976 Vector<GridTrackSize> repeated_track_sizes;
977 size_t auto_repeat_index = 0;
978 CSSValueID auto_repeat_id = grid_auto_repeat_value->AutoRepeatID();
979 DCHECK(auto_repeat_id == CSSValueID::kAutoFill ||
980 auto_repeat_id == CSSValueID::kAutoFit);
981 auto_repeat_type = auto_repeat_id == CSSValueID::kAutoFill
982 ? AutoRepeatType::kAutoFill
983 : AutoRepeatType::kAutoFit;
984 for (auto auto_repeat_value : To<CSSValueList>(*curr_value)) {
985 if (auto_repeat_value->IsGridLineNamesValue()) {
986 ConvertGridLineNamesList(*auto_repeat_value, auto_repeat_index,
987 auto_repeat_named_grid_lines,
988 auto_repeat_ordered_named_grid_lines);
989 continue;
990 }
991 ++auto_repeat_index;
992 repeated_track_sizes.push_back(
993 ConvertGridTrackSize(state, *auto_repeat_value));
994 }
995 if (RuntimeEnabledFeatures::LayoutNGGridEnabled()) {
996 track_sizes.NGTrackList().AddAutoRepeater(
997 repeated_track_sizes,
998 static_cast<NGGridTrackRepeater::RepeatType>(auto_repeat_type));
999 }
1000 DCHECK(auto_repeat_track_sizes.IsEmpty());
1001 auto_repeat_track_sizes = std::move(repeated_track_sizes);
1002 auto_repeat_insertion_point = current_named_grid_line++;
1003 continue;
1004 }
1005
1006 if (auto* repeated_values =
1007 DynamicTo<cssvalue::CSSGridIntegerRepeatValue>(curr_value.Get())) {
1008 size_t repetitions = repeated_values->Repetitions();
1009 for (size_t i = 0; i < repetitions; ++i) {
1010 for (auto curr_repeat_value : *repeated_values)
1011 convert_line_name_or_track_size(*curr_repeat_value);
1012 }
1013 if (RuntimeEnabledFeatures::LayoutNGGridEnabled()) {
1014 Vector<GridTrackSize> repeater_sizes;
1015 for (auto curr_repeat_value : *repeated_values) {
1016 if (!curr_repeat_value->IsGridLineNamesValue()) {
1017 repeater_sizes.push_back(
1018 ConvertGridTrackSize(state, *curr_repeat_value));
1019 }
1020 }
1021 track_sizes.NGTrackList().AddRepeater(repeater_sizes, repetitions);
1022 }
1023 continue;
1024 }
1025
1026 convert_line_name_or_track_size(*curr_value);
1027 if (RuntimeEnabledFeatures::LayoutNGGridEnabled() &&
1028 !curr_value->IsGridLineNamesValue()) {
1029 track_sizes.NGTrackList().AddRepeater(
1030 {ConvertGridTrackSize(state, *curr_value)}, 1);
1031 }
1032 }
1033
1034 // The parser should have rejected any <track-list> without any <track-size>
1035 // as this is not conformant to the syntax.
1036 DCHECK(!track_sizes.LegacyTrackList().IsEmpty() ||
1037 !auto_repeat_track_sizes.IsEmpty());
1038 }
1039
CreateImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap & named_grid_areas,NamedGridLinesMap & named_grid_lines,GridTrackSizingDirection direction)1040 void StyleBuilderConverter::CreateImplicitNamedGridLinesFromGridArea(
1041 const NamedGridAreaMap& named_grid_areas,
1042 NamedGridLinesMap& named_grid_lines,
1043 GridTrackSizingDirection direction) {
1044 for (const auto& named_grid_area_entry : named_grid_areas) {
1045 GridSpan area_span = direction == kForRows
1046 ? named_grid_area_entry.value.rows
1047 : named_grid_area_entry.value.columns;
1048 {
1049 NamedGridLinesMap::AddResult start_result = named_grid_lines.insert(
1050 named_grid_area_entry.key + "-start", Vector<size_t>());
1051 start_result.stored_value->value.push_back(area_span.StartLine());
1052 std::sort(start_result.stored_value->value.begin(),
1053 start_result.stored_value->value.end());
1054 }
1055 {
1056 NamedGridLinesMap::AddResult end_result = named_grid_lines.insert(
1057 named_grid_area_entry.key + "-end", Vector<size_t>());
1058 end_result.stored_value->value.push_back(area_span.EndLine());
1059 std::sort(end_result.stored_value->value.begin(),
1060 end_result.stored_value->value.end());
1061 }
1062 }
1063 }
1064
ConvertBorderWidth(StyleResolverState & state,const CSSValue & value)1065 float StyleBuilderConverter::ConvertBorderWidth(StyleResolverState& state,
1066 const CSSValue& value) {
1067 double result = 0;
1068 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1069 switch (identifier_value->GetValueID()) {
1070 case CSSValueID::kThin:
1071 result = 1;
1072 break;
1073 case CSSValueID::kMedium:
1074 result = 3;
1075 break;
1076 case CSSValueID::kThick:
1077 result = 5;
1078 break;
1079 default:
1080 NOTREACHED();
1081 break;
1082 }
1083 result = state.CssToLengthConversionData().ZoomedComputedPixels(
1084 result, CSSPrimitiveValue::UnitType::kPixels);
1085 } else {
1086 const auto& primitive_value = To<CSSPrimitiveValue>(value);
1087 result =
1088 primitive_value.ComputeLength<float>(state.CssToLengthConversionData());
1089 }
1090 if (result > 0.0 && result < 1.0)
1091 return 1.0;
1092 return clampTo<float>(result, defaultMinimumForClamp<float>(),
1093 defaultMaximumForClamp<float>());
1094 }
1095
ConvertLayoutUnit(StyleResolverState & state,const CSSValue & value)1096 LayoutUnit StyleBuilderConverter::ConvertLayoutUnit(StyleResolverState& state,
1097 const CSSValue& value) {
1098 return LayoutUnit::Clamp(ConvertComputedLength<float>(state, value));
1099 }
1100
ConvertGapLength(const StyleResolverState & state,const CSSValue & value)1101 base::Optional<Length> StyleBuilderConverter::ConvertGapLength(
1102 const StyleResolverState& state,
1103 const CSSValue& value) {
1104 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1105 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNormal)
1106 return base::nullopt;
1107
1108 return ConvertLength(state, value);
1109 }
1110
ConvertLength(const StyleResolverState & state,const CSSValue & value)1111 Length StyleBuilderConverter::ConvertLength(const StyleResolverState& state,
1112 const CSSValue& value) {
1113 return To<CSSPrimitiveValue>(value).ConvertToLength(
1114 state.CssToLengthConversionData());
1115 }
1116
ConvertUnzoomedLength(const StyleResolverState & state,const CSSValue & value)1117 UnzoomedLength StyleBuilderConverter::ConvertUnzoomedLength(
1118 const StyleResolverState& state,
1119 const CSSValue& value) {
1120 return UnzoomedLength(To<CSSPrimitiveValue>(value).ConvertToLength(
1121 state.UnzoomedLengthConversionData()));
1122 }
1123
ConvertZoom(const StyleResolverState & state,const CSSValue & value)1124 float StyleBuilderConverter::ConvertZoom(const StyleResolverState& state,
1125 const CSSValue& value) {
1126 SECURITY_DCHECK(value.IsPrimitiveValue() || value.IsIdentifierValue());
1127
1128 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1129 if (identifier_value->GetValueID() == CSSValueID::kNormal)
1130 return ComputedStyleInitialValues::InitialZoom();
1131 } else if (const auto* primitive_value =
1132 DynamicTo<CSSPrimitiveValue>(value)) {
1133 if (primitive_value->IsPercentage()) {
1134 float percent = primitive_value->GetFloatValue();
1135 return percent ? (percent / 100.0f) : 1.0f;
1136 } else if (primitive_value->IsNumber()) {
1137 float number = primitive_value->GetFloatValue();
1138 return number ? number : 1.0f;
1139 }
1140 }
1141
1142 NOTREACHED();
1143 return 1.0f;
1144 }
1145
ConvertLengthOrAuto(const StyleResolverState & state,const CSSValue & value)1146 Length StyleBuilderConverter::ConvertLengthOrAuto(
1147 const StyleResolverState& state,
1148 const CSSValue& value) {
1149 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1150 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
1151 return Length::Auto();
1152 return To<CSSPrimitiveValue>(value).ConvertToLength(
1153 state.CssToLengthConversionData());
1154 }
1155
ConvertLengthSizing(StyleResolverState & state,const CSSValue & value)1156 Length StyleBuilderConverter::ConvertLengthSizing(StyleResolverState& state,
1157 const CSSValue& value) {
1158 const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1159 if (!identifier_value)
1160 return ConvertLength(state, value);
1161
1162 switch (identifier_value->GetValueID()) {
1163 case CSSValueID::kMinContent:
1164 case CSSValueID::kWebkitMinContent:
1165 return Length::MinContent();
1166 case CSSValueID::kMaxContent:
1167 case CSSValueID::kWebkitMaxContent:
1168 return Length::MaxContent();
1169 case CSSValueID::kWebkitFillAvailable:
1170 return Length::FillAvailable();
1171 case CSSValueID::kWebkitFitContent:
1172 case CSSValueID::kFitContent:
1173 return Length::FitContent();
1174 case CSSValueID::kAuto:
1175 return Length::Auto();
1176 default:
1177 NOTREACHED();
1178 return Length();
1179 }
1180 }
1181
ConvertLengthMaxSizing(StyleResolverState & state,const CSSValue & value)1182 Length StyleBuilderConverter::ConvertLengthMaxSizing(StyleResolverState& state,
1183 const CSSValue& value) {
1184 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1185 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNone)
1186 return Length::None();
1187 return ConvertLengthSizing(state, value);
1188 }
1189
ConvertLengthOrTabSpaces(StyleResolverState & state,const CSSValue & value)1190 TabSize StyleBuilderConverter::ConvertLengthOrTabSpaces(
1191 StyleResolverState& state,
1192 const CSSValue& value) {
1193 const auto& primitive_value = To<CSSPrimitiveValue>(value);
1194 if (primitive_value.IsNumber())
1195 return TabSize(primitive_value.GetFloatValue(), TabSizeValueType::kSpace);
1196 return TabSize(
1197 primitive_value.ComputeLength<float>(state.CssToLengthConversionData()),
1198 TabSizeValueType::kLength);
1199 }
1200
LineHeightToLengthConversionData(StyleResolverState & state)1201 static CSSToLengthConversionData LineHeightToLengthConversionData(
1202 StyleResolverState& state) {
1203 float multiplier = state.Style()->EffectiveZoom();
1204 if (LocalFrame* frame = state.GetDocument().GetFrame())
1205 multiplier *= frame->TextZoomFactor();
1206 return state.CssToLengthConversionData().CopyWithAdjustedZoom(multiplier);
1207 }
1208
ConvertLineHeight(StyleResolverState & state,const CSSValue & value)1209 Length StyleBuilderConverter::ConvertLineHeight(StyleResolverState& state,
1210 const CSSValue& value) {
1211 if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
1212 if (primitive_value->IsLength()) {
1213 return primitive_value->ComputeLength<Length>(
1214 LineHeightToLengthConversionData(state));
1215 }
1216 if (primitive_value->IsPercentage()) {
1217 return Length::Fixed(
1218 (state.Style()->ComputedFontSize() * primitive_value->GetIntValue()) /
1219 100.0);
1220 }
1221 if (primitive_value->IsNumber()) {
1222 return Length::Percent(
1223 clampTo<float>(primitive_value->GetDoubleValue() * 100.0));
1224 }
1225 if (primitive_value->IsCalculated()) {
1226 Length zoomed_length =
1227 Length(To<CSSMathFunctionValue>(primitive_value)
1228 ->ToCalcValue(LineHeightToLengthConversionData(state)));
1229 return Length::Fixed(ValueForLength(
1230 zoomed_length, LayoutUnit(state.Style()->ComputedFontSize())));
1231 }
1232 }
1233
1234 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNormal);
1235 return ComputedStyleInitialValues::InitialLineHeight();
1236 }
1237
ConvertNumberOrPercentage(StyleResolverState & state,const CSSValue & value)1238 float StyleBuilderConverter::ConvertNumberOrPercentage(
1239 StyleResolverState& state,
1240 const CSSValue& value) {
1241 const auto& primitive_value = To<CSSPrimitiveValue>(value);
1242 DCHECK(primitive_value.IsNumber() || primitive_value.IsPercentage());
1243 if (primitive_value.IsNumber())
1244 return primitive_value.GetFloatValue();
1245 return primitive_value.GetFloatValue() / 100.0f;
1246 }
1247
ConvertAlpha(StyleResolverState & state,const CSSValue & value)1248 float StyleBuilderConverter::ConvertAlpha(StyleResolverState& state,
1249 const CSSValue& value) {
1250 return clampTo<float>(ConvertNumberOrPercentage(state, value), 0, 1);
1251 }
1252
ConvertOffsetRotate(StyleResolverState &,const CSSValue & value)1253 StyleOffsetRotation StyleBuilderConverter::ConvertOffsetRotate(
1254 StyleResolverState&,
1255 const CSSValue& value) {
1256 return ConvertOffsetRotate(value);
1257 }
1258
ConvertOffsetRotate(const CSSValue & value)1259 StyleOffsetRotation StyleBuilderConverter::ConvertOffsetRotate(
1260 const CSSValue& value) {
1261 StyleOffsetRotation result(0, OffsetRotationType::kFixed);
1262
1263 const auto& list = To<CSSValueList>(value);
1264 DCHECK(list.length() == 1 || list.length() == 2);
1265 for (const auto& item : list) {
1266 auto* identifier_value = DynamicTo<CSSIdentifierValue>(item.Get());
1267 if (identifier_value &&
1268 identifier_value->GetValueID() == CSSValueID::kAuto) {
1269 result.type = OffsetRotationType::kAuto;
1270 } else if (identifier_value &&
1271 identifier_value->GetValueID() == CSSValueID::kReverse) {
1272 result.type = OffsetRotationType::kAuto;
1273 result.angle = clampTo<float>(result.angle + 180);
1274 } else {
1275 const auto& primitive_value = To<CSSPrimitiveValue>(*item);
1276 result.angle =
1277 clampTo<float>(result.angle + primitive_value.ComputeDegrees());
1278 }
1279 }
1280
1281 return result;
1282 }
1283
ConvertPosition(StyleResolverState & state,const CSSValue & value)1284 LengthPoint StyleBuilderConverter::ConvertPosition(StyleResolverState& state,
1285 const CSSValue& value) {
1286 const auto& pair = To<CSSValuePair>(value);
1287 return LengthPoint(
1288 ConvertPositionLength<CSSValueID::kLeft, CSSValueID::kRight>(
1289 state, pair.First()),
1290 ConvertPositionLength<CSSValueID::kTop, CSSValueID::kBottom>(
1291 state, pair.Second()));
1292 }
1293
ConvertPositionOrAuto(StyleResolverState & state,const CSSValue & value)1294 LengthPoint StyleBuilderConverter::ConvertPositionOrAuto(
1295 StyleResolverState& state,
1296 const CSSValue& value) {
1297 if (value.IsValuePair())
1298 return ConvertPosition(state, value);
1299 DCHECK(To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kAuto);
1300 return LengthPoint(Length::Auto(), Length::Auto());
1301 }
1302
ConvertPerspectiveLength(StyleResolverState & state,const CSSPrimitiveValue & primitive_value)1303 static float ConvertPerspectiveLength(
1304 StyleResolverState& state,
1305 const CSSPrimitiveValue& primitive_value) {
1306 return std::max(
1307 primitive_value.ComputeLength<float>(state.CssToLengthConversionData()),
1308 0.0f);
1309 }
1310
ConvertPerspective(StyleResolverState & state,const CSSValue & value)1311 float StyleBuilderConverter::ConvertPerspective(StyleResolverState& state,
1312 const CSSValue& value) {
1313 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1314 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNone)
1315 return ComputedStyleInitialValues::InitialPerspective();
1316 return ConvertPerspectiveLength(state, To<CSSPrimitiveValue>(value));
1317 }
1318
ConvertPaintOrder(StyleResolverState &,const CSSValue & css_paint_order)1319 EPaintOrder StyleBuilderConverter::ConvertPaintOrder(
1320 StyleResolverState&,
1321 const CSSValue& css_paint_order) {
1322 if (const auto* order_type_list = DynamicTo<CSSValueList>(css_paint_order)) {
1323 switch (To<CSSIdentifierValue>(order_type_list->Item(0)).GetValueID()) {
1324 case CSSValueID::kFill:
1325 return order_type_list->length() > 1 ? kPaintOrderFillMarkersStroke
1326 : kPaintOrderFillStrokeMarkers;
1327 case CSSValueID::kStroke:
1328 return order_type_list->length() > 1 ? kPaintOrderStrokeMarkersFill
1329 : kPaintOrderStrokeFillMarkers;
1330 case CSSValueID::kMarkers:
1331 return order_type_list->length() > 1 ? kPaintOrderMarkersStrokeFill
1332 : kPaintOrderMarkersFillStroke;
1333 default:
1334 NOTREACHED();
1335 return kPaintOrderNormal;
1336 }
1337 }
1338
1339 return kPaintOrderNormal;
1340 }
1341
ConvertQuirkyLength(StyleResolverState & state,const CSSValue & value)1342 Length StyleBuilderConverter::ConvertQuirkyLength(StyleResolverState& state,
1343 const CSSValue& value) {
1344 Length length = ConvertLengthOrAuto(state, value);
1345 // This is only for margins which use __qem
1346 auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value);
1347 length.SetQuirk(numeric_literal && numeric_literal->IsQuirkyEms());
1348 return length;
1349 }
1350
ConvertQuotes(StyleResolverState &,const CSSValue & value)1351 scoped_refptr<QuotesData> StyleBuilderConverter::ConvertQuotes(
1352 StyleResolverState&,
1353 const CSSValue& value) {
1354 if (const auto* list = DynamicTo<CSSValueList>(value)) {
1355 scoped_refptr<QuotesData> quotes = QuotesData::Create();
1356 for (wtf_size_t i = 0; i < list->length(); i += 2) {
1357 String start_quote = To<CSSStringValue>(list->Item(i)).Value();
1358 String end_quote = To<CSSStringValue>(list->Item(i + 1)).Value();
1359 quotes->AddPair(std::make_pair(start_quote, end_quote));
1360 }
1361 return quotes;
1362 }
1363 if (To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kNone)
1364 return QuotesData::Create();
1365 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kAuto);
1366 return nullptr;
1367 }
1368
ConvertRadius(StyleResolverState & state,const CSSValue & value)1369 LengthSize StyleBuilderConverter::ConvertRadius(StyleResolverState& state,
1370 const CSSValue& value) {
1371 const auto& pair = To<CSSValuePair>(value);
1372 Length radius_width = To<CSSPrimitiveValue>(pair.First())
1373 .ConvertToLength(state.CssToLengthConversionData());
1374 Length radius_height =
1375 To<CSSPrimitiveValue>(pair.Second())
1376 .ConvertToLength(state.CssToLengthConversionData());
1377 return LengthSize(radius_width, radius_height);
1378 }
1379
ConvertShadow(const CSSToLengthConversionData & conversion_data,StyleResolverState * state,const CSSValue & value)1380 ShadowData StyleBuilderConverter::ConvertShadow(
1381 const CSSToLengthConversionData& conversion_data,
1382 StyleResolverState* state,
1383 const CSSValue& value) {
1384 const auto& shadow = To<CSSShadowValue>(value);
1385 float x = shadow.x->ComputeLength<float>(conversion_data);
1386 float y = shadow.y->ComputeLength<float>(conversion_data);
1387 float blur =
1388 shadow.blur ? shadow.blur->ComputeLength<float>(conversion_data) : 0;
1389 float spread =
1390 shadow.spread ? shadow.spread->ComputeLength<float>(conversion_data) : 0;
1391 ShadowStyle shadow_style =
1392 shadow.style && shadow.style->GetValueID() == CSSValueID::kInset
1393 ? ShadowStyle::kInset
1394 : ShadowStyle::kNormal;
1395 StyleColor color = StyleColor::CurrentColor();
1396 if (shadow.color) {
1397 if (state) {
1398 color = ConvertStyleColor(*state, *shadow.color);
1399 } else {
1400 // For OffScreen canvas, we default to black and only parse non
1401 // Document dependent CSS colors.
1402 color = StyleColor(Color::kBlack);
1403 if (auto* color_value =
1404 DynamicTo<cssvalue::CSSColorValue>(shadow.color.Get())) {
1405 color = StyleColor(color_value->Value());
1406 } else {
1407 CSSValueID value_id =
1408 To<CSSIdentifierValue>(*shadow.color).GetValueID();
1409 switch (value_id) {
1410 case CSSValueID::kInvalid:
1411 NOTREACHED();
1412 FALLTHROUGH;
1413 case CSSValueID::kInternalQuirkInherit:
1414 case CSSValueID::kWebkitLink:
1415 case CSSValueID::kWebkitActivelink:
1416 case CSSValueID::kWebkitFocusRingColor:
1417 case CSSValueID::kCurrentcolor:
1418 break;
1419 default:
1420 color = StyleColor(StyleColor::ColorFromKeyword(
1421 value_id, ComputedStyle::InitialStyle().UsedColorScheme()));
1422 }
1423 }
1424 }
1425 }
1426
1427 return ShadowData(FloatPoint(x, y), blur, spread, shadow_style, color);
1428 }
1429
ConvertShadowList(StyleResolverState & state,const CSSValue & value)1430 scoped_refptr<ShadowList> StyleBuilderConverter::ConvertShadowList(
1431 StyleResolverState& state,
1432 const CSSValue& value) {
1433 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1434 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1435 return scoped_refptr<ShadowList>();
1436 }
1437
1438 ShadowDataVector shadows;
1439 for (const auto& item : To<CSSValueList>(value)) {
1440 shadows.push_back(
1441 ConvertShadow(state.CssToLengthConversionData(), &state, *item));
1442 }
1443
1444 return ShadowList::Adopt(shadows);
1445 }
1446
ConvertShapeValue(StyleResolverState & state,const CSSValue & value)1447 ShapeValue* StyleBuilderConverter::ConvertShapeValue(StyleResolverState& state,
1448 const CSSValue& value) {
1449 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1450 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1451 return nullptr;
1452 }
1453
1454 if (value.IsImageValue() || value.IsImageGeneratorValue() ||
1455 value.IsImageSetValue()) {
1456 return MakeGarbageCollected<ShapeValue>(
1457 state.GetStyleImage(CSSPropertyID::kShapeOutside, value));
1458 }
1459
1460 scoped_refptr<BasicShape> shape;
1461 CSSBoxType css_box = CSSBoxType::kMissing;
1462 const auto& value_list = To<CSSValueList>(value);
1463 for (unsigned i = 0; i < value_list.length(); ++i) {
1464 const CSSValue& item_value = value_list.Item(i);
1465 if (item_value.IsBasicShapeValue()) {
1466 shape = BasicShapeForValue(state, item_value);
1467 } else {
1468 css_box = To<CSSIdentifierValue>(item_value).ConvertTo<CSSBoxType>();
1469 }
1470 }
1471
1472 if (shape)
1473 return MakeGarbageCollected<ShapeValue>(std::move(shape), css_box);
1474
1475 DCHECK_NE(css_box, CSSBoxType::kMissing);
1476 return MakeGarbageCollected<ShapeValue>(css_box);
1477 }
1478
ConvertSpacing(StyleResolverState & state,const CSSValue & value)1479 float StyleBuilderConverter::ConvertSpacing(StyleResolverState& state,
1480 const CSSValue& value) {
1481 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1482 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNormal)
1483 return 0;
1484 return To<CSSPrimitiveValue>(value).ComputeLength<float>(
1485 state.CssToLengthConversionData());
1486 }
1487
ConvertStrokeDasharray(StyleResolverState & state,const CSSValue & value)1488 scoped_refptr<SVGDashArray> StyleBuilderConverter::ConvertStrokeDasharray(
1489 StyleResolverState& state,
1490 const CSSValue& value) {
1491 const auto* dashes = DynamicTo<CSSValueList>(value);
1492 if (!dashes)
1493 return SVGComputedStyle::InitialStrokeDashArray();
1494
1495 scoped_refptr<SVGDashArray> array = base::MakeRefCounted<SVGDashArray>();
1496
1497 wtf_size_t length = dashes->length();
1498 for (wtf_size_t i = 0; i < length; ++i) {
1499 array->data.push_back(
1500 ConvertLength(state, To<CSSPrimitiveValue>(dashes->Item(i))));
1501 }
1502
1503 return array;
1504 }
1505
CountSystemColorComputeToSelfUsage(const StyleResolverState & state)1506 void StyleBuilderConverter::CountSystemColorComputeToSelfUsage(
1507 const StyleResolverState& state) {
1508 // Count cases where a system color keyword is used on an element whose
1509 // color-scheme is different from its parent.
1510 // This is a superset of when the feature will change the resolved color
1511 // (inheriting the keyword is also required) but it should be a reasonable
1512 // approximation for use counting purposes.
1513 if (state.Style()->ComputedColorScheme() !=
1514 state.ParentStyle()->ComputedColorScheme()) {
1515 UseCounter::Count(state.GetDocument(),
1516 WebFeature::kCSSSystemColorComputeToSelf);
1517 }
1518 }
1519
ConvertStyleColor(StyleResolverState & state,const CSSValue & value,bool for_visited_link)1520 StyleColor StyleBuilderConverter::ConvertStyleColor(StyleResolverState& state,
1521 const CSSValue& value,
1522 bool for_visited_link) {
1523 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1524 if (identifier_value) {
1525 CSSValueID value_id = identifier_value->GetValueID();
1526 if (value_id == CSSValueID::kCurrentcolor)
1527 return StyleColor::CurrentColor();
1528 if (StyleColor::IsSystemColor(value_id)) {
1529 CountSystemColorComputeToSelfUsage(state);
1530 return StyleColor(
1531 state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
1532 value, Color(), state.Style()->UsedColorScheme(),
1533 for_visited_link),
1534 value_id);
1535 }
1536 }
1537 return StyleColor(state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
1538 value, Color(), state.Style()->UsedColorScheme(), for_visited_link));
1539 }
1540
ConvertStyleAutoColor(StyleResolverState & state,const CSSValue & value,bool for_visited_link)1541 StyleAutoColor StyleBuilderConverter::ConvertStyleAutoColor(
1542 StyleResolverState& state,
1543 const CSSValue& value,
1544 bool for_visited_link) {
1545 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1546 CSSValueID value_id = identifier_value->GetValueID();
1547 if (value_id == CSSValueID::kCurrentcolor)
1548 return StyleAutoColor::CurrentColor();
1549 if (value_id == CSSValueID::kAuto)
1550 return StyleAutoColor::AutoColor();
1551 if (StyleColor::IsSystemColor(value_id)) {
1552 CountSystemColorComputeToSelfUsage(state);
1553 if (RuntimeEnabledFeatures::CSSSystemColorComputeToSelfEnabled())
1554 return StyleAutoColor(value_id);
1555 }
1556 }
1557 return StyleAutoColor(
1558 state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
1559 value, Color(), state.Style()->UsedColorScheme(), for_visited_link));
1560 }
1561
ConvertSVGPaint(StyleResolverState & state,const CSSValue & value)1562 SVGPaint StyleBuilderConverter::ConvertSVGPaint(StyleResolverState& state,
1563 const CSSValue& value) {
1564 const CSSValue* local_value = &value;
1565 SVGPaint paint;
1566 if (const auto* list = DynamicTo<CSSValueList>(value)) {
1567 DCHECK_EQ(list->length(), 2u);
1568 paint.resource = ConvertElementReference(state, list->Item(0));
1569 local_value = &list->Item(1);
1570 }
1571
1572 if (local_value->IsURIValue()) {
1573 paint.type = SVG_PAINTTYPE_URI;
1574 paint.resource = ConvertElementReference(state, *local_value);
1575 } else {
1576 auto* local_identifier_value = DynamicTo<CSSIdentifierValue>(local_value);
1577 if (local_identifier_value &&
1578 local_identifier_value->GetValueID() == CSSValueID::kNone) {
1579 paint.type =
1580 !paint.resource ? SVG_PAINTTYPE_NONE : SVG_PAINTTYPE_URI_NONE;
1581 } else {
1582 paint.color = ConvertStyleColor(state, *local_value);
1583 paint.type =
1584 !paint.resource ? SVG_PAINTTYPE_COLOR : SVG_PAINTTYPE_URI_COLOR;
1585 }
1586 }
1587 return paint;
1588 }
1589
ConvertTextDecorationThickness(StyleResolverState & state,const CSSValue & value)1590 TextDecorationThickness StyleBuilderConverter::ConvertTextDecorationThickness(
1591 StyleResolverState& state,
1592 const CSSValue& value) {
1593 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1594 if (identifier_value &&
1595 identifier_value->GetValueID() == CSSValueID::kFromFont)
1596 return TextDecorationThickness(identifier_value->GetValueID());
1597
1598 return TextDecorationThickness(ConvertLengthOrAuto(state, value));
1599 }
1600
ConvertTextTextEmphasisPosition(StyleResolverState & state,const CSSValue & value)1601 TextEmphasisPosition StyleBuilderConverter::ConvertTextTextEmphasisPosition(
1602 StyleResolverState& state,
1603 const CSSValue& value) {
1604 const auto& list = To<CSSValueList>(value);
1605 CSSValueID first = To<CSSIdentifierValue>(list.Item(0)).GetValueID();
1606 CSSValueID second = To<CSSIdentifierValue>(list.Item(1)).GetValueID();
1607 if (first == CSSValueID::kOver && second == CSSValueID::kRight)
1608 return TextEmphasisPosition::kOverRight;
1609 if (first == CSSValueID::kOver && second == CSSValueID::kLeft)
1610 return TextEmphasisPosition::kOverLeft;
1611 if (first == CSSValueID::kUnder && second == CSSValueID::kRight)
1612 return TextEmphasisPosition::kUnderRight;
1613 if (first == CSSValueID::kUnder && second == CSSValueID::kLeft)
1614 return TextEmphasisPosition::kUnderLeft;
1615 return TextEmphasisPosition::kOverRight;
1616 }
1617
ConvertTextStrokeWidth(StyleResolverState & state,const CSSValue & value)1618 float StyleBuilderConverter::ConvertTextStrokeWidth(StyleResolverState& state,
1619 const CSSValue& value) {
1620 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1621 if (identifier_value && IsValidCSSValueID(identifier_value->GetValueID())) {
1622 float multiplier = ConvertLineWidth<float>(state, value);
1623 return CSSNumericLiteralValue::Create(multiplier / 48,
1624 CSSPrimitiveValue::UnitType::kEms)
1625 ->ComputeLength<float>(state.CssToLengthConversionData());
1626 }
1627 return To<CSSPrimitiveValue>(value).ComputeLength<float>(
1628 state.CssToLengthConversionData());
1629 }
1630
ConvertTextSizeAdjust(StyleResolverState & state,const CSSValue & value)1631 TextSizeAdjust StyleBuilderConverter::ConvertTextSizeAdjust(
1632 StyleResolverState& state,
1633 const CSSValue& value) {
1634 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1635 if (identifier_value->GetValueID() == CSSValueID::kNone)
1636 return TextSizeAdjust::AdjustNone();
1637 if (identifier_value->GetValueID() == CSSValueID::kAuto)
1638 return TextSizeAdjust::AdjustAuto();
1639 }
1640 const CSSPrimitiveValue& primitive_value = To<CSSPrimitiveValue>(value);
1641 DCHECK(primitive_value.IsPercentage());
1642 return TextSizeAdjust(primitive_value.GetFloatValue() / 100.0f);
1643 }
1644
ConvertTextUnderlinePosition(StyleResolverState & state,const CSSValue & value)1645 TextUnderlinePosition StyleBuilderConverter::ConvertTextUnderlinePosition(
1646 StyleResolverState& state,
1647 const CSSValue& value) {
1648 TextUnderlinePosition flags = kTextUnderlinePositionAuto;
1649
1650 auto process = [&flags](const CSSValue& identifier) {
1651 flags |=
1652 To<CSSIdentifierValue>(identifier).ConvertTo<TextUnderlinePosition>();
1653 };
1654
1655 if (auto* value_list = DynamicTo<CSSValueList>(value)) {
1656 for (auto& entry : *value_list) {
1657 process(*entry);
1658 }
1659 } else {
1660 process(value);
1661 }
1662 return flags;
1663 }
1664
ConvertTextUnderlineOffset(StyleResolverState & state,const CSSValue & value)1665 Length StyleBuilderConverter::ConvertTextUnderlineOffset(
1666 StyleResolverState& state,
1667 const CSSValue& value) {
1668 return ConvertLengthOrAuto(state, value);
1669 }
1670
ConvertTransformOperations(StyleResolverState & state,const CSSValue & value)1671 TransformOperations StyleBuilderConverter::ConvertTransformOperations(
1672 StyleResolverState& state,
1673 const CSSValue& value) {
1674 return TransformBuilder::CreateTransformOperations(
1675 value, state.CssToLengthConversionData());
1676 }
1677
ConvertTransformOrigin(StyleResolverState & state,const CSSValue & value)1678 TransformOrigin StyleBuilderConverter::ConvertTransformOrigin(
1679 StyleResolverState& state,
1680 const CSSValue& value) {
1681 const auto& list = To<CSSValueList>(value);
1682 DCHECK_GE(list.length(), 2u);
1683 DCHECK(list.Item(0).IsPrimitiveValue() || list.Item(0).IsIdentifierValue());
1684 DCHECK(list.Item(1).IsPrimitiveValue() || list.Item(1).IsIdentifierValue());
1685 float z = 0;
1686 if (list.length() == 3) {
1687 DCHECK(list.Item(2).IsPrimitiveValue());
1688 z = StyleBuilderConverter::ConvertComputedLength<float>(state,
1689 list.Item(2));
1690 }
1691
1692 return TransformOrigin(
1693 ConvertPositionLength<CSSValueID::kLeft, CSSValueID::kRight>(
1694 state, list.Item(0)),
1695 ConvertPositionLength<CSSValueID::kTop, CSSValueID::kBottom>(
1696 state, list.Item(1)),
1697 z);
1698 }
1699
ConvertSnapType(StyleResolverState &,const CSSValue & value)1700 cc::ScrollSnapType StyleBuilderConverter::ConvertSnapType(
1701 StyleResolverState&,
1702 const CSSValue& value) {
1703 cc::ScrollSnapType snapType =
1704 ComputedStyleInitialValues::InitialScrollSnapType();
1705 if (const auto* pair = DynamicTo<CSSValuePair>(value)) {
1706 snapType.is_none = false;
1707 snapType.axis =
1708 To<CSSIdentifierValue>(pair->First()).ConvertTo<cc::SnapAxis>();
1709 snapType.strictness =
1710 To<CSSIdentifierValue>(pair->Second()).ConvertTo<cc::SnapStrictness>();
1711 return snapType;
1712 }
1713
1714 if (To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kNone) {
1715 snapType.is_none = true;
1716 return snapType;
1717 }
1718
1719 snapType.is_none = false;
1720 snapType.axis = To<CSSIdentifierValue>(value).ConvertTo<cc::SnapAxis>();
1721 return snapType;
1722 }
1723
ConvertSnapAlign(StyleResolverState &,const CSSValue & value)1724 cc::ScrollSnapAlign StyleBuilderConverter::ConvertSnapAlign(
1725 StyleResolverState&,
1726 const CSSValue& value) {
1727 cc::ScrollSnapAlign snapAlign =
1728 ComputedStyleInitialValues::InitialScrollSnapAlign();
1729 if (const auto* pair = DynamicTo<CSSValuePair>(value)) {
1730 snapAlign.alignment_block =
1731 To<CSSIdentifierValue>(pair->First()).ConvertTo<cc::SnapAlignment>();
1732 snapAlign.alignment_inline =
1733 To<CSSIdentifierValue>(pair->Second()).ConvertTo<cc::SnapAlignment>();
1734 } else {
1735 snapAlign.alignment_block =
1736 To<CSSIdentifierValue>(value).ConvertTo<cc::SnapAlignment>();
1737 snapAlign.alignment_inline = snapAlign.alignment_block;
1738 }
1739 return snapAlign;
1740 }
1741
1742 scoped_refptr<TranslateTransformOperation>
ConvertTranslate(StyleResolverState & state,const CSSValue & value)1743 StyleBuilderConverter::ConvertTranslate(StyleResolverState& state,
1744 const CSSValue& value) {
1745 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1746 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1747 return nullptr;
1748 }
1749 const auto& list = To<CSSValueList>(value);
1750 DCHECK_LE(list.length(), 3u);
1751 Length tx = ConvertLength(state, list.Item(0));
1752 Length ty = Length::Fixed(0);
1753 double tz = 0;
1754 if (list.length() >= 2)
1755 ty = ConvertLength(state, list.Item(1));
1756 if (list.length() == 3)
1757 tz = To<CSSPrimitiveValue>(list.Item(2))
1758 .ComputeLength<double>(state.CssToLengthConversionData());
1759
1760 return TranslateTransformOperation::Create(tx, ty, tz,
1761 TransformOperation::kTranslate3D);
1762 }
1763
ConvertRotation(const CSSValue & value)1764 Rotation StyleBuilderConverter::ConvertRotation(const CSSValue& value) {
1765 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1766 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1767 return Rotation(FloatPoint3D(0, 0, 1), 0);
1768 }
1769
1770 const auto& list = To<CSSValueList>(value);
1771 DCHECK(list.length() == 1 || list.length() == 2);
1772 double x = 0;
1773 double y = 0;
1774 double z = 1;
1775 if (list.length() == 2) {
1776 // axis angle
1777 const cssvalue::CSSAxisValue& axis =
1778 To<cssvalue::CSSAxisValue>(list.Item(0));
1779 x = axis.X();
1780 y = axis.Y();
1781 z = axis.Z();
1782 }
1783 double angle =
1784 To<CSSPrimitiveValue>(list.Item(list.length() - 1)).ComputeDegrees();
1785 return Rotation(FloatPoint3D(x, y, z), angle);
1786 }
1787
ConvertRotate(StyleResolverState & state,const CSSValue & value)1788 scoped_refptr<RotateTransformOperation> StyleBuilderConverter::ConvertRotate(
1789 StyleResolverState& state,
1790 const CSSValue& value) {
1791 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1792 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1793 return nullptr;
1794 }
1795
1796 return RotateTransformOperation::Create(ConvertRotation(value),
1797 TransformOperation::kRotate3D);
1798 }
1799
ConvertScale(StyleResolverState & state,const CSSValue & value)1800 scoped_refptr<ScaleTransformOperation> StyleBuilderConverter::ConvertScale(
1801 StyleResolverState& state,
1802 const CSSValue& value) {
1803 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1804 DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
1805 return nullptr;
1806 }
1807
1808 const auto& list = To<CSSValueList>(value);
1809 DCHECK_LE(list.length(), 3u);
1810 double sx = To<CSSPrimitiveValue>(list.Item(0)).GetDoubleValue();
1811 double sy = sx;
1812 double sz = 1;
1813 if (list.length() >= 2)
1814 sy = To<CSSPrimitiveValue>(list.Item(1)).GetDoubleValue();
1815 if (list.length() == 3)
1816 sz = To<CSSPrimitiveValue>(list.Item(2)).GetDoubleValue();
1817
1818 return ScaleTransformOperation::Create(sx, sy, sz,
1819 TransformOperation::kScale3D);
1820 }
1821
ConvertImageOrientation(StyleResolverState & state,const CSSValue & value)1822 RespectImageOrientationEnum StyleBuilderConverter::ConvertImageOrientation(
1823 StyleResolverState& state,
1824 const CSSValue& value) {
1825 // The default is kFromImage, so branch on the only other valid value, kNone
1826 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
1827 return identifier_value && identifier_value->GetValueID() == CSSValueID::kNone
1828 ? kDoNotRespectImageOrientation
1829 : kRespectImageOrientation;
1830 }
1831
ConvertPathOrNone(StyleResolverState & state,const CSSValue & value)1832 scoped_refptr<StylePath> StyleBuilderConverter::ConvertPathOrNone(
1833 StyleResolverState& state,
1834 const CSSValue& value) {
1835 if (auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value))
1836 return path_value->GetStylePath();
1837 DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNone);
1838 return nullptr;
1839 }
1840
ConvertOffsetPath(StyleResolverState & state,const CSSValue & value)1841 scoped_refptr<BasicShape> StyleBuilderConverter::ConvertOffsetPath(
1842 StyleResolverState& state,
1843 const CSSValue& value) {
1844 if (value.IsRayValue())
1845 return BasicShapeForValue(state, value);
1846 return ConvertPathOrNone(state, value);
1847 }
1848
ComputeRegisteredPropertyValue(const Document & document,const StyleResolverState * state,const CSSToLengthConversionData & css_to_length_conversion_data,const CSSValue & value,const String & base_url,const WTF::TextEncoding & charset)1849 static const CSSValue& ComputeRegisteredPropertyValue(
1850 const Document& document,
1851 const StyleResolverState* state,
1852 const CSSToLengthConversionData& css_to_length_conversion_data,
1853 const CSSValue& value,
1854 const String& base_url,
1855 const WTF::TextEncoding& charset) {
1856 // TODO(timloh): Images values can also contain lengths.
1857 if (const auto* function_value = DynamicTo<CSSFunctionValue>(value)) {
1858 CSSFunctionValue* new_function =
1859 MakeGarbageCollected<CSSFunctionValue>(function_value->FunctionType());
1860 for (const CSSValue* inner_value : To<CSSValueList>(value)) {
1861 new_function->Append(ComputeRegisteredPropertyValue(
1862 document, state, css_to_length_conversion_data, *inner_value,
1863 base_url, charset));
1864 }
1865 return *new_function;
1866 }
1867
1868 if (const auto* old_list = DynamicTo<CSSValueList>(value)) {
1869 CSSValueList* new_list = CSSValueList::CreateWithSeparatorFrom(*old_list);
1870 for (const CSSValue* inner_value : *old_list) {
1871 new_list->Append(ComputeRegisteredPropertyValue(
1872 document, state, css_to_length_conversion_data, *inner_value,
1873 base_url, charset));
1874 }
1875 return *new_list;
1876 }
1877
1878 if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
1879 // For simple (non-calculated) px or percentage values, we do not need to
1880 // convert, as the value already has the proper computed form.
1881 if (!primitive_value->IsCalculated() &&
1882 (primitive_value->IsPx() || primitive_value->IsPercentage())) {
1883 return value;
1884 }
1885
1886 if (primitive_value->IsLength() || primitive_value->IsPercentage() ||
1887 primitive_value->IsCalculatedPercentageWithLength()) {
1888 // Instead of the actual zoom, use 1 to avoid potential rounding errors
1889 Length length = primitive_value->ConvertToLength(
1890 css_to_length_conversion_data.CopyWithAdjustedZoom(1));
1891 return *CSSPrimitiveValue::CreateFromLength(length, 1);
1892 }
1893
1894 // If we encounter a calculated number that was not resolved during
1895 // parsing, it means that a calc()-expression was allowed in place of
1896 // an integer. Such calc()-for-integers must be rounded at computed value
1897 // time.
1898 // https://drafts.csswg.org/css-values-4/#calc-type-checking
1899 if (primitive_value->IsCalculated()) {
1900 const CSSMathFunctionValue& math_value =
1901 To<CSSMathFunctionValue>(*primitive_value);
1902 if (math_value.IsNumber()) {
1903 double double_value = math_value.GetDoubleValue();
1904 auto unit_type = CSSPrimitiveValue::UnitType::kInteger;
1905 return *CSSNumericLiteralValue::Create(std::round(double_value),
1906 unit_type);
1907 }
1908 }
1909
1910 if (primitive_value->IsAngle()) {
1911 return *CSSNumericLiteralValue::Create(
1912 primitive_value->ComputeDegrees(),
1913 CSSPrimitiveValue::UnitType::kDegrees);
1914 }
1915
1916 if (primitive_value->IsTime()) {
1917 return *CSSNumericLiteralValue::Create(
1918 primitive_value->ComputeSeconds(),
1919 CSSPrimitiveValue::UnitType::kSeconds);
1920 }
1921
1922 if (primitive_value->IsResolution()) {
1923 return *CSSNumericLiteralValue::Create(
1924 primitive_value->ComputeDotsPerPixel(),
1925 CSSPrimitiveValue::UnitType::kDotsPerPixel);
1926 }
1927 }
1928
1929 if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
1930 CSSValueID value_id = identifier_value->GetValueID();
1931 if (value_id == CSSValueID::kCurrentcolor)
1932 return value;
1933 if (StyleColor::IsColorKeyword(value_id)) {
1934 mojom::blink::ColorScheme scheme =
1935 state ? state->Style()->UsedColorScheme()
1936 : mojom::blink::ColorScheme::kLight;
1937 Color color = document.GetTextLinkColors().ColorFromCSSValue(
1938 value, Color(), scheme, false);
1939 return *cssvalue::CSSColorValue::Create(color.Rgb());
1940 }
1941 }
1942
1943 if (const auto* uri_value = DynamicTo<cssvalue::CSSURIValue>(value))
1944 return *uri_value->ValueWithURLMadeAbsolute(KURL(base_url), charset);
1945
1946 return value;
1947 }
1948
ConvertRegisteredPropertyInitialValue(const Document & document,const CSSValue & value)1949 const CSSValue& StyleBuilderConverter::ConvertRegisteredPropertyInitialValue(
1950 const Document& document,
1951 const CSSValue& value) {
1952 return ComputeRegisteredPropertyValue(
1953 document, nullptr /* state */, CSSToLengthConversionData(), value,
1954 document.BaseURL(), document.Encoding());
1955 }
1956
ConvertRegisteredPropertyValue(const StyleResolverState & state,const CSSValue & value,const String & base_url,const WTF::TextEncoding & charset)1957 const CSSValue& StyleBuilderConverter::ConvertRegisteredPropertyValue(
1958 const StyleResolverState& state,
1959 const CSSValue& value,
1960 const String& base_url,
1961 const WTF::TextEncoding& charset) {
1962 return ComputeRegisteredPropertyValue(state.GetDocument(), &state,
1963 state.CssToLengthConversionData(),
1964 value, base_url, charset);
1965 }
1966
1967 // Registered properties need to substitute as absolute values. This means
1968 // that 'em' units (for instance) are converted to 'px ' and calc()-expressions
1969 // are resolved. This function creates new tokens equivalent to the computed
1970 // value of the registered property.
1971 //
1972 // This is necessary to make things like font-relative units in inherited
1973 // (and registered) custom properties work correctly.
1974 //
1975 // https://drafts.css-houdini.org/css-properties-values-api-1/#substitution
1976 scoped_refptr<CSSVariableData>
ConvertRegisteredPropertyVariableData(const CSSValue & value,bool is_animation_tainted)1977 StyleBuilderConverter::ConvertRegisteredPropertyVariableData(
1978 const CSSValue& value,
1979 bool is_animation_tainted) {
1980 // TODO(andruud): Produce tokens directly from CSSValue.
1981 String text = value.CssText();
1982
1983 CSSTokenizer tokenizer(text);
1984 Vector<CSSParserToken> tokens;
1985 tokens.AppendVector(tokenizer.TokenizeToEOF());
1986
1987 Vector<String> backing_strings;
1988 backing_strings.push_back(text);
1989
1990 const bool has_font_units = false;
1991 const bool has_root_font_units = false;
1992
1993 return CSSVariableData::CreateResolved(
1994 std::move(tokens), std::move(backing_strings), is_animation_tainted,
1995 has_font_units, has_root_font_units, g_null_atom, WTF::TextEncoding());
1996 }
1997
ConvertIntrinsicSize(StyleResolverState & state,const CSSValue & value)1998 LengthSize StyleBuilderConverter::ConvertIntrinsicSize(
1999 StyleResolverState& state,
2000 const CSSValue& value) {
2001 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2002 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
2003 return LengthSize(Length::Auto(), Length::Auto());
2004 const CSSValuePair& pair = To<CSSValuePair>(value);
2005 Length width = ConvertLength(state, pair.First());
2006 Length height = ConvertLength(state, pair.Second());
2007 return LengthSize(width, height);
2008 }
2009
2010 namespace {
GetRatioFromList(const CSSValueList & list)2011 FloatSize GetRatioFromList(const CSSValueList& list) {
2012 auto* ratio_list = DynamicTo<CSSValueList>(list.Item(0));
2013 if (!ratio_list) {
2014 DCHECK_EQ(list.length(), 2u);
2015 ratio_list = DynamicTo<CSSValueList>(list.Item(1));
2016 }
2017 DCHECK(ratio_list);
2018 DCHECK_GE(ratio_list->length(), 1u);
2019 DCHECK_LE(ratio_list->length(), 2u);
2020 float width = To<CSSPrimitiveValue>(ratio_list->Item(0)).GetFloatValue();
2021 float height = 1;
2022 if (ratio_list->length() == 2u)
2023 height = To<CSSPrimitiveValue>(ratio_list->Item(1)).GetFloatValue();
2024 return FloatSize(width, height);
2025 }
2026
ListHasAuto(const CSSValueList & list)2027 bool ListHasAuto(const CSSValueList& list) {
2028 // If there's only one entry, it needs to be a ratio.
2029 // (A single auto is handled separately)
2030 if (list.length() == 1u)
2031 return false;
2032 auto* auto_value = DynamicTo<CSSIdentifierValue>(list.Item(0));
2033 if (!auto_value)
2034 auto_value = DynamicTo<CSSIdentifierValue>(list.Item(1));
2035 DCHECK(auto_value) << "If we have two items, one of them must be auto";
2036 DCHECK_EQ(auto_value->GetValueID(), CSSValueID::kAuto);
2037 return true;
2038 }
2039 } // namespace
2040
ConvertAspectRatio(StyleResolverState & state,const CSSValue & value)2041 StyleAspectRatio StyleBuilderConverter::ConvertAspectRatio(
2042 StyleResolverState& state,
2043 const CSSValue& value) {
2044 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2045 if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
2046 return StyleAspectRatio(EAspectRatioType::kAuto, FloatSize());
2047
2048 // (auto, (1, 2)) or ((1, 2), auto) or ((1, 2))
2049 const CSSValueList& list = To<CSSValueList>(value);
2050 DCHECK_GE(list.length(), 1u);
2051 DCHECK_LE(list.length(), 2u);
2052
2053 bool has_auto = ListHasAuto(list);
2054 EAspectRatioType type =
2055 has_auto ? EAspectRatioType::kAutoAndRatio : EAspectRatioType::kRatio;
2056 FloatSize ratio = GetRatioFromList(list);
2057 return StyleAspectRatio(type, ratio);
2058 }
2059
ConvertInternalAlignSelfBlock(StyleResolverState &,const CSSValue & value)2060 bool StyleBuilderConverter::ConvertInternalAlignSelfBlock(
2061 StyleResolverState&,
2062 const CSSValue& value) {
2063 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2064 return identifier_value &&
2065 identifier_value->GetValueID() == CSSValueID::kCenter;
2066 }
2067
ConvertInternalEmptyLineHeight(StyleResolverState &,const CSSValue & value)2068 bool StyleBuilderConverter::ConvertInternalEmptyLineHeight(
2069 StyleResolverState&,
2070 const CSSValue& value) {
2071 auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
2072 return identifier_value &&
2073 identifier_value->GetValueID() == CSSValueID::kFabricated;
2074 }
2075
ConvertPage(StyleResolverState & state,const CSSValue & value)2076 AtomicString StyleBuilderConverter::ConvertPage(StyleResolverState& state,
2077 const CSSValue& value) {
2078 if (auto* custom_ident_value = DynamicTo<CSSCustomIdentValue>(value))
2079 return AtomicString(custom_ident_value->Value());
2080 DCHECK(DynamicTo<CSSIdentifierValue>(value));
2081 DCHECK_EQ(DynamicTo<CSSIdentifierValue>(value)->GetValueID(),
2082 CSSValueID::kAuto);
2083 return AtomicString();
2084 }
2085
ConvertRubyPosition(StyleResolverState & state,const CSSValue & value)2086 RubyPosition StyleBuilderConverter::ConvertRubyPosition(
2087 StyleResolverState& state,
2088 const CSSValue& value) {
2089 if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
2090 CSSValueID value_id = identifier_value->GetValueID();
2091 if (value_id == CSSValueID::kOver)
2092 return RubyPosition::kBefore;
2093 if (value_id == CSSValueID::kUnder)
2094 return RubyPosition::kAfter;
2095 return identifier_value->ConvertTo<blink::RubyPosition>();
2096 }
2097 NOTREACHED();
2098 return RubyPosition::kBefore;
2099 }
2100
ConvertScrollbarGutter(StyleResolverState & state,const CSSValue & value)2101 ScrollbarGutter StyleBuilderConverter::ConvertScrollbarGutter(
2102 StyleResolverState& state,
2103 const CSSValue& value) {
2104 ScrollbarGutter flags = kScrollbarGutterAuto;
2105
2106 auto process = [&flags](const CSSValue& identifier) {
2107 flags |= To<CSSIdentifierValue>(identifier).ConvertTo<ScrollbarGutter>();
2108 };
2109
2110 if (auto* value_list = DynamicTo<CSSValueList>(value)) {
2111 for (auto& entry : *value_list)
2112 process(*entry);
2113 } else {
2114 process(value);
2115 }
2116 return flags;
2117 }
2118
2119 } // namespace blink
2120