diff --git a/Tests/LibWeb/Text/expected/css/FontFaceSet-setlike.txt b/Tests/LibWeb/Text/expected/css/FontFaceSet-setlike.txt new file mode 100644 index 00000000000..753b4d98167 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/FontFaceSet-setlike.txt @@ -0,0 +1,23 @@ +-- Empty FontFaceSet -- +fontFaceSet.size: 0 +fontFaceSet.has(fontFace): false +fontFaceSet.status: loaded +deleteBeforeAdd: false +-- Add Font -- +fontFaceSet.size: 1 +fontFaceSet.has(fontFace): true +fontFaceKey.name: Hash Sans +FIXME: fontFaceSet.status: loaded +-- Delete Font -- +fontFaceSet.size: 0 +fontFaceSet.has(fontFace): false +didDelete: true +fontFaceSet.status: loaded +-- Add Font again -- +fontFaceSet.size: 1 +fontFaceSet.has(fontFace): true +FIXME: fontFaceSet.status: loaded +-- Clear FontFaceSet -- +fontFaceSet.size: 0 +fontFaceSet.has(fontFace): false +fontFaceSet.status: loaded diff --git a/Tests/LibWeb/Text/input/css/FontFaceSet-setlike.html b/Tests/LibWeb/Text/input/css/FontFaceSet-setlike.html new file mode 100644 index 00000000000..4b03b722df4 --- /dev/null +++ b/Tests/LibWeb/Text/input/css/FontFaceSet-setlike.html @@ -0,0 +1,50 @@ + + + diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp index 35fbd076bcc..d3995826601 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp @@ -6,8 +6,10 @@ #include #include +#include #include #include +#include #include #include @@ -15,10 +17,20 @@ namespace Web::CSS { JS_DEFINE_ALLOCATOR(FontFaceSet); -JS::NonnullGCPtr FontFaceSet::construct_impl(JS::Realm& realm, Vector> initial_faces) +// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-fontfaceset +JS::NonnullGCPtr FontFaceSet::construct_impl(JS::Realm& realm, Vector> const& initial_faces) { - auto promise = WebIDL::create_promise(realm); - return realm.heap().allocate(realm, realm, promise, move(initial_faces)); + auto ready_promise = WebIDL::create_promise(realm); + auto set_entries = JS::Set::create(realm); + + // The FontFaceSet constructor, when called, must iterate its initialFaces argument and add each value to its set entries. + for (auto const& face : initial_faces) + set_entries->set_add(face); + + if (set_entries->set_size() == 0) + WebIDL::resolve_promise(realm, *ready_promise); + + return realm.heap().allocate(realm, realm, ready_promise, set_entries); } JS::NonnullGCPtr FontFaceSet::create(JS::Realm& realm) @@ -26,14 +38,13 @@ JS::NonnullGCPtr FontFaceSet::create(JS::Realm& realm) return construct_impl(realm, {}); } -FontFaceSet::FontFaceSet(JS::Realm& realm, JS::NonnullGCPtr ready_promise, Vector>) +FontFaceSet::FontFaceSet(JS::Realm& realm, JS::NonnullGCPtr ready_promise, JS::NonnullGCPtr set_entries) : Bindings::PlatformObject(realm) + , m_set_entries(set_entries) , m_ready_promise(ready_promise) { - // FIXME: Only set this after all the initial faces have been loaded - m_status = Bindings::FontFaceSetLoadStatus::Loaded; - // FIXME: Only resolve the promise after all the initial faces have been loaded - WebIDL::resolve_promise(realm, *m_ready_promise); + bool const is_ready = ready()->state() == JS::Promise::State::Fulfilled; + m_status = is_ready ? Bindings::FontFaceSetLoadStatus::Loaded : Bindings::FontFaceSetLoadStatus::Loading; } void FontFaceSet::initialize(JS::Realm& realm) @@ -46,16 +57,32 @@ void FontFaceSet::initialize(JS::Realm& realm) void FontFaceSet::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); + visitor.visit(m_set_entries); visitor.visit(m_ready_promise); } // https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-add -JS::NonnullGCPtr FontFaceSet::add(JS::Handle) +JS::NonnullGCPtr FontFaceSet::add(JS::Handle face) { - // FIXME: Do the steps + // FIXME: Do the actual spec steps + m_set_entries->set_add(face); return *this; } +// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-delete +bool FontFaceSet::delete_(JS::Handle face) +{ + // FIXME: Do the actual spec steps + return m_set_entries->set_remove(face); +} + +// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-clear +void FontFaceSet::clear() +{ + // FIXME: Do the actual spec steps + m_set_entries->set_clear(); +} + // https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load JS::ThrowCompletionOr> FontFaceSet::load(String const&, String const&) { diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.h b/Userland/Libraries/LibWeb/CSS/FontFaceSet.h index a6bb5ec1e6e..98f0bbb6519 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.h +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.h @@ -6,6 +6,8 @@ #pragma once +#include +#include #include #include #include @@ -17,23 +19,29 @@ class FontFaceSet final : public Bindings::PlatformObject { JS_DECLARE_ALLOCATOR(FontFaceSet); public: - [[nodiscard]] static JS::NonnullGCPtr construct_impl(JS::Realm&, Vector> initial_faces); + [[nodiscard]] static JS::NonnullGCPtr construct_impl(JS::Realm&, Vector> const& initial_faces); [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&); virtual ~FontFaceSet() override = default; - JS::NonnullGCPtr add(JS::Handle face); + JS::NonnullGCPtr set_entries() const { return m_set_entries; } + + JS::NonnullGCPtr add(JS::Handle); + bool delete_(JS::Handle); + void clear(); JS::ThrowCompletionOr> load(String const& font, String const& text); JS::NonnullGCPtr ready() const; Bindings::FontFaceSetLoadStatus status() const { return m_status; } private: - FontFaceSet(JS::Realm&, JS::NonnullGCPtr ready_promise, Vector> initial_faces); + FontFaceSet(JS::Realm&, JS::NonnullGCPtr ready_promise, JS::NonnullGCPtr set_entries); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + JS::NonnullGCPtr m_set_entries; JS::GCPtr m_ready_promise; // [[ReadyPromise]] + Bindings::FontFaceSetLoadStatus m_status { Bindings::FontFaceSetLoadStatus::Loading }; }; diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.idl b/Userland/Libraries/LibWeb/CSS/FontFaceSet.idl index 30e13c4d5b4..de816d39889 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.idl +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.idl @@ -18,10 +18,10 @@ enum FontFaceSetLoadStatus { "loading", "loaded" }; interface FontFaceSet : EventTarget { constructor(sequence initialFaces); - // FIXME: setlike; + setlike; FontFaceSet add(FontFace font); - [FIXME] boolean delete(FontFace font); - [FIXME] undefined clear(); + boolean delete(FontFace font); + undefined clear(); // events for when loading state changes [FIXME] attribute EventHandler onloading;