evas/map - fixed afterimage problem. now we don't need work-around code anymore.
[framework/uifw/evas.git] / src / lib / canvas / evas_object_text.c
1 #include "evas_common.h" /* Includes evas_bidi_utils stuff. */
2 #include "evas_private.h"
3
4 /* save typing */
5 #define ENFN obj->layer->evas->engine.func
6 #define ENDT obj->layer->evas->engine.data.output
7
8 /* private magic number for text objects */
9 static const char o_type[] = "text";
10
11 /* private struct for text object internal data */
12 typedef struct _Evas_Object_Text Evas_Object_Text;
13 typedef struct _Evas_Object_Text_Item Evas_Object_Text_Item;
14
15 struct _Evas_Object_Text
16 {
17    DATA32               magic;
18
19    struct {
20       const char          *utf8_text; /* The text exposed to the API */
21       const char          *font;
22       Evas_Font_Description *fdesc;
23       const char          *source;
24       Evas_Font_Size       size;
25       struct {
26          unsigned char  r, g, b, a;
27       } outline, shadow, glow, glow2;
28
29       unsigned char        style;
30    } cur, prev;
31
32    float                       ascent, descent;
33    float                       max_ascent, max_descent;
34    Evas_BiDi_Paragraph_Props  *bidi_par_props;
35    const char                 *bidi_delimiters;
36    Evas_Object_Text_Item      *items;
37
38    Evas_Font_Set              *font;
39
40    char                        changed : 1;
41 };
42
43 struct _Evas_Object_Text_Item
44 {
45    EINA_INLIST;
46
47    size_t               text_pos;
48    size_t               visual_pos;
49    Evas_Text_Props      text_props;
50    Evas_Coord           x, w, h, adv;
51 };
52
53 /* private methods for text objects */
54 static void evas_object_text_init(Evas_Object *obj);
55 static void *evas_object_text_new(void);
56 static void evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
57 static void evas_object_text_free(Evas_Object *obj);
58 static void evas_object_text_render_pre(Evas_Object *obj);
59 static void evas_object_text_render_post(Evas_Object *obj);
60
61 static unsigned int evas_object_text_id_get(Evas_Object *obj);
62 static unsigned int evas_object_text_visual_id_get(Evas_Object *obj);
63 static void *evas_object_text_engine_data_get(Evas_Object *obj);
64
65 static int evas_object_text_is_opaque(Evas_Object *obj);
66 static int evas_object_text_was_opaque(Evas_Object *obj);
67
68 static void evas_object_text_scale_update(Evas_Object *obj);
69 static void _evas_object_text_recalc(Evas_Object *obj);
70
71 static const Evas_Object_Func object_func =
72 {
73    /* methods (compulsory) */
74    evas_object_text_free,
75      evas_object_text_render,
76      evas_object_text_render_pre,
77      evas_object_text_render_post,
78      evas_object_text_id_get,
79      evas_object_text_visual_id_get,
80      evas_object_text_engine_data_get,
81    /* these are optional. NULL = nothing */
82      NULL,
83      NULL,
84      NULL,
85      NULL,
86      evas_object_text_is_opaque,
87      evas_object_text_was_opaque,
88      NULL,
89      NULL,
90      NULL,
91      evas_object_text_scale_update,
92      NULL,
93      NULL,
94      NULL
95 };
96
97 /* the actual api call to add a rect */
98 /* it has no other api calls as all properties are standard */
99
100 EVAS_MEMPOOL(_mp_obj);
101
102 static int
103 _evas_object_text_char_coords_get(const Evas_Object *obj,
104       const Evas_Object_Text *o,
105       size_t pos, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
106 {
107    Evas_Object_Text_Item *it;
108
109    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
110      {
111         if ((it->text_pos <= pos) &&
112               (pos < (it->text_pos + it->text_props.text_len)))
113           {
114              int ret;
115              ret = ENFN->font_char_coords_get(ENDT, o->font,
116                    &it->text_props, pos - it->text_pos, x, y, w, h);
117              if (x) *x += it->x;
118              return ret;
119           }
120      }
121    return 0;
122 }
123
124 static void
125 _evas_object_text_item_clean(Evas_Object_Text_Item *it)
126 {
127    evas_common_text_props_content_unref(&it->text_props);
128 }
129
130 static void
131 _evas_object_text_items_clear(Evas_Object_Text *o)
132 {
133    Evas_Object_Text_Item *it;
134
135    while (o->items)
136      {
137         it = o->items;
138         o->items = (Evas_Object_Text_Item *) eina_inlist_remove(
139               EINA_INLIST_GET(o->items),
140               EINA_INLIST_GET(it));
141         _evas_object_text_item_clean(it);
142         free(it);
143      }
144 }
145
146 #ifdef BIDI_SUPPORT
147 static int
148 _evas_object_text_it_compare_logical(const void *_it1, const void *_it2)
149 {
150    const Evas_Object_Text_Item *it1 = _it1, *it2 = _it2;
151    if (it1->text_pos < it2->text_pos)
152      return -1;
153    else if (it1->text_pos == it2->text_pos)
154      return 0;
155    else
156      return 1;
157
158 }
159 #endif
160
161 static int
162 _evas_object_text_last_up_to_pos(const Evas_Object *obj,
163       const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy)
164 {
165    Evas_Object_Text_Item *it;
166
167 #ifdef BIDI_SUPPORT
168    /*FIXME: not very efficient, sort the items arrays. */
169    /* Reorder if it's a bidi text */
170    if (o->bidi_par_props)
171      {
172         Eina_List *logical_it = NULL;
173         Evas_Object_Text_Item *i;
174         Eina_List *itr;
175         Evas_Coord x = 0;
176         /* Insert all to the logical list */
177         EINA_INLIST_FOREACH(o->items, i)
178           {
179              logical_it = eina_list_sorted_insert(logical_it,
180                    _evas_object_text_it_compare_logical, i);
181           }
182         EINA_LIST_FOREACH(logical_it, itr, it)
183           {
184              if ((x <= cx) && (cx < x + it->adv))
185                {
186                   return it->text_pos + ENFN->font_last_up_to_pos(ENDT,
187                         o->font,
188                         &it->text_props,
189                         cx - x,
190                         cy);
191                }
192              x += it->adv;
193           }
194         eina_list_free(logical_it);
195      }
196    else
197 #endif
198      {
199         EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
200           {
201              if ((it->x <= cx) && (cx < it->x + it->adv))
202                {
203                   return it->text_pos + ENFN->font_last_up_to_pos(ENDT,
204                         o->font,
205                         &it->text_props,
206                         cx - it->x,
207                         cy);
208                }
209           }
210      }
211    return -1;
212 }
213
214 static int
215 _evas_object_text_char_at_coords(const Evas_Object *obj,
216       const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy,
217       Evas_Coord *rx, Evas_Coord *ry, Evas_Coord *rw, Evas_Coord *rh)
218 {
219    Evas_Object_Text_Item *it;
220
221    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
222      {
223         if ((it->x <= cx) && (cx < it->x + it->adv))
224           {
225              return it->text_pos + ENFN->font_char_at_coords_get(ENDT,
226                    o->font,
227                    &it->text_props,
228                    cx - it->x,
229                    cy,
230                    rx, ry,
231                    rw, rh);
232           }
233      }
234    return -1;
235 }
236
237 static Evas_Coord
238 _evas_object_text_horiz_advance_get(const Evas_Object *obj,
239       const Evas_Object_Text *o)
240 {
241    Evas_Object_Text_Item *it;
242    Evas_Coord adv;
243    (void) obj;
244
245    adv = 0;
246    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
247      {
248         adv += it->adv;
249      }
250    return adv;
251 }
252
253 static Evas_Coord
254 _evas_object_text_vert_advance_get(const Evas_Object *obj __UNUSED__,
255       const Evas_Object_Text *o)
256 {
257    return o->max_ascent + o->max_descent;
258 }
259
260 EAPI Evas_Object *
261 evas_object_text_add(Evas *e)
262 {
263    Evas_Object *obj;
264
265    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
266    return NULL;
267    MAGIC_CHECK_END();
268    obj = evas_object_new(e);
269    evas_object_text_init(obj);
270    evas_object_inject(obj, e);
271    return obj;
272 }
273
274 EAPI void
275 evas_object_text_font_source_set(Evas_Object *obj, const char *font_source)
276 {
277    Evas_Object_Text *o;
278
279    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
280    return;
281    MAGIC_CHECK_END();
282    o = (Evas_Object_Text *)(obj->object_data);
283    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
284    return;
285    MAGIC_CHECK_END();
286
287    if ((o->cur.source) && (font_source) &&
288        (!strcmp(o->cur.source, font_source)))
289      return;
290    /*
291    if (o->cur.source) eina_stringshare_del(o->cur.source);
292    if (font_source) o->cur.source = eina_stringshare_add(font_source);
293    else o->cur.source = NULL;
294     */
295    eina_stringshare_replace(&o->cur.source, font_source);
296 }
297
298 EAPI const char *
299 evas_object_text_font_source_get(const Evas_Object *obj)
300 {
301    Evas_Object_Text *o;
302
303    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
304    return NULL;
305    MAGIC_CHECK_END();
306    o = (Evas_Object_Text *)(obj->object_data);
307    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
308    return NULL;
309    MAGIC_CHECK_END();
310    return o->cur.source;
311 }
312
313 EAPI void
314 evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size size)
315 {
316    Evas_Object_Text *o;
317    int is, was = 0, pass = 0, freeze = 0;
318    Evas_Font_Description *fdesc;
319
320    if ((!font) || (size <= 0)) return;
321    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
322    return;
323    MAGIC_CHECK_END();
324    o = (Evas_Object_Text *)(obj->object_data);
325    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
326    return;
327    MAGIC_CHECK_END();
328
329    fdesc = evas_font_desc_new();
330    evas_font_name_parse(fdesc, font);
331    if (o->cur.fdesc && !evas_font_desc_cmp(fdesc, o->cur.fdesc) &&
332          (size == o->cur.size))
333      {
334         evas_font_desc_unref(fdesc);
335         return;
336      }
337
338    if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
339    o->cur.fdesc = fdesc;
340
341    o->cur.size = size;
342    eina_stringshare_replace(&o->cur.font, font);
343    o->prev.font = NULL;
344
345    if (obj->layer->evas->events_frozen <= 0)
346      {
347         pass = evas_event_passes_through(obj);
348         freeze = evas_event_freezes_through(obj);
349         if ((!pass) && (!freeze))
350           was = evas_object_is_in_output_rect(obj,
351                                               obj->layer->evas->pointer.x,
352                                               obj->layer->evas->pointer.y, 1, 1);
353      }
354
355 #ifdef EVAS_FRAME_QUEUING
356    if (o->font)
357       evas_common_pipe_op_text_flush((RGBA_Font *) o->font);
358 #endif
359
360    /* DO IT */
361    if (o->font)
362      {
363         evas_font_free(obj->layer->evas, o->font);
364         o->font = NULL;
365      }
366
367    o->font = evas_font_load(obj->layer->evas, o->cur.fdesc, o->cur.source,
368          (int)(((double) o->cur.size) * obj->cur.scale));
369    if (o->font)
370      {
371         o->ascent = ENFN->font_ascent_get(ENDT, o->font);
372         o->descent = ENFN->font_descent_get(ENDT, o->font);
373         o->max_ascent = ENFN->font_max_ascent_get(ENDT, o->font);
374         o->max_descent = ENFN->font_max_descent_get(ENDT, o->font);
375      }
376    else
377      {
378         o->ascent = 0;
379         o->descent = 0;
380         o->max_ascent = 0;
381         o->max_descent = 0;
382      }
383    _evas_object_text_recalc(obj);
384    o->changed = 1;
385    evas_object_change(obj);
386    evas_object_clip_dirty(obj);
387    evas_object_coords_recalc(obj);
388    if (obj->layer->evas->events_frozen <= 0)
389      {
390         if ((!pass) && (!freeze))
391           {
392              is = evas_object_is_in_output_rect(obj,
393                                                 obj->layer->evas->pointer.x,
394                                                 obj->layer->evas->pointer.y,
395                                                 1, 1);
396              if ((is ^ was) && obj->cur.visible)
397                evas_event_feed_mouse_move(obj->layer->evas,
398                                           obj->layer->evas->pointer.x,
399                                           obj->layer->evas->pointer.y,
400                                           obj->layer->evas->last_timestamp,
401                                           NULL);
402           }
403      }
404    evas_object_inform_call_resize(obj);
405 }
406
407 EAPI void
408 evas_object_text_font_get(const Evas_Object *obj, const char **font, Evas_Font_Size *size)
409 {
410    Evas_Object_Text *o;
411
412    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
413    if (font) *font = "";
414    if (size) *size = 0;
415    return;
416    MAGIC_CHECK_END();
417    o = (Evas_Object_Text *)(obj->object_data);
418    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
419    if (font) *font = "";
420    if (size) *size = 0;
421    return;
422    MAGIC_CHECK_END();
423    if (font) *font = o->cur.font;
424    if (size) *size = o->cur.size;
425 }
426
427
428 /**
429  * @internal
430  * Create a new text layout item from the string and the format.
431  *
432  * @param c the context to work on - Not NULL.
433  * @param fmt the format to use.
434  * @param str the string to use.
435  */
436 static Evas_Object_Text_Item *
437 _evas_object_text_item_new(Evas_Object *obj, Evas_Object_Text *o,
438       Evas_Font_Instance *fi, const Eina_Unicode *str, Evas_Script_Type script,
439       size_t pos, size_t visual_pos, size_t len)
440 {
441    Evas_Object_Text_Item *it;
442
443    it = calloc(1, sizeof(Evas_Object_Text_Item));
444    it->text_pos = pos;
445    it->visual_pos = visual_pos;
446    evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props,
447          it->text_pos);
448    evas_common_text_props_script_set(&it->text_props, script);
449
450    if (fi)
451      {
452         ENFN->font_text_props_info_create(ENDT,
453               fi, str + pos, &it->text_props,
454               o->bidi_par_props, it->text_pos, len);
455
456         ENFN->font_string_size_get(ENDT,
457               o->font,
458               &it->text_props,
459               &it->w, &it->h);
460         it->adv = ENFN->font_h_advance_get(ENDT, o->font,
461               &it->text_props);
462      }
463    o->items = (Evas_Object_Text_Item *)
464       eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(it));
465    return it;
466 }
467
468 /**
469  * @internal
470  * Orders o->items according to the visual position.
471  *
472  * @param obj the evas object
473  * @param o the text object
474  */
475 static void
476 _evas_object_text_item_order(Evas_Object *obj, Evas_Object_Text *o)
477 {
478    (void) obj;
479 #ifdef BIDI_SUPPORT
480    /*FIXME: not very efficient, sort the items arrays. */
481    /* Reorder if it's a bidi text */
482    if (o->bidi_par_props)
483      {
484         Evas_Object_Text_Item *i, *j, *min;
485         i = o->items;
486         while (i)
487           {
488              min = i;
489              EINA_INLIST_FOREACH(i, j)
490                {
491                   if (j->visual_pos < min->visual_pos)
492                     {
493                        min = j;
494                     }
495                }
496              if (min != i)
497                {
498                   o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min));
499                   o->items = (Evas_Object_Text_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
500                }
501
502              i = (Evas_Object_Text_Item *) EINA_INLIST_GET(min)->next;
503           }
504      }
505 #endif
506
507    /* calculate the positions according to the order. */
508      {
509         Evas_Object_Text_Item *it = o->items;
510         Evas_Coord x = 0;
511
512         while (it)
513           {
514              it->x = x;
515              x += it->adv;
516              it = (Evas_Object_Text_Item *) EINA_INLIST_GET(it)->next;
517           }
518      }
519 }
520
521 /**
522  * @internal
523  * Populates o->items with the items of the text according to text
524  *
525  * @param obj the evas object
526  * @param o the text object
527  * @param text the text to layout
528  */
529 static void
530 _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unicode *text)
531 {
532    EvasBiDiStrIndex *v_to_l = NULL;
533    size_t pos, visual_pos;
534    int len = eina_unicode_strlen(text);
535 #ifdef BIDI_SUPPORT
536    int par_len = len;
537    int *segment_idxs = NULL;
538    if (o->bidi_delimiters)
539       segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
540    evas_bidi_paragraph_props_unref(o->bidi_par_props);
541    o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs);
542    evas_bidi_props_reorder_line(NULL, 0, len, o->bidi_par_props, &v_to_l);
543    if (segment_idxs) free(segment_idxs);
544 #endif
545    visual_pos = pos = 0;
546
547    while (len > 0)
548      {
549         Evas_Font_Instance *script_fi = NULL;
550         int script_len = len, tmp_cut;
551         Evas_Script_Type script;
552         tmp_cut = evas_common_language_script_end_of_run_get(
553               text + pos,
554               o->bidi_par_props,
555               pos, len);
556         if (tmp_cut > 0)
557            script_len = tmp_cut;
558
559         script = evas_common_language_script_type_get(text, script_len);
560
561         while (script_len > 0)
562           {
563              Evas_Font_Instance *cur_fi = NULL;
564              int run_len = script_len;
565              if (o->font)
566                {
567                   run_len = ENFN->font_run_end_get(ENDT,
568                         o->font, &script_fi, &cur_fi,
569                         script, text + pos, script_len);
570                }
571 #ifdef BIDI_SUPPORT
572              visual_pos = evas_bidi_position_logical_to_visual(
573                    v_to_l, par_len, pos);
574 #else
575              visual_pos = pos;
576 #endif
577              _evas_object_text_item_new(obj, o, cur_fi, text, script,
578                    pos, visual_pos, run_len);
579
580              pos += run_len;
581              script_len -= run_len;
582              len -= run_len;
583           }
584      }
585
586    _evas_object_text_item_order(obj, o);
587
588    if (v_to_l) free(v_to_l);
589 }
590
591
592 EAPI void
593 evas_object_text_text_set(Evas_Object *obj, const char *_text)
594 {
595    Evas_Object_Text *o;
596    int is, was, len;
597    Eina_Unicode *text;
598    
599    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
600    return;
601    MAGIC_CHECK_END();
602    o = (Evas_Object_Text *)(obj->object_data);
603    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
604    return;
605    MAGIC_CHECK_END();
606
607    if ((o->cur.utf8_text) && (_text) && (!strcmp(o->cur.utf8_text, _text)))
608       return;
609    text = eina_unicode_utf8_to_unicode(_text, &len);
610
611    if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
612    was = evas_object_is_in_output_rect(obj,
613                                        obj->layer->evas->pointer.x,
614                                        obj->layer->evas->pointer.y, 1, 1);
615    /* DO II */
616    /*Update bidi_props*/
617
618    if (o->items) _evas_object_text_items_clear(o);
619
620    if ((text) && (*text)) 
621      {
622         _evas_object_text_layout(obj, o, text);
623         eina_stringshare_replace(&o->cur.utf8_text, _text);
624         o->prev.utf8_text = NULL;
625     }
626    else 
627      {
628         eina_stringshare_replace(&o->cur.utf8_text, NULL);
629      }
630    if (text)
631      {
632         free(text);
633         text = NULL;
634      }
635    _evas_object_text_recalc(obj);
636    o->changed = 1;
637    evas_object_change(obj);
638    evas_object_clip_dirty(obj);
639    evas_object_coords_recalc(obj);
640    is = evas_object_is_in_output_rect(obj,
641                                       obj->layer->evas->pointer.x,
642                                       obj->layer->evas->pointer.y, 1, 1);
643    if ((is || was) && obj->cur.visible)
644      evas_event_feed_mouse_move(obj->layer->evas,
645                                 obj->layer->evas->pointer.x,
646                                 obj->layer->evas->pointer.y,
647                                 obj->layer->evas->last_timestamp,
648                                 NULL);
649    evas_object_inform_call_resize(obj);
650    if (text) free(text);
651 }
652
653 EAPI void
654 evas_object_text_bidi_delimiters_set(Evas_Object *obj, const char *delim)
655 {
656    Evas_Object_Text *o;
657
658    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
659    return;
660    MAGIC_CHECK_END();
661    o = (Evas_Object_Text *)(obj->object_data);
662    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
663    return;
664    MAGIC_CHECK_END();
665
666    eina_stringshare_replace(&o->bidi_delimiters, delim);
667 }
668
669 EAPI const char *
670 evas_object_text_bidi_delimiters_get(const Evas_Object *obj)
671 {
672    Evas_Object_Text *o;
673
674    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
675    return NULL;
676    MAGIC_CHECK_END();
677    o = (Evas_Object_Text *)(obj->object_data);
678    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
679    return NULL;
680    MAGIC_CHECK_END();
681
682    return o->bidi_delimiters;
683 }
684
685
686 EAPI const char *
687 evas_object_text_text_get(const Evas_Object *obj)
688 {
689    Evas_Object_Text *o;
690
691    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
692    return NULL;
693    MAGIC_CHECK_END();
694    o = (Evas_Object_Text *)(obj->object_data);
695    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
696    return NULL;
697    MAGIC_CHECK_END();
698    return o->cur.utf8_text;
699 }
700
701 EAPI Evas_BiDi_Direction
702 evas_object_text_direction_get(const Evas_Object *obj)
703 {
704    Evas_Object_Text *o;
705
706    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
707    return EVAS_BIDI_DIRECTION_NEUTRAL;
708    MAGIC_CHECK_END();
709    o = (Evas_Object_Text *)(obj->object_data);
710    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
711    return EVAS_BIDI_DIRECTION_NEUTRAL;
712    MAGIC_CHECK_END();
713    if (o->items)
714      {
715         return o->items->text_props.bidi.dir;
716      }
717    return EVAS_BIDI_DIRECTION_NEUTRAL;
718 }
719
720 EAPI Evas_Coord
721 evas_object_text_ascent_get(const Evas_Object *obj)
722 {
723    Evas_Object_Text *o;
724
725    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
726    return 0;
727    MAGIC_CHECK_END();
728    o = (Evas_Object_Text *)(obj->object_data);
729    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
730    return 0;
731    MAGIC_CHECK_END();
732    return o->ascent;
733 }
734
735 EAPI Evas_Coord
736 evas_object_text_descent_get(const Evas_Object *obj)
737 {
738    Evas_Object_Text *o;
739
740    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
741    return 0;
742    MAGIC_CHECK_END();
743    o = (Evas_Object_Text *)(obj->object_data);
744    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
745    return 0;
746    MAGIC_CHECK_END();
747    return o->descent;
748 }
749
750 EAPI Evas_Coord
751 evas_object_text_max_ascent_get(const Evas_Object *obj)
752 {
753    Evas_Object_Text *o;
754
755    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
756    return 0;
757    MAGIC_CHECK_END();
758    o = (Evas_Object_Text *)(obj->object_data);
759    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
760    return 0;
761    MAGIC_CHECK_END();
762    return o->max_ascent;
763 }
764
765 EAPI Evas_Coord
766 evas_object_text_max_descent_get(const Evas_Object *obj)
767 {
768    Evas_Object_Text *o;
769
770    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
771    return 0;
772    MAGIC_CHECK_END();
773    o = (Evas_Object_Text *)(obj->object_data);
774    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
775    return 0;
776    MAGIC_CHECK_END();
777    return o->max_descent;
778 }
779
780 EAPI Evas_Coord
781 evas_object_text_inset_get(const Evas_Object *obj)
782 {
783    Evas_Object_Text *o;
784
785    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
786    return 0;
787    MAGIC_CHECK_END();
788    o = (Evas_Object_Text *)(obj->object_data);
789    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
790    return 0;
791    MAGIC_CHECK_END();
792    if (!o->font) return 0;
793    if (!o->items) return 0;
794    return ENFN->font_inset_get(ENDT, o->font, &o->items->text_props);
795 }
796
797 EAPI Evas_Coord
798 evas_object_text_horiz_advance_get(const Evas_Object *obj)
799 {
800    Evas_Object_Text *o;
801
802    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
803    return 0;
804    MAGIC_CHECK_END();
805    o = (Evas_Object_Text *)(obj->object_data);
806    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
807    return 0;
808    MAGIC_CHECK_END();
809    if (!o->font) return 0;
810    if (!o->items) return 0;
811    return _evas_object_text_horiz_advance_get(obj, o);
812 }
813
814 EAPI Evas_Coord
815 evas_object_text_vert_advance_get(const Evas_Object *obj)
816 {
817    Evas_Object_Text *o;
818
819    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
820    return 0;
821    MAGIC_CHECK_END();
822    o = (Evas_Object_Text *)(obj->object_data);
823    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
824    return 0;
825    MAGIC_CHECK_END();
826    if (!o->font) return 0;
827    if (!o->items) return o->ascent + o->descent;
828    return _evas_object_text_vert_advance_get(obj, o);
829 }
830
831 EAPI Eina_Bool
832 evas_object_text_char_pos_get(const Evas_Object *obj, int pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
833 {
834    Evas_Object_Text *o;
835    int l = 0, r = 0, t = 0, b = 0;
836    int ret, x = 0, y = 0, w = 0, h = 0;
837
838    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
839    return EINA_FALSE;
840    MAGIC_CHECK_END();
841    o = (Evas_Object_Text *)(obj->object_data);
842    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
843    return EINA_FALSE;
844    MAGIC_CHECK_END();
845    if (!o->font) return EINA_FALSE;
846    if (!o->items || (pos < 0)) return EINA_FALSE;
847    ret = _evas_object_text_char_coords_get(obj, o, (size_t) pos,
848             &x, &y, &w, &h);
849    evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
850    y += o->max_ascent - t;
851    x -= l;
852    if (x < 0)
853      {
854         w += x;
855         x = 0;
856      }
857    if ((x + w) > obj->cur.geometry.w) w = obj->cur.geometry.w - x;
858    if (w < 0) w = 0;
859    if (y < 0)
860      {
861         h += y;
862         y = 0;
863      }
864    if ((y + h) > obj->cur.geometry.h) h = obj->cur.geometry.h - y;
865    if (h < 0) h = 0;
866    if (cx) *cx = x;
867    if (cy) *cy = y;
868    if (cw) *cw = w + l + r;
869    if (ch) *ch = h + t + b;
870    return ret;
871 }
872
873
874 EAPI int
875 evas_object_text_last_up_to_pos(const Evas_Object *obj, Evas_Coord x, Evas_Coord y)
876 {
877    Evas_Object_Text *o;
878
879    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
880    return -1;
881    MAGIC_CHECK_END();
882    o = (Evas_Object_Text *)(obj->object_data);
883    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
884    return -1;
885    MAGIC_CHECK_END();
886    if (!o->font) return -1;
887    if (!o->items) return -1;
888    return _evas_object_text_last_up_to_pos(obj, o, x, y - o->max_ascent);
889 }
890
891 EAPI int
892 evas_object_text_char_coords_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
893 {
894    Evas_Object_Text *o;
895    int l = 0, r = 0, t = 0, b = 0;
896    int ret, rx = 0, ry = 0, rw = 0, rh = 0;
897
898    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
899    return -1;
900    MAGIC_CHECK_END();
901    o = (Evas_Object_Text *)(obj->object_data);
902    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
903    return -1;
904    MAGIC_CHECK_END();
905    if (!o->font) return -1;
906    if (!o->items) return -1;
907    ret = _evas_object_text_char_at_coords(obj, o, x, y - o->max_ascent,
908          &rx, &ry, &rw, &rh);
909    evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
910    ry += o->max_ascent - t;
911    rx -= l;
912    if (rx < 0)
913      {
914         rw += rx;
915         rx = 0;
916      }
917    if ((rx + rw) > obj->cur.geometry.w) rw = obj->cur.geometry.w - rx;
918    if (rw < 0) rw = 0;
919    if (ry < 0)
920      {
921         rh += ry;
922         ry = 0;
923      }
924    if ((ry + rh) > obj->cur.geometry.h) rh = obj->cur.geometry.h - ry;
925    if (rh < 0) rh = 0;
926    if (cx) *cx = rx;
927    if (cy) *cy = ry;
928    if (cw) *cw = rw + l + r;
929    if (ch) *ch = rh + t + b;
930    return ret;
931 }
932
933 EAPI void
934 evas_object_text_style_set(Evas_Object *obj, Evas_Text_Style_Type style)
935 {
936    Evas_Object_Text *o;
937    int pl = 0, pr = 0, pt = 0, pb = 0, l = 0, r = 0, t = 0, b = 0;
938
939    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
940    return;
941    MAGIC_CHECK_END();
942    o = (Evas_Object_Text *)(obj->object_data);
943    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
944    return;
945    MAGIC_CHECK_END();
946    if (o->cur.style == style) return;
947    evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb);
948    o->cur.style = style;
949    evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
950    if (o->items)
951      obj->cur.geometry.w += (l - pl) + (r - pr);
952    else
953      obj->cur.geometry.w = 0;
954    obj->cur.geometry.h += (t - pt) + (b - pb);
955    evas_object_change(obj);
956    evas_object_clip_dirty(obj);
957 }
958
959 EAPI Evas_Text_Style_Type
960 evas_object_text_style_get(const Evas_Object *obj)
961 {
962    Evas_Object_Text *o;
963
964    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
965    return EVAS_TEXT_STYLE_PLAIN;
966    MAGIC_CHECK_END();
967    o = (Evas_Object_Text *)(obj->object_data);
968    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
969    return EVAS_TEXT_STYLE_PLAIN;
970    MAGIC_CHECK_END();
971    return o->cur.style;
972 }
973
974 EAPI void
975 evas_object_text_shadow_color_set(Evas_Object *obj, int r, int g, int b, int a)
976 {
977    Evas_Object_Text *o;
978
979    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
980    return;
981    MAGIC_CHECK_END();
982    o = (Evas_Object_Text *)(obj->object_data);
983    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
984    return;
985    MAGIC_CHECK_END();
986    if ((o->cur.shadow.r == r) && (o->cur.shadow.g == g) &&
987        (o->cur.shadow.b == b) && (o->cur.shadow.a == a))
988      return;
989    o->cur.shadow.r = r;
990    o->cur.shadow.g = g;
991    o->cur.shadow.b = b;
992    o->cur.shadow.a = a;
993    o->changed = 1;
994    evas_object_change(obj);
995 }
996
997 EAPI void
998 evas_object_text_shadow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
999 {
1000    Evas_Object_Text *o;
1001
1002    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1003    if (r) *r = 0;
1004    if (g) *g = 0;
1005    if (b) *b = 0;
1006    if (a) *a = 0;
1007    return;
1008    MAGIC_CHECK_END();
1009    o = (Evas_Object_Text *)(obj->object_data);
1010    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1011    if (r) *r = 0;
1012    if (g) *g = 0;
1013    if (b) *b = 0;
1014    if (a) *a = 0;
1015    return;
1016    MAGIC_CHECK_END();
1017    if (r) *r = o->cur.shadow.r;
1018    if (g) *g = o->cur.shadow.g;
1019    if (b) *b = o->cur.shadow.b;
1020    if (a) *a = o->cur.shadow.a;
1021 }
1022
1023 EAPI void
1024 evas_object_text_glow_color_set(Evas_Object *obj, int r, int g, int b, int a)
1025 {
1026    Evas_Object_Text *o;
1027
1028    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1029    return;
1030    MAGIC_CHECK_END();
1031    o = (Evas_Object_Text *)(obj->object_data);
1032    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1033    return;
1034    MAGIC_CHECK_END();
1035    if ((o->cur.glow.r == r) && (o->cur.glow.g == g) &&
1036        (o->cur.glow.b == b) && (o->cur.glow.a == a))
1037      return;
1038    o->cur.glow.r = r;
1039    o->cur.glow.g = g;
1040    o->cur.glow.b = b;
1041    o->cur.glow.a = a;
1042    o->changed = 1;
1043    evas_object_change(obj);
1044 }
1045
1046 EAPI void
1047 evas_object_text_glow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1048 {
1049    Evas_Object_Text *o;
1050
1051    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1052    if (r) *r = 0;
1053    if (g) *g = 0;
1054    if (b) *b = 0;
1055    if (a) *a = 0;
1056    return;
1057    MAGIC_CHECK_END();
1058    o = (Evas_Object_Text *)(obj->object_data);
1059    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1060    if (r) *r = 0;
1061    if (g) *g = 0;
1062    if (b) *b = 0;
1063    if (a) *a = 0;
1064    return;
1065    MAGIC_CHECK_END();
1066    if (r) *r = o->cur.glow.r;
1067    if (g) *g = o->cur.glow.g;
1068    if (b) *b = o->cur.glow.b;
1069    if (a) *a = o->cur.glow.a;
1070 }
1071
1072 EAPI void
1073 evas_object_text_glow2_color_set(Evas_Object *obj, int r, int g, int b, int a)
1074 {
1075    Evas_Object_Text *o;
1076
1077    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1078    return;
1079    MAGIC_CHECK_END();
1080    o = (Evas_Object_Text *)(obj->object_data);
1081    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1082    return;
1083    MAGIC_CHECK_END();
1084    if ((o->cur.glow2.r == r) && (o->cur.glow2.g == g) &&
1085        (o->cur.glow2.b == b) && (o->cur.glow2.a == a))
1086      return;
1087    o->cur.glow2.r = r;
1088    o->cur.glow2.g = g;
1089    o->cur.glow2.b = b;
1090    o->cur.glow2.a = a;
1091    o->changed = 1;
1092    evas_object_change(obj);
1093 }
1094
1095 EAPI void
1096 evas_object_text_glow2_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1097 {
1098    Evas_Object_Text *o;
1099
1100    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1101    if (r) *r = 0;
1102    if (g) *g = 0;
1103    if (b) *b = 0;
1104    if (a) *a = 0;
1105    return;
1106    MAGIC_CHECK_END();
1107    o = (Evas_Object_Text *)(obj->object_data);
1108    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1109    if (r) *r = 0;
1110    if (g) *g = 0;
1111    if (b) *b = 0;
1112    if (a) *a = 0;
1113    return;
1114    MAGIC_CHECK_END();
1115    if (r) *r = o->cur.glow2.r;
1116    if (g) *g = o->cur.glow2.g;
1117    if (b) *b = o->cur.glow2.b;
1118    if (a) *a = o->cur.glow2.a;
1119 }
1120
1121 EAPI void
1122 evas_object_text_outline_color_set(Evas_Object *obj, int r, int g, int b, int a)
1123 {
1124    Evas_Object_Text *o;
1125
1126    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1127    return;
1128    MAGIC_CHECK_END();
1129    o = (Evas_Object_Text *)(obj->object_data);
1130    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1131    return;
1132    MAGIC_CHECK_END();
1133    if ((o->cur.outline.r == r) && (o->cur.outline.g == g) &&
1134        (o->cur.outline.b == b) && (o->cur.outline.a == a))
1135      return;
1136    o->cur.outline.r = r;
1137    o->cur.outline.g = g;
1138    o->cur.outline.b = b;
1139    o->cur.outline.a = a;
1140    o->changed = 1;
1141    evas_object_change(obj);
1142 }
1143
1144 EAPI void
1145 evas_object_text_outline_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1146 {
1147    Evas_Object_Text *o;
1148
1149    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1150    if (r) *r = 0;
1151    if (g) *g = 0;
1152    if (b) *b = 0;
1153    if (a) *a = 0;
1154    return;
1155    MAGIC_CHECK_END();
1156    o = (Evas_Object_Text *)(obj->object_data);
1157    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1158    if (r) *r = 0;
1159    if (g) *g = 0;
1160    if (b) *b = 0;
1161    if (a) *a = 0;
1162    return;
1163    MAGIC_CHECK_END();
1164    if (r) *r = o->cur.outline.r;
1165    if (g) *g = o->cur.outline.g;
1166    if (b) *b = o->cur.outline.b;
1167    if (a) *a = o->cur.outline.a;
1168 }
1169
1170 EAPI void
1171 evas_object_text_style_pad_get(const Evas_Object *obj, int *l, int *r, int *t, int *b)
1172 {
1173    int sl = 0, sr = 0, st = 0, sb = 0;
1174    Evas_Object_Text *o;
1175
1176    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1177    if (l) *l = 0;
1178    if (r) *r = 0;
1179    if (t) *t = 0;
1180    if (b) *b = 0;
1181    return;
1182    MAGIC_CHECK_END();
1183    o = (Evas_Object_Text *)(obj->object_data);
1184    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1185    if (l) *l = 0;
1186    if (r) *r = 0;
1187    if (t) *t = 0;
1188    if (b) *b = 0;
1189    return;
1190    MAGIC_CHECK_END();
1191    /* use temps to be certain we have initialized values */
1192    evas_text_style_pad_get(o->cur.style, &sl, &sr, &st, &sb);
1193    if (l) *l = sl;
1194    if (r) *r = sr;
1195    if (t) *t = st;
1196    if (b) *b = sb;
1197 }
1198
1199
1200
1201
1202 EAPI int
1203 evas_string_char_next_get(const char *str, int pos, int *decoded)
1204 {
1205    int p, d;
1206
1207    if (decoded) *decoded = 0;
1208    if ((!str) || (pos < 0)) return 0;
1209    p = pos;
1210    d = eina_unicode_utf8_get_next(str, &p);
1211    if (decoded) *decoded = d;
1212    return p;
1213 }
1214
1215 EAPI int
1216 evas_string_char_prev_get(const char *str, int pos, int *decoded)
1217 {
1218    int p, d;
1219
1220    if (decoded) *decoded = 0;
1221    if ((!str) || (pos < 1)) return 0;
1222    p = pos;
1223    d = eina_unicode_utf8_get_prev(str, &p);
1224    if (decoded) *decoded = d;
1225    return p;
1226 }
1227
1228 EAPI int
1229 evas_string_char_len_get(const char *str)
1230 {
1231    if (!str) return 0;
1232    return eina_unicode_utf8_get_len(str);
1233 }
1234
1235 void
1236 evas_text_style_pad_get(Evas_Text_Style_Type style, int *l, int *r, int *t, int *b)
1237 {
1238    int sl = 0, sr = 0, st = 0, sb = 0;
1239
1240    /* Don't calc anything if there's no style. */
1241    if (style != EVAS_TEXT_STYLE_PLAIN)
1242      {
1243         int shad_sz = 0, shad_dst = 0, out_sz = 0;
1244         int dx = 0, minx = 0, maxx = 0;
1245         int dy = 0, miny = 0, maxy = 0;
1246         Eina_Bool have_shadow = EINA_FALSE;
1247
1248         switch (style & EVAS_TEXT_STYLE_MASK_BASIC)
1249           {
1250            case EVAS_TEXT_STYLE_SHADOW:
1251               shad_dst = 1;
1252               have_shadow = EINA_TRUE;
1253               break;
1254            case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1255            case EVAS_TEXT_STYLE_FAR_SHADOW:
1256               shad_dst = 2;
1257               out_sz = 1;
1258               have_shadow = EINA_TRUE;
1259               break;
1260            case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1261               shad_dst = 1;
1262               shad_sz = 2;
1263               out_sz = 1;
1264               have_shadow = EINA_TRUE;
1265               break;
1266            case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1267               shad_dst = 2;
1268               shad_sz = 2;
1269               have_shadow = EINA_TRUE;
1270               break;
1271            case EVAS_TEXT_STYLE_SOFT_SHADOW:
1272               shad_dst = 1;
1273               shad_sz = 2;
1274               have_shadow = EINA_TRUE;
1275               break;
1276            case EVAS_TEXT_STYLE_GLOW:
1277            case EVAS_TEXT_STYLE_SOFT_OUTLINE:
1278               out_sz = 2;
1279               break;
1280            case EVAS_TEXT_STYLE_OUTLINE:
1281               out_sz = 1;
1282               break;
1283            default:
1284               break;
1285           }
1286
1287         minx = -out_sz;
1288         maxx = out_sz;
1289         miny = -out_sz;
1290         maxy = out_sz;
1291         if (have_shadow)
1292           {
1293              int shx1, shx2, shy1, shy2;
1294              switch (style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1295                {
1296                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1297                    dx = 1;
1298                    dy = 1;
1299                    break;
1300                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1301                    dx = 0;
1302                    dy = 1;
1303                    break;
1304                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1305                    dx = -1;
1306                    dy = 1;
1307                    break;
1308                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1309                    dx = -1;
1310                    dy = 0;
1311                    break;
1312                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1313                    dx = -1;
1314                    dy = -1;
1315                    break;
1316                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1317                    dx = 0;
1318                    dy = -1;
1319                    break;
1320                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1321                    dx = 1;
1322                    dy = -1;
1323                    break;
1324                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1325                    dx = 1;
1326                    dy = 0;
1327                 default:
1328                    break;
1329                }
1330              shx1 = dx * shad_dst;
1331              shx1 -= shad_sz;
1332              shx2 = dx * shad_dst;
1333              shx2 += shad_sz;
1334              if (shx1 < minx) minx = shx1;
1335              if (shx2 > maxx) maxx = shx2;
1336
1337              shy1 = dy * shad_dst;
1338              shy1 -= shad_sz;
1339              shy2 = dy * shad_dst;
1340              shy2 += shad_sz;
1341              if (shy1 < miny) miny = shy1;
1342              if (shy2 > maxy) maxy = shy2;
1343           }
1344
1345         if (l) sl = *l;
1346         if (r) sr = *r;
1347         if (t) st = *t;
1348         if (b) sb = *b;
1349
1350         if (sr < maxx) sr = maxx;
1351         if (sl < -minx) sl = -minx;
1352         if (sb < maxy) sb = maxy;
1353         if (st < -miny) st = -miny;
1354      }
1355
1356    if (l) *l = sl;
1357    if (r) *r = sr;
1358    if (t) *t = st;
1359    if (b) *b = sb;
1360 }
1361
1362 /* all nice and private */
1363 static void
1364 evas_object_text_init(Evas_Object *obj)
1365 {
1366    /* alloc text ob, setup methods and default values */
1367    obj->object_data = evas_object_text_new();
1368    /* set up default settings for this kind of object */
1369    obj->cur.color.r = 255;
1370    obj->cur.color.g = 255;
1371    obj->cur.color.b = 255;
1372    obj->cur.color.a = 255;
1373    obj->cur.geometry.x = 0;
1374    obj->cur.geometry.y = 0;
1375    obj->cur.geometry.w = 0;
1376    obj->cur.geometry.h = 0;
1377    obj->cur.layer = 0;
1378    /* set up object-specific settings */
1379    obj->prev = obj->cur;
1380    /* set up methods (compulsory) */
1381    obj->func = &object_func;
1382    obj->type = o_type;
1383 }
1384
1385 static void *
1386 evas_object_text_new(void)
1387 {
1388    Evas_Object_Text *o;
1389
1390    /* alloc obj private data */
1391    EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_text", Evas_Object_Text, 128, NULL);
1392    o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Text);
1393    if (!o) return NULL;
1394    EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Text);
1395    o->magic = MAGIC_OBJ_TEXT;
1396    o->prev = o->cur;
1397 #ifdef BIDI_SUPPORT
1398    o->bidi_par_props = evas_bidi_paragraph_props_new();
1399 #endif
1400    return o;
1401 }
1402
1403 static void
1404 evas_object_text_free(Evas_Object *obj)
1405 {
1406    Evas_Object_Text *o;
1407
1408    /* frees private object data. very simple here */
1409    o = (Evas_Object_Text *)(obj->object_data);
1410    MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1411    return;
1412    MAGIC_CHECK_END();
1413    /* free obj */
1414    if (o->items) _evas_object_text_items_clear(o);
1415    if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text);
1416    if (o->cur.font) eina_stringshare_del(o->cur.font);
1417    if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
1418    if (o->cur.source) eina_stringshare_del(o->cur.source);
1419    if (o->font) evas_font_free(obj->layer->evas, o->font);
1420 #ifdef BIDI_SUPPORT
1421    evas_bidi_paragraph_props_unref(o->bidi_par_props);
1422 #endif
1423    o->magic = 0;
1424    EVAS_MEMPOOL_FREE(_mp_obj, o);
1425 }
1426
1427 static void
1428 evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
1429 {
1430    int i, j;
1431    Evas_Object_Text *o;
1432    Evas_Object_Text_Item *it;
1433    const char vals[5][5] =
1434      {
1435         {0, 1, 2, 1, 0},
1436         {1, 3, 4, 3, 1},
1437         {2, 4, 5, 4, 2},
1438         {1, 3, 4, 3, 1},
1439         {0, 1, 2, 1, 0}
1440      };
1441    int sl = 0, st = 0;
1442    int shad_dst, shad_sz, dx, dy, haveshad;
1443
1444    /* render object to surface with context, and offxet by x,y */
1445    o = (Evas_Object_Text *)(obj->object_data);
1446    evas_text_style_pad_get(o->cur.style, &sl, NULL, &st, NULL);
1447    ENFN->context_multiplier_unset(output, context);
1448    ENFN->context_render_op_set(output, context, obj->cur.render_op);
1449    /* FIXME: This clipping is just until we fix inset handling correctly. */
1450    ENFN->context_clip_clip(output, context,
1451                               obj->cur.geometry.x + x,
1452                               obj->cur.geometry.y + y,
1453                               obj->cur.geometry.w,
1454                               obj->cur.geometry.h);
1455 /*
1456    ENFN->context_color_set(output,
1457                            context,
1458                            230, 160, 30, 100);
1459    ENFN->rectangle_draw(output,
1460                         context,
1461                         surface,
1462                         obj->cur.geometry.x + x,
1463                         obj->cur.geometry.y + y,
1464                         obj->cur.geometry.w,
1465                         obj->cur.geometry.h);
1466  */
1467 #define COLOR_ONLY_SET(object, sub, col) \
1468         ENFN->context_color_set(output, context, \
1469                                 object->sub.col.r, \
1470                                 object->sub.col.g, \
1471                                 object->sub.col.b, \
1472                                 object->sub.col.a);
1473
1474 #define COLOR_SET(object, sub, col) \
1475         if (obj->cur.clipper)\
1476            ENFN->context_color_set(output, context, \
1477                                 ((int)object->sub.col.r * ((int)obj->cur.clipper->cur.cache.clip.r + 1)) >> 8, \
1478                                 ((int)object->sub.col.g * ((int)obj->cur.clipper->cur.cache.clip.g + 1)) >> 8, \
1479                                 ((int)object->sub.col.b * ((int)obj->cur.clipper->cur.cache.clip.b + 1)) >> 8, \
1480                                 ((int)object->sub.col.a * ((int)obj->cur.clipper->cur.cache.clip.a + 1)) >> 8); \
1481         else\
1482            ENFN->context_color_set(output, context, \
1483                                 object->sub.col.r, \
1484                                 object->sub.col.g, \
1485                                 object->sub.col.b, \
1486                                 object->sub.col.a);
1487
1488 #define COLOR_SET_AMUL(object, sub, col, amul) \
1489         if (obj->cur.clipper) \
1490             ENFN->context_color_set(output, context, \
1491                                 (((int)object->sub.col.r) * ((int)obj->cur.clipper->cur.cache.clip.r) * (amul)) / 65025, \
1492                                 (((int)object->sub.col.g) * ((int)obj->cur.clipper->cur.cache.clip.g) * (amul)) / 65025, \
1493                                 (((int)object->sub.col.b) * ((int)obj->cur.clipper->cur.cache.clip.b) * (amul)) / 65025, \
1494                                 (((int)object->sub.col.a) * ((int)obj->cur.clipper->cur.cache.clip.a) * (amul)) / 65025); \
1495         else \
1496             ENFN->context_color_set(output, context, \
1497                                 (((int)object->sub.col.r) * (amul)) / 255, \
1498                                 (((int)object->sub.col.g) * (amul)) / 255, \
1499                                 (((int)object->sub.col.b) * (amul)) / 255, \
1500                                 (((int)object->sub.col.a) * (amul)) / 255);
1501
1502 #define DRAW_TEXT(ox, oy) \
1503    if ((o->font) && (it->text_props.len > 0)) \
1504      ENFN->font_draw(output, \
1505                      context, \
1506                      surface, \
1507                      o->font, \
1508                      obj->cur.geometry.x + x + sl + ox + it->x, \
1509                      obj->cur.geometry.y + y + st + oy + \
1510                      (int) \
1511                      (((o->max_ascent * obj->cur.geometry.h) / obj->cur.geometry.h) - 0.5), \
1512                      obj->cur.geometry.w, \
1513                      obj->cur.geometry.h, \
1514                      obj->cur.geometry.w, \
1515                      obj->cur.geometry.h, \
1516                      &it->text_props);
1517
1518    /* shadows */
1519    shad_dst = shad_sz = dx = dy = haveshad = 0;
1520    switch (o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC)
1521      {
1522       case EVAS_TEXT_STYLE_SHADOW:
1523       case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1524          shad_dst = 1;
1525          haveshad = 1;
1526          break;
1527       case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1528       case EVAS_TEXT_STYLE_FAR_SHADOW:
1529          shad_dst = 2;
1530          haveshad = 1;
1531          break;
1532       case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1533          shad_dst = 2;
1534          shad_sz = 2;
1535          haveshad = 1;
1536          break;
1537       case EVAS_TEXT_STYLE_SOFT_SHADOW:
1538          shad_dst = 1;
1539          shad_sz = 2;
1540          haveshad = 1;
1541          break;
1542       default:
1543          break;
1544      }
1545    if (haveshad)
1546      {
1547         if (shad_dst > 0)
1548           {
1549              switch (o->cur.style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1550                {
1551                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1552                    dx = 1;
1553                    dy = 1;
1554                    break;
1555                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1556                    dx = 0;
1557                    dy = 1;
1558                    break;
1559                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1560                    dx = -1;
1561                    dy = 1;
1562                    break;
1563                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1564                    dx = -1;
1565                    dy = 0;
1566                    break;
1567                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1568                    dx = -1;
1569                    dy = -1;
1570                    break;
1571                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1572                    dx = 0;
1573                    dy = -1;
1574                    break;
1575                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1576                    dx = 1;
1577                    dy = -1;
1578                    break;
1579                 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1580                    dx = 1;
1581                    dy = 0;
1582                 default:
1583                    break;
1584                }
1585              dx *= shad_dst;
1586              dy *= shad_dst;
1587           }
1588      }
1589    EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
1590      {
1591         /* Shadows */
1592         if (haveshad)
1593           {
1594              switch (shad_sz)
1595                {
1596                 case 0:
1597                   COLOR_SET(o, cur, shadow);
1598                   DRAW_TEXT(dx, dy);
1599                   break;
1600                 case 2:
1601                   for (j = 0; j < 5; j++)
1602                     {
1603                        for (i = 0; i < 5; i++)
1604                          {
1605                             if (vals[i][j] != 0)
1606                               {
1607                                  COLOR_SET_AMUL(o, cur, shadow, vals[i][j] * 50);
1608                                  DRAW_TEXT(i - 2 + dx, j - 2 + dy);
1609                               }
1610                          }
1611                     }
1612                   break;
1613                 default:
1614                   break;
1615                }
1616           }
1617
1618         /* glows */
1619         if (o->cur.style == EVAS_TEXT_STYLE_GLOW)
1620           {
1621              for (j = 0; j < 5; j++)
1622                {
1623                   for (i = 0; i < 5; i++)
1624                     {
1625                        if (vals[i][j] != 0)
1626                          {
1627                             COLOR_SET_AMUL(o, cur, glow, vals[i][j] * 50);
1628                             DRAW_TEXT(i - 2, j - 2);
1629                          }
1630                     }
1631                }
1632              COLOR_SET(o, cur, glow2);
1633              DRAW_TEXT(-1, 0);
1634              DRAW_TEXT(1, 0);
1635              DRAW_TEXT(0, -1);
1636              DRAW_TEXT(0, 1);
1637           }
1638
1639         /* outlines */
1640         if ((o->cur.style == EVAS_TEXT_STYLE_OUTLINE) ||
1641               (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
1642               (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
1643           {
1644              COLOR_SET(o, cur, outline);
1645              DRAW_TEXT(-1, 0);
1646              DRAW_TEXT(1, 0);
1647              DRAW_TEXT(0, -1);
1648              DRAW_TEXT(0, 1);
1649           }
1650         else if (o->cur.style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
1651           {
1652              for (j = 0; j < 5; j++)
1653                {
1654                   for (i = 0; i < 5; i++)
1655                     {
1656                        if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
1657                          {
1658                             COLOR_SET_AMUL(o, cur, outline, vals[i][j] * 50);
1659                             DRAW_TEXT(i - 2, j - 2);
1660                          }
1661                     }
1662                }
1663           }
1664
1665         /* normal text */
1666         COLOR_ONLY_SET(obj, cur.cache, clip);
1667         DRAW_TEXT(0, 0);
1668      }
1669 }
1670
1671 static void
1672 evas_object_text_render_pre(Evas_Object *obj)
1673 {
1674    Evas_Object_Text *o;
1675    int is_v, was_v;
1676
1677    /* dont pre-render the obj twice! */
1678    if (obj->pre_render_done) return;
1679    obj->pre_render_done = 1;
1680    /* pre-render phase. this does anything an object needs to do just before
1681     rendering. This could mean loading the image data, retrieving it from 
1682     elsewhere, decoding video etc.
1683     Then when this is done the object needs to figure if it changed and 
1684     if so what and where and add the appropriate redraw rectangles */
1685    o = (Evas_Object_Text *)(obj->object_data);
1686    /* if someone is clipping this obj - go calculate the clipper */
1687    if (obj->cur.clipper)
1688      {
1689         if (obj->cur.cache.clip.dirty)
1690           evas_object_clip_recalc(obj->cur.clipper);
1691         obj->cur.clipper->func->render_pre(obj->cur.clipper);
1692      }
1693    /* now figure what changed and add draw rects
1694     if it just became visible or invisible */
1695    is_v = evas_object_is_visible(obj);
1696    was_v = evas_object_was_visible(obj);
1697    if (is_v != was_v)
1698      {
1699         evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, 
1700                                               obj, is_v, was_v);
1701         goto done;
1702      }
1703    if (obj->changed_map)
1704      {
1705         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1706                                             obj);
1707         goto done;
1708      }
1709    /* its not visible - we accounted for it appearing or not so just abort */
1710    if (!is_v) goto done;
1711    /* clipper changed this is in addition to anything else for obj */
1712    evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
1713    /* if we restacked (layer or just within a layer) and dont clip anyone */
1714    if (obj->restack)
1715      {
1716         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1717                                             obj);
1718         goto done;
1719      }
1720    /* if it changed color */
1721    if ((obj->cur.color.r != obj->prev.color.r) ||
1722        (obj->cur.color.g != obj->prev.color.g) ||
1723        (obj->cur.color.b != obj->prev.color.b) ||
1724        (obj->cur.color.a != obj->prev.color.a))
1725      {
1726         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1727                                             obj);
1728         goto done;
1729      }
1730    /* if it changed geometry - and obviously not visibility or color
1731     calculate differences since we have a constant color fill
1732     we really only need to update the differences */
1733    if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
1734        (obj->cur.geometry.y != obj->prev.geometry.y) ||
1735        (obj->cur.geometry.w != obj->prev.geometry.w) ||
1736        (obj->cur.geometry.h != obj->prev.geometry.h))
1737      {
1738         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1739                                             obj);
1740         goto done;
1741      }
1742    if (obj->cur.render_op != obj->prev.render_op)
1743      {
1744         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1745                                             obj);
1746         goto done;
1747      }
1748    if (obj->cur.scale != obj->prev.scale)
1749      {
1750         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1751                                             obj);
1752         goto done;
1753      }
1754    if (o->changed)
1755      {
1756         if ((o->cur.size != o->prev.size) ||
1757             ((o->cur.font != o->prev.font)) ||
1758             ((o->cur.utf8_text != o->prev.utf8_text)) ||
1759             ((o->cur.style != o->prev.style)) ||
1760             ((o->cur.shadow.r != o->prev.shadow.r)) ||
1761             ((o->cur.shadow.g != o->prev.shadow.g)) ||
1762             ((o->cur.shadow.b != o->prev.shadow.b)) ||
1763             ((o->cur.shadow.a != o->prev.shadow.a)) ||
1764             ((o->cur.outline.r != o->prev.outline.r)) ||
1765             ((o->cur.outline.g != o->prev.outline.g)) ||
1766             ((o->cur.outline.b != o->prev.outline.b)) ||
1767             ((o->cur.outline.a != o->prev.outline.a)) ||
1768             ((o->cur.glow.r != o->prev.glow.r)) ||
1769             ((o->cur.glow.g != o->prev.glow.g)) ||
1770             ((o->cur.glow.b != o->prev.glow.b)) ||
1771             ((o->cur.glow.a != o->prev.glow.a)) ||
1772             ((o->cur.glow2.r != o->prev.glow2.r)) ||
1773             ((o->cur.glow2.g != o->prev.glow2.g)) ||
1774             ((o->cur.glow2.b != o->prev.glow2.b)) ||
1775             ((o->cur.glow2.a != o->prev.glow2.a)))
1776           {
1777              evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, 
1778                                                  obj);
1779              goto done;
1780           }
1781      }
1782    done:
1783    evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, 
1784                                          obj, is_v, was_v);
1785 }
1786
1787 static void
1788 evas_object_text_render_post(Evas_Object *obj)
1789 {
1790    Evas_Object_Text *o;
1791
1792    /* this moves the current data to the previous state parts of the object
1793     in whatever way is safest for the object. also if we don't need object
1794     data anymore we can free it if the object deems this is a good idea */
1795    o = (Evas_Object_Text *)(obj->object_data);
1796    /* remove those pesky changes */
1797    evas_object_clip_changes_clean(obj);
1798    /* move cur to prev safely for object data */
1799    obj->prev = obj->cur;
1800    o->prev = o->cur;
1801    o->changed = 0;
1802 }
1803
1804 static unsigned int 
1805 evas_object_text_id_get(Evas_Object *obj)
1806 {
1807    Evas_Object_Text *o;
1808
1809    o = (Evas_Object_Text *)(obj->object_data);
1810    if (!o) return 0;
1811    return MAGIC_OBJ_TEXT;
1812 }
1813
1814 static unsigned int 
1815 evas_object_text_visual_id_get(Evas_Object *obj)
1816 {
1817    Evas_Object_Text *o;
1818
1819    o = (Evas_Object_Text *)(obj->object_data);
1820    if (!o) return 0;
1821    return MAGIC_OBJ_SHAPE;
1822 }
1823
1824 static void *
1825 evas_object_text_engine_data_get(Evas_Object *obj)
1826 {
1827    Evas_Object_Text *o;
1828
1829    o = (Evas_Object_Text *)(obj->object_data);
1830    if (!o) return NULL;
1831    return o->font;
1832 }
1833
1834 static int
1835 evas_object_text_is_opaque(Evas_Object *obj __UNUSED__)
1836 {
1837    /* this returns 1 if the internal object data implies that the object is 
1838     currently fully opaque over the entire gradient it occupies */
1839    return 0;
1840 }
1841
1842 static int
1843 evas_object_text_was_opaque(Evas_Object *obj __UNUSED__)
1844 {
1845    /* this returns 1 if the internal object data implies that the object was
1846     currently fully opaque over the entire gradient it occupies */
1847    return 0;
1848 }
1849
1850 static void
1851 evas_object_text_scale_update(Evas_Object *obj)
1852 {
1853    Evas_Object_Text *o;
1854    int size;
1855    const char *font;
1856
1857    o = (Evas_Object_Text *)(obj->object_data);
1858    font = eina_stringshare_add(o->cur.font);
1859    size = o->cur.size;
1860    if (o->cur.font) eina_stringshare_del(o->cur.font);
1861    o->cur.font = NULL;
1862    o->prev.font = NULL;
1863    o->cur.size = 0;
1864    o->prev.size = 0;
1865    evas_object_text_font_set(obj, font, size);
1866 }
1867
1868 void
1869 _evas_object_text_rehint(Evas_Object *obj)
1870 {
1871    Evas_Object_Text *o;
1872    int is, was;
1873
1874    o = (Evas_Object_Text *)(obj->object_data);
1875    if (!o->font) return;
1876 #ifdef EVAS_FRAME_QUEUING
1877    evas_common_pipe_op_text_flush((RGBA_Font *) o->font);
1878 #endif
1879    evas_font_load_hinting_set(obj->layer->evas, o->font,
1880                               obj->layer->evas->hinting);
1881    was = evas_object_is_in_output_rect(obj,
1882                                        obj->layer->evas->pointer.x,
1883                                        obj->layer->evas->pointer.y, 1, 1);
1884    /* DO II */
1885    _evas_object_text_recalc(obj);
1886    o->changed = 1;
1887    evas_object_change(obj);
1888    evas_object_clip_dirty(obj);
1889    evas_object_coords_recalc(obj);
1890    is = evas_object_is_in_output_rect(obj,
1891                                       obj->layer->evas->pointer.x,
1892                                       obj->layer->evas->pointer.y, 1, 1);
1893    if ((is || was) && obj->cur.visible)
1894      evas_event_feed_mouse_move(obj->layer->evas,
1895                                 obj->layer->evas->pointer.x,
1896                                 obj->layer->evas->pointer.y,
1897                                 obj->layer->evas->last_timestamp,
1898                                 NULL);
1899    evas_object_inform_call_resize(obj);
1900 }
1901
1902 static void
1903 _evas_object_text_recalc(Evas_Object *obj)
1904 {
1905    Evas_Object_Text *o;
1906    Eina_Unicode *text = NULL;
1907    o = (Evas_Object_Text *)(obj->object_data);
1908
1909    if (o->items) _evas_object_text_items_clear(o);
1910    if (o->cur.utf8_text)
1911      text = eina_unicode_utf8_to_unicode(o->cur.utf8_text,
1912            NULL);
1913
1914    if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
1915
1916    _evas_object_text_layout(obj, o, text);
1917
1918    if (text) free(text);
1919
1920    if ((o->font) && (o->items))
1921      {
1922         int w, h;
1923         int l = 0, r = 0, t = 0, b = 0;
1924
1925         w = _evas_object_text_horiz_advance_get(obj, o);
1926         h = _evas_object_text_vert_advance_get(obj, o);
1927         evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
1928         obj->cur.geometry.w = w + l + r;
1929         obj->cur.geometry.h = h + t + b;
1930 ////        obj->cur.cache.geometry.validity = 0;
1931      }
1932    else
1933      {
1934         int t = 0, b = 0;
1935
1936         evas_text_style_pad_get(o->cur.style, NULL, NULL, &t, &b);
1937         obj->cur.geometry.w = 0;
1938         obj->cur.geometry.h = o->max_ascent + o->max_descent + t + b;
1939 ////        obj->cur.cache.geometry.validity = 0;
1940      }
1941 }
1942