blob: 9e40f29b6cb9f3e523fe364167dc978e5ec408b8 [file]
/*
* Copyright 2026 Behdad Esfahbod. All Rights Reserved.
*/
#include "demo-font.h"
#include "demo-atlas.h"
#include "../helper-extents-overlay.hh"
#include <hb-ot.h>
#include <map>
typedef std::map<unsigned int, glyph_info_t> glyph_cache_t;
struct demo_font_t {
hb_face_t *face;
hb_font_t *font;
glyph_cache_t *glyph_cache;
demo_atlas_t *atlas;
hb_gpu_paint_t *p;
hb_gpu_draw_t *d;
bool draw_only;
bool show_extents;
unsigned int num_glyphs;
unsigned int sum_bytes;
};
demo_font_t *
demo_font_create (hb_font_t *hb_font,
demo_atlas_t *atlas,
hb_bool_t draw_only)
{
demo_font_t *font = (demo_font_t *) calloc (1, sizeof (demo_font_t));
font->face = hb_face_reference (hb_font_get_face (hb_font));
font->font = hb_font_reference (hb_font);
font->glyph_cache = new glyph_cache_t ();
font->atlas = demo_atlas_reference (atlas);
font->draw_only = draw_only;
if (draw_only)
font->d = hb_gpu_draw_create_or_fail ();
else
font->p = hb_gpu_paint_create_or_fail ();
return font;
}
void
demo_font_destroy (demo_font_t *font)
{
if (!font)
return;
hb_gpu_paint_destroy (font->p);
hb_gpu_draw_destroy (font->d);
demo_atlas_destroy (font->atlas);
delete font->glyph_cache;
hb_font_destroy (font->font);
hb_face_destroy (font->face);
free (font);
}
hb_face_t *
demo_font_get_face (demo_font_t *font)
{
return font->face;
}
hb_font_t *
demo_font_get_font (demo_font_t *font)
{
return font->font;
}
void
demo_font_set_show_extents (demo_font_t *font, hb_bool_t show)
{
bool b = !!show;
if (font->show_extents == b) return;
font->show_extents = b;
demo_font_clear_cache (font);
}
void
demo_font_set_palette (demo_font_t *font, unsigned palette_index)
{
if (font->draw_only)
return;
hb_gpu_paint_set_palette (font->p, palette_index);
demo_font_clear_cache (font);
}
void
demo_font_clear_custom_palette_colors (demo_font_t *font)
{
if (font->draw_only)
return;
hb_gpu_paint_clear_custom_palette_colors (font->p);
demo_font_clear_cache (font);
}
hb_bool_t
demo_font_set_custom_palette_color (demo_font_t *font,
unsigned int color_index,
hb_color_t color)
{
if (font->draw_only)
return false;
hb_bool_t ok = hb_gpu_paint_set_custom_palette_color (font->p, color_index, color);
demo_font_clear_cache (font);
return ok;
}
static void
_demo_font_upload_glyph (demo_font_t *font,
unsigned int glyph_index,
glyph_info_t *glyph_info)
{
hb_glyph_extents_t hb_ext = {};
hb_blob_t *blob;
int x_scale, y_scale;
hb_font_get_scale (font->font, &x_scale, &y_scale);
float sw = (float) (x_scale * 0.01);
if (font->draw_only)
{
hb_gpu_draw_clear (font->d);
hb_gpu_draw_glyph (font->d, font->font, glyph_index);
if (font->show_extents)
{
hb_glyph_extents_t g;
if (hb_font_get_glyph_extents (font->font, glyph_index, &g))
util_emit_extents_overlay_into_draw (
hb_gpu_draw_get_funcs (font->d), font->d,
&g, /*pen_x*/ 0.f, /*pen_y*/ 0.f, sw);
}
blob = hb_gpu_draw_encode (font->d, &hb_ext);
}
else
{
hb_gpu_paint_clear (font->p);
hb_gpu_paint_glyph (font->p, font->font, glyph_index);
if (font->show_extents)
{
hb_glyph_extents_t g;
if (hb_font_get_glyph_extents (font->font, glyph_index, &g))
util_emit_extents_overlay_into_paint (
hb_gpu_paint_get_funcs (font->p), font->p,
&g, /*pen_x*/ 0.f, /*pen_y*/ 0.f, sw);
}
blob = hb_gpu_paint_encode (font->p, &hb_ext);
}
unsigned int len = blob ? hb_blob_get_length (blob) : 0;
glyph_info->extents.min_x = hb_ext.x_bearing;
glyph_info->extents.max_x = hb_ext.x_bearing + hb_ext.width;
glyph_info->extents.max_y = hb_ext.y_bearing;
glyph_info->extents.min_y = hb_ext.y_bearing + hb_ext.height;
glyph_info->advance = hb_font_get_glyph_h_advance (font->font, glyph_index);
glyph_info->upem = y_scale;
glyph_info->is_empty = (len == 0);
if (!glyph_info->is_empty)
glyph_info->atlas_offset = demo_atlas_alloc (font->atlas,
hb_blob_get_data (blob, NULL),
len);
font->num_glyphs++;
font->sum_bytes += len;
if (blob)
{
if (font->draw_only)
hb_gpu_draw_recycle_blob (font->d, blob);
else
hb_gpu_paint_recycle_blob (font->p, blob);
}
}
void
demo_font_lookup_glyph (demo_font_t *font,
unsigned int glyph_index,
glyph_info_t *glyph_info)
{
if (font->glyph_cache->find (glyph_index) == font->glyph_cache->end ()) {
_demo_font_upload_glyph (font, glyph_index, glyph_info);
(*font->glyph_cache)[glyph_index] = *glyph_info;
} else
*glyph_info = (*font->glyph_cache)[glyph_index];
}
void
demo_font_clear_cache (demo_font_t *font)
{
font->glyph_cache->clear ();
font->num_glyphs = 0;
font->sum_bytes = 0;
}
void
demo_font_print_stats (demo_font_t *font)
{
double atlas_used_kb = demo_atlas_get_used (font->atlas) * 8 / 1024.;
if (!font->num_glyphs)
return;
LOGI ("%3u glyphs; avg %5.2fkb per glyph; atlas used %5.2fkb\n",
font->num_glyphs,
font->sum_bytes / 1024. / font->num_glyphs,
atlas_used_kb);
}