ladybird/Libraries/LibWeb/CSS/FontFace.h
Callum Law 668d3afde0 LibWeb: Properly parse attributes for CSS-connected FontFace
Previously we would just set the attributes to the serialized
descriptors, even if they were the empty string.

We now apply defaults when we have empty descriptors and apply parsing
logic from the various `set_*` methods (only applicable to `font-family`
so far where we now extract the value from either a string or a
custom-ident)

Fixes an issue in some css/css-shapes WPT tests where we weren't
properly matching fonts.
2026-01-13 10:40:00 +00:00

135 lines
5.1 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();
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; }
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;
};
bool font_format_is_supported(FlyString const& name);
bool font_tech_is_supported(FontTech);
bool font_tech_is_supported(FlyString const& name);
}