Evas font-engine: Fixed font fallback in the same script run.

SVN revision: 59777
This commit is contained in:
Tom Hacohen 2011-05-29 09:20:18 +00:00
parent ca1fc26a0e
commit 81b217f8c4
10 changed files with 262 additions and 88 deletions

View File

@ -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);

View File

@ -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)
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)
{
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 = 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)

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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++)

View File

@ -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);

View File

@ -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

View File

@ -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 */
};