summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-09-03 15:05:54 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-09-03 15:05:54 +0300
commit0b9732ed9f8dcf9729c9dfb0d3850969563812e5 (patch)
tree639583b8913c062eea90c984f37337d9587d8093 /src
parent66849901ab1fbacb97644a8635d6b3a3259cbc4c (diff)
Text: Keep a cache of common glyph indices
Diffstat (limited to 'src')
-rw-r--r--src/ui/text.c81
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
55struct Impl_Glyph { 55struct 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
63void init_Glyph(iGlyph *d, iChar ch) { 64void 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
71void deinit_Glyph(iGlyph *d) { 73void 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
95static iFont *font_Text_(enum iFontId id); 98static 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
111static void deinit_Font(iFont *d) { 115static 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
123static 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
119iDeclareType(Text) 134iDeclareType(Text)
120iDeclareType(CacheRow) 135iDeclareType(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
281static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, iChar ch, float xShift) { 294static 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
370iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch) { 383iLocalDef 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
385static const iGlyph *glyph_Font_(iFont *d, iChar ch) { 400static 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 }