diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-03 15:05:54 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-03 15:05:54 +0300 |
commit | 0b9732ed9f8dcf9729c9dfb0d3850969563812e5 (patch) | |
tree | 639583b8913c062eea90c984f37337d9587d8093 /src | |
parent | 66849901ab1fbacb97644a8635d6b3a3259cbc4c (diff) |
Text: Keep a cache of common glyph indices
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/text.c | 81 |
1 files changed, 49 insertions, 32 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index 6c97a4ce..57788409 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -54,6 +54,7 @@ int enableKerning_Text = iTrue; /* looking up kern pairs is slow */ | |||
54 | 54 | ||
55 | struct Impl_Glyph { | 55 | struct Impl_Glyph { |
56 | iHashNode node; | 56 | iHashNode node; |
57 | uint32_t glyphIndex; | ||
57 | const iFont *font; /* may come from symbols/emoji */ | 58 | const iFont *font; /* may come from symbols/emoji */ |
58 | iRect rect[2]; /* zero and half pixel offset */ | 59 | iRect rect[2]; /* zero and half pixel offset */ |
59 | iInt2 d[2]; | 60 | iInt2 d[2]; |
@@ -61,11 +62,12 @@ struct Impl_Glyph { | |||
61 | }; | 62 | }; |
62 | 63 | ||
63 | void init_Glyph(iGlyph *d, iChar ch) { | 64 | void init_Glyph(iGlyph *d, iChar ch) { |
64 | d->node.key = ch; | 65 | d->node.key = ch; |
65 | d->font = NULL; | 66 | d->glyphIndex = 0; |
66 | d->rect[0] = zero_Rect(); | 67 | d->font = NULL; |
67 | d->rect[1] = zero_Rect(); | 68 | d->rect[0] = zero_Rect(); |
68 | d->advance = 0.0f; | 69 | d->rect[1] = zero_Rect(); |
70 | d->advance = 0.0f; | ||
69 | } | 71 | } |
70 | 72 | ||
71 | void deinit_Glyph(iGlyph *d) { | 73 | void deinit_Glyph(iGlyph *d) { |
@@ -90,6 +92,7 @@ struct Impl_Font { | |||
90 | iBool isMonospaced; | 92 | iBool isMonospaced; |
91 | iBool manualKernOnly; | 93 | iBool manualKernOnly; |
92 | enum iFontId symbolsFont; /* font to use for symbols */ | 94 | enum iFontId symbolsFont; /* font to use for symbols */ |
95 | uint32_t indexTable[128 - 32]; | ||
93 | }; | 96 | }; |
94 | 97 | ||
95 | static iFont *font_Text_(enum iFontId id); | 98 | static iFont *font_Text_(enum iFontId id); |
@@ -106,6 +109,7 @@ static void init_Font(iFont *d, const iBlock *data, int height, enum iFontId sym | |||
106 | d->baseline = (int) ascent * d->scale; | 109 | d->baseline = (int) ascent * d->scale; |
107 | d->symbolsFont = symbolsFont; | 110 | d->symbolsFont = symbolsFont; |
108 | d->isMonospaced = iFalse; | 111 | d->isMonospaced = iFalse; |
112 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); | ||
109 | } | 113 | } |
110 | 114 | ||
111 | static void deinit_Font(iFont *d) { | 115 | static void deinit_Font(iFont *d) { |
@@ -116,6 +120,17 @@ static void deinit_Font(iFont *d) { | |||
116 | delete_Block(d->data); | 120 | delete_Block(d->data); |
117 | } | 121 | } |
118 | 122 | ||
123 | static uint32_t glyphIndex_Font_(iFont *d, iChar ch) { | ||
124 | const size_t entry = ch - 32; | ||
125 | if (entry < iElemCount(d->indexTable)) { | ||
126 | if (d->indexTable[entry] == iInvalidPos) { | ||
127 | d->indexTable[entry] = stbtt_FindGlyphIndex(&d->font, ch); | ||
128 | } | ||
129 | return d->indexTable[entry]; | ||
130 | } | ||
131 | return stbtt_FindGlyphIndex(&d->font, ch); | ||
132 | } | ||
133 | |||
119 | iDeclareType(Text) | 134 | iDeclareType(Text) |
120 | iDeclareType(CacheRow) | 135 | iDeclareType(CacheRow) |
121 | 136 | ||
@@ -216,9 +231,7 @@ static void initCache_Text_(iText *d) { | |||
216 | SDL_PIXELFORMAT_RGBA4444, | 231 | SDL_PIXELFORMAT_RGBA4444, |
217 | SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, | 232 | SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, |
218 | d->cacheSize.x, | 233 | d->cacheSize.x, |
219 | d->cacheSize.y); | 234 | d->cacheSize.y); |
220 | |||
221 | printf("cache texture:%p size:%d x %d\n", d->cache, d->cacheSize.x, d->cacheSize.y); | ||
222 | SDL_SetTextureBlendMode(d->cache, SDL_BLENDMODE_BLEND); | 235 | SDL_SetTextureBlendMode(d->cache, SDL_BLENDMODE_BLEND); |
223 | } | 236 | } |
224 | 237 | ||
@@ -278,16 +291,16 @@ static void freeBmp_(void *ptr) { | |||
278 | stbtt_FreeBitmap(ptr, NULL); | 291 | stbtt_FreeBitmap(ptr, NULL); |
279 | } | 292 | } |
280 | 293 | ||
281 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, iChar ch, float xShift) { | 294 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { |
282 | int w, h; | 295 | int w, h; |
283 | uint8_t *bmp = stbtt_GetCodepointBitmapSubpixel( | 296 | uint8_t *bmp = stbtt_GetGlyphBitmapSubpixel( |
284 | &d->font, d->scale, d->scale, xShift, 0.0f, ch, &w, &h, 0, 0); | 297 | &d->font, d->scale, d->scale, xShift, 0.0f, glyphIndex, &w, &h, 0, 0); |
285 | /* Note: `bmp` must be freed afterwards. */ | 298 | /* Note: `bmp` must be freed afterwards. */ |
286 | collect_Garbage(bmp, freeBmp_); | 299 | collect_Garbage(bmp, freeBmp_); |
287 | SDL_Surface *surface8 = | 300 | SDL_Surface *surface8 = |
288 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); | 301 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); |
289 | SDL_SetSurfacePalette(surface8, text_.grayscale); | 302 | SDL_SetSurfacePalette(surface8, text_.grayscale); |
290 | SDL_PixelFormat *fmt = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA4444); | 303 | SDL_PixelFormat *fmt = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA8888); |
291 | SDL_Surface *surface = SDL_ConvertSurface(surface8, fmt, 0); | 304 | SDL_Surface *surface = SDL_ConvertSurface(surface8, fmt, 0); |
292 | SDL_FreeFormat(fmt); | 305 | SDL_FreeFormat(fmt); |
293 | SDL_FreeSurface(surface8); | 306 | SDL_FreeSurface(surface8); |
@@ -333,22 +346,22 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) { | |||
333 | const iChar ch = char_Glyph(glyph); | 346 | const iChar ch = char_Glyph(glyph); |
334 | iRect *glRect = &glyph->rect[hoff]; | 347 | iRect *glRect = &glyph->rect[hoff]; |
335 | /* Rasterize the glyph using stbtt. */ { | 348 | /* Rasterize the glyph using stbtt. */ { |
336 | surface = rasterizeGlyph_Font_(d, ch, hoff * 0.5f); | 349 | surface = rasterizeGlyph_Font_(d, glyph->glyphIndex, hoff * 0.5f); |
337 | if (hoff == 0) { | 350 | if (hoff == 0) { |
338 | int adv; | 351 | int adv; |
339 | stbtt_GetCodepointHMetrics(&d->font, ch, &adv, NULL); | 352 | stbtt_GetGlyphHMetrics(&d->font, glyph->glyphIndex, &adv, NULL); |
340 | glyph->advance = d->scale * adv; | 353 | glyph->advance = d->scale * adv; |
341 | } | 354 | } |
342 | stbtt_GetCodepointBitmapBoxSubpixel(&d->font, | 355 | stbtt_GetGlyphBitmapBoxSubpixel(&d->font, |
343 | ch, | 356 | glyph->glyphIndex, |
344 | d->scale, | 357 | d->scale, |
345 | d->scale, | 358 | d->scale, |
346 | hoff * 0.5f, | 359 | hoff * 0.5f, |
347 | 0.0f, | 360 | 0.0f, |
348 | &glyph->d[hoff].x, | 361 | &glyph->d[hoff].x, |
349 | &glyph->d[hoff].y, | 362 | &glyph->d[hoff].y, |
350 | NULL, | 363 | NULL, |
351 | NULL); | 364 | NULL); |
352 | tex = SDL_CreateTextureFromSurface(render, surface); | 365 | tex = SDL_CreateTextureFromSurface(render, surface); |
353 | SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_NONE); | 366 | SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_NONE); |
354 | glRect->size = init_I2(surface->w, surface->h); | 367 | glRect->size = init_I2(surface->w, surface->h); |
@@ -367,30 +380,34 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) { | |||
367 | } | 380 | } |
368 | } | 381 | } |
369 | 382 | ||
370 | iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch) { | 383 | iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { |
371 | if (stbtt_FindGlyphIndex(&d->font, ch) != 0) { | 384 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { |
372 | return d; | 385 | return d; |
373 | } | 386 | } |
374 | /* Not defined in current font, try Noto Emoji (for selected characters). */ | 387 | /* Not defined in current font, try Noto Emoji (for selected characters). */ |
375 | if ((ch >= 0x1f300 && ch < 0x1f600) || (ch >= 0x1f680 && ch <= 0x1f6c5)) { | 388 | if ((ch >= 0x1f300 && ch < 0x1f600) || (ch >= 0x1f680 && ch <= 0x1f6c5)) { |
376 | iFont *emoji = font_Text_(d->symbolsFont + fromSymbolsToEmojiOffset_FontId); | 389 | iFont *emoji = font_Text_(d->symbolsFont + fromSymbolsToEmojiOffset_FontId); |
377 | if (emoji != d && stbtt_FindGlyphIndex(&emoji->font, ch)) { | 390 | if (emoji != d && (*glyphIndex = glyphIndex_Font_(emoji, ch)) != 0) { |
378 | return emoji; | 391 | return emoji; |
379 | } | 392 | } |
380 | } | 393 | } |
381 | /* Fall back to Symbola for anything else. */ | 394 | /* Fall back to Symbola for anything else. */ |
382 | return font_Text_(d->symbolsFont); | 395 | iFont *font = font_Text_(d->symbolsFont); |
396 | *glyphIndex = glyphIndex_Font_(font, ch); | ||
397 | return font; | ||
383 | } | 398 | } |
384 | 399 | ||
385 | static const iGlyph *glyph_Font_(iFont *d, iChar ch) { | 400 | static const iGlyph *glyph_Font_(iFont *d, iChar ch) { |
386 | /* It may actually come from a different font. */ | 401 | /* It may actually come from a different font. */ |
387 | iFont *font = characterFont_Font_(d, ch); | 402 | uint32_t glyphIndex = 0; |
403 | iFont *font = characterFont_Font_(d, ch, &glyphIndex); | ||
388 | const void *node = value_Hash(&font->glyphs, ch); | 404 | const void *node = value_Hash(&font->glyphs, ch); |
389 | if (node) { | 405 | if (node) { |
390 | return node; | 406 | return node; |
391 | } | 407 | } |
392 | iGlyph *glyph = new_Glyph(ch); | 408 | iGlyph *glyph = new_Glyph(ch); |
393 | glyph->font = font; | 409 | glyph->glyphIndex = glyphIndex; |
410 | glyph->font = font; | ||
394 | cache_Font_(font, glyph, 0); | 411 | cache_Font_(font, glyph, 0); |
395 | cache_Font_(font, glyph, 1); /* half-pixel offset */ | 412 | cache_Font_(font, glyph, 1); /* half-pixel offset */ |
396 | insert_Hash(&font->glyphs, &glyph->node); | 413 | insert_Hash(&font->glyphs, &glyph->node); |
@@ -541,7 +558,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
541 | #endif | 558 | #endif |
542 | #if defined (LAGRANGE_ENABLE_KERNING) | 559 | #if defined (LAGRANGE_ENABLE_KERNING) |
543 | if (enableKerning_Text && !d->manualKernOnly && next) { | 560 | if (enableKerning_Text && !d->manualKernOnly && next) { |
544 | xpos += d->scale * stbtt_GetCodepointKernAdvance(&d->font, ch, next); | 561 | xpos += d->scale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next); |
545 | } | 562 | } |
546 | #endif | 563 | #endif |
547 | } | 564 | } |