/* * Copyright (c) 2018-2025, Andreas Kling * Copyright (c) 2021, the SerenityOS developers. * Copyright (c) 2021-2025, Sam Atkins * Copyright (c) 2024, Matthew Olsson * Copyright (c) 2025, Callum Law * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #pragma once namespace Web::CSS { struct FontFaceKey; struct OwnFontFaceKey { explicit OwnFontFaceKey(FontFaceKey const& other); operator FontFaceKey() const; [[nodiscard]] u32 hash() const { return pair_int_hash(family_name.hash(), pair_int_hash(weight, slope)); } [[nodiscard]] bool operator==(OwnFontFaceKey const& other) const = default; [[nodiscard]] bool operator==(FontFaceKey const& other) const; FlyString family_name; int weight { 0 }; int slope { 0 }; }; struct FontMatchingAlgorithmCacheKey { FlyString family_name; int weight; int slope; float font_size_in_pt; [[nodiscard]] bool operator==(FontMatchingAlgorithmCacheKey const& other) const = default; }; class FontLoader final : public GC::Cell { GC_CELL(FontLoader, GC::Cell); GC_DECLARE_ALLOCATOR(FontLoader); public: FontLoader(FontComputer& font_computer, GC::Ptr parent_style_sheet, FlyString family_name, Vector unicode_ranges, Vector urls, ESCAPING Function)> on_load = {}); virtual ~FontLoader(); Vector const& unicode_ranges() const { return m_unicode_ranges; } RefPtr vector_font() const { return m_vector_font; } RefPtr font_with_point_size(float point_size, Gfx::FontVariationSettings const& variations = {}); void start_loading_next_url(); bool is_loading() const; private: virtual void visit_edges(Visitor&) override; ErrorOr> try_load_font(Fetch::Infrastructure::Response const&, ByteBuffer const&); void font_did_load_or_fail(RefPtr); GC::Ref m_font_computer; GC::Ptr m_parent_style_sheet; FlyString m_family_name; Vector m_unicode_ranges; RefPtr m_vector_font; Vector m_urls; GC::Ptr m_fetch_controller; Function)> m_on_load; }; class WEB_API FontComputer final : public GC::Cell { GC_CELL(FontComputer, GC::Cell); GC_DECLARE_ALLOCATOR(FontComputer); public: explicit FontComputer(DOM::Document& document) : m_document(document) { } ~FontComputer() = default; DOM::Document& document() { return m_document; } DOM::Document const& document() const { return m_document; } Gfx::Font const& initial_font() const; void did_load_font(FlyString const& family_name); GC::Ptr load_font_face(ParsedFontFace const&, ESCAPING Function)> on_load = {}); void load_fonts_from_sheet(CSSStyleSheet&); void unload_fonts_from_sheet(CSSStyleSheet&); RefPtr compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int font_slope, double font_weight, Percentage const& font_width, HashMap const& font_variation_settings) const; size_t number_of_css_font_faces_with_loading_in_progress() const; private: virtual void visit_edges(Visitor&) override; struct MatchingFontCandidate; static RefPtr find_matching_font_weight_ascending(Vector const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); static RefPtr find_matching_font_weight_descending(Vector const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); RefPtr font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; RefPtr font_matching_algorithm_impl(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; GC::Ref m_document; using FontLoaderList = Vector>; HashMap m_loaded_fonts; mutable HashMap> m_font_matching_algorithm_cache; }; }