| 
									
										
										
										
											2022-03-28 20:30:26 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |  * Copyright (c) 2022-2025, Sam Atkins <sam@ladybird.org> | 
					
						
							| 
									
										
										
										
											2024-10-04 13:19:50 +02:00
										 |  |  |  * Copyright (c) 2023, Andreas Kling <andreas@ladybird.org> | 
					
						
							| 
									
										
										
										
											2022-03-28 20:30:26 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  | #include <LibWeb/CSS/CSSFontFaceDescriptors.h>
 | 
					
						
							| 
									
										
										
										
											2025-05-02 12:07:22 +01:00
										 |  |  | #include <LibWeb/CSS/CSSRule.h>
 | 
					
						
							| 
									
										
										
										
											2024-05-07 09:18:37 -06:00
										 |  |  | #include <LibWeb/CSS/ParsedFontFace.h>
 | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  | #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/FontSourceStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/OpenTypeTaggedStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/StringStyleValue.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleValues/UnicodeRangeStyleValue.h>
 | 
					
						
							| 
									
										
										
										
											2022-03-28 20:30:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web::CSS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 15:30:36 +01:00
										 |  |  | static FlyString extract_font_name(CSSStyleValue const& value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (value.is_string()) | 
					
						
							|  |  |  |         return value.as_string().string_value(); | 
					
						
							|  |  |  |     if (value.is_custom_ident()) | 
					
						
							|  |  |  |         return value.as_custom_ident().custom_ident(); | 
					
						
							|  |  |  |     return FlyString {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<ParsedFontFace::Source> ParsedFontFace::sources_from_style_value(CSSStyleValue const& style_value) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-04-04 15:30:36 +01:00
										 |  |  |     Vector<Source> sources; | 
					
						
							|  |  |  |     auto add_source = [&sources](FontSourceStyleValue const& font_source) { | 
					
						
							|  |  |  |         font_source.source().visit( | 
					
						
							|  |  |  |             [&](FontSourceStyleValue::Local const& local) { | 
					
						
							|  |  |  |                 sources.empend(extract_font_name(local.name), OptionalNone {}); | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2025-05-02 12:07:22 +01:00
										 |  |  |             [&](URL const& url) { | 
					
						
							| 
									
										
										
										
											2025-04-04 15:30:36 +01:00
										 |  |  |                 // FIXME: tech()
 | 
					
						
							|  |  |  |                 sources.empend(url, font_source.format()); | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 15:30:36 +01:00
										 |  |  |     if (style_value.is_font_source()) { | 
					
						
							|  |  |  |         add_source(style_value.as_font_source()); | 
					
						
							|  |  |  |     } else if (style_value.is_value_list()) { | 
					
						
							|  |  |  |         for (auto const& source : style_value.as_value_list().values()) | 
					
						
							|  |  |  |             add_source(source->as_font_source()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return sources; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& descriptors) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |     auto extract_percentage_or_normal = [](CSSStyleValue const& value) -> Optional<Percentage> { | 
					
						
							|  |  |  |         if (value.is_percentage()) | 
					
						
							|  |  |  |             return value.as_percentage().percentage(); | 
					
						
							|  |  |  |         if (value.is_calculated()) { | 
					
						
							|  |  |  |             // FIXME: These should probably be simplified already?
 | 
					
						
							|  |  |  |             return value.as_calculated().resolve_percentage({}); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.to_keyword() == Keyword::Normal) | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FlyString font_family; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontFamily)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         font_family = extract_font_name(*value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<int> weight; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontWeight)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         weight = value->to_font_weight(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<int> slope; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontStyle)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         slope = value->to_font_slope(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<int> width; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontWidth)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         width = value->to_font_width(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<Source> sources; | 
					
						
							| 
									
										
										
										
											2025-04-04 15:30:36 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::Src)) | 
					
						
							|  |  |  |         sources = sources_from_style_value(*value); | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Vector<Gfx::UnicodeRange> unicode_ranges; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::UnicodeRange)) { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         if (value->is_unicode_range()) { | 
					
						
							|  |  |  |             unicode_ranges.append(value->as_unicode_range().unicode_range()); | 
					
						
							|  |  |  |         } else if (value->is_value_list()) { | 
					
						
							|  |  |  |             for (auto const& range : value->as_value_list().values()) | 
					
						
							|  |  |  |                 unicode_ranges.append(range->as_unicode_range().unicode_range()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<Percentage> ascent_override; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::AscentOverride)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         ascent_override = extract_percentage_or_normal(*value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<Percentage> descent_override; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::DescentOverride)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         descent_override = extract_percentage_or_normal(*value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<Percentage> line_gap_override; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::LineGapOverride)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         line_gap_override = extract_percentage_or_normal(*value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FontDisplay font_display; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontDisplay)) | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         font_display = keyword_to_font_display(value->to_keyword()).value_or(FontDisplay::Auto); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<FlyString> font_named_instance; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontNamedInstance)) { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         if (value->is_string()) | 
					
						
							|  |  |  |             font_named_instance = value->as_string().string_value(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<FlyString> font_language_override; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontLanguageOverride)) { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         if (value->is_string()) | 
					
						
							|  |  |  |             font_language_override = value->as_string().string_value(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<OrderedHashMap<FlyString, i64>> font_feature_settings; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontFeatureSettings)) { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         if (value->to_keyword() == Keyword::Normal) { | 
					
						
							|  |  |  |             font_feature_settings.clear(); | 
					
						
							|  |  |  |         } else if (value->is_value_list()) { | 
					
						
							|  |  |  |             auto const& feature_tags = value->as_value_list().values(); | 
					
						
							|  |  |  |             OrderedHashMap<FlyString, i64> settings; | 
					
						
							|  |  |  |             settings.ensure_capacity(feature_tags.size()); | 
					
						
							|  |  |  |             for (auto const& feature_tag : feature_tags) { | 
					
						
							|  |  |  |                 auto const& setting_value = feature_tag->as_open_type_tagged().value(); | 
					
						
							|  |  |  |                 if (setting_value->is_integer()) { | 
					
						
							|  |  |  |                     settings.set(feature_tag->as_open_type_tagged().tag(), setting_value->as_integer().integer()); | 
					
						
							|  |  |  |                 } else if (setting_value->is_calculated() && setting_value->as_calculated().resolves_to_number()) { | 
					
						
							|  |  |  |                     if (auto integer = setting_value->as_calculated().resolve_integer({}); integer.has_value()) { | 
					
						
							|  |  |  |                         settings.set(feature_tag->as_open_type_tagged().tag(), *integer); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             font_feature_settings = move(settings); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<OrderedHashMap<FlyString, double>> font_variation_settings; | 
					
						
							| 
									
										
										
										
											2025-04-04 12:10:12 +01:00
										 |  |  |     if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontVariationSettings)) { | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         if (value->to_keyword() == Keyword::Normal) { | 
					
						
							|  |  |  |             font_variation_settings.clear(); | 
					
						
							|  |  |  |         } else if (value->is_value_list()) { | 
					
						
							|  |  |  |             auto const& variation_tags = value->as_value_list().values(); | 
					
						
							|  |  |  |             OrderedHashMap<FlyString, double> settings; | 
					
						
							|  |  |  |             settings.ensure_capacity(variation_tags.size()); | 
					
						
							|  |  |  |             for (auto const& variation_tag : variation_tags) { | 
					
						
							|  |  |  |                 auto const& setting_value = variation_tag->as_open_type_tagged().value(); | 
					
						
							|  |  |  |                 if (setting_value->is_number()) { | 
					
						
							|  |  |  |                     settings.set(variation_tag->as_open_type_tagged().tag(), setting_value->as_number().number()); | 
					
						
							|  |  |  |                 } else if (setting_value->is_calculated() && setting_value->as_calculated().resolves_to_number()) { | 
					
						
							|  |  |  |                     if (auto number = setting_value->as_calculated().resolve_number({}); number.has_value()) { | 
					
						
							|  |  |  |                         settings.set(variation_tag->as_open_type_tagged().tag(), *number); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             font_variation_settings = move(settings); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ParsedFontFace { | 
					
						
							| 
									
										
										
										
											2025-05-02 12:07:22 +01:00
										 |  |  |         descriptors.parent_rule()->parent_style_sheet(), | 
					
						
							| 
									
										
										
										
											2025-04-03 11:50:05 +01:00
										 |  |  |         move(font_family), | 
					
						
							|  |  |  |         move(weight), | 
					
						
							|  |  |  |         move(slope), | 
					
						
							|  |  |  |         move(width), | 
					
						
							|  |  |  |         move(sources), | 
					
						
							|  |  |  |         move(unicode_ranges), | 
					
						
							|  |  |  |         move(ascent_override), | 
					
						
							|  |  |  |         move(descent_override), | 
					
						
							|  |  |  |         move(line_gap_override), | 
					
						
							|  |  |  |         move(font_display), | 
					
						
							|  |  |  |         move(font_named_instance), | 
					
						
							|  |  |  |         move(font_language_override), | 
					
						
							|  |  |  |         move(font_feature_settings), | 
					
						
							|  |  |  |         move(font_variation_settings) | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-02 12:07:22 +01:00
										 |  |  | ParsedFontFace::ParsedFontFace(GC::Ptr<CSSStyleSheet> parent_style_sheet, FlyString font_family, Optional<int> weight, Optional<int> slope, Optional<int> width, Vector<Source> sources, Vector<Gfx::UnicodeRange> unicode_ranges, Optional<Percentage> ascent_override, Optional<Percentage> descent_override, Optional<Percentage> line_gap_override, FontDisplay font_display, Optional<FlyString> font_named_instance, Optional<FlyString> font_language_override, Optional<OrderedHashMap<FlyString, i64>> font_feature_settings, Optional<OrderedHashMap<FlyString, double>> font_variation_settings) | 
					
						
							|  |  |  |     : m_parent_style_sheet(parent_style_sheet) | 
					
						
							|  |  |  |     , m_font_family(move(font_family)) | 
					
						
							| 
									
										
										
										
											2024-09-26 14:45:55 +01:00
										 |  |  |     , m_font_named_instance(move(font_named_instance)) | 
					
						
							| 
									
										
										
										
											2023-05-24 15:35:04 +02:00
										 |  |  |     , m_weight(weight) | 
					
						
							|  |  |  |     , m_slope(slope) | 
					
						
							| 
									
										
										
										
											2024-09-27 14:27:55 +01:00
										 |  |  |     , m_width(width) | 
					
						
							| 
									
										
										
										
											2022-03-28 20:30:26 +01:00
										 |  |  |     , m_sources(move(sources)) | 
					
						
							| 
									
										
										
										
											2022-03-31 16:39:52 +01:00
										 |  |  |     , m_unicode_ranges(move(unicode_ranges)) | 
					
						
							| 
									
										
										
										
											2024-09-26 12:51:41 +01:00
										 |  |  |     , m_ascent_override(move(ascent_override)) | 
					
						
							|  |  |  |     , m_descent_override(move(descent_override)) | 
					
						
							|  |  |  |     , m_line_gap_override(move(line_gap_override)) | 
					
						
							| 
									
										
										
										
											2024-09-26 14:07:46 +01:00
										 |  |  |     , m_font_display(font_display) | 
					
						
							| 
									
										
										
										
											2024-09-27 17:11:31 +01:00
										 |  |  |     , m_font_language_override(font_language_override) | 
					
						
							| 
									
										
										
										
											2024-10-01 11:02:05 +01:00
										 |  |  |     , m_font_feature_settings(move(font_feature_settings)) | 
					
						
							|  |  |  |     , m_font_variation_settings(move(font_variation_settings)) | 
					
						
							| 
									
										
										
										
											2022-03-28 20:30:26 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |