From ca057090791f0ad8de1769feba9f03db02de6988 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 25 Jan 2025 08:19:33 -0800
Subject: [PATCH] Allow each glyph to come from a different font face
---
include/SDL3_ttf/SDL_textengine.h | 3 ++-
src/SDL_gpu_textengine.c | 3 ++-
src/SDL_renderer_textengine.c | 3 ++-
src/SDL_surface_textengine.c | 10 +++++-----
src/SDL_ttf.c | 31 +++++++++++++++++++------------
5 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/include/SDL3_ttf/SDL_textengine.h b/include/SDL3_ttf/SDL_textengine.h
index 287809f8..78e34c46 100644
--- a/include/SDL3_ttf/SDL_textengine.h
+++ b/include/SDL3_ttf/SDL_textengine.h
@@ -79,7 +79,8 @@ typedef struct TTF_CopyOperation
later. In this case the glyphs and codepoints are grouped
together and the group bounding box is the union of the dst
rectangles for the corresponding glyphs. */
- Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphForIndex() */
+ TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
+ Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
SDL_Rect src; /**< The area within the glyph to be drawn */
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
void *reserved;
diff --git a/src/SDL_gpu_textengine.c b/src/SDL_gpu_textengine.c
index 16eab888..35c05742 100644
--- a/src/SDL_gpu_textengine.c
+++ b/src/SDL_gpu_textengine.c
@@ -505,6 +505,7 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
for (int i = 0; i < num_ops; ++i) {
TTF_DrawOperation *op = &ops[i];
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
+ TTF_Font *glyph_font = op->copy.glyph_font;
Uint32 glyph_index = op->copy.glyph_index;
if (SDL_FindInHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
continue;
@@ -513,7 +514,7 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
goto done;
}
- surfaces[i] = TTF_GetGlyphImageForIndex(fontdata->font, glyph_index);
+ surfaces[i] = TTF_GetGlyphImageForIndex(glyph_font, glyph_index);
if (!surfaces[i]) {
goto done;
}
diff --git a/src/SDL_renderer_textengine.c b/src/SDL_renderer_textengine.c
index 7eef5829..3ff42e1f 100644
--- a/src/SDL_renderer_textengine.c
+++ b/src/SDL_renderer_textengine.c
@@ -439,6 +439,7 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
for (int i = 0; i < num_ops; ++i) {
TTF_DrawOperation *op = &ops[i];
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
+ TTF_Font *glyph_font = op->copy.glyph_font;
Uint32 glyph_index = op->copy.glyph_index;
if (SDL_FindInHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
continue;
@@ -447,7 +448,7 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
goto done;
}
- surfaces[i] = TTF_GetGlyphImageForIndex(fontdata->font, glyph_index);
+ surfaces[i] = TTF_GetGlyphImageForIndex(glyph_font, glyph_index);
if (!surfaces[i]) {
goto done;
}
diff --git a/src/SDL_surface_textengine.c b/src/SDL_surface_textengine.c
index e5d313f3..5f1a3565 100644
--- a/src/SDL_surface_textengine.c
+++ b/src/SDL_surface_textengine.c
@@ -80,12 +80,12 @@ static TTF_SurfaceTextEngineGlyphData *CreateGlyphData(SDL_Surface *surface)
return data;
}
-static TTF_SurfaceTextEngineGlyphData *GetGlyphData(TTF_SurfaceTextEngineFontData *fontdata, Uint32 idx)
+static TTF_SurfaceTextEngineGlyphData *GetGlyphData(TTF_SurfaceTextEngineFontData *fontdata, TTF_Font *glyph_font, Uint32 glyph_index)
{
TTF_SurfaceTextEngineGlyphData *data;
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)idx, (const void **)&data)) {
- SDL_Surface *surface = TTF_GetGlyphImageForIndex(fontdata->font, idx);
+ if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, (const void **)&data)) {
+ SDL_Surface *surface = TTF_GetGlyphImageForIndex(glyph_font, glyph_index);
if (!surface) {
return NULL;
}
@@ -95,7 +95,7 @@ static TTF_SurfaceTextEngineGlyphData *GetGlyphData(TTF_SurfaceTextEngineFontDat
return NULL;
}
- if (!SDL_InsertIntoHashTable(fontdata->glyphs, (const void *)(uintptr_t)idx, data)) {
+ if (!SDL_InsertIntoHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, data)) {
DestroyGlyphData(data);
return NULL;
}
@@ -140,7 +140,7 @@ static TTF_SurfaceTextEngineTextData *CreateTextData(TTF_SurfaceTextEngineFontDa
for (int i = 0; i < data->num_ops; ++i) {
TTF_DrawOperation *op = &data->ops[i];
if (op->cmd == TTF_DRAW_COMMAND_COPY) {
- TTF_SurfaceTextEngineGlyphData *glyph = GetGlyphData(fontdata, op->copy.glyph_index);
+ TTF_SurfaceTextEngineGlyphData *glyph = GetGlyphData(fontdata, op->copy.glyph_font, op->copy.glyph_index);
if (!glyph) {
DestroyTextData(data);
return NULL;
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index 4290fe48..73a8c31c 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -218,6 +218,7 @@ typedef struct cached_glyph {
/* Internal buffer to store positions computed by TTF_Size_Internal()
* for rendered string by Render_Line() */
typedef struct PosBuf {
+ TTF_Font *font;
FT_UInt index;
int x;
int y;
@@ -1173,12 +1174,13 @@ static bool Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart,
int i; \
Uint8 fg_alpha = (fg ? fg->a : 0); \
for (i = 0; i < font->pos_len; i++) { \
+ TTF_Font *glyph_font = font->pos_buf[i].font; \
FT_UInt idx = font->pos_buf[i].index; \
- int x = font->pos_buf[i].x; \
- int y = font->pos_buf[i].y; \
+ int x = font->pos_buf[i].x; \
+ int y = font->pos_buf[i].y; \
TTF_Image *image; \
\
- if (Find_GlyphByIndex(font, idx, WB_WP_WC, WS, x & 63, NULL, &image)) { \
+ if (Find_GlyphByIndex(glyph_font, idx, WB_WP_WC, WS, x & 63, NULL, &image)) { \
int above_w, above_h; \
Uint32 dstskip; \
Sint32 srcskip; /* Can be negative */ \
@@ -1435,13 +1437,14 @@ static bool Render_Line_TextEngine(TTF_Font *font, int xstart, int ystart, int w
bounds.h = font->height;
for (i = 0; i < font->pos_len; i++) {
+ TTF_Font *glyph_font = font->pos_buf[i].font;
FT_UInt idx = font->pos_buf[i].index;
- int x = font->pos_buf[i].x;
- int y = font->pos_buf[i].y;
- int offset = font->pos_buf[i].offset;
+ int x = font->pos_buf[i].x;
+ int y = font->pos_buf[i].y;
+ int offset = font->pos_buf[i].offset;
c_glyph *glyph;
- if (Find_GlyphByIndex(font, idx, 0, 0, 0, 0, 0, 0, &glyph, NULL)) {
+ if (Find_GlyphByIndex(glyph_font, idx, 0, 0, 0, 0, 0, 0, &glyph, NULL)) {
int above_w, above_h;
int glyph_x = 0;
int glyph_y = 0;
@@ -1480,6 +1483,7 @@ static bool Render_Line_TextEngine(TTF_Font *font, int xstart, int ystart, int w
op = &ops[op_index++];
op->cmd = TTF_DRAW_COMMAND_COPY;
op->copy.text_offset = offset;
+ op->copy.glyph_font = glyph_font;
op->copy.glyph_index = idx;
op->copy.src.x = glyph_x;
op->copy.src.y = glyph_y;
@@ -3093,6 +3097,7 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
// Load and render each character
int offset = 0;
for (g = 0; g < glyph_count; g++) {
+ TTF_Font *glyph_font = font;
FT_UInt idx = hb_glyph_info[g].codepoint;
int x_advance = hb_glyph_position[g].x_advance;
int y_advance = hb_glyph_position[g].y_advance;
@@ -3107,7 +3112,8 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
while (length > 0) {
offset = (int)(text - start);
Uint32 c = SDL_StepUTF8(&text, &length);
- FT_UInt idx = get_char_index(font, c);
+ TTF_Font *glyph_font = font;
+ FT_UInt idx = get_char_index(glyph_font, c);
if (c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED) {
continue;
@@ -3117,7 +3123,7 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
--length;
}
#endif
- if (!Find_GlyphByIndex(font, idx, 0, 0, 0, 0, 0, 0, &glyph, NULL)) {
+ if (!Find_GlyphByIndex(glyph_font, idx, 0, 0, 0, 0, 0, 0, &glyph, NULL)) {
goto failure;
}
@@ -3136,7 +3142,7 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
#if TTF_USE_HARFBUZZ
// Compute positions
- pos_x = x + x_offset;
+ pos_x = x + x_offset;
pos_y = y + F26Dot6(font->ascent) - y_offset;
x += x_advance + advance_if_bold;
y += y_advance;
@@ -3147,7 +3153,7 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
if (font->use_kerning) {
if (prev_index && glyph->index) {
FT_Vector delta;
- FT_Get_Kerning(font->face, prev_index, glyph->index, FT_KERNING_UNFITTED, &delta);
+ FT_Get_Kerning(glyph_font->face, prev_index, glyph->index, FT_KERNING_UNFITTED, &delta);
x += delta.x;
}
prev_index = glyph->index;
@@ -3177,9 +3183,10 @@ static bool TTF_Size_Internal(TTF_Font *font, const char *text, size_t length, i
pos_y = F26Dot6(font->ascent);
#endif
// Store things for Render_Line()
+ font->pos_buf[font->pos_len].font = glyph_font;
+ font->pos_buf[font->pos_len].index = idx;
font->pos_buf[font->pos_len].x = pos_x;
font->pos_buf[font->pos_len].y = pos_y;
- font->pos_buf[font->pos_len].index = idx;
font->pos_buf[font->pos_len].offset = offset;
font->pos_len += 1;