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