TTF渲染 #4
@@ -37,7 +37,6 @@ static f26_6 render_codepoint(ttf_face_t* face, SSINT32 cp,
|
|||||||
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color)
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color)
|
||||||
{
|
{
|
||||||
SUINT16 gid = ttf_cmap_lookup(face, cp);
|
SUINT16 gid = ttf_cmap_lookup(face, cp);
|
||||||
if (gid == 0 && cp != 0) gid = 0; // notdef
|
|
||||||
|
|
||||||
if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) {
|
if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) {
|
||||||
return 0; // composite / parse error
|
return 0; // composite / parse error
|
||||||
@@ -83,8 +82,6 @@ static f26_6 render_codepoint(ttf_face_t* face, SSINT32 cp,
|
|||||||
ttf_rasterize(s_segs, n_segs, 0, 0, pw, ph, s_coverage, N);
|
ttf_rasterize(s_segs, n_segs, 0, 0, pw, ph, s_coverage, N);
|
||||||
|
|
||||||
// Screen origin of bitmap
|
// Screen origin of bitmap
|
||||||
// bitmap (0, 0) is at font (xmin, ymax) which is at screen
|
|
||||||
// (x + xmin/64, y - ymax/64) since screen y is flipped
|
|
||||||
SSINT32 px_screen = x + (s_outline.xmin >> 6);
|
SSINT32 px_screen = x + (s_outline.xmin >> 6);
|
||||||
SSINT32 py_screen = y - (s_outline.ymax >> 6);
|
SSINT32 py_screen = y - (s_outline.ymax >> 6);
|
||||||
|
|
||||||
|
|||||||
+132
-2
@@ -145,7 +145,137 @@ bool ttf_load_glyph(ttf_face_t* face, SUINT16 glyph_id,
|
|||||||
const SUINT8* g = face->glyf + off0;
|
const SUINT8* g = face->glyf + off0;
|
||||||
SSINT16 numContours = rd16s(g + 0);
|
SSINT16 numContours = rd16s(g + 0);
|
||||||
if (numContours < 0) {
|
if (numContours < 0) {
|
||||||
// Composite — unsupported in v1. Keep advance, no outline.
|
// Composite glyph — parse component records and merge outlines
|
||||||
|
const SUINT8* cp = g + 10;
|
||||||
|
SSINT32 all_xmin = 0x7FFFFFFF, all_ymin = 0x7FFFFFFF;
|
||||||
|
SSINT32 all_xmax = -0x7FFFFFFF, all_ymax = -0x7FFFFFFF;
|
||||||
|
|
||||||
|
// Composite glyph flags (OpenType spec):
|
||||||
|
// 0x0001 = ARG_1_AND_2_ARE_WORDS (16-bit args; else 8-bit)
|
||||||
|
// 0x0002 = ARGS_ARE_XY_VALUES (offsets; else point indices)
|
||||||
|
// 0x0008 = WE_HAVE_A_SCALE
|
||||||
|
// 0x0040 = WE_HAVE_A_2x2
|
||||||
|
// 0x0080 = WE_HAVE_AN_X_AND_Y_SCALE
|
||||||
|
// 0x0020 = MORE_COMPONENTS
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
SUINT16 comp_flags = rd16(cp); cp += 2;
|
||||||
|
SUINT16 comp_glyph = rd16(cp); cp += 2;
|
||||||
|
|
||||||
|
// Read arguments (size depends on ARG_1_AND_2_ARE_WORDS)
|
||||||
|
SSINT32 arg1, arg2;
|
||||||
|
if (comp_flags & 0x0001) {
|
||||||
|
// 16-bit signed words
|
||||||
|
arg1 = rd16s(cp); cp += 2;
|
||||||
|
arg2 = rd16s(cp); cp += 2;
|
||||||
|
} else {
|
||||||
|
// 8-bit signed bytes
|
||||||
|
arg1 = (SSINT8)cp[0];
|
||||||
|
arg2 = (SSINT8)cp[1];
|
||||||
|
cp += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read transform scale if present
|
||||||
|
f26_6 scale = F26_ONE;
|
||||||
|
if (comp_flags & 0x0008) {
|
||||||
|
// WE_HAVE_A_SCALE: 16.16 fixed-point
|
||||||
|
SSINT16 s16 = rd16s(cp); cp += 2;
|
||||||
|
scale = (f26_6)s16; // already in f26.6 from 16.16
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read x/y scale if present
|
||||||
|
f26_6 scaleX = F26_ONE, scaleY = F26_ONE;
|
||||||
|
if (comp_flags & 0x0080) {
|
||||||
|
// WE_HAVE_AN_X_AND_Y_SCALE: two 16.16 values
|
||||||
|
SSINT16 sx16 = rd16s(cp); cp += 2;
|
||||||
|
SSINT16 sy16 = rd16s(cp); cp += 2;
|
||||||
|
scaleX = (f26_6)sx16;
|
||||||
|
scaleY = (f26_6)sy16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read 2x2 matrix if present
|
||||||
|
f26_6 m00 = F26_ONE, m01 = 0, m10 = 0, m11 = F26_ONE;
|
||||||
|
if (comp_flags & 0x0040) {
|
||||||
|
// WE_HAVE_A_2x2: four 2.14 values
|
||||||
|
SSINT16 a = rd16s(cp); cp += 2;
|
||||||
|
SSINT16 b = rd16s(cp); cp += 2;
|
||||||
|
SSINT16 c = rd16s(cp); cp += 2;
|
||||||
|
SSINT16 d = rd16s(cp); cp += 2;
|
||||||
|
m00 = (f26_6)(a >> 8); // 2.14 -> 26.6: shift right 8
|
||||||
|
m01 = (f26_6)(b >> 8);
|
||||||
|
m10 = (f26_6)(c >> 8);
|
||||||
|
m11 = (f26_6)(d >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load component glyph
|
||||||
|
ttf_outline_t comp;
|
||||||
|
if (!ttf_load_glyph(face, comp_glyph, pixel_size_px, &comp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Determine if args are offsets (XY values) or point indices
|
||||||
|
SSINT32 offset_x = 0, offset_y = 0;
|
||||||
|
if (comp_flags & 0x0002) {
|
||||||
|
// ARGS_ARE_XY_VALUES: args are pixel offsets (already scaled)
|
||||||
|
// Scale from font units to pixel space like simple glyphs
|
||||||
|
offset_x = (SSINT32)(((SSINT64)arg1 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
|
||||||
|
offset_y = (SSINT32)(((SSINT64)arg2 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform and merge component points
|
||||||
|
for (SUINT16 i = 0; i < comp.num_points; i++) {
|
||||||
|
f26_6 fx = comp.x[i];
|
||||||
|
f26_6 fy = comp.y[i];
|
||||||
|
f26_6 tx, ty;
|
||||||
|
|
||||||
|
if (comp_flags & 0x0040) {
|
||||||
|
// 2x2 matrix transform
|
||||||
|
tx = f26_mul(m00, fx) + f26_mul(m01, fy);
|
||||||
|
ty = f26_mul(m10, fx) + f26_mul(m11, fy);
|
||||||
|
} else if (comp_flags & 0x0008) {
|
||||||
|
// Uniform scale
|
||||||
|
tx = f26_mul(scale, fx);
|
||||||
|
ty = f26_mul(scale, fy);
|
||||||
|
} else if (comp_flags & 0x0080) {
|
||||||
|
// X/Y scale
|
||||||
|
tx = f26_mul(scaleX, fx);
|
||||||
|
ty = f26_mul(scaleY, fy);
|
||||||
|
} else {
|
||||||
|
tx = fx;
|
||||||
|
ty = fy;
|
||||||
|
}
|
||||||
|
|
||||||
|
f26_6 final_x = tx + offset_x;
|
||||||
|
f26_6 final_y = ty + offset_y;
|
||||||
|
|
||||||
|
out->x[out->num_points] = final_x;
|
||||||
|
out->y[out->num_points] = final_y;
|
||||||
|
out->on_curve[out->num_points] = comp.on_curve[i];
|
||||||
|
out->num_points++;
|
||||||
|
if (out->num_points > 1024) return false;
|
||||||
|
|
||||||
|
SSINT32 xi = F26_FLOOR(final_x);
|
||||||
|
SSINT32 yi = F26_FLOOR(final_y);
|
||||||
|
if (xi < all_xmin) all_xmin = xi;
|
||||||
|
if (xi > all_xmax) all_xmax = xi;
|
||||||
|
if (yi < all_ymin) all_ymin = yi;
|
||||||
|
if (yi > all_ymax) all_ymax = yi;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SUINT16 i = 0; i < comp.num_contours; i++) {
|
||||||
|
if (out->num_contours >= 64) return false;
|
||||||
|
out->first[out->num_contours] = (SUINT16)(out->num_points - comp.num_points + comp.first[i]);
|
||||||
|
out->last[out->num_contours] = (SUINT16)(out->num_points - comp.num_points + comp.last[i]);
|
||||||
|
out->num_contours++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(comp_flags & 0x0020)) break; // no more components
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out->num_points == 0) return true;
|
||||||
|
out->xmin = all_xmin;
|
||||||
|
out->ymin = all_ymin;
|
||||||
|
out->xmax = all_xmax;
|
||||||
|
out->ymax = all_ymax;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (numContours == 0) return true;
|
if (numContours == 0) return true;
|
||||||
@@ -173,7 +303,7 @@ bool ttf_load_glyph(ttf_face_t* face, SUINT16 glyph_id,
|
|||||||
flags[pi++] = f;
|
flags[pi++] = f;
|
||||||
if (f & 0x08) {
|
if (f & 0x08) {
|
||||||
SUINT8 rep = *p++;
|
SUINT8 rep = *p++;
|
||||||
for (SUINT16 k = 1; k < rep && pi < numPoints; k++)
|
for (SUINT16 k = 1; k <= rep && pi < numPoints; k++)
|
||||||
flags[pi++] = f;
|
flags[pi++] = f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,6 +193,16 @@ void ttf_rasterize(const ttf_seg_t* segs, SUINT32 num_segs,
|
|||||||
while (j > 0 && xs[j-1] > v) { xs[j] = xs[j-1]; j--; }
|
while (j > 0 && xs[j-1] > v) { xs[j] = xs[j-1]; j--; }
|
||||||
xs[j] = v;
|
xs[j] = v;
|
||||||
}
|
}
|
||||||
|
// Deduplicate: merge intersections within 1 pixel (64 in 26.6)
|
||||||
|
SUINT32 nxd = 0;
|
||||||
|
for (SUINT32 i = 0; i < nxs; i++) {
|
||||||
|
if (nxd > 0 && (xs[i] - xs[nxd - 1]) < 64) {
|
||||||
|
// Near-duplicate — skip to avoid spurious fill slivers
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xs[nxd++] = xs[i];
|
||||||
|
}
|
||||||
|
nxs = nxd;
|
||||||
// Fill alternating pairs
|
// Fill alternating pairs
|
||||||
for (SUINT32 i = 0; i + 1 < nxs; i += 2) {
|
for (SUINT32 i = 0; i + 1 < nxs; i += 2) {
|
||||||
f26_6 xa = xs[i];
|
f26_6 xa = xs[i];
|
||||||
|
|||||||
Reference in New Issue
Block a user