diff --git a/src/mirage_render/src/font/font_system.cpp b/src/mirage_render/src/font/font_system.cpp index a095847..da74862 100644 --- a/src/mirage_render/src/font/font_system.cpp +++ b/src/mirage_render/src/font/font_system.cpp @@ -61,9 +61,6 @@ std::shared_ptr font_manager::get_font_for_code_point(uint3 return primary; } -/** - * @brief 布局文本,将Unicode文本转换为可渲染的字形布局 - */ text_layout_t font_manager::layout_text( const std::u32string& text, const std::shared_ptr& in_font, @@ -79,25 +76,27 @@ text_layout_t font_manager::layout_text( primary_font->set_font_size(font_size); // 初始化布局变量 - float cursor_x = 0.0f; - float cursor_y = 0.0f; - float width = 0.0f; - float height = 0.0f; - uint32_t prev_glyph_id = 0; // 上一个字形索引 + float cursor_x = 0.0f; // 当前光标X位置 + float cursor_y = 0.0f; // 当前光标Y位置 + float width = 0.0f; // 总布局宽度 + float height = 0.0f; // 总布局高度 + uint32_t prev_glyph_id = 0; // 上一个字形ID(用于字距调整) // 当前行信息 struct line_info { - float height = 0.0f; // 行总高度 - float ascent = 0.0f; // 最大上升距离 - float descent = 0.0f; // 最大下降距离 - float line_width = 0.0f; // 行宽度 - bool has_content = false; + float height = 0.0f; // 行总高度 + float ascent = 0.0f; // 最大上升距离 + float descent = 0.0f; // 最大下降距离 + float line_width = 0.0f; // 行宽度 + bool has_content = false; // 标记行是否有内容 }; line_info current_line; - // 完成当前行的布局 - auto finish_line = [&] { + /** + * @brief 完成当前行的布局并准备下一行 + */ + auto finish_line = [&]() { if (current_line.has_content) { // 更新总体尺寸 width = std::max(width, current_line.line_width); @@ -112,28 +111,30 @@ text_layout_t font_manager::layout_text( } }; - // 处理每个字符 - for (const auto& c : text) { - // 检查是否是换行符 + /** + * @brief 处理单个字符的布局 + * + * @param c 要处理的Unicode字符 + */ + auto process_character = [&](const char32_t c) { + // 处理换行符 if (c == U'\n') { finish_line(); - continue; + return; } // 检查是否是表情符号 const bool is_emoji = emoji_detector::is_emoji(c); - // 当前使用的字体,开始时使用主字体 + // 查找能够渲染此字符的字体 auto using_font = primary_font; - - // 获取字形索引 auto glyph_index = using_font->find_glyph_index(c); - // 如果当前字体不支持该字符,尝试查找支持该字符的其他字体 + // 如果主字体不支持该字符,则尝试查找其他字体 if (glyph_index == 0) { using_font = get_font_for_code_point(c); if (!using_font) { - continue; // 如果没有找到支持的字体,跳过该字符 + return; // 如果没有找到支持的字体,跳过该字符 } // 使用新字体重新获取字形索引 @@ -146,17 +147,21 @@ text_layout_t font_manager::layout_text( // 获取当前字体的度量信息 const auto& current_metrics = using_font->get_metrics(); - // 获取字形度量信息 + // 获取字形度量信息(形状、尺寸、间距等) 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; // 如果无法在图集中获取或创建字形,跳过该字符 + return; // 如果无法获取或创建字形区域,跳过该字符 } - // 检查是否需要换行 - if (max_width > 0 && cursor_x + glyph_metrics.advance.x() > max_width && current_line.has_content) { + // 检查是否需要自动换行 + if (max_width > 0 && + cursor_x + glyph_metrics.advance.x() > max_width && + current_line.has_content) { finish_line(); } @@ -166,38 +171,45 @@ text_layout_t font_manager::layout_text( // 更新当前行的度量信息 current_line.ascent = std::max(current_line.ascent, current_metrics.ascent); current_line.descent = std::min(current_line.descent, current_metrics.descent); + current_line.height = std::max(current_line.height, current_metrics.line_height); - // 使用字体的行高 - current_line.height = std::max(current_line.height, current_metrics.line_height); - - // 计算基线位置 - 使用当前行的上升距离 + // 计算基线位置 - 基于当前行的上升距离 float baseline = cursor_y + current_line.ascent; - // 计算字形坐标 + // 计算字形绘制坐标 float x = cursor_x + glyph_metrics.hori_bearing.x(); float y = baseline + glyph_metrics.hori_bearing.y(); // 添加字形位置信息到布局 - 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.region = *region; + 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.region = *region; + + // 更新当前行宽度 + current_line.line_width += glyph_metrics.advance.x(); - current_line.line_width += glyph_metrics.advance.x(); // 更新当前行宽度 // 更新光标位置 - cursor_x += glyph_metrics.advance.x(); // 添加字形间距 + cursor_x += glyph_metrics.advance.x(); - if (prev_glyph_id != 0) { - // 添加字形间距 - cursor_x += using_font->get_kerning(prev_glyph_id, glyph_index); - } + // 应用字距调整(kerning) + if (prev_glyph_id != 0) { + cursor_x += using_font->get_kerning(prev_glyph_id, glyph_index); + } - prev_glyph_id = glyph_index; // 更新上一个字形索引 + // 更新上一个字形索引 + prev_glyph_id = glyph_index; + }; + + // 处理每个字符 + for (const auto& c : text) { + process_character(c); } - height += current_line.descent; // 最后一行需要减去下降高度 + // 考虑最后一行的下降部分 + height -= std::abs(current_line.descent); // 处理最后一行 finish_line(); @@ -208,6 +220,7 @@ text_layout_t font_manager::layout_text( return layout; } + /** * @brief 获取或创建字形在图集中的区域 */ diff --git a/src/mirage_render/src/font/font_system.h b/src/mirage_render/src/font/font_system.h index 2ae8bc9..e53d0fe 100644 --- a/src/mirage_render/src/font/font_system.h +++ b/src/mirage_render/src/font/font_system.h @@ -97,18 +97,16 @@ public: return !emoji_font_ids_.empty(); } - /** - * @brief 布局文本 - * - * 将Unicode文本转换为可渲染的字形布局,包括位置计算和换行处理。 - * - * @param text Unicode文本 - * @param in_font 指定字体,如为空则使用主字体 - * @param font_size 字体大小 - * @param max_width 最大宽度,超过此宽度会自动换行,0表示不限制宽度 - * @param line_spacing 行间距系数 - * @return 文本布局结果 - */ + /** + * @brief 计算文本布局,确定每个字形的位置和大小 + * + * @param text 要布局的Unicode文本 + * @param in_font 指定的字体(如果为nullptr则使用主字体) + * @param font_size 字体大小(像素单位) + * @param max_width 文本的最大宽度(用于自动换行,0表示不限制宽度) + * @param line_spacing 行间距因子(1.0表示标准行距) + * @return text_layout_t 包含所有字形位置和布局信息的结构 + */ text_layout_t layout_text( const std::u32string& text, const std::shared_ptr& in_font,