Skip to content

Commit 5eeb967

Browse files
committed
Engine: fixed auto-outline for fonts with glyphs with negative offsets
Some rare fonts may have glyphs that have negative offsets, that is - their leftmost pixels lie to the left from the "pen" position (requested top-left text render coords). We may learn this by reading font's BBox. This commit fixes this problem for the auto-outlining. But the general issue still remains: if such text is positioned too close to the leftmost border of a parent surface (gui control, overlay, etc), then there's a chance that parts of the letter will be cut off. This issue cannot be resolved without displacing text further from its starting draw position. But that may go against text rendering logic, and produce effects unexpected to the user. So I'll leave that for the future consideration.
1 parent 7fa0d6a commit 5eeb967

File tree

6 files changed

+45
-20
lines changed

6 files changed

+45
-20
lines changed

Common/font/fonts.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,14 @@ int get_font_surface_height_outlined(int font_number)
410410
return get_font_height_with_outline(font_number, true /* use surface height */);
411411
}
412412

413-
std::pair<int, int> get_font_surface_extent(int font_number)
413+
std::pair<int, int> get_font_surface_hextent(int font_number)
414+
{
415+
if (!assert_font_number(font_number))
416+
return std::make_pair(0, 0);
417+
return std::make_pair(fonts[font_number].Metrics.BBox.Left, fonts[font_number].Metrics.BBox.Right);
418+
}
419+
420+
std::pair<int, int> get_font_surface_vextent(int font_number)
414421
{
415422
if (!assert_font_number(font_number))
416423
return std::make_pair(0, 0);

Common/font/fonts.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,14 @@ int get_font_height_outlined(int font_number);
7171
int get_font_surface_height(int font_number);
7272
// Gets the surface height of the given font with corresponding outlining
7373
int get_font_surface_height_outlined(int font_number);
74-
// Get font's maximal graphical extent: this means the farthest vertical positions of glyphs,
75-
// relative to the "pen" position. Besides letting to calculate the surface height,
76-
// this information also lets to detect if some of the glyphs may appear above y0.
77-
std::pair<int, int> get_font_surface_extent(int font_number);
74+
// Get font's maximal horizontal extent: this means the farthest horizontal positions
75+
// of any glyph, relative to the "pen" position.
76+
std::pair<int, int> get_font_surface_hextent(int font_number);
77+
// Get font's maximal vertical extent: this means the farthest vertical positions
78+
// of any glyph, relative to the "pen" position. Besides letting to calculate the
79+
// surface height, this information also lets to detect if some of the glyphs may
80+
// appear above y0.
81+
std::pair<int, int> get_font_surface_vextent(int font_number);
7882
// Get font's glyphs max bounding box, in pixels relative to the "pen" position.
7983
Rect get_font_glyph_bbox(int font_number);
8084
// Get font's line spacing

Common/gui/guimain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ Line CalcFontGraphicalVExtent(int font)
864864
// * font's real graphical extent (top and bottom offsets relative to the "pen")
865865
// * custom vertical offset set by user (if non-zero),
866866
const auto finfo = get_fontinfo(font);
867-
const auto fextent = get_font_surface_extent(font);
867+
const auto fextent = get_font_surface_vextent(font);
868868
int top = fextent.first +
869869
std::min(0, finfo.YOffset); // apply YOffset only if negative
870870
int bottom = fextent.second +

Common/libsrc/alfont-2.0.9/alfont.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,14 @@ int alfont_get_font_real_height(ALFONT_FONT *f) {
533533
}
534534

535535
ALFONT_DLL_DECLSPEC void alfont_get_font_bbox(ALFONT_FONT *f, int *left, int *top, int *right, int *bottom) {
536-
*left = f->face_bbox.xmin;
537-
*right = f->face_bbox.xmax;
538-
*top = f->face_bbox.ymax;
539-
*bottom = f->face_bbox.ymin;
536+
if (left)
537+
*left = f->face_bbox.xmin;
538+
if (right)
539+
*right = f->face_bbox.xmax;
540+
if (top)
541+
*top = f->face_bbox.ymax;
542+
if (bottom)
543+
*bottom = f->face_bbox.ymin;
540544
}
541545

542546
ALFONT_DLL_DECLSPEC void alfont_get_charcode_range(ALFONT_FONT *f, int *first_charcode, int *last_charcode, int *num_charcodes) {

Engine/ac/display.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -654,20 +654,27 @@ void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *
654654
color |= makeacol32(0, 0, 0, 0xff);
655655

656656
const int t_width = get_text_width(texx, font);
657-
const auto t_extent = get_font_surface_extent(font);
658-
const int t_height = t_extent.second - t_extent.first + 1;
657+
// Horizontal extent lets us know if any glyphs have negative horizontal offset
658+
const auto t_extent_hor = get_font_surface_hextent(font);
659+
const auto t_extent_ver = get_font_surface_vextent(font);
660+
const int t_height = t_extent_ver.second - t_extent_ver.first + 1;
659661
if (t_width == 0 || t_height == 0)
660662
return;
661663
// Prepare stencils
662-
const int t_yoff = t_extent.first;
664+
const int t_xoff = (t_extent_hor.first < 0 ? t_extent_hor.first : 0);
665+
const int t_yoff = t_extent_ver.first;
663666
Bitmap *texx_stencil, *outline_stencil;
664667
alloc_font_outline_buffers(font, &texx_stencil, &outline_stencil,
665-
t_width, t_height, stencil_cd);
668+
t_width + (-t_xoff) * 2, t_height, stencil_cd);
666669
texx_stencil->ClearTransparent();
667670
outline_stencil->ClearTransparent();
668671
// Ready text stencil
669-
// Note we are drawing with y off, in case some font's glyphs exceed font's ascender
670-
wouttextxy(texx_stencil, 0, -t_yoff, font, color, texx);
672+
// Note we are drawing with x off, in case some glyphs have negative offsets
673+
// and appear further to the left (we create stencil with extra space in that case);
674+
// and y off, in case some font's glyphs exceed font's ascender
675+
// NOTE: t_xoff here will only fix the outline, but this won't resolve e.g. parts
676+
// of leftmost glyph positioned outside of a gui control or an overlay.
677+
wouttextxy(texx_stencil, -t_xoff, -t_yoff, font, color, texx);
671678
// Anti-aliased TTFs require to be alpha-blended, not blit,
672679
// or the alpha values will be plain copied and final image will be broken.
673680
void(Bitmap::*pfn_drawstencil)(const Bitmap *src, int dst_x, int dst_y);
@@ -681,11 +688,12 @@ void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *
681688
pfn_drawstencil = &Bitmap::MaskedBlit;
682689
}
683690

684-
// move start of text so that the outline doesn't drop off the bitmap
685-
xxp += thickness;
691+
// move start of text so that the outline doesn't drop off the bitmap;
692+
// move by glyph offset in case the stencil was drawn with offset
693+
xxp += thickness + t_xoff;
686694
int const outline_y = yyp + t_yoff;
687695
yyp += thickness;
688-
696+
689697
// What we do here: first we paint text onto outline_stencil offsetting vertically;
690698
// then we paint resulting outline_stencil onto final dest offsetting horizontally.
691699
int largest_y_diff_reached_so_far = -1;
@@ -713,6 +721,8 @@ void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *
713721
if (x_diff > 0)
714722
(ds->*pfn_drawstencil)(outline_stencil, xxp + x_diff, outline_y);
715723
}
724+
725+
xxp -= t_xoff; // remove glyph offset from the final text position (keep std text pos)
716726
}
717727

718728
void wouttext_outline(Bitmap *ds, int xxp, int yyp, int font, color_t text_color, color_t outline_color, const char *texx)

Engine/ac/draw.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2414,7 +2414,7 @@ void draw_fps(const Rect &viewport)
24142414
char loop_buffer[128];
24152415
snprintf(loop_buffer, sizeof(loop_buffer), "Loop %u Time %.2f", loopcounter, time_ms * 0.001f);
24162416

2417-
int text_off = get_font_surface_extent(font).first; // TODO: a generic function that accounts for this?
2417+
int text_off = get_font_surface_vextent(font).first; // TODO: a generic function that accounts for this?
24182418
wouttext_outline(fpsDisplay.get(), 1, 1 - text_off, font, text_color, fps_buffer);
24192419
wouttext_outline(fpsDisplay.get(), viewport.GetWidth() / 2, 1 - text_off, font, text_color, loop_buffer);
24202420

0 commit comments

Comments
 (0)