优化代码可读性
This commit is contained in:
@@ -246,7 +246,7 @@ void destroy_font_system() {
|
||||
FT_Done_FreeType(library_);
|
||||
}
|
||||
|
||||
std::shared_ptr<font_face_interface> create_font_face(const std::filesystem::path& in_path) {
|
||||
font_face_ptr create_font_face(const std::filesystem::path& in_path) {
|
||||
auto font_face = std::make_shared<freetype_interface>();
|
||||
if (!font_face->load(in_path)) {
|
||||
return nullptr;
|
||||
|
||||
@@ -178,7 +178,7 @@ void destroy_font_system() {
|
||||
// stb_truetype不需要销毁
|
||||
}
|
||||
|
||||
std::shared_ptr<font_face_interface> create_font_face(const std::filesystem::path& in_path) {
|
||||
font_face_ptr create_font_face(const std::filesystem::path& in_path) {
|
||||
auto font_face = std::make_shared<stb_font_face_t>();
|
||||
if (!font_face->load(in_path)) {
|
||||
return nullptr;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "interface/font_interface.h"
|
||||
|
||||
char_key_t::char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face,
|
||||
char_key_t::char_key_t(uint32_t in_glyph_index, const font_face_ptr& in_font_face,
|
||||
float in_font_size):
|
||||
glyph_index(in_glyph_index),
|
||||
font_face(in_font_face),
|
||||
|
||||
@@ -31,10 +31,10 @@ struct glyph_atlas_result_t {
|
||||
|
||||
struct char_key_t {
|
||||
uint32_t glyph_index;
|
||||
std::shared_ptr<font_face_interface> font_face;
|
||||
font_face_ptr font_face;
|
||||
float font_size;
|
||||
|
||||
char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face, float in_font_size);
|
||||
char_key_t(uint32_t in_glyph_index, const font_face_ptr& in_font_face, float in_font_size);
|
||||
|
||||
bool operator==(const char_key_t& other) const {
|
||||
// Implement comparison logic. Might involve comparing font pointers
|
||||
|
||||
@@ -71,7 +71,7 @@ std::optional<atlas_region_t> find_or_create_in_atlases(
|
||||
|
||||
std::optional<atlas_region_t> font_atlas_manager::get_or_create_glyph(
|
||||
const int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
const float in_font_size,
|
||||
const bool is_emoji) {
|
||||
const char_key_t key(in_glyph_id, in_font, in_font_size);
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
*/
|
||||
std::optional<atlas_region_t> get_or_create_glyph(
|
||||
int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float in_font_size,
|
||||
bool is_emoji);
|
||||
|
||||
|
||||
@@ -4,6 +4,74 @@
|
||||
|
||||
#include "emoji_detector.h"
|
||||
|
||||
namespace text_layout_impl {
|
||||
void finalize_line_glyphs(text_layout_t& layout, const text_layout_t::line_info_t& line, float cursor_y) {
|
||||
const float line_height = line.max_line_height;
|
||||
const float content_height = line.max_ascent + line.max_descent;
|
||||
const float baseline_y = cursor_y + line.max_ascent + (line_height - content_height) / 2.f;
|
||||
|
||||
for (const auto& pending: line.glyphs) {
|
||||
const float size_y_diff =
|
||||
pending.metrics.rect.size().y() - static_cast<float>(pending.region.rect.size().y());
|
||||
|
||||
auto& glyph = layout.glyphs.emplace_back();
|
||||
glyph.is_emoji = pending.is_emoji;
|
||||
glyph.glyph_index = pending.glyph_index;
|
||||
glyph.position = { pending.start_x + pending.metrics.offset.x(),
|
||||
baseline_y + pending.metrics.offset.y() + size_y_diff };
|
||||
glyph.size = pending.metrics.rect.size();
|
||||
glyph.region = pending.region;
|
||||
}
|
||||
}
|
||||
void update_line_metrics(text_layout_t::line_info_t& line, const font_v_metrics_t& font_metrics, float line_spacing) {
|
||||
line.max_ascent = std::max(line.max_ascent, font_metrics.ascent);
|
||||
line.max_descent = std::max(line.max_descent, std::abs(font_metrics.descent));
|
||||
line.max_line_height = std::max(line.max_line_height, font_metrics.line_height * line_spacing);
|
||||
}
|
||||
void add_pending_glyph(text_layout_t::line_info_t& line,
|
||||
const font_manager::glyph_info_t& info,
|
||||
float cursor_x) {
|
||||
text_layout_t::pending_glyph_t pending;
|
||||
pending.glyph_index = info.glyph_index;
|
||||
pending.prev_glyph_id_for_kerning = line.prev_glyph_id;
|
||||
pending.start_x = cursor_x;
|
||||
pending.metrics = info.metrics;
|
||||
pending.region = info.region;
|
||||
pending.is_emoji = info.is_emoji;
|
||||
pending.font = info.font;
|
||||
|
||||
line.glyphs.push_back(pending);
|
||||
}
|
||||
|
||||
bool should_wrap_line(float max_width, float next_x, bool has_content) {
|
||||
return max_width > 0 && next_x > max_width && has_content;
|
||||
}
|
||||
|
||||
void handle_newline(bool& at_line_start,
|
||||
text_layout_t::line_info_t& line,
|
||||
float& total_height,
|
||||
const std::function<void(bool)>& finish_line) {
|
||||
if (at_line_start) {
|
||||
total_height += line.max_line_height;
|
||||
} else {
|
||||
finish_line(true);
|
||||
}
|
||||
}
|
||||
|
||||
void finalize_layout(const text_layout_t::line_info_t& line,
|
||||
bool at_line_start,
|
||||
bool text_empty,
|
||||
float& total_height,
|
||||
float default_line_height,
|
||||
const std::function<void(bool)>& finish_line) {
|
||||
if (line.has_content) {
|
||||
finish_line(false);
|
||||
} else if (at_line_start && !text_empty) {
|
||||
total_height += line.max_line_height;
|
||||
}
|
||||
}
|
||||
} // namespace text_layout_impl
|
||||
|
||||
void font_manager::destroy() {
|
||||
fonts_.clear();
|
||||
emoji_font_ids_.clear();
|
||||
@@ -44,11 +112,11 @@ int font_manager::add_font(const std::filesystem::path& in_font_path, const std:
|
||||
return font_id;
|
||||
}
|
||||
|
||||
std::shared_ptr<font_face_interface> font_manager::get_font_for_code_point(
|
||||
const std::shared_ptr<font_face_interface>& in_custom_primary_font, const uint32_t in_code_point,
|
||||
font_face_ptr font_manager::get_font_for_code_point(
|
||||
const font_face_ptr& in_custom_primary_font, const uint32_t in_code_point,
|
||||
uint32_t* out_glyph_index) {
|
||||
// **辅助 Lambda:检查字体并更新字形索引**
|
||||
auto check_font = [&](const std::shared_ptr<font_face_interface>& font) -> std::shared_ptr<font_face_interface> {
|
||||
auto check_font = [&](const font_face_ptr& font) -> font_face_ptr {
|
||||
if (!font)
|
||||
return nullptr; // 跳过空指针
|
||||
|
||||
@@ -76,7 +144,7 @@ std::shared_ptr<font_face_interface> font_manager::get_font_for_code_point(
|
||||
// 此过滤器排除了空指针字体和已检查过的主字体。
|
||||
// 注意: 更复杂的过滤器可以基于 is_emoji 和字体元数据 (例如 is_emoji_font())
|
||||
// 来优先选择特定类型的字体(例如,为表情符号优先选择表情字体)。
|
||||
auto font_filter = [&](const std::shared_ptr<font_face_interface>& font) {
|
||||
auto font_filter = [&](const font_face_ptr& font) {
|
||||
// **确保字体有效且不是我们已经检查过的主字体**
|
||||
if (is_emoji) {
|
||||
return std::ranges::contains(emoji_font_ids_, font);
|
||||
@@ -112,7 +180,7 @@ std::shared_ptr<font_face_interface> font_manager::get_font_for_code_point(
|
||||
|
||||
text_layout_t font_manager::layout_text(
|
||||
const std::u32string& text,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float font_size,
|
||||
float max_width,
|
||||
float line_spacing) {
|
||||
@@ -122,198 +190,89 @@ text_layout_t font_manager::layout_text(
|
||||
}
|
||||
|
||||
void font_manager::append_layout_text(
|
||||
text_layout_t& in_layout,
|
||||
const std::u32string& append_text,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
float font_size,
|
||||
float max_width,
|
||||
float line_spacing) {
|
||||
in_layout.glyphs.reserve(in_layout.glyphs.size() + append_text.size());
|
||||
text_layout_t& in_layout,
|
||||
const std::u32string& append_text,
|
||||
const font_face_ptr& in_font,
|
||||
float font_size,
|
||||
float max_width,
|
||||
float line_spacing) {
|
||||
|
||||
in_layout.glyphs.reserve(in_layout.glyphs.size() + append_text.size());
|
||||
|
||||
const auto& primary_font = in_font ? in_font : get_primary_font();
|
||||
assert(primary_font && "No valid font available");
|
||||
auto& current_line = in_layout.last_line;
|
||||
|
||||
float total_width = 0.0f;
|
||||
float total_height = 0.0f;
|
||||
bool at_line_start = true; // 跟踪是否在行的开始位置
|
||||
auto& current_line = in_layout.last_line;
|
||||
float& cursor_y = in_layout.last_cursor.y();
|
||||
float& cursor_x = in_layout.last_cursor.x();
|
||||
|
||||
float& cursor_y = in_layout.last_cursor.y();
|
||||
float& cursor_x = in_layout.last_cursor.x();
|
||||
float total_width = 0.0f;
|
||||
float total_height = 0.0f;
|
||||
bool at_line_start = true;
|
||||
|
||||
std::map<std::shared_ptr<font_face_interface>, font_v_metrics_t> font_metrics_cache;
|
||||
// 缓存字体度量
|
||||
auto font_metrics_cache = cache_font_metrics(font_size, primary_font);
|
||||
const float default_line_height = font_metrics_cache[primary_font].line_height * line_spacing;
|
||||
current_line.max_line_height = default_line_height;
|
||||
|
||||
// 设置所有可能用到的字体大小
|
||||
for (const auto& font : fonts_ | std::views::values) {
|
||||
if (!font)
|
||||
continue;
|
||||
font->set_font_size(font_size);
|
||||
// 确保获取度量前字体大小已设置 (已在循环开始前完成)
|
||||
font_metrics_cache[font] = font->get_metrics();
|
||||
}
|
||||
if (primary_font) {
|
||||
primary_font->set_font_size(font_size);
|
||||
font_metrics_cache[primary_font] = primary_font->get_metrics();
|
||||
}
|
||||
const float current_font_max_height = font_metrics_cache[primary_font].line_height * line_spacing;
|
||||
current_line.max_line_height = current_font_max_height; // 初始化当前行的最大行高
|
||||
|
||||
/**
|
||||
* @brief 完成当前行的布局并将字形添加到最终布局中
|
||||
*/
|
||||
// 完成当前行
|
||||
auto finish_line = [&](bool next_line = true) {
|
||||
at_line_start = true; // 标记下一行的开始
|
||||
at_line_start = true;
|
||||
text_layout_impl::finalize_line_glyphs(in_layout, current_line, cursor_y);
|
||||
|
||||
// --- 计算行垂直居中的基线 ---
|
||||
// **1. 计算该行分配的总高度**
|
||||
const float actual_line_height = current_line.max_line_height;
|
||||
// **2. 计算该行内容的实际高度**
|
||||
const float content_height = current_line.max_ascent + current_line.max_descent;
|
||||
// **3. 计算垂直居中对齐的基线 Y 坐标**
|
||||
// 目标是将 content_height 放在 actual_line_height 的中间。
|
||||
// 行空间的中心点 Y = cursor_y + actual_line_height / 2.0f
|
||||
// 内容空间的中心点相对于基线的偏移 = (max_ascent - max_descent) / 2.0f
|
||||
// 所以 baseline_y + (max_ascent - max_descent) / 2.0f = cursor_y + actual_line_height / 2.0f
|
||||
// baseline_y = cursor_y + (actual_line_height - max_ascent + max_descent) / 2.0f
|
||||
// (注意:这里假设 ascent 为正, descent 为正)
|
||||
const float baseline_y = cursor_y + current_line.max_ascent + (actual_line_height - content_height) / 2.f;
|
||||
|
||||
// --- 处理当前行的所有字形,计算最终位置 ---
|
||||
for (const auto& pending_glyph : current_line.glyphs) {
|
||||
const auto& metrics = pending_glyph.metrics;
|
||||
const auto& region = pending_glyph.region;
|
||||
|
||||
// 计算Y轴差异 (确保从位图数据的实际顶部开始绘制)
|
||||
const float size_y_diff = metrics.rect.size().y() - static_cast<float>(region.rect.size().y());
|
||||
|
||||
// 计算最终字形绘制坐标 (使用新的 baseline_y)
|
||||
float final_x = pending_glyph.start_x + metrics.offset.x();
|
||||
// **final_y = baseline_y + 字形相对于基线的偏移 + 高度差异**
|
||||
float final_y = baseline_y + metrics.offset.y() + size_y_diff;
|
||||
|
||||
// 添加字形位置信息到最终布局
|
||||
auto& glyph_position = in_layout.glyphs.emplace_back();
|
||||
glyph_position.is_emoji = pending_glyph.is_emoji;
|
||||
glyph_position.glyph_index = pending_glyph.glyph_index;
|
||||
glyph_position.position = { final_x, final_y };
|
||||
glyph_position.size = metrics.rect.size();
|
||||
glyph_position.region = region;
|
||||
}
|
||||
|
||||
// --- 更新总体宽度 ---
|
||||
total_width = std::max(total_width, current_line.current_width);
|
||||
// 增加行计数(只要调用了 finish_line 就说明有一行)
|
||||
total_height += actual_line_height;
|
||||
total_height += current_line.max_line_height;
|
||||
|
||||
// 移到下一行的顶部
|
||||
if (next_line) {
|
||||
cursor_y = total_height;
|
||||
cursor_x = 0.0f;
|
||||
|
||||
// 重置行信息和上一个字形ID
|
||||
current_line = text_layout_t::line_info_t{};
|
||||
current_line.max_line_height = current_font_max_height; // 设置新行的默认行高
|
||||
}
|
||||
if (next_line) {
|
||||
cursor_y = total_height;
|
||||
cursor_x = 0.0f;
|
||||
current_line = text_layout_t::line_info_t{};
|
||||
current_line.max_line_height = default_line_height;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 处理单个字符的布局(第一阶段:收集信息和换行判断)
|
||||
* (此函数逻辑基本不变,主要负责收集信息给 finish_line 使用)
|
||||
*/
|
||||
auto process_character = [&](const char32_t c) {
|
||||
if (c == U'\n') {
|
||||
// 如果当前行没有内容但我们在行的开始,仍然需要计算这个空行
|
||||
if (at_line_start) {
|
||||
total_height += current_line.max_line_height;
|
||||
} else {
|
||||
finish_line();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
at_line_start = false; // 不再是行的开始
|
||||
|
||||
const bool is_emoji = emoji_detector::is_emoji(c);
|
||||
uint32_t glyph_index = 0;
|
||||
const auto& using_font = get_font_for_code_point(primary_font, c, &glyph_index);
|
||||
if (!using_font)
|
||||
return;
|
||||
|
||||
const auto& current_font_metrics = font_metrics_cache[using_font];
|
||||
|
||||
const auto& glyph_metrics = using_font->shape_glyph(glyph_index);
|
||||
const auto& region_opt = get_or_create_glyph_by_index(glyph_metrics.glyph_index, using_font, font_size,
|
||||
is_emoji);
|
||||
|
||||
if (!region_opt) {
|
||||
current_line.prev_glyph_id = 0;
|
||||
return;
|
||||
}
|
||||
const auto& region = *region_opt;
|
||||
|
||||
float kerning = 0.0f;
|
||||
if (current_line.prev_glyph_id != 0) {
|
||||
kerning = using_font->get_kerning(current_line.prev_glyph_id, glyph_index);
|
||||
}
|
||||
|
||||
float estimated_next_x = cursor_x + kerning + glyph_metrics.advance.x();
|
||||
|
||||
// 检查自动换行
|
||||
if (max_width > 0 &&
|
||||
estimated_next_x > max_width &&
|
||||
current_line.has_content) {
|
||||
finish_line();
|
||||
// !! 继续处理当前字符 c 在新行上 !!
|
||||
kerning = 0.0f; // 新行首字符无 kerning
|
||||
// line_cursor_x 和 prev_glyph_id 已在 finish_line 中重置为 0
|
||||
}
|
||||
|
||||
current_line.has_content = true;
|
||||
|
||||
// **更新当前行的最大度量信息** (保持不变)
|
||||
current_line.max_ascent = std::max(current_line.max_ascent, current_font_metrics.ascent);
|
||||
// **确保 descent 是正值**
|
||||
current_line.max_descent = std::max(current_line.max_descent, std::abs(current_font_metrics.descent));
|
||||
current_line.max_line_height = std::max(current_line.max_line_height, current_font_metrics.line_height * line_spacing);
|
||||
|
||||
cursor_x += kerning;
|
||||
|
||||
text_layout_t::pending_glyph_t pending_glyph;
|
||||
pending_glyph.glyph_index = glyph_index;
|
||||
pending_glyph.prev_glyph_id_for_kerning = current_line.prev_glyph_id;
|
||||
pending_glyph.start_x = cursor_x;
|
||||
pending_glyph.metrics = glyph_metrics;
|
||||
pending_glyph.region = region;
|
||||
pending_glyph.is_emoji = is_emoji;
|
||||
pending_glyph.font = using_font;
|
||||
|
||||
current_line.glyphs.push_back(pending_glyph);
|
||||
|
||||
// 更新行宽度
|
||||
current_line.current_width = cursor_x + glyph_metrics.advance.x();
|
||||
|
||||
// 更新光标 X 位置
|
||||
cursor_x += glyph_metrics.advance.x();
|
||||
|
||||
// 更新上一个字形索引
|
||||
current_line.prev_glyph_id = glyph_index;
|
||||
};
|
||||
|
||||
// --- 主处理循环 ---
|
||||
// 处理每个字符
|
||||
for (const char32_t c : append_text) {
|
||||
process_character(c);
|
||||
if (c == U'\n') {
|
||||
text_layout_impl::handle_newline(at_line_start, current_line, total_height, finish_line);
|
||||
continue;
|
||||
}
|
||||
|
||||
at_line_start = false;
|
||||
|
||||
// 获取字形信息
|
||||
auto glyph_info = get_glyph_info(c, primary_font, font_size);
|
||||
if (!glyph_info.font) continue;
|
||||
|
||||
// 计算间距和位置
|
||||
float kerning = current_line.prev_glyph_id ?
|
||||
glyph_info.font->get_kerning(current_line.prev_glyph_id, glyph_info.glyph_index) : 0.0f;
|
||||
|
||||
float next_x = cursor_x + kerning + glyph_info.metrics.advance.x();
|
||||
|
||||
// 检查换行
|
||||
if (text_layout_impl::should_wrap_line(max_width, next_x, current_line.has_content)) {
|
||||
finish_line();
|
||||
kerning = 0.0f;
|
||||
}
|
||||
|
||||
// 更新行信息
|
||||
text_layout_impl::update_line_metrics(current_line, font_metrics_cache[glyph_info.font], line_spacing);
|
||||
|
||||
// 添加待处理字形
|
||||
cursor_x += kerning;
|
||||
text_layout_impl::add_pending_glyph(current_line, glyph_info, cursor_x);
|
||||
|
||||
cursor_x += glyph_info.metrics.advance.x();
|
||||
current_line.current_width = cursor_x;
|
||||
current_line.prev_glyph_id = glyph_info.glyph_index;
|
||||
current_line.has_content = true;
|
||||
}
|
||||
|
||||
// 处理最后一行
|
||||
if (current_line.has_content) {
|
||||
finish_line(false);
|
||||
} else if (at_line_start && !append_text.empty()) {
|
||||
// 如果在行的开始位置且有处理过字符(比如文本以\n结尾),需要计入这个空行
|
||||
total_height += current_line.max_line_height;
|
||||
}
|
||||
text_layout_impl::finalize_layout(current_line, at_line_start, append_text.empty(),
|
||||
total_height, default_line_height, finish_line);
|
||||
|
||||
// --- 设置最终布局尺寸 ---
|
||||
// 使用公式: total_height = max(1, line_count) * line_height
|
||||
in_layout.total_size = { total_width, total_height };
|
||||
}
|
||||
|
||||
@@ -322,7 +281,7 @@ void font_manager::append_layout_text(
|
||||
*/
|
||||
std::optional<atlas_region_t> font_manager::get_or_create_glyph_by_index(
|
||||
int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float in_font_size,
|
||||
bool is_emoji) {
|
||||
// 验证字体有效性
|
||||
@@ -334,8 +293,42 @@ std::optional<atlas_region_t> font_manager::get_or_create_glyph_by_index(
|
||||
}
|
||||
|
||||
font_manager::font_manager() {
|
||||
// 初始化字体系统
|
||||
if (!init_font_system()) {
|
||||
throw std::runtime_error("无法初始化字体系统");
|
||||
}
|
||||
// 初始化字体系统
|
||||
if (!init_font_system()) {
|
||||
throw std::runtime_error("无法初始化字体系统");
|
||||
}
|
||||
}
|
||||
std::map<font_face_ptr, font_v_metrics_t> font_manager::cache_font_metrics(float font_size, const font_face_ptr& primary_font) {
|
||||
std::map<font_face_ptr, font_v_metrics_t> cache;
|
||||
|
||||
for (const auto& font: fonts_ | std::views::values) {
|
||||
if (!font)
|
||||
continue;
|
||||
font->set_font_size(font_size);
|
||||
cache[font] = font->get_metrics();
|
||||
}
|
||||
|
||||
if (primary_font) {
|
||||
primary_font->set_font_size(font_size);
|
||||
cache[primary_font] = primary_font->get_metrics();
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
font_manager::glyph_info_t font_manager::get_glyph_info(char32_t c, const font_face_ptr& primary_font, float font_size) {
|
||||
glyph_info_t info;
|
||||
info.is_emoji = emoji_detector::is_emoji(c);
|
||||
info.font = get_font_for_code_point(primary_font, c, &info.glyph_index);
|
||||
|
||||
if (!info.font)
|
||||
return info;
|
||||
|
||||
info.metrics = info.font->shape_glyph(info.glyph_index);
|
||||
if (auto region_opt = get_or_create_glyph_by_index(info.metrics.glyph_index, info.font, font_size, info.is_emoji)) {
|
||||
info.region = *region_opt;
|
||||
info.valid = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
|
||||
#include <filesystem>
|
||||
#include <ranges>
|
||||
#include "atlas/font_atlas.h"
|
||||
#include "atlas/font_atlas_manager.h"
|
||||
#include <filesystem>
|
||||
|
||||
#include "font_type.h"
|
||||
#include "interface/font_interface.h"
|
||||
@@ -21,6 +22,15 @@
|
||||
*/
|
||||
class font_manager {
|
||||
public:
|
||||
struct glyph_info_t {
|
||||
font_face_ptr font;
|
||||
uint32_t glyph_index = 0;
|
||||
glyph_shaped_t metrics;
|
||||
atlas_region_t region;
|
||||
bool is_emoji = false;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
*
|
||||
@@ -81,21 +91,21 @@ public:
|
||||
* @param in_code_point Unicode码点
|
||||
* @return 最适合渲染该码点的字体
|
||||
*/
|
||||
std::shared_ptr<font_face_interface> get_font_for_code_point(uint32_t in_code_point,
|
||||
font_face_ptr get_font_for_code_point(uint32_t in_code_point,
|
||||
uint32_t* out_glyph_index = nullptr) {
|
||||
auto primary = get_primary_font();
|
||||
return get_font_for_code_point(primary, in_code_point, out_glyph_index);
|
||||
}
|
||||
|
||||
std::shared_ptr<font_face_interface> get_font_for_code_point(
|
||||
const std::shared_ptr<font_face_interface>& in_custom_primary_font, uint32_t in_code_point,
|
||||
font_face_ptr get_font_for_code_point(
|
||||
const font_face_ptr& in_custom_primary_font, uint32_t in_code_point,
|
||||
uint32_t* out_glyph_index = nullptr);
|
||||
|
||||
/**
|
||||
* @brief 获取主字体
|
||||
* @return 主字体
|
||||
*/
|
||||
std::shared_ptr<font_face_interface> get_primary_font() {
|
||||
font_face_ptr get_primary_font() {
|
||||
if (primary_font_id_ != -1 && fonts_.contains(primary_font_id_)) {
|
||||
return fonts_[primary_font_id_];
|
||||
}
|
||||
@@ -122,7 +132,7 @@ public:
|
||||
*/
|
||||
text_layout_t layout_text(
|
||||
const std::u32string& text,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float font_size,
|
||||
float max_width = 0.0f,
|
||||
float line_spacing = 1.2f);
|
||||
@@ -130,7 +140,7 @@ public:
|
||||
void append_layout_text(
|
||||
text_layout_t& in_layout,
|
||||
const std::u32string& append_text,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float font_size,
|
||||
float max_width = 0.0f,
|
||||
float line_spacing = 1.2f
|
||||
@@ -149,7 +159,7 @@ public:
|
||||
*/
|
||||
std::optional<atlas_region_t> get_or_create_glyph_by_index(
|
||||
int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
const font_face_ptr& in_font,
|
||||
float in_font_size,
|
||||
bool is_emoji);
|
||||
|
||||
@@ -172,10 +182,13 @@ public:
|
||||
private:
|
||||
font_manager();
|
||||
|
||||
std::unordered_map<int32_t, std::shared_ptr<font_face_interface>> fonts_; ///< 字体ID到字体对象的映射
|
||||
std::map<font_face_ptr, font_v_metrics_t> cache_font_metrics(float font_size, const font_face_ptr& primary_font);
|
||||
glyph_info_t get_glyph_info(char32_t c, const font_face_ptr& primary_font, float font_size);
|
||||
|
||||
std::unordered_map<int32_t, font_face_ptr> fonts_; ///< 字体ID到字体对象的映射
|
||||
font_atlas_manager atlas_manager_; ///< 图集管理器
|
||||
|
||||
std::vector<std::shared_ptr<font_face_interface>> emoji_font_ids_; ///< 表情符号字体ID列表
|
||||
std::vector<font_face_ptr> emoji_font_ids_; ///< 表情符号字体ID列表
|
||||
int32_t primary_font_id_ = -1; ///< 主字体ID
|
||||
int32_t next_font_id_ = 0; ///< 下一个可用的字体ID
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ struct text_layout_t {
|
||||
glyph_shaped_t metrics; // 字形度量信息
|
||||
atlas_region_t region; // 字形在图集中的区域
|
||||
bool is_emoji; // 是否为表情符号
|
||||
std::shared_ptr<font_face_interface> font; // 使用的字体
|
||||
font_face_ptr font; // 使用的字体
|
||||
};
|
||||
|
||||
struct line_info_t {
|
||||
|
||||
@@ -62,6 +62,8 @@ private:
|
||||
float font_size_ = 16.0f; // 字体大小
|
||||
};
|
||||
|
||||
using font_face_ptr = std::shared_ptr<font_face_interface>;
|
||||
|
||||
bool init_font_system();
|
||||
void destroy_font_system();
|
||||
std::shared_ptr<font_face_interface> create_font_face(const std::filesystem::path& in_path);
|
||||
font_face_ptr create_font_face(const std::filesystem::path& in_path);
|
||||
|
||||
@@ -6,7 +6,7 @@ class font_face_interface;
|
||||
|
||||
struct editable_text_box_args {
|
||||
WARG(std::u32string, text, {})
|
||||
WARG(std::shared_ptr<font_face_interface>, font, {})
|
||||
WARG(font_face_ptr, font, {})
|
||||
WARG(float, font_size, 24.f)
|
||||
WARG(float, line_spacing, 1.2f)
|
||||
WARG(bool, warp_text, false)
|
||||
@@ -45,5 +45,5 @@ private:
|
||||
text_layout_t layout_{};
|
||||
std::u32string text_; // 最终显示的文本
|
||||
std::u32string temp_text_; // 当前输入的文本
|
||||
std::shared_ptr<font_face_interface> font_;
|
||||
font_face_ptr font_;
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ class font_face_interface;
|
||||
|
||||
struct text_block_args {
|
||||
WARG(std::u32string, text, {})
|
||||
WARG(std::shared_ptr<font_face_interface>, font, {})
|
||||
WARG(font_face_ptr, font, {})
|
||||
WARG(float, font_size, 24.f)
|
||||
WARG(float, line_spacing, 1.2f)
|
||||
WARG(bool, warp_text, false)
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
update_no_wrap_size();
|
||||
}
|
||||
|
||||
void set_font(const std::shared_ptr<font_face_interface>& in_font) {
|
||||
void set_font(const font_face_ptr& in_font) {
|
||||
font_ = in_font;
|
||||
update_no_wrap_size();
|
||||
}
|
||||
@@ -53,5 +53,5 @@ private:
|
||||
float font_size_ = .0f;
|
||||
float line_spacing_ = 1.f;
|
||||
bool warp_text_ = false;
|
||||
std::shared_ptr<font_face_interface> font_;
|
||||
font_face_ptr font_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user