|
| 1 | +/* |
| 2 | + * Copyright (c) 2018-2025, Andreas Kling <[email protected]> |
| 3 | + * Copyright (c) 2021, the SerenityOS developers. |
| 4 | + * Copyright (c) 2021-2025, Sam Atkins <[email protected]> |
| 5 | + * Copyright (c) 2024, Matthew Olsson <[email protected]> |
| 6 | + * Copyright (c) 2025, Callum Law <[email protected]> |
| 7 | + * |
| 8 | + * SPDX-License-Identifier: BSD-2-Clause |
| 9 | + */ |
| 10 | + |
| 11 | +#include <LibGC/CellAllocator.h> |
| 12 | +#include <LibGfx/FontCascadeList.h> |
| 13 | +#include <LibWeb/Export.h> |
| 14 | +#include <LibWeb/Forward.h> |
| 15 | + |
| 16 | +#pragma once |
| 17 | + |
| 18 | +namespace Web::CSS { |
| 19 | + |
| 20 | +struct FontFaceKey; |
| 21 | + |
| 22 | +struct OwnFontFaceKey { |
| 23 | + explicit OwnFontFaceKey(FontFaceKey const& other); |
| 24 | + |
| 25 | + operator FontFaceKey() const; |
| 26 | + |
| 27 | + [[nodiscard]] u32 hash() const { return pair_int_hash(family_name.hash(), pair_int_hash(weight, slope)); } |
| 28 | + [[nodiscard]] bool operator==(OwnFontFaceKey const& other) const = default; |
| 29 | + [[nodiscard]] bool operator==(FontFaceKey const& other) const; |
| 30 | + |
| 31 | + FlyString family_name; |
| 32 | + int weight { 0 }; |
| 33 | + int slope { 0 }; |
| 34 | +}; |
| 35 | + |
| 36 | +struct FontMatchingAlgorithmCacheKey { |
| 37 | + FlyString family_name; |
| 38 | + int weight; |
| 39 | + int slope; |
| 40 | + float font_size_in_pt; |
| 41 | + |
| 42 | + [[nodiscard]] bool operator==(FontMatchingAlgorithmCacheKey const& other) const = default; |
| 43 | +}; |
| 44 | + |
| 45 | +class FontLoader final : public GC::Cell { |
| 46 | + GC_CELL(FontLoader, GC::Cell); |
| 47 | + GC_DECLARE_ALLOCATOR(FontLoader); |
| 48 | + |
| 49 | +public: |
| 50 | + FontLoader(FontComputer& font_computer, GC::Ptr<CSSStyleSheet> parent_style_sheet, FlyString family_name, Vector<Gfx::UnicodeRange> unicode_ranges, Vector<URL> urls, ESCAPING Function<void(RefPtr<Gfx::Typeface const>)> on_load = {}); |
| 51 | + |
| 52 | + virtual ~FontLoader(); |
| 53 | + |
| 54 | + Vector<Gfx::UnicodeRange> const& unicode_ranges() const { return m_unicode_ranges; } |
| 55 | + RefPtr<Gfx::Typeface const> vector_font() const { return m_vector_font; } |
| 56 | + |
| 57 | + RefPtr<Gfx::Font const> font_with_point_size(float point_size, Gfx::FontVariationSettings const& variations = {}); |
| 58 | + void start_loading_next_url(); |
| 59 | + |
| 60 | + bool is_loading() const; |
| 61 | + |
| 62 | +private: |
| 63 | + virtual void visit_edges(Visitor&) override; |
| 64 | + |
| 65 | + ErrorOr<NonnullRefPtr<Gfx::Typeface const>> try_load_font(Fetch::Infrastructure::Response const&, ByteBuffer const&); |
| 66 | + |
| 67 | + void font_did_load_or_fail(RefPtr<Gfx::Typeface const>); |
| 68 | + |
| 69 | + GC::Ref<FontComputer> m_font_computer; |
| 70 | + GC::Ptr<CSSStyleSheet> m_parent_style_sheet; |
| 71 | + FlyString m_family_name; |
| 72 | + Vector<Gfx::UnicodeRange> m_unicode_ranges; |
| 73 | + RefPtr<Gfx::Typeface const> m_vector_font; |
| 74 | + Vector<URL> m_urls; |
| 75 | + GC::Ptr<Fetch::Infrastructure::FetchController> m_fetch_controller; |
| 76 | + Function<void(RefPtr<Gfx::Typeface const>)> m_on_load; |
| 77 | +}; |
| 78 | + |
| 79 | +class WEB_API FontComputer final : public GC::Cell { |
| 80 | + GC_CELL(FontComputer, GC::Cell); |
| 81 | + GC_DECLARE_ALLOCATOR(FontComputer); |
| 82 | + |
| 83 | +public: |
| 84 | + explicit FontComputer(DOM::Document& document) |
| 85 | + : m_document(document) |
| 86 | + { |
| 87 | + } |
| 88 | + |
| 89 | + ~FontComputer() = default; |
| 90 | + |
| 91 | + DOM::Document& document() { return m_document; } |
| 92 | + DOM::Document const& document() const { return m_document; } |
| 93 | + |
| 94 | + Gfx::Font const& initial_font() const; |
| 95 | + |
| 96 | + void did_load_font(FlyString const& family_name); |
| 97 | + |
| 98 | + GC::Ptr<FontLoader> load_font_face(ParsedFontFace const&, ESCAPING Function<void(RefPtr<Gfx::Typeface const>)> on_load = {}); |
| 99 | + |
| 100 | + void load_fonts_from_sheet(CSSStyleSheet&); |
| 101 | + void unload_fonts_from_sheet(CSSStyleSheet&); |
| 102 | + |
| 103 | + RefPtr<Gfx::FontCascadeList const> compute_font_for_style_values(StyleValue const& font_family, CSSPixels const& font_size, int font_slope, double font_weight, Percentage const& font_width, HashMap<FlyString, double> const& font_variation_settings) const; |
| 104 | + |
| 105 | + size_t number_of_css_font_faces_with_loading_in_progress() const; |
| 106 | + |
| 107 | +private: |
| 108 | + virtual void visit_edges(Visitor&) override; |
| 109 | + |
| 110 | + struct MatchingFontCandidate; |
| 111 | + static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_ascending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); |
| 112 | + static RefPtr<Gfx::FontCascadeList const> find_matching_font_weight_descending(Vector<MatchingFontCandidate> const& candidates, int target_weight, float font_size_in_pt, Gfx::FontVariationSettings const& variations, bool inclusive); |
| 113 | + RefPtr<Gfx::FontCascadeList const> font_matching_algorithm(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; |
| 114 | + RefPtr<Gfx::FontCascadeList const> font_matching_algorithm_impl(FlyString const& family_name, int weight, int slope, float font_size_in_pt) const; |
| 115 | + |
| 116 | + GC::Ref<DOM::Document> m_document; |
| 117 | + |
| 118 | + using FontLoaderList = Vector<GC::Ref<FontLoader>>; |
| 119 | + HashMap<OwnFontFaceKey, FontLoaderList> m_loaded_fonts; |
| 120 | + |
| 121 | + mutable HashMap<FontMatchingAlgorithmCacheKey, RefPtr<Gfx::FontCascadeList const>> m_font_matching_algorithm_cache; |
| 122 | +}; |
| 123 | + |
| 124 | +} |
0 commit comments