#include #include "ttf_internal.h" #include #include #include // Per-glyph scratch — kept static to avoid stack pressure for big Chinese glyphs static ttf_outline_t s_outline; static ttf_seg_t s_segs[4096]; static SUINT8 s_coverage[256 * 256]; // Render one glyph bitmap at screen (px, py) where py is the glyph TOP // (already converted from baseline). (px, py) may be negative — caller // must have clipped into the visible region. static void blit_glyph(SSINT32 px, SSINT32 py, SUINT32 w, SUINT32 h, const SUINT8* coverage, SUINT32 N, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) { SUINT32 scale = 255 / N; for (SUINT32 y = 0; y < h; y++) { SSINT32 sy = py + (SSINT32)y; if (sy < 0) continue; for (SUINT32 x = 0; x < w; x++) { SSINT32 sx = px + (SSINT32)x; if (sx < 0) continue; SUINT8 c = coverage[y * w + x]; if (c == 0) continue; SUINT8 a = (SUINT8)(c * scale); draw_pixel_alpha(sx, sy, color, a); } } } // Render a single codepoint at (x, y) = baseline. Returns advance (26.6). static f26_6 render_codepoint(ttf_face_t* face, SSINT32 cp, SSINT32 x, SSINT32 y, SUINT32 pixel_size, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) { SUINT16 gid = ttf_cmap_lookup(face, cp); if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) { return 0; // composite / parse error } // Bitmap dims in pixels SSINT32 bbox_w = s_outline.xmax - s_outline.xmin; SSINT32 bbox_h = s_outline.ymax - s_outline.ymin; if (bbox_w <= 0 || bbox_h <= 0) { return s_outline.advance; // whitespace or zero-size } SUINT32 pw = (SUINT32)((bbox_w + 63) >> 6); SUINT32 ph = (SUINT32)((bbox_h + 63) >> 6); if (pw > 256 || ph > 256) { return s_outline.advance; // too big for scratch } // Translate outline to bitmap-local: bx = fx - xmin, by = ymax - fy ttf_outline_t local; local.num_points = s_outline.num_points; local.num_contours = s_outline.num_contours; for (SUINT16 i = 0; i < s_outline.num_contours; i++) { local.first[i] = s_outline.first[i]; local.last[i] = s_outline.last[i]; } for (SUINT16 i = 0; i < s_outline.num_points; i++) { local.x[i] = s_outline.x[i] - s_outline.xmin; local.y[i] = s_outline.ymax - s_outline.y[i]; local.on_curve[i] = s_outline.on_curve[i]; } local.xmin = 0; local.ymin = 0; local.xmax = bbox_w; local.ymax = bbox_h; SUINT32 n_segs = 0; ttf_outline_to_segments(&local, s_segs, &n_segs); // Clear coverage for (SUINT32 i = 0; i < pw * ph; i++) s_coverage[i] = 0; const SUINT32 N = 5; // subsamples per pixel row ttf_rasterize(s_segs, n_segs, 0, 0, pw, ph, s_coverage, N); // Screen origin of bitmap SSINT32 px_screen = x + (s_outline.xmin >> 6); SSINT32 py_screen = y - (s_outline.ymax >> 6); blit_glyph(px_screen, py_screen, pw, ph, s_coverage, N, color); return s_outline.advance; } SSINT32 ttf_draw_text(ttf_face_t* face, const char* utf8, SSINT32 x, SSINT32 y, SUINT32 pixel_size, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) { if (!face || !utf8) return 0; const char* p = utf8; f26_6 pen = 0; while (*p) { SSINT32 cp = ttf_utf8_decode(&p); if (cp < 0) continue; f26_6 adv = render_codepoint(face, cp, x + (pen >> 6), y, pixel_size, color); pen += adv; } return pen; } SSINT32 ttf_text_width(ttf_face_t* face, const char* utf8, SUINT32 pixel_size) { if (!face || !utf8) return 0; const char* p = utf8; f26_6 pen = 0; while (*p) { SSINT32 cp = ttf_utf8_decode(&p); if (cp < 0) continue; SUINT16 gid = ttf_cmap_lookup(face, cp); if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) continue; pen += s_outline.advance; } return pen; }