raster pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=972cd7f62bbfaa03d3b25ea1e8ba643de24cf7b9
commit 972cd7f62bbfaa03d3b25ea1e8ba643de24cf7b9 Author: Ali Alzyod <[email protected]> Date: Mon Jul 6 12:43:40 2020 +0100 evas_text: lazy loading color glyph images in RAM Summary: Lazy loading for glyph images into RAM, instead of caching at layout level we will cache only when rendering. This may affect speed a bit since color glyphs will be loaded twice before caching (with FT_Load_Glyph) Try to run test application, and hit `scale font` ** RAM consumption (Accelerated Rendering) ** | Before | After | |-------:|-------| | 111.9 | 21.8 | | 204.8 | 24.4 | | 298.0 | 26.3 | | 391.5 | 28.4 | | 484.8 | 29.9 | | 578.1 | 31.4 | | 671.4 | 32.5 | ** RAM consumption (SW Rendering) ** | Before | After | |-------:|-------| | 104 | 14.6 | | 197 | 17 | | 290 | 19.1 | | 384 | 21.2 | | 477 | 22.8 | | 571 | 24.3 | | 664 | 25.6 | Test Plan: ``` #include <Elementary.h> typedef struct _APP { Evas_Object *tb1; Evas_Object *btnLoad; } APP; char *text = "<align=center><color=#4DE0FFFF underline=on underline_color=#4DE0FFFF><a href='tel:1234567890'>1234567890</a></color>๐๐๐๐คฃ๐๐๐ ๐๐๐๐๐๐๐๐๐๐โบ๐๐ค๐ค๐๐๐ถ๐๐๐ฃ๐ฅ๐ฎ๐ค๐ฏ๐ช๐ซ๐ด๐๐ค๐๐๐๐คค๐๐๐๐๐๐ค๐ฒโน๐๐๐๐๐ค๐ข๐ญ๐ฆ๐ง๐จ๐ฉ๐ฌ๐ฐ๐ฑ๐ณ๐ต๐ก๐ ๐๐ค ๐คก๐คฅ๐ท๐ค๐ค๐คข๐คงโป๐๐ฟ๐น๐บ๐โ ๐ป๐ฝ๐พ๐ค๐ฉ๐บ๐ธ๐น๐ป๐ผ๐ฝ๐๐ฟ๐พ๐๐๐๐ฆ๐ง๐จ๐ฉ๐ต๐ถ๐ผ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐ซ๐ฉโ๐ซ๐จโโ๐ฉโโ๐จโ๐พ๐ฉโ๐พ๐จโ๐ณ๐ฉโ๐ณ๐จโ๐ง๐ฉโ๐ง๐จโ๐ญ๐ฉโ๐ญ๐จโ๐ผ๐ฉโ๐ผ๐จโ๐ฌ๐ฉโ๐ฌ๐จโ๐ป๐ฉโ๐ป๐จโ๐ค๐ฉโ๐ค๐จโ๐จ๐ฉโ๐จ๐จโโ๏ธ๐ฉโโ๏ธ๐จโ๐๐ฉโ๐๐จโ๐๐ฉโ๐๐ฎโโ๏ธ๐ฎโโ๏ธ๐ต๏ธโโ๏ธ๐ต๏ธโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ทโโ๏ธ๐ทโโ๏ธ๐ณโโ๏ธ๐ณโโ๏ธ๐ฑโโ๏ธ๐ฑโโ๏ธ๐ ๐คถ๐ธ๐คด๐ฐ๐คต๐คฐ๐ฒ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ โโ๏ธ๐ โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐คฆโโ๏ธ๐คฆโโ๏ธ๐คทโโ๏ธ๐คทโโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐โโ๏ธ๐ถโโ๏ธ๐ถโ [...] int font_size = 50; int counter = 0; void _button_clicked(void *data, Evas_Object *obj, void *event_info) { APP *app = data; font_size += 10; Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; } EAPI_MAIN int elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) { APP *app = calloc(1, sizeof(APP)); Evas_Object *win, *scroller1, *scroller2, *box; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); scroller1 = elm_scroller_add(win); evas_object_size_hint_weight_set(scroller1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(scroller1, EVAS_HINT_FILL, EVAS_HINT_FILL); app->tb1 = evas_object_textblock_add(win); Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; evas_font_cache_set(evas_object_evas_get(app->tb1), 0); int w,h; evas_object_textblock_text_markup_set(app->tb1, ""); evas_object_size_hint_min_set(app->tb1, 400, 400); elm_object_content_set(scroller1, app->tb1); elm_box_pack_end(box, scroller1); elm_object_content_set(win, box); app->btnLoad = elm_button_add(win); elm_object_text_set(app->btnLoad, "Scale Font"); evas_object_smart_callback_add(app->btnLoad, "clicked", _button_clicked, app); evas_object_show(app->btnLoad); evas_object_move(app->btnLoad, 0, 20); evas_object_resize(app->btnLoad, 150, 20); evas_object_textblock_text_markup_set(app->tb1, text); evas_object_textblock_size_formatted_get(app->tb1, &w, &h); evas_object_size_hint_min_set(app->tb1, 400, w/400 + h + 150); evas_object_resize(win, 400, 400); evas_object_show(box); evas_object_show(scroller1); evas_object_show(scroller2); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: raster, woohyun, bowonryu, bu5hm4n, zmike, segfaultxavi Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8727 Differential Revision: https://phab.enlightenment.org/D11861 --- src/lib/evas/common/evas_font.h | 1 + src/lib/evas/common/evas_font_main.c | 102 +++++++++++++++++++++++++--------- src/lib/evas/common/evas_font_ot.c | 2 +- src/lib/evas/common/evas_text_utils.c | 4 +- 4 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/lib/evas/common/evas_font.h b/src/lib/evas/common/evas_font.h index 8b97c19399..fbed8e64bf 100644 --- a/src/lib/evas/common/evas_font.h +++ b/src/lib/evas/common/evas_font.h @@ -362,6 +362,7 @@ struct _RGBA_Font_Glyph Evas_Coord x_bear; Evas_Coord y_bear; FT_Glyph glyph; + FT_Vector advance; RGBA_Font_Glyph_Out *glyph_out; void *col_dat; /* this is a problem - only 1 engine at a time can extend such a font... grrr */ diff --git a/src/lib/evas/common/evas_font_main.c b/src/lib/evas/common/evas_font_main.c index 548ce4d01c..3a5b280437 100644 --- a/src/lib/evas/common/evas_font_main.c +++ b/src/lib/evas/common/evas_font_main.c @@ -711,6 +711,46 @@ _fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph) fash->bucket[grp]->bucket[maj]->item[min] = glyph; } +static void evas_font_glyph_load(RGBA_Font_Glyph *fg) +{ + if(fg->glyph) return; + + RGBA_Font_Int *fi = fg->fi; + FT_UInt idx = fg->index; + FT_Error error; + + const FT_Int32 hintflags[3] = + { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT }; + static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000, + 0x00000, 0x10000}; + + evas_common_font_int_reload(fi); + FTLOCK(); + error = FT_Load_Glyph(fi->src->ft.face, idx, + (FT_HAS_COLOR(fi->src->ft.face) ? + (FT_LOAD_COLOR | hintflags[fi->hinting]) : + (FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | hintflags[fi->hinting]))); + + FTUNLOCK(); + if (error) + { + return; + } + + /* Transform the outline of Glyph according to runtime_rend. */ + if (fi->runtime_rend & FONT_REND_SLANT) + FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform); + /* Embolden the outline of Glyph according to rundtime_rend. */ + if (fi->runtime_rend & FONT_REND_WEIGHT) + FT_GlyphSlot_Embolden(fi->src->ft.face->glyph); + + FTLOCK(); + error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph)); + FTUNLOCK(); + + return; +} + EAPI RGBA_Font_Glyph * evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx) { @@ -749,48 +789,60 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx) /* Transform the outline of Glyph according to runtime_rend. */ if (fi->runtime_rend & FONT_REND_SLANT) - FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform); + FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform); /* Embolden the outline of Glyph according to rundtime_rend. */ if (fi->runtime_rend & FONT_REND_WEIGHT) - FT_GlyphSlot_Embolden(fi->src->ft.face->glyph); + FT_GlyphSlot_Embolden(fi->src->ft.face->glyph); fg = calloc(1, sizeof(RGBA_Font_Glyph)); if (!fg) return NULL; - FTLOCK(); - error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph)); - FTUNLOCK(); - if (error) + if (FT_HAS_COLOR(fi->src->ft.face)) { - free(fg); - if (!fi->fash) fi->fash = _fash_gl_new(); - if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1)); - return NULL; - } + fg->advance.x = fi->src->ft.face->glyph->advance.x * 1024; + fg->advance.y = fi->src->ft.face->glyph->advance.y * 1024; - { - FT_BBox outbox; - FT_Glyph_Get_CBox(fg->glyph, - ((fi->hinting == 0) ? FT_GLYPH_BBOX_UNSCALED : - FT_GLYPH_BBOX_GRIDFIT), - &outbox); - fg->width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin); - fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMin); - fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax); + FT_GlyphSlot slot = fi->src->ft.face->glyph; + fg->width = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.width); + fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.horiBearingX); + fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(slot->metrics.horiBearingY); if (FT_HAS_FIXED_SIZES(fi->src->ft.face)) { - if (FT_HAS_COLOR(fi->src->ft.face) && - fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR) + if (fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR) { - fg->glyph->advance.x *= fi->scale_factor; - fg->glyph->advance.y *= fi->scale_factor; + fg->advance.x *= fi->scale_factor; + fg->advance.y *= fi->scale_factor; fg->width *= fi->scale_factor; fg->x_bear *= fi->scale_factor; fg->y_bear *= fi->scale_factor; } } } + else + { + FTLOCK(); + error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph)); + FTUNLOCK(); + if (error) + { + free(fg); + if (!fi->fash) fi->fash = _fash_gl_new(); + if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1)); + return NULL; + } + fg->advance.x = fg->glyph->advance.x; + fg->advance.y = fg->glyph->advance.y; + + FT_BBox outbox; + FT_Glyph_Get_CBox(fg->glyph, + ((fi->hinting == 0) ? FT_GLYPH_BBOX_UNSCALED : + FT_GLYPH_BBOX_GRIDFIT), + &outbox); + fg->width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin); + fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMin); + fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax); + } fg->index = idx; fg->fi = fi; @@ -813,7 +865,7 @@ evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg) /* no cserve2 case */ if (fg->glyph_out) return EINA_TRUE; - + evas_font_glyph_load(fg); FTLOCK(); error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1); if (error) diff --git a/src/lib/evas/common/evas_font_ot.c b/src/lib/evas/common/evas_font_ot.c index 47c624c99a..275727d8be 100644 --- a/src/lib/evas/common/evas_font_ot.c +++ b/src/lib/evas/common/evas_font_ot.c @@ -188,7 +188,7 @@ _evas_common_font_ot_hb_get_glyph_advance(hb_font_t *font, fg = evas_common_font_int_cache_glyph_get(fi, glyph); if (fg) { - return fg->glyph->advance.x >> 10; + return fg->advance.x >> 10; } return 0; } diff --git a/src/lib/evas/common/evas_text_utils.c b/src/lib/evas/common/evas_text_utils.c index fc291a9536..b109e9b98a 100644 --- a/src/lib/evas/common/evas_text_utils.c +++ b/src/lib/evas/common/evas_text_utils.c @@ -1104,7 +1104,7 @@ _content_create_ot(RGBA_Font_Int *fi, const Eina_Unicode *text, if (is_replacement) { /* Update the advance accordingly */ - adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) - + adjust_x += (pen_x + (fg->advance.x >> 16)) - gl_itr->pen_after; } pen_x = gl_itr->pen_after; @@ -1198,7 +1198,7 @@ _content_create_regular(RGBA_Font_Int *fi, const Eina_Unicode *text, gl_itr->index = idx; gl_itr->x_bear = fg->x_bear; gl_itr->y_bear = fg->y_bear; - adv = fg->glyph->advance.x >> 10; + adv = fg->advance.x >> 10; gl_itr->width = fg->width; if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl)) --
