From f7381f17cb3884eb4c4057376d97a6926ed4cce9 Mon Sep 17 00:00:00 2001 From: Daniel Juyung Seo Date: Sat, 3 Jul 2010 00:21:59 +0900 Subject: [PATCH] Added word cache and metric cache but disabled. --- configure.ac | 44 +++++- debian/rules | 2 + src/lib/engines/common/evas_font_draw.c | 254 +++++++++++++++++++++++++++++++- 3 files changed, 297 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index b847723..be700f2 100755 --- a/configure.ac +++ b/configure.ac @@ -1093,9 +1093,48 @@ AC_MSG_RESULT($want_evas_magic_debug) AM_CONDITIONAL(EVAS_MAGIC_DEBUG, test "x$want_evas_magic_debug" = "xyes") if test "x$want_evas_magic_debug" = "xyes"; then - AC_DEFINE(EVAS_MAGIC_DEBUG, 1, [complain when peole pass in wrong object types etc.]) + AC_DEFINE(EVAS_MAGIC_DEBUG, 1, [complain when people pass in wrong object types etc.]) fi + +####################################### +## Word Caching +want_word_cache="no" +AC_MSG_CHECKING(whether to enable caching of rendered words) +AC_ARG_ENABLE(word-cache, + AC_HELP_STRING( + [--enable-word-cache], + [Enable experimental word caching to speed up rendering [[default=disabled]]] + ), + [ want_word_cache="$enableval" ] +) +AC_MSG_RESULT($want_word_cache) + +AM_CONDITIONAL(WORD_CACHE, test "x$want_word_cache" = "xyes") +if test "x$want_word_cache" = "xyes"; then + AC_DEFINE(WORD_CACHE, 1, [Experimental word caching to speed up text rendering.]) +fi + +####################################### +## Metric Caching +want_metric_cache="no" +AC_MSG_CHECKING(whether to enable caching of rendered metrics) +AC_ARG_ENABLE(metric-cache, + AC_HELP_STRING( + [--enable-metric-cache], + [Enable experimental metric caching to speed up rendering [[default=disabled]]] + ), + [ want_metric_cache="$enableval" ] +) +AC_MSG_RESULT($want_metric_cache) + +AM_CONDITIONAL(METRIC_CACHE, test "x$want_metric_cache" = "xyes") +if test "x$want_metric_cache" = "xyes"; then + AC_DEFINE(METRIC_CACHE, 1, [Experimental metric caching to speed up text rendering.]) +fi + + + ##################################################################### ## ARGB engine options @@ -1538,6 +1577,9 @@ echo " Async Pipe Rendering....: $build_async_render" echo " Async Events............: $build_async_events" echo " Async Image Preload.....: $build_async_preload" echo +echo " Word Cache..............: $want_word_cache" +echo " Metric Cache............: $want_metric_cache" +echo echo "ARGB Software Engine Options:" echo " Sampling Scaler.........: $scaler_sample" echo " Smooth Scaler...........: $scaler_smooth" diff --git a/debian/rules b/debian/rules index 47811e6..0d89f3c 100755 --- a/debian/rules +++ b/debian/rules @@ -32,6 +32,8 @@ else arch_flags += --enable-winkcodec=no endif +#arch_flags += --enable-word-cache --enable-metric-cache + DEB_CONFIGURE_EXTRA_FLAGS := --disable-image-loader-svg \ --enable-simple-x11 \ --with-x \ diff --git a/src/lib/engines/common/evas_font_draw.c b/src/lib/engines/common/evas_font_draw.c index d629718..02a422f 100644 --- a/src/lib/engines/common/evas_font_draw.c +++ b/src/lib/engines/common/evas_font_draw.c @@ -9,6 +9,45 @@ #include "evas_intl_utils.h" /*defines INTERNATIONAL_SUPPORT if possible */ #include "evas_font_private.h" /* for Frame-Queuing support */ +#define WORD_CACHE_MAXLEN 50 +/* How many to cache */ +#define WORD_CACHE_NWORDS 20 + +struct prword { + EINA_INLIST; + /* FIXME: Need to save font/size et al */ + int size; + struct cinfo *cinfo; + RGBA_Font *font; + const char *str; + int len; + DATA8 *im; + int roww; + int width; + int height; + int baseline; +}; + +struct cinfo { + int gl; + FT_UInt index; + struct { int x, y; } pos; + int posx; + char chr; + RGBA_Font_Glyph *fg; + struct { + int w,h; + int rows; + unsigned char *data; + } bm; +}; + + + + +static Eina_Inlist *words = NULL; +static struct prword *evas_font_word_prerender(RGBA_Draw_Context *dc, const char *text, int len, RGBA_Font *fn, RGBA_Font_Int *fi,int use_kerning); + #ifdef EVAS_FRAME_QUEUING EAPI void evas_common_font_draw_init(void) @@ -203,7 +242,7 @@ static FT_UInt _evas_common_get_char_index(RGBA_Font_Int* fi, int gl) { Font_Char_Index result; - FT_UInt ret; + //FT_UInt ret; #ifdef HAVE_PTHREAD /// pthread_mutex_lock(&fi->ft_mutex); @@ -349,14 +388,83 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font int pen_x, pen_y; int chr; const char *text = in_text; + int len; FT_Face pface = NULL; FT_UInt prev_index; DATA32 *im; int c; int char_index = 0; /* the index of the current char */ + +#if defined(METRIC_CACHE) || defined(WORD_CACHE) + /* A fast strNlen would be nice (there is a wcsnlen strangely) */ + for (len = 0 ; text[len] && len < WORD_CACHE_MAXLEN ; len ++) + ; + + if (len > 2 && len < WORD_CACHE_MAXLEN){ + struct prword *word = evas_font_word_prerender(dc, text, len, fn, fi, + use_kerning); + if (word){ + int j,rowstart,rowend,xstart,xrun; + im = dst->image.data; + xrun = word->width; + y -= word->baseline; + xstart = 0; + rowstart = 0; + rowend = word->height; + /* Clip to extent */ + if (x + xrun > ext_x + ext_w){ + xrun -= x + xrun - ext_x - ext_w; + } + if (x < ext_x) { + int excess = ext_x - x; + xstart = excess - 1; + xrun -= excess; + x = ext_x; + } + if (y + rowend > ext_y + ext_h){ + rowend -= (y - ext_y + rowend - ext_h); + } + if (y < ext_y){ + int excess = ext_y - y; + rowstart += excess; + //rowend -= excess; + // y = ext_y; + } + +#ifdef WORD_CACHE + for (j = rowstart ; j < rowend ; j ++){ + func(NULL, word->im + (word->roww * j) + xstart, dc->col.col, + im + ((y + j) * im_w) + x, xrun); + } +#elif defined(METRIC_CACHE) + int ind; + y += word->baseline; + for (ind = 0 ; ind < len ; ind ++){ + // FIXME Do we need to draw? + struct cinfo *ci = word->cinfo + ind; + if ((ci->fg->ext_dat) && (dc->font_ext.func.gl_draw)) + { + /* ext glyph draw */ + dc->font_ext.func.gl_draw(dc->font_ext.data, + (void *)dst, + dc, ci->fg, + x + ci->pos.x, + y - ci->bm.h + ); + } + else { + func(NULL, word->im + (word->roww * j) + xstart, dc->col.col, im + ((y + j) * im_w) + x, xrun); + } + } +#endif + return; + } + +} +#endif + #ifdef INTERNATIONAL_SUPPORT - int len = 0; /*FIXME: should get the direction by parmater */ EvasIntlParType direction = FRIBIDI_TYPE_ON; EvasIntlLevel *level_list; @@ -369,6 +477,7 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font #endif + pen_x = x; pen_y = y; prev_index = 0; @@ -648,3 +757,144 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int LKU(fn->lock); #endif } + + + +struct prword * +evas_font_word_prerender(RGBA_Draw_Context *dc, const char *in_text, int len, RGBA_Font *fn, RGBA_Font_Int *fi,int use_kerning){ + int pen_x, pen_y; + struct cinfo *metrics; + const char *text; + int chr; + FT_Face pface = NULL; + FT_UInt prev_index; + unsigned char *im; + int width; + int height, above, below, baseline, descent; + int c; + int i,j; + int char_index = 0; /* the index of the current char */ + struct prword *w; + int gl; + + EINA_INLIST_FOREACH(words,w){ + if (w->len == len && w->font == fn && fi->size == w->size && + (w->str == in_text || strcmp(w->str, in_text) == 0)){ + words = eina_inlist_promote(words, EINA_INLIST_GET(w)); + return w; + } + } + +#ifdef INTERNATIONAL_SUPPORT + /*FIXME: should get the direction by parmater */ + EvasIntlParType direction = FRIBIDI_TYPE_ON; + EvasIntlLevel *level_list; + + /* change the text to visual ordering and update the level list + * for as minimum impact on the code as possible just use text as an + * holder, will change in the future.*/ + char *visual_text = evas_intl_utf8_to_visual(in_text, &len, &direction, NULL, NULL, &level_list); + text = (visual_text) ? visual_text : in_text; + +#endif + + gl = dc->font_ext.func.gl_new ? 1: 0; + + pen_x = pen_y = 0; + above = 0; below = 0; baseline = 0; height = 0; descent = 0; + metrics = malloc(sizeof(struct cinfo) * len); + /* First pass: Work out how big */ + for (char_index = 0, c = 0, chr = 0 ; text[chr] ; char_index ++){ + struct cinfo *ci = metrics + char_index; + ci->chr = text[chr]; + ci->gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr); + if (ci->gl == 0) break; + ci->index = evas_common_font_glyph_search(fn, &fi, ci->gl); + if (fi->src->current_size != fi->size) + { + FT_Activate_Size(fi->ft.size); + fi->src->current_size = fi->size; + } + if (use_kerning && char_index && (pface == fi->src->ft.face)) + { + int kern; + if (evas_common_font_query_kerning(fi, prev_index,ci->index,&kern)) + ci->pos.x += kern; + } + pface = fi->src->ft.face; + ci->fg = evas_common_font_int_cache_glyph_get(fi, ci->index); + if (!ci->fg) continue; + if (gl){ + ci->fg->ext_dat =dc->font_ext.func.gl_new(dc->font_ext.data,ci->fg); + ci->fg->ext_dat_free = dc->font_ext.func.gl_free; + } + ci->bm.data = ci->fg->glyph_out->bitmap.buffer; + ci->bm.w = MAX(ci->fg->glyph_out->bitmap.pitch, + ci->fg->glyph_out->bitmap.width); + ci->bm.rows = ci->fg->glyph_out->bitmap.rows; + ci->bm.h = ci->fg->glyph_out->top; + above = ci->bm.rows - (ci->bm.rows - ci->bm.h); + below = ci->bm.rows - ci->bm.h; + if (below > descent) descent = below; + if (above > baseline) baseline = above; + ci->pos.x = pen_x + ci->fg->glyph_out->left; + ci->pos.y = pen_y + ci->fg->glyph_out->top; + pen_x += ci->fg->glyph->advance.x >> 16; + prev_index = ci->index; + } + + /* First loop done */ + width = pen_x; + width = (width & 0x7) ? width + (8 - (width & 0x7)) : width; + + height = baseline + descent; + if (!gl){ + im = calloc(height, width); + for (i = 0 ; i < char_index ; i ++){ + struct cinfo *ci = metrics + i; + for (j = 0 ; j < ci->bm.rows ; j ++){ + memcpy(im + ci->pos.x + (j + baseline - ci->bm.h) * width, ci->bm.data + j * ci->bm.w, ci->bm.w); + } + + } + } else { + im = NULL; + } + /* Save it */ + struct prword *save; + + + save = malloc(sizeof(struct prword)); + save->cinfo = metrics; + save->str = eina_stringshare_add(text); + save->font = fn; + save->size = fi->size; + save->len = len; + save->im = im; + save->width = pen_x; + save->roww = width; + save->height = height; + save->baseline = baseline; + words = eina_inlist_prepend(words, EINA_INLIST_GET(save)); + + /* Clean up if too long */ + if (eina_inlist_count(words) > 20){ + struct prword *last = (struct prword *)(words->last); + if (last->im) free(last->im); + if (last->cinfo) free(last->cinfo); + eina_stringshare_del(last->str); + words = eina_inlist_remove(words,EINA_INLIST_GET(last)); + free(last); + } + + return save; + +#ifdef INTERNATIONAL_SUPPORT + if (level_list) free(level_list); + if (visual_text) free(visual_text); +#endif + +} + + + -- 2.7.4