ladybird/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp
Kostya Farber 14d62d7f31 LibWeb/CSS: Implement add for FontFaceSet
There is still some work to do with some of the underying methods
called inside this method (e.g is_css_connected) but this is a start.
2024-09-27 14:49:27 -06:00

165 lines
5.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/Set.h>
#include <LibWeb/Bindings/FontFaceSetPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/FontFace.h>
#include <LibWeb/CSS/FontFaceSet.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::CSS {
JS_DEFINE_ALLOCATOR(FontFaceSet);
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-fontfaceset
JS::NonnullGCPtr<FontFaceSet> FontFaceSet::construct_impl(JS::Realm& realm, Vector<JS::Handle<FontFace>> const& 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<FontFaceSet>(realm, realm, ready_promise, set_entries);
}
JS::NonnullGCPtr<FontFaceSet> FontFaceSet::create(JS::Realm& realm)
{
return construct_impl(realm, {});
}
FontFaceSet::FontFaceSet(JS::Realm& realm, JS::NonnullGCPtr<WebIDL::Promise> ready_promise, JS::NonnullGCPtr<JS::Set> set_entries)
: DOM::EventTarget(realm)
, m_set_entries(set_entries)
, m_ready_promise(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)
{
Base::initialize(realm);
WEB_SET_PROTOTYPE_FOR_INTERFACE(FontFaceSet);
}
void FontFaceSet::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_set_entries);
visitor.visit(m_ready_promise);
visitor.visit(m_loading_fonts);
visitor.visit(m_loaded_fonts);
visitor.visit(m_failed_fonts);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-add
WebIDL::ExceptionOr<JS::NonnullGCPtr<FontFaceSet>>
FontFaceSet::add(JS::Handle<FontFace> face)
{
// 1. If font is already in the FontFaceSets set entries, skip to the last step of this algorithm immediately.
if (m_set_entries->set_has(face))
return JS::NonnullGCPtr<FontFaceSet>(*this);
// 2. If font is CSS-connected, throw an InvalidModificationError exception and exit this algorithm immediately.
if (face->is_css_connected()) {
return WebIDL::InvalidModificationError::create(realm(), "Cannot add a CSS-connected FontFace to a FontFaceSet"_fly_string);
}
// 3. Add the font argument to the FontFaceSets set entries.
m_set_entries->set_add(face);
// 4. If fonts status attribute is "loading"
if (face->status() == Bindings::FontFaceLoadStatus::Loading) {
// 1. If the FontFaceSets [[LoadingFonts]] list is empty, switch the FontFaceSet to loading.
if (m_loading_fonts.is_empty()) {
m_status = Bindings::FontFaceSetLoadStatus::Loading;
}
// 2. Append font to the FontFaceSets [[LoadingFonts]] list.
m_loading_fonts.append(*face);
}
// 5. Return the FontFaceSet.
return JS::NonnullGCPtr<FontFaceSet>(*this);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-delete
bool FontFaceSet::delete_(JS::Handle<FontFace> 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-onloading
void FontFaceSet::set_onloading(WebIDL::CallbackType* event_handler)
{
set_event_handler_attribute(HTML::EventNames::loading, event_handler);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloading
WebIDL::CallbackType* FontFaceSet::onloading()
{
return event_handler_attribute(HTML::EventNames::loading);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingdone
void FontFaceSet::set_onloadingdone(WebIDL::CallbackType* event_handler)
{
set_event_handler_attribute(HTML::EventNames::loadingdone, event_handler);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingdone
WebIDL::CallbackType* FontFaceSet::onloadingdone()
{
return event_handler_attribute(HTML::EventNames::loadingdone);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingerror
void FontFaceSet::set_onloadingerror(WebIDL::CallbackType* event_handler)
{
set_event_handler_attribute(HTML::EventNames::loadingerror, event_handler);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingerror
WebIDL::CallbackType* FontFaceSet::onloadingerror()
{
return event_handler_attribute(HTML::EventNames::loadingerror);
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> FontFaceSet::load(String const&, String const&)
{
// FIXME: Do the steps
auto promise = WebIDL::create_rejected_promise(realm(), WebIDL::NotSupportedError::create(realm(), "FontFaceSet::load is not yet implemented"_fly_string));
return verify_cast<JS::Promise>(*promise->promise());
}
// https://drafts.csswg.org/css-font-loading/#font-face-set-ready
JS::NonnullGCPtr<JS::Promise> FontFaceSet::ready() const
{
return verify_cast<JS::Promise>(*m_ready_promise->promise());
}
}