summaryrefslogtreecommitdiffstats
path: root/minuitwrp/truetype.c
diff options
context:
space:
mode:
authorEthan Yonker <dees_troy@teamw.in>2015-12-28 21:54:50 +0100
committerEthan Yonker <dees_troy@teamw.in>2016-01-27 17:53:13 +0100
commitfbb4353a247157d32208f8f133cd1ee42f4fbc49 (patch)
tree6f819fbdd21f2adef4f7ba4a5b4d02054cc02f29 /minuitwrp/truetype.c
parentAdopted Storage support (diff)
downloadandroid_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar.gz
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar.bz2
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar.lz
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar.xz
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.tar.zst
android_bootable_recovery-fbb4353a247157d32208f8f133cd1ee42f4fbc49.zip
Diffstat (limited to 'minuitwrp/truetype.c')
-rw-r--r--minuitwrp/truetype.c816
1 files changed, 0 insertions, 816 deletions
diff --git a/minuitwrp/truetype.c b/minuitwrp/truetype.c
deleted file mode 100644
index d9ed0198b..000000000
--- a/minuitwrp/truetype.c
+++ /dev/null
@@ -1,816 +0,0 @@
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <errno.h>
-#include <stdio.h>
-
-#include "minui.h"
-
-#include <cutils/hashmap.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-
-#include <pixelflinger/pixelflinger.h>
-#include <pthread.h>
-
-#define STRING_CACHE_MAX_ENTRIES 400
-#define STRING_CACHE_TRUNCATE_ENTRIES 150
-
-typedef struct
-{
- int size;
- int dpi;
- char *path;
-} TrueTypeFontKey;
-
-typedef struct
-{
- int type;
- int refcount;
- int size;
- int dpi;
- int max_height;
- int base;
- FT_Face face;
- Hashmap *glyph_cache;
- Hashmap *string_cache;
- struct StringCacheEntry *string_cache_head;
- struct StringCacheEntry *string_cache_tail;
- pthread_mutex_t mutex;
- TrueTypeFontKey *key;
-} TrueTypeFont;
-
-typedef struct
-{
- FT_BBox bbox;
- FT_BitmapGlyph glyph;
-} TrueTypeCacheEntry;
-
-typedef struct
-{
- char *text;
- int max_width;
-} StringCacheKey;
-
-struct StringCacheEntry
-{
- GGLSurface surface;
- int rendered_bytes; // number of bytes from C string rendered, not number of UTF8 characters!
- StringCacheKey *key;
- struct StringCacheEntry *prev;
- struct StringCacheEntry *next;
-};
-
-typedef struct StringCacheEntry StringCacheEntry;
-
-typedef struct
-{
- FT_Library ft_library;
- Hashmap *fonts;
- pthread_mutex_t mutex;
-} FontData;
-
-static FontData font_data = {
- .ft_library = NULL,
- .fonts = NULL,
- .mutex = PTHREAD_MUTEX_INITIALIZER,
-};
-
-#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-
-// 32bit FNV-1a hash algorithm
-// http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
-static const uint32_t FNV_prime = 16777619U;
-static const uint32_t offset_basis = 2166136261U;
-
-static uint32_t fnv_hash(void *data, uint32_t len)
-{
- uint8_t *d8 = data;
- uint32_t *d32 = data;
- uint32_t i, max;
- uint32_t hash = offset_basis;
-
- max = len/4;
-
- // 32 bit data
- for(i = 0; i < max; ++i)
- {
- hash ^= *d32++;
- hash *= FNV_prime;
- }
-
- // last bits
- for(i *= 4; i < len; ++i)
- {
- hash ^= (uint32_t) d8[i];
- hash *= FNV_prime;
- }
- return hash;
-}
-
-static inline uint32_t fnv_hash_add(uint32_t cur_hash, uint32_t word)
-{
- cur_hash ^= word;
- cur_hash *= FNV_prime;
- return cur_hash;
-}
-
-int utf8_to_unicode(unsigned char* pIn, unsigned int *pOut)
-{
- int utf_bytes = 1;
- unsigned int unicode = 0;
- unsigned char tmp;
- tmp = *pIn++;
- if (tmp < 0x80)
- {
- *pOut = tmp;
- }
- else
- {
- unsigned int high_bit_mask = 0x3F;
- unsigned int high_bit_shift = 0;
- int total_bits = 0;
- while((tmp & 0xC0) == 0xC0)
- {
- utf_bytes ++;
- if(utf_bytes > 6)
- {
- *pOut = tmp;
- return 1;
- }
- tmp = 0xFF & (tmp << 1);
- total_bits += 6;
- high_bit_mask >>= 1;
- high_bit_shift++;
- unicode <<= 6;
- unicode |= (*pIn++) & 0x3F;
- }
- unicode |= ((tmp >> high_bit_shift) & high_bit_mask) << total_bits;
- *pOut = unicode;
- }
-
- return utf_bytes;
-}
-
-static bool gr_ttf_string_cache_equals(void *keyA, void *keyB)
-{
- StringCacheKey *a = keyA;
- StringCacheKey *b = keyB;
- return a->max_width == b->max_width && strcmp(a->text, b->text) == 0;
-}
-
-static int gr_ttf_string_cache_hash(void *key)
-{
- StringCacheKey *k = key;
- return fnv_hash(k->text, strlen(k->text));
-}
-
-static bool gr_ttf_font_cache_equals(void *keyA, void *keyB)
-{
- TrueTypeFontKey *a = keyA;
- TrueTypeFontKey *b = keyB;
- return (a->size == b->size) && (a->dpi == b->dpi) && !strcmp(a->path, b->path);
-}
-
-static int gr_ttf_font_cache_hash(void *key)
-{
- TrueTypeFontKey *k = key;
-
- uint32_t hash = fnv_hash(k->path, strlen(k->path));
- hash = fnv_hash_add(hash, k->size);
- hash = fnv_hash_add(hash, k->dpi);
- return hash;
-}
-
-void *gr_ttf_loadFont(const char *filename, int size, int dpi)
-{
- int error;
- TrueTypeFont *res = NULL;
-
- pthread_mutex_lock(&font_data.mutex);
-
- if(font_data.fonts)
- {
- TrueTypeFontKey k = {
- .size = size,
- .dpi = dpi,
- .path = (char*)filename
- };
-
- res = hashmapGet(font_data.fonts, &k);
- if(res)
- {
- ++res->refcount;
- goto exit;
- }
- }
-
- if(!font_data.ft_library)
- {
- error = FT_Init_FreeType(&font_data.ft_library);
- if(error)
- {
- fprintf(stderr, "Failed to init libfreetype! %d\n", error);
- goto exit;
- }
- }
-
- FT_Face face;
- error = FT_New_Face(font_data.ft_library, filename, 0, &face);
- if(error)
- {
- fprintf(stderr, "Failed to load truetype face %s: %d\n", filename, error);
- goto exit;
- }
-
- error = FT_Set_Char_Size(face, 0, size*16, dpi, dpi);
- if(error)
- {
- fprintf(stderr, "Failed to set truetype face size to %d, dpi %d: %d\n", size, dpi, error);
- FT_Done_Face(face);
- goto exit;
- }
-
- res = malloc(sizeof(TrueTypeFont));
- memset(res, 0, sizeof(TrueTypeFont));
- res->type = FONT_TYPE_TTF;
- res->size = size;
- res->dpi = dpi;
- res->face = face;
- res->max_height = -1;
- res->base = -1;
- res->refcount = 1;
- res->glyph_cache = hashmapCreate(32, hashmapIntHash, hashmapIntEquals);
- res->string_cache = hashmapCreate(128, gr_ttf_string_cache_hash, gr_ttf_string_cache_equals);
- pthread_mutex_init(&res->mutex, 0);
-
- if(!font_data.fonts)
- font_data.fonts = hashmapCreate(4, gr_ttf_font_cache_hash, gr_ttf_font_cache_equals);
-
- TrueTypeFontKey *key = malloc(sizeof(TrueTypeFontKey));
- memset(key, 0, sizeof(TrueTypeFontKey));
- key->path = strdup(filename);
- key->size = size;
- key->dpi = dpi;
-
- res->key = key;
-
- hashmapPut(font_data.fonts, key, res);
-
-exit:
- pthread_mutex_unlock(&font_data.mutex);
- return res;
-}
-
-void *gr_ttf_scaleFont(void *font, int max_width, int measured_width)
-{
- if (!font)
- return NULL;
-
- TrueTypeFont *f = font;
- float scale_value = (float)(max_width) / (float)(measured_width);
- int new_size = ((int)((float)f->size * scale_value)) - 1;
- if (new_size < 1)
- new_size = 1;
- const char* file = f->key->path;
- int dpi = f->dpi;
- return gr_ttf_loadFont(file, new_size, dpi);
-}
-
-static bool gr_ttf_freeFontCache(void *key, void *value, void *context)
-{
- TrueTypeCacheEntry *e = value;
- FT_Done_Glyph((FT_Glyph)e->glyph);
- free(e);
- free(key);
- return true;
-}
-
-static bool gr_ttf_freeStringCache(void *key, void *value, void *context)
-{
- StringCacheKey *k = key;
- free(k->text);
- free(k);
-
- StringCacheEntry *e = value;
- free(e->surface.data);
- free(e);
- return true;
-}
-
-void gr_ttf_freeFont(void *font)
-{
- pthread_mutex_lock(&font_data.mutex);
-
- TrueTypeFont *d = font;
-
- if(--d->refcount == 0)
- {
- hashmapRemove(font_data.fonts, d->key);
-
- if(hashmapSize(font_data.fonts) == 0)
- {
- hashmapFree(font_data.fonts);
- font_data.fonts = NULL;
- }
-
- free(d->key->path);
- free(d->key);
-
- FT_Done_Face(d->face);
- hashmapForEach(d->string_cache, gr_ttf_freeStringCache, NULL);
- hashmapFree(d->string_cache);
- hashmapForEach(d->glyph_cache, gr_ttf_freeFontCache, NULL);
- hashmapFree(d->glyph_cache);
- pthread_mutex_destroy(&d->mutex);
- free(d);
- }
-
- pthread_mutex_unlock(&font_data.mutex);
-}
-
-static TrueTypeCacheEntry *gr_ttf_glyph_cache_peek(TrueTypeFont *font, int char_index)
-{
- return hashmapGet(font->glyph_cache, &char_index);
-}
-
-static TrueTypeCacheEntry *gr_ttf_glyph_cache_get(TrueTypeFont *font, int char_index)
-{
- TrueTypeCacheEntry *res = hashmapGet(font->glyph_cache, &char_index);
- if(!res)
- {
- int error = FT_Load_Glyph(font->face, char_index, FT_LOAD_RENDER);
- if(error)
- {
- fprintf(stderr, "Failed to load glyph idx %d: %d\n", char_index, error);
- return NULL;
- }
-
- FT_BitmapGlyph glyph;
- error = FT_Get_Glyph(font->face->glyph, (FT_Glyph*)&glyph);
- if(error)
- {
- fprintf(stderr, "Failed to copy glyph %d: %d\n", char_index, error);
- return NULL;
- }
-
- res = malloc(sizeof(TrueTypeCacheEntry));
- memset(res, 0, sizeof(TrueTypeCacheEntry));
- res->glyph = glyph;
- FT_Glyph_Get_CBox((FT_Glyph)glyph, FT_GLYPH_BBOX_PIXELS, &res->bbox);
-
- int *key = malloc(sizeof(int));
- *key = char_index;
-
- hashmapPut(font->glyph_cache, key, res);
- }
-
- return res;
-}
-
-static int gr_ttf_copy_glyph_to_surface(GGLSurface *dest, FT_BitmapGlyph glyph, int offX, int offY, int base)
-{
- int y;
- uint8_t *src_itr = glyph->bitmap.buffer;
- uint8_t *dest_itr = dest->data;
-
- if(glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
- {
- fprintf(stderr, "Unsupported pixel mode in FT_BitmapGlyph %d\n", glyph->bitmap.pixel_mode);
- return -1;
- }
-
- dest_itr += (offY + base - glyph->top)*dest->stride + (offX + glyph->left);
-
- // FIXME: if glyph->left is negative and everything else is 0 (e.g. letter 'j' in Roboto-Regular),
- // the result might end up being before the buffer - I'm not sure how to properly handle this.
- if(dest_itr < dest->data)
- dest_itr = dest->data;
-
- for(y = 0; y < glyph->bitmap.rows; ++y)
- {
- memcpy(dest_itr, src_itr, glyph->bitmap.width);
- src_itr += glyph->bitmap.pitch;
- dest_itr += dest->stride;
- }
- return 0;
-}
-
-static void gr_ttf_calcMaxFontHeight(TrueTypeFont *f)
-{
- char c;
- int char_idx;
- int error;
- FT_Glyph glyph;
- FT_BBox bbox;
- FT_BBox bbox_glyph;
- TrueTypeCacheEntry *ent;
-
- bbox.yMin = bbox_glyph.yMin = LONG_MAX;
- bbox.yMax = bbox_glyph.yMax = LONG_MIN;
-
- for(c = '!'; c <= '~'; ++c)
- {
- char_idx = FT_Get_Char_Index(f->face, c);
- ent = gr_ttf_glyph_cache_peek(f, char_idx);
- if(ent)
- {
- bbox.yMin = MIN(bbox.yMin, ent->bbox.yMin);
- bbox.yMax = MAX(bbox.yMax, ent->bbox.yMax);
- }
- else
- {
- error = FT_Load_Glyph(f->face, char_idx, 0);
- if(error)
- continue;
-
- error = FT_Get_Glyph(f->face->glyph, &glyph);
- if(error)
- continue;
-
- FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox_glyph);
- bbox.yMin = MIN(bbox.yMin, bbox_glyph.yMin);
- bbox.yMax = MAX(bbox.yMax, bbox_glyph.yMax);
-
- FT_Done_Glyph(glyph);
- }
- }
-
- if(bbox.yMin > bbox.yMax)
- bbox.yMin = bbox.yMax = 0;
-
- f->max_height = bbox.yMax - bbox.yMin;
- f->base = bbox.yMax;
-
- // FIXME: twrp fonts have some padding on top, I'll add it here
- // Should be fixed in the themes
- f->max_height += f->size / 4;
- f->base += f->size / 4;
-}
-
-// returns number of bytes from const char *text rendered to fit max_width, not number of UTF8 characters!
-static int gr_ttf_render_text(TrueTypeFont *font, GGLSurface *surface, const char *text, int max_width)
-{
- TrueTypeFont *f = font;
- TrueTypeCacheEntry *ent;
- int bytes_rendered = 0, total_w = 0;
- int utf_bytes = 0;
- unsigned int unicode = 0;
- int i, x, diff, char_idx, prev_idx = 0;
- int height, base;
- FT_Vector delta;
- uint8_t *data = NULL;
- const char *text_itr = text;
- int *char_idxs;
- int char_idxs_len = 0;
-
- char_idxs = malloc(strlen(text) * sizeof(int));
-
- while(*text_itr)
- {
- utf_bytes = utf8_to_unicode(text_itr, &unicode);
- text_itr += utf_bytes;
- bytes_rendered += utf_bytes;
-
- char_idx = FT_Get_Char_Index(f->face, unicode);
- char_idxs[char_idxs_len] = char_idx;
-
- ent = gr_ttf_glyph_cache_get(f, char_idx);
- if(ent)
- {
- diff = ent->glyph->root.advance.x >> 16;
-
- if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
- {
- FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
- diff += delta.x >> 6;
- }
-
- if(max_width != -1 && total_w + diff > max_width)
- break;
-
- total_w += diff;
- }
- prev_idx = char_idx;
- ++char_idxs_len;
- }
-
- if(font->max_height == -1)
- gr_ttf_calcMaxFontHeight(font);
-
- if(font->max_height == -1)
- {
- free(char_idxs);
- return -1;
- }
-
- height = font->max_height;
-
- data = malloc(total_w*height);
- memset(data, 0, total_w*height);
- x = 0;
- prev_idx = 0;
-
- surface->version = sizeof(*surface);
- surface->width = total_w;
- surface->height = height;
- surface->stride = total_w;
- surface->data = (void*)data;
- surface->format = GGL_PIXEL_FORMAT_A_8;
-
- for(i = 0; i < char_idxs_len; ++i)
- {
- char_idx = char_idxs[i];
- if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
- {
- FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
- x += delta.x >> 6;
- }
-
- ent = gr_ttf_glyph_cache_get(f, char_idx);
- if(ent)
- {
- gr_ttf_copy_glyph_to_surface(surface, ent->glyph, x, 0, font->base);
- x += ent->glyph->root.advance.x >> 16;
- }
-
- prev_idx = char_idx;
- }
-
- free(char_idxs);
- return bytes_rendered;
-}
-
-static StringCacheEntry *gr_ttf_string_cache_peek(TrueTypeFont *font, const char *text, int max_width)
-{
- StringCacheEntry *res;
- StringCacheKey k = {
- .text = (char*)text,
- .max_width = max_width
- };
-
- return hashmapGet(font->string_cache, &k);
-}
-
-static StringCacheEntry *gr_ttf_string_cache_get(TrueTypeFont *font, const char *text, int max_width)
-{
- StringCacheEntry *res;
- StringCacheKey k = {
- .text = (char*)text,
- .max_width = max_width
- };
-
- res = hashmapGet(font->string_cache, &k);
- if(!res)
- {
- res = malloc(sizeof(StringCacheEntry));
- memset(res, 0, sizeof(StringCacheEntry));
- res->rendered_bytes = gr_ttf_render_text(font, &res->surface, text, max_width);
- if(res->rendered_bytes < 0)
- {
- free(res);
- return NULL;
- }
-
- StringCacheKey *new_key = malloc(sizeof(StringCacheKey));
- memset(new_key, 0, sizeof(StringCacheKey));
- new_key->max_width = max_width;
- new_key->text = strdup(text);
-
- res->key = new_key;
-
- if(font->string_cache_tail)
- {
- res->prev = font->string_cache_tail;
- res->prev->next = res;
- }
- else
- font->string_cache_head = res;
- font->string_cache_tail = res;
-
- hashmapPut(font->string_cache, new_key, res);
- }
- else if(res->next)
- {
- // move this entry to the tail of the linked list
- // if it isn't already there
- if(res->prev)
- res->prev->next = res->next;
-
- res->next->prev = res->prev;
-
- if(!res->prev)
- font->string_cache_head = res->next;
-
- res->next = NULL;
- res->prev = font->string_cache_tail;
- res->prev->next = res;
- font->string_cache_tail = res;
-
- // truncate old entries
- if(hashmapSize(font->string_cache) >= STRING_CACHE_MAX_ENTRIES)
- {
- printf("Truncating string cache entries.\n");
- int i;
- StringCacheEntry *ent;
- for(i = 0; i < STRING_CACHE_TRUNCATE_ENTRIES; ++i)
- {
- ent = font->string_cache_head;
- font->string_cache_head = ent->next;
- font->string_cache_head->prev = NULL;
-
- hashmapRemove(font->string_cache, ent->key);
-
- gr_ttf_freeStringCache(ent->key, ent, NULL);
- }
- }
- }
- return res;
-}
-
-int gr_ttf_measureEx(const char *s, void *font)
-{
- TrueTypeFont *f = font;
- int res = -1;
-
- pthread_mutex_lock(&f->mutex);
- StringCacheEntry *e = gr_ttf_string_cache_get(font, s, -1);
- if(e)
- res = e->surface.width;
- pthread_mutex_unlock(&f->mutex);
-
- return res;
-}
-
-int gr_ttf_maxExW(const char *s, void *font, int max_width)
-{
- TrueTypeFont *f = font;
- TrueTypeCacheEntry *ent;
- int max_bytes = 0, total_w = 0;
- int utf_bytes, prev_utf_bytes = 0;
- unsigned int unicode = 0;
- int char_idx, prev_idx = 0;
- FT_Vector delta;
- StringCacheEntry *e;
-
- pthread_mutex_lock(&f->mutex);
-
- e = gr_ttf_string_cache_peek(font, s, max_width);
- if(e)
- {
- max_bytes = e->rendered_bytes;
- pthread_mutex_unlock(&f->mutex);
- return max_bytes;
- }
-
- while(*s)
- {
- utf_bytes = utf8_to_unicode(s, &unicode);
- s += utf_bytes;
-
- char_idx = FT_Get_Char_Index(f->face, unicode);
- if(FT_HAS_KERNING(f->face) && prev_idx && char_idx)
- {
- FT_Get_Kerning(f->face, prev_idx, char_idx, FT_KERNING_DEFAULT, &delta);
- total_w += delta.x >> 6;
- }
- prev_idx = char_idx;
-
- if(total_w > max_width)
- {
- max_bytes -= prev_utf_bytes;
- break;
- }
- prev_utf_bytes = utf_bytes;
-
- ent = gr_ttf_glyph_cache_get(f, char_idx);
- if(!ent)
- continue;
-
- total_w += ent->glyph->root.advance.x >> 16;
- max_bytes += utf_bytes;
- }
- pthread_mutex_unlock(&f->mutex);
- return max_bytes;
-}
-
-int gr_ttf_textExWH(void *context, int x, int y, const char *s, void *pFont, int max_width, int max_height)
-{
- GGLContext *gl = context;
- TrueTypeFont *font = pFont;
-
- // not actualy max width, but max_width + x
- if(max_width != -1)
- {
- max_width -= x;
- if(max_width <= 0)
- return 0;
- }
-
- pthread_mutex_lock(&font->mutex);
-
- StringCacheEntry *e = gr_ttf_string_cache_get(font, s, max_width);
- if(!e)
- {
- pthread_mutex_unlock(&font->mutex);
- return -1;
- }
-
- int y_bottom = y + e->surface.height;
- int res = e->rendered_bytes;
-
- if(max_height != -1 && max_height < y_bottom)
- {
- y_bottom = max_height;
- if(y_bottom <= y)
- {
- pthread_mutex_unlock(&font->mutex);
- return 0;
- }
- }
-
- gl->bindTexture(gl, &e->surface);
- gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
- gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
- gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
-
- gl->enable(gl, GGL_TEXTURE_2D);
- gl->texCoord2i(gl, -x, -y);
- gl->recti(gl, x, y, x + e->surface.width, y_bottom);
- gl->disable(gl, GGL_TEXTURE_2D);
-
- pthread_mutex_unlock(&font->mutex);
- return res;
-}
-
-int gr_ttf_getMaxFontHeight(void *font)
-{
- int res;
- TrueTypeFont *f = font;
-
- pthread_mutex_lock(&f->mutex);
-
- if(f->max_height == -1)
- gr_ttf_calcMaxFontHeight(f);
- res = f->max_height;
-
- pthread_mutex_unlock(&f->mutex);
- return res;
-}
-
-static bool gr_ttf_dump_stats_count_string_cache(void *key, void *value, void *context)
-{
- int *string_cache_size = context;
- StringCacheEntry *e = value;
- *string_cache_size += e->surface.height*e->surface.width + sizeof(StringCacheEntry);
- return true;
-}
-
-static bool gr_ttf_dump_stats_font(void *key, void *value, void *context)
-{
- TrueTypeFontKey *k = key;
- TrueTypeFont *f = value;
- int *total_string_cache_size = context;
- int string_cache_size = 0;
-
- pthread_mutex_lock(&f->mutex);
-
- hashmapForEach(f->string_cache, gr_ttf_dump_stats_count_string_cache, &string_cache_size);
-
- printf(" Font %s (size %d, dpi %d):\n"
- " refcount: %d\n"
- " max_height: %d\n"
- " base: %d\n"
- " glyph_cache: %d entries\n"
- " string_cache: %d entries (%.2f kB)\n",
- k->path, k->size, k->dpi,
- f->refcount, f->max_height, f->base,
- hashmapSize(f->glyph_cache),
- hashmapSize(f->string_cache), ((double)string_cache_size)/1024);
-
- pthread_mutex_unlock(&f->mutex);
-
- *total_string_cache_size += string_cache_size;
- return true;
-}
-
-void gr_ttf_dump_stats(void)
-{
- pthread_mutex_lock(&font_data.mutex);
-
- printf("TrueType fonts system stats: ");
- if(!font_data.fonts)
- printf("no truetype fonts loaded.\n");
- else
- {
- int total_string_cache_size = 0;
- printf("%d fonts loaded.\n", hashmapSize(font_data.fonts));
- hashmapForEach(font_data.fonts, gr_ttf_dump_stats_font, &total_string_cache_size);
- printf(" Total string cache size: %.2f kB\n", ((double)total_string_cache_size)/1024);
- }
-
- pthread_mutex_unlock(&font_data.mutex);
-}