1 #define EFL_CANVAS_FILTER_INTERNAL_PROTECTED
2 
3 #include "evas_common_private.h" /* Includes evas_bidi_utils stuff. */
4 #include "evas_private.h"
5 
6 #include "../efl/interfaces/efl_gfx_filter.eo.h"
7 #include "efl_canvas_filter_internal.eo.h"
8 #include "evas_filter.h"
9 
10 #define MY_CLASS EVAS_TEXT_CLASS
11 
12 #define MY_CLASS_NAME "Evas_Text"
13 
14 /* save typing */
15 #define COL_OBJECT(obj, sub) ARGB_JOIN(obj->sub->color.a, obj->sub->color.r, obj->sub->color.g, obj->sub->color.b)
16 #define COL_JOIN(o, sub, color) ARGB_JOIN(o->sub.color.a, o->sub.color.r, o->sub.color.g, o->sub.color.b)
17 
18 /* private magic number for text objects */
19 static const char o_type[] = "text";
20 
21 /* private struct for text object internal data */
22 typedef struct _Evas_Text_Data Evas_Text_Data;
23 typedef struct _Evas_Object_Text_Item Evas_Object_Text_Item;
24 
25 struct _Evas_Text_Data
26 {
27    DATA32               magic;
28 
29    struct {
30       // WARNING - you cannot change the below outline/shadow etc. members
31       // and their content without also updating _color_same() in this
32       // file
33       struct {
34          unsigned char  r, g, b, a;
35       } outline, shadow, glow, glow2;
36 
37       const char          *utf8_text; /* The text exposed to the API */
38       const char          *font;
39       Evas_Font_Description *fdesc;
40       const char          *source;
41       Eina_Unicode        *text;
42 
43       double               ellipsis;
44 
45       Evas_Font_Size       size;
46       Evas_Text_Style_Type style;
47       Efl_Text_Font_Bitmap_Scalable bitmap_scalable;
48    } cur, prev;
49 
50    struct {
51       Evas_Object_Text_Item    *ellipsis_start;
52       Evas_Object_Text_Item    *ellipsis_end;
53       Evas_Coord                w, h;
54       int                       advance;
55       int                       width_without_ellipsis;
56       Eina_Bool                 ellipsis;
57    } last_computed;
58 
59    Evas_BiDi_Paragraph_Props  *bidi_par_props;
60    const char                 *bidi_delimiters;
61    Evas_Object_Text_Item      *items;
62 
63    Evas_Font_Set              *font;
64 
65    float                       ascent, descent;
66    float                       max_ascent, max_descent;
67 
68    Evas_BiDi_Direction         bidi_dir : 2;
69    Evas_BiDi_Direction         paragraph_direction : 2;
70    Eina_Bool                   inherit_paragraph_direction : 1;
71    Eina_Bool                   changed_paragraph_direction : 1;
72    Eina_Bool                   changed : 1;
73    Eina_Bool                   has_filter : 1;
74 };
75 
76 struct _Evas_Object_Text_Item
77 {
78    EINA_INLIST;
79 
80    size_t               text_pos;
81    size_t               visual_pos;
82    Evas_Text_Props      text_props;
83    Evas_Coord           x, w, h, adv;
84 };
85 
86 /* private methods for text objects */
87 static void evas_object_text_init(Evas_Object *eo_obj);
88 static void evas_object_text_render(Evas_Object *eo_obj,
89                                     Evas_Object_Protected_Data *obj,
90                                     void *type_private_data,
91                                     void *engine, void *output, void *context, void *surface,
92                                     int x, int y, Eina_Bool do_async);
93 static void evas_object_text_free(Evas_Object *eo_obj,
94 				  Evas_Object_Protected_Data *obj);
95 static void evas_object_text_render_pre(Evas_Object *eo_obj,
96 					Evas_Object_Protected_Data *obj,
97 					void *type_private_data);
98 static void evas_object_text_render_post(Evas_Object *eo_obj,
99 					 Evas_Object_Protected_Data *obj,
100 					 void *type_private_data);
101 
102 static void *evas_object_text_engine_data_get(Evas_Object *eo_obj);
103 
104 static int evas_object_text_is_opaque(Evas_Object *eo_obj,
105 				      Evas_Object_Protected_Data *obj,
106 				      void *type_private_data);
107 static int evas_object_text_was_opaque(Evas_Object *eo_obj,
108 				       Evas_Object_Protected_Data *obj,
109 				       void *type_private_data);
110 
111 static void _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text);
112 
113 static const Evas_Object_Func object_func =
114 {
115    /* methods (compulsory) */
116    NULL,
117      evas_object_text_render,
118      evas_object_text_render_pre,
119      evas_object_text_render_post,
120      evas_object_text_engine_data_get,
121    /* these are optional. NULL = nothing */
122      NULL,
123      NULL,
124      evas_object_text_is_opaque,
125      evas_object_text_was_opaque,
126      NULL,
127      NULL,
128      NULL,
129      NULL,
130      NULL,
131      NULL,
132      NULL // render_prepare
133 };
134 
135 /* the actual api call to add a rect */
136 /* it has no other api calls as all properties are standard */
137 
138 static int
_evas_object_text_char_coords_get(const Evas_Object * eo_obj,const Evas_Text_Data * o,size_t pos,Evas_Coord * x,Evas_Coord * y,Evas_Coord * w,Evas_Coord * h)139 _evas_object_text_char_coords_get(const Evas_Object *eo_obj,
140       const Evas_Text_Data *o,
141       size_t pos, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
142 {
143    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
144    Evas_Object_Text_Item *it;
145 
146    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
147      {
148         if ((it->text_pos <= pos) &&
149               (pos < (it->text_pos + it->text_props.text_len)))
150           {
151              int ret;
152              ret = ENFN->font_char_coords_get(ENC, o->font,
153                    &it->text_props, pos - it->text_pos, x, y, w, h);
154              if (x) *x += it->x;
155              return ret;
156           }
157      }
158    return 0;
159 }
160 
161 static void
_evas_object_text_item_clean(Evas_Object_Text_Item * it)162 _evas_object_text_item_clean(Evas_Object_Text_Item *it)
163 {
164    evas_common_text_props_content_unref(&it->text_props);
165 }
166 
167 static void
_evas_object_text_item_del(Evas_Text_Data * o,Evas_Object_Text_Item * it)168 _evas_object_text_item_del(Evas_Text_Data *o, Evas_Object_Text_Item *it)
169 {
170    if (o->last_computed.ellipsis_start == it)
171      o->last_computed.ellipsis_start = NULL;
172    else if (o->last_computed.ellipsis_end == it)
173      o->last_computed.ellipsis_end = NULL;
174 
175    if ((EINA_INLIST_GET(it)->next) ||
176        (EINA_INLIST_GET(it)->prev) ||
177        (EINA_INLIST_GET(o->items) == (EINA_INLIST_GET(it))))
178      o->items = (Evas_Object_Text_Item *)eina_inlist_remove
179      (EINA_INLIST_GET(o->items), EINA_INLIST_GET(it));
180    _evas_object_text_item_clean(it);
181    free(it);
182 }
183 
184 static inline Eina_Bool
_color_same(const void * col1,const void * col2)185 _color_same(const void *col1, const void *col2)
186 {
187    const unsigned int *icol1 = col1, *icol2 = col2;
188    return (*icol1 == *icol2);
189 }
190 
191 static void
_evas_object_text_items_clean(Evas_Object_Protected_Data * obj,Evas_Text_Data * o)192 _evas_object_text_items_clean(Evas_Object_Protected_Data *obj, Evas_Text_Data *o)
193 {
194    /* FIXME: also preserve item */
195    if ((o->cur.font == o->prev.font) &&
196        (o->cur.fdesc == o->prev.fdesc) &&
197        (o->cur.size == o->prev.size) &&
198        (_color_same(&o->cur.outline, &o->prev.outline)) &&
199        (_color_same(&o->cur.shadow, &o->prev.shadow)) &&
200        (_color_same(&o->cur.glow, &o->prev.glow)) &&
201        (_color_same(&o->cur.glow2, &o->prev.glow2)) &&
202        (o->cur.style == o->prev.style) &&
203        (EINA_DBL_EQ(obj->cur->scale, obj->prev->scale)))
204      {
205         if ((o->last_computed.ellipsis_start) &&
206             (o->last_computed.ellipsis_start == o->items))
207           o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items),
208                                                                   EINA_INLIST_GET(o->last_computed.ellipsis_start));
209         if ((o->last_computed.ellipsis_end) &&
210             (EINA_INLIST_GET(o->last_computed.ellipsis_end) == EINA_INLIST_GET(o->items)->last))
211           o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items),
212                                                                   EINA_INLIST_GET(o->last_computed.ellipsis_end));
213      }
214    else
215      {
216         /* It is not guaranteed that the ellipsis are still inside the items, so remove them by force  */
217         if (o->last_computed.ellipsis_start)
218           _evas_object_text_item_del(o, o->last_computed.ellipsis_start);
219         o->last_computed.ellipsis_start = NULL;
220 
221         if (o->last_computed.ellipsis_end)
222           _evas_object_text_item_del(o, o->last_computed.ellipsis_end);
223         o->last_computed.ellipsis_end = NULL;
224      }
225    while (o->items)
226      {
227         _evas_object_text_item_del(o, o->items);
228      }
229 }
230 
231 static void
_evas_object_text_items_clear(Evas_Text_Data * o)232 _evas_object_text_items_clear(Evas_Text_Data *o)
233 {
234    if ((o->last_computed.ellipsis_start) &&
235        (o->last_computed.ellipsis_start != o->items))
236      {
237         _evas_object_text_item_del(o, o->last_computed.ellipsis_start);
238      }
239    o->last_computed.ellipsis_start = NULL;
240    if ((o->last_computed.ellipsis_end) &&
241        (EINA_INLIST_GET(o->last_computed.ellipsis_end) != EINA_INLIST_GET(o->items)->last))
242      {
243         _evas_object_text_item_del(o, o->last_computed.ellipsis_end);
244      }
245    o->last_computed.ellipsis_end = NULL;
246    while (o->items)
247      {
248         _evas_object_text_item_del(o, o->items);
249      }
250 }
251 
252 #ifdef BIDI_SUPPORT
253 static int
_evas_object_text_it_compare_logical(const void * _it1,const void * _it2)254 _evas_object_text_it_compare_logical(const void *_it1, const void *_it2)
255 {
256    const Evas_Object_Text_Item *it1 = _it1, *it2 = _it2;
257    if (it1->text_pos < it2->text_pos)
258      return -1;
259    else if (it1->text_pos == it2->text_pos)
260      return 0;
261    else
262      return 1;
263 
264 }
265 #endif
266 
267 static int
_evas_object_text_last_up_to_pos(const Evas_Object * eo_obj,const Evas_Text_Data * o,Evas_Coord cx,Evas_Coord cy)268 _evas_object_text_last_up_to_pos(const Evas_Object *eo_obj,
269       const Evas_Text_Data *o, Evas_Coord cx, Evas_Coord cy)
270 {
271    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
272    Evas_Object_Text_Item *it;
273    int pos = -1;
274 
275 #ifdef BIDI_SUPPORT
276    /* Reorder if it's a bidi text */
277    if (o->bidi_par_props)
278      {
279         Eina_List *logical_it = NULL;
280         Evas_Object_Text_Item *i;
281         Eina_List *itr;
282         Evas_Coord x = 0;
283         /* Insert all to the logical list */
284         EINA_INLIST_FOREACH(o->items, i)
285           {
286              logical_it = eina_list_sorted_insert(logical_it,
287                    _evas_object_text_it_compare_logical, i);
288           }
289         EINA_LIST_FOREACH(logical_it, itr, it)
290           {
291              if ((x <= cx) && (cx < x + it->adv))
292                {
293                   pos = it->text_pos + ENFN->font_last_up_to_pos(ENC,
294                         o->font,
295                         &it->text_props,
296                         cx - x,
297                         cy, 0);
298                   break;
299                }
300              x += it->adv;
301           }
302         eina_list_free(logical_it);
303      }
304    else
305 #endif
306      {
307         EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
308           {
309              if ((it->x <= cx) && (cx < it->x + it->adv))
310                {
311                   return it->text_pos + ENFN->font_last_up_to_pos(ENC,
312                         o->font,
313                         &it->text_props,
314                         cx - it->x,
315                         cy, 0);
316                }
317           }
318      }
319    return pos;
320 }
321 
322 static int
_evas_object_text_char_at_coords(const Evas_Object * eo_obj,const Evas_Text_Data * o,Evas_Coord cx,Evas_Coord cy,Evas_Coord * rx,Evas_Coord * ry,Evas_Coord * rw,Evas_Coord * rh)323 _evas_object_text_char_at_coords(const Evas_Object *eo_obj,
324       const Evas_Text_Data *o, Evas_Coord cx, Evas_Coord cy,
325       Evas_Coord *rx, Evas_Coord *ry, Evas_Coord *rw, Evas_Coord *rh)
326 {
327    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
328    Evas_Object_Text_Item *it;
329 
330    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
331      {
332         if ((it->x <= cx) && (cx < it->x + it->adv))
333           {
334              return it->text_pos + ENFN->font_char_at_coords_get(ENC,
335                    o->font,
336                    &it->text_props,
337                    cx - it->x,
338                    cy,
339                    rx, ry,
340                    rw, rh);
341           }
342      }
343    return -1;
344 }
345 
346 static Evas_Coord
_evas_object_text_horiz_width_without_ellipsis_get(const Evas_Text_Data * o)347 _evas_object_text_horiz_width_without_ellipsis_get(const Evas_Text_Data *o)
348 {
349    return o->last_computed.width_without_ellipsis;
350 }
351 
352 static Evas_Coord
_evas_object_text_horiz_advance_get(const Evas_Text_Data * o)353 _evas_object_text_horiz_advance_get(const Evas_Text_Data *o)
354 {
355    return o->last_computed.advance;
356 }
357 
358 static Evas_Coord
_evas_object_text_vert_advance_get(const Evas_Object * obj EINA_UNUSED,const Evas_Text_Data * o)359 _evas_object_text_vert_advance_get(const Evas_Object *obj EINA_UNUSED,
360       const Evas_Text_Data *o)
361 {
362    return o->max_ascent + o->max_descent;
363 }
364 
365 EAPI Evas_Object *
evas_object_text_add(Evas * e)366 evas_object_text_add(Evas *e)
367 {
368    e = evas_find(e);
369    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(e, EVAS_CANVAS_CLASS), NULL);
370    return efl_add(EVAS_TEXT_CLASS, e, efl_canvas_object_legacy_ctor(efl_added));
371 }
372 
373 EOLIAN static Eo *
_evas_text_efl_object_constructor(Eo * eo_obj,Evas_Text_Data * o EINA_UNUSED)374 _evas_text_efl_object_constructor(Eo *eo_obj, Evas_Text_Data *o EINA_UNUSED)
375 {
376    eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
377    evas_object_text_init(eo_obj);
378 
379    return eo_obj;
380 }
381 
382 EOLIAN static void
_evas_text_efl_text_font_font_source_set(Eo * eo_obj,Evas_Text_Data * o,const char * font_source)383 _evas_text_efl_text_font_font_source_set(Eo *eo_obj, Evas_Text_Data *o, const char *font_source)
384 {
385    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
386    if (((o->cur.source) && (font_source) &&
387         (!strcmp(o->cur.source, font_source))) ||
388        (!o->cur.source && !font_source))
389      return;
390    evas_object_async_block(obj);
391    /*
392    if (o->cur.source) eina_stringshare_del(o->cur.source);
393    if (font_source) o->cur.source = eina_stringshare_add(font_source);
394    else o->cur.source = NULL;
395     */
396    eina_stringshare_replace(&o->cur.source, font_source);
397 }
398 
399 EOLIAN static const char*
_evas_text_efl_text_font_font_source_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)400 _evas_text_efl_text_font_font_source_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
401 {
402    return o->cur.source;
403 }
404 
405 static void
_evas_text_font_reload(Eo * eo_obj,Evas_Text_Data * o)406 _evas_text_font_reload(Eo *eo_obj, Evas_Text_Data *o)
407 {
408    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
409    Eina_Bool pass = EINA_FALSE, freeze = EINA_FALSE;
410    Eina_Bool source_invisible = EINA_FALSE;
411    Eina_List *was = NULL;
412 
413    if (o->cur.size == 0 || (!o->cur.font && !o->cur.source)) return ;
414 
415    if (!(obj->layer->evas->is_frozen))
416      {
417         pass = evas_event_passes_through(eo_obj, obj);
418         freeze = evas_event_freezes_through(eo_obj, obj);
419         source_invisible = evas_object_is_source_invisible(eo_obj, obj);
420         if ((!pass) && (!freeze) && (!source_invisible))
421           was = _evas_pointer_list_in_rect_get(obj->layer->evas, eo_obj, obj,
422                                                1, 1);
423      }
424 
425    /* DO IT */
426    evas_font_free(o->font);
427    o->font = NULL;
428 
429    o->font = evas_font_load(obj->layer->evas->font_path,
430                             obj->layer->evas->hinting,
431                             o->cur.fdesc, o->cur.source,
432                             (int)(((double) o->cur.size) * obj->cur->scale),
433                             o->cur.bitmap_scalable);
434      {
435         o->ascent = 0;
436         o->descent = 0;
437         o->max_ascent = 0;
438         o->max_descent = 0;
439      }
440    _evas_object_text_items_clear(o);
441    _evas_object_text_recalc(eo_obj, o->cur.text);
442    o->changed = 1;
443    if (o->has_filter)
444      evas_filter_changed_set(eo_obj, EINA_TRUE);
445    evas_object_change(eo_obj, obj);
446    evas_object_clip_dirty(eo_obj, obj);
447    evas_object_coords_recalc(eo_obj, obj);
448    if (!obj->layer->evas->is_frozen && !pass && !freeze && obj->cur->visible)
449      _evas_canvas_event_pointer_in_list_mouse_move_feed(obj->layer->evas, was, eo_obj, obj, 1, 1, EINA_TRUE, NULL);
450    eina_list_free(was);
451    evas_object_inform_call_resize(eo_obj, obj);
452 }
453 
454 EOLIAN static void
_evas_text_efl_text_font_font_family_set(Eo * eo_obj,Evas_Text_Data * o,const char * font)455 _evas_text_efl_text_font_font_family_set(Eo *eo_obj, Evas_Text_Data *o, const char *font)
456 {
457    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
458    Evas_Font_Description *fdesc;
459 
460    EINA_SAFETY_ON_NULL_RETURN(font);
461 
462    evas_object_async_block(obj);
463    if (eina_streq(font, o->cur.font)) return;
464 
465    /* We can't assume the given font is same with current fdesc by comparing string.
466       Since Evas starts to supporting "auto" for language,
467       the given font string should be parsed once before comparing it. */
468    fdesc = evas_font_desc_new();
469 
470    /* Set default language according to locale. */
471    eina_stringshare_replace(&(fdesc->lang), evas_font_lang_normalize("auto"));
472    evas_font_name_parse(fdesc, font);
473 
474    if (o->cur.fdesc && !evas_font_desc_cmp(fdesc, o->cur.fdesc))
475      {
476         evas_font_desc_unref(fdesc);
477         return;
478      }
479 
480    if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
481    o->cur.fdesc = fdesc;
482    eina_stringshare_replace(&o->cur.font, font);
483    o->prev.font = NULL;
484 
485    _evas_text_font_reload(eo_obj, o);
486 }
487 
488 EOLIAN static const char *
_evas_text_efl_text_font_font_family_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)489 _evas_text_efl_text_font_font_family_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
490 {
491    return o->cur.font;
492 }
493 
494 EOLIAN static void
_evas_text_efl_text_font_font_size_set(Eo * eo_obj,Evas_Text_Data * o,Evas_Font_Size size)495 _evas_text_efl_text_font_font_size_set(Eo *eo_obj, Evas_Text_Data *o, Evas_Font_Size size)
496 {
497    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
498 
499    EINA_SAFETY_ON_TRUE_RETURN(size <= 0);
500    if (size == o->cur.size) return;
501 
502    evas_object_async_block(obj);
503 
504    o->cur.size = size;
505 
506    _evas_text_font_reload(eo_obj, o);
507 }
508 
509 EOLIAN static Evas_Font_Size
_evas_text_efl_text_font_font_size_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)510 _evas_text_efl_text_font_font_size_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
511 {
512    return o->cur.size;
513 }
514 
515 static void
_evas_object_text_item_update_sizes(Evas_Object_Protected_Data * obj,Evas_Text_Data * o,Evas_Object_Text_Item * it)516 _evas_object_text_item_update_sizes(Evas_Object_Protected_Data *obj, Evas_Text_Data *o, Evas_Object_Text_Item *it)
517 {
518    ENFN->font_string_size_get(ENC,
519          o->font,
520          &it->text_props,
521          &it->w, &it->h);
522    it->adv = ENFN->font_h_advance_get(ENC, o->font,
523          &it->text_props);
524 }
525 
526 /**
527  * @internal
528  * Create a new text layout item from the string and the format.
529  *
530  * @param c the context to work on - Not NULL.
531  * @param fmt the format to use.
532  * @param str the string to use.
533  */
534 static Evas_Object_Text_Item *
_evas_object_text_item_new(Evas_Object_Protected_Data * obj,Evas_Text_Data * o,Evas_Font_Instance * fi,const Eina_Unicode * str,Evas_Script_Type script,size_t pos,size_t visual_pos,size_t len)535 _evas_object_text_item_new(Evas_Object_Protected_Data *obj,
536                            Evas_Text_Data *o,
537                            Evas_Font_Instance *fi, const Eina_Unicode *str,
538                            Evas_Script_Type script,
539                            size_t pos, size_t visual_pos, size_t len)
540 {
541    Evas_Object_Text_Item *it;
542 
543    it = calloc(1, sizeof(Evas_Object_Text_Item));
544    it->text_pos = pos;
545    it->visual_pos = visual_pos;
546    evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props,
547          it->text_pos);
548    evas_common_text_props_script_set(&it->text_props, script);
549 
550    if (fi)
551      {
552         ENFN->font_text_props_info_create(ENC,
553               fi, str + pos, &it->text_props,
554               o->bidi_par_props, it->text_pos, len, EVAS_TEXT_PROPS_MODE_SHAPE,
555               o->cur.fdesc->lang);
556         _evas_object_text_item_update_sizes(obj, o, it);
557      }
558    o->items = (Evas_Object_Text_Item *)
559       eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(it));
560    return it;
561 }
562 
563 /**
564  * @internal
565  * Orders o->items according to the visual position.
566  *
567  * @param obj the evas object
568  * @param o the text object
569  */
570 static void
_evas_object_text_item_order(Evas_Object * eo_obj,Evas_Text_Data * o)571 _evas_object_text_item_order(Evas_Object *eo_obj, Evas_Text_Data *o)
572 {
573    (void) eo_obj;
574 #ifdef BIDI_SUPPORT
575    /* Reorder if it's a bidi text */
576    if (o->bidi_par_props)
577      {
578         Evas_Object_Text_Item *i, *j, *min;
579         i = o->items;
580         while (i)
581           {
582              min = i;
583              EINA_INLIST_FOREACH(i, j)
584                {
585                   if (j->visual_pos < min->visual_pos)
586                     {
587                        min = j;
588                     }
589                }
590              if (min != i)
591                {
592                   o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min));
593                   o->items = (Evas_Object_Text_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
594                }
595 
596              i = (Evas_Object_Text_Item *) EINA_INLIST_GET(min)->next;
597           }
598      }
599 #endif
600 
601    /* calculate the positions according to the order. */
602      {
603         Evas_Object_Text_Item *it = o->items;
604         Evas_Coord x = 0;
605 
606         while (it)
607           {
608              it->x = x;
609              x += it->adv;
610              it = (Evas_Object_Text_Item *) EINA_INLIST_GET(it)->next;
611           }
612      }
613 }
614 
615 /**
616  * Create ellipsis.
617  */
618 static const Eina_Unicode _ellip_str[2] = { 0x2026, '\0' };
619 
620 /* FIXME: We currently leak ellipsis items. */
621 static Evas_Object_Text_Item *
_layout_ellipsis_item_new(Evas_Object_Protected_Data * obj,Evas_Text_Data * o)622 _layout_ellipsis_item_new(Evas_Object_Protected_Data *obj, Evas_Text_Data *o)
623 {
624    Evas_Object_Text_Item *ellip_ti = NULL;
625    Evas_Script_Type script;
626    Evas_Font_Instance *script_fi = NULL, *cur_fi = NULL;
627    size_t len = 1; /* The length of _ellip_str */
628 
629    script = evas_common_language_script_type_get(_ellip_str, 1);
630 
631    if (o->font)
632      {
633         (void) ENFN->font_run_end_get(ENC, o->font, &script_fi, &cur_fi,
634                                       script, _ellip_str, 1);
635          ellip_ti = _evas_object_text_item_new(obj, o, cur_fi,
636                                                _ellip_str, script, 0, 0, len);
637      }
638 
639    return ellip_ti;
640 }
641 
642 /* EINA_TRUE if this item is ok and should be included, false if should be
643  * discarded. */
644 static Eina_Bool
_layout_text_item_trim(Evas_Object_Protected_Data * obj,Evas_Text_Data * o,Evas_Object_Text_Item * ti,int idx,Eina_Bool want_start)645 _layout_text_item_trim(Evas_Object_Protected_Data *obj, Evas_Text_Data *o, Evas_Object_Text_Item *ti, int idx, Eina_Bool want_start)
646 {
647    Evas_Text_Props new_text_props;
648    if (idx >= (int) ti->text_props.text_len)
649       return EINA_FALSE;
650 
651    memset(&new_text_props, 0, sizeof (new_text_props));
652 
653    while (!evas_common_text_props_split(&ti->text_props, &new_text_props, idx))
654      idx--;
655    if (want_start)
656      {
657         evas_common_text_props_content_unref(&new_text_props);
658      }
659    else
660      {
661         evas_common_text_props_content_unref(&ti->text_props);
662         memcpy(&ti->text_props, &new_text_props, sizeof(ti->text_props));
663         ti->text_pos += idx;
664         ti->visual_pos += idx;
665      }
666    _evas_object_text_item_update_sizes(obj, o, ti);
667 
668    return EINA_TRUE;
669 }
670 
671 static void
_evas_object_text_pad_get(const Eo * eo_obj,Evas_Text_Data * o,int * l,int * r,int * t,int * b)672 _evas_object_text_pad_get(const Eo *eo_obj, Evas_Text_Data *o, int *l, int *r, int *t, int *b)
673 {
674    if (l) *l = 0;
675    if (r) *r = 0;
676    if (t) *t = 0;
677    if (b) *b = 0;
678    if (!o->has_filter)
679      evas_text_style_pad_get(o->cur.style, l, r, t, b);
680    else
681      efl_gfx_filter_padding_get(eo_obj, l, r, t, b);
682 }
683 
684 /**
685  * @internal
686  * Populates o->items with the items of the text according to text
687  *
688  * @param obj the evas object
689  * @param o the text object
690  * @param text the text to layout
691  */
692 static void
_evas_object_text_layout(Evas_Object * eo_obj,Evas_Text_Data * o,Eina_Unicode * text)693 _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *text)
694 {
695    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
696    EvasBiDiStrIndex *v_to_l = NULL;
697    Evas_Coord advance = 0, width = 0;
698    size_t pos, visual_pos;
699    int len = eina_unicode_strlen(text);
700    int l = 0, r = 0;
701 #ifdef BIDI_SUPPORT
702    int par_len = len;
703    int *segment_idxs = NULL;
704    Eina_Bool is_bidi = EINA_FALSE;
705 #endif
706 
707    if (o->items &&
708        !memcmp(&o->cur, &o->prev, sizeof (o->cur)) &&
709        o->cur.text == text &&
710        (EINA_DBL_EQ(obj->cur->scale, obj->prev->scale)) &&
711        ((o->last_computed.advance <= obj->cur->geometry.w && !o->last_computed.ellipsis) ||
712         (o->last_computed.w == obj->cur->geometry.w)) &&
713        !o->changed_paragraph_direction)
714      return;
715 
716    o->last_computed.ellipsis = EINA_FALSE;
717    evas_object_content_change(eo_obj, obj);
718 
719    if (o->items) _evas_object_text_items_clean(obj, o);
720 
721    if (text && *text)
722       o->bidi_dir = EVAS_BIDI_DIRECTION_LTR;
723    else
724       o->bidi_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
725 
726 #ifdef BIDI_SUPPORT
727    if (text)
728      {
729         if (o->bidi_delimiters)
730           segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
731      }
732    evas_bidi_paragraph_props_unref(o->bidi_par_props);
733    if (text)
734      {
735         Evas_BiDi_Direction par_dir;
736         EvasBiDiParType bidi_par_type;
737 
738         par_dir = o->paragraph_direction;
739 
740         switch (par_dir)
741           {
742            case EVAS_BIDI_DIRECTION_LTR:
743               bidi_par_type = EVAS_BIDI_PARAGRAPH_LTR;
744               break;
745            case EVAS_BIDI_DIRECTION_RTL:
746               bidi_par_type = EVAS_BIDI_PARAGRAPH_RTL;
747               break;
748            case EVAS_BIDI_DIRECTION_NEUTRAL:
749            default:
750               bidi_par_type = EVAS_BIDI_PARAGRAPH_NEUTRAL;
751               break;
752           }
753 
754         o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs, bidi_par_type);
755         is_bidi = !!o->bidi_par_props;
756      }
757 
758    if (o->bidi_par_props)
759       o->bidi_dir = EVAS_BIDI_PAR_TYPE_TO_DIRECTION(o->bidi_par_props->direction);
760 
761    evas_bidi_props_reorder_line(NULL, 0, len, o->bidi_par_props, &v_to_l);
762    if (segment_idxs) free(segment_idxs);
763 #endif
764    visual_pos = pos = 0;
765 
766    if (text)
767      {
768         const Evas_Object_Text_Item *last_it = NULL;
769 #ifdef BIDI_SUPPORT
770         size_t max_vpos = 0;
771 #endif
772 
773         while (len > 0)
774           {
775              Evas_Font_Instance *script_fi = NULL;
776              int script_len = len, tmp_cut;
777              Evas_Script_Type script;
778              tmp_cut = evas_common_language_script_end_of_run_get
779                (text + pos,
780                 o->bidi_par_props,
781                 pos, len);
782              if (tmp_cut > 0) script_len = tmp_cut;
783 
784              script = evas_common_language_script_type_get(text + pos, script_len);
785 
786              while (script_len > 0)
787                {
788                   const Evas_Object_Text_Item *it;
789                   Evas_Font_Instance *cur_fi = NULL;
790                   int run_len = script_len;
791                   if (o->font)
792                     {
793                        run_len = ENFN->font_run_end_get
794                          (ENC, o->font, &script_fi, &cur_fi,
795                           script, text + pos, script_len);
796                     }
797 #ifdef BIDI_SUPPORT
798                   visual_pos = evas_bidi_position_logical_to_visual
799                     (v_to_l, par_len, pos);
800 #else
801                   visual_pos = pos;
802 #endif
803                   it = _evas_object_text_item_new(obj, o, cur_fi, text, script,
804                                                   pos, visual_pos, run_len);
805 
806                   advance += it->adv;
807                   pos += run_len;
808                   script_len -= run_len;
809                   len -= run_len;
810 
811                   if (it->w > 0)
812                     {
813 #ifdef BIDI_SUPPORT
814                        if (is_bidi)
815                          {
816                             if (!last_it || (visual_pos >= max_vpos))
817                               {
818                                  last_it = it;
819                                  max_vpos = visual_pos;
820                               }
821                          }
822                        else
823 #endif
824                          {
825                             last_it = it;
826                          }
827                     }
828                }
829           }
830 
831         width = advance;
832         if (last_it)
833           width += last_it->w - last_it->adv;
834      }
835    o->last_computed.width_without_ellipsis = width;
836 
837    _evas_object_text_pad_get(eo_obj, o, &l, &r, NULL, NULL);
838 
839    /* Handle ellipsis */
840    if (pos && (o->cur.ellipsis >= 0.0) && (width + l + r > obj->cur->geometry.w) && (obj->cur->geometry.w > 0))
841      {
842         Evas_Coord ellip_frame = obj->cur->geometry.w;
843         Evas_Object_Text_Item *start_ellip_it = NULL, *end_ellip_it = NULL;
844 
845         o->last_computed.ellipsis = EINA_TRUE;
846 
847         /* Account of the ellipsis item width. As long as ellipsis != 0
848          * we have a left ellipsis. And the same with 1 and right. */
849         if (!EINA_DBL_EQ(o->cur.ellipsis, 0.0))
850           {
851              if (o->last_computed.ellipsis_start)
852                {
853                   start_ellip_it = o->last_computed.ellipsis_start;
854                   o->items = (Evas_Object_Text_Item *)
855                     eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(start_ellip_it));
856                }
857              else
858                {
859                   start_ellip_it = _layout_ellipsis_item_new(obj, o);
860                }
861              o->last_computed.ellipsis_start = start_ellip_it;
862              ellip_frame -= start_ellip_it->w;
863           }
864         if (!EINA_DBL_EQ(o->cur.ellipsis, 1.0))
865           {
866              /* FIXME: Should take the last item's font and style and etc. *//* weird it's a text, should always have the same style/font */
867              if (o->last_computed.ellipsis_end)
868                {
869                   end_ellip_it = o->last_computed.ellipsis_end;
870                   o->items = (Evas_Object_Text_Item *)
871                     eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(end_ellip_it));
872                }
873              else
874                {
875                   end_ellip_it = _layout_ellipsis_item_new(obj, o);
876                }
877              o->last_computed.ellipsis_end = end_ellip_it;
878              ellip_frame -= end_ellip_it->w;
879           }
880 
881         /* The point where we should start from, going for the full
882          * ellip frame. */
883         Evas_Coord ellipsis_coord = o->cur.ellipsis * (width - ellip_frame);
884         if (start_ellip_it)
885           {
886              Evas_Object_Text_Item *itr = o->items;
887              advance = 0;
888 
889              while (itr && (advance + l + r + itr->w < ellipsis_coord))
890                {
891                   Eina_Inlist *itrn = EINA_INLIST_GET(itr)->next;
892                   if ((itr != start_ellip_it) && (itr != end_ellip_it))
893                     {
894                        advance += itr->adv;
895                        _evas_object_text_item_del(o, itr);
896                     }
897                   itr = (Evas_Object_Text_Item *) itrn;
898                }
899              if (itr && (itr != start_ellip_it))
900                {
901                   int cut = ENFN->font_last_up_to_pos(ENC,
902                         o->font,
903                         &itr->text_props,
904                         ellipsis_coord - (advance + l + r),
905                         0, start_ellip_it->w);
906                   if (cut >= 0)
907                     {
908                        start_ellip_it->text_pos = itr->text_pos;
909 
910                        if (itr->text_props.bidi_dir == EVAS_BIDI_DIRECTION_RTL)
911                          start_ellip_it->visual_pos = itr->visual_pos + cut + 1;
912                        else
913                          start_ellip_it->visual_pos = itr->visual_pos;
914 
915                        if (!_layout_text_item_trim(obj, o, itr, cut + 1, EINA_FALSE))
916                          {
917                             _evas_object_text_item_del(o, itr);
918                          }
919                     }
920                }
921 
922              if (!o->bidi_par_props)
923                {
924                   o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items), EINA_INLIST_GET(start_ellip_it));
925                   o->items = (Evas_Object_Text_Item *) eina_inlist_prepend(EINA_INLIST_GET(o->items), EINA_INLIST_GET(start_ellip_it));
926                }
927           }
928 
929         if (end_ellip_it)
930           {
931              Evas_Object_Text_Item *itr = o->items;
932              advance = 0;
933 
934              while (itr)
935                {
936                   if (itr != end_ellip_it) /* was start_ellip_it */
937                     {
938                        if (advance + l + r + itr->w >= ellip_frame)
939                          {
940                             break;
941                          }
942                        advance += itr->adv;
943                     }
944                   itr = (Evas_Object_Text_Item *) EINA_INLIST_GET(itr)->next;
945                }
946 
947              if (itr == end_ellip_it)
948                {
949                   /* FIXME: We shouldn't do anything. */
950                }
951 
952              /* In case when we reach end of itr list, and have NULL */
953              int cut = -1;
954              if (itr && (itr != end_ellip_it))
955                {
956                   cut = ENFN->font_last_up_to_pos(ENC,
957                                                   o->font,
958                                                   &itr->text_props,
959                                                   ellip_frame - (advance + l + r),
960                                                   0, end_ellip_it->w);
961                   if (cut >= 0)
962                     {
963                        end_ellip_it->text_pos = itr->text_pos + cut;
964 
965                         if (itr->text_props.bidi_dir == EVAS_BIDI_DIRECTION_RTL)
966                          end_ellip_it->visual_pos = itr->visual_pos - 1;
967                         else
968                          end_ellip_it->visual_pos = itr->visual_pos + cut;
969 
970                        if (_layout_text_item_trim(obj, o, itr, cut, EINA_TRUE))
971                          {
972                             itr = (Evas_Object_Text_Item *) EINA_INLIST_GET(itr)->next;
973                          }
974                     }
975                }
976 
977 
978              /* Remove the rest of the items */
979              while (itr)
980                {
981                   Eina_Inlist *itrn = EINA_INLIST_GET(itr)->next;
982                   if ((itr != start_ellip_it) && (itr != end_ellip_it))
983                     {
984                        _evas_object_text_item_del(o, itr);
985                     }
986                   itr = (Evas_Object_Text_Item *) itrn;
987                }
988           }
989      }
990    if (o->cur.text != text) free(o->cur.text);
991    o->cur.text = text;
992    o->prev = o->cur;
993 
994    {
995       Evas_Object_Text_Item *itr = o->items;
996       advance = 0;
997 
998       while (itr)
999         {
1000            advance += itr->adv;
1001            itr = (Evas_Object_Text_Item *) EINA_INLIST_GET(itr)->next;
1002         }
1003       o->last_computed.advance = advance;
1004    }
1005 
1006    _evas_object_text_item_order(eo_obj, o);
1007 
1008    if (v_to_l) free(v_to_l);
1009 }
1010 
1011 EOLIAN static void
_evas_text_efl_gfx_entity_size_set(Eo * eo_obj,Evas_Text_Data * o,Eina_Size2D sz)1012 _evas_text_efl_gfx_entity_size_set(Eo *eo_obj, Evas_Text_Data *o, Eina_Size2D sz)
1013 {
1014    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1015 
1016    if (_evas_object_intercept_call_evas(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
1017      return;
1018 
1019    EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
1020      {
1021         state_write->geometry.w = sz.w;
1022         state_write->geometry.h = sz.h;
1023      }
1024    EINA_COW_STATE_WRITE_END(obj, state_write, cur);
1025 
1026    _evas_object_text_recalc(eo_obj, o->cur.text);
1027 }
1028 
1029 EOLIAN static void
_evas_text_ellipsis_set(Eo * eo_obj,Evas_Text_Data * o,double ellipsis)1030 _evas_text_ellipsis_set(Eo *eo_obj, Evas_Text_Data *o, double ellipsis)
1031 {
1032    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1033 
1034    if (EINA_DBL_EQ(o->cur.ellipsis, ellipsis)) return;
1035 
1036    evas_object_async_block(obj);
1037    o->prev.ellipsis = o->cur.ellipsis;
1038    o->cur.ellipsis = ellipsis;
1039    o->changed = 1;
1040    if (o->has_filter)
1041      evas_filter_changed_set(eo_obj, EINA_TRUE);
1042    evas_object_change(eo_obj, obj);
1043    evas_object_clip_dirty(eo_obj, obj);
1044 }
1045 
1046 EOLIAN static double
_evas_text_ellipsis_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1047 _evas_text_ellipsis_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1048 {
1049    return o->cur.ellipsis;
1050 }
1051 
1052 EOLIAN static void
_evas_text_efl_object_dbg_info_get(Eo * eo_obj,Evas_Text_Data * o EINA_UNUSED,Efl_Dbg_Info * root)1053 _evas_text_efl_object_dbg_info_get(Eo *eo_obj, Evas_Text_Data *o EINA_UNUSED, Efl_Dbg_Info *root)
1054 {
1055    efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root);
1056    Efl_Dbg_Info *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
1057 
1058    const char *text;
1059    int size;
1060    text = efl_text_font_family_get(eo_obj);
1061    size = efl_text_font_size_get(eo_obj);
1062    EFL_DBG_INFO_APPEND(group, "Font", EINA_VALUE_TYPE_STRING, text);
1063    EFL_DBG_INFO_APPEND(group, "Text size", EINA_VALUE_TYPE_INT, size);
1064 
1065    text = efl_text_font_source_get(eo_obj);
1066    EFL_DBG_INFO_APPEND(group, "Font source", EINA_VALUE_TYPE_STRING, text);
1067 
1068    text = efl_text_get(eo_obj);
1069    EFL_DBG_INFO_APPEND(group, "Text", EINA_VALUE_TYPE_STRING, text);
1070 }
1071 
1072 EOLIAN static void
_evas_text_efl_text_text_set(Eo * eo_obj,Evas_Text_Data * o,const char * _text)1073 _evas_text_efl_text_text_set(Eo *eo_obj, Evas_Text_Data *o, const char *_text)
1074 {
1075    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1076    int len;
1077    Eina_Unicode *text;
1078    Eina_List *was = NULL;
1079 
1080    if ((o->cur.utf8_text) && (_text) && (!strcmp(o->cur.utf8_text, _text)))
1081       return;
1082    evas_object_async_block(obj);
1083    text = eina_unicode_utf8_to_unicode(_text, &len);
1084 
1085    if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
1086    was = _evas_pointer_list_in_rect_get(obj->layer->evas, eo_obj, obj, 1, 1);
1087    /* DO II */
1088    /*Update bidi_props*/
1089 
1090    _evas_object_text_items_clear(o);
1091 
1092    _evas_object_text_recalc(eo_obj, text);
1093    eina_stringshare_replace(&o->cur.utf8_text, _text);
1094    o->prev.utf8_text = NULL;
1095 
1096    if (o->cur.text != text) free(text);
1097 
1098    o->changed = 1;
1099    if (o->has_filter)
1100      evas_filter_changed_set(eo_obj, EINA_TRUE);
1101    evas_object_change(eo_obj, obj);
1102    evas_object_clip_dirty(eo_obj, obj);
1103    evas_object_coords_recalc(eo_obj, obj);
1104    if (obj->cur->visible)
1105      _evas_canvas_event_pointer_in_list_mouse_move_feed(obj->layer->evas, was, eo_obj, obj, 1, 1, EINA_FALSE, NULL);
1106    eina_list_free(was);
1107    evas_object_inform_call_resize(eo_obj, obj);
1108 }
1109 
1110 EOLIAN static void
_evas_text_bidi_delimiters_set(Eo * eo_obj,Evas_Text_Data * o,const char * delim)1111 _evas_text_bidi_delimiters_set(Eo *eo_obj, Evas_Text_Data *o, const char *delim)
1112 {
1113    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1114    evas_object_async_block(obj);
1115    eina_stringshare_replace(&o->bidi_delimiters, delim);
1116 }
1117 
1118 EOLIAN static const char*
_evas_text_bidi_delimiters_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1119 _evas_text_bidi_delimiters_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1120 {
1121    return o->bidi_delimiters;
1122 }
1123 
1124 EOLIAN static const char*
_evas_text_efl_text_text_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1125 _evas_text_efl_text_text_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1126 {
1127    return o->cur.utf8_text;
1128 }
1129 
1130 EOLIAN static Efl_Text_Bidirectional_Type
_evas_text_direction_get(const Eo * eo_obj,Evas_Text_Data * o)1131 _evas_text_direction_get(const Eo *eo_obj, Evas_Text_Data *o)
1132 {
1133 #ifdef BIDI_SUPPORT
1134    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1135 
1136    if (o->inherit_paragraph_direction)
1137      {
1138         Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
1139 
1140         if (obj->smart.parent)
1141           parent_dir = evas_object_paragraph_direction_get(obj->smart.parent);
1142 
1143         if (parent_dir != o->paragraph_direction)
1144           {
1145              o->paragraph_direction = parent_dir;
1146              o->changed_paragraph_direction = EINA_TRUE;
1147           }
1148      }
1149 
1150    if (o->changed_paragraph_direction)
1151      {
1152         /* XXX const? */
1153         _evas_object_text_recalc((Evas_Object *)eo_obj, o->cur.text);
1154         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1155                                             (Evas_Object *)eo_obj, obj);
1156      }
1157 #else
1158    (void)eo_obj;
1159 #endif
1160 
1161    return (Efl_Text_Bidirectional_Type)o->bidi_dir;
1162 }
1163 
1164 EOLIAN static Evas_Coord
_evas_text_ascent_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1165 _evas_text_ascent_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1166 {
1167    return o->ascent;
1168 }
1169 
1170 EOLIAN static Evas_Coord
_evas_text_descent_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1171 _evas_text_descent_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1172 {
1173    return o->descent;
1174 }
1175 
1176 EOLIAN static Evas_Coord
_evas_text_max_ascent_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1177 _evas_text_max_ascent_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1178 {
1179    return o->max_ascent;
1180 }
1181 
1182 EOLIAN static Evas_Coord
_evas_text_max_descent_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1183 _evas_text_max_descent_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1184 {
1185    return o->max_descent;
1186 }
1187 
1188 EOLIAN static Evas_Coord
_evas_text_inset_get(const Eo * eo_obj,Evas_Text_Data * o)1189 _evas_text_inset_get(const Eo *eo_obj, Evas_Text_Data *o)
1190 {
1191    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1192    Evas_Coord inset = 0;
1193    if (!o->font) return inset;
1194    if (!o->items) return inset;
1195    inset = ENFN->font_inset_get(ENC, o->font, &o->items->text_props);
1196 
1197    return inset;
1198 }
1199 
1200 EOLIAN static Evas_Coord
_evas_text_horiz_advance_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1201 _evas_text_horiz_advance_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1202 {
1203    Evas_Coord horiz = 0;
1204    if (!o->font) return horiz;
1205    if (!o->items) return horiz;
1206    horiz = _evas_object_text_horiz_advance_get(o);
1207 
1208    return horiz;
1209 }
1210 
1211 EOLIAN static Evas_Coord
_evas_text_vert_advance_get(const Eo * eo_obj,Evas_Text_Data * o)1212 _evas_text_vert_advance_get(const Eo *eo_obj, Evas_Text_Data *o)
1213 {
1214    Evas_Coord vert;
1215    vert = 0;
1216    if (!o->font) return vert;
1217    if (!o->items)
1218      {
1219         vert = o->max_ascent + o->max_descent;
1220         return vert;
1221      }
1222    vert = _evas_object_text_vert_advance_get(eo_obj, o);
1223 
1224    return vert;
1225 }
1226 
1227 EOLIAN static Eina_Bool
_evas_text_char_pos_get(const Eo * eo_obj,Evas_Text_Data * o,int pos,Evas_Coord * cx,Evas_Coord * cy,Evas_Coord * cw,Evas_Coord * ch)1228 _evas_text_char_pos_get(const Eo *eo_obj, Evas_Text_Data *o, int pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
1229 {
1230    Eina_Bool ret;
1231    ret = EINA_FALSE;
1232 
1233    int l = 0, r = 0, t = 0, b = 0;
1234    int x = 0, y = 0, w = 0, h = 0;
1235 
1236    if (!o->font) return ret;
1237    if (!o->items || (pos < 0)) return ret;
1238 
1239    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1240 
1241    Eina_Bool int_ret = _evas_object_text_char_coords_get(eo_obj, o, (size_t) pos,
1242             &x, &y, &w, &h);
1243 
1244    _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
1245    y += o->max_ascent - t;
1246    x -= l;
1247    if (x < 0)
1248      {
1249         w += x;
1250         x = 0;
1251      }
1252    if ((x + w) > obj->cur->geometry.w) w = obj->cur->geometry.w - x;
1253    if (w < 0) w = 0;
1254    if (y < 0)
1255      {
1256         h += y;
1257         y = 0;
1258      }
1259    if ((y + h) > obj->cur->geometry.h) h = obj->cur->geometry.h - y;
1260    if (h < 0) h = 0;
1261    if (cx) *cx = x;
1262    if (cy) *cy = y;
1263    if (cw) *cw = w + l + r;
1264    if (ch) *ch = h + t + b;
1265    ret = int_ret;
1266 
1267    return ret;
1268 }
1269 
1270 EOLIAN static int
_evas_text_last_up_to_pos(const Eo * eo_obj,Evas_Text_Data * o,Evas_Coord x,Evas_Coord y)1271 _evas_text_last_up_to_pos(const Eo *eo_obj, Evas_Text_Data *o, Evas_Coord x, Evas_Coord y)
1272 {
1273    int ret;
1274    ret = -1;
1275 
1276    if (!o->font) return ret;
1277    if (!o->items) return ret;
1278    int int_ret = _evas_object_text_last_up_to_pos(eo_obj, o, x, y - o->max_ascent);
1279    ret = int_ret;
1280 
1281    return ret;
1282 }
1283 
1284 EOLIAN static int
_evas_text_char_coords_get(const Eo * eo_obj,Evas_Text_Data * o,Evas_Coord x,Evas_Coord y,Evas_Coord * cx,Evas_Coord * cy,Evas_Coord * cw,Evas_Coord * ch)1285 _evas_text_char_coords_get(const Eo *eo_obj, Evas_Text_Data *o, Evas_Coord x, Evas_Coord y, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
1286 {
1287    int ret;
1288    ret = -1;
1289 
1290    int l = 0, r = 0, t = 0, b = 0;
1291    int rx = 0, ry = 0, rw = 0, rh = 0;
1292 
1293    if (!o->font) return ret;
1294    if (!o->items) return ret;
1295 
1296    int int_ret = _evas_object_text_char_at_coords(eo_obj, o, x, y - o->max_ascent,
1297          &rx, &ry, &rw, &rh);
1298    _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
1299    ry += o->max_ascent - t;
1300    rx -= l;
1301    if (rx < 0)
1302      {
1303         rw += rx;
1304         rx = 0;
1305      }
1306    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1307    if ((rx + rw) > obj->cur->geometry.w) rw = obj->cur->geometry.w - rx;
1308    if (rw < 0) rw = 0;
1309    if (ry < 0)
1310      {
1311         rh += ry;
1312         ry = 0;
1313      }
1314    if ((ry + rh) > obj->cur->geometry.h) rh = obj->cur->geometry.h - ry;
1315    if (rh < 0) rh = 0;
1316    if (cx) *cx = rx;
1317    if (cy) *cy = ry;
1318    if (cw) *cw = rw + l + r;
1319    if (ch) *ch = rh + t + b;
1320    ret = int_ret;
1321 
1322    return ret;
1323 }
1324 
1325 EOLIAN static void
_evas_text_style_set(Eo * eo_obj,Evas_Text_Data * o,Evas_Text_Style_Type style)1326 _evas_text_style_set(Eo *eo_obj, Evas_Text_Data *o, Evas_Text_Style_Type style)
1327 {
1328    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1329    int pl = 0, pr = 0, pt = 0, pb = 0, l = 0, r = 0, t = 0, b = 0;
1330    int w = 0, h = 0;
1331 
1332    if (o->cur.style == style) return;
1333    evas_object_async_block(obj);
1334 
1335    _evas_object_text_pad_get(eo_obj, o, &pl, &pr, &pt, &pb);
1336    //evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb);
1337    o->cur.style = style;
1338    _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
1339    //evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
1340 
1341    if (o->items) w = obj->cur->geometry.w + (l - pl) + (r - pr);
1342    h = obj->cur->geometry.h + (t - pt) + (b - pb);
1343 
1344    efl_gfx_entity_size_set(efl_super(eo_obj, MY_CLASS), EINA_SIZE2D(w,  h));
1345    evas_object_change(eo_obj, obj);
1346 }
1347 
1348 EOLIAN static Evas_Text_Style_Type
_evas_text_style_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)1349 _evas_text_style_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
1350 {
1351    return o->cur.style;
1352 }
1353 
1354 EOLIAN static void
_evas_text_shadow_color_set(Eo * eo_obj,Evas_Text_Data * o,int r,int g,int b,int a)1355 _evas_text_shadow_color_set(Eo *eo_obj, Evas_Text_Data *o, int r, int g, int b, int a)
1356 {
1357    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1358    if ((o->cur.shadow.r == r) && (o->cur.shadow.g == g) &&
1359        (o->cur.shadow.b == b) && (o->cur.shadow.a == a))
1360      return;
1361    evas_object_async_block(obj);
1362    o->cur.shadow.r = r;
1363    o->cur.shadow.g = g;
1364    o->cur.shadow.b = b;
1365    o->cur.shadow.a = a;
1366    o->changed = 1;
1367    evas_object_change(eo_obj, obj);
1368 }
1369 
1370 EOLIAN static void
_evas_text_shadow_color_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o,int * r,int * g,int * b,int * a)1371 _evas_text_shadow_color_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *r, int *g, int *b, int *a)
1372 {
1373    if (r) *r = o->cur.shadow.r;
1374    if (g) *g = o->cur.shadow.g;
1375    if (b) *b = o->cur.shadow.b;
1376    if (a) *a = o->cur.shadow.a;
1377 }
1378 
1379 EOLIAN static void
_evas_text_glow_color_set(Eo * eo_obj,Evas_Text_Data * o,int r,int g,int b,int a)1380 _evas_text_glow_color_set(Eo *eo_obj, Evas_Text_Data *o, int r, int g, int b, int a)
1381 {
1382    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1383    if ((o->cur.glow.r == r) && (o->cur.glow.g == g) &&
1384        (o->cur.glow.b == b) && (o->cur.glow.a == a))
1385      return;
1386    evas_object_async_block(obj);
1387    o->cur.glow.r = r;
1388    o->cur.glow.g = g;
1389    o->cur.glow.b = b;
1390    o->cur.glow.a = a;
1391    o->changed = 1;
1392    evas_object_change(eo_obj, obj);
1393 }
1394 
1395 EOLIAN static void
_evas_text_glow_color_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o,int * r,int * g,int * b,int * a)1396 _evas_text_glow_color_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *r, int *g, int *b, int *a)
1397 {
1398    if (r) *r = o->cur.glow.r;
1399    if (g) *g = o->cur.glow.g;
1400    if (b) *b = o->cur.glow.b;
1401    if (a) *a = o->cur.glow.a;
1402 }
1403 
1404 EOLIAN static void
_evas_text_glow2_color_set(Eo * eo_obj,Evas_Text_Data * o,int r,int g,int b,int a)1405 _evas_text_glow2_color_set(Eo *eo_obj, Evas_Text_Data *o, int r, int g, int b, int a)
1406 {
1407    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1408    if ((o->cur.glow2.r == r) && (o->cur.glow2.g == g) &&
1409        (o->cur.glow2.b == b) && (o->cur.glow2.a == a))
1410      return;
1411    evas_object_async_block(obj);
1412    o->cur.glow2.r = r;
1413    o->cur.glow2.g = g;
1414    o->cur.glow2.b = b;
1415    o->cur.glow2.a = a;
1416    o->changed = 1;
1417    evas_object_change(eo_obj, obj);
1418 }
1419 
1420 EOLIAN static void
_evas_text_glow2_color_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o,int * r,int * g,int * b,int * a)1421 _evas_text_glow2_color_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *r, int *g, int *b, int *a)
1422 {
1423    if (r) *r = o->cur.glow2.r;
1424    if (g) *g = o->cur.glow2.g;
1425    if (b) *b = o->cur.glow2.b;
1426    if (a) *a = o->cur.glow2.a;
1427 }
1428 
1429 EOLIAN static void
_evas_text_outline_color_set(Eo * eo_obj,Evas_Text_Data * o,int r,int g,int b,int a)1430 _evas_text_outline_color_set(Eo *eo_obj, Evas_Text_Data *o, int r, int g, int b, int a)
1431 {
1432    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1433    if ((o->cur.outline.r == r) && (o->cur.outline.g == g) &&
1434        (o->cur.outline.b == b) && (o->cur.outline.a == a))
1435      return;
1436    evas_object_async_block(obj);
1437    o->cur.outline.r = r;
1438    o->cur.outline.g = g;
1439    o->cur.outline.b = b;
1440    o->cur.outline.a = a;
1441    o->changed = 1;
1442    evas_object_change(eo_obj, obj);
1443 }
1444 
1445 EOLIAN static void
_evas_text_outline_color_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o,int * r,int * g,int * b,int * a)1446 _evas_text_outline_color_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *r, int *g, int *b, int *a)
1447 {
1448    if (r) *r = o->cur.outline.r;
1449    if (g) *g = o->cur.outline.g;
1450    if (b) *b = o->cur.outline.b;
1451    if (a) *a = o->cur.outline.a;
1452 }
1453 
1454 EOLIAN static void
_evas_text_style_pad_get(const Eo * eo_obj,Evas_Text_Data * o,int * l,int * r,int * t,int * b)1455 _evas_text_style_pad_get(const Eo *eo_obj, Evas_Text_Data *o, int *l, int *r, int *t, int *b)
1456 {
1457    _evas_object_text_pad_get(eo_obj, o, l, r, t, b);
1458 }
1459 
1460 EAPI int
evas_string_char_next_get(const char * str,int pos,int * decoded)1461 evas_string_char_next_get(const char *str, int pos, int *decoded)
1462 {
1463    int p, d;
1464 
1465    if ((!str) || (pos < 0))
1466      {
1467         if (decoded) *decoded = 0;
1468         return 0;
1469      }
1470    p = pos;
1471    d = eina_unicode_utf8_next_get(str, &p);
1472    if (decoded) *decoded = d;
1473    return p;
1474 }
1475 
1476 EAPI int
evas_string_char_prev_get(const char * str,int pos,int * decoded)1477 evas_string_char_prev_get(const char *str, int pos, int *decoded)
1478 {
1479    int p, d;
1480 
1481    if (decoded) *decoded = 0;
1482    if ((!str) || (pos < 1)) return 0;
1483    p = pos;
1484    d = eina_unicode_utf8_get_prev(str, &p);
1485    if (decoded) *decoded = d;
1486    return p;
1487 }
1488 
1489 EAPI int
evas_string_char_len_get(const char * str)1490 evas_string_char_len_get(const char *str)
1491 {
1492    if (!str) return 0;
1493    return eina_unicode_utf8_get_len(str);
1494 }
1495 
1496 void
evas_text_style_pad_get(Evas_Text_Style_Type style,int * l,int * r,int * t,int * b)1497 evas_text_style_pad_get(Evas_Text_Style_Type style, int *l, int *r, int *t, int *b)
1498 {
1499    int sl = 0, sr = 0, st = 0, sb = 0;
1500 
1501    /* Don't calc anything if there's no style. */
1502    if (style != EVAS_TEXT_STYLE_PLAIN)
1503      {
1504         int shad_sz = 0, shad_dst = 0, out_sz = 0;
1505         int dx = 0, minx = 0, maxx = 0;
1506         int dy = 0, miny = 0, maxy = 0;
1507         Eina_Bool have_shadow = EINA_FALSE;
1508 
1509         switch (style & EVAS_TEXT_STYLE_MASK_BASIC)
1510           {
1511            case EVAS_TEXT_STYLE_SHADOW:
1512               shad_dst = 1;
1513               have_shadow = EINA_TRUE;
1514               break;
1515            case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1516            case EVAS_TEXT_STYLE_FAR_SHADOW:
1517               shad_dst = 2;
1518               out_sz = 1;
1519               have_shadow = EINA_TRUE;
1520               break;
1521            case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1522               shad_dst = 1;
1523               shad_sz = 2;
1524               out_sz = 1;
1525               have_shadow = EINA_TRUE;
1526               break;
1527            case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1528               shad_dst = 2;
1529               shad_sz = 2;
1530               have_shadow = EINA_TRUE;
1531               break;
1532            case EVAS_TEXT_STYLE_SOFT_SHADOW:
1533               shad_dst = 1;
1534               shad_sz = 2;
1535               have_shadow = EINA_TRUE;
1536               break;
1537            case EVAS_TEXT_STYLE_GLOW:
1538            case EVAS_TEXT_STYLE_SOFT_OUTLINE:
1539               out_sz = 2;
1540               break;
1541            case EVAS_TEXT_STYLE_OUTLINE:
1542               out_sz = 1;
1543               break;
1544            default:
1545               break;
1546           }
1547 
1548         minx = -out_sz;
1549         maxx = out_sz;
1550         miny = -out_sz;
1551         maxy = out_sz;
1552         if (have_shadow)
1553           {
1554              int shx1, shx2, shy1, shy2;
1555              switch (style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1556                {
1557                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1558                    dx = 1;
1559                    dy = 1;
1560                    break;
1561                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1562                    dx = 0;
1563                    dy = 1;
1564                    break;
1565                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1566                    dx = -1;
1567                    dy = 1;
1568                    break;
1569                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1570                    dx = -1;
1571                    dy = 0;
1572                    break;
1573                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1574                    dx = -1;
1575                    dy = -1;
1576                    break;
1577                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1578                    dx = 0;
1579                    dy = -1;
1580                    break;
1581                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1582                    dx = 1;
1583                    dy = -1;
1584                    break;
1585                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1586                    dx = 1;
1587                    dy = 0;
1588                 default:
1589                    break;
1590                }
1591              shx1 = dx * shad_dst;
1592              shx1 -= shad_sz;
1593              shx2 = dx * shad_dst;
1594              shx2 += shad_sz;
1595              if (shx1 < minx) minx = shx1;
1596              if (shx2 > maxx) maxx = shx2;
1597 
1598              shy1 = dy * shad_dst;
1599              shy1 -= shad_sz;
1600              shy2 = dy * shad_dst;
1601              shy2 += shad_sz;
1602              if (shy1 < miny) miny = shy1;
1603              if (shy2 > maxy) maxy = shy2;
1604           }
1605 
1606         if (l) sl = *l;
1607         if (r) sr = *r;
1608         if (t) st = *t;
1609         if (b) sb = *b;
1610 
1611         if (sr < maxx) sr = maxx;
1612         if (sl < -minx) sl = -minx;
1613         if (sb < maxy) sb = maxy;
1614         if (st < -miny) st = -miny;
1615      }
1616 
1617    if (l) *l = sl;
1618    if (r) *r = sr;
1619    if (t) *t = st;
1620    if (b) *b = sb;
1621 }
1622 
1623 /* all nice and private */
1624 static void
evas_object_text_init(Evas_Object * eo_obj)1625 evas_object_text_init(Evas_Object *eo_obj)
1626 {
1627    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1628    /* set up methods (compulsory) */
1629    obj->func = &object_func;
1630    obj->private_data = efl_data_ref(eo_obj, MY_CLASS);
1631    obj->type = o_type;
1632 
1633    Evas_Text_Data *o = obj->private_data;
1634    /* alloc obj private data */
1635    o->prev.ellipsis = o->cur.ellipsis = -1.0;
1636    o->prev.bitmap_scalable = o->cur.bitmap_scalable = EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR;
1637    o->prev = o->cur;
1638 #ifdef BIDI_SUPPORT
1639    o->bidi_par_props = evas_bidi_paragraph_props_new();
1640    o->inherit_paragraph_direction = EINA_TRUE;
1641 #endif
1642 }
1643 
1644 EOLIAN static void
_evas_text_efl_object_destructor(Eo * eo_obj,Evas_Text_Data * o EINA_UNUSED)1645 _evas_text_efl_object_destructor(Eo *eo_obj, Evas_Text_Data *o EINA_UNUSED)
1646 {
1647    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1648    evas_object_text_free(eo_obj, obj);
1649    efl_destructor(efl_super(eo_obj, MY_CLASS));
1650 }
1651 
1652 static void
evas_object_text_free(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)1653 evas_object_text_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
1654 {
1655    Evas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1656 
1657    /* free obj */
1658    _evas_object_text_items_clear(o);
1659    if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text);
1660    if (o->cur.font) eina_stringshare_del(o->cur.font);
1661    if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
1662    if (o->cur.source) eina_stringshare_del(o->cur.source);
1663    if (o->bidi_delimiters) eina_stringshare_del(o->bidi_delimiters);
1664    if (o->cur.text) free(o->cur.text);
1665    if (obj->layer && obj->layer->evas)
1666       evas_font_free(o->font);
1667    o->font = NULL;
1668    o->cur.utf8_text = NULL;
1669    o->cur.font = NULL;
1670    o->cur.fdesc = NULL;
1671    o->cur.source = NULL;
1672    o->bidi_delimiters = NULL;
1673    o->cur.text = NULL;
1674    o->prev = o->cur;
1675 #ifdef BIDI_SUPPORT
1676    evas_bidi_paragraph_props_unref(o->bidi_par_props);
1677    o->bidi_par_props = NULL;
1678 #endif
1679 }
1680 
1681 void
evas_font_draw_async_check(Evas_Object_Protected_Data * obj,void * engine,void * data,void * context,void * surface,Evas_Font_Set * font,int x,int y,int w,int h,int ow,int oh,Evas_Text_Props * intl_props,Eina_Bool do_async)1682 evas_font_draw_async_check(Evas_Object_Protected_Data *obj,
1683                            void *engine, void *data, void *context, void *surface,
1684                            Evas_Font_Set *font,
1685                            int x, int y, int w, int h, int ow, int oh,
1686                            Evas_Text_Props *intl_props, Eina_Bool do_async)
1687 {
1688    Eina_Bool async_unref;
1689 
1690    async_unref = obj->layer->evas->engine.func->font_draw(engine, data, context, surface,
1691                                                           font, x, y, w, h, ow, oh,
1692                                                           intl_props, do_async);
1693    if (do_async && async_unref)
1694      {
1695         evas_common_font_glyphs_ref(intl_props->glyphs);
1696         evas_unref_queue_glyph_put(obj->layer->evas, intl_props->glyphs);
1697      }
1698 }
1699 
1700 /* ugly binding between evas_fitler_mixin.c and this object */
1701 
1702 EOLIAN static void
_evas_text_efl_canvas_filter_internal_filter_dirty(Eo * eo_obj,Evas_Text_Data * o)1703 _evas_text_efl_canvas_filter_internal_filter_dirty(Eo *eo_obj, Evas_Text_Data *o)
1704 {
1705    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1706 
1707    _evas_object_text_items_clear(o);
1708    o->changed = 1;
1709    evas_object_change(eo_obj, obj);
1710    _evas_object_text_recalc(eo_obj, o->cur.text);
1711 }
1712 
1713 EOLIAN static Eina_Bool
_evas_text_efl_canvas_filter_internal_filter_input_alpha(Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o EINA_UNUSED)1714 _evas_text_efl_canvas_filter_internal_filter_input_alpha(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o EINA_UNUSED)
1715 {
1716    return EINA_TRUE;
1717 }
1718 
1719 EOLIAN static void
_evas_text_efl_canvas_filter_internal_filter_state_prepare(Eo * eo_obj,Evas_Text_Data * o,Efl_Canvas_Filter_State * state,void * data EINA_UNUSED)1720 _evas_text_efl_canvas_filter_internal_filter_state_prepare(Eo *eo_obj, Evas_Text_Data *o,
1721                                                            Efl_Canvas_Filter_State *state, void *data EINA_UNUSED)
1722 {
1723    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1724 
1725 #define STATE_COLOR(dst, src) dst.r = src.r; dst.g = src.g; dst.b = src.b; dst.a = src.a
1726    STATE_COLOR(state->color, obj->cur->color);
1727    STATE_COLOR(state->text.glow, o->cur.glow);
1728    STATE_COLOR(state->text.glow2, o->cur.glow2);
1729    STATE_COLOR(state->text.shadow, o->cur.shadow);
1730    STATE_COLOR(state->text.outline, o->cur.outline);
1731 #undef STATE_COLOR
1732 
1733    state->w = obj->cur->geometry.w;
1734    state->h = obj->cur->geometry.h;
1735    state->scale = obj->cur->scale;
1736 }
1737 
1738 EOLIAN static Eina_Bool
_evas_text_efl_canvas_filter_internal_filter_input_render(Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o,void * _filter,void * engine,void * output,void * drawctx,void * draw EINA_UNUSED,int l,int r EINA_UNUSED,int t,int b EINA_UNUSED,int x,int y,Eina_Bool do_async)1739 _evas_text_efl_canvas_filter_internal_filter_input_render(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o,
1740                                                           void *_filter, void *engine, void *output, void *drawctx, void *draw EINA_UNUSED,
1741                                                           int l, int r EINA_UNUSED, int t, int b EINA_UNUSED,
1742                                                           int x, int y,
1743                                                           Eina_Bool do_async)
1744 {
1745    Evas_Filter_Context *filter = _filter;
1746    Evas_Object_Text_Item *it;
1747 
1748    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
1749      if ((o->font) && (it->text_props.len > 0))
1750        {
1751           if (!evas_filter_font_draw(filter, engine, output, drawctx,
1752                                      EVAS_FILTER_BUFFER_INPUT_ID, o->font,
1753                                      x + l + it->x,
1754                                      y + t + (int) o->max_ascent,
1755                                      &it->text_props,
1756                                      do_async))
1757             return EINA_FALSE;
1758        }
1759 
1760    return EINA_TRUE;
1761 }
1762 
1763 static void
evas_object_text_render(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data,void * engine,void * output,void * context,void * surface,int x,int y,Eina_Bool do_async)1764 evas_object_text_render(Evas_Object *eo_obj,
1765                         Evas_Object_Protected_Data *obj,
1766                         void *type_private_data,
1767                         void *engine, void *output, void *context, void *surface,
1768                         int x, int y, Eina_Bool do_async)
1769 {
1770    int i, j;
1771    Evas_Text_Data *o = type_private_data;
1772    Evas_Object_Text_Item *it;
1773    const char vals[5][5] =
1774      {
1775         {0, 1, 2, 1, 0},
1776         {1, 3, 4, 3, 1},
1777         {2, 4, 5, 4, 2},
1778         {1, 3, 4, 3, 1},
1779         {0, 1, 2, 1, 0}
1780      };
1781    int sl = 0, st = 0;
1782    int shad_dst = 0, shad_sz = 0, dx = 0, dy = 0, haveshad = 0;
1783 
1784    /* render object to surface with context, and offxet by x,y */
1785    _evas_object_text_pad_get(eo_obj, o, &sl, NULL, &st, NULL);
1786    ENFN->context_multiplier_unset(engine, context);
1787    ENFN->context_render_op_set(engine, context, obj->cur->render_op);
1788    /* FIXME: This clipping is just until we fix inset handling correctly. */
1789    ENFN->context_clip_clip(engine, context,
1790                            obj->cur->geometry.x + x,
1791                            obj->cur->geometry.y + y,
1792                            obj->cur->geometry.w,
1793                            obj->cur->geometry.h);
1794 
1795 /*
1796    ENFN->context_color_set(output,
1797                            context,
1798                            230, 160, 30, 100);
1799    ENFN->rectangle_draw(output,
1800                         context,
1801                         surface,
1802                         obj->cur->geometry.x + x,
1803                         obj->cur->geometry.y + y,
1804                         obj->cur->geometry.w,
1805                         obj->cur->geometry.h);
1806  */
1807 #define COLOR_ONLY_SET(object, sub, col) \
1808     ENFN->context_color_set(engine, context, \
1809                 object->sub.col.r, \
1810                 object->sub.col.g, \
1811                 object->sub.col.b, \
1812                 object->sub.col.a);
1813 
1814 #define COLOR_SET(object, sub, col) \
1815         if (obj->cur->clipper)\
1816           { \
1817              ENFN->context_color_set(engine, context, \
1818                 ((int)object->sub.col.r * ((int)obj->cur->clipper->cur->cache.clip.r + 1)) >> 8, \
1819                 ((int)object->sub.col.g * ((int)obj->cur->clipper->cur->cache.clip.g + 1)) >> 8, \
1820                 ((int)object->sub.col.b * ((int)obj->cur->clipper->cur->cache.clip.b + 1)) >> 8, \
1821                 ((int)object->sub.col.a * ((int)obj->cur->clipper->cur->cache.clip.a + 1)) >> 8); \
1822           } \
1823         else\
1824           ENFN->context_color_set(engine, context, \
1825                 object->sub.col.r, \
1826                 object->sub.col.g, \
1827                 object->sub.col.b, \
1828                 object->sub.col.a);
1829 
1830 #define COLOR_SET_AMUL(object, sub, col, amul) \
1831         if (obj->cur->clipper) \
1832           { \
1833              ENFN->context_color_set(engine, context, \
1834                 (((int)object->sub.col.r) * ((int)obj->cur->clipper->cur->cache.clip.r) * (amul)) / 65025, \
1835                 (((int)object->sub.col.g) * ((int)obj->cur->clipper->cur->cache.clip.g) * (amul)) / 65025, \
1836                 (((int)object->sub.col.b) * ((int)obj->cur->clipper->cur->cache.clip.b) * (amul)) / 65025, \
1837                 (((int)object->sub.col.a) * ((int)obj->cur->clipper->cur->cache.clip.a) * (amul)) / 65025); \
1838           } \
1839         else \
1840           ENFN->context_color_set(engine, context, \
1841                 (((int)object->sub.col.r) * (amul)) / 255, \
1842                 (((int)object->sub.col.g) * (amul)) / 255, \
1843                 (((int)object->sub.col.b) * (amul)) / 255, \
1844                 (((int)object->sub.col.a) * (amul)) / 255);
1845 
1846 #define DRAW_TEXT(ox, oy) \
1847    if ((o->font) && (it->text_props.len > 0)) {                         \
1848       ENFN->context_cutout_target(engine, context,              \
1849                                   obj->cur->geometry.x + x + sl + ox + it->x, \
1850                                   obj->cur->geometry.y + y + st + oy,   \
1851                                   it->w, it->h);                        \
1852       evas_font_draw_async_check(obj, engine,                           \
1853                                  output,                                \
1854                                  context,                               \
1855                                  surface,                               \
1856                                  o->font,                               \
1857                                  obj->cur->geometry.x + x + sl + ox + it->x, \
1858                                  obj->cur->geometry.y + y + st + oy +   \
1859                                  (int)o->max_ascent,                    \
1860                                  obj->cur->geometry.w,                  \
1861                                  obj->cur->geometry.h,                  \
1862                                  obj->cur->geometry.w,                  \
1863                                  obj->cur->geometry.h,                  \
1864                                  &it->text_props,                       \
1865                                  do_async);                             \
1866    }
1867 
1868    if (o->has_filter)
1869      {
1870         if (evas_filter_object_render(eo_obj, obj,
1871                                       engine, output, context, surface,
1872                                       x, y, do_async, EINA_TRUE))
1873           return;
1874      }
1875 
1876    /* shadows */
1877    switch (o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC)
1878      {
1879       case EVAS_TEXT_STYLE_SHADOW:
1880          shad_dst = 1;
1881          haveshad = 1;
1882          break;
1883       case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1884          shad_dst = 1;
1885          shad_sz = 2;
1886          haveshad = 1;
1887          break;
1888       case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1889       case EVAS_TEXT_STYLE_FAR_SHADOW:
1890          shad_dst = 2;
1891          haveshad = 1;
1892          break;
1893       case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1894          shad_dst = 2;
1895          shad_sz = 2;
1896          haveshad = 1;
1897          break;
1898       case EVAS_TEXT_STYLE_SOFT_SHADOW:
1899          shad_dst = 1;
1900          shad_sz = 2;
1901          haveshad = 1;
1902          break;
1903       default:
1904          break;
1905      }
1906    if (haveshad)
1907      {
1908         if (shad_dst > 0)
1909           {
1910              switch (o->cur.style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1911                {
1912                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1913                    dx = 1;
1914                    dy = 1;
1915                    break;
1916                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1917                    dx = 0;
1918                    dy = 1;
1919                    break;
1920                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1921                    dx = -1;
1922                    dy = 1;
1923                    break;
1924                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1925                    dx = -1;
1926                    dy = 0;
1927                    break;
1928                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1929                    dx = -1;
1930                    dy = -1;
1931                    break;
1932                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1933                    dx = 0;
1934                    dy = -1;
1935                    break;
1936                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1937                    dx = 1;
1938                    dy = -1;
1939                    break;
1940                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1941                    dx = 1;
1942                    dy = 0;
1943                 default:
1944                    break;
1945                }
1946              dx *= shad_dst;
1947              dy *= shad_dst;
1948           }
1949      }
1950    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
1951      {
1952         ENFN->context_multiplier_set(engine, context, 0, 0, 0, 0);
1953         /* Shadows */
1954         if (haveshad)
1955           {
1956              switch (shad_sz)
1957                {
1958                 case 0:
1959                   COLOR_SET(o, cur, shadow);
1960                   DRAW_TEXT(dx, dy);
1961                   break;
1962                 case 2:
1963                   for (j = 0; j < 5; j++)
1964                     {
1965                        for (i = 0; i < 5; i++)
1966                          {
1967                             if (vals[i][j] != 0)
1968                               {
1969                                  COLOR_SET_AMUL(o, cur, shadow, vals[i][j] * 50);
1970                                  DRAW_TEXT(i - 2 + dx, j - 2 + dy);
1971                               }
1972                          }
1973                     }
1974                   break;
1975                 default:
1976                   break;
1977                }
1978           }
1979 
1980         /* glows */
1981         if (o->cur.style == EVAS_TEXT_STYLE_GLOW)
1982           {
1983              for (j = 0; j < 5; j++)
1984                {
1985                   for (i = 0; i < 5; i++)
1986                     {
1987                        if (vals[i][j] != 0)
1988                          {
1989                             COLOR_SET_AMUL(o, cur, glow, vals[i][j] * 50);
1990                             DRAW_TEXT(i - 2, j - 2);
1991                          }
1992                     }
1993                }
1994              COLOR_SET(o, cur, glow2);
1995              DRAW_TEXT(-1, 0);
1996              DRAW_TEXT(1, 0);
1997              DRAW_TEXT(0, -1);
1998              DRAW_TEXT(0, 1);
1999           }
2000 
2001         /* outlines */
2002         if (((o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE) ||
2003             ((o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
2004             ((o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
2005           {
2006              COLOR_SET(o, cur, outline);
2007              DRAW_TEXT(-1, 0);
2008              DRAW_TEXT(1, 0);
2009              DRAW_TEXT(0, -1);
2010              DRAW_TEXT(0, 1);
2011           }
2012         else if (o->cur.style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
2013           {
2014              for (j = 0; j < 5; j++)
2015                {
2016                   for (i = 0; i < 5; i++)
2017                     {
2018                        if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
2019                          {
2020                             COLOR_SET_AMUL(o, cur, outline, vals[i][j] * 50);
2021                             DRAW_TEXT(i - 2, j - 2);
2022                          }
2023                     }
2024                }
2025           }
2026 
2027         /* normal text */
2028         ENFN->context_multiplier_unset(engine, context);
2029 
2030         if (obj->cur->clipper)
2031           ENFN->context_multiplier_set(engine, context,
2032                                        obj->cur->clipper->cur->cache.clip.r,
2033                                        obj->cur->clipper->cur->cache.clip.g,
2034                                        obj->cur->clipper->cur->cache.clip.b,
2035                                        obj->cur->clipper->cur->cache.clip.a);
2036 
2037         COLOR_ONLY_SET(obj, cur->cache, clip);
2038         DRAW_TEXT(0, 0);
2039         ENFN->context_multiplier_unset(engine, context);
2040      }
2041 }
2042 
2043 static void
evas_object_text_render_pre(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data)2044 evas_object_text_render_pre(Evas_Object *eo_obj,
2045 			    Evas_Object_Protected_Data *obj,
2046 			    void *type_private_data)
2047 {
2048    Evas_Text_Data *o = type_private_data;
2049    int is_v = 0, was_v = 0;
2050    /* dont pre-render the obj twice! */
2051    if (obj->pre_render_done) return;
2052    obj->pre_render_done = EINA_TRUE;
2053    /* pre-render phase. this does anything an object needs to do just before
2054     rendering. This could mean loading the image data, retrieving it from
2055     elsewhere, decoding video etc.
2056     Then when this is done the object needs to figure if it changed and
2057     if so what and where and add the appropriate redraw rectangles */
2058    /* if someone is clipping this obj - go calculate the clipper */
2059    if (obj->cur->clipper)
2060      {
2061         if (obj->cur->cache.clip.dirty)
2062           {
2063              evas_object_clip_recalc(obj->cur->clipper);
2064           }
2065         obj->cur->clipper->func->render_pre(obj->cur->clipper->object,
2066                         obj->cur->clipper,
2067                         obj->cur->clipper->private_data);
2068      }
2069 
2070    /* If object size changed and ellipsis is set */
2071    if (((o->cur.ellipsis >= 0.0) &&
2072        ((obj->cur->geometry.w != o->last_computed.w) ||
2073        (obj->cur->geometry.h != o->last_computed.h))) ||
2074        (!EINA_DBL_EQ(o->cur.ellipsis, o->prev.ellipsis)) ||
2075        (!EINA_DBL_EQ(obj->cur->scale, obj->prev->scale)) ||
2076        (o->changed_paragraph_direction))
2077      {
2078         _evas_object_text_recalc(eo_obj, o->cur.text);
2079         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2080                         eo_obj, obj);
2081         goto done;
2082      }
2083    /* now figure what changed and add draw rects
2084     if it just became visible or invisible */
2085    is_v = evas_object_is_visible(obj);
2086    was_v = evas_object_was_visible(obj);
2087    if (is_v != was_v)
2088      {
2089         evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes,
2090                           eo_obj, is_v, was_v);
2091         goto done;
2092      }
2093    if (obj->changed_map || obj->changed_src_visible)
2094      {
2095         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2096                           eo_obj, obj);
2097         goto done;
2098      }
2099    /* its not visible - we accounted for it appearing or not so just abort */
2100    if (!is_v) goto done;
2101    /* clipper changed this is in addition to anything else for obj */
2102    evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, eo_obj);
2103    /* if we restacked (layer or just within a layer) and dont clip anyone */
2104    if (obj->restack)
2105      {
2106         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2107                           eo_obj, obj);
2108         goto done;
2109      }
2110    /* if it changed color */
2111    if ((obj->cur->color.r != obj->prev->color.r) ||
2112        (obj->cur->color.g != obj->prev->color.g) ||
2113        (obj->cur->color.b != obj->prev->color.b) ||
2114        (obj->cur->color.a != obj->prev->color.a))
2115      {
2116         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2117                           eo_obj, obj);
2118         goto done;
2119      }
2120    /* if it changed geometry - and obviously not visibility or color
2121     calculate differences since we have a constant color fill
2122     we really only need to update the differences */
2123    if ((obj->cur->geometry.x != obj->prev->geometry.x) ||
2124        (obj->cur->geometry.y != obj->prev->geometry.y) ||
2125        (obj->cur->geometry.w != obj->prev->geometry.w) ||
2126        (obj->cur->geometry.h != obj->prev->geometry.h))
2127      {
2128         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2129                          eo_obj, obj);
2130         goto done;
2131      }
2132    if (obj->cur->render_op != obj->prev->render_op)
2133      {
2134         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2135                          eo_obj, obj);
2136         goto done;
2137      }
2138    if (o->changed)
2139      {
2140         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
2141                                             eo_obj, obj);
2142         goto done;
2143      }
2144    done:
2145    evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes,
2146                      eo_obj, is_v, was_v);
2147 }
2148 
2149 static void
evas_object_text_render_post(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data EINA_UNUSED)2150 evas_object_text_render_post(Evas_Object *eo_obj EINA_UNUSED,
2151                              Evas_Object_Protected_Data *obj,
2152                              void *type_private_data EINA_UNUSED)
2153 {
2154    /* this moves the current data to the previous state parts of the object
2155     in whatever way is safest for the object. also if we don't need object
2156     data anymore we can free it if the object deems this is a good idea */
2157    /* remove those pesky changes */
2158    evas_object_clip_changes_clean(obj);
2159    /* move cur to prev safely for object data */
2160    evas_object_cur_prev(obj);
2161 }
2162 
2163 static void *
evas_object_text_engine_data_get(Evas_Object * eo_obj)2164 evas_object_text_engine_data_get(Evas_Object *eo_obj)
2165 {
2166    Evas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
2167    if (!o) return NULL;
2168    return o->font;
2169 }
2170 
2171 static int
evas_object_text_is_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,void * type_private_data EINA_UNUSED)2172 evas_object_text_is_opaque(Evas_Object *eo_obj EINA_UNUSED,
2173                            Evas_Object_Protected_Data *obj EINA_UNUSED,
2174                            void *type_private_data EINA_UNUSED)
2175 {
2176    /* this returns 1 if the internal object data implies that the object is
2177     currently fully opaque over the entire gradient it occupies */
2178    return 0;
2179 }
2180 
2181 static int
evas_object_text_was_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,void * type_private_data EINA_UNUSED)2182 evas_object_text_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
2183                             Evas_Object_Protected_Data *obj EINA_UNUSED,
2184                             void *type_private_data EINA_UNUSED)
2185 {
2186    /* this returns 1 if the internal object data implies that the object was
2187     currently fully opaque over the entire gradient it occupies */
2188    return 0;
2189 }
2190 
2191 EOLIAN static void
_evas_text_efl_gfx_entity_scale_set(Evas_Object * eo_obj,Evas_Text_Data * o,double scale)2192 _evas_text_efl_gfx_entity_scale_set(Evas_Object *eo_obj, Evas_Text_Data *o,
2193                                  double scale)
2194 {
2195    int size;
2196    const char *font;
2197 
2198    if (EINA_DBL_EQ(efl_gfx_entity_scale_get(eo_obj), scale)) return;
2199    efl_gfx_entity_scale_set(efl_super(eo_obj, MY_CLASS), scale);
2200 
2201    font = eina_stringshare_add(o->cur.font);
2202    size = o->cur.size;
2203    if (o->cur.font) eina_stringshare_del(o->cur.font);
2204    if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
2205    o->cur.fdesc = NULL;
2206    o->cur.font = NULL;
2207    o->prev.font = NULL;
2208    o->cur.size = 0;
2209    o->prev.size = 0;
2210    evas_object_text_font_set(eo_obj, font, size);
2211 }
2212 
2213 void
_evas_object_text_rehint(Evas_Object * eo_obj)2214 _evas_object_text_rehint(Evas_Object *eo_obj)
2215 {
2216    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2217    Evas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
2218    Eina_List *was = NULL;
2219 
2220    if (!o->font) return;
2221    evas_font_load_hinting_set(o->font, obj->layer->evas->hinting);
2222    was = _evas_pointer_list_in_rect_get(obj->layer->evas, eo_obj, obj, 1, 1);
2223    /* DO II */
2224    _evas_object_text_recalc(eo_obj, o->cur.text);
2225    o->changed = 1;
2226    if (o->has_filter)
2227      evas_filter_changed_set(eo_obj, EINA_TRUE);
2228    evas_object_change(eo_obj, obj);
2229    evas_object_clip_dirty(eo_obj, obj);
2230    evas_object_coords_recalc(eo_obj, obj);
2231    if (obj->cur->visible)
2232      _evas_canvas_event_pointer_in_list_mouse_move_feed(obj->layer->evas, was, eo_obj, obj, 1, 1, EINA_FALSE, NULL);
2233    eina_list_free(was);
2234    evas_object_inform_call_resize(eo_obj, obj);
2235 }
2236 
2237 static void
_evas_object_text_recalc(Evas_Object * eo_obj,Eina_Unicode * text)2238 _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text)
2239 {
2240    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2241    Evas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
2242 
2243    if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
2244 
2245    _evas_object_text_layout(eo_obj, o, text);
2246 
2247    /* Calc ascent/descent. */
2248    if (o->items)
2249      {
2250 /*
2251         Evas_Object_Text_Item *item;
2252 
2253         for (item = o->items ; item ;
2254               item = EINA_INLIST_CONTAINER_GET(
2255                  EINA_INLIST_GET(item)->next, Evas_Object_Text_Item))
2256           {
2257              int asc = 0, desc = 0;
2258 
2259              // Skip items without meaning full information.
2260              if (!item->text_props.font_instance) continue;
2261 
2262              asc = evas_common_font_instance_ascent_get(item->text_props.font_instance);
2263              desc = evas_common_font_instance_descent_get(item->text_props.font_instance);
2264              if (asc > o->ascent) o->ascent = asc;
2265              if (desc > o->descent) o->descent = desc;
2266 
2267              asc = evas_common_font_instance_max_ascent_get(item->text_props.font_instance);
2268              desc = evas_common_font_instance_max_descent_get(item->text_props.font_instance);
2269              if (asc > o->max_ascent) o->max_ascent = asc;
2270              if (desc > o->max_descent) o->max_descent = desc;
2271           }
2272  */
2273         if (o->font)
2274           {
2275              o->ascent = ENFN->font_ascent_get(ENC, o->font);
2276              o->descent = ENFN->font_descent_get(ENC, o->font);
2277              o->max_ascent = ENFN->font_max_ascent_get(ENC, o->font);
2278              o->max_descent = ENFN->font_max_descent_get(ENC, o->font);
2279           }
2280      }
2281    else if (o->font)
2282      {
2283         o->ascent = ENFN->font_ascent_get(ENC, o->font);
2284         o->descent = ENFN->font_descent_get(ENC, o->font);
2285         o->max_ascent = ENFN->font_max_ascent_get(ENC, o->font);
2286         o->max_descent = ENFN->font_max_descent_get(ENC, o->font);
2287      }
2288 
2289    if ((o->font) && (o->items))
2290      {
2291         int w, h;
2292         int l = 0, r = 0, t = 0, b = 0;
2293 
2294         w = _evas_object_text_horiz_width_without_ellipsis_get(o);
2295         h = _evas_object_text_vert_advance_get(eo_obj, o);
2296         _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
2297 
2298         if (o->cur.ellipsis >= 0.0)
2299           {
2300              int min;
2301 
2302              min = w + l + r < obj->cur->geometry.w || obj->cur->geometry.w == 0 ? w + l + r : obj->cur->geometry.w;
2303              efl_gfx_entity_size_set(efl_super(eo_obj, MY_CLASS), EINA_SIZE2D(min,  h + t + b));
2304           }
2305         else
2306           {
2307              efl_gfx_entity_size_set(efl_super(eo_obj, MY_CLASS), EINA_SIZE2D(w + l + r,  h + t + b));
2308           }
2309 ////        obj->cur->cache.geometry.validity = 0;
2310      }
2311    else
2312      {
2313         int t = 0, b = 0, l = 0, r = 0;
2314         _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
2315         efl_gfx_entity_size_set(efl_super(eo_obj, MY_CLASS), EINA_SIZE2D(0,  o->max_ascent + o->max_descent + t + b));
2316 ////        obj->cur->cache.geometry.validity = 0;
2317      }
2318    o->last_computed.w = obj->cur->geometry.w;
2319    o->last_computed.h = obj->cur->geometry.h;
2320 #ifdef BIDI_SUPPORT
2321    o->changed_paragraph_direction = EINA_FALSE;
2322 #endif
2323 }
2324 
2325 EAPI void
evas_object_text_font_source_set(Eo * obj,const char * font_source)2326 evas_object_text_font_source_set(Eo *obj, const char *font_source)
2327 {
2328    efl_text_font_source_set((Eo *) obj, font_source);
2329 }
2330 
2331 EAPI const char *
evas_object_text_font_source_get(const Eo * obj)2332 evas_object_text_font_source_get(const Eo *obj)
2333 {
2334    const char *font_source = 0;
2335    font_source = efl_text_font_source_get((Eo *) obj);
2336    return font_source;
2337 }
2338 
2339 EAPI void
evas_object_text_font_set(Eo * obj,const char * font,Evas_Font_Size size)2340 evas_object_text_font_set(Eo *obj, const char *font, Evas_Font_Size size)
2341 {
2342    if (!font || size <= 0) return; /*Condition for legacy object*/
2343 
2344    efl_text_font_family_set((Eo *) obj, font);
2345    efl_text_font_size_set((Eo *) obj, size);
2346 }
2347 
2348 EAPI void
evas_object_text_font_get(const Eo * obj,const char ** font,Evas_Font_Size * size)2349 evas_object_text_font_get(const Eo *obj, const char **font, Evas_Font_Size *size)
2350 {
2351    if (font) *font = efl_text_font_family_get((Eo *) obj);
2352    if (size) *size = efl_text_font_size_get((Eo *) obj);
2353 }
2354 
2355 EAPI void
evas_object_text_text_set(Eo * obj,const char * text)2356 evas_object_text_text_set(Eo *obj, const char *text)
2357 {
2358    efl_text_set((Eo *) obj, text);
2359 }
2360 
2361 EAPI const char *
evas_object_text_text_get(const Eo * obj)2362 evas_object_text_text_get(const Eo *obj)
2363 {
2364    return efl_text_get((Eo *) obj);
2365 }
2366 
2367 EOLIAN static void
_evas_text_efl_gfx_filter_filter_program_set(Eo * obj,Evas_Text_Data * pd EINA_UNUSED,const char * code,const char * name)2368 _evas_text_efl_gfx_filter_filter_program_set(Eo *obj, Evas_Text_Data *pd EINA_UNUSED, const char *code, const char *name)
2369 {
2370    pd->has_filter = (code != NULL);
2371    efl_gfx_filter_program_set(efl_super(obj, MY_CLASS), code, name);
2372 }
2373 
2374 /* deprecated */
2375 EAPI void
evas_object_text_filter_program_set(Evas_Object * obj,const char * code)2376 evas_object_text_filter_program_set(Evas_Object *obj, const char *code)
2377 {
2378    efl_gfx_filter_program_set(obj, code, NULL);
2379 }
2380 
2381 /* deprecated */
2382 EAPI void
evas_object_text_filter_source_set(Evas_Object * obj,const char * name,Evas_Object * source)2383 evas_object_text_filter_source_set(Evas_Object *obj, const char *name, Evas_Object *source)
2384 {
2385    efl_gfx_filter_source_set(obj, name, source);
2386 }
2387 
2388 EOLIAN static void
_evas_text_efl_canvas_object_paragraph_direction_set(Eo * eo_obj,Evas_Text_Data * o,Efl_Text_Bidirectional_Type dir)2389 _evas_text_efl_canvas_object_paragraph_direction_set(Eo *eo_obj, Evas_Text_Data *o,
2390                                                      Efl_Text_Bidirectional_Type dir)
2391 {
2392 #ifdef BIDI_SUPPORT
2393    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2394 
2395    if ((!(o->inherit_paragraph_direction) && (o->paragraph_direction == (Evas_BiDi_Direction)dir)) ||
2396        (o->inherit_paragraph_direction && ((Evas_BiDi_Direction)dir == EVAS_BIDI_DIRECTION_INHERIT)))
2397      return;
2398 
2399    if (dir == (Efl_Text_Bidirectional_Type)EVAS_BIDI_DIRECTION_INHERIT)
2400      {
2401         o->inherit_paragraph_direction = EINA_TRUE;
2402         Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
2403 
2404         if (obj->smart.parent)
2405           parent_dir = evas_object_paragraph_direction_get(obj->smart.parent);
2406 
2407         if (parent_dir != o->paragraph_direction)
2408           {
2409              o->paragraph_direction = parent_dir;
2410              o->changed_paragraph_direction = EINA_TRUE;
2411              evas_object_change(eo_obj, obj);
2412           }
2413      }
2414    else
2415      {
2416         o->inherit_paragraph_direction = EINA_FALSE;
2417         o->paragraph_direction = dir;
2418         o->changed_paragraph_direction = EINA_TRUE;
2419         evas_object_change(eo_obj, obj);
2420      }
2421 #else
2422    (void) eo_obj;
2423    (void) o;
2424    (void) dir;
2425 #endif
2426 }
2427 
2428 EOLIAN static Efl_Text_Bidirectional_Type
_evas_text_efl_canvas_object_paragraph_direction_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)2429 _evas_text_efl_canvas_object_paragraph_direction_get(const Eo *eo_obj EINA_UNUSED,
2430                                                      Evas_Text_Data *o)
2431 {
2432    return (Efl_Text_Bidirectional_Type)o->paragraph_direction;
2433 }
2434 
2435 EOLIAN static void
_evas_text_efl_text_font_font_bitmap_scalable_set(Eo * eo_obj,Evas_Text_Data * o,Efl_Text_Font_Bitmap_Scalable bitmap_scalable)2436 _evas_text_efl_text_font_font_bitmap_scalable_set(Eo *eo_obj, Evas_Text_Data *o, Efl_Text_Font_Bitmap_Scalable bitmap_scalable)
2437 {
2438    if (o->cur.bitmap_scalable == bitmap_scalable) return;
2439    o->prev.bitmap_scalable = o->cur.bitmap_scalable;
2440    o->cur.bitmap_scalable = bitmap_scalable;
2441    _evas_text_font_reload(eo_obj, o);
2442 }
2443 
2444 EOLIAN static Efl_Text_Font_Bitmap_Scalable
_evas_text_efl_text_font_font_bitmap_scalable_get(const Eo * eo_obj EINA_UNUSED,Evas_Text_Data * o)2445 _evas_text_efl_text_font_font_bitmap_scalable_get(const Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
2446 {
2447    return o->cur.bitmap_scalable;
2448 }
2449 
2450 #define EVAS_TEXT_EXTRA_OPS \
2451    EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _evas_text_efl_object_dbg_info_get)
2452 
2453 #include "canvas/evas_text_eo.c"
2454