text: Allow x-adjusted glyph rendering, for better kerning in caches

This commit is contained in:
K. Lange 2022-08-22 13:36:30 +09:00
parent 1349d1a2e0
commit af69cd6369
3 changed files with 23 additions and 17 deletions

View File

@ -20,7 +20,7 @@ extern void tt_draw_glyph(gfx_context_t * ctx, struct TT_Font * font, int x_offs
extern int tt_glyph_for_codepoint(struct TT_Font * font, unsigned int codepoint);
extern int tt_xadvance_for_glyph(struct TT_Font * font, unsigned int ind);
extern float tt_glyph_width(struct TT_Font * font, unsigned int glyph);
extern sprite_t * tt_bake_glyph(struct TT_Font * font, unsigned int glyph, uint32_t color, int *_x, int *_y);
extern sprite_t * tt_bake_glyph(struct TT_Font * font, unsigned int glyph, uint32_t color, int *_x, int *_y, float xadjust);
/* Convenience functions for dealing with whole strings */
extern int tt_string_width(struct TT_Font * font, const char * s);

View File

@ -6,6 +6,7 @@
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2021 K. Lange
*/
#include <math.h>
#include <toaru/markup.h>
#include <toaru/list.h>
#include <toaru/graphics.h>
@ -131,50 +132,55 @@ static int sizeForState(struct MarkupState * state) {
struct GlyphCacheEntry {
struct TT_Font * font;
sprite_t * sprite;
sprite_t * sprites[3];
int xs[3];
uint32_t size;
uint32_t glyph;
uint32_t color;
int x;
int y;
};
static struct GlyphCacheEntry glyph_cache[1024];
static void draw_cached_glyph(gfx_context_t * ctx, struct TT_Font * _font, uint32_t size, int x, int y, uint32_t glyph, uint32_t fg) {
static void draw_cached_glyph(gfx_context_t * ctx, struct TT_Font * _font, uint32_t size, int x, int y, uint32_t glyph, uint32_t fg, float xadj) {
unsigned int hash = (((uintptr_t)_font >> 8) ^ (glyph * size)) & 1023;
struct GlyphCacheEntry * entry = &glyph_cache[hash];
if (entry->font != _font || entry->size != size || entry->glyph != glyph) {
if (entry->sprite) sprite_free(entry->sprite);
if (entry->sprites[0]) sprite_free(entry->sprites[0]);
if (entry->sprites[1]) sprite_free(entry->sprites[1]);
if (entry->sprites[2]) sprite_free(entry->sprites[2]);
tt_set_size(_font, size);
entry->font = _font;
entry->size = size;
entry->glyph = glyph;
entry->color = _ALP(fg) == 255 ? fg : rgb(0,0,0);
entry->sprite = tt_bake_glyph(entry->font, entry->glyph, entry->color, &entry->x, &entry->y);
entry->sprites[0] = tt_bake_glyph(entry->font, entry->glyph, entry->color, &entry->xs[0], &entry->y, 0.0);
entry->sprites[1] = tt_bake_glyph(entry->font, entry->glyph, entry->color, &entry->xs[1], &entry->y, 0.333);
entry->sprites[2] = tt_bake_glyph(entry->font, entry->glyph, entry->color, &entry->xs[2], &entry->y, 0.666);
}
if (entry->sprite) {
if (entry->sprites[0]) {
int sprite = xadj < 0.166 ? 0 : xadj < 0.5 ? 1 : 2;
if (entry->color != fg) {
draw_sprite_alpha_paint(ctx, entry->sprite, x + entry->x, y + entry->y, 1.0, fg);
draw_sprite_alpha_paint(ctx, entry->sprites[sprite], x + entry->xs[sprite], y + entry->y, 1.0, fg);
} else {
draw_sprite(ctx, entry->sprite, x + entry->x, y + entry->y);
draw_sprite(ctx, entry->sprites[sprite], x + entry->xs[sprite], y + entry->y);
}
}
}
static int string_draw_internal(gfx_context_t * ctx, struct TT_Font * font, int font_size, int x, int y, char * data, uint32_t color) {
int x_offset = x;
float x_offset = x;
uint32_t cp = 0;
uint32_t istate = 0;
for (const unsigned char * c = (const unsigned char*)data; *c; ++c) {
if (!decode(&istate, &cp, *c)) {
unsigned int glyph = tt_glyph_for_codepoint(font, cp);
draw_cached_glyph(ctx, font, font_size, x_offset, y, glyph, color);
draw_cached_glyph(ctx, font, font_size, (int)floor(x_offset), y, glyph, color, x_offset-floor(x_offset));
x_offset += tt_glyph_width(font, glyph);
}
}
@ -196,7 +202,7 @@ static int parser_dryrun(struct markup_state * self, void * user, char * data) {
struct MarkupState * state = (struct MarkupState*)user;
struct TT_Font * font = fontForState(state);
tt_set_size(font, sizeForState(state));
state->cursor_x += tt_string_width_int(font, data);
state->cursor_x += tt_string_width(font, data);
if (state->cursor_x > state->max_cursor_x) state->max_cursor_x = state->cursor_x;
return 0;
}

View File

@ -682,9 +682,9 @@ static struct TT_Contour * tt_draw_glyph_into(struct TT_Contour * contour, struc
return contour;
}
sprite_t * tt_bake_glyph(struct TT_Font * font, unsigned int glyph, uint32_t color, int *_x, int *_y) {
sprite_t * tt_bake_glyph(struct TT_Font * font, unsigned int glyph, uint32_t color, int *_x, int *_y, float xadjust) {
struct TT_Contour * contour = tt_contour_start(0, 0);
contour = tt_draw_glyph_into(contour,font,100,100,glyph);
contour = tt_draw_glyph_into(contour,font,100+xadjust,100,glyph);
if (!contour->edgeCount) {
*_x = 0;
*_y = 0;
@ -694,11 +694,11 @@ sprite_t * tt_bake_glyph(struct TT_Font * font, unsigned int glyph, uint32_t col
/* Calculate bounds to render a sprite */
struct TT_Shape * shape = tt_contour_finish(contour);
int width = shape->lastX - shape->startX + 2;
int width = shape->lastX - shape->startX + 3;
int height = shape->lastY - shape->startY + 2;
int off_x = shape->startX - 2; shape->startX -= off_x; shape->lastX -= off_x;
int off_y = shape->startY - 2; shape->startY -= off_y; shape->lastY -= off_y;
int off_x = shape->startX - 1; shape->startX -= off_x; shape->lastX -= off_x;
int off_y = shape->startY - 1; shape->startY -= off_y; shape->lastY -= off_y;
/* Adjust the entire shape */
for (size_t i = 0; i < shape->edgeCount; ++i) {