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