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