浏览代码

LibGfx+LibUnicode: Support specifying the path to search for emoji

Similar to the FontDatabase, this will be needed for Ladybird to find
emoji images. We now generate just the file name of emoji image in
LibUnicode, and look for that file in the specified path (defaulting to
/res/emoji) at runtime.
Timothy Flynn 2 年之前
父节点
当前提交
fd1fbad1d2

+ 2 - 3
Meta/CMake/unicode_data.cmake

@@ -64,8 +64,7 @@ set(SENTENCE_BREAK_PROP_PATH "${UCD_PATH}/${SENTENCE_BREAK_PROP_SOURCE}")
 string(REGEX REPLACE "([0-9]+\\.[0-9]+)\\.[0-9]+" "\\1" EMOJI_VERSION "${UCD_VERSION}")
 string(REGEX REPLACE "([0-9]+\\.[0-9]+)\\.[0-9]+" "\\1" EMOJI_VERSION "${UCD_VERSION}")
 set(EMOJI_TEST_URL "https://www.unicode.org/Public/emoji/${EMOJI_VERSION}/emoji-test.txt")
 set(EMOJI_TEST_URL "https://www.unicode.org/Public/emoji/${EMOJI_VERSION}/emoji-test.txt")
 set(EMOJI_TEST_PATH "${UCD_PATH}/emoji-test.txt")
 set(EMOJI_TEST_PATH "${UCD_PATH}/emoji-test.txt")
-set(EMOJI_BASE_PATH "${SerenityOS_SOURCE_DIR}/Base")
-set(EMOJI_RES_PATH "${EMOJI_BASE_PATH}/res/emoji")
+set(EMOJI_RES_PATH "${SerenityOS_SOURCE_DIR}/Base/res/emoji")
 set(EMOJI_SERENITY_PATH "${SerenityOS_SOURCE_DIR}/Base/home/anon/Documents/emoji-serenity.txt")
 set(EMOJI_SERENITY_PATH "${SerenityOS_SOURCE_DIR}/Base/home/anon/Documents/emoji-serenity.txt")
 set(EMOJI_INSTALL_PATH "${CMAKE_BINARY_DIR}/Root/home/anon/Documents/emoji.txt")
 set(EMOJI_INSTALL_PATH "${CMAKE_BINARY_DIR}/Root/home/anon/Documents/emoji.txt")
 
 
@@ -118,7 +117,7 @@ if (ENABLE_UNICODE_DATABASE_DOWNLOAD)
         "${UCD_VERSION_FILE}"
         "${UCD_VERSION_FILE}"
         "${EMOJI_DATA_HEADER}"
         "${EMOJI_DATA_HEADER}"
         "${EMOJI_DATA_IMPLEMENTATION}"
         "${EMOJI_DATA_IMPLEMENTATION}"
-        arguments "${EMOJI_INSTALL_ARG}" -e "${EMOJI_TEST_PATH}" -s "${EMOJI_SERENITY_PATH}" -b "${EMOJI_BASE_PATH}" -r "${EMOJI_RES_PATH}"
+        arguments "${EMOJI_INSTALL_ARG}" -e "${EMOJI_TEST_PATH}" -s "${EMOJI_SERENITY_PATH}" -r "${EMOJI_RES_PATH}"
 
 
         # This will make this command only run when the modified time of the directory changes,
         # This will make this command only run when the modified time of the directory changes,
         # which only happens if files within it are added or deleted, but not when a file is modified.
         # which only happens if files within it are added or deleted, but not when a file is modified.

+ 5 - 8
Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateEmojiData.cpp

@@ -32,7 +32,7 @@ struct EmojiData {
     Vector<Emoji> emojis;
     Vector<Emoji> emojis;
 };
 };
 
 
-static void set_image_path_for_emoji(StringView emoji_base_path, StringView emoji_resource_path, EmojiData& emoji_data, Emoji& emoji)
+static void set_image_path_for_emoji(StringView emoji_resource_path, EmojiData& emoji_data, Emoji& emoji)
 {
 {
     StringBuilder builder;
     StringBuilder builder;
 
 
@@ -44,12 +44,12 @@ static void set_image_path_for_emoji(StringView emoji_base_path, StringView emoj
         builder.appendff("U+{:X}", code_point);
         builder.appendff("U+{:X}", code_point);
     }
     }
 
 
-    auto path = DeprecatedString::formatted("{}/{}.png", emoji_resource_path, builder.to_deprecated_string());
+    auto file = DeprecatedString::formatted("{}.png", builder.to_deprecated_string());
+    auto path = DeprecatedString::formatted("{}/{}", emoji_resource_path, file);
     if (!Core::DeprecatedFile::exists(path))
     if (!Core::DeprecatedFile::exists(path))
         return;
         return;
 
 
-    auto installed_image_path = path.replace(emoji_base_path, {}, ReplaceMode::FirstOnly);
-    emoji.image_path = emoji_data.unique_strings.ensure(move(installed_image_path));
+    emoji.image_path = emoji_data.unique_strings.ensure(move(file));
 }
 }
 
 
 static ErrorOr<void> parse_emoji_test_data(Core::BufferedFile& file, EmojiData& emoji_data)
 static ErrorOr<void> parse_emoji_test_data(Core::BufferedFile& file, EmojiData& emoji_data)
@@ -335,7 +335,6 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     StringView generated_installation_path;
     StringView generated_installation_path;
     StringView emoji_test_path;
     StringView emoji_test_path;
     StringView emoji_serenity_path;
     StringView emoji_serenity_path;
-    StringView emoji_base_path;
     StringView emoji_resource_path;
     StringView emoji_resource_path;
 
 
     Core::ArgsParser args_parser;
     Core::ArgsParser args_parser;
@@ -344,11 +343,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     args_parser.add_option(generated_installation_path, "Path to the emoji.txt file to generate", "generated-installation-path", 'i', "generated-installation-path");
     args_parser.add_option(generated_installation_path, "Path to the emoji.txt file to generate", "generated-installation-path", 'i', "generated-installation-path");
     args_parser.add_option(emoji_test_path, "Path to emoji-test.txt file", "emoji-test-path", 'e', "emoji-test-path");
     args_parser.add_option(emoji_test_path, "Path to emoji-test.txt file", "emoji-test-path", 'e', "emoji-test-path");
     args_parser.add_option(emoji_serenity_path, "Path to emoji-serenity.txt file", "emoji-serenity-path", 's', "emoji-serenity-path");
     args_parser.add_option(emoji_serenity_path, "Path to emoji-serenity.txt file", "emoji-serenity-path", 's', "emoji-serenity-path");
-    args_parser.add_option(emoji_base_path, "Path to the Base directory", "emoji-base-path", 'b', "emoji-base-path");
     args_parser.add_option(emoji_resource_path, "Path to the /res/emoji directory", "emoji-resource-path", 'r', "emoji-resource-path");
     args_parser.add_option(emoji_resource_path, "Path to the /res/emoji directory", "emoji-resource-path", 'r', "emoji-resource-path");
     args_parser.parse(arguments);
     args_parser.parse(arguments);
 
 
-    VERIFY(!emoji_base_path.is_empty() && Core::DeprecatedFile::exists(emoji_base_path));
     VERIFY(!emoji_resource_path.is_empty() && Core::DeprecatedFile::exists(emoji_resource_path));
     VERIFY(!emoji_resource_path.is_empty() && Core::DeprecatedFile::exists(emoji_resource_path));
 
 
     auto emoji_test_file = TRY(open_file(emoji_test_path, Core::File::OpenMode::Read));
     auto emoji_test_file = TRY(open_file(emoji_test_path, Core::File::OpenMode::Read));
@@ -366,7 +363,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
         emoji.code_point_array_index = code_point_array_index;
         emoji.code_point_array_index = code_point_array_index;
         code_point_array_index += emoji.code_points.size();
         code_point_array_index += emoji.code_points.size();
 
 
-        set_image_path_for_emoji(emoji_base_path, emoji_resource_path, emoji_data, emoji);
+        set_image_path_for_emoji(emoji_resource_path, emoji_data, emoji);
     }
     }
 
 
     if (!generated_header_path.is_empty()) {
     if (!generated_header_path.is_empty()) {

+ 21 - 6
Userland/Libraries/LibGfx/Font/Emoji.cpp

@@ -8,9 +8,11 @@
 #include <AK/Debug.h>
 #include <AK/Debug.h>
 #include <AK/DeprecatedString.h>
 #include <AK/DeprecatedString.h>
 #include <AK/HashMap.h>
 #include <AK/HashMap.h>
+#include <AK/LexicalPath.h>
 #include <AK/Span.h>
 #include <AK/Span.h>
 #include <AK/Utf32View.h>
 #include <AK/Utf32View.h>
 #include <AK/Utf8View.h>
 #include <AK/Utf8View.h>
+#include <AK/Variant.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Font/Emoji.h>
 #include <LibGfx/Font/Emoji.h>
 #include <LibUnicode/CharacterTypes.h>
 #include <LibUnicode/CharacterTypes.h>
@@ -23,6 +25,17 @@ namespace Gfx {
 // https://unicode.org/emoji/charts/emoji-zwj-sequences.html
 // https://unicode.org/emoji/charts/emoji-zwj-sequences.html
 
 
 static HashMap<StringView, RefPtr<Gfx::Bitmap>> s_emojis;
 static HashMap<StringView, RefPtr<Gfx::Bitmap>> s_emojis;
+static Variant<String, StringView> s_emoji_lookup_path = "/res/emoji"sv;
+
+static StringView emoji_lookup_path()
+{
+    return s_emoji_lookup_path.visit([](auto const& path) -> StringView { return path; });
+}
+
+void Emoji::set_emoji_lookup_path(String emoji_lookup_path)
+{
+    s_emoji_lookup_path = move(emoji_lookup_path);
+}
 
 
 Bitmap const* Emoji::emoji_for_code_point(u32 code_point)
 Bitmap const* Emoji::emoji_for_code_point(u32 code_point)
 {
 {
@@ -35,19 +48,21 @@ Bitmap const* Emoji::emoji_for_code_points(ReadonlySpan<u32> const& code_points)
     if (!emoji.has_value() || !emoji->image_path.has_value())
     if (!emoji.has_value() || !emoji->image_path.has_value())
         return nullptr;
         return nullptr;
 
 
-    auto emoji_path = emoji->image_path.value();
-    if (auto it = s_emojis.find(emoji_path); it != s_emojis.end())
+    auto emoji_file = emoji->image_path.value();
+    if (auto it = s_emojis.find(emoji_file); it != s_emojis.end())
         return it->value.ptr();
         return it->value.ptr();
 
 
-    auto bitmap_or_error = Bitmap::load_from_file(emoji_path);
+    auto emoji_path = LexicalPath::join(emoji_lookup_path(), emoji_file);
+    auto bitmap_or_error = Bitmap::load_from_file(emoji_path.string());
+
     if (bitmap_or_error.is_error()) {
     if (bitmap_or_error.is_error()) {
-        dbgln_if(EMOJI_DEBUG, "Generated emoji data has path {}, but could not load image: {}", emoji_path, bitmap_or_error.error());
-        s_emojis.set(emoji_path, nullptr);
+        dbgln_if(EMOJI_DEBUG, "Generated emoji data has file {}, but could not load image: {}", emoji_file, bitmap_or_error.error());
+        s_emojis.set(emoji_file, nullptr);
         return nullptr;
         return nullptr;
     }
     }
 
 
     auto bitmap = bitmap_or_error.release_value();
     auto bitmap = bitmap_or_error.release_value();
-    s_emojis.set(emoji_path, bitmap);
+    s_emojis.set(emoji_file, bitmap);
     return bitmap.ptr();
     return bitmap.ptr();
 }
 }
 
 

+ 3 - 0
Userland/Libraries/LibGfx/Font/Emoji.h

@@ -9,6 +9,7 @@
 
 
 #include <AK/Forward.h>
 #include <AK/Forward.h>
 #include <AK/Span.h>
 #include <AK/Span.h>
+#include <AK/String.h>
 #include <AK/Types.h>
 #include <AK/Types.h>
 
 
 namespace Gfx {
 namespace Gfx {
@@ -17,6 +18,8 @@ class Bitmap;
 
 
 class Emoji {
 class Emoji {
 public:
 public:
+    static void set_emoji_lookup_path(String);
+
     static Gfx::Bitmap const* emoji_for_code_point(u32 code_point);
     static Gfx::Bitmap const* emoji_for_code_point(u32 code_point);
     static Gfx::Bitmap const* emoji_for_code_points(ReadonlySpan<u32> const&);
     static Gfx::Bitmap const* emoji_for_code_points(ReadonlySpan<u32> const&);
     static Gfx::Bitmap const* emoji_for_code_point_iterator(Utf8CodePointIterator&);
     static Gfx::Bitmap const* emoji_for_code_point_iterator(Utf8CodePointIterator&);