Chapter 88 · 字体与文本

文本整形

TextShape 将字符串转换为字形序列(GlyphRun),处理连字、字距调整和复杂文字布局。

88

API 速查

函数说明
int xgeTextShape(const xge_text_shape_desc_t* pDesc, xge_glyph_run_t* pRun)文本整形
void xgeGlyphRunFree(xge_glyph_run_t* pRun)释放字形序列
xge_vec2_t xgeGlyphRunMeasure(const xge_glyph_run_t* pRun)测量尺寸
int xgeGlyphRunHitTest(const xge_glyph_run_t* pRun, float fX, float fY, uint32_t* pCluster, int* pTrailing)命中测试

编译本章示例

gcc -O2 -I. -o ch88.exe ch88_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch88.exe

示例:整形与测量

xge_font font = NULL;
xgeFontLoad(&font, "Roboto.ttf", 24.0f);

// 构建整形描述
xge_text_shape_desc_t desc = { 0 };
desc.pFont = font;
desc.sText = "Hello, 世界!";
desc.fFontSize = 24.0f;

// 执行整形
xge_glyph_run_t run;
xgeTextShape(&desc, &run);

// 测量文本尺寸
xge_vec2_t size = xgeGlyphRunMeasure(&run);
// size.x = 宽度, size.y = 高度

// 命中测试(点击位置 → 字符索引)
uint32_t cluster;
int trailing;
xgeGlyphRunHitTest(&run, 50.0f, 12.0f,
    &cluster, &trailing);

// 释放
xgeGlyphRunFree(&run);

完整代码

将以下代码保存为 ch88_main.c,编译后运行即可看到文本整形、测量与命中测试效果:

#include "xge.h"
#include <stdio.h>

static xge_font g_font = NULL;
static xge_glyph_run_t g_run;
static int g_hasRun = 0;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    if (!g_hasRun) return XGE_OK;

    // 测量文本尺寸
    xge_vec2_t size = xgeGlyphRunMeasure(&g_run);

    char buf[256];
    sprintf(buf, "Text size: %.1f x %.1f", size.x, size.y);
    xgeTextDraw(g_font, buf, 20.0f, 20.0f, 0xFFFFFFFF)

    // 绘制整形后的文本
    float baseX = 20.0f, baseY = 80.0f;
    xgeTextDraw(g_font, "Hello, 世界!", baseX, baseY,
        0xFFFFFFFF)

    // 绘制文本包围盒
    xgeShapeRectStroke((xge_rect_t){baseX, baseY, size.x, size.y}, 1.0f, 0x44FF8844)

    // 命中测试:模拟点击 x=50 位置
    uint32_t cluster;
    int trailing;
    if (xgeGlyphRunHitTest(&g_run, 50.0f, 12.0f,
        &cluster, &trailing) == XGE_OK) {
        sprintf(buf, "HitTest(50,12): cluster=%u trailing=%d",
            cluster, trailing);
        xgeTextDraw(g_font, buf, 20.0f, 140.0f,
            0xFF88FF88)
    }

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch88 - Text Shape & HitTest";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xgeFontLoad(&g_font, "Roboto.ttf", 24.0f);

    // 执行文本整形
    xge_text_shape_desc_t desc = { 0 };
    desc.pFont = g_font;
    desc.sText = "Hello, 世界!";
    desc.fFontSize = 24.0f;
    if (xgeTextShape(&desc, &g_run) == XGE_OK)
        g_hasRun = 1;

    xgeRun(onFrame, NULL);

    xgeGlyphRunFree(&g_run);
    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • TextShape:将字符串整形为 GlyphRun,处理连字、字距调整,适合精确排版。
  • GlyphRunMeasure:返回整形后文本的总宽高,用于布局计算。
  • GlyphRunHitTest:将屏幕坐标映射回字符索引(cluster)和前后半(trailing),用于文本编辑光标定位。
  • GlyphRunFree:GlyphRun 内部分配了字形数组内存,程序结束前必须释放。

要点与陷阱

  • 整形 vs 简单绘制:TextShape 处理连字、字距调整,适合精确排版。
  • GlyphRun:包含字形数组、位置、cluster 映射。
  • HitTest:返回 cluster(字符索引)和 trailing(前半/后半)。
  • 必须 Free:GlyphRun 内部分配内存,用完必须释放。

进阶练习

  1. 实现文本选择:HitTest 获取起止字符,高亮选区。
  2. 实现自动换行:按宽度分割 GlyphRun。
文本整形效果
图:文本整形渲染效果