aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas/evas_object_text.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_text.c1943
1 files changed, 1943 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_object_text.c b/libraries/evas/src/lib/canvas/evas_object_text.c
new file mode 100644
index 0000000..6c30fcc
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_text.c
@@ -0,0 +1,1943 @@
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 */
9static const char o_type[] = "text";
10
11/* private struct for text object internal data */
12typedef struct _Evas_Object_Text Evas_Object_Text;
13typedef struct _Evas_Object_Text_Item Evas_Object_Text_Item;
14
15struct _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
43struct _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 */
54static void evas_object_text_init(Evas_Object *obj);
55static void *evas_object_text_new(void);
56static void evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
57static void evas_object_text_free(Evas_Object *obj);
58static void evas_object_text_render_pre(Evas_Object *obj);
59static void evas_object_text_render_post(Evas_Object *obj);
60
61static unsigned int evas_object_text_id_get(Evas_Object *obj);
62static unsigned int evas_object_text_visual_id_get(Evas_Object *obj);
63static void *evas_object_text_engine_data_get(Evas_Object *obj);
64
65static int evas_object_text_is_opaque(Evas_Object *obj);
66static int evas_object_text_was_opaque(Evas_Object *obj);
67
68static void evas_object_text_scale_update(Evas_Object *obj);
69static void _evas_object_text_recalc(Evas_Object *obj);
70
71static 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
100EVAS_MEMPOOL(_mp_obj);
101
102static 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
124static 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
130static 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
147static 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
161static 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
214static 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
237static 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
253static 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
260EAPI Evas_Object *
261evas_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
274EAPI void
275evas_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
298EAPI const char *
299evas_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
313EAPI void
314evas_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
407EAPI void
408evas_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 */
436static 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 */
475static 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 */
529static 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), par_len;
535#ifdef BIDI_SUPPORT
536 int *segment_idxs = NULL;
537 if (o->bidi_delimiters)
538 segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
539 evas_bidi_paragraph_props_unref(o->bidi_par_props);
540 o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs);
541 evas_bidi_props_reorder_line(NULL, 0, len, o->bidi_par_props, &v_to_l);
542 if (segment_idxs) free(segment_idxs);
543#endif
544 visual_pos = pos = 0;
545
546 par_len = len;
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
592EAPI void
593evas_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
653EAPI void
654evas_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
669EAPI const char *
670evas_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
686EAPI const char *
687evas_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
701EAPI Evas_BiDi_Direction
702evas_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
720EAPI Evas_Coord
721evas_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
735EAPI Evas_Coord
736evas_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
750EAPI Evas_Coord
751evas_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
765EAPI Evas_Coord
766evas_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
780EAPI Evas_Coord
781evas_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
797EAPI Evas_Coord
798evas_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
814EAPI Evas_Coord
815evas_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
831EAPI Eina_Bool
832evas_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
874EAPI int
875evas_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
891EAPI int
892evas_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
933EAPI void
934evas_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
959EAPI Evas_Text_Style_Type
960evas_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
974EAPI void
975evas_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
997EAPI void
998evas_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
1023EAPI void
1024evas_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
1046EAPI void
1047evas_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
1072EAPI void
1073evas_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
1095EAPI void
1096evas_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
1121EAPI void
1122evas_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
1144EAPI void
1145evas_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
1170EAPI void
1171evas_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
1202EAPI int
1203evas_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
1215EAPI int
1216evas_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
1228EAPI int
1229evas_string_char_len_get(const char *str)
1230{
1231 if (!str) return 0;
1232 return eina_unicode_utf8_get_len(str);
1233}
1234
1235void
1236evas_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 */
1363static void
1364evas_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
1385static void *
1386evas_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
1403static void
1404evas_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
1427static void
1428evas_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
1671static void
1672evas_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->cur.map != obj->prev.map) ||
1704 (obj->cur.usemap != obj->prev.usemap))
1705 {
1706 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1707 obj);
1708 goto done;
1709 }
1710 /* its not visible - we accounted for it appearing or not so just abort */
1711 if (!is_v) goto done;
1712 /* clipper changed this is in addition to anything else for obj */
1713 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
1714 /* if we restacked (layer or just within a layer) and dont clip anyone */
1715 if (obj->restack)
1716 {
1717 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1718 obj);
1719 goto done;
1720 }
1721 /* if it changed color */
1722 if ((obj->cur.color.r != obj->prev.color.r) ||
1723 (obj->cur.color.g != obj->prev.color.g) ||
1724 (obj->cur.color.b != obj->prev.color.b) ||
1725 (obj->cur.color.a != obj->prev.color.a))
1726 {
1727 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1728 obj);
1729 goto done;
1730 }
1731 /* if it changed geometry - and obviously not visibility or color
1732 calculate differences since we have a constant color fill
1733 we really only need to update the differences */
1734 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
1735 (obj->cur.geometry.y != obj->prev.geometry.y) ||
1736 (obj->cur.geometry.w != obj->prev.geometry.w) ||
1737 (obj->cur.geometry.h != obj->prev.geometry.h))
1738 {
1739 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1740 obj);
1741 goto done;
1742 }
1743 if (obj->cur.render_op != obj->prev.render_op)
1744 {
1745 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1746 obj);
1747 goto done;
1748 }
1749 if (obj->cur.scale != obj->prev.scale)
1750 {
1751 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1752 obj);
1753 goto done;
1754 }
1755 if (o->changed)
1756 {
1757 if ((o->cur.size != o->prev.size) ||
1758 ((o->cur.font != o->prev.font)) ||
1759 ((o->cur.utf8_text != o->prev.utf8_text)) ||
1760 ((o->cur.style != o->prev.style)) ||
1761 ((o->cur.shadow.r != o->prev.shadow.r)) ||
1762 ((o->cur.shadow.g != o->prev.shadow.g)) ||
1763 ((o->cur.shadow.b != o->prev.shadow.b)) ||
1764 ((o->cur.shadow.a != o->prev.shadow.a)) ||
1765 ((o->cur.outline.r != o->prev.outline.r)) ||
1766 ((o->cur.outline.g != o->prev.outline.g)) ||
1767 ((o->cur.outline.b != o->prev.outline.b)) ||
1768 ((o->cur.outline.a != o->prev.outline.a)) ||
1769 ((o->cur.glow.r != o->prev.glow.r)) ||
1770 ((o->cur.glow.g != o->prev.glow.g)) ||
1771 ((o->cur.glow.b != o->prev.glow.b)) ||
1772 ((o->cur.glow.a != o->prev.glow.a)) ||
1773 ((o->cur.glow2.r != o->prev.glow2.r)) ||
1774 ((o->cur.glow2.g != o->prev.glow2.g)) ||
1775 ((o->cur.glow2.b != o->prev.glow2.b)) ||
1776 ((o->cur.glow2.a != o->prev.glow2.a)))
1777 {
1778 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1779 obj);
1780 goto done;
1781 }
1782 }
1783 done:
1784 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes,
1785 obj, is_v, was_v);
1786}
1787
1788static void
1789evas_object_text_render_post(Evas_Object *obj)
1790{
1791 Evas_Object_Text *o;
1792
1793 /* this moves the current data to the previous state parts of the object
1794 in whatever way is safest for the object. also if we don't need object
1795 data anymore we can free it if the object deems this is a good idea */
1796 o = (Evas_Object_Text *)(obj->object_data);
1797 /* remove those pesky changes */
1798 evas_object_clip_changes_clean(obj);
1799 /* move cur to prev safely for object data */
1800 obj->prev = obj->cur;
1801 o->prev = o->cur;
1802 o->changed = 0;
1803}
1804
1805static unsigned int
1806evas_object_text_id_get(Evas_Object *obj)
1807{
1808 Evas_Object_Text *o;
1809
1810 o = (Evas_Object_Text *)(obj->object_data);
1811 if (!o) return 0;
1812 return MAGIC_OBJ_TEXT;
1813}
1814
1815static unsigned int
1816evas_object_text_visual_id_get(Evas_Object *obj)
1817{
1818 Evas_Object_Text *o;
1819
1820 o = (Evas_Object_Text *)(obj->object_data);
1821 if (!o) return 0;
1822 return MAGIC_OBJ_SHAPE;
1823}
1824
1825static void *
1826evas_object_text_engine_data_get(Evas_Object *obj)
1827{
1828 Evas_Object_Text *o;
1829
1830 o = (Evas_Object_Text *)(obj->object_data);
1831 if (!o) return NULL;
1832 return o->font;
1833}
1834
1835static int
1836evas_object_text_is_opaque(Evas_Object *obj __UNUSED__)
1837{
1838 /* this returns 1 if the internal object data implies that the object is
1839 currently fully opaque over the entire gradient it occupies */
1840 return 0;
1841}
1842
1843static int
1844evas_object_text_was_opaque(Evas_Object *obj __UNUSED__)
1845{
1846 /* this returns 1 if the internal object data implies that the object was
1847 currently fully opaque over the entire gradient it occupies */
1848 return 0;
1849}
1850
1851static void
1852evas_object_text_scale_update(Evas_Object *obj)
1853{
1854 Evas_Object_Text *o;
1855 int size;
1856 const char *font;
1857
1858 o = (Evas_Object_Text *)(obj->object_data);
1859 font = eina_stringshare_add(o->cur.font);
1860 size = o->cur.size;
1861 if (o->cur.font) eina_stringshare_del(o->cur.font);
1862 o->cur.font = NULL;
1863 o->prev.font = NULL;
1864 o->cur.size = 0;
1865 o->prev.size = 0;
1866 evas_object_text_font_set(obj, font, size);
1867}
1868
1869void
1870_evas_object_text_rehint(Evas_Object *obj)
1871{
1872 Evas_Object_Text *o;
1873 int is, was;
1874
1875 o = (Evas_Object_Text *)(obj->object_data);
1876 if (!o->font) return;
1877#ifdef EVAS_FRAME_QUEUING
1878 evas_common_pipe_op_text_flush((RGBA_Font *) o->font);
1879#endif
1880 evas_font_load_hinting_set(obj->layer->evas, o->font,
1881 obj->layer->evas->hinting);
1882 was = evas_object_is_in_output_rect(obj,
1883 obj->layer->evas->pointer.x,
1884 obj->layer->evas->pointer.y, 1, 1);
1885 /* DO II */
1886 _evas_object_text_recalc(obj);
1887 o->changed = 1;
1888 evas_object_change(obj);
1889 evas_object_clip_dirty(obj);
1890 evas_object_coords_recalc(obj);
1891 is = evas_object_is_in_output_rect(obj,
1892 obj->layer->evas->pointer.x,
1893 obj->layer->evas->pointer.y, 1, 1);
1894 if ((is || was) && obj->cur.visible)
1895 evas_event_feed_mouse_move(obj->layer->evas,
1896 obj->layer->evas->pointer.x,
1897 obj->layer->evas->pointer.y,
1898 obj->layer->evas->last_timestamp,
1899 NULL);
1900 evas_object_inform_call_resize(obj);
1901}
1902
1903static void
1904_evas_object_text_recalc(Evas_Object *obj)
1905{
1906 Evas_Object_Text *o;
1907 Eina_Unicode *text = NULL;
1908 o = (Evas_Object_Text *)(obj->object_data);
1909
1910 if (o->items) _evas_object_text_items_clear(o);
1911 if (o->cur.utf8_text)
1912 text = eina_unicode_utf8_to_unicode(o->cur.utf8_text,
1913 NULL);
1914
1915 if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
1916
1917 _evas_object_text_layout(obj, o, text);
1918
1919 if (text) free(text);
1920
1921 if ((o->font) && (o->items))
1922 {
1923 int w, h;
1924 int l = 0, r = 0, t = 0, b = 0;
1925
1926 w = _evas_object_text_horiz_advance_get(obj, o);
1927 h = _evas_object_text_vert_advance_get(obj, o);
1928 evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
1929 obj->cur.geometry.w = w + l + r;
1930 obj->cur.geometry.h = h + t + b;
1931//// obj->cur.cache.geometry.validity = 0;
1932 }
1933 else
1934 {
1935 int t = 0, b = 0;
1936
1937 evas_text_style_pad_get(o->cur.style, NULL, NULL, &t, &b);
1938 obj->cur.geometry.w = 0;
1939 obj->cur.geometry.h = o->max_ascent + o->max_descent + t + b;
1940//// obj->cur.cache.geometry.validity = 0;
1941 }
1942}
1943