From cab3cb13ea514b06a0adcbd88801196cc29e65ff Mon Sep 17 00:00:00 2001 From: tasn Date: Sun, 29 May 2011 09:20:18 +0000 Subject: [PATCH] Evas font-engine: Fixed font fallback in the same script run. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@59777 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/canvas/evas_object_text.c | 52 +++++--- src/lib/canvas/evas_object_textblock.c | 96 ++++++++++---- src/lib/engines/common/evas_font.h | 1 + src/lib/engines/common/evas_font_ot.c | 4 +- src/lib/engines/common/evas_font_ot.h | 2 +- src/lib/engines/common/evas_font_query.c | 139 +++++++++++++++++++++ src/lib/engines/common/evas_text_utils.c | 41 +----- src/lib/engines/common/evas_text_utils.h | 5 +- src/lib/include/evas_private.h | 1 + src/modules/engines/software_generic/evas_engine.c | 11 +- 10 files changed, 263 insertions(+), 89 deletions(-) diff --git a/src/lib/canvas/evas_object_text.c b/src/lib/canvas/evas_object_text.c index ac2ef15..0e7208d 100644 --- a/src/lib/canvas/evas_object_text.c +++ b/src/lib/canvas/evas_object_text.c @@ -459,23 +459,24 @@ evas_object_text_font_get(const Evas_Object *obj, const char **font, Evas_Font_S */ static Evas_Object_Text_Item * _evas_object_text_item_new(Evas_Object *obj, Evas_Object_Text *o, - const Eina_Unicode *str, + void *fi, const Eina_Unicode *str, Evas_Script_Type script, size_t pos, size_t visual_pos, size_t len) { Evas_Object_Text_Item *it; - const Eina_Unicode *text = str + pos; it = calloc(1, sizeof(Evas_Object_Text_Item)); it->text_pos = pos; it->visual_pos = visual_pos; evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props, it->text_pos); - evas_common_text_props_script_set(&it->text_props, text, len); + evas_common_text_props_script_set(&it->text_props, script); + if (o->engine_data) { ENFN->font_text_props_info_create(ENDT, - o->engine_data, text, &it->text_props, + fi, str + pos, &it->text_props, o->bidi_par_props, it->text_pos, len); + ENFN->font_string_size_get(ENDT, o->engine_data, &it->text_props, @@ -554,7 +555,6 @@ _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unico { EvasBiDiStrIndex *v_to_l = NULL; size_t pos, visual_pos; - int cutoff; int len = eina_unicode_strlen(text); #ifdef BIDI_SUPPORT int *segment_idxs = NULL; @@ -567,32 +567,44 @@ _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unico #endif visual_pos = pos = 0; - do + while (len > 0) { - cutoff = evas_common_language_script_end_of_run_get( + void *script_fi = NULL; + int script_len = len, tmp_cut; + Evas_Script_Type script; + tmp_cut = evas_common_language_script_end_of_run_get( text + pos, o->bidi_par_props, - pos, len - pos); - if (cutoff > 0) + pos, len); + if (tmp_cut > 0) + script_len = tmp_cut; + + script = evas_common_language_script_type_get(text, script_len); + + while (script_len > 0) { + void *cur_fi; + int run_len = script_len; + if (o->engine_data) + { + run_len = ENFN->font_run_end_get(ENDT, + o->engine_data, &script_fi, &cur_fi, + script, text + pos, script_len); + } #ifdef BIDI_SUPPORT visual_pos = evas_bidi_position_logical_to_visual( - v_to_l, len, pos); + v_to_l, run_len, pos); #else visual_pos = pos; #endif - _evas_object_text_item_new(obj, o, text, pos, visual_pos, cutoff); - pos += cutoff; + _evas_object_text_item_new(obj, o, cur_fi, text, script, + pos, visual_pos, run_len); + + pos += run_len; + script_len -= run_len; + len -= run_len; } } - while (cutoff > 0); -#ifdef BIDI_SUPPORT - visual_pos = evas_bidi_position_logical_to_visual( - v_to_l, len, pos); -#else - visual_pos = pos; -#endif - _evas_object_text_item_new(obj, o, text, pos, visual_pos, len - pos); _evas_object_text_item_order(obj, o); diff --git a/src/lib/canvas/evas_object_textblock.c b/src/lib/canvas/evas_object_textblock.c index 8bdb0af..1a26a94 100644 --- a/src/lib/canvas/evas_object_textblock.c +++ b/src/lib/canvas/evas_object_textblock.c @@ -2816,43 +2816,75 @@ skip: empty_item = 0; + /* If there's no parent text node, only create an empty item */ + if (!n) + { + ti = _layout_text_item_new(c, fmt); + ti->parent.text_node = NULL; + ti->parent.text_pos = 0; + _layout_text_add_logical_item(c, ti, NULL); + + goto end; + } + while (str) { - int tmp_len; + void *script_fi = NULL; + int script_len, tmp_cut; + Evas_Script_Type script; - ti = _layout_text_item_new(c, fmt); - ti->parent.text_node = n; - ti->parent.text_pos = start + str - tbase; - tmp_len = off - (str - tbase); - if (ti->parent.text_node) - { - int tmp_cut; - tmp_cut = evas_common_language_script_end_of_run_get(str, - c->par->bidi_props, ti->parent.text_pos, tmp_len); - if (tmp_cut > 0) + script_len = off - (str - tbase); + + tmp_cut = evas_common_language_script_end_of_run_get(str, + c->par->bidi_props, start + str - tbase, script_len); + if (tmp_cut > 0) + { + script_len = tmp_cut; + } + + script = evas_common_language_script_type_get(str, script_len); + + + while (script_len > 0) + { + void *cur_fi; + int run_len = script_len; + ti = _layout_text_item_new(c, fmt); + ti->parent.text_node = n; + ti->parent.text_pos = start + str - tbase; + + if (ti->parent.format->font.font) { - tmp_len = tmp_cut; + run_len = c->ENFN->font_run_end_get(c->ENDT, + ti->parent.format->font.font, &script_fi, &cur_fi, + script, str, script_len); } + evas_common_text_props_bidi_set(&ti->text_props, c->par->bidi_props, ti->parent.text_pos); - evas_common_text_props_script_set(&ti->text_props, str, tmp_len); + evas_common_text_props_script_set(&ti->text_props, script); + if (ti->parent.format->font.font) { c->ENFN->font_text_props_info_create(c->ENDT, - ti->parent.format->font.font, str, &ti->text_props, - c->par->bidi_props, ti->parent.text_pos, tmp_len); + cur_fi, str, &ti->text_props, c->par->bidi_props, + ti->parent.text_pos, run_len); } + str += run_len; + cur_len -= run_len; + script_len -= run_len; + + _layout_text_add_logical_item(c, ti, NULL); } - str += tmp_len; - cur_len -= tmp_len; - _layout_text_add_logical_item(c, ti, NULL); - /* Break if we reached the end. */ + /* Break if we reached the end. We do it here + * because we want at least one run if it's an empty string. */ if (!*str) break; } +end: if (alloc_str) free(alloc_str); } @@ -3283,21 +3315,33 @@ static Evas_Object_Textblock_Text_Item * _layout_ellipsis_item_new(Ctxt *c, const Evas_Object_Textblock_Item *cur_it) { Evas_Object_Textblock_Text_Item *ellip_ti; + Evas_Script_Type script; + void *script_fi = NULL, *cur_fi; size_t len = 1; /* The length of _ellip_str */ ellip_ti = _layout_text_item_new(c, eina_list_data_get(eina_list_last(c->format_stack))); ellip_ti->parent.text_node = cur_it->text_node; ellip_ti->parent.text_pos = cur_it->text_pos; + script = evas_common_language_script_type_get(_ellip_str, len); evas_common_text_props_bidi_set(&ellip_ti->text_props, c->par->bidi_props, ellip_ti->parent.text_pos); - evas_common_text_props_script_set (&ellip_ti->text_props, - _ellip_str, len); - c->ENFN->font_text_props_info_create(c->ENDT, - ellip_ti->parent.format->font.font, - _ellip_str, &ellip_ti->text_props, - c->par->bidi_props, - ellip_ti->parent.text_pos, len); + evas_common_text_props_script_set (&ellip_ti->text_props, script); + + if (ellip_ti->parent.format->font.font) + { + /* It's only 1 char anyway, we don't need the run end. */ + (void) c->ENFN->font_run_end_get(c->ENDT, + ellip_ti->parent.format->font.font, &script_fi, &cur_fi, + script, _ellip_str, len); + + c->ENFN->font_text_props_info_create(c->ENDT, + ellip_ti->parent.format->font.font, + _ellip_str, &ellip_ti->text_props, + c->par->bidi_props, + ellip_ti->parent.text_pos, len); + } + _text_item_update_sizes(c, ellip_ti); if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT) diff --git a/src/lib/engines/common/evas_font.h b/src/lib/engines/common/evas_font.h index 62e2597..533d897 100644 --- a/src/lib/engines/common/evas_font.h +++ b/src/lib/engines/common/evas_font.h @@ -64,6 +64,7 @@ EAPI int evas_common_font_query_char_coords (RGBA_Font *fn, con EAPI int evas_common_font_query_pen_coords (RGBA_Font *fn, const Evas_Text_Props *intl_props, int pos, int *cpen_x, int *cy, int *cadv, int *ch); EAPI int evas_common_font_query_char_at_coords (RGBA_Font *fn, const Evas_Text_Props *intl_props, int x, int y, int *cx, int *cy, int *cw, int *ch); EAPI int evas_common_font_query_last_up_to_pos (RGBA_Font *fn, const Evas_Text_Props *intl_props, int x, int y); +EAPI int evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len); #ifdef EVAS_FRAME_QUEUING EAPI void evas_common_font_draw_finish(void); diff --git a/src/lib/engines/common/evas_font_ot.c b/src/lib/engines/common/evas_font_ot.c index 5a1f2d9..fe704a3 100644 --- a/src/lib/engines/common/evas_font_ot.c +++ b/src/lib/engines/common/evas_font_ot.c @@ -262,8 +262,8 @@ _evas_common_font_ot_shape(hb_buffer_t *buffer, RGBA_Font_Int *fi) } EAPI Eina_Bool -evas_common_font_ot_populate_text_props(void *_fn __UNUSED__, - const Eina_Unicode *text, Evas_Text_Props *props, int len) +evas_common_font_ot_populate_text_props(const Eina_Unicode *text, + Evas_Text_Props *props, int len) { RGBA_Font_Int *fi; hb_buffer_t *buffer; diff --git a/src/lib/engines/common/evas_font_ot.h b/src/lib/engines/common/evas_font_ot.h index adbe54d..bc5ab02 100644 --- a/src/lib/engines/common/evas_font_ot.h +++ b/src/lib/engines/common/evas_font_ot.h @@ -39,7 +39,7 @@ EAPI int evas_common_font_ot_cluster_size_get(const Evas_Text_Props *props, size_t char_index); EAPI Eina_Bool -evas_common_font_ot_populate_text_props(void *fn, const Eina_Unicode *text, +evas_common_font_ot_populate_text_props(const Eina_Unicode *text, Evas_Text_Props *props, int len); #endif diff --git a/src/lib/engines/common/evas_font_query.c b/src/lib/engines/common/evas_font_query.c index d2a34ad..b3bb783 100644 --- a/src/lib/engines/common/evas_font_query.c +++ b/src/lib/engines/common/evas_font_query.c @@ -3,6 +3,145 @@ #include "evas_font_private.h" /* for Frame-Queuing support */ #include "evas_font_ot.h" + +/* FIXME: Check coverage according to the font and not by actually loading */ +/** + * @internal + * Find the end of a run according to font coverage, and return the base script + * font and the current wanted font. + * + * @param[in] fn the font to use. + * @param script_fi The base font instance to be used with the script. If NULL, then it's calculated and returned in this variable, if not NULL, it's used and not modified. + * @param[out] cur_fi The font instance found for the current run. + * @param[in] script the base script + * @param[in] text the text to work on. + * @param[in] run_let the current run len, i.e "search limit". + * @return length of the run found. + */ +EAPI int +evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len) +{ + RGBA_Font_Int *fi; + const Eina_Unicode *run_end = text + run_len; + const Eina_Unicode *itr; + + /* If there's no current script_fi, find it first */ + if (!*script_fi) + { + const Eina_Unicode *base_char = NULL; + /* Skip common chars */ + for (base_char = text ; + (base_char < run_end) && + (evas_common_language_char_script_get(*base_char) != script) ; + base_char++) + ; + if (base_char == run_end) base_char = text; + + /* Find the first renderable char */ + while (base_char < run_end) + { + /* 0x1F is the last ASCII contral char, just a hack in + * the meanwhile. */ + if ((*base_char > 0x1F) && + evas_common_font_glyph_search(fn, &fi, *base_char)) + break; + base_char++; + } + + + /* If everything else fails, at least try to find a font for the + * replacement char */ + if (base_char == run_end) + evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); + + *script_fi = fi; + } + else + { + fi = *script_fi; + } + + /* Find the longest run of the same font starting from the start position + * and update cur_fi accordingly. */ + itr = text; + while (itr < run_end) + { + RGBA_Font_Int *tmp_fi; + /* Itr will end up being the first of the next run */ + for ( ; itr < run_end ; itr++) + { + /* Break if either it's not in the font, or if it is in the + * script's font. */ + if (fi == *script_fi) + { + if (!evas_common_get_char_index(fi, *itr)) + break; + } + else + { + if (evas_common_get_char_index(*script_fi, *itr)) + break; + } + } + + /* If the script font doesn't fit even one char, find a new font. */ + if (itr == text) + { + /* If we can find a font, use it. Otherwise, find the first + * char the run of chars that can't be rendered until the first + * one that can. */ + if (evas_common_font_glyph_search(fn, &tmp_fi, *itr)) + { + fi = tmp_fi; + } + else + { + itr++; + /* Go through all the chars that can't be rendered with any + * font */ + for ( ; itr < run_end ; itr++) + { + if (evas_common_get_char_index(fi, *itr) || + evas_common_font_glyph_search(fn, &fi, *itr)) + break; + } + + /* If we found a renderable character and the found font + * can render the replacement char, continue, otherwise + * find a font most suitable for the replacement char and + * break */ + if ((itr == run_end) || + !evas_common_get_char_index(fi, REPLACEMENT_CHAR)) + { + evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); + break; + } + } + itr++; + } + else + { + /* If this char is not renderable by any font, but the replacement + * char can be rendered using the currentfont, continue this + * run. */ + if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) && + evas_common_get_char_index(fi, REPLACEMENT_CHAR)) + { + itr++; + } + else + { + /* Done, we did as much as possible */ + break; + } + } + } + + *cur_fi = fi; + + return itr - text; +} + /** * @internal * Calculate the kerning between "left" and "right. diff --git a/src/lib/engines/common/evas_text_utils.c b/src/lib/engines/common/evas_text_utils.c index 6d48f4b..ab0a53e 100644 --- a/src/lib/engines/common/evas_text_utils.c +++ b/src/lib/engines/common/evas_text_utils.c @@ -22,10 +22,9 @@ evas_common_text_props_bidi_set(Evas_Text_Props *props, } void -evas_common_text_props_script_set(Evas_Text_Props *props, - const Eina_Unicode *str, size_t len) +evas_common_text_props_script_set(Evas_Text_Props *props, Evas_Script_Type scr) { - props->script = evas_common_language_script_type_get(str, len); + props->script = scr; } void @@ -195,12 +194,11 @@ evas_common_text_props_merge(Evas_Text_Props *item1, } EAPI Eina_Bool -evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text, +evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text, Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props, size_t par_pos, int len) { - RGBA_Font *fn = (RGBA_Font *) _fn; - RGBA_Font_Int *fi; + RGBA_Font_Int *fi = (RGBA_Font_Int *) _fi; if (text_props->info) { @@ -213,35 +211,6 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text, } text_props->info = calloc(1, sizeof(Evas_Text_Props_Info)); - fi = fn->fonts->data; - /* Load the glyph according to the first letter of the script, pretty - * bad, but will have to do */ - { - const Eina_Unicode *base_char; - /* Skip common chars */ - for (base_char = text ; - *base_char && - (evas_common_language_char_script_get(*base_char) != - text_props->script) ; - base_char++) - ; - if (!*base_char) base_char = text; - - /* Find the first renderable char, and if there is none, find - * one that can show the replacement char. */ - while (*base_char) - { - /* 0x1F is the last ASCII contral char. */ - if ((*base_char > 0x1F) && - evas_common_font_glyph_search(fn, &fi, *base_char)) - break; - base_char++; - } - - if (!*base_char) - evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); - } - text_props->font_instance = fi; evas_common_font_int_reload(fi); @@ -260,7 +229,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text, (void) par_props; (void) par_pos; - evas_common_font_ot_populate_text_props(fn, text, text_props, len); + evas_common_font_ot_populate_text_props(text, text_props, len); gl_itr = text_props->info->glyph; for (char_index = 0 ; char_index < text_props->len ; char_index++) diff --git a/src/lib/engines/common/evas_text_utils.h b/src/lib/engines/common/evas_text_utils.h index 689ab29..5a0a439 100644 --- a/src/lib/engines/common/evas_text_utils.h +++ b/src/lib/engines/common/evas_text_utils.h @@ -54,11 +54,10 @@ evas_common_text_props_bidi_set(Evas_Text_Props *props, Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start); void -evas_common_text_props_script_set(Evas_Text_Props *props, - const Eina_Unicode *str, size_t len); +evas_common_text_props_script_set(Evas_Text_Props *props, Evas_Script_Type scr); EAPI Eina_Bool -evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text, +evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text, Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props, size_t par_pos, int len); diff --git a/src/lib/include/evas_private.h b/src/lib/include/evas_private.h index 51a7a24..94c891c 100644 --- a/src/lib/include/evas_private.h +++ b/src/lib/include/evas_private.h @@ -733,6 +733,7 @@ struct _Evas_Func int (*gl_native_surface_get) (void *data, void *surface, void *native_surface); void *(*gl_api_get) (void *data); int (*image_load_error_get) (void *data, void *image); + int (*font_run_end_get) (void *data __UNUSED__, void *fn, void **script_fi, void **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len); }; struct _Evas_Image_Load_Func diff --git a/src/modules/engines/software_generic/evas_engine.c b/src/modules/engines/software_generic/evas_engine.c index 3e2c89d..95d46b9 100644 --- a/src/modules/engines/software_generic/evas_engine.c +++ b/src/modules/engines/software_generic/evas_engine.c @@ -799,6 +799,14 @@ eng_font_last_up_to_pos(void *data __UNUSED__, void *font, const Evas_Text_Props return evas_common_font_query_last_up_to_pos(font, text_props, x, y); } +static int +eng_font_run_font_end_get(void *data __UNUSED__, void *fn, void **script_fi, void **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len) +{ + return evas_common_font_query_run_font_end_get(fn, + (RGBA_Font_Int **) script_fi, (RGBA_Font_Int **) cur_fi, + script, text, run_len); +} + static void eng_font_draw(void *data __UNUSED__, void *context, void *surface, void *font, int x, int y, int w __UNUSED__, int h __UNUSED__, int ow __UNUSED__, int oh __UNUSED__, const Evas_Text_Props *text_props) { @@ -1081,7 +1089,8 @@ static Evas_Func func = NULL, // FIXME: need software mesa for gl rendering <- gl_proc_address_get NULL, // FIXME: need software mesa for gl rendering <- gl_native_surface_get NULL, // FIXME: need software mesa for gl rendering <- gl_api_get - eng_image_load_error_get + eng_image_load_error_get, + eng_font_run_font_end_get /* FUTURE software generic calls go here */ }; -- 2.7.4