evas: give width offset when Evas tries to find ellipsis position

Summary:
If the last item before ellipsis item has bigger width than its advance,
evas_common_font_query_last_up_to_pos() function can find wrong ellipsis position.
When Evas finds a position for non last item, Evas must care about additionally
available space for glyph's width of the given x position.

ex) the last item's glyph before ellipsis item has a tail to draw above the ellipsis item.

@fix

Test Plan:
Test case will added as comment.
(Becasue of font license problem.)

Reviewers: herdsman, raster, jpeg, woohyun

Subscribers: cedric, Blackmole

Differential Revision: https://phab.enlightenment.org/D4727
This commit is contained in:
Youngbok Shin 2017-04-10 12:15:19 +09:00 committed by Carsten Haitzler (Rasterman)
parent 46bfd7ffb9
commit 1ab87367d8
6 changed files with 30 additions and 22 deletions

View File

@ -309,7 +309,7 @@ _evas_object_text_last_up_to_pos(const Evas_Object *eo_obj,
o->font,
&it->text_props,
cx - x,
cy);
cy, 0);
break;
}
x += it->adv;
@ -327,7 +327,7 @@ _evas_object_text_last_up_to_pos(const Evas_Object *eo_obj,
o->font,
&it->text_props,
cx - it->x,
cy);
cy, 0);
}
}
}
@ -893,7 +893,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
o->font,
&itr->text_props,
ellipsis_coord - (advance + l + r),
0);
0, start_ellip_it->w);
if (cut >= 0)
{
start_ellip_it->text_pos = itr->text_pos;
@ -948,7 +948,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
o->font,
&itr->text_props,
ellip_frame - (advance + l + r),
0);
0, end_ellip_it->w);
if (cut >= 0)
{
end_ellip_it->text_pos = itr->text_pos + cut;

View File

@ -3922,7 +3922,7 @@ _layout_text_item_new(Ctxt *c EINA_UNUSED, Evas_Object_Textblock_Format *fmt)
*/
static int
_layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt,
const Evas_Object_Textblock_Text_Item *ti)
const Evas_Object_Textblock_Text_Item *ti, int width_offset)
{
if (fmt->font.font)
{
@ -3933,7 +3933,7 @@ _layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt,
x = 0;
Evas_Object_Protected_Data *obj = efl_data_scope_get(c->obj, EFL_CANVAS_OBJECT_CLASS);
return ENFN->font_last_up_to_pos(ENDT, fmt->font.font,
&ti->text_props, x, 0);
&ti->text_props, x, 0, width_offset);
}
return -1;
}
@ -4706,7 +4706,7 @@ _layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
wrap = 0;
else
wrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it));
wrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it), 0);
if (wrap < 0)
return -1;
@ -4767,13 +4767,13 @@ _layout_get_hyphenationwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
Evas_Coord cw;
/* Get cutoff */
swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it));
swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it), 0);
/* Get cutoff considering an additional hyphen item */
cw = c->w;
c->hyphen_ti = _layout_hyphen_item_new(c, _ITEM_TEXT(it));
c->w -= c->hyphen_ti->parent.w;
hyphen_swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it));
hyphen_swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it), c->hyphen_ti->parent.w);
c->w = cw;
/* Stronger condition than '< 0' for hyphenations */
@ -4924,7 +4924,7 @@ _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt,
if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
swrap = 0;
else
swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it));
swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it), 0);
/* Avoiding too small textblocks to even contain one char.
* FIXME: This can cause breaking inside ligatures. */
@ -5098,7 +5098,7 @@ _layout_handle_ellipsis(Ctxt *c, Evas_Object_Textblock_Item *it, Eina_List *i)
// XXX: with RTL considerations in mind, we need to take max(adv, w) as the
// line may be reordered in a way that the item placement will cause the
// formatted width to exceed the width constraints.
if (ellip_ti->parent.adv > ellip_ti->parent.w)
if (c->par->is_bidi && ellip_ti->parent.adv > ellip_ti->parent.w)
{
ellip_w = ellip_ti->parent.adv;
}
@ -5124,7 +5124,7 @@ _layout_handle_ellipsis(Ctxt *c, Evas_Object_Textblock_Item *it, Eina_List *i)
{
ti = _ITEM_TEXT(last_it);
wrap = _layout_text_cutoff_get(c, last_it->format, ti);
wrap = _layout_text_cutoff_get(c, last_it->format, ti, ellip_ti->parent.w);
if ((wrap > 0) && !IS_AT_END(ti, (size_t) wrap))
{
@ -5246,7 +5246,7 @@ _calc_items_width(Ctxt *c)
}
static inline int
_item_get_cutoff(Ctxt *c, Evas_Object_Textblock_Item *it, Evas_Coord x)
_item_get_cutoff(Ctxt *c, Evas_Object_Textblock_Item *it, Evas_Coord x, Evas_Coord width_offset)
{
int pos = -1;
Evas_Object_Textblock_Text_Item *ti;
@ -5256,7 +5256,7 @@ _item_get_cutoff(Ctxt *c, Evas_Object_Textblock_Item *it, Evas_Coord x)
if (ti && ti->parent.format->font.font)
{
pos = ENFN->font_last_up_to_pos(ENDT, ti->parent.format->font.font,
&ti->text_props, x, 0);
&ti->text_props, x, 0, width_offset);
}
return pos;
}
@ -5319,7 +5319,7 @@ _layout_par_ellipsis_items(Ctxt *c, double ellip)
pos = (it && it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
(_item_get_cutoff(c, it, l - off)) : -1;
(_item_get_cutoff(c, it, l - off, ellip_ti->parent.w)) : -1;
if (pos >= 0)
{
_layout_item_text_split_strip_white(c, _ITEM_TEXT(it), i, pos);
@ -5340,7 +5340,7 @@ _layout_par_ellipsis_items(Ctxt *c, double ellip)
}
pos = (it && it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
(_item_get_cutoff(c, it, h - off)) : -1;
(_item_get_cutoff(c, it, h - off, 0)) : -1;
if (pos >= 0)
_layout_item_text_split_strip_white(c, _ITEM_TEXT(it), j, pos + 1);
if (it)

View File

@ -80,7 +80,7 @@ EAPI void evas_common_font_query_advance (RGBA_Font *fn, con
EAPI int evas_common_font_query_char_coords (RGBA_Font *fn, const Evas_Text_Props *intl_props, int pos, int *cx, int *cy, int *cw, int *ch);
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_last_up_to_pos (RGBA_Font *fn, const Evas_Text_Props *intl_props, int x, int y, int width_offset);
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);
EAPI void evas_common_font_ascent_descent_get(RGBA_Font *fn, const Evas_Text_Props *text_props, int *ascent, int *descent);

View File

@ -813,7 +813,7 @@ end:
* @return the position found, -1 on failure.
*/
EAPI int
evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text_props, int x, int y)
evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text_props, int x, int y, int width_offset)
{
int asc, desc;
int ret=-1;
@ -845,6 +845,14 @@ evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text
pen_x = full_adv - (gli->pen_after - start_pen);
/* If invisible, skip */
if (gli->index == 0) continue;
/* FIXME: Should we care glyph's width for RTL?
I think if width+x_bear/advance stacked from left side,
we don't need to care glyph's width to find linebreak position
or ellipsis position.
Even if (x < (pen_x + gli->x_bear + gli->width)))) is removed,
the whole test suite is passed.
*/
if ((x >= pen_x) &&
(((i == 0) && (x <= full_adv)) ||
(x < (full_adv - (gli[-1].pen_after - start_pen)) ||
@ -875,7 +883,7 @@ evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text
if ((x >= EVAS_FONT_WALK_PEN_X) &&
((x < (EVAS_FONT_WALK_PEN_X_AFTER)) ||
(x < (EVAS_FONT_WALK_PEN_X +
(x + width_offset < (EVAS_FONT_WALK_PEN_X +
_glyph_itr->x_bear + _glyph_itr->width))) &&
(y >= -asc) && (y <= desc))
{

View File

@ -1483,7 +1483,7 @@ struct _Evas_Func
void (*image_scale_hint_set) (void *data, void *image, int hint);
int (*image_scale_hint_get) (void *data, void *image);
int (*font_last_up_to_pos) (void *data, Evas_Font_Set *font, const Evas_Text_Props *intl_props, int x, int y);
int (*font_last_up_to_pos) (void *data, Evas_Font_Set *font, const Evas_Text_Props *intl_props, int x, int y, int width_offset);
Eina_Bool (*image_map_draw) (void *data, void *context, void *surface, void *image, RGBA_Map *m, int smooth, int level, Eina_Bool do_async);
void *(*image_map_surface_new) (void *data, int w, int h, int alpha);

View File

@ -3316,9 +3316,9 @@ eng_font_char_at_coords_get(void *data EINA_UNUSED, Evas_Font_Set *font, const E
}
static int
eng_font_last_up_to_pos(void *data EINA_UNUSED, Evas_Font_Set *font, const Evas_Text_Props *text_props, int x, int y)
eng_font_last_up_to_pos(void *data EINA_UNUSED, Evas_Font_Set *font, const Evas_Text_Props *text_props, int x, int y, int width_offset)
{
return evas_common_font_query_last_up_to_pos((RGBA_Font *) font, text_props, x, y);
return evas_common_font_query_last_up_to_pos((RGBA_Font *) font, text_props, x, y, width_offset);
}
static int