mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-19 02:10:26 +00:00
As FontFaces are added or removed from a FontFaceSet, and as they load or fail, the FontFaceSet moves them between a few different lists, and updates its loading/loaded status. In the spec, this is how the FontFaceSet.[[ReadyPromise]] gets fulfilled: When the document has finished loading and FontFaceSet.[[LoadingFonts]] is empty, it resolves the promise. To support this, FontFace now keeps a set of FontFaceSets that it is contained in. This lets us remove the non-spec resolve_ready_promise() call in EventLoop which was sometimes triggering before any fonts had attempted to load. As noted, there's a spec issue with the ready promise: If nothing modifies the document's fonts, then it would never resolve. My ad-hoc fix is to also switch the FontFaceSet to the loaded state if it is empty, which appears to solve the issues but is not ideal.
141 lines
5.3 KiB
C++
141 lines
5.3 KiB
C++
/*
|
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibGfx/Font/Typeface.h>
|
|
#include <LibURL/URL.h>
|
|
#include <LibWeb/Bindings/FontFacePrototype.h>
|
|
#include <LibWeb/Bindings/PlatformObject.h>
|
|
#include <LibWeb/CSS/ParsedFontFace.h>
|
|
|
|
namespace Web::CSS {
|
|
|
|
struct FontFaceDescriptors {
|
|
String style = "normal"_string;
|
|
String weight = "normal"_string;
|
|
String stretch = "normal"_string;
|
|
String unicode_range = "U+0-10FFFF"_string;
|
|
String feature_settings = "normal"_string;
|
|
String variation_settings = "normal"_string;
|
|
String display = "auto"_string;
|
|
String ascent_override = "normal"_string;
|
|
String descent_override = "normal"_string;
|
|
String line_gap_override = "normal"_string;
|
|
};
|
|
|
|
class FontFace final : public Bindings::PlatformObject {
|
|
WEB_PLATFORM_OBJECT(FontFace, Bindings::PlatformObject);
|
|
GC_DECLARE_ALLOCATOR(FontFace);
|
|
|
|
public:
|
|
using FontFaceSource = Variant<String, GC::Root<WebIDL::BufferSource>>;
|
|
|
|
[[nodiscard]] static GC::Ref<FontFace> construct_impl(JS::Realm&, String family, FontFaceSource source, FontFaceDescriptors const& descriptors);
|
|
[[nodiscard]] static GC::Ref<FontFace> create_css_connected(JS::Realm&, CSSFontFaceRule&);
|
|
virtual ~FontFace() override;
|
|
|
|
String family() const { return m_family; }
|
|
WebIDL::ExceptionOr<void> set_family(String const&);
|
|
void set_family_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String style() const { return m_style; }
|
|
WebIDL::ExceptionOr<void> set_style(String const&);
|
|
void set_style_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String weight() const { return m_weight; }
|
|
WebIDL::ExceptionOr<void> set_weight(String const&);
|
|
void set_weight_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String stretch() const { return m_stretch; }
|
|
WebIDL::ExceptionOr<void> set_stretch(String const&);
|
|
void set_stretch_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String unicode_range() const { return m_unicode_range; }
|
|
WebIDL::ExceptionOr<void> set_unicode_range(String const&);
|
|
void set_unicode_range_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String feature_settings() const { return m_feature_settings; }
|
|
WebIDL::ExceptionOr<void> set_feature_settings(String const&);
|
|
void set_feature_settings_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String variation_settings() const { return m_variation_settings; }
|
|
WebIDL::ExceptionOr<void> set_variation_settings(String const&);
|
|
void set_variation_settings_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String display() const { return m_display; }
|
|
WebIDL::ExceptionOr<void> set_display(String const&);
|
|
void set_display_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String ascent_override() const { return m_ascent_override; }
|
|
WebIDL::ExceptionOr<void> set_ascent_override(String const&);
|
|
void set_ascent_override_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String descent_override() const { return m_descent_override; }
|
|
WebIDL::ExceptionOr<void> set_descent_override(String const&);
|
|
void set_descent_override_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
String line_gap_override() const { return m_line_gap_override; }
|
|
WebIDL::ExceptionOr<void> set_line_gap_override(String const&);
|
|
void set_line_gap_override_impl(NonnullRefPtr<StyleValue const> const& value);
|
|
|
|
bool is_css_connected() const { return m_css_font_face_rule != nullptr; }
|
|
void disconnect_from_css_rule();
|
|
void reparse_connected_css_font_face_rule_descriptors();
|
|
|
|
ParsedFontFace parsed_font_face() const;
|
|
|
|
Bindings::FontFaceLoadStatus status() const { return m_status; }
|
|
|
|
GC::Ref<WebIDL::Promise> load();
|
|
GC::Ref<WebIDL::Promise> loaded() const;
|
|
|
|
GC::Ref<WebIDL::Promise> font_status_promise() { return m_font_status_promise; }
|
|
|
|
void add_to_set(FontFaceSet&);
|
|
void remove_from_set(FontFaceSet&);
|
|
|
|
private:
|
|
FontFace(JS::Realm&, GC::Ref<WebIDL::Promise> font_status_promise);
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
virtual void visit_edges(Visitor&) override;
|
|
void reject_status_promise(JS::Value reason);
|
|
|
|
// FIXME: Should we be storing StyleValues instead?
|
|
String m_family;
|
|
String m_style;
|
|
String m_weight;
|
|
String m_stretch;
|
|
String m_unicode_range;
|
|
Vector<Gfx::UnicodeRange> m_unicode_ranges;
|
|
String m_feature_settings;
|
|
String m_variation_settings;
|
|
String m_display;
|
|
String m_ascent_override;
|
|
String m_descent_override;
|
|
String m_line_gap_override;
|
|
|
|
// https://drafts.csswg.org/css-font-loading/#dom-fontface-status
|
|
Bindings::FontFaceLoadStatus m_status { Bindings::FontFaceLoadStatus::Unloaded };
|
|
|
|
GC::Ref<WebIDL::Promise> m_font_status_promise; // [[FontStatusPromise]]
|
|
Vector<ParsedFontFace::Source> m_urls; // [[Urls]]
|
|
ByteBuffer m_binary_data {}; // [[Data]]
|
|
|
|
RefPtr<Gfx::Typeface const> m_parsed_font;
|
|
RefPtr<Core::Promise<NonnullRefPtr<Gfx::Typeface const>>> m_font_load_promise;
|
|
|
|
GC::Ptr<CSSFontFaceRule> m_css_font_face_rule;
|
|
HashTable<GC::Ref<FontFaceSet>> m_containing_sets;
|
|
};
|
|
|
|
bool font_format_is_supported(FlyString const& name);
|
|
|
|
bool font_tech_is_supported(FontTech);
|
|
bool font_tech_is_supported(FlyString const& name);
|
|
|
|
}
|