From d5465f1953ffdde0610b731b5b6cb3218970a31a Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Wed, 2 Apr 2025 00:07:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BD=E8=B1=A1=E5=AD=97=E4=BD=93=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 8 +- CMakeLists.txt | 2 - example/src/main.cpp | 47 --- src/mirage_app/mirage.cpp | 2 + src/mirage_render/CMakeLists.txt | 23 +- .../font/freetype_font/CMakeLists.txt | 10 + .../font/freetype_font}/freetype | 0 .../font/freetype_font}/harfbuzz | 0 .../freetype_font/src/freetype_interface.cpp | 163 ++++++++ .../freetype_font/src/freetype_interface.h | 23 ++ .../font/stb_truetype_font/CMakeLists.txt | 8 + .../stb_truetype_font}/stb_truetype.h | 0 .../stb_truetype_interface.cpp | 212 ++++++++++ .../stb_truetype_interface.h | 28 ++ .../stb_image_loader/CMakeLists.txt | 0 .../{ => image}/stb_image_loader/stb_image.h | 0 .../stb_image_loader/stb_image_loader.cpp | 0 .../stb_image_loader/stb_image_loader.h | 0 .../src/font/atlas/bitmap_glyph_atlas.cpp | 45 +++ .../src/font/atlas/bitmap_glyph_atlas.h | 59 +-- .../src/font/atlas/color_emoji_atlas.cpp | 44 +++ .../src/font/atlas/color_emoji_atlas.h | 43 +- src/mirage_render/src/font/atlas/font_atlas.h | 1 - .../src/font/atlas/font_atlas_manager.cpp | 8 +- .../src/font/atlas/font_atlas_manager.h | 5 +- src/mirage_render/src/font/font_face.cpp | 371 ------------------ src/mirage_render/src/font/font_face.h | 242 ------------ .../src/font/font_renderer/cbdt_renderer.cpp | 295 -------------- .../src/font/font_renderer/cbdt_renderer.h | 73 ---- .../src/font/font_renderer/colr_renderer.cpp | 351 ----------------- .../src/font/font_renderer/colr_renderer.h | 38 -- .../src/font/font_renderer/font_renderer.h | 72 ---- .../src/font/font_renderer/sbix_renderer.cpp | 220 ----------- .../src/font/font_renderer/sbix_renderer.h | 75 ---- .../standard_bitmap_renderer.cpp | 50 --- .../font_renderer/standard_bitmap_renderer.h | 21 - .../src/font/font_renderer/svg_renderer.cpp | 169 -------- .../src/font/font_renderer/svg_renderer.h | 65 --- src/mirage_render/src/font/font_system.cpp | 56 +-- src/mirage_render/src/font/font_system.h | 18 +- src/mirage_render/src/font/font_type.h | 40 -- .../src/interface/font_interface.cpp | 10 + .../src/interface/font_interface.h | 63 +++ .../src/interface/image_interface.h | 15 +- .../src/render/render_elements.h | 1 - .../widget/leaf_widget/mtext_block.h | 6 +- 46 files changed, 691 insertions(+), 2291 deletions(-) create mode 100644 src/mirage_render/font/freetype_font/CMakeLists.txt rename {third_party => src/mirage_render/font/freetype_font}/freetype (100%) rename {third_party => src/mirage_render/font/freetype_font}/harfbuzz (100%) create mode 100644 src/mirage_render/font/freetype_font/src/freetype_interface.cpp create mode 100644 src/mirage_render/font/freetype_font/src/freetype_interface.h create mode 100644 src/mirage_render/font/stb_truetype_font/CMakeLists.txt rename src/mirage_render/{src/font => font/stb_truetype_font}/stb_truetype.h (100%) create mode 100644 src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp create mode 100644 src/mirage_render/font/stb_truetype_font/stb_truetype_interface.h rename src/mirage_render/{ => image}/stb_image_loader/CMakeLists.txt (100%) rename src/mirage_render/{ => image}/stb_image_loader/stb_image.h (100%) rename src/mirage_render/{ => image}/stb_image_loader/stb_image_loader.cpp (100%) rename src/mirage_render/{ => image}/stb_image_loader/stb_image_loader.h (100%) create mode 100644 src/mirage_render/src/font/atlas/bitmap_glyph_atlas.cpp create mode 100644 src/mirage_render/src/font/atlas/color_emoji_atlas.cpp delete mode 100644 src/mirage_render/src/font/font_face.cpp delete mode 100644 src/mirage_render/src/font/font_face.h delete mode 100644 src/mirage_render/src/font/font_renderer/cbdt_renderer.cpp delete mode 100644 src/mirage_render/src/font/font_renderer/cbdt_renderer.h delete mode 100644 src/mirage_render/src/font/font_renderer/colr_renderer.cpp delete mode 100644 src/mirage_render/src/font/font_renderer/colr_renderer.h delete mode 100644 src/mirage_render/src/font/font_renderer/font_renderer.h delete mode 100644 src/mirage_render/src/font/font_renderer/sbix_renderer.cpp delete mode 100644 src/mirage_render/src/font/font_renderer/sbix_renderer.h delete mode 100644 src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.cpp delete mode 100644 src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.h delete mode 100644 src/mirage_render/src/font/font_renderer/svg_renderer.cpp delete mode 100644 src/mirage_render/src/font/font_renderer/svg_renderer.h create mode 100644 src/mirage_render/src/interface/font_interface.cpp create mode 100644 src/mirage_render/src/interface/font_interface.h diff --git a/.gitmodules b/.gitmodules index 9ac60b3..c571b32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "third_party/freetype"] - path = third_party/freetype +[submodule "src/mirage_render/font/freetype_font/freetype"] + path = src/mirage_render/font/freetype_font/freetype url = https://github.com/freetype/freetype -[submodule "third_party/harfbuzz"] - path = third_party/harfbuzz +[submodule "src/mirage_render/font/freetype_font/harfbuzz"] + path = src/mirage_render/font/freetype_font/harfbuzz url = https://github.com/harfbuzz/harfbuzz diff --git a/CMakeLists.txt b/CMakeLists.txt index 556586d..9e9f460 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,8 +50,6 @@ else () endif () add_subdirectory(src/sokol) -add_subdirectory(third_party/freetype) -add_subdirectory(third_party/harfbuzz) add_subdirectory(src/mirage_render) add_subdirectory(src/mirage_image) add_subdirectory(src/mirage_core) diff --git a/example/src/main.cpp b/example/src/main.cpp index 018a203..8210512 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -3,7 +3,6 @@ #include "mirage.h" #include "window/mwindow.h" #include "font/font_system.h" -#include "font/font_renderer/colr_renderer.h" #include "widget/widget_new.h" #include "widget/compound_widget/mbutton.h" #include "widget/leaf_widget/mtext_block.h" @@ -15,52 +14,6 @@ int main(int argc, char* argv[]) { mirage_app::get().init(); - FT_Library ft_library; - if (FT_Init_FreeType(&ft_library)) { - std::cerr << "Failed to initialize FreeType library" << std::endl; - return -1; - } - FT_Library_SetLcdFilter(ft_library, FT_LCD_FILTER_DEFAULT); - FT_Face ft_face; - if (FT_New_Face(ft_library, "C:/Windows/Fonts/msyh.ttc", 0, &ft_face)) { - std::cerr << "Failed to load font face" << std::endl; - return -1; - } - FT_Library_SetLcdFilterWeights(ft_library, nullptr); - FT_Library_SetLcdGeometry(ft_library, nullptr); - FT_Library_SetLcdFilter(ft_library, FT_LCD_FILTER_DEFAULT); - - // 渲染一个字符 - FT_Set_Pixel_Sizes(ft_face, 0, 24); - FT_Load_Char(ft_face, U'你', FT_LOAD_RENDER); - FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_LCD); - - // 获取渲染的位图 - FT_Bitmap bitmap = ft_face->glyph->bitmap; - if (bitmap.buffer) { - std::cout << "Bitmap width: " << bitmap.width << ", height: " << bitmap.rows << std::endl; - } else { - std::cerr << "Failed to get bitmap" << std::endl; - } - - // 保存位图到文件 - color_emoji_bitmap_t bitmap_; - // 将bitmap数据转换为color_emoji_bitmap_t格式 - bitmap_.width = bitmap.width; - bitmap_.height = bitmap.rows; - bitmap_.data.resize(bitmap.width * bitmap.rows * 4); // RGBA格式 - for (int y = 0; y < bitmap.rows; ++y) { - for (int x = 0; x < bitmap.width; ++x) { - int index = y * bitmap.width + x; - bitmap_.data[index * 4 + 0] = bitmap.buffer[index]; // R - bitmap_.data[index * 4 + 1] = bitmap.buffer[index]; // G - bitmap_.data[index * 4 + 2] = bitmap.buffer[index]; // B - bitmap_.data[index * 4 + 3] = bitmap.buffer[index]; // A - } - } - save_bitmap("output.bmp", bitmap_); - FT_Done_Face(ft_face); - auto& manager = font_manager::instance(); manager.add_font(L"C:/Users/46944/AppData/Local/Microsoft/Windows/Fonts/MapleMono-NF-CN-Regular.ttf"); manager.add_font(L"C:/Windows/Fonts/msyh.ttc"); diff --git a/src/mirage_app/mirage.cpp b/src/mirage_app/mirage.cpp index 5309a30..ff079f0 100644 --- a/src/mirage_app/mirage.cpp +++ b/src/mirage_app/mirage.cpp @@ -4,6 +4,7 @@ #include #include +#include "font/font_system.h" #include "window/mwindow.h" #include "misc/mirage_scoped_duration_timer.h" #include "platform_window/platform_window.h" @@ -91,4 +92,5 @@ void mirage_app::run() { texture_sampler_builder::clear(); render_context->cleanup(); delete render_context; + font_manager::instance().destroy(); } diff --git a/src/mirage_render/CMakeLists.txt b/src/mirage_render/CMakeLists.txt index 15151ea..9e2b615 100644 --- a/src/mirage_render/CMakeLists.txt +++ b/src/mirage_render/CMakeLists.txt @@ -1,12 +1,11 @@ project(mirage_render) - set(SOURCE_FILES) retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCE_FILES) add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core sokol freetype) +target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core sokol freetype mirage_image) option(MIRAGE_SVG_EMOJI "Use svg emoji" ON) if (MIRAGE_SVG_EMOJI) @@ -16,13 +15,27 @@ if (MIRAGE_SVG_EMOJI) target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_NANOSVG) endif () -option(MIRAGE_STB_IMAGE_LOADER "Use stb load image" ON) -if (MIRAGE_STB_IMAGE_LOADER) - add_subdirectory(stb_image_loader) +# 设置图像加载器 +set(MIRAGE_IMAGE_LOAD_BACKEND "STB_IMAGE" CACHE STRING "选择图像加载器") +set_property(CACHE MIRAGE_IMAGE_LOAD_BACKEND PROPERTY STRINGS "STB_IMAGE" "CUSTOM") +if (MIRAGE_IMAGE_LOAD_BACKEND STREQUAL "STB_IMAGE") + add_subdirectory(image/stb_image_loader) target_link_libraries(${PROJECT_NAME} PUBLIC stb_image_loader) target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_STB_IMAGE) endif () +# 设置字体后端 +set(MIRAGE_FONT_BACKEND "STB_TRUETYPE" CACHE STRING "选择字体后端") +set_property(CACHE MIRAGE_FONT_BACKEND PROPERTY STRINGS "STB_TRUETYPE" "FREETYPE" "CUSTOM") +if (MIRAGE_FONT_BACKEND STREQUAL "STB_TRUETYPE") + add_subdirectory(font/stb_truetype_font) + target_link_libraries(${PROJECT_NAME} PUBLIC stb_truetype_font) + target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_STB_TRUETYPE) +elseif (MIRAGE_FONT_BACKEND STREQUAL "FREETYPE") + add_subdirectory(font/freetype_font) + target_link_libraries(${PROJECT_NAME} PUBLIC freetype_font) + target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_FREETYPE) +endif () # 添加编译shader的自定义命令 add_mirage_shader_directory(${CMAKE_CURRENT_SOURCE_DIR}/shaders) diff --git a/src/mirage_render/font/freetype_font/CMakeLists.txt b/src/mirage_render/font/freetype_font/CMakeLists.txt new file mode 100644 index 0000000..46f07d8 --- /dev/null +++ b/src/mirage_render/font/freetype_font/CMakeLists.txt @@ -0,0 +1,10 @@ +project(freetype_font) + +add_subdirectory(freetype) +add_subdirectory(harfbuzz) + +set(SRC_FILES) +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_FILES) +add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) +target_link_libraries(${PROJECT_NAME} PUBLIC freetype harfbuzz mirage_render) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) diff --git a/third_party/freetype b/src/mirage_render/font/freetype_font/freetype similarity index 100% rename from third_party/freetype rename to src/mirage_render/font/freetype_font/freetype diff --git a/third_party/harfbuzz b/src/mirage_render/font/freetype_font/harfbuzz similarity index 100% rename from third_party/harfbuzz rename to src/mirage_render/font/freetype_font/harfbuzz diff --git a/src/mirage_render/font/freetype_font/src/freetype_interface.cpp b/src/mirage_render/font/freetype_font/src/freetype_interface.cpp new file mode 100644 index 0000000..f5dea2a --- /dev/null +++ b/src/mirage_render/font/freetype_font/src/freetype_interface.cpp @@ -0,0 +1,163 @@ +// +// Created by 46944 on 25-4-1. +// + +#include "freetype_interface.h" + +#include "freetype/ftglyph.h" +#include "interface/image_interface.h" + +FT_Library library_; + +void freetype_bitmap_deleter(image_heap_t* in_data) { + if (in_data == nullptr) { + return; + } + if (in_data->data != nullptr) { + const auto data = (uint8_t*)in_data->data; + delete[] data; + in_data->data = nullptr; + } + delete in_data; +} + +std::string freetype_interface::get_font_name() const { + if (face_ == nullptr) { + return "unknown font"; + } + return face_->family_name ? face_->family_name : "unknown font"; +} + +std::string freetype_interface::get_font_family() const { + if (face_ == nullptr) { + return "unknown font"; + } + return face_->family_name ? face_->family_name : "unknown font"; +} + +std::string freetype_interface::get_font_style() const { + if (face_ == nullptr) { + return "unknown font"; + } + return face_->style_name ? face_->style_name : "unknown font"; +} + +bool freetype_interface::supports_color_emoji() const { + return FT_HAS_COLOR(face_) || FT_HAS_SBIX(face_) || FT_HAS_SVG(face_); +} + +font_v_metrics_t freetype_interface::get_metrics() const { + font_v_metrics_t metrics{}; + metrics.ascent = face_->ascender; + metrics.descent = face_->descender; + metrics.line_gap = face_->height - (face_->ascender - face_->descender); + return metrics; +} + +std::shared_ptr freetype_interface::get_glyph_image(int32_t in_glyph_id) const { + if (in_glyph_id == 0) { + return nullptr; + } + + // 加载字形 + FT_Load_Glyph(face_, in_glyph_id, FT_LOAD_RENDER); + if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP) { + return nullptr; + } + + // 创建位图 + // 这里使用了一个自定义的删除器来释放位图数据 + std::shared_ptr image(new image_heap_t(), freetype_bitmap_deleter); + image->width = face_->glyph->bitmap.width; + image->height = face_->glyph->bitmap.rows; + image->pixel_format = SG_PIXELFORMAT_R8; + image->data = new uint8_t[image->width * image->height]; + std::memcpy(image->data, face_->glyph->bitmap.buffer, image->width * image->height); + + return image; +} + +std::shared_ptr freetype_interface::get_emoji_image(int32_t in_glyph_id) const { + if (in_glyph_id == 0) { + return nullptr; + } + + // 加载字形 + FT_Load_Glyph(face_, in_glyph_id, FT_LOAD_COLOR); + if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP) { + return nullptr; + } + + // 创建位图 + // 这里使用了一个自定义的删除器来释放位图数据 + std::shared_ptr image(new image_heap_t(), freetype_bitmap_deleter); + image->width = face_->glyph->bitmap.width; + image->height = face_->glyph->bitmap.rows; + image->pixel_format = SG_PIXELFORMAT_RGBA8; + image->data = new uint8_t[image->width * image->height * 4]; + std::memcpy(image->data, face_->glyph->bitmap.buffer, image->width * image->height); + return image; +} + +uint32_t freetype_interface::find_glyph_index(uint32_t in_unicode_codepoint) const { + return FT_Get_Char_Index(face_, in_unicode_codepoint); +} + +float freetype_interface::get_kerning(uint32_t in_first_glyph_id, uint32_t in_second_glyph_id) const { + FT_Vector kerning; + if (FT_Get_Kerning(face_, in_first_glyph_id, in_second_glyph_id, FT_KERNING_DEFAULT, &kerning) != 0) { + return 0.0f; + } + return static_cast(kerning.x) / 64.0f; // FreeType返回的单位是1/64像素 +} + +glyph_shaped_t freetype_interface::shape_glyph(uint32_t in_glyph_id) const { + glyph_shaped_t out{}; + + FT_Load_Glyph(face_, in_glyph_id, FT_LOAD_NO_BITMAP); + FT_Glyph glyph; + if (FT_Get_Glyph(face_->glyph, &glyph) != 0) { + return out; + } + FT_Done_Glyph(glyph); + + out.glyph_index = in_glyph_id; + out.advance.x() = static_cast(face_->glyph->advance.x) / 64.0f; + out.advance.y() = static_cast(face_->glyph->advance.y) / 64.0f; + out.offset.x() = static_cast(face_->glyph->metrics.horiBearingX) / 64.0f; + out.offset.y() = static_cast(face_->glyph->metrics.horiBearingY) / 64.0f; + out.rect.set_position({ static_cast(face_->glyph->metrics.horiBearingX), + static_cast(face_->glyph->metrics.horiBearingY) }); + out.rect.set_size({ static_cast(face_->glyph->metrics.width), + static_cast(face_->glyph->metrics.height) }); + + return out; +} + +bool freetype_interface::on_load() { + return FT_New_Memory_Face(library_, font_data_->get_u8(), font_data_->get_size(), 0, &face_) == 0; +} + +void freetype_interface::on_set_font_size(float in_size) { + font_face_interface::on_set_font_size(in_size); + FT_Set_Pixel_Sizes(face_, 0, static_cast(in_size)); +} + +bool init_font_system() { + if (FT_Init_FreeType(&library_)) { + return false; + } + return true; +} + +void destroy_font_system() { + FT_Done_FreeType(library_); +} + +std::shared_ptr create_font_face(const std::filesystem::path& in_path) { + auto font_face = std::make_shared(); + if (!font_face->load(in_path)) { + return nullptr; + } + return font_face; +} diff --git a/src/mirage_render/font/freetype_font/src/freetype_interface.h b/src/mirage_render/font/freetype_font/src/freetype_interface.h new file mode 100644 index 0000000..2c84e86 --- /dev/null +++ b/src/mirage_render/font/freetype_font/src/freetype_interface.h @@ -0,0 +1,23 @@ +#pragma once +#include "freetype/freetype.h" +#include "interface/font_interface.h" + +class freetype_interface : public font_face_interface { +public: + [[nodiscard]] std::string get_font_name() const override; + [[nodiscard]] std::string get_font_family() const override; + [[nodiscard]] std::string get_font_style() const override; + [[nodiscard]] bool supports_color_emoji() const override; + [[nodiscard]] font_v_metrics_t get_metrics() const override; + [[nodiscard]] std::shared_ptr get_glyph_image(int32_t in_glyph_id) const override; + [[nodiscard]] std::shared_ptr get_emoji_image(int32_t in_glyph_id) const override; + [[nodiscard]] uint32_t find_glyph_index(uint32_t in_unicode_codepoint) const override; + [[nodiscard]] float get_kerning(uint32_t in_first_glyph_id, uint32_t in_second_glyph_id) const override; + [[nodiscard]] glyph_shaped_t shape_glyph(uint32_t in_glyph_id) const override; + +protected: + bool on_load() override; + void on_set_font_size(float in_size) override; +protected: + FT_Face face_{}; +}; diff --git a/src/mirage_render/font/stb_truetype_font/CMakeLists.txt b/src/mirage_render/font/stb_truetype_font/CMakeLists.txt new file mode 100644 index 0000000..0ae95ae --- /dev/null +++ b/src/mirage_render/font/stb_truetype_font/CMakeLists.txt @@ -0,0 +1,8 @@ +project(stb_truetype_font) + +set(SRC_FILES) +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES) + +add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(${PROJECT_NAME} PUBLIC mirage_render) diff --git a/src/mirage_render/src/font/stb_truetype.h b/src/mirage_render/font/stb_truetype_font/stb_truetype.h similarity index 100% rename from src/mirage_render/src/font/stb_truetype.h rename to src/mirage_render/font/stb_truetype_font/stb_truetype.h diff --git a/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp new file mode 100644 index 0000000..061fccb --- /dev/null +++ b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp @@ -0,0 +1,212 @@ +#include "stb_truetype_interface.h" + +#include "font/font_utils.h" +#include "interface/image_interface.h" + +void stb_truetype_deleter(image_heap_t* in_data) { + if (in_data == nullptr) { + return; + } + if (in_data->data != nullptr) { + stbtt_FreeBitmap((uint8_t*)in_data->data, nullptr); + } + delete in_data; +} + +std::string stb_font_face_t::get_font_name() const { + const auto* data = static_cast(font_data_->get_data()); + const int font_offset = stbtt_GetFontOffsetForIndex(data, 0); + if (font_offset < 0) { + goto error; + } + + uint32_t name_offset = font::find_table_offset(data, font_offset, "name"); + if (name_offset == 0) { + goto error; + } + + const uint8_t* name_table = data + name_offset; + const uint16_t count = font::read_u16(name_table + 2); + const uint16_t string_offset = font::read_u16(name_table + 4); + + for (uint16_t i = 0; i < count; ++i) { + const uint8_t* record = name_table + 6 + 12 * i; + const uint16_t name_id = font::read_u16(record + 6); + if (name_id == 4 || name_id == 1) { + const uint16_t length = font::read_u16(record + 8); + const uint16_t offset = font::read_u16(record + 10); + if (length > 0) { + const uint8_t* string_data = name_table + string_offset + offset; + std::string name(reinterpret_cast(string_data), length); + return name; + } + } + } + +error: + return "unknown font"; +} + +std::string stb_font_face_t::get_font_family() const { + const auto* data = static_cast(font_data_->get_data()); + const int font_offset = stbtt_GetFontOffsetForIndex(data, 0); + if (font_offset < 0) { + goto error; + } + + uint32_t name_offset = font::find_table_offset(data, font_offset, "name"); + if (name_offset == 0) { + goto error; + } + + const uint8_t* name_table = data + name_offset; + const uint16_t count = font::read_u16(name_table + 2); + const uint16_t string_offset = font::read_u16(name_table + 4); + + for (uint16_t i = 0; i < count; ++i) { + const uint8_t* record = name_table + 6 + 12 * i; + const uint16_t name_id = font::read_u16(record + 6); + if (name_id == 1) { + const uint16_t length = font::read_u16(record + 8); + const uint16_t offset = font::read_u16(record + 10); + if (length > 0) { + const uint8_t* string_data = name_table + string_offset + offset; + std::string name(reinterpret_cast(string_data), length); + return name; + } + } + } +error: + return "unknown font"; +} + +std::string stb_font_face_t::get_font_style() const { + const auto* data = static_cast(font_data_->get_data()); + const int font_offset = stbtt_GetFontOffsetForIndex(data, 0); + if (font_offset < 0) { + goto error; + } + + uint32_t name_offset = font::find_table_offset(data, font_offset, "name"); + if (name_offset == 0) { + goto error; + } + + const uint8_t* name_table = data + name_offset; + const uint16_t count = font::read_u16(name_table + 2); + const uint16_t string_offset = font::read_u16(name_table + 4); + + for (uint16_t i = 0; i < count; ++i) { + const uint8_t* record = name_table + 6 + 12 * i; + const uint16_t name_id = font::read_u16(record + 6); + if (name_id == 2) { + const uint16_t length = font::read_u16(record + 8); + const uint16_t offset = font::read_u16(record + 10); + if (length > 0) { + const uint8_t* string_data = name_table + string_offset + offset; + std::string name(reinterpret_cast(string_data), length); + return name; + } + } + } +error: + return "unknown font"; +} + +bool stb_font_face_t::supports_color_emoji() const { + // stb_truetype不支持彩色表情符号 + return false; +} + +font_v_metrics_t stb_font_face_t::get_metrics() const { + int32_t ascent, descent, line_gap; + // 尝试使用OS2表中的度量,这通常更准确 + if (!stbtt_GetFontVMetricsOS2(&font_info_, &ascent, &descent, &line_gap)) { + // 如果失败,使用默认的VMetrics + stbtt_GetFontVMetrics(&font_info_, &ascent, &descent, &line_gap); + } + + font_v_metrics_t metrics{}; + metrics.ascent = static_cast(ascent) * scale_; + metrics.descent = static_cast(descent) * scale_; + metrics.line_gap = static_cast(line_gap) * scale_; + return metrics; +} + +std::shared_ptr stb_font_face_t::get_glyph_image(int32_t in_glyph_id) const { + if (in_glyph_id == 0) { + return nullptr; + } + + int32_t width, height, xoff, yoff; + + // 获取字形图像 + const auto bitmap = stbtt_GetGlyphBitmap(&font_info_, scale_, scale_, in_glyph_id, &width, &height, &xoff, &yoff); + + // 创建位图 + std::shared_ptr image(new image_heap_t(), stb_truetype_deleter); + image->width = width; + image->height = height; + image->pixel_format = SG_PIXELFORMAT_R8; + image->data = bitmap; + + return image; +} + +std::shared_ptr stb_font_face_t::get_emoji_image(int32_t in_glyph_id) const { + return nullptr; +} + +uint32_t stb_font_face_t::find_glyph_index(uint32_t in_unicode_codepoint) const { + return stbtt_FindGlyphIndex(&font_info_, in_unicode_codepoint); +} + +float stb_font_face_t::get_kerning(uint32_t in_first_glyph_id, uint32_t in_second_glyph_id) const { + return (float)stbtt_GetGlyphKernAdvance(&font_info_, in_first_glyph_id, in_second_glyph_id) * scale_; +} + +glyph_shaped_t stb_font_face_t::shape_glyph(uint32_t in_glyph_id) const { + int32_t advance, lsb; + stbtt_GetGlyphHMetrics(&font_info_, in_glyph_id, &advance, &lsb); + // 获取字形的边界框 + int32_t x0, y0, x1, y1; + stbtt_GetGlyphBox(&font_info_, in_glyph_id, &x0, &y0, &x1, &y1); + + glyph_shaped_t out; + out.glyph_index = in_glyph_id; + out.advance.x() = (float)advance * scale_; + out.advance.y() = 0.0f; + out.offset.x() = (float)lsb * scale_; + out.offset.y() = 0.0f; + out.rect.set_position({ x0, y0 }); + out.rect.set_size({ x1 - x0, y1 - y0 }); + + return out; +} + +bool stb_font_face_t::on_load() { + const auto offset = stbtt_GetFontOffsetForIndex(font_data_->get_u8(), 0); + return stbtt_InitFont(&font_info_, font_data_->get_u8(), offset) != 0; +} + +void stb_font_face_t::on_set_font_size(float in_size) { + font_face_interface::on_set_font_size(in_size); + scale_ = get_scale_for_pixel_height(in_size); +} + +bool init_font_system() { + // stb_truetype不需要初始化 + return true; +} + +void destroy_font_system() { + // stb_truetype不需要销毁 +} + +std::shared_ptr create_font_face(const std::filesystem::path& in_path) { + auto font_face = std::make_shared(); + if (!font_face->load(in_path)) { + return nullptr; + } + return font_face; +} diff --git a/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.h b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.h new file mode 100644 index 0000000..ee4c1d4 --- /dev/null +++ b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.h @@ -0,0 +1,28 @@ +#pragma once +#include "stb_truetype.h" +#include "interface/font_interface.h" + +class stb_font_face_t : public font_face_interface { +public: + [[nodiscard]] std::string get_font_name() const override; + [[nodiscard]] std::string get_font_family() const override; + [[nodiscard]] std::string get_font_style() const override; + + [[nodiscard]] bool supports_color_emoji() const override; + [[nodiscard]] font_v_metrics_t get_metrics() const override; + [[nodiscard]] std::shared_ptr get_glyph_image(int32_t in_glyph_id) const override; + [[nodiscard]] std::shared_ptr get_emoji_image(int32_t in_glyph_id) const override; + [[nodiscard]] uint32_t find_glyph_index(uint32_t in_unicode_codepoint) const override; + [[nodiscard]] float get_kerning(uint32_t in_first_glyph_id, uint32_t in_second_glyph_id) const override; + [[nodiscard]] glyph_shaped_t shape_glyph(uint32_t in_glyph_id) const override; + + [[nodiscard]] float get_scale_for_pixel_height(float font_size) const { + return stbtt_ScaleForPixelHeight(&font_info_, font_size); + } +protected: + bool on_load() override; + void on_set_font_size(float in_size) override; +protected: + stbtt_fontinfo font_info_{}; + float scale_{}; +}; diff --git a/src/mirage_render/stb_image_loader/CMakeLists.txt b/src/mirage_render/image/stb_image_loader/CMakeLists.txt similarity index 100% rename from src/mirage_render/stb_image_loader/CMakeLists.txt rename to src/mirage_render/image/stb_image_loader/CMakeLists.txt diff --git a/src/mirage_render/stb_image_loader/stb_image.h b/src/mirage_render/image/stb_image_loader/stb_image.h similarity index 100% rename from src/mirage_render/stb_image_loader/stb_image.h rename to src/mirage_render/image/stb_image_loader/stb_image.h diff --git a/src/mirage_render/stb_image_loader/stb_image_loader.cpp b/src/mirage_render/image/stb_image_loader/stb_image_loader.cpp similarity index 100% rename from src/mirage_render/stb_image_loader/stb_image_loader.cpp rename to src/mirage_render/image/stb_image_loader/stb_image_loader.cpp diff --git a/src/mirage_render/stb_image_loader/stb_image_loader.h b/src/mirage_render/image/stb_image_loader/stb_image_loader.h similarity index 100% rename from src/mirage_render/stb_image_loader/stb_image_loader.h rename to src/mirage_render/image/stb_image_loader/stb_image_loader.h diff --git a/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.cpp b/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.cpp new file mode 100644 index 0000000..dbef106 --- /dev/null +++ b/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.cpp @@ -0,0 +1,45 @@ +#include "bitmap_glyph_atlas.h" + +#include "interface/image_interface.h" + +glyph_atlas_result_t bitmap_glyph_atlas::get_or_create_glyph(int32_t in_glyph_index, + const std::shared_ptr& in_font, float in_font_size) { + + glyph_atlas_result_t result{}; + + // 创建缓存键 + const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_name(), in_font_size); + + // 检查缓存,如果已存在则直接返回 + auto cached_result = find_in_cache(cache_key); + if (cached_result.reason == glyph_atlas_reason_t::success) { + return cached_result; + } + + in_font->set_font_size(in_font_size); + + // 获取字形的位图数据 + auto bitmap = in_font->get_glyph_image(in_glyph_index); + if (!bitmap) { + result.reason = glyph_atlas_reason_t::glyph_not_found; + return result; + } + + // 从图集分配空间,添加2像素的padding防止纹理采样时的边缘混合问题 + auto region = atlas_->allocate_region(bitmap->get_size(), { 2, 2 }); + if (!region) { + result.reason = glyph_atlas_reason_t::atlas_full; + return result; + } + + // 更新图集,将位图数据上传到纹理 + atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect); + + // 缓存结果以便未来复用 + add_to_cache(cache_key, *region); + + result.reason = glyph_atlas_reason_t::success; + result.region = *region; + + return result; +} diff --git a/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.h b/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.h index 1321848..8e46b1b 100644 --- a/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.h +++ b/src/mirage_render/src/font/atlas/bitmap_glyph_atlas.h @@ -1,5 +1,6 @@ #pragma once #include "font_atlas.h" +#include "interface/font_interface.h" /** * @class bitmap_glyph_atlas @@ -32,60 +33,6 @@ public: */ glyph_atlas_result_t get_or_create_glyph( int32_t in_glyph_index, - const font_face_t& in_font, - float in_font_size) { - - glyph_atlas_result_t result{}; - - // 创建缓存键 - const auto& cache_key = create_cache_key(in_glyph_index, in_font.get_font_name(), in_font_size); - - // 检查缓存,如果已存在则直接返回 - auto cached_result = find_in_cache(cache_key); - if (cached_result.reason == glyph_atlas_reason_t::success) { - return cached_result; - } - - // 获取字形形状 - 使用指定字体大小 - auto glyph_shape = in_font.get_glyph_shape_by_index(in_glyph_index, in_font_size); - if (glyph_shape.empty()) { - result.reason = glyph_atlas_reason_t::glyph_not_found; - return result; - } - - // 使用stb_truetype生成位图 - float scale = in_font.get_scale_for_pixel_height(in_font_size); - int width, height, xoff, yoff; - auto bitmap = stbtt_GetGlyphBitmap(&in_font.get_font_info(), scale, scale, in_glyph_index, - &width, &height, &xoff, &yoff); - // stbtt_GetGlyphSDF(); - - if (!bitmap || width == 0 || height == 0) { - result.reason = glyph_atlas_reason_t::glyph_not_found; - if (bitmap) { - stbtt_FreeBitmap(bitmap, nullptr); - } - return result; - } - - // 从图集分配空间,添加2像素的padding防止纹理采样时的边缘混合问题 - auto region = atlas_->allocate_region({ width, height }, { 2, 2 }); - if (!region) { - stbtt_FreeBitmap(bitmap, nullptr); - result.reason = glyph_atlas_reason_t::atlas_full; - return result; - } - - // 更新图集,将位图数据上传到纹理 - atlas_->update_region(bitmap, width * height, region->rect); - stbtt_FreeBitmap(bitmap, nullptr); - - // 缓存结果以便未来复用 - add_to_cache(cache_key, *region); - - result.reason = glyph_atlas_reason_t::success; - result.region = *region; - - return result; - } + const std::shared_ptr& in_font, + float in_font_size); }; diff --git a/src/mirage_render/src/font/atlas/color_emoji_atlas.cpp b/src/mirage_render/src/font/atlas/color_emoji_atlas.cpp new file mode 100644 index 0000000..3169b3f --- /dev/null +++ b/src/mirage_render/src/font/atlas/color_emoji_atlas.cpp @@ -0,0 +1,44 @@ +#include "color_emoji_atlas.h" + +#include "interface/image_interface.h" + +glyph_atlas_result_t color_emoji_atlas::get_or_create_emoji(int32_t in_glyph_index, + const std::shared_ptr& in_font, float in_font_size) { + + glyph_atlas_result_t result{}; + + // 创建缓存键 + const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_name(), in_font_size); + + // 检查缓存 + auto cached_result = find_in_cache(cache_key); + if (cached_result.reason == glyph_atlas_reason_t::success) { + return cached_result; + } + + in_font->set_font_size(in_font_size); + + // 获取彩色表情位图 + auto bitmap = in_font->get_emoji_image(in_glyph_index); + if (!bitmap) { + result.reason = glyph_atlas_reason_t::glyph_not_found; + return result; + } + + // 从图集分配空间,添加2像素的padding防止纹理采样时的边缘混合问题 + const auto& region = atlas_->allocate_region(bitmap->get_size(), { 2, 2 }); + if (!region) { + result.reason = glyph_atlas_reason_t::atlas_full; + return result; + } + + // 更新图集,将位图数据上传到纹理 + atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect); + + // 缓存结果以便未来复用 + add_to_cache(cache_key, *region); + + result.reason = glyph_atlas_reason_t::success; + result.region = *region; + return result; +} diff --git a/src/mirage_render/src/font/atlas/color_emoji_atlas.h b/src/mirage_render/src/font/atlas/color_emoji_atlas.h index 0d24fb8..4aabc50 100644 --- a/src/mirage_render/src/font/atlas/color_emoji_atlas.h +++ b/src/mirage_render/src/font/atlas/color_emoji_atlas.h @@ -1,5 +1,6 @@ #pragma once #include "font_atlas.h" +#include "interface/font_interface.h" /** * @class color_emoji_atlas @@ -32,44 +33,6 @@ public: */ glyph_atlas_result_t get_or_create_emoji( int32_t in_glyph_index, - const font_face_t& in_font, - float in_font_size) { - - glyph_atlas_result_t result{}; - - // 创建缓存键 - const auto& cache_key = create_cache_key(in_glyph_index, in_font.get_font_name(), in_font_size); - - // 检查缓存 - auto cached_result = find_in_cache(cache_key); - if (cached_result.reason == glyph_atlas_reason_t::success) { - return cached_result; - } - - // 获取彩色表情位图 - auto bitmap_opt = in_font.get_color_emoji_bitmap(in_glyph_index, in_font_size); - if (!bitmap_opt) { - result.reason = glyph_atlas_reason_t::glyph_not_found; - return result; - } - - const auto& bitmap = *bitmap_opt; - - // 从图集分配空间,添加2像素的padding防止纹理采样时的边缘混合问题 - const auto& region = atlas_->allocate_region({ bitmap.width, bitmap.height }, { 2, 2 }); - if (!region) { - result.reason = glyph_atlas_reason_t::atlas_full; - return result; - } - - // 更新图集,将位图数据上传到纹理 - atlas_->update_region(bitmap.data.data(), bitmap.data.size(), region->rect); - - // 缓存结果以便未来复用 - add_to_cache(cache_key, *region); - - result.reason = glyph_atlas_reason_t::success; - result.region = *region; - return result; - } + const std::shared_ptr& in_font, + float in_font_size); }; diff --git a/src/mirage_render/src/font/atlas/font_atlas.h b/src/mirage_render/src/font/atlas/font_atlas.h index d967ff5..3e7f337 100644 --- a/src/mirage_render/src/font/atlas/font_atlas.h +++ b/src/mirage_render/src/font/atlas/font_atlas.h @@ -7,7 +7,6 @@ #include #include -#include "font/font_face.h" #include "texture/atlas/texture2d_atlas.h" /** diff --git a/src/mirage_render/src/font/atlas/font_atlas_manager.cpp b/src/mirage_render/src/font/atlas/font_atlas_manager.cpp index dd94700..91f26d0 100644 --- a/src/mirage_render/src/font/atlas/font_atlas_manager.cpp +++ b/src/mirage_render/src/font/atlas/font_atlas_manager.cpp @@ -2,16 +2,10 @@ std::optional font_atlas_manager::get_or_create_glyph( int32_t in_glyph_id, - const font_face_t& in_font, + const std::shared_ptr& in_font, float in_font_size, bool is_emoji) { - // 获取字形度量信息 - const auto& glyph = in_font.get_glyph_by_index(in_glyph_id, in_font_size); - if (!glyph) { - return std::nullopt; - } - glyph_atlas_result_t result{}; result.reason = glyph_atlas_reason_t::atlas_full; diff --git a/src/mirage_render/src/font/atlas/font_atlas_manager.h b/src/mirage_render/src/font/atlas/font_atlas_manager.h index 1928b01..0852a1a 100644 --- a/src/mirage_render/src/font/atlas/font_atlas_manager.h +++ b/src/mirage_render/src/font/atlas/font_atlas_manager.h @@ -1,12 +1,9 @@ #pragma once #include -#include #include -#include #include "bitmap_glyph_atlas.h" #include "color_emoji_atlas.h" -#include "font/font_face.h" /** * @class font_atlas_manager @@ -33,7 +30,7 @@ public: */ std::optional get_or_create_glyph( int32_t in_glyph_id, - const font_face_t& in_font, + const std::shared_ptr& in_font, float in_font_size, bool is_emoji); diff --git a/src/mirage_render/src/font/font_face.cpp b/src/mirage_render/src/font/font_face.cpp deleted file mode 100644 index 571839b..0000000 --- a/src/mirage_render/src/font/font_face.cpp +++ /dev/null @@ -1,371 +0,0 @@ -#include "font_face.h" - -#define STB_TRUETYPE_IMPLEMENTATION -#include "font_utils.h" -#include "font_renderer/cbdt_renderer.h" -#include "font_renderer/colr_renderer.h" -#include "font_renderer/sbix_renderer.h" -#include "font_renderer/standard_bitmap_renderer.h" -#include "font_renderer/svg_renderer.h" - -font_face_t::font_face_t() { - // 延迟初始化渲染器,直到加载字体 -} - -bool font_face_t::load_from_file(const std::filesystem::path& font_path) { - // 读取字体文件数据 - if (!load_font_data(font_path)) { - return false; - } - - const auto* font_data = static_cast(font_data_->get_data()); - - // 初始化stb_truetype - const auto offset = stbtt_GetFontOffsetForIndex(font_data, 0); - if (!stbtt_InitFont(&font_info_, font_data, offset)) { - return false; - } - - // 初始化渲染器 - init_renderers(); - - return true; -} - -font_v_metrics_t font_face_t::get_v_metrics() const { - font_v_metrics_t metrics; - // 尝试使用OS2表中的度量,这通常更准确 - if (!stbtt_GetFontVMetricsOS2(&font_info_, &metrics.ascent, &metrics.descent, &metrics.line_gap)) { - // 如果失败,使用默认的VMetrics - stbtt_GetFontVMetrics(&font_info_, &metrics.ascent, &metrics.descent, &metrics.line_gap); - } - return metrics; -} - -float font_face_t::get_scale_for_pixel_height(float font_size) const { - return stbtt_ScaleForPixelHeight(&font_info_, font_size); -} - -float font_face_t::get_line_height() const { - // 获取字体的行高 - const auto v_metrics = get_v_metrics(); - return static_cast(v_metrics.ascent - v_metrics.descent + v_metrics.line_gap); -} - -std::optional font_face_t::get_glyph(int32_t code_point, float font_size) const { - // 获取字形索引 - const auto glyph_index = find_glyph_index(code_point); - if (glyph_index == 0) { - return std::nullopt; // 缺失字形 - } - - return get_glyph_by_index(glyph_index, font_size); -} - -std::optional font_face_t::get_glyph_by_index(int32_t glyph_index, float font_size) const { - if (glyph_index == 0) { - return std::nullopt; // 无效字形索引 - } - - glyph_t glyph; - glyph.glyph_index = glyph_index; - - // 计算缩放比例 - const auto scale = get_scale_for_pixel_height(font_size); - - // 获取水平度量 - int advance, lsb; - stbtt_GetGlyphHMetrics(&font_info_, glyph_index, &advance, &lsb); - - // 获取字形边界 - int x0, y0, x1, y1; - stbtt_GetGlyphBitmapBox(&font_info_, glyph_index, scale, scale, &x0, &y0, &x1, &y1); - - // 设置字形数据 - glyph.rect.set_position({ x0, y0 }); - glyph.rect.set_size({ x1 - x0, y1 - y0 }); - glyph.lsb = static_cast(lsb) * scale; - glyph.advance = static_cast(advance) * scale; - - return glyph; -} - -int32_t font_face_t::find_glyph_index(int32_t code_point) const { - return stbtt_FindGlyphIndex(&font_info_, code_point); -} - -float font_face_t::get_glyph_advance(int32_t glyph_index1, int32_t glyph_index2) const { - return static_cast(stbtt_GetGlyphKernAdvance(&font_info_, glyph_index1, glyph_index2)); -} - -bool font_face_t::has_glyph(int32_t code_point) const { - return find_glyph_index(code_point) > 0; -} - -std::vector font_face_t::get_glyph_shape(int32_t code_point, float font_size) const { - // 获取字形索引 - const int glyph_index = find_glyph_index(code_point); - if (glyph_index == 0) { - return {}; // 缺失字形,返回空向量 - } - - return get_glyph_shape_by_index(glyph_index, font_size); -} - -std::vector font_face_t::get_glyph_shape_by_index(int32_t glyph_index, float font_size) const { - if (glyph_index == 0) { - return {}; // 无效字形索引 - } - - // 计算缩放比例 - const float scale = get_scale_for_pixel_height(font_size); - - // 获取原始字形轮廓 - stbtt_vertex* vertices; - const int num_vertices = stbtt_GetGlyphShape(&font_info_, glyph_index, &vertices); - - if (num_vertices <= 0 || vertices == nullptr) { - return {}; // 无轮廓或获取失败 - } - - // 复制顶点并应用缩放 - std::vector shape; - shape.reserve(num_vertices); - - for (int i = 0; i < num_vertices; i++) { - stbtt_vertex v = vertices[i]; - - // 对所有坐标应用缩放 - v.x *= scale; - v.y *= scale; - - // 处理不同类型的曲线控制点 - if (v.type == STBTT_vcurve) { - v.cx *= scale; - v.cy *= scale; - } else if (v.type == STBTT_vcubic) { - v.cx *= scale; - v.cy *= scale; - v.cx1 *= scale; - v.cy1 *= scale; - } - - shape.push_back(v); - } - - // 释放stb分配的内存 - stbtt_FreeShape(&font_info_, vertices); - - return shape; -} - -std::optional font_face_t::get_glyph_bitmap(int32_t glyph_index, float font_size) const { - if (!bitmap_renderer_ || glyph_index == 0) { - return std::nullopt; - } - - return bitmap_renderer_->render_bitmap(font_info_, glyph_index, font_size); -} - -std::optional font_face_t::get_glyph_bitmap_by_code_point(int32_t code_point, float font_size) const { - const auto glyph_index = find_glyph_index(code_point); - if (glyph_index == 0) { - return std::nullopt; - } - return get_glyph_bitmap(glyph_index, font_size); -} - -bool font_face_t::supports_color_emoji() const { - if (!font_data_ || !font_data_->get_data()) { - return false; - } - - const auto* font_data = static_cast(font_data_->get_data()); - const int font_offset = stbtt_GetFontOffsetForIndex(font_data, 0); - - if (font_offset < 0) { - return false; - } - - for (const auto& renderer : emoji_renderers_) { - if (renderer->supports_font(font_data, font_offset)) { - return true; - } - } - - return false; -} - -std::optional font_face_t::get_color_emoji_bitmap(int32_t glyph_index, float font_size) const { - if (glyph_index == 0 || emoji_renderers_.empty()) { - return std::nullopt; - } - - const auto* font_data = static_cast(font_data_->get_data()); - const int font_offset = stbtt_GetFontOffsetForIndex(font_data, 0); - - if (font_offset < 0) { - return std::nullopt; - } - - // 尝试每一个渲染器 - for (const auto& renderer : emoji_renderers_) { - if (renderer->supports_font(font_data, font_offset)) { - auto bitmap = renderer->render_emoji(font_info_, font_data, font_offset, glyph_index, font_size); - if (bitmap) { - return bitmap; - } - } - } - - return std::nullopt; -} - -std::optional font_face_t::get_color_emoji_bitmap_by_code_point(int32_t code_point, float font_size) const { - const auto glyph_index = find_glyph_index(code_point); - if (glyph_index == 0) { - return std::nullopt; - } - return get_color_emoji_bitmap(glyph_index, font_size); -} - -std::string font_face_t::get_font_name() const { - return font_name_; -} - -std::string font_face_t::get_font_type() const { - return font_type_; -} - -void font_face_t::set_font_type(const std::string& font_type) { - font_type_ = font_type; -} - -const stbtt_fontinfo& font_face_t::get_font_info() const { - return font_info_; -} - -void font_face_t::init_renderers() { - // 创建标准位图渲染器 - bitmap_renderer_ = std::make_unique(); - - // 创建彩色表情渲染器 -#ifdef HAS_STB_IMAGE - emoji_renderers_.push_back(std::make_unique()); -#endif - emoji_renderers_.push_back(std::make_unique()); - emoji_renderers_.push_back(std::make_unique()); -#ifdef HAS_NANOSVG - emoji_renderers_.push_back(std::make_unique()); -#endif -} - -bool font_face_t::load_font_data(const std::filesystem::path& font_path) { - // 创建内存映射文件 - font_data_ = mapped_file::create(); - if (!font_data_ || !font_data_->map_file(font_path)) { - return false; - } - - if (font_data_->get_size() == 0) { - return false; - } - - // 提取字体名称 - extract_font_name(); - - return true; -} - -void font_face_t::extract_font_name() { - // 默认名称 - font_name_ = "Unknown Font"; - - if (!font_data_ || !font_data_->get_data() || font_data_->get_size() == 0) { - return; - } - - const auto* data = static_cast(font_data_->get_data()); - const int font_offset = stbtt_GetFontOffsetForIndex(data, 0); - - if (font_offset < 0) { - return; - } - - // 查找名称表 - uint32_t name_offset = font::find_table_offset(data, font_offset, "name"); - if (name_offset == 0) { - return; - } - - // 解析名称表 - const uint8_t* name_table = data + name_offset; - const uint16_t count = font::read_u16(name_table + 2); - const uint16_t string_offset = font::read_u16(name_table + 4); - - // 字体名称优先级: 完整名称(4) > 字体族(1) - std::string family_name; - - for (uint16_t i = 0; i < count; ++i) { - const uint8_t* record = name_table + 6 + 12 * i; - const uint16_t platform_id = font::read_u16(record); - const uint16_t encoding_id = font::read_u16(record + 2); - const uint16_t language_id = font::read_u16(record + 4); - const uint16_t name_id = font::read_u16(record + 6); - const uint16_t length = font::read_u16(record + 8); - const uint16_t offset = font::read_u16(record + 10); - - // 是否为英语或首选语言 - const bool is_english = (platform_id == 3 && language_id == 0x0409); // Windows 英语 (US) - - if ((name_id == 4 || name_id == 1) && length > 0) { - const uint8_t* string_data = name_table + string_offset + offset; - std::string name; - - // 处理不同平台的编码 - if (platform_id == 3) { // Windows Unicode (UTF-16BE) - // 简单的UTF-16BE转UTF-8 - for (uint16_t j = 0; j < length; j += 2) { - if (j + 1 < length) { - const uint16_t unicode = (string_data[j] << 8) | string_data[j + 1]; - - if (unicode < 0x80) { - name.push_back(static_cast(unicode)); - } else if (unicode < 0x800) { - name.push_back(static_cast(0xC0 | ((unicode >> 6) & 0x1F))); - name.push_back(static_cast(0x80 | (unicode & 0x3F))); - } else { - name.push_back(static_cast(0xE0 | ((unicode >> 12) & 0x0F))); - name.push_back(static_cast(0x80 | ((unicode >> 6) & 0x3F))); - name.push_back(static_cast(0x80 | (unicode & 0x3F))); - } - } - } - } else { // 假设为ASCII或其他单字节编码 - name = std::string(reinterpret_cast(string_data), length); - } - - if (!name.empty()) { - // 根据name_id和语言更新字体名称 - if (name_id == 4) { // 完整名称 - if (is_english) { - // 找到英语的完整名称,优先使用 - font_name_ = name; - return; - } else if (font_name_ == "Unknown Font") { - // 如果还没有设置名称,使用非英语完整名称 - font_name_ = name; - } - } else if (name_id == 1 && family_name.empty()) { // 字体族 - // 保存字体族名称作为备选 - family_name = name; - } - } - } - } - - // 如果没有找到完整名称,但有字体族名称,则使用字体族 - if (font_name_ == "Unknown Font" && !family_name.empty()) { - font_name_ = family_name; - } -} diff --git a/src/mirage_render/src/font/font_face.h b/src/mirage_render/src/font/font_face.h deleted file mode 100644 index a2d0ff1..0000000 --- a/src/mirage_render/src/font/font_face.h +++ /dev/null @@ -1,242 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#include "font_type.h" -#include "stb_truetype.h" -#include "misc/mapped_file/mapped_file.h" -#include "font_renderer/font_renderer.h" -#include - -/** - * @class font_face_t - * @brief 字体面对象,封装单个字体文件的加载和渲染功能 - * - * 提供对TrueType/OpenType字体的访问,支持标准字形渲染和彩色表情符号。 - */ -class font_face_t { -public: - /** - * @brief 默认构造函数 - */ - font_face_t(); - - /** - * @brief 析构函数 - */ - ~font_face_t() = default; - - /** - * @brief 禁用拷贝构造和赋值操作 - */ - font_face_t(const font_face_t&) = delete; - font_face_t& operator=(const font_face_t&) = delete; - - //-------------------------------------------------------------------------- - // 字体加载与初始化 - //-------------------------------------------------------------------------- - - /** - * @brief 从文件加载字体 - * @param font_path 字体文件路径 - * @return 是否成功加载 - */ - bool load_from_file(const std::filesystem::path& font_path); - - //-------------------------------------------------------------------------- - // 字体度量信息 - //-------------------------------------------------------------------------- - - /** - * @brief 获取字体上升高度(baseline以上的高度) - * @return 上升高度值 - */ - font_v_metrics_t get_v_metrics() const; - - /** - * @brief 获取特定像素高度的缩放因子 - * @param font_size 目标字体大小(像素) - * @return 缩放因子 - */ - float get_scale_for_pixel_height(float font_size) const; - - /** - * @brief 获取字体的行高 - * @return 行高值 - */ - [[nodiscard]] float get_line_height() const; - - //-------------------------------------------------------------------------- - // 字形信息查询 - //-------------------------------------------------------------------------- - - /** - * @brief 通过Unicode码点获取字形信息 - * @param code_point Unicode码点 - * @param font_size 字体大小(像素) - * @return 可选的字形信息,不存在时返回空 - */ - [[nodiscard]] std::optional get_glyph(int32_t code_point, float font_size) const; - - /** - * @brief 通过字形索引获取字形信息 - * @param glyph_index 字形索引 - * @param font_size 字体大小(像素) - * @return 可选的字形信息,不存在时返回空 - */ - [[nodiscard]] std::optional get_glyph_by_index(int32_t glyph_index, float font_size) const; - - /** - * @brief 查找码点对应的字形索引 - * @param code_point Unicode码点 - * @return 字形索引,0表示未找到 - */ - int32_t find_glyph_index(int32_t code_point) const; - - /** - * @brief 获取两个相邻字形之间的间距调整值 - * @param glyph_index1 第一个字形索引 - * @param glyph_index2 第二个字形索引 - * @return 间距调整值 - */ - float get_glyph_advance(int32_t glyph_index1, int32_t glyph_index2) const; - - /** - * @brief 检查字体是否包含指定码点的字形 - * @param code_point Unicode码点 - * @return 是否包含该字形 - */ - [[nodiscard]] bool has_glyph(int32_t code_point) const; - - //-------------------------------------------------------------------------- - // 字形轮廓提取 - //-------------------------------------------------------------------------- - - /** - * @brief 通过Unicode码点获取字形轮廓 - * @param code_point Unicode码点 - * @param font_size 字体大小(像素) - * @return 字形轮廓顶点集合 - */ - [[nodiscard]] std::vector get_glyph_shape(int32_t code_point, float font_size) const; - - /** - * @brief 通过字形索引获取字形轮廓 - * @param glyph_index 字形索引 - * @param font_size 字体大小(像素) - * @return 字形轮廓顶点集合 - */ - [[nodiscard]] std::vector get_glyph_shape_by_index(int32_t glyph_index, float font_size) const; - - //-------------------------------------------------------------------------- - // 位图渲染 - //-------------------------------------------------------------------------- - - /** - * @brief 获取字形的灰度位图 - * @param glyph_index 字形索引 - * @param font_size 字体大小(像素) - * @return 灰度位图,渲染失败返回空 - */ - [[nodiscard]] std::optional get_glyph_bitmap(int32_t glyph_index, float font_size) const; - - /** - * @brief 通过Unicode码点获取字形的灰度位图 - * @param code_point Unicode码点 - * @param font_size 字体大小(像素) - * @return 灰度位图,渲染失败返回空 - */ - [[nodiscard]] std::optional get_glyph_bitmap_by_code_point(int32_t code_point, float font_size) const; - - //-------------------------------------------------------------------------- - // 彩色表情符号支持 - //-------------------------------------------------------------------------- - - /** - * @brief 检查字体是否支持彩色表情符号 - * @return 是否支持彩色表情 - */ - [[nodiscard]] bool supports_color_emoji() const; - - /** - * @brief 获取彩色表情符号位图 - * @param glyph_index 字形索引 - * @param font_size 字体大小(像素) - * @return 可选的彩色位图,不支持时返回空 - */ - [[nodiscard]] std::optional get_color_emoji_bitmap(int32_t glyph_index, float font_size) const; - - /** - * @brief 通过Unicode码点获取彩色表情符号位图 - * @param code_point Unicode码点 - * @param font_size 字体大小(像素) - * @return 可选的彩色位图,不支持时返回空 - */ - [[nodiscard]] std::optional get_color_emoji_bitmap_by_code_point(int32_t code_point, float font_size) const; - - //-------------------------------------------------------------------------- - // 字体元数据 - //-------------------------------------------------------------------------- - - /** - * @brief 获取字体名称 - * @return 字体名称 - */ - [[nodiscard]] std::string get_font_name() const; - - /** - * @brief 获取字体类型(如regular, bold, italic等) - * @return 字体类型 - */ - [[nodiscard]] std::string get_font_type() const; - - /** - * @brief 设置字体类型 - * @param font_type 字体类型 - */ - void set_font_type(const std::string& font_type); - - /** - * @brief 获取底层stb_truetype字体信息 - * @return 字体信息结构引用 - */ - const stbtt_fontinfo& get_font_info() const; - -private: - //-------------------------------------------------------------------------- - // 内部数据成员 - //-------------------------------------------------------------------------- - - stbtt_fontinfo font_info_{}; // stb_truetype字体信息 - std::shared_ptr font_data_; // 字体文件映射数据 - std::string font_name_ = "Unknown"; // 字体名称 - std::string font_type_ = "regular"; // 字体类型 - - // 渲染器 - std::unique_ptr bitmap_renderer_; // 位图渲染器 - std::vector> emoji_renderers_; // 表情渲染器集合 - - //-------------------------------------------------------------------------- - // 内部辅助方法 - //-------------------------------------------------------------------------- - - /** - * @brief 加载字体文件数据 - * @param font_path 字体文件路径 - * @return 是否成功 - */ - bool load_font_data(const std::filesystem::path& font_path); - - /** - * @brief 从字体数据中提取字体名称 - */ - void extract_font_name(); - - /** - * @brief 初始化渲染器 - */ - void init_renderers(); -}; diff --git a/src/mirage_render/src/font/font_renderer/cbdt_renderer.cpp b/src/mirage_render/src/font/font_renderer/cbdt_renderer.cpp deleted file mode 100644 index 0e8fd95..0000000 --- a/src/mirage_render/src/font/font_renderer/cbdt_renderer.cpp +++ /dev/null @@ -1,295 +0,0 @@ -#include "cbdt_renderer.h" -#include -#include - -bool cbdt_renderer_t::supports_font(const uint8_t* font_data, int font_offset) const { - // 检查CBDT和CBLC表是否同时存在 - return font::find_table_offset(font_data, font_offset, "CBDT") != 0 && - font::find_table_offset(font_data, font_offset, "CBLC") != 0; -} - -std::optional cbdt_renderer_t::render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const { - - // 检查参数有效性 - if (glyph_index == 0 || font_size <= 0.0f) { - return std::nullopt; - } - - // 查找CBDT和CBLC表 - const uint32_t cbdt_offset = font::find_table_offset(font_data, font_offset, "CBDT"); - const uint32_t cblc_offset = font::find_table_offset(font_data, font_offset, "CBLC"); - - if (cbdt_offset == 0 || cblc_offset == 0) { - return std::nullopt; - } - - const uint8_t* cbdt_data = font_data + cbdt_offset; - const uint8_t* cblc_data = font_data + cblc_offset; - - // 查找字形位图 - auto bitmap_loc = find_bitmap(cblc_data, cbdt_data, glyph_index, font_size); - if (!bitmap_loc) { - return std::nullopt; - } - - // 解码位图数据 - return decode_bitmap(*bitmap_loc); -} - -std::optional cbdt_renderer_t::find_bitmap( - const uint8_t* cblc_data, - const uint8_t* cbdt_data, - int32_t glyph_index, - float target_size) const { - - // 解析CBLC表头部 - // 2字节:majorVersion - // 2字节:minorVersion - // 4字节:numSizes(bitmapSize数量) - const uint16_t major_version = font::read_u16(cblc_data); - const uint16_t minor_version = font::read_u16(cblc_data + 2); - const uint32_t num_sizes = font::read_u32(cblc_data + 4); - - if (num_sizes == 0) { - return std::nullopt; - } - - // 找到最佳匹配的bitmapSize(位图尺寸) - uint32_t best_size_index = 0; - uint16_t best_ppem = 0; - uint16_t target_ppem = static_cast(target_size); - - // bitmapSize数组 - const uint8_t* bitmapSize_array = cblc_data + 8; - - // 遍历所有bitmapSize,找到最接近目标尺寸的一个 - for (uint32_t i = 0; i < num_sizes; i++) { - const uint8_t* size_table = bitmapSize_array + i * 48; // 每个bitmapSize表48字节 - - // 读取当前bitmapSize的ppem(像素每em) - const uint16_t ppem_x = font::read_u16(size_table); - const uint16_t ppem_y = font::read_u16(size_table + 2); - const uint16_t ppem = std::max(ppem_x, ppem_y); // 通常两者相等 - - // 找到最接近的尺寸 - if (best_ppem == 0 || - (ppem >= target_ppem && ppem < best_ppem) || - (best_ppem < target_ppem && ppem > best_ppem)) { - best_ppem = ppem; - best_size_index = i; - } - } - - // 获取选中的bitmapSize数据 - const uint8_t* size_table = bitmapSize_array + best_size_index * 48; - - // 读取indexSubTableArray偏移和数量 - const uint32_t index_subtable_array_offset = font::read_u32(size_table + 8); - const uint32_t num_index_subtables = font::read_u32(size_table + 12); - - // 访问indexSubTableArray - const uint8_t* index_subtable_array = cblc_data + index_subtable_array_offset; - - // 查找包含目标字形的索引子表 - for (uint32_t i = 0; i < num_index_subtables; i++) { - const uint8_t* subtable_entry = index_subtable_array + i * 8; - - // 读取firstGlyphIndex和lastGlyphIndex - const uint16_t first_glyph = font::read_u16(subtable_entry); - const uint16_t last_glyph = font::read_u16(subtable_entry + 2); - - // 检查字形索引是否在范围内 - if (glyph_index >= first_glyph && glyph_index <= last_glyph) { - // 找到了包含目标字形的子表 - const uint32_t subtable_offset = font::read_u32(subtable_entry + 4); - const uint8_t* index_subtable = cblc_data + subtable_offset; - - // 读取索引子表头部 - const uint16_t index_format = font::read_u16(index_subtable); - const uint16_t image_format = font::read_u16(index_subtable + 2); - const uint32_t image_data_offset = font::read_u32(index_subtable + 4); - - // 根据索引格式查找位图数据 - uint32_t bitmap_offset = 0; - uint32_t bitmap_length = 0; - - // 处理不同的索引格式 - if (index_format == 1) { - // 格式1:只有一个字形范围,所有字形共享相同的位图度量 - const uint8_t* sbit_line = index_subtable + 8; - bitmap_offset = font::read_u32(sbit_line) + image_data_offset; - bitmap_length = font::read_u32(sbit_line + 4); - } else if (index_format == 2) { - // 格式2:图像大小相同,但每个字形有不同的位图 - const uint16_t image_size = font::read_u32(index_subtable + 8); - const uint32_t glyph_offset = (glyph_index - first_glyph) * image_size; - bitmap_offset = image_data_offset + glyph_offset; - bitmap_length = image_size; - } else if (index_format == 3) { - // 格式3:每个字形有偏移数组 - const uint16_t glyph_array_offset = 16 + (glyph_index - first_glyph) * 4; - bitmap_offset = font::read_u32(index_subtable + glyph_array_offset) + image_data_offset; - - // 下一个字形的偏移或表的结束位置确定长度 - uint32_t next_offset; - if (glyph_index < last_glyph) { - next_offset = font::read_u32(index_subtable + glyph_array_offset + 4) + image_data_offset; - } else { - // 估计最后一个字形的长度 - next_offset = bitmap_offset + 1024; // 假设最大长度 - } - bitmap_length = next_offset - bitmap_offset; - } else if (index_format == 4 || index_format == 5) { - // 格式4和5:更复杂的索引方式,这里简化实现 - // 实际情况中需要根据具体字体完善 - continue; - } - - // 如果找到了位图偏移 - if (bitmap_offset > 0) { - // 访问CBDT表中的位图数据 - const uint8_t* bitmap_data = cbdt_data + bitmap_offset; - - // 创建位图位置信息 - bitmap_location_t location; - - // 根据图像格式解析度量信息 - if (image_format == 17) { - // 小字形位图格式 (SmallGlyphMetrics) - const uint8_t height = font::read_u8(bitmap_data); - const uint8_t width = font::read_u8(bitmap_data + 1); - const int8_t bearing_x = font::read_i8(bitmap_data + 2); - const int8_t bearing_y = font::read_i8(bitmap_data + 3); - const uint8_t advance = font::read_u8(bitmap_data + 4); - - location.data = bitmap_data + 5; // 跳过SmallGlyphMetrics - location.data_format = image_format; - location.size = bitmap_length - 5; - location.width = width; - location.height = height; - location.bearing_x = bearing_x; - location.bearing_y = bearing_y; - location.bits_per_pixel = 32; // RGBA 8888 - - return location; - } - if (image_format == 18) { - // 大字形位图格式 (BigGlyphMetrics) - const uint8_t height = font::read_u8(bitmap_data); - const uint8_t width = font::read_u8(bitmap_data + 1); - const int8_t horiBearingX = font::read_i8(bitmap_data + 2); - const int8_t horiBearingY = font::read_i8(bitmap_data + 3); - const uint8_t horiAdvance = font::read_u8(bitmap_data + 4); - const int8_t vertBearingX = font::read_i8(bitmap_data + 5); - const int8_t vertBearingY = font::read_i8(bitmap_data + 6); - const uint8_t vertAdvance = font::read_u8(bitmap_data + 7); - - location.data = bitmap_data + 8; // 跳过BigGlyphMetrics - location.data_format = image_format; - location.size = bitmap_length - 8; - location.width = width; - location.height = height; - location.bearing_x = horiBearingX; - location.bearing_y = horiBearingY; - location.bits_per_pixel = 32; // RGBA 8888 - - return location; - } - if (image_format == 19) { - // 格式19:含调色板的位图 - const uint8_t height = font::read_u8(bitmap_data); - const uint8_t width = font::read_u8(bitmap_data + 1); - const int8_t bearing_x = font::read_i8(bitmap_data + 2); - const int8_t bearing_y = font::read_i8(bitmap_data + 3); - const uint8_t advance = font::read_u8(bitmap_data + 4); - - location.data = bitmap_data; // 包含完整头部 - location.data_format = image_format; - location.size = bitmap_length; - location.width = width; - location.height = height; - location.bearing_x = bearing_x; - location.bearing_y = bearing_y; - location.bits_per_pixel = 8; // 调色板索引 - - return location; - } - } - } - } - - // 未找到匹配的位图 - return std::nullopt; -} - -std::optional cbdt_renderer_t::decode_bitmap( - const bitmap_location_t& location) const { - - if (!location.data || location.size == 0) { - return std::nullopt; - } - - // 创建位图结构 - color_emoji_bitmap_t bitmap; - bitmap.width = location.width; - bitmap.height = location.height; - bitmap.x_offset = location.bearing_x; - bitmap.y_offset = location.bearing_y; - bitmap.data.resize(location.width * location.height * 4, 0); - - // 根据不同的格式解码位图 - if (location.data_format == 17 || location.data_format == 18) { - // 格式17/18: 直接RGBA位图 - if (location.size >= location.width * location.height * 4) { - std::memcpy(bitmap.data.data(), location.data, location.width * location.height * 4); - } else { - return std::nullopt; // 数据大小不足 - } - } else if (location.data_format == 19) { - // 格式19: 带调色板的位图 - const uint8_t* data = location.data; - - // 跳过SmallGlyphMetrics (5字节) - data += 5; - - const uint8_t num_palette_entries = font::read_u8(data); - const uint8_t color_ref_type = font::read_u8(data + 1); - - // 调色板数据 - const uint8_t* palette = data + 2; - - // 位图数据在调色板之后 - const uint8_t* image_data = palette + num_palette_entries * 4; - - // 如果是调色板索引格式 - if (color_ref_type == 1) { - for (uint16_t y = 0; y < location.height; y++) { - for (uint16_t x = 0; x < location.width; x++) { - const uint8_t index = image_data[y * location.width + x]; - if (index < num_palette_entries) { - const uint8_t* color = palette + index * 4; - const uint32_t pixel_offset = (y * location.width + x) * 4; - - bitmap.data[pixel_offset] = color[0]; // R - bitmap.data[pixel_offset + 1] = color[1]; // G - bitmap.data[pixel_offset + 2] = color[2]; // B - bitmap.data[pixel_offset + 3] = color[3]; // A - } - } - } - } else { - // 直接颜色格式 (不常见) - return std::nullopt; - } - } else { - // 不支持的格式 - return std::nullopt; - } - - return bitmap; -} diff --git a/src/mirage_render/src/font/font_renderer/cbdt_renderer.h b/src/mirage_render/src/font/font_renderer/cbdt_renderer.h deleted file mode 100644 index 28a525f..0000000 --- a/src/mirage_render/src/font/font_renderer/cbdt_renderer.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once -#include "font_renderer.h" -#include "font/font_utils.h" - -/** - * @class cbdt_renderer_t - * @brief 基于CBDT/CBLC表的彩色表情渲染器 - * - * 实现了Google CBDT/CBLC彩色字体格式的渲染,主要用于Android彩色表情 - * CBDT表存储位图数据,CBLC表存储位图位置信息 - */ -class cbdt_renderer_t : public color_emoji_renderer_t { -public: - /** - * @brief 检查字体是否支持CBDT/CBLC表 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @return 是否支持 - */ - bool supports_font(const uint8_t* font_data, int font_offset) const override; - - /** - * @brief 渲染CBDT/CBLC彩色表情 - * @param font_info 字体信息 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 彩色位图数据 - */ - std::optional render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const override; - -private: - /** - * @brief 存储位图数据的位置和信息 - */ - struct bitmap_location_t { - const uint8_t* data = nullptr; // 位图数据起点 - uint32_t data_format = 0; // 数据格式 - uint32_t size = 0; // 数据大小 - uint16_t width = 0; // 位图宽度 - uint16_t height = 0; // 位图高度 - int16_t bearing_x = 0; // 水平原点偏移 - int16_t bearing_y = 0; // 垂直原点偏移 - uint8_t bits_per_pixel = 0; // 像素位深 - }; - - /** - * @brief 在CBLC/CBDT表中查找字形位图 - * @param cblc_data CBLC表数据 - * @param cbdt_data CBDT表数据 - * @param glyph_index 字形索引 - * @param target_size 目标尺寸 - * @return 位图位置信息 - */ - std::optional find_bitmap( - const uint8_t* cblc_data, - const uint8_t* cbdt_data, - int32_t glyph_index, - float target_size) const; - - /** - * @brief 解码CBDT格式位图 - * @param location 位图位置信息 - * @return 解码后的RGBA位图 - */ - std::optional decode_bitmap(const bitmap_location_t& location) const; -}; diff --git a/src/mirage_render/src/font/font_renderer/colr_renderer.cpp b/src/mirage_render/src/font/font_renderer/colr_renderer.cpp deleted file mode 100644 index 1544365..0000000 --- a/src/mirage_render/src/font/font_renderer/colr_renderer.cpp +++ /dev/null @@ -1,351 +0,0 @@ -#include "colr_renderer.h" - -#include - -#include "font/font_utils.h" -#include "font/stb_truetype.h" - -bool colr_renderer_t::supports_font(const uint8_t* font_data, int font_offset) const { - return font::find_table_offset(font_data, font_offset, "COLR") != 0 && - font::find_table_offset(font_data, font_offset, "CPAL") != 0; -} - -void save_bitmap(const std::string& filename, const color_emoji_bitmap_t& bitmap) { - // 检查输入有效性 - if (bitmap.width <= 0 || bitmap.height <= 0 || bitmap.data.empty()) { - throw std::invalid_argument("Invalid bitmap data"); - } - - if (bitmap.data.size() < static_cast(bitmap.width * bitmap.height * 4)) { - throw std::invalid_argument("Bitmap data size doesn't match dimensions"); - } - - #pragma pack(push, 1) - // BMP文件头结构 - struct BITMAPFILEHEADER { - uint16_t bfType; // 文件类型,必须是"BM"(0x4D42) - uint32_t bfSize; // 文件大小 - uint16_t bfReserved1; // 保留,必须为0 - uint16_t bfReserved2; // 保留,必须为0 - uint32_t bfOffBits; // 从文件开始到像素数据的偏移量 - }; - - // BMP V4信息头结构,**支持Alpha通道** - struct BITMAPV4HEADER { - uint32_t biSize; // 信息头大小 - int32_t biWidth; // 图像宽度 - int32_t biHeight; // 图像高度 - uint16_t biPlanes; // 颜色平面数,必须为1 - uint16_t biBitCount; // 每个像素的位数 - uint32_t biCompression; // 压缩方式 - uint32_t biSizeImage; // 图像大小 - int32_t biXPelsPerMeter; // 水平分辨率 - int32_t biYPelsPerMeter; // 垂直分辨率 - uint32_t biClrUsed; // 使用的颜色索引数 - uint32_t biClrImportant; // 重要的颜色索引数 - uint32_t bV4RedMask; // 红色掩码 - uint32_t bV4GreenMask; // 绿色掩码 - uint32_t bV4BlueMask; // 蓝色掩码 - uint32_t bV4AlphaMask; // Alpha掩码 - uint32_t bV4CSType; // 颜色空间类型 - uint8_t bV4Endpoints[36]; // 端点 - uint32_t bV4GammaRed; // 红色Gamma - uint32_t bV4GammaGreen; // 绿色Gamma - uint32_t bV4GammaBlue; // 蓝色Gamma - }; - #pragma pack(pop) - - // 常量定义 - const uint32_t BI_BITFIELDS = 3; // 位域压缩 - const uint16_t BMP_SIGNATURE = 0x4D42; // "BM" - - // 计算文件大小 - int rowSize = ((bitmap.width * 32 + 31) / 32) * 4; // 每行字节数(必须是4的倍数) - int dataSize = rowSize * bitmap.height; - int fileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV4HEADER) + dataSize; - - // 准备文件头 - BITMAPFILEHEADER fileHeader = {0}; - fileHeader.bfType = BMP_SIGNATURE; - fileHeader.bfSize = fileSize; - fileHeader.bfReserved1 = 0; - fileHeader.bfReserved2 = 0; - fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV4HEADER); - - // 准备信息头 - BITMAPV4HEADER infoHeader = {0}; - infoHeader.biSize = sizeof(BITMAPV4HEADER); - infoHeader.biWidth = bitmap.width; - infoHeader.biHeight = bitmap.height; // **正值表示图像从下到上存储** - infoHeader.biPlanes = 1; - infoHeader.biBitCount = 32; // 32位每像素(BGRA) - infoHeader.biCompression = BI_BITFIELDS; - infoHeader.biSizeImage = dataSize; - infoHeader.biXPelsPerMeter = 0; - infoHeader.biYPelsPerMeter = 0; - infoHeader.biClrUsed = 0; - infoHeader.biClrImportant = 0; - infoHeader.bV4RedMask = 0x00FF0000; // R在第3字节 - infoHeader.bV4GreenMask = 0x0000FF00; // G在第2字节 - infoHeader.bV4BlueMask = 0x000000FF; // B在第1字节 - infoHeader.bV4AlphaMask = 0xFF000000; // A在第4字节 - infoHeader.bV4CSType = 0; // LCS_CALIBRATED_RGB - - // 打开文件 - std::ofstream file(filename, std::ios::binary); - if (!file) { - throw std::runtime_error("Failed to open file for writing: " + filename); - } - - // 写入文件头 - file.write(reinterpret_cast(&fileHeader), sizeof(fileHeader)); - - // 写入信息头 - file.write(reinterpret_cast(&infoHeader), sizeof(infoHeader)); - - // 转换并写入像素数据 - // **BMP存储顺序是从下到上,从左到右,且是BGRA而不是RGBA** - std::vector bmpData(dataSize, 0); // 初始化为0 - - for (int y = 0; y < bitmap.height; y++) { - for (int x = 0; x < bitmap.width; x++) { - // 计算源数据和目标数据的索引 - size_t srcIndex = (y * bitmap.width + x) * 4; // RGBA - size_t destIndex = ((bitmap.height - 1 - y) * rowSize) + (x * 4); // BGRA, 从下到上 - - // RGBA -> BGRA - bmpData[destIndex + 0] = bitmap.data[srcIndex + 2]; // B <- R - bmpData[destIndex + 1] = bitmap.data[srcIndex + 1]; // G <- G - bmpData[destIndex + 2] = bitmap.data[srcIndex + 0]; // R <- B - bmpData[destIndex + 3] = bitmap.data[srcIndex + 3]; // A <- A - } - } - - // 写入像素数据 - file.write(reinterpret_cast(bmpData.data()), dataSize); - - if (!file.good()) { - throw std::runtime_error("Error occurred while writing to file: " + filename); - } -} - -std::optional colr_renderer_t::render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const { - - if (glyph_index == 0) { - return std::nullopt; - } - - // 查找COLR和CPAL表 - const uint32_t colr_offset = font::find_table_offset(font_data, font_offset, "COLR"); - const uint32_t cpal_offset = font::find_table_offset(font_data, font_offset, "CPAL"); - - if (colr_offset == 0 || cpal_offset == 0) { - return std::nullopt; - } - - const uint8_t* colr_data = font_data + colr_offset; - const uint8_t* cpal_data = font_data + cpal_offset; - - // 解析COLR表 - const uint16_t colr_version = font::read_u16(colr_data); - const uint16_t num_base_glyphs = font::read_u16(colr_data + 2); - const uint32_t base_glyph_records_offset = font::read_u32(colr_data + 4); - const uint32_t layer_records_offset = font::read_u32(colr_data + 8); - const uint16_t num_layers = font::read_u16(colr_data + 12); - - // 查找基本字形记录 - const uint8_t* base_records = colr_data + base_glyph_records_offset; - int target_record_index = -1; - - for (uint16_t i = 0; i < num_base_glyphs; i++) { - const uint8_t* record = base_records + i * 6; - const uint16_t base_glyph_id = font::read_u16(record); - - if (base_glyph_id == glyph_index) { - target_record_index = i; - break; - } - } - - if (target_record_index == -1) { - return std::nullopt; // 未找到目标字形 - } - - // 获取图层信息 - const uint8_t* target_record = base_records + target_record_index * 6; - const uint16_t first_layer_index = font::read_u16(target_record + 2); - const uint16_t num_layers_for_glyph = font::read_u16(target_record + 4); - - // 检查图层数量 - if (num_layers_for_glyph == 0 || first_layer_index + num_layers_for_glyph > num_layers) { - return std::nullopt; // 无效的图层配置 - } - - // 解析CPAL表 - 为Windows字体特别处理 - const uint16_t cpal_version = font::read_u16(cpal_data); - const uint16_t num_palette_entries = font::read_u16(cpal_data + 2); - const uint16_t num_palettes = font::read_u16(cpal_data + 4); - const uint32_t color_records_offset = font::read_u32(cpal_data + 8); - - // Windows字体可能有类型选择器字段 - uint16_t color_record_indices_offset = 12; - if (cpal_version > 0 && cpal_data + 12 < font_data + font_offset + color_records_offset) { - color_record_indices_offset = 14; // 调整CPAL格式偏移 - } - - // 使用第一个调色板 - const uint8_t* palette_indices = cpal_data + color_record_indices_offset; - uint16_t first_color_index = 0; - if (num_palettes > 0) { - first_color_index = font::read_u16(palette_indices); - } - - // 计算缩放比例 - const float scale = stbtt_ScaleForPixelHeight(&font_info, font_size); - - // 获取字形边界框 - int x0, y0, x1, y1; - stbtt_GetGlyphBitmapBox(&font_info, glyph_index, scale, scale, &x0, &y0, &x1, &y1); - - // 创建位图结构 - color_emoji_bitmap_t bitmap; - bitmap.width = x1 - x0; - bitmap.height = y1 - y0; - - // 确保位图尺寸有效 - Windows字体可能需要额外的填充 - if (bitmap.width <= 0 || bitmap.height <= 0) { - bitmap.width = static_cast(font_size * 1.2); // 添加额外空间 - bitmap.height = static_cast(font_size * 1.2); - x0 = 0; - y0 = 0; - } - - // 初始化RGBA位图数据 - bitmap.data.resize(bitmap.width * bitmap.height * 4, 0); - - // 渲染每一个图层 - Windows Segoe UI Emoji特别处理 - const uint8_t* layer_records = colr_data + layer_records_offset; - const uint8_t* color_records = cpal_data + color_records_offset; - - // 处理Microsoft特有的图层顺序 - for (uint16_t i = 0; i < num_layers_for_glyph; i++) { - const uint8_t* layer = layer_records + (first_layer_index + i) * 4; - const uint16_t layer_glyph_id = font::read_u16(layer); - const uint16_t palette_entry_index = font::read_u16(layer + 2); - - // 确保层索引有效 - if (palette_entry_index >= num_palette_entries) { - continue; - } - - // 获取颜色 - Windows字体可能有不同的颜色格式 - const uint16_t color_index = first_color_index + palette_entry_index; - if (color_index >= num_palette_entries) { - continue; - } - - const uint8_t* color = color_records + color_index * 4; - // Windows字体通常使用BGRA顺序 - const uint8_t blue = color[0]; - const uint8_t green = color[1]; - const uint8_t red = color[2]; - const uint8_t alpha = color[3]; - - // Windows字体可能会对特定颜色设置特殊意义 - // 如果alpha为0,微软通常将其视为"不透明黑色" - const uint8_t effective_alpha = (alpha == 0 && (red > 0 || green > 0 || blue > 0)) - ? 255 : alpha; - - // 为图层创建临时位图 - int layer_x0, layer_y0, layer_x1, layer_y1; - stbtt_GetGlyphBitmapBox(&font_info, layer_glyph_id, scale, scale, - &layer_x0, &layer_y0, &layer_x1, &layer_y1); - - const int layer_width = layer_x1 - layer_x0; - const int layer_height = layer_y1 - layer_y0; - - if (layer_width <= 0 || layer_height <= 0) { - continue; - } - - // 渲染图层字形的灰度位图 - std::vector layer_bitmap(layer_width * layer_height, 0); - - // 使用更高精度的渲染方法 - 关键是对细节(如眼睛)的处理 - stbtt_MakeGlyphBitmap(&font_info, layer_bitmap.data(), - layer_width, layer_height, layer_width, - scale, scale, layer_glyph_id); - - // 测试,保存BMP - save_bitmap(std::to_string(i) + ".bmp", bitmap); - - - // 计算图层在最终位图中的位置 - const int offset_x = layer_x0 - x0; - const int offset_y = layer_y0 - y0; - - // 将图层与颜色混合到最终位图 - Windows样式混合 - for (int y = 0; y < layer_height; y++) { - const int dst_y = offset_y + y; - if (dst_y < 0 || dst_y >= bitmap.height) { - continue; - } - - for (int x = 0; x < layer_width; x++) { - const int dst_x = offset_x + x; - if (dst_x < 0 || dst_x >= bitmap.width) { - continue; - } - - const uint8_t coverage = layer_bitmap[y * layer_width + x]; - if (coverage == 0) { - continue; - } - - const int dst_idx = (dst_y * bitmap.width + dst_x) * 4; - - // Windows风格的Alpha混合 - 这对眼睛等小细节很重要 - const float src_alpha = (coverage / 255.0f) * (effective_alpha / 255.0f); - - // 对于细节图层(如眼睛),增强其影响 - float enhanced_alpha = src_alpha; - // if (palette_entry_index > 0 && src_alpha > 0) { // 非底色图层且有透明度 - // enhanced_alpha = std::min(src_alpha * 1.2f, 1.0f); // 稍微增强 - // } - - const float dst_alpha = bitmap.data[dst_idx + 3] / 255.0f; - const float out_alpha = enhanced_alpha + dst_alpha * (1.0f - enhanced_alpha); - - if (out_alpha > 0) { - // 特别处理黑色或暗色像素,这通常是眼睛等细节 - if (red <= 64 && green <= 64 && blue <= 64 && enhanced_alpha > 0.2f) { - // 增强黑色细节的可见度 - bitmap.data[dst_idx + 0] = red; - bitmap.data[dst_idx + 1] = green; - bitmap.data[dst_idx + 2] = blue; - bitmap.data[dst_idx + 3] = static_cast(enhanced_alpha * 255.0f); - } else { - // 标准混合 - const float src_factor = enhanced_alpha / out_alpha; - const float dst_factor = dst_alpha * (1.0f - enhanced_alpha) / out_alpha; - - bitmap.data[dst_idx + 0] = static_cast( - std::min(255.0f, red * src_factor + bitmap.data[dst_idx + 0] * dst_factor)); - bitmap.data[dst_idx + 1] = static_cast( - std::min(255.0f, green * src_factor + bitmap.data[dst_idx + 1] * dst_factor)); - bitmap.data[dst_idx + 2] = static_cast( - std::min(255.0f, blue * src_factor + bitmap.data[dst_idx + 2] * dst_factor)); - bitmap.data[dst_idx + 3] = static_cast(out_alpha * 255.0f); - } - } - } - } - } - - return bitmap; -} diff --git a/src/mirage_render/src/font/font_renderer/colr_renderer.h b/src/mirage_render/src/font/font_renderer/colr_renderer.h deleted file mode 100644 index c2899f5..0000000 --- a/src/mirage_render/src/font/font_renderer/colr_renderer.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "font_renderer.h" -#include "font/stb_truetype.h" - -void save_bitmap(const std::string& filename, const color_emoji_bitmap_t& bitmap); - -/** - * @class colr_renderer_t - * @brief 基于COLR/CPAL表的彩色表情渲染器 - * - * 实现了Microsoft COLR/CPAL彩色字体格式的渲染 - */ -class colr_renderer_t : public color_emoji_renderer_t { -public: - /** - * @brief 检查字体是否支持COLR/CPAL表 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @return 是否支持 - */ - bool supports_font(const uint8_t* font_data, int font_offset) const override; - - /** - * @brief 渲染COLR/CPAL彩色表情 - * @param font_info 字体信息 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 彩色位图数据 - */ - std::optional render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const override; -}; diff --git a/src/mirage_render/src/font/font_renderer/font_renderer.h b/src/mirage_render/src/font/font_renderer/font_renderer.h deleted file mode 100644 index 7658cbe..0000000 --- a/src/mirage_render/src/font/font_renderer/font_renderer.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include -#include -#include -#include "font/font_type.h" -#include "font/stb_truetype.h" - -/** - * @struct bitmap_t - * @brief 表示灰度位图 - */ -struct bitmap_t { - int width = 0; // 位图宽度 - int height = 0; // 位图高度 - int bearing_x = 0; // 水平位置 - int bearing_y = 0; // 垂直位置 - std::vector data; // 灰度数据,每个像素1字节 -}; - -/** - * @class bitmap_renderer_t - * @brief 字体位图渲染器的基础接口 - */ -class bitmap_renderer_t { -public: - virtual ~bitmap_renderer_t() = default; - - /** - * @brief 渲染普通灰度位图 - * @param font_info 字体信息 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 位图数据,如果渲染失败返回空 - */ - virtual std::optional render_bitmap( - const stbtt_fontinfo& font_info, - int32_t glyph_index, - float font_size) const = 0; -}; - -/** - * @class color_emoji_renderer_t - * @brief 彩色表情位图渲染器的基础接口 - */ -class color_emoji_renderer_t { -public: - virtual ~color_emoji_renderer_t() = default; - - /** - * @brief 检查渲染器是否可以处理给定的字体 - * @param font_data 字体数据 - * @param font_offset 字体偏移量 - * @return 是否支持该字体 - */ - virtual bool supports_font(const uint8_t* font_data, int font_offset) const = 0; - - /** - * @brief 渲染彩色表情位图 - * @param font_info 字体信息 - * @param font_data 字体数据 - * @param font_offset 字体偏移量 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 彩色位图数据,如果渲染失败返回空 - */ - virtual std::optional render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const = 0; -}; diff --git a/src/mirage_render/src/font/font_renderer/sbix_renderer.cpp b/src/mirage_render/src/font/font_renderer/sbix_renderer.cpp deleted file mode 100644 index 599f9f1..0000000 --- a/src/mirage_render/src/font/font_renderer/sbix_renderer.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include "sbix_renderer.h" -#ifdef HAS_STB_IMAGE -#include - -#include "stb_image.h" -#include "font/font_utils.h" - -bool sbix_renderer_t::supports_font(const uint8_t* font_data, int font_offset) const { - // 检查是否存在sbix表 - return font::find_table_offset(font_data, font_offset, "sbix") != 0; -} - -std::optional sbix_renderer_t::render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const { - - // 检查参数有效性 - if (glyph_index == 0 || font_size <= 0.0f) { - return std::nullopt; - } - - // 查找sbix表 - const uint32_t sbix_offset = font::find_table_offset(font_data, font_offset, "sbix"); - if (sbix_offset == 0) { - return std::nullopt; - } - - const uint8_t* sbix_data = font_data + sbix_offset; - - // 查找最佳尺寸的位图 - auto bitmap_loc = find_best_bitmap(font_info, sbix_data, glyph_index, font_size); - if (!bitmap_loc) { - return std::nullopt; - } - - // 目前只支持PNG格式 - // sbix表中的graphic_type是4字节标记,通常为'png ' - if (bitmap_loc->graphic_type != 0x706E6720) { // 'png '的大端字节值 - return std::nullopt; - } - - // 解码PNG格式的位图 - auto bitmap = decode_png(bitmap_loc->data, bitmap_loc->size); - if (!bitmap) { - return std::nullopt; - } - - // 记录位图的原点偏移(可用于定位) - bitmap->x_offset = bitmap_loc->x_offset; - bitmap->y_offset = bitmap_loc->y_offset; - - return bitmap; -} - -std::optional sbix_renderer_t::find_best_bitmap( - const stbtt_fontinfo& font_info, - const uint8_t* sbix_data, - int32_t glyph_index, - float target_size) const { - - // 解析sbix表头部 - // 2字节:version - // 2字节:flags - // 4字节:numStrikes(trike数量,每个strike对应一个像素尺寸) - // 变长:strike偏移数组 - - const uint16_t version = font::read_u16(sbix_data); - const uint16_t flags = font::read_u16(sbix_data + 2); - const uint32_t num_strikes = font::read_u32(sbix_data + 4); - - if (num_strikes == 0) { - return std::nullopt; - } - - // 找到最佳匹配的strike(位图尺寸) - // 每一个strike包含一组相同尺寸的位图 - uint32_t best_strike_index = 0; - uint16_t best_ppem = 0; - uint16_t target_ppem = static_cast(target_size); - - // strike偏移数组 - const uint8_t* strike_offset_array = sbix_data + 8; - - // 遍历所有strike,找到最接近目标尺寸的strike - for (uint32_t i = 0; i < num_strikes; i++) { - const uint32_t strike_offset = font::read_u32(strike_offset_array + i * 4); - const uint8_t* strike_data = sbix_data + strike_offset; - - // 读取当前strike的ppem(像素每em) - const uint16_t ppem = font::read_u16(strike_data); - - // 找到最接近的尺寸 - if (best_ppem == 0 || - (ppem >= target_ppem && ppem < best_ppem) || - (best_ppem < target_ppem && ppem > best_ppem)) { - best_ppem = ppem; - best_strike_index = i; - } - } - - // 获取选中的strike数据 - const uint32_t strike_offset = font::read_u32(strike_offset_array + best_strike_index * 4); - const uint8_t* strike_data = sbix_data + strike_offset; - - // 读取strike头部 - // 2字节:ppem - // 2字节:ppi(每英寸像素数) - // 变长:glyphOffset数组(每个字形对应一个偏移) - - // 获取当前字体的最大字形ID - int num_glyphs = 0; - stbtt_GetFontBoundingBox(&font_info, nullptr, nullptr, nullptr, nullptr); // 确保已初始化 - if (font_info.numGlyphs > 0) { - num_glyphs = font_info.numGlyphs; - } else { - // 如果stbtt_fontinfo中没有,尝试从maxp表获取 - const uint32_t maxp_offset = font::find_table_offset( - reinterpret_cast(font_info.data), - 0, "maxp"); - if (maxp_offset) { - num_glyphs = font::read_u16(reinterpret_cast(font_info.data) + maxp_offset + 4); - } - - if (num_glyphs <= 0) { - return std::nullopt; // 无法确定字形数量 - } - } - - // 检查字形索引是否有效 - if (glyph_index >= num_glyphs) { - return std::nullopt; - } - - // 字形偏移数组 - const uint8_t* glyph_offset_array = strike_data + 4; - - // 获取当前字形的数据偏移和下一个字形的数据偏移 - const uint32_t glyph_offset = font::read_u32(glyph_offset_array + glyph_index * 4); - uint32_t next_glyph_offset; - - if (glyph_index + 1 < num_glyphs) { - next_glyph_offset = font::read_u32(glyph_offset_array + (glyph_index + 1) * 4); - } else { - // 如果是最后一个字形,使用strike的总大小作为边界 - const uint32_t next_strike_offset = (best_strike_index + 1 < num_strikes) ? - font::read_u32(strike_offset_array + (best_strike_index + 1) * 4) : - font::find_table_offset(reinterpret_cast(font_info.data), 0, "sbix") + font::read_u32(reinterpret_cast(font_info.data) + font::find_table_offset(reinterpret_cast(font_info.data), 0, "sbix") + 8); - - next_glyph_offset = next_strike_offset - strike_offset; - } - - // 如果当前字形没有位图数据或偏移无效 - if (glyph_offset >= next_glyph_offset || glyph_offset == 0) { - return std::nullopt; - } - - // 访问字形数据 - const uint8_t* glyph_data = strike_data + glyph_offset; - - // sbix字形记录格式: - // 2字节:originOffsetX(水平原点偏移) - // 2字节:originOffsetY(垂直原点偏移) - // 4字节:graphicType(图像格式,如'png ') - // 变长:图像数据 - - const int16_t x_offset = font::read_i16(glyph_data); - const int16_t y_offset = font::read_i16(glyph_data + 2); - const uint32_t graphic_type = font::read_u32(glyph_data + 4); - - // 计算位图数据大小 - const uint32_t bitmap_size = next_glyph_offset - glyph_offset - 8; - - // 返回位图位置信息 - bitmap_location_t location; - location.data = glyph_data + 8; // 跳过头部 - location.size = bitmap_size; - location.graphic_type = graphic_type; - location.x_offset = x_offset; - location.y_offset = y_offset; - - return location; -} - -std::optional sbix_renderer_t::decode_png( - const uint8_t* data, - size_t data_size) const { - - if (!data || data_size == 0) { - return std::nullopt; - } - - // 使用stb_image解码PNG数据 - int width, height, channels; - unsigned char* decoded = stbi_load_from_memory( - data, static_cast(data_size), - &width, &height, &channels, 4); // 强制转换为RGBA - - if (!decoded) { - return std::nullopt; - } - - // 创建并填充位图结构 - color_emoji_bitmap_t bitmap; - bitmap.width = width; - bitmap.height = height; - bitmap.data.resize(width * height * 4); - - // 复制解码后的数据 - std::memcpy(bitmap.data.data(), decoded, width * height * 4); - - // 释放stb_image分配的内存 - stbi_image_free(decoded); - - return bitmap; -} - -#endif diff --git a/src/mirage_render/src/font/font_renderer/sbix_renderer.h b/src/mirage_render/src/font/font_renderer/sbix_renderer.h deleted file mode 100644 index d903f08..0000000 --- a/src/mirage_render/src/font/font_renderer/sbix_renderer.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "font_renderer.h" - -#ifdef HAS_STB_IMAGE - -/** - * @class sbix_renderer_t - * @brief 基于sbix表的彩色表情渲染器 - * - * 实现了Apple sbix彩色字体格式的渲染,主要用于Apple Color Emoji字体 - * sbix表存储预渲染的位图表情,通常是PNG格式图像 - */ -class sbix_renderer_t : public color_emoji_renderer_t { -public: - /** - * @brief 检查字体是否支持sbix表 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @return 是否支持 - */ - bool supports_font(const uint8_t* font_data, int font_offset) const override; - - /** - * @brief 渲染sbix彩色表情 - * @param font_info 字体信息 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 彩色位图数据 - */ - std::optional render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const override; - -private: - /** - * @brief 存储位图数据的位置和信息 - */ - struct bitmap_location_t { - const uint8_t* data = nullptr; // 位图数据起点 - uint32_t size = 0; // 数据大小 - uint32_t graphic_type = 0; // 数据格式 (如 'png ') - int16_t x_offset = 0; // 水平原点偏移 - int16_t y_offset = 0; // 垂直原点偏移 - }; - - /** - * @brief 在sbix表中查找最适合的位图 - * @param sbix_data sbix表数据 - * @param glyph_index 字形索引 - * @param target_size 目标尺寸 - * @return 位图位置信息 - */ - std::optional find_best_bitmap( - const stbtt_fontinfo& font_info, - const uint8_t* sbix_data, - int32_t glyph_index, - float target_size) const; - - /** - * @brief 解码PNG格式位图 - * @param data PNG数据 - * @param data_size 数据大小 - * @return 解码后的RGBA位图 - */ - std::optional decode_png( - const uint8_t* data, - size_t data_size) const; -}; - -#endif \ No newline at end of file diff --git a/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.cpp b/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.cpp deleted file mode 100644 index 0e93cdc..0000000 --- a/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "standard_bitmap_renderer.h" - -std::optional standard_bitmap_renderer_t::render_bitmap( - const stbtt_fontinfo& font_info, - int32_t glyph_index, - float font_size) const { - - if (glyph_index == 0) { - return std::nullopt; - } - - // 计算缩放比例 - const float scale = stbtt_ScaleForPixelHeight(&font_info, font_size); - - // 获取字形边界 - int x0, y0, x1, y1; - stbtt_GetGlyphBitmapBoxSubpixel(&font_info, - glyph_index, - scale, scale, - 0.5f, 0, - &x0, &y0, &x1, &y1); - - const int width = x1 - x0; - const int height = y1 - y0; - - // 确保位图尺寸有效 - if (width <= 0 || height <= 0) { - return std::nullopt; - } - - // 创建位图结构 - bitmap_t bitmap; - bitmap.width = width; - bitmap.height = height; - bitmap.bearing_x = x0; - bitmap.bearing_y = y0; - bitmap.data.resize(width * height); - - // 渲染字形 - stbtt_MakeGlyphBitmapSubpixel( - &font_info, - bitmap.data.data(), - width, height, width, - scale, scale, - 0.5f, 0, - glyph_index - ); - - return bitmap; -} diff --git a/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.h b/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.h deleted file mode 100644 index 7de4a5e..0000000 --- a/src/mirage_render/src/font/font_renderer/standard_bitmap_renderer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "font_renderer.h" - -/** - * @class standard_bitmap_renderer_t - * @brief 使用stb_truetype实现的标准灰度位图渲染器 - */ -class standard_bitmap_renderer_t : public bitmap_renderer_t { -public: - /** - * @brief 渲染灰度位图 - * @param font_info 字体信息 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 位图数据,如果渲染失败返回空 - */ - std::optional render_bitmap( - const stbtt_fontinfo& font_info, - int32_t glyph_index, - float font_size) const override; -}; diff --git a/src/mirage_render/src/font/font_renderer/svg_renderer.cpp b/src/mirage_render/src/font/font_renderer/svg_renderer.cpp deleted file mode 100644 index aafddbb..0000000 --- a/src/mirage_render/src/font/font_renderer/svg_renderer.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "svg_renderer.h" - -#ifdef HAS_NANOSVG - -#include -#include // 用于解压缩SVGZ - -// 使用NanoSVG作为SVG解析和渲染器 -#define NANOSVG_IMPLEMENTATION -#include "nanosvg.h" -#define NANOSVGRAST_IMPLEMENTATION -#include "nanosvgrast.h" - -svg_renderer_t::svg_renderer_t() { - // 初始化任何需要的资源 -} - -svg_renderer_t::~svg_renderer_t() { - // 清理资源 -} - -bool svg_renderer_t::supports_font(const uint8_t* font_data, int font_offset) const { - // 检查字体是否包含SVG表 - return font::find_table_offset(font_data, font_offset, "SVG ") != 0; -} - -std::optional svg_renderer_t::render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const { - - // 验证参数 - if (glyph_index == 0 || font_size <= 0.0f) { - return std::nullopt; - } - - // 使用stb_truetype提供的API获取SVG数据 - const char* svg_data = nullptr; - int result = stbtt_GetGlyphSVG(&font_info, glyph_index, &svg_data); - - if (result == 0 || svg_data == nullptr) { - return std::nullopt; // 没有找到SVG数据 - } - - // 计算渲染尺寸 - const float scale = stbtt_ScaleForPixelHeight(&font_info, font_size); - int x0, y0, x1, y1; - stbtt_GetGlyphBitmapBox(&font_info, glyph_index, scale, scale, &x0, &y0, &x1, &y1); - - int width = x1 - x0; - int height = y1 - y0; - - // 确保尺寸有效 - if (width <= 0 || height <= 0) { - width = static_cast(font_size); - height = static_cast(font_size); - } - - // 渲染SVG为位图 - return render_svg_to_bitmap(svg_data, width, height); -} - -std::optional svg_renderer_t::render_svg_to_bitmap( - const char* svg_data, - int width, - int height) const { - - if (!svg_data || width <= 0 || height <= 0) { - return std::nullopt; - } - - // 检查是否是SVGZ (gzip压缩的SVG) - const uint8_t* data_bytes = reinterpret_cast(svg_data); - bool is_compressed = data_bytes[0] == 0x1F && data_bytes[1] == 0x8B; - - // 准备SVG字符串 - std::string svg_str; - - if (is_compressed) { - // 获取压缩数据的长度(近似值,因为stbtt_GetGlyphSVG不返回长度) - size_t compressed_size = 0; - while (data_bytes[compressed_size]) { - compressed_size++; - // 安全检查,防止无限循环 - if (compressed_size > 10 * 1024 * 1024) { // 10MB限制 - return std::nullopt; - } - } - - // 解压缩SVGZ - z_stream zs = {0}; - if (inflateInit2(&zs, 15 + 32) != Z_OK) { - return std::nullopt; - } - - // 设置输入 - zs.avail_in = static_cast(compressed_size); - zs.next_in = const_cast(data_bytes); - - // 准备输出缓冲区 - const size_t buffer_size = 16384; - char buffer[buffer_size]; - - // 解压缩循环 - int ret; - do { - zs.avail_out = buffer_size; - zs.next_out = reinterpret_cast(buffer); - - ret = inflate(&zs, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) { - inflateEnd(&zs); - return std::nullopt; - } - - svg_str.append(buffer, buffer_size - zs.avail_out); - } while (zs.avail_out == 0); - - inflateEnd(&zs); - } else { - // 直接使用未压缩的SVG数据 - svg_str = svg_data; - } - - // 使用NanoSVG解析SVG - NSVGimage* svg_image = nsvgParse(const_cast(svg_str.c_str()), "px", 96.0f); - if (!svg_image) { - return std::nullopt; - } - - // 创建栅格化器 - NSVGrasterizer* rast = nsvgCreateRasterizer(); - if (!rast) { - nsvgDelete(svg_image); - return std::nullopt; - } - - // 创建位图结构 - color_emoji_bitmap_t bitmap; - bitmap.width = width; - bitmap.height = height; - bitmap.data.resize(width * height * 4, 0); - - // 栅格化SVG到位图 - float scale_factor = std::min( - static_cast(width) / svg_image->width, - static_cast(height) / svg_image->height - ); - - nsvgRasterize( - rast, - svg_image, - 0, 0, - scale_factor, - bitmap.data.data(), - width, height, - width * 4 - ); - - // 清理资源 - nsvgDeleteRasterizer(rast); - nsvgDelete(svg_image); - - return bitmap; -} - -#endif \ No newline at end of file diff --git a/src/mirage_render/src/font/font_renderer/svg_renderer.h b/src/mirage_render/src/font/font_renderer/svg_renderer.h deleted file mode 100644 index c9a9a6b..0000000 --- a/src/mirage_render/src/font/font_renderer/svg_renderer.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include "font_renderer.h" -#include "font/font_utils.h" -#include - -#ifdef HAS_NANOSVG - -/** - * @class svg_renderer_t - * @brief 基于SVG表的彩色表情渲染器,使用stb_truetype提供的SVG接口 - * - * 实现了OpenType SVG彩色字体格式的渲染 - * SVG表存储矢量图形表情,支持无损缩放 - */ -class svg_renderer_t : public color_emoji_renderer_t { -public: - /** - * @brief 构造函数 - */ - svg_renderer_t(); - - /** - * @brief 析构函数 - */ - ~svg_renderer_t(); - - /** - * @brief 检查字体是否支持SVG表 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @return 是否支持 - */ - bool supports_font(const uint8_t* font_data, int font_offset) const override; - - /** - * @brief 渲染SVG彩色表情 - * @param font_info 字体信息 - * @param font_data 字体数据 - * @param font_offset 字体偏移 - * @param glyph_index 字形索引 - * @param font_size 字体大小 - * @return 彩色位图数据 - */ - std::optional render_emoji( - const stbtt_fontinfo& font_info, - const uint8_t* font_data, - int font_offset, - int32_t glyph_index, - float font_size) const override; - -private: - /** - * @brief 渲染SVG为位图 - * @param svg_data SVG数据 - * @param width 目标宽度 - * @param height 目标高度 - * @return 渲染后的位图 - */ - std::optional render_svg_to_bitmap( - const char* svg_data, - int width, - int height) const; -}; - -#endif diff --git a/src/mirage_render/src/font/font_system.cpp b/src/mirage_render/src/font/font_system.cpp index 305f19f..4db9afb 100644 --- a/src/mirage_render/src/font/font_system.cpp +++ b/src/mirage_render/src/font/font_system.cpp @@ -8,15 +8,15 @@ void font_manager::destroy() { atlas_manager_.clear(); primary_font_id_ = -1; next_font_id_ = 0; + destroy_font_system(); } int font_manager::add_font(const std::filesystem::path& in_font_path, const std::string& in_font_type) { - auto font = std::make_shared(); - if (!font->load_from_file(in_font_path)) { + auto font = create_font_face(in_font_path); + if (!font) { return -1; } - font->set_font_type(in_font_type); int font_id = next_font_id_++; fonts_[font_id] = font; @@ -33,7 +33,7 @@ int font_manager::add_font(const std::filesystem::path& in_font_path, const std: return font_id; } -std::shared_ptr font_manager::get_font_for_code_point(uint32_t in_code_point) { +std::shared_ptr font_manager::get_font_for_code_point(uint32_t in_code_point) { // 首先尝试主字体 auto primary = get_primary_font(); if (primary && primary->has_glyph(in_code_point)) { @@ -66,7 +66,7 @@ std::shared_ptr font_manager::get_font_for_code_point(uint32_t in_c */ text_layout_t font_manager::layout_text( const std::u32string& text, - const std::shared_ptr& in_font, + const std::shared_ptr& in_font, float font_size, float max_width, float line_spacing) @@ -77,19 +77,15 @@ text_layout_t font_manager::layout_text( const auto& primary_font = in_font ? in_font : get_primary_font(); assert(primary_font && "No valid font available"); - // 计算字体缩放比例 - const float scale = primary_font->get_scale_for_pixel_height(font_size); - // 初始化布局变量 float cursor_x = 0.0f; float cursor_y = 0.0f; - const float line_height = primary_font->get_line_height() * scale + line_spacing; float line_max_width = 0.0f; - const auto& v_metrics = primary_font->get_v_metrics(); + const auto& v_metrics = primary_font->get_metrics(); - float font_ascent = v_metrics.ascent * scale; - float font_descent = std::abs(v_metrics.descent * scale); + float font_ascent = v_metrics.ascent; + float font_descent = std::abs(v_metrics.descent); int32_t last_index = 0; // 上一个字形索引,用于字距调整 float line_start_x = 0.0f; // 当前行的起始x坐标 @@ -106,6 +102,7 @@ text_layout_t font_manager::layout_text( baseline = cursor_y + font_ascent; line_max_width = std::max(line_max_width, cursor_x); + const float line_height = v_metrics.line_height() + line_spacing; // 移到下一行 cursor_y += line_height; @@ -113,8 +110,8 @@ text_layout_t font_manager::layout_text( line_start_x = 0.0f; // 重置为下一行的基线计算 - font_ascent = v_metrics.ascent * scale; - font_descent = std::abs(v_metrics.descent * scale); + font_ascent = v_metrics.ascent; + font_descent = std::abs(v_metrics.descent); baseline = cursor_y + font_ascent; }; @@ -144,45 +141,43 @@ text_layout_t font_manager::layout_text( // 使用新字体重新获取字形索引 glyph_index = using_font->find_glyph_index(c); } + using_font->set_font_size(font_size); // 获取字形度量信息 - const auto& glyph_metrics = using_font->get_glyph_by_index(glyph_index, font_size); - if (!glyph_metrics) { - continue; // 如果无法获取字形度量,跳过该字符 - } + const auto& glyph_metrics = using_font->shape_glyph(glyph_index); // 获取或创建字形在图集中的区域 - const auto& region = get_or_create_glyph_by_index(glyph_metrics->glyph_index, using_font, font_size, is_emoji); + const auto& region = get_or_create_glyph_by_index(glyph_metrics.glyph_index, using_font, font_size, is_emoji); if (!region) { continue; // 如果无法在图集中获取或创建字形,跳过该字符 } // 检查是否需要换行 if (max_width > 0 && - cursor_x + glyph_metrics->advance > max_width && + cursor_x + glyph_metrics.advance.x() > max_width && cursor_x > line_start_x) { // 确保不是行首字符 finish_line(); } // 计算字形坐标 - float x = cursor_x + glyph_metrics->lsb + glyph_metrics->rect.left(); + float x = cursor_x + glyph_metrics.offset.x() + glyph_metrics.rect.left(); // float y = cursor_y + font_ascent + glyph_metrics->rect.top() + font_descent; - float y = baseline + glyph_metrics->rect.top(); + float y = baseline + glyph_metrics.rect.top(); // 添加字形位置信息到布局 auto& glyph_position = layout.glyphs.emplace_back(); glyph_position.is_emoji = is_emoji; glyph_position.glyph_index = glyph_index; glyph_position.position = { x, y }; - glyph_position.size = glyph_metrics->rect.size(); + glyph_position.size = glyph_metrics.rect.size(); glyph_position.region = *region; // 更新光标位置 - cursor_x += glyph_metrics->advance + glyph_metrics->rect.left(); + cursor_x += glyph_metrics.advance.x() + glyph_metrics.rect.left(); // 应用字距调整 if (last_index > 0) { - const float kern_advance = using_font->get_glyph_advance(last_index, glyph_index) * scale; + const float kern_advance = using_font->get_kerning(last_index, glyph_index); cursor_x += kern_advance; } @@ -207,7 +202,7 @@ text_layout_t font_manager::layout_text( */ std::optional font_manager::get_or_create_glyph_by_index( int32_t in_glyph_id, - std::shared_ptr in_font, + const std::shared_ptr& in_font, float in_font_size, bool is_emoji) { @@ -216,5 +211,12 @@ std::optional font_manager::get_or_create_glyph_by_index( return std::nullopt; } - return atlas_manager_.get_or_create_glyph(in_glyph_id, *in_font, in_font_size, is_emoji); + return atlas_manager_.get_or_create_glyph(in_glyph_id, in_font, in_font_size, is_emoji); +} + +font_manager::font_manager() { + // 初始化字体系统 + if (!init_font_system()) { + throw std::runtime_error("无法初始化字体系统"); + } } diff --git a/src/mirage_render/src/font/font_system.h b/src/mirage_render/src/font/font_system.h index db33ea2..2ae8bc9 100644 --- a/src/mirage_render/src/font/font_system.h +++ b/src/mirage_render/src/font/font_system.h @@ -5,11 +5,13 @@ #include #include -#include "font_face.h" #include "atlas/font_atlas.h" #include "atlas/font_atlas_manager.h" #include +#include "font_type.h" +#include "interface/font_interface.h" + /** * @class font_manager * @brief 字体管理系统 @@ -74,13 +76,13 @@ public: * @param in_code_point Unicode码点 * @return 最适合渲染该码点的字体 */ - std::shared_ptr get_font_for_code_point(uint32_t in_code_point); + std::shared_ptr get_font_for_code_point(uint32_t in_code_point); /** * @brief 获取主字体 * @return 主字体 */ - std::shared_ptr get_primary_font() { + std::shared_ptr get_primary_font() { if (primary_font_id_ != -1 && fonts_.contains(primary_font_id_)) { return fonts_[primary_font_id_]; } @@ -109,7 +111,7 @@ public: */ text_layout_t layout_text( const std::u32string& text, - const std::shared_ptr& in_font, + const std::shared_ptr& in_font, float font_size, float max_width = 0.0f, float line_spacing = 1.2f); @@ -127,7 +129,7 @@ public: */ std::optional get_or_create_glyph_by_index( int32_t in_glyph_id, - std::shared_ptr in_font, + const std::shared_ptr& in_font, float in_font_size, bool is_emoji); @@ -147,8 +149,10 @@ public: return atlas_manager_.get_emoji_atlases(); } private: - std::unordered_map> fonts_; ///< 字体ID到字体对象的映射 - font_atlas_manager atlas_manager_; ///< 图集管理器 + font_manager(); + + std::unordered_map> fonts_; ///< 字体ID到字体对象的映射 + font_atlas_manager atlas_manager_; ///< 图集管理器 std::vector emoji_font_ids_; ///< 表情符号字体ID列表 int primary_font_id_ = -1; ///< 主字体ID diff --git a/src/mirage_render/src/font/font_type.h b/src/mirage_render/src/font/font_type.h index a667c6b..5bf797b 100644 --- a/src/mirage_render/src/font/font_type.h +++ b/src/mirage_render/src/font/font_type.h @@ -27,17 +27,6 @@ enum class vertical_text_alignment_t { bottom ///< 文本底部对齐 }; -/** - * @struct glyph_t - * @brief 字形基本信息 - */ -struct glyph_t { - uint32_t glyph_index = 0; ///< 字形索引 - rect_t rect; ///< 字形矩形(相对于基线) - float lsb; ///< 左侧轴向边距 - float advance = 0.0f; ///< 水平前进量 -}; - /** * @struct positioned_glyph_t * @brief 已定位的字形 @@ -126,13 +115,6 @@ struct text_style_t { margin_t text_margin = { 0, 0, 0, 0 }; ///< 文本边距 }; -struct shaped_glyph_t { - int32_t glyph_index; // Unicode码点 - Eigen::Vector2f offset; // 相对位置偏移 - Eigen::Vector2f advance; // 前进值 - int cluster; // 字符簇索引 -}; - struct text_layout_t { struct glyph_position_t { bool is_emoji; // 是否为表情符号 @@ -147,25 +129,3 @@ struct text_layout_t { float ascent; // 上升高度 float baseline; // 基线位置 }; - -/** - * @struct color_emoji_bitmap_t - * @brief 彩色表情位图 - */ -struct color_emoji_bitmap_t { - int width = 0; // 位图宽度 - int height = 0; // 位图高度 - int16_t x_offset = 0; // 水平原点偏移 - int16_t y_offset = 0; // 垂直原点偏移 - std::vector data; // RGBA数据,每个像素4字节 -}; - -/** - * @struct font_v_metrics_t - * @brief 字体垂直度量 - */ -struct font_v_metrics_t { - int32_t ascent; // 上升高度 - int32_t descent; // 下降高度 - int32_t line_gap; // 行间距 -}; diff --git a/src/mirage_render/src/interface/font_interface.cpp b/src/mirage_render/src/interface/font_interface.cpp new file mode 100644 index 0000000..20f670b --- /dev/null +++ b/src/mirage_render/src/interface/font_interface.cpp @@ -0,0 +1,10 @@ +#include "font_interface.h" + +bool font_face_interface::load(const std::filesystem::path& in_path) { + font_data_ = mapped_file::create(); + if (!font_data_->map_file(in_path)) { + return false; + } + return on_load(); +} + diff --git a/src/mirage_render/src/interface/font_interface.h b/src/mirage_render/src/interface/font_interface.h new file mode 100644 index 0000000..cdfab68 --- /dev/null +++ b/src/mirage_render/src/interface/font_interface.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include + +#include "geometry/rect.h" +#include "misc/mapped_file/mapped_file.h" + +struct image_heap_t; + +/** + * @struct font_v_metrics_t + * @brief 字体垂直度量 + */ +struct font_v_metrics_t { + float ascent; // 上升高度 + float descent; // 下降高度 + float line_gap; // 行间距 + [[nodiscard]] float line_height() const { return ascent - descent + line_gap; } // 行高 +}; + +struct glyph_shaped_t { + int32_t glyph_index; // Unicode码点 + Eigen::Vector2f offset; // 相对位置偏移 + Eigen::Vector2f advance; // 前进值 + rect_t<> rect; // 字形矩形区域 +}; + +class font_face_interface { +public: + virtual ~font_face_interface() = default; + bool load(const std::filesystem::path& in_path); + + void set_font_size(float in_size) { font_size_ = in_size; on_set_font_size(in_size); } + [[nodiscard]] float get_font_size() const { return font_size_; } + + [[nodiscard]] virtual std::string get_font_name() const = 0; + [[nodiscard]] virtual std::string get_font_family() const = 0; + [[nodiscard]] virtual std::string get_font_style() const = 0; + + [[nodiscard]] virtual bool supports_color_emoji() const = 0; + + [[nodiscard]] virtual font_v_metrics_t get_metrics() const = 0; + [[nodiscard]] virtual std::shared_ptr get_glyph_image(int32_t in_glyph_id) const = 0; + [[nodiscard]] virtual std::shared_ptr get_emoji_image(int32_t in_glyph_id) const = 0; + + [[nodiscard]] virtual uint32_t find_glyph_index(uint32_t in_unicode_codepoint) const = 0; + [[nodiscard]] virtual bool has_glyph(uint32_t in_unicode_codepoint) const { return find_glyph_index(in_unicode_codepoint) > 0; } + + [[nodiscard]] virtual float get_kerning(uint32_t in_first_glyph_id, uint32_t in_second_glyph_id) const = 0; + [[nodiscard]] virtual glyph_shaped_t shape_glyph(uint32_t in_glyph_id) const = 0; +protected: + virtual bool on_load() = 0; + virtual void on_set_font_size(float in_size) {} +protected: + std::shared_ptr font_data_; // 字体文件映射数据 +private: + float font_size_ = 16.0f; // 字体大小 +}; + +bool init_font_system(); +void destroy_font_system(); +std::shared_ptr create_font_face(const std::filesystem::path& in_path); diff --git a/src/mirage_render/src/interface/image_interface.h b/src/mirage_render/src/interface/image_interface.h index 0d8d0b9..ace21be 100644 --- a/src/mirage_render/src/interface/image_interface.h +++ b/src/mirage_render/src/interface/image_interface.h @@ -2,20 +2,23 @@ #include #include #include +#include -#include "pixel.h" #include "sokol_gfx.h" #include "misc/mapped_file/mapped_file.h" struct image_heap_t { - int32_t width; // 图像宽度 - int32_t height; // 图像高度 + uint32_t width; // 图像宽度 + uint32_t height; // 图像高度 sg_pixel_format pixel_format; // 像素格式 void* data; // 图像数据指针 - template - image_accessor

make_accessor() { - return image_accessor

(data, width, height); + [[nodiscard]] Eigen::Vector2i get_size() const { + return { static_cast(width), static_cast(height) }; + } + [[nodiscard]] size_t get_data_size() const { + const auto& pixel_info = sg_query_pixelformat(pixel_format); + return width * height * pixel_info.bytes_per_pixel; } }; diff --git a/src/mirage_render/src/render/render_elements.h b/src/mirage_render/src/render/render_elements.h index 225f12a..e528ae9 100644 --- a/src/mirage_render/src/render/render_elements.h +++ b/src/mirage_render/src/render/render_elements.h @@ -15,7 +15,6 @@ #include "font/font_type.h" #include "misc/mirage_type.h" -class font_face_t; /** * @enum draw_effect * @brief 定义渲染效果类型 diff --git a/src/mirage_widget/widget/leaf_widget/mtext_block.h b/src/mirage_widget/widget/leaf_widget/mtext_block.h index 036c2e8..3191b61 100644 --- a/src/mirage_widget/widget/leaf_widget/mtext_block.h +++ b/src/mirage_widget/widget/leaf_widget/mtext_block.h @@ -2,6 +2,8 @@ #include "font/font_type.h" #include "widget/mleaf_widget.h" +class font_face_interface; + class mtext_block : public mleaf_widget { public: void on_paint(mirage_paint_context& in_context) override; @@ -11,7 +13,7 @@ public: update_layout(); } - void set_font(const std::shared_ptr& in_font) { + void set_font(const std::shared_ptr& in_font) { font_ = in_font; update_layout(); } @@ -46,5 +48,5 @@ private: float font_size_ = 48.0f; float line_spacing_ = 1.2f; float max_width_ = 0.0f; - std::shared_ptr font_; + std::shared_ptr font_; };