This commit is contained in:
Nanako 2025-04-04 14:02:49 +08:00
parent 0c32af832d
commit c79167eb93
2 changed files with 72 additions and 61 deletions

View File

@ -61,9 +61,6 @@ std::shared_ptr<font_face_interface> 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<font_face_interface>& 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
*/

View File

@ -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<font_face_interface>& in_font,