瀏覽代碼

LibWeb: Add stub implementation of FontFaceSet and Document.fonts

This is now enough for duolingo to load and use its fallback fonts.
Andrew Kaster 1 年之前
父節點
當前提交
e10721f1b5

+ 1 - 1
Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

@@ -1569,7 +1569,7 @@ void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& ge
 )~~~");
 )~~~");
     } else {
     } else {
         sequence_generator.append(R"~~~(
         sequence_generator.append(R"~~~(
-    @sequence.storage_type@ @cpp_name@ { vm.heap() };
+    @sequence.storage_type@<@sequence.type@> @cpp_name@ { vm.heap() };
 )~~~");
 )~~~");
     }
     }
 
 

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -55,6 +55,7 @@ set(SOURCES
     CSS/Display.cpp
     CSS/Display.cpp
     CSS/EdgeRect.cpp
     CSS/EdgeRect.cpp
     CSS/FontFace.cpp
     CSS/FontFace.cpp
+    CSS/FontFaceSet.cpp
     CSS/Flex.cpp
     CSS/Flex.cpp
     CSS/Frequency.cpp
     CSS/Frequency.cpp
     CSS/GridTrackPlacement.cpp
     CSS/GridTrackPlacement.cpp

+ 55 - 0
Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Heap/Heap.h>
+#include <LibJS/Runtime/Realm.h>
+#include <LibWeb/Bindings/FontFaceSetPrototype.h>
+#include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/CSS/FontFaceSet.h>
+#include <LibWeb/WebIDL/Promise.h>
+
+namespace Web::CSS {
+
+JS_DEFINE_ALLOCATOR(FontFaceSet);
+
+JS::NonnullGCPtr<FontFaceSet> FontFaceSet::construct_impl(JS::Realm& realm, Vector<JS::Handle<FontFace>> initial_faces)
+{
+    return realm.heap().allocate<FontFaceSet>(realm, realm, move(initial_faces));
+}
+
+JS::NonnullGCPtr<FontFaceSet> FontFaceSet::create(JS::Realm& realm)
+{
+    return construct_impl(realm, {});
+}
+
+FontFaceSet::FontFaceSet(JS::Realm& realm, Vector<JS::Handle<FontFace>>)
+    : Bindings::PlatformObject(realm)
+{
+}
+
+void FontFaceSet::initialize(JS::Realm& realm)
+{
+    Base::initialize(realm);
+
+    WEB_SET_PROTOTYPE_FOR_INTERFACE(FontFaceSet);
+}
+
+// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-add
+JS::NonnullGCPtr<FontFaceSet> FontFaceSet::add(JS::Handle<FontFace>)
+{
+    // FIXME: Do the steps
+    return *this;
+}
+
+// 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());
+}
+
+}

+ 32 - 0
Userland/Libraries/LibWeb/CSS/FontFaceSet.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/Bindings/PlatformObject.h>
+#include <LibWeb/CSS/FontFace.h>
+
+namespace Web::CSS {
+
+class FontFaceSet final : public Bindings::PlatformObject {
+    WEB_PLATFORM_OBJECT(FontFace, Bindings::PlatformObject);
+    JS_DECLARE_ALLOCATOR(FontFaceSet);
+
+public:
+    [[nodiscard]] static JS::NonnullGCPtr<FontFaceSet> construct_impl(JS::Realm&, Vector<JS::Handle<FontFace>> initial_faces);
+    [[nodiscard]] static JS::NonnullGCPtr<FontFaceSet> create(JS::Realm&);
+    virtual ~FontFaceSet() override = default;
+
+    JS::NonnullGCPtr<FontFaceSet> add(JS::Handle<FontFace> face);
+    JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> load(String const& font, String const& text);
+
+private:
+    FontFaceSet(JS::Realm&, Vector<JS::Handle<FontFace>> initial_faces);
+
+    virtual void initialize(JS::Realm&) override;
+};
+
+}

+ 49 - 0
Userland/Libraries/LibWeb/CSS/FontFaceSet.idl

@@ -0,0 +1,49 @@
+#import <CSS/FontFace.idl>
+
+dictionary FontFaceSetLoadEventInit : EventInit {
+    sequence<FontFace> fontfaces = [];
+};
+
+// FIXME
+// [Exposed=(Window,Worker)]
+//interface FontFaceSetLoadEvent : Event {
+//    constructor(CSSOMString type, optional FontFaceSetLoadEventInit eventInitDict = {});
+//    [SameObject] readonly attribute FrozenArray<FontFace> fontfaces;
+//};
+
+enum FontFaceSetLoadStatus { "loading", "loaded" };
+
+// https://drafts.csswg.org/css-font-loading/#fontfaceset
+[Exposed=(Window,Worker)]
+interface FontFaceSet : EventTarget {
+    constructor(sequence<FontFace> initialFaces);
+
+    // FIXME: setlike<FontFace>;
+    FontFaceSet add(FontFace font);
+    // FIXME: boolean delete(FontFace font);
+    // FIXME:  clear();
+
+    // events for when loading state changes
+    // FIXME: attribute EventHandler onloading;
+    // FIXME: attribute EventHandler onloadingdone;
+    // FIXME: attribute EventHandler onloadingerror;
+
+    // check and start loads if appropriate
+    // and fulfill promise when all loads complete
+    // FIXME: Promise<sequence<FontFace>> load(CSSOMString font, optional CSSOMString text = " ");
+    Promise<sequence<FontFace>> load(CSSOMString font, optional CSSOMString text = "");
+
+    // return whether all fonts in the fontlist are loaded
+    // (does not initiate load if not available)
+    // FIXME: boolean check(CSSOMString font, optional CSSOMString text = " ");
+
+    // async notification that font loading and layout operations are done
+    // FIXME: readonly attribute Promise<FontFaceSet> ready;
+
+    // loading state, "loading" while one or more fonts loading, "loaded" otherwise
+    // FIXME: readonly attribute FontFaceSetLoadStatus status;
+};
+
+interface mixin FontFaceSource {
+    readonly attribute FontFaceSet fonts;
+};

+ 10 - 0
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -26,6 +26,7 @@
 #include <LibWeb/Bindings/MainThreadVM.h>
 #include <LibWeb/Bindings/MainThreadVM.h>
 #include <LibWeb/CSS/AnimationEvent.h>
 #include <LibWeb/CSS/AnimationEvent.h>
 #include <LibWeb/CSS/CSSAnimation.h>
 #include <LibWeb/CSS/CSSAnimation.h>
+#include <LibWeb/CSS/FontFaceSet.h>
 #include <LibWeb/CSS/MediaQueryList.h>
 #include <LibWeb/CSS/MediaQueryList.h>
 #include <LibWeb/CSS/MediaQueryListEvent.h>
 #include <LibWeb/CSS/MediaQueryListEvent.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleComputer.h>
@@ -440,6 +441,7 @@ void Document::visit_edges(Cell::Visitor& visitor)
     visitor.visit(m_forms);
     visitor.visit(m_forms);
     visitor.visit(m_scripts);
     visitor.visit(m_scripts);
     visitor.visit(m_all);
     visitor.visit(m_all);
+    visitor.visit(m_fonts);
     visitor.visit(m_selection);
     visitor.visit(m_selection);
     visitor.visit(m_first_base_element_with_href_in_tree_order);
     visitor.visit(m_first_base_element_with_href_in_tree_order);
     visitor.visit(m_parser);
     visitor.visit(m_parser);
@@ -1452,6 +1454,14 @@ JS::NonnullGCPtr<HTML::HTMLAllCollection> Document::all()
     return *m_all;
     return *m_all;
 }
 }
 
 
+// https://drafts.csswg.org/css-font-loading/#font-source
+JS::NonnullGCPtr<CSS::FontFaceSet> Document::fonts()
+{
+    if (!m_fonts)
+        m_fonts = CSS::FontFaceSet::create(realm());
+    return *m_fonts;
+}
+
 // https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-clear
 // https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-clear
 void Document::clear()
 void Document::clear()
 {
 {

+ 6 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -256,6 +256,9 @@ public:
     JS::NonnullGCPtr<HTMLCollection> scripts();
     JS::NonnullGCPtr<HTMLCollection> scripts();
     JS::NonnullGCPtr<HTML::HTMLAllCollection> all();
     JS::NonnullGCPtr<HTML::HTMLAllCollection> all();
 
 
+    // https://drafts.csswg.org/css-font-loading/#font-source
+    JS::NonnullGCPtr<CSS::FontFaceSet> fonts();
+
     void clear();
     void clear();
     void capture_events();
     void capture_events();
     void release_events();
     void release_events();
@@ -810,6 +813,9 @@ private:
     JS::GCPtr<HTMLCollection> m_scripts;
     JS::GCPtr<HTMLCollection> m_scripts;
     JS::GCPtr<HTML::HTMLAllCollection> m_all;
     JS::GCPtr<HTML::HTMLAllCollection> m_all;
 
 
+    // https://drafts.csswg.org/css-font-loading/#font-source
+    JS::GCPtr<CSS::FontFaceSet> m_fonts;
+
     // https://html.spec.whatwg.org/#completely-loaded-time
     // https://html.spec.whatwg.org/#completely-loaded-time
     Optional<AK::UnixDateTime> m_completely_loaded_time;
     Optional<AK::UnixDateTime> m_completely_loaded_time;
 
 

+ 2 - 0
Userland/Libraries/LibWeb/DOM/Document.idl

@@ -1,4 +1,5 @@
 #import <Animations/DocumentTimeline.idl>
 #import <Animations/DocumentTimeline.idl>
+#import <CSS/FontFaceSet.idl>
 #import <CSS/StyleSheetList.idl>
 #import <CSS/StyleSheetList.idl>
 #import <DOM/CDATASection.idl>
 #import <DOM/CDATASection.idl>
 #import <DOM/Comment.idl>
 #import <DOM/Comment.idl>
@@ -152,3 +153,4 @@ dictionary ElementCreationOptions {
 Document includes ParentNode;
 Document includes ParentNode;
 Document includes GlobalEventHandlers;
 Document includes GlobalEventHandlers;
 Document includes DocumentOrShadowRoot;
 Document includes DocumentOrShadowRoot;
+Document includes FontFaceSource;

+ 1 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -125,6 +125,7 @@ class Flex;
 class FlexOrCalculated;
 class FlexOrCalculated;
 class FlexStyleValue;
 class FlexStyleValue;
 class FontFace;
 class FontFace;
+class FontFaceSet;
 class Frequency;
 class Frequency;
 class FrequencyOrCalculated;
 class FrequencyOrCalculated;
 class FrequencyPercentage;
 class FrequencyPercentage;

+ 9 - 0
Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp

@@ -8,6 +8,7 @@
 #include <LibWeb/Bindings/DedicatedWorkerExposedInterfaces.h>
 #include <LibWeb/Bindings/DedicatedWorkerExposedInterfaces.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/WorkerGlobalScopePrototype.h>
 #include <LibWeb/Bindings/WorkerGlobalScopePrototype.h>
+#include <LibWeb/CSS/FontFaceSet.h>
 #include <LibWeb/HTML/EventHandler.h>
 #include <LibWeb/HTML/EventHandler.h>
 #include <LibWeb/HTML/EventNames.h>
 #include <LibWeb/HTML/EventNames.h>
 #include <LibWeb/HTML/MessageEvent.h>
 #include <LibWeb/HTML/MessageEvent.h>
@@ -53,6 +54,7 @@ void WorkerGlobalScope::visit_edges(Cell::Visitor& visitor)
     visitor.visit(m_navigator);
     visitor.visit(m_navigator);
     visitor.visit(m_internal_port);
     visitor.visit(m_internal_port);
     visitor.visit(m_page);
     visitor.visit(m_page);
+    visitor.visit(m_fonts);
 }
 }
 
 
 void WorkerGlobalScope::finalize()
 void WorkerGlobalScope::finalize()
@@ -127,4 +129,11 @@ WebIDL::ExceptionOr<void> WorkerGlobalScope::post_message(JS::Value message, Str
 ENUMERATE_WORKER_GLOBAL_SCOPE_EVENT_HANDLERS(__ENUMERATE)
 ENUMERATE_WORKER_GLOBAL_SCOPE_EVENT_HANDLERS(__ENUMERATE)
 #undef __ENUMERATE
 #undef __ENUMERATE
 
 
+JS::NonnullGCPtr<CSS::FontFaceSet> WorkerGlobalScope::fonts()
+{
+    if (!m_fonts)
+        m_fonts = CSS::FontFaceSet::create(realm());
+    return *m_fonts;
+}
+
 }
 }

+ 5 - 0
Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.h

@@ -77,6 +77,8 @@ public:
 
 
     WebIDL::ExceptionOr<void> post_message(JS::Value message, StructuredSerializeOptions const&);
     WebIDL::ExceptionOr<void> post_message(JS::Value message, StructuredSerializeOptions const&);
 
 
+    JS::NonnullGCPtr<CSS::FontFaceSet> fonts();
+
     // Non-IDL public methods
     // Non-IDL public methods
 
 
     URL::URL const& url() const { return m_url.value(); }
     URL::URL const& url() const { return m_url.value(); }
@@ -136,6 +138,9 @@ private:
 
 
     // https://html.spec.whatwg.org/multipage/workers.html#concept-workerglobalscope-cross-origin-isolated-capability
     // https://html.spec.whatwg.org/multipage/workers.html#concept-workerglobalscope-cross-origin-isolated-capability
     bool m_cross_origin_isolated_capability { false };
     bool m_cross_origin_isolated_capability { false };
+
+    // https://drafts.csswg.org/css-font-loading/#font-source
+    JS::GCPtr<CSS::FontFaceSet> m_fonts;
 };
 };
 
 
 }
 }

+ 2 - 0
Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.idl

@@ -1,3 +1,4 @@
+#import <CSS/FontFaceSet.idl>
 #import <DOM/EventTarget.idl>
 #import <DOM/EventTarget.idl>
 #import <DOM/EventHandler.idl>
 #import <DOM/EventHandler.idl>
 #import <HTML/WindowOrWorkerGlobalScope.idl>
 #import <HTML/WindowOrWorkerGlobalScope.idl>
@@ -28,3 +29,4 @@ interface WorkerGlobalScope : EventTarget {
 };
 };
 
 
 WorkerGlobalScope includes WindowOrWorkerGlobalScope;
 WorkerGlobalScope includes WindowOrWorkerGlobalScope;
+WorkerGlobalScope includes FontFaceSource;

+ 1 - 0
Userland/Libraries/LibWeb/idl_files.cmake

@@ -30,6 +30,7 @@ libweb_js_bindings(CSS/CSSStyleSheet)
 libweb_js_bindings(CSS/CSSSupportsRule)
 libweb_js_bindings(CSS/CSSSupportsRule)
 libweb_js_bindings(CSS/CSSTransition)
 libweb_js_bindings(CSS/CSSTransition)
 libweb_js_bindings(CSS/FontFace)
 libweb_js_bindings(CSS/FontFace)
+libweb_js_bindings(CSS/FontFaceSet)
 libweb_js_bindings(CSS/MediaList)
 libweb_js_bindings(CSS/MediaList)
 libweb_js_bindings(CSS/MediaQueryList)
 libweb_js_bindings(CSS/MediaQueryList)
 libweb_js_bindings(CSS/MediaQueryListEvent)
 libweb_js_bindings(CSS/MediaQueryListEvent)