Quellcode durchsuchen

LibGfx: Move FontDatabase internals to SystemFontProvider interface

This will be the first step is making better use of system libraries
like fontconfig and CoreText to load system fonts for use by the UI
process and the CSS style computer.
Andrew Kaster vor 9 Monaten
Ursprung
Commit
36a8ad9157

+ 11 - 4
Ladybird/FontPlugin.cpp

@@ -8,9 +8,11 @@
 #include "FontPlugin.h"
 #include <AK/ByteString.h>
 #include <AK/String.h>
+#include <AK/TypeCasts.h>
 #include <LibCore/Resource.h>
 #include <LibCore/StandardPaths.h>
 #include <LibGfx/Font/FontDatabase.h>
+#include <LibGfx/Font/PathFontProvider.h>
 
 #ifdef USE_FONTCONFIG
 #    include <fontconfig/fontconfig.h>
@@ -18,7 +20,7 @@
 
 namespace Ladybird {
 
-FontPlugin::FontPlugin(bool is_layout_test_mode)
+FontPlugin::FontPlugin(bool is_layout_test_mode, Gfx::SystemFontProvider* font_provider)
     : m_is_layout_test_mode(is_layout_test_mode)
 {
 #ifdef USE_FONTCONFIG
@@ -28,9 +30,14 @@ FontPlugin::FontPlugin(bool is_layout_test_mode)
     }
 #endif
 
-    // Load anything we can find in the system's font directories
-    for (auto const& path : Core::StandardPaths::font_directories().release_value_but_fixme_should_propagate_errors())
-        Gfx::FontDatabase::the().load_all_fonts_from_uri(MUST(String::formatted("file://{}", path)));
+    if (!font_provider)
+        font_provider = &static_cast<Gfx::PathFontProvider&>(Gfx::FontDatabase::the().install_system_font_provider(make<Gfx::PathFontProvider>()));
+    if (is<Gfx::PathFontProvider>(*font_provider)) {
+        auto& path_font_provider = static_cast<Gfx::PathFontProvider&>(*font_provider);
+        // Load anything we can find in the system's font directories
+        for (auto const& path : Core::StandardPaths::font_directories().release_value_but_fixme_should_propagate_errors())
+            path_font_provider.load_all_fonts_from_uri(MUST(String::formatted("file://{}", path)));
+    }
 
     update_generic_fonts();
 

+ 2 - 1
Ladybird/FontPlugin.h

@@ -8,13 +8,14 @@
 
 #include <AK/RefPtr.h>
 #include <AK/Vector.h>
+#include <LibGfx/Font/FontDatabase.h>
 #include <LibWeb/Platform/FontPlugin.h>
 
 namespace Ladybird {
 
 class FontPlugin final : public Web::Platform::FontPlugin {
 public:
-    FontPlugin(bool is_layout_test_mode);
+    FontPlugin(bool is_layout_test_mode, Gfx::SystemFontProvider* = nullptr);
     virtual ~FontPlugin();
 
     virtual Gfx::Font& default_font() override;

+ 5 - 4
Ladybird/WebContent/main.cpp

@@ -15,6 +15,7 @@
 #include <LibCore/Resource.h>
 #include <LibCore/SystemServerTakeover.h>
 #include <LibGfx/Font/FontDatabase.h>
+#include <LibGfx/Font/PathFontProvider.h>
 #include <LibIPC/ConnectionFromClient.h>
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibMain/Main.h>
@@ -128,11 +129,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         Core::Process::wait_for_debugger_and_break();
     }
 
+    auto& font_provider = static_cast<Gfx::PathFontProvider&>(Gfx::FontDatabase::the().install_system_font_provider(make<Gfx::PathFontProvider>()));
     if (force_fontconfig) {
-        Gfx::FontDatabase::the().set_force_fontconfig(true);
+        font_provider.set_name_but_fixme_should_create_custom_system_font_provider("FontConfig"_string);
     }
-
-    Gfx::FontDatabase::the().load_all_fonts_from_uri("resource://fonts"sv);
+    font_provider.load_all_fonts_from_uri("resource://fonts"sv);
 
     // Layout test mode implies internals object is exposed and the Skia CPU backend is used
     if (is_layout_test_mode) {
@@ -167,7 +168,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     Web::HTML::Window::set_internals_object_exposed(expose_internals_object);
 
-    Web::Platform::FontPlugin::install(*new Ladybird::FontPlugin(is_layout_test_mode));
+    Web::Platform::FontPlugin::install(*new Ladybird::FontPlugin(is_layout_test_mode, &font_provider));
 
     TRY(Web::Bindings::initialize_main_thread_vm(Web::HTML::EventLoop::Type::Window));
 

+ 11 - 0
Tests/LibGfx/TestWOFF2.cpp

@@ -4,11 +4,22 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <LibGfx/Font/FontDatabase.h>
+#include <LibGfx/Font/PathFontProvider.h>
 #include <LibGfx/Font/WOFF2/Loader.h>
 #include <LibTest/TestCase.h>
 
 #define TEST_INPUT(x) ("test-inputs/" x)
 
+namespace {
+struct Global {
+    Global()
+    {
+        Gfx::FontDatabase::the().install_system_font_provider(make<Gfx::PathFontProvider>());
+    }
+} global;
+}
+
 TEST_CASE(tolerate_incorrect_sfnt_size)
 {
     auto file = MUST(Core::MappedFile::map(TEST_INPUT("woff2/incorrect_sfnt_size.woff2"sv)));

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

@@ -15,6 +15,7 @@ set(SOURCES
     Font/Font.cpp
     Font/FontData.cpp
     Font/FontDatabase.cpp
+    Font/PathFontProvider.cpp
     Font/ScaledFont.cpp
     Font/ScaledFontSkia.cpp
     Font/Typeface.cpp

+ 13 - 69
Userland/Libraries/LibGfx/Font/FontDatabase.cpp

@@ -4,100 +4,44 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <AK/DeprecatedFlyString.h>
 #include <AK/FlyString.h>
-#include <AK/LexicalPath.h>
-#include <AK/Queue.h>
-#include <LibCore/Resource.h>
 #include <LibGfx/Font/Font.h>
 #include <LibGfx/Font/FontDatabase.h>
-#include <LibGfx/Font/ScaledFont.h>
-#include <LibGfx/Font/WOFF/Loader.h>
 
 namespace Gfx {
 
+// Key function for SystemFontProvider to emit the vtable here
+SystemFontProvider::~SystemFontProvider() = default;
+
 FontDatabase& FontDatabase::the()
 {
     static FontDatabase s_the;
     return s_the;
 }
 
-struct FontDatabase::Private {
-    bool force_fontconfig { false };
-    HashMap<FlyString, Vector<NonnullRefPtr<Typeface>>, AK::ASCIICaseInsensitiveFlyStringTraits> typeface_by_family;
-};
-
-void FontDatabase::set_force_fontconfig(bool force_fontconfig)
-{
-    m_private->force_fontconfig = force_fontconfig;
-}
-
-bool FontDatabase::should_force_fontconfig() const
+SystemFontProvider& FontDatabase::install_system_font_provider(NonnullOwnPtr<SystemFontProvider> provider)
 {
-    return m_private->force_fontconfig;
+    VERIFY(!m_system_font_provider);
+    m_system_font_provider = move(provider);
+    return *m_system_font_provider;
 }
 
-void FontDatabase::load_all_fonts_from_uri(StringView uri)
+StringView FontDatabase::system_font_provider_name() const
 {
-    auto root_or_error = Core::Resource::load_from_uri(uri);
-    if (root_or_error.is_error()) {
-        if (root_or_error.error().is_errno() && root_or_error.error().code() == ENOENT) {
-            return;
-        }
-        dbgln("FontDatabase::load_all_fonts_from_uri('{}'): {}", uri, root_or_error.error());
-        return;
-    }
-    auto root = root_or_error.release_value();
-
-    root->for_each_descendant_file([this](Core::Resource const& resource) -> IterationDecision {
-        auto uri = resource.uri();
-        auto path = LexicalPath(uri.bytes_as_string_view());
-        if (path.has_extension(".ttf"sv) || path.has_extension(".ttc"sv)) {
-            // FIXME: What about .otf
-            if (auto font_or_error = Typeface::try_load_from_resource(resource); !font_or_error.is_error()) {
-                auto font = font_or_error.release_value();
-                auto& family = m_private->typeface_by_family.ensure(font->family(), [] {
-                    return Vector<NonnullRefPtr<Typeface>> {};
-                });
-                family.append(font);
-            }
-        } else if (path.has_extension(".woff"sv)) {
-            if (auto font_or_error = WOFF::try_load_from_resource(resource); !font_or_error.is_error()) {
-                auto font = font_or_error.release_value();
-                auto& family = m_private->typeface_by_family.ensure(font->family(), [] {
-                    return Vector<NonnullRefPtr<Typeface>> {};
-                });
-                family.append(font);
-            }
-        }
-        return IterationDecision::Continue;
-    });
+    VERIFY(m_system_font_provider);
+    return m_system_font_provider->name();
 }
 
-FontDatabase::FontDatabase()
-    : m_private(make<Private>())
-{
-}
+FontDatabase::FontDatabase() = default;
 
 RefPtr<Gfx::Font> FontDatabase::get(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope)
 {
-    auto it = m_private->typeface_by_family.find(family);
-    if (it == m_private->typeface_by_family.end())
-        return nullptr;
-    for (auto const& typeface : it->value) {
-        if (typeface->weight() == weight && typeface->width() == width && typeface->slope() == slope)
-            return typeface->scaled_font(point_size);
-    }
-    return nullptr;
+    return m_system_font_provider->get_font(family, point_size, weight, width, slope);
 }
 
 void FontDatabase::for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)> callback)
 {
-    auto it = m_private->typeface_by_family.find(family_name);
-    if (it == m_private->typeface_by_family.end())
-        return;
-    for (auto const& typeface : it->value)
-        callback(*typeface);
+    m_system_font_provider->for_each_typeface_with_family_name(family_name, move(callback));
 }
 
 }

+ 12 - 10
Userland/Libraries/LibGfx/Font/FontDatabase.h

@@ -6,36 +6,38 @@
 
 #pragma once
 
-#include <AK/ByteString.h>
 #include <AK/FlyString.h>
 #include <AK/Function.h>
 #include <AK/HashMap.h>
 #include <AK/OwnPtr.h>
-#include <LibGfx/Font/FontWeight.h>
 #include <LibGfx/Font/Typeface.h>
 #include <LibGfx/Forward.h>
 
 namespace Gfx {
 
+class SystemFontProvider {
+public:
+    virtual ~SystemFontProvider();
+
+    virtual StringView name() const = 0;
+    virtual RefPtr<Gfx::Font> get_font(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope) = 0;
+    virtual void for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)>) = 0;
+};
+
 class FontDatabase {
 public:
     static FontDatabase& the();
+    SystemFontProvider& install_system_font_provider(NonnullOwnPtr<SystemFontProvider>);
 
     RefPtr<Gfx::Font> get(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope);
-
     void for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)>);
-
-    void load_all_fonts_from_uri(StringView);
-
-    void set_force_fontconfig(bool);
-    [[nodiscard]] bool should_force_fontconfig() const;
+    [[nodiscard]] StringView system_font_provider_name() const;
 
 private:
     FontDatabase();
     ~FontDatabase() = default;
 
-    struct Private;
-    OwnPtr<Private> m_private;
+    OwnPtr<SystemFontProvider> m_system_font_provider;
 };
 
 }

+ 78 - 0
Userland/Libraries/LibGfx/Font/PathFontProvider.cpp

@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Format.h>
+#include <AK/LexicalPath.h>
+#include <LibCore/Resource.h>
+#include <LibGfx/Font/PathFontProvider.h>
+#include <LibGfx/Font/ScaledFont.h>
+#include <LibGfx/Font/WOFF/Loader.h>
+
+namespace Gfx {
+
+PathFontProvider::PathFontProvider() = default;
+PathFontProvider::~PathFontProvider() = default;
+
+void PathFontProvider::load_all_fonts_from_uri(StringView uri)
+{
+    auto root_or_error = Core::Resource::load_from_uri(uri);
+    if (root_or_error.is_error()) {
+        if (root_or_error.error().is_errno() && root_or_error.error().code() == ENOENT) {
+            return;
+        }
+        dbgln("PathFontProvider::load_all_fonts_from_uri('{}'): {}", uri, root_or_error.error());
+        return;
+    }
+    auto root = root_or_error.release_value();
+
+    root->for_each_descendant_file([this](Core::Resource const& resource) -> IterationDecision {
+        auto uri = resource.uri();
+        auto path = LexicalPath(uri.bytes_as_string_view());
+        if (path.has_extension(".ttf"sv) || path.has_extension(".ttc"sv)) {
+            // FIXME: What about .otf
+            if (auto font_or_error = Typeface::try_load_from_resource(resource); !font_or_error.is_error()) {
+                auto font = font_or_error.release_value();
+                auto& family = m_typeface_by_family.ensure(font->family(), [] {
+                    return Vector<NonnullRefPtr<Typeface>> {};
+                });
+                family.append(font);
+            }
+        } else if (path.has_extension(".woff"sv)) {
+            if (auto font_or_error = WOFF::try_load_from_resource(resource); !font_or_error.is_error()) {
+                auto font = font_or_error.release_value();
+                auto& family = m_typeface_by_family.ensure(font->family(), [] {
+                    return Vector<NonnullRefPtr<Typeface>> {};
+                });
+                family.append(font);
+            }
+        }
+        return IterationDecision::Continue;
+    });
+}
+
+RefPtr<Gfx::Font> PathFontProvider::get_font(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope)
+{
+    auto it = m_typeface_by_family.find(family);
+    if (it == m_typeface_by_family.end())
+        return nullptr;
+    for (auto const& typeface : it->value) {
+        if (typeface->weight() == weight && typeface->width() == width && typeface->slope() == slope)
+            return typeface->scaled_font(point_size);
+    }
+    return nullptr;
+}
+
+void PathFontProvider::for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)> callback)
+{
+    auto it = m_typeface_by_family.find(family_name);
+    if (it == m_typeface_by_family.end())
+        return;
+    for (auto const& typeface : it->value) {
+        callback(*typeface);
+    }
+}
+
+}

+ 39 - 0
Userland/Libraries/LibGfx/Font/PathFontProvider.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/FlyString.h>
+#include <AK/Function.h>
+#include <AK/HashMap.h>
+#include <AK/OwnPtr.h>
+#include <LibGfx/Font/FontDatabase.h>
+#include <LibGfx/Font/Typeface.h>
+
+namespace Gfx {
+
+class PathFontProvider final : public SystemFontProvider {
+    AK_MAKE_NONCOPYABLE(PathFontProvider);
+    AK_MAKE_NONMOVABLE(PathFontProvider);
+
+public:
+    PathFontProvider();
+    virtual ~PathFontProvider() override;
+
+    void set_name_but_fixme_should_create_custom_system_font_provider(String name) { m_name = move(name); }
+
+    void load_all_fonts_from_uri(StringView);
+
+    virtual RefPtr<Gfx::Font> get_font(FlyString const& family, float point_size, unsigned weight, unsigned width, unsigned slope) override;
+    virtual void for_each_typeface_with_family_name(FlyString const& family_name, Function<void(Typeface const&)>) override;
+    virtual StringView name() const override { return m_name.bytes_as_string_view(); }
+
+private:
+    HashMap<FlyString, Vector<NonnullRefPtr<Typeface>>, AK::ASCIICaseInsensitiveFlyStringTraits> m_typeface_by_family;
+    String m_name { "Path"_string };
+};
+
+}

+ 1 - 1
Userland/Libraries/LibGfx/Font/TypefaceSkia.cpp

@@ -35,7 +35,7 @@ ErrorOr<NonnullRefPtr<TypefaceSkia>> TypefaceSkia::load_from_buffer(AK::Readonly
 {
     if (!s_font_manager) {
 #ifdef AK_OS_MACOS
-        if (!Gfx::FontDatabase::the().should_force_fontconfig()) {
+        if (Gfx::FontDatabase::the().system_font_provider_name() != "FontConfig"sv) {
             s_font_manager = SkFontMgr_New_CoreText(nullptr);
         }
 #endif

+ 1 - 0
Userland/Libraries/LibWeb/CSS/StyleComputer.cpp

@@ -19,6 +19,7 @@
 #include <LibGfx/Font/Font.h>
 #include <LibGfx/Font/FontDatabase.h>
 #include <LibGfx/Font/FontStyleMapping.h>
+#include <LibGfx/Font/FontWeight.h>
 #include <LibGfx/Font/ScaledFont.h>
 #include <LibGfx/Font/Typeface.h>
 #include <LibGfx/Font/WOFF/Loader.h>