*/
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,
{
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;
#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);
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);
}
_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)
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);
}
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;
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
#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.
}
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
}
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)
{
}
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);
(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++)
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);
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
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)
{
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 */
};