2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
5 #include "evas_common.h"
6 #include "evas_private.h"
9 #define ENFN obj->layer->evas->engine.func
10 #define ENDT obj->layer->evas->engine.data.output
12 /* private magic number for textblock objects */
13 static const char o_type[] = "textblock";
15 /* private struct for textblock object internal data */
16 typedef struct _Evas_Object_Textblock Evas_Object_Textblock;
17 typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag;
18 typedef struct _Evas_Object_Textblock_Node Evas_Object_Textblock_Node;
19 typedef struct _Evas_Object_Textblock_Line Evas_Object_Textblock_Line;
20 typedef struct _Evas_Object_Textblock_Item Evas_Object_Textblock_Item;
21 typedef struct _Evas_Object_Textblock_Format_Item Evas_Object_Textblock_Format_Item;
22 typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format;
24 /* the current state of the formatting */
29 struct _Evas_Object_Style_Tag
38 struct _Evas_Object_Textblock_Node
45 struct _Evas_Object_Textblock_Line
48 Evas_Object_Textblock_Item *items;
49 Evas_Object_Textblock_Format_Item *format_items;
55 struct _Evas_Object_Textblock_Item
59 Evas_Object_Textblock_Format *format;
60 Evas_Object_Textblock_Node *source_node;
67 struct _Evas_Object_Textblock_Format_Item
71 Evas_Object_Textblock_Node *source_node;
72 int x, w, h, y, ascent, descent;
73 unsigned char vsize : 2;
74 unsigned char size : 2;
75 unsigned char formatme : 1;
76 unsigned char ___padding___ : 3;
79 struct _Evas_Object_Textblock_Format
87 const char *fallbacks;
93 unsigned char r, g, b, a;
94 } normal, underline, underline2, outline, shadow, glow, glow2, backing,
106 unsigned char wrap_word : 1;
107 unsigned char wrap_char : 1;
108 unsigned char underline : 1;
109 unsigned char underline2 : 1;
110 unsigned char strikethrough : 1;
111 unsigned char backing : 1;
114 struct _Evas_Textblock_Style
118 Evas_Object_Style_Tag *tags;
120 unsigned char delete_me : 1;
123 struct _Evas_Textblock_Cursor
127 Evas_Object_Textblock_Node *node;
131 struct _Evas_Object_Textblock
134 Evas_Textblock_Style *style;
135 Evas_Textblock_Cursor *cursor;
137 Evas_Object_Textblock_Node *nodes;
138 Evas_Object_Textblock_Line *lines;
148 unsigned char valid : 1;
150 unsigned char redraw : 1;
151 unsigned char changed : 1;
154 /* private methods for textblock objects */
155 static void evas_object_textblock_init(Evas_Object *obj);
156 static void *evas_object_textblock_new(void);
157 static void evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
158 static void evas_object_textblock_free(Evas_Object *obj);
159 static void evas_object_textblock_render_pre(Evas_Object *obj);
160 static void evas_object_textblock_render_post(Evas_Object *obj);
162 static unsigned int evas_object_textblock_id_get(Evas_Object *obj);
163 static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj);
164 static void *evas_object_textblock_engine_data_get(Evas_Object *obj);
166 static int evas_object_textblock_is_opaque(Evas_Object *obj);
167 static int evas_object_textblock_was_opaque(Evas_Object *obj);
169 static void evas_object_textblock_coords_recalc(Evas_Object *obj);
171 static void evas_object_textblock_scale_update(Evas_Object *obj);
173 static const Evas_Object_Func object_func =
175 /* methods (compulsory) */
176 evas_object_textblock_free,
177 evas_object_textblock_render,
178 evas_object_textblock_render_pre,
179 evas_object_textblock_render_post,
180 evas_object_textblock_id_get,
181 evas_object_textblock_visual_id_get,
182 evas_object_textblock_engine_data_get,
183 /* these are optional. NULL = nothing */
188 evas_object_textblock_is_opaque,
189 evas_object_textblock_was_opaque,
192 evas_object_textblock_coords_recalc,
193 evas_object_textblock_scale_update,
199 /* the actual api call to add a textblock */
202 Evas_Object_Textblock *o; \
203 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
206 o = (Evas_Object_Textblock *)(obj->object_data); \
207 MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
211 #define TB_HEAD_RETURN(x) \
212 Evas_Object_Textblock *o; \
213 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
216 o = (Evas_Object_Textblock *)(obj->object_data); \
217 MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
223 * @addtogroup Evas_Object_Textblock
229 _style_clear(Evas_Textblock_Style *ts)
231 if (ts->style_text) free(ts->style_text);
232 if (ts->default_tag) free(ts->default_tag);
235 Evas_Object_Style_Tag *tag;
237 tag = (Evas_Object_Style_Tag *)ts->tags;
238 ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
243 ts->style_text = NULL;
244 ts->default_tag = NULL;
248 static inline const char *
249 _style_match_replace(Evas_Textblock_Style *ts, const char *s, size_t replace_len, size_t *tag_len)
251 Evas_Object_Style_Tag *tag;
253 EINA_INLIST_FOREACH(ts->tags, tag)
255 if (tag->replace_len != replace_len) continue;
256 if (!strcmp(tag->replace, s))
258 *tag_len = tag->tag_len;
266 static inline const char *
267 _style_match_tag(Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len)
269 Evas_Object_Style_Tag *tag;
271 EINA_INLIST_FOREACH(ts->tags, tag)
273 if (tag->tag_len != tag_len) continue;
274 if (!strcmp(tag->tag, s))
276 *replace_len = tag->replace_len;
285 _nodes_clear(const Evas_Object *obj)
287 Evas_Object_Textblock *o;
289 o = (Evas_Object_Textblock *)(obj->object_data);
292 Evas_Object_Textblock_Node *n;
294 n = (Evas_Object_Textblock_Node *)o->nodes;
295 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
296 if (n->text) eina_strbuf_free(n->text);
302 _format_free(const Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
305 if (fmt->ref > 0) return;
306 if (fmt->font.name) eina_stringshare_del(fmt->font.name);
307 if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
308 if (fmt->font.source) eina_stringshare_del(fmt->font.source);
309 evas_font_free(obj->layer->evas, fmt->font.font);
314 _line_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln)
318 Evas_Object_Textblock_Item *it;
320 it = (Evas_Object_Textblock_Item *)ln->items;
321 ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items));
322 if (it->text) free(it->text);
323 _format_free(obj, it->format);
326 while (ln->format_items)
328 Evas_Object_Textblock_Format_Item *fi;
330 fi = (Evas_Object_Textblock_Format_Item *)ln->format_items;
331 ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->format_items),
332 EINA_INLIST_GET(ln->format_items));
333 if (fi->item) eina_stringshare_del(fi->item);
340 _lines_clear(const Evas_Object *obj, Evas_Object_Textblock_Line *lines)
344 Evas_Object_Textblock_Line *ln;
346 ln = (Evas_Object_Textblock_Line *)lines;
347 lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(lines), EINA_INLIST_GET(ln));
353 _nodes_adjacent_merge(const Evas_Object *obj, Evas_Object_Textblock_Node *n1)
355 Evas_Object_Textblock *o;
356 Evas_Object_Textblock_Node *n0, *n2;
358 Evas_Textblock_Cursor *data;
361 if (n1->type != NODE_TEXT) return;
362 o = (Evas_Object_Textblock *)(obj->object_data);
363 n0 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->prev;
364 n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next;
365 if ((n0) && (n0->type == NODE_TEXT))
367 plen = eina_strbuf_length_get(n0->text);
368 eina_strbuf_append_length(n0->text, eina_strbuf_string_get(n1->text),
369 eina_strbuf_length_get(n1->text));
370 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove
371 (EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1));
372 // (EINA_INLIST_GET(n0))->next = EINA_INLIST_GET(n2);
373 // if (n2) (EINA_INLIST_GET(n2))->prev = EINA_INLIST_GET(n0);
374 // fix any cursors in n1
375 if (n1 == o->cursor->node)
377 o->cursor->node = n0;
378 o->cursor->pos += plen;
380 EINA_LIST_FOREACH(o->cursors, l, data)
382 if (n1 == data->node)
388 if (n1->text) eina_strbuf_free(n1->text);
391 n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next;
393 if ((n2) && (n2->type == NODE_TEXT))
397 n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next;
398 plen = eina_strbuf_length_get(n0->text);
399 eina_strbuf_append_length(n0->text, eina_strbuf_string_get(n1->text),
400 eina_strbuf_length_get(n1->text));
401 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove
402 (EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1));
403 // (EINA_INLIST_GET(n0))->next = EINA_INLIST_GET(n2);
404 // if (n2) (EINA_INLIST_GET(n2))->prev = EINA_INLIST_GET(n0);
405 // fix any cursors in n1
406 if (n1 == o->cursor->node)
408 o->cursor->node = n0;
409 o->cursor->pos += plen;
411 EINA_LIST_FOREACH(o->cursors, l, data)
413 if (n1 == data->node)
419 if (n1->text) eina_strbuf_free(n1->text);
424 /* table of html escapes (that i can find) this should be ordered with the
425 * most common first as it's a linear search to match - no hash for this.
427 * these are stored as one large string and one additional array that
428 * contains the offsets to the tokens for space efficiency.
430 static const char escape_strings[] =
431 /* most common escaped stuff */
432 " \0" "\x20\0" /* NOTE: this here to avoid escaping to   */
433 " \0" "\x20\0" /* NOTE: we allow nsbp's to break as we map early - maybe map to ascii 0x01 and then make the rendering code think 0x01 -> 0x20 */
439 "¡\0" "\xc2\xa1\0"
440 "¢\0" "\xc2\xa2\0"
441 "£\0" "\xc2\xa3\0"
442 "¤\0" "\xc2\xa4\0"
443 "¥\0" "\xc2\xa5\0"
444 "¦\0" "\xc2\xa6\0"
445 "§\0" "\xc2\xa7\0"
446 "¨\0" "\xc2\xa8\0"
447 "©\0" "\xc2\xa9\0"
448 "ª\0" "\xc2\xaa\0"
449 "«\0" "\xc2\xab\0"
450 "¬\0" "\xc2\xac\0"
451 "®\0" "\xc2\xae\0"
452 "¯\0" "\xc2\xaf\0"
453 "°\0" "\xc2\xb0\0"
454 "±\0" "\xc2\xb1\0"
455 "²\0" "\xc2\xb2\0"
456 "³\0" "\xc2\xb3\0"
457 "´\0" "\xc2\xb4\0"
458 "µ\0" "\xc2\xb5\0"
459 "¶\0" "\xc2\xb6\0"
460 "·\0" "\xc2\xb7\0"
461 "¸\0" "\xc2\xb8\0"
462 "¹\0" "\xc2\xb9\0"
463 "º\0" "\xc2\xba\0"
464 "»\0" "\xc2\xbb\0"
465 "¼\0" "\xc2\xbc\0"
466 "½\0" "\xc2\xbd\0"
467 "¾\0" "\xc2\xbe\0"
468 "¿\0" "\xc2\xbf\0"
469 "À\0" "\xc3\x80\0"
470 "Á\0" "\xc3\x81\0"
471 "Â\0" "\xc3\x82\0"
472 "Ã\0" "\xc3\x83\0"
473 "Ä\0" "\xc3\x84\0"
474 "Å\0" "\xc3\x85\0"
475 "&Aelig;\0" "\xc3\x86\0"
476 "Ç\0" "\xc3\x87\0"
477 "È\0" "\xc3\x88\0"
478 "É\0" "\xc3\x89\0"
479 "Ê\0" "\xc3\x8a\0"
480 "Ë\0" "\xc3\x8b\0"
481 "È\0" "\xc3\x8c\0"
482 "É\0" "\xc3\x8d\0"
483 "Î\0" "\xc3\x8e\0"
484 "Ï\0" "\xc3\x8f\0"
485 "&Eth;\0" "\xc3\x90\0"
486 "Ñ\0" "\xc3\x91\0"
487 "Ò\0" "\xc3\x92\0"
488 "Ó\0" "\xc3\x93\0"
489 "Ô\0" "\xc3\x94\0"
490 "Õ\0" "\xc3\x95\0"
491 "Ö\0" "\xc3\x96\0"
492 "×\0" "\xc3\x97\0"
493 "Ø\0" "\xc3\x98\0"
494 "Ù\0" "\xc3\x99\0"
495 "Ú\0" "\xc3\x9a\0"
496 "Û\0" "\xc3\x9b\0"
497 "Ý\0" "\xc3\x9d\0"
498 "&Thorn;\0" "\xc3\x9e\0"
499 "ß\0" "\xc3\x9f\0"
500 "à\0" "\xc3\xa0\0"
501 "á\0" "\xc3\xa1\0"
502 "â\0" "\xc3\xa2\0"
503 "ã\0" "\xc3\xa3\0"
504 "ä\0" "\xc3\xa4\0"
505 "å\0" "\xc3\xa5\0"
506 "æ\0" "\xc3\xa6\0"
507 "ç\0" "\xc3\xa7\0"
508 "è\0" "\xc3\xa8\0"
509 "é\0" "\xc3\xa9\0"
510 "ê\0" "\xc3\xaa\0"
511 "ë\0" "\xc3\xab\0"
512 "ì\0" "\xc3\xac\0"
513 "í\0" "\xc3\xad\0"
514 "î\0" "\xc3\xae\0"
515 "ï\0" "\xc3\xaf\0"
516 "ð\0" "\xc3\xb0\0"
517 "ñ\0" "\xc3\xb1\0"
518 "ò\0" "\xc3\xb2\0"
519 "ó\0" "\xc3\xb3\0"
520 "ô\0" "\xc3\xb4\0"
521 "õ\0" "\xc3\xb5\0"
522 "ö\0" "\xc3\xb6\0"
523 "÷\0" "\xc3\xb7\0"
524 "ø\0" "\xc3\xb8\0"
525 "ù\0" "\xc3\xb9\0"
526 "ú\0" "\xc3\xba\0"
527 "û\0" "\xc3\xbb\0"
528 "ü\0" "\xc3\xbc\0"
529 "ý\0" "\xc3\xbd\0"
530 "þ\0" "\xc3\xbe\0"
531 "ÿ\0" "\xc3\xbf\0"
532 "α\0" "\xce\x91\0"
533 "β\0" "\xce\x92\0"
534 "γ\0" "\xce\x93\0"
535 "δ\0" "\xce\x94\0"
536 "ε\0" "\xce\x95\0"
537 "ζ\0" "\xce\x96\0"
538 "η\0" "\xce\x97\0"
539 "θ\0" "\xce\x98\0"
540 "ι\0" "\xce\x99\0"
541 "κ\0" "\xce\x9a\0"
542 "λ\0" "\xce\x9b\0"
543 "μ\0" "\xce\x9c\0"
544 "ν\0" "\xce\x9d\0"
545 "ξ\0" "\xce\x9e\0"
546 "ο\0" "\xce\x9f\0"
547 "π\0" "\xce\xa0\0"
548 "ρ\0" "\xce\xa1\0"
549 "σ\0" "\xce\xa3\0"
550 "τ\0" "\xce\xa4\0"
551 "υ\0" "\xce\xa5\0"
552 "φ\0" "\xce\xa6\0"
553 "χ\0" "\xce\xa7\0"
554 "ψ\0" "\xce\xa8\0"
555 "ω\0" "\xce\xa9\0"
556 "…\0" "\xe2\x80\xa6\0"
557 "€\0" "\xe2\x82\xac\0"
558 "←\0" "\xe2\x86\x90\0"
559 "↑\0" "\xe2\x86\x91\0"
560 "→\0" "\xe2\x86\x92\0"
561 "↓\0" "\xe2\x86\x93\0"
562 "↔\0" "\xe2\x86\x94\0"
563 "←\0" "\xe2\x87\x90\0"
564 "→\0" "\xe2\x87\x92\0"
565 "∀\0" "\xe2\x88\x80\0"
566 "∃\0" "\xe2\x88\x83\0"
567 "∇\0" "\xe2\x88\x87\0"
568 "∏\0" "\xe2\x88\x8f\0"
569 "∑\0" "\xe2\x88\x91\0"
570 "∧\0" "\xe2\x88\xa7\0"
571 "∨\0" "\xe2\x88\xa8\0"
572 "∫\0" "\xe2\x88\xab\0"
573 "≠\0" "\xe2\x89\xa0\0"
574 "≡\0" "\xe2\x89\xa1\0"
575 "⊕\0" "\xe2\x8a\x95\0"
576 "⊥\0" "\xe2\x8a\xa5\0"
584 * unicode list of whitespace chars
586 * 0009..000D <control-0009>..<control-000D>
588 * 0085 <control-0085>
589 * 00A0 NO-BREAK SPACE
590 * 1680 OGHAM SPACE MARK
591 * 180E MONGOLIAN VOWEL SEPARATOR
592 * 2000..200A EN QUAD..HAIR SPACE
593 * 2028 LINE SEPARATOR
594 * 2029 PARAGRAPH SEPARATOR
595 * 202F NARROW NO-BREAK SPACE
596 * 205F MEDIUM MATHEMATICAL SPACE
597 * 3000 IDEOGRAPHIC SPACE
601 ((c >= 0x9) && (c <= 0xd)) ||
606 ((c >= 0x2000) && (c <= 0x200a)) ||
618 _clean_white(int clean_start, int clean_end, char *str)
620 char *p, *p2, *str2 = NULL;
621 int white, pwhite, start, ok;
624 str2 = malloc(strlen(str) + 2);
633 if (isspace(*p) || _is_white(*p)) white = 1;
635 if ((pwhite) && (white)) ok = 0;
640 if ((start) && (pwhite) && (!white))
647 if (!white) start = 0;
651 if ((start) && (ok)) ok = 0;
666 if (!(isspace(*p2) || _is_white(*p2))) break;
675 _append_text_run(Evas_Object_Textblock *o, char *s, char *p)
681 ts = alloca(p - s + 1);
682 strncpy(ts, s, p - s);
684 ts = _clean_white(0, 0, ts);
685 evas_textblock_cursor_text_append(o->cursor, ts);
690 _prepend_text_run(Evas_Object_Textblock *o, char *s, char *p)
696 ts = alloca(p - s + 1);
697 strncpy(ts, s, p - s);
699 ts = _clean_white(0, 0, ts);
700 evas_textblock_cursor_text_prepend(o->cursor, ts);
706 _hex_string_get(char ch)
708 if ((ch >= '0') && (ch <= '9')) return (ch - '0');
709 else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
710 else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
715 _format_color_parse(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
720 *r = *g = *b = *a = 0;
722 if (slen == 7) /* #RRGGBB */
724 *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
725 *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
726 *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
729 else if (slen == 9) /* #RRGGBBAA */
731 *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
732 *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
733 *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
734 *a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8]));
736 else if (slen == 4) /* #RGB */
738 *r = _hex_string_get(str[1]);
740 *g = _hex_string_get(str[2]);
742 *b = _hex_string_get(str[3]);
746 else if (slen == 5) /* #RGBA */
748 *r = _hex_string_get(str[1]);
750 *g = _hex_string_get(str[2]);
752 *b = _hex_string_get(str[3]);
754 *a = _hex_string_get(str[4]);
757 *r = (*r * *a) / 255;
758 *g = (*g * *a) / 255;
759 *b = (*b * *a) / 255;
762 static const char *fontstr = NULL;
763 static const char *font_fallbacksstr = NULL;
764 static const char *font_sizestr = NULL;
765 static const char *font_sourcestr = NULL;
766 static const char *colorstr = NULL;
767 static const char *underline_colorstr = NULL;
768 static const char *underline2_colorstr = NULL;
769 static const char *outline_colorstr = NULL;
770 static const char *shadow_colorstr = NULL;
771 static const char *glow_colorstr = NULL;
772 static const char *glow2_colorstr = NULL;
773 static const char *backing_colorstr = NULL;
774 static const char *strikethrough_colorstr = NULL;
775 static const char *alignstr = NULL;
776 static const char *valignstr = NULL;
777 static const char *wrapstr = NULL;
778 static const char *left_marginstr = NULL;
779 static const char *right_marginstr = NULL;
780 static const char *underlinestr = NULL;
781 static const char *strikethroughstr = NULL;
782 static const char *backingstr = NULL;
783 static const char *stylestr = NULL;
784 static const char *tabstopsstr = NULL;
785 static const char *linesizestr = NULL;
786 static const char *linerelsizestr = NULL;
787 static const char *linegapstr = NULL;
788 static const char *linerelgapstr = NULL;
789 static const char *itemstr = NULL;
792 _format_command_init(void)
795 fontstr = eina_stringshare_add("font");
796 font_fallbacksstr = eina_stringshare_add("font_fallbacks");
797 font_sizestr = eina_stringshare_add("font_size");
798 font_sourcestr = eina_stringshare_add("font_source");
799 colorstr = eina_stringshare_add("color");
800 underline_colorstr = eina_stringshare_add("underline_color");
801 underline2_colorstr = eina_stringshare_add("underline2_color");
802 outline_colorstr = eina_stringshare_add("outline_color");
803 shadow_colorstr = eina_stringshare_add("shadow_color");
804 glow_colorstr = eina_stringshare_add("glow_color");
805 glow2_colorstr = eina_stringshare_add("glow2_color");
806 backing_colorstr = eina_stringshare_add("backing_color");
807 strikethrough_colorstr = eina_stringshare_add("strikethrough_color");
808 alignstr = eina_stringshare_add("align");
809 valignstr = eina_stringshare_add("valign");
810 wrapstr = eina_stringshare_add("wrap");
811 left_marginstr = eina_stringshare_add("left_margin");
812 right_marginstr = eina_stringshare_add("right_margin");
813 underlinestr = eina_stringshare_add("underline");
814 strikethroughstr = eina_stringshare_add("strikethrough");
815 backingstr = eina_stringshare_add("backing");
816 stylestr = eina_stringshare_add("style");
817 tabstopsstr = eina_stringshare_add("tabstops");
818 linesizestr = eina_stringshare_add("linesize");
819 linerelsizestr = eina_stringshare_add("linerelsize");
820 linegapstr = eina_stringshare_add("linegap");
821 linerelgapstr = eina_stringshare_add("linerelgap");
822 itemstr = eina_stringshare_add("item");
826 _format_command_shutdown(void)
829 eina_stringshare_del(fontstr);
830 eina_stringshare_del(font_fallbacksstr);
831 eina_stringshare_del(font_sizestr);
832 eina_stringshare_del(font_sourcestr);
833 eina_stringshare_del(colorstr);
834 eina_stringshare_del(underline_colorstr);
835 eina_stringshare_del(underline2_colorstr);
836 eina_stringshare_del(outline_colorstr);
837 eina_stringshare_del(shadow_colorstr);
838 eina_stringshare_del(glow_colorstr);
839 eina_stringshare_del(glow2_colorstr);
840 eina_stringshare_del(backing_colorstr);
841 eina_stringshare_del(strikethrough_colorstr);
842 eina_stringshare_del(alignstr);
843 eina_stringshare_del(valignstr);
844 eina_stringshare_del(wrapstr);
845 eina_stringshare_del(left_marginstr);
846 eina_stringshare_del(right_marginstr);
847 eina_stringshare_del(underlinestr);
848 eina_stringshare_del(strikethroughstr);
849 eina_stringshare_del(backingstr);
850 eina_stringshare_del(stylestr);
851 eina_stringshare_del(tabstopsstr);
852 eina_stringshare_del(linesizestr);
853 eina_stringshare_del(linerelsizestr);
854 eina_stringshare_del(linegapstr);
855 eina_stringshare_del(linerelgapstr);
856 eina_stringshare_del(itemstr);
860 _format_clean_param(char *dst, const char *src)
866 for (ss = src; *ss; ss++, ds++)
868 if ((*ss == '\\') && *(ss + 1)) ss++;
875 _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *cmd, const char *param)
880 tmp_param = alloca(strlen(param) + 1);
882 _format_clean_param(tmp_param, param);
885 if ((!fmt->font.name) ||
886 ((fmt->font.name) && (strcmp(fmt->font.name, tmp_param))))
888 if (fmt->font.name) eina_stringshare_del(fmt->font.name);
889 fmt->font.name = eina_stringshare_add(tmp_param);
893 else if (cmd == font_fallbacksstr)
895 if ((!fmt->font.fallbacks) ||
896 ((fmt->font.fallbacks) && (strcmp(fmt->font.fallbacks, tmp_param))))
898 /* policy - when we say "fallbacks" do we prepend and use prior
899 * fallbacks... or should we replace. for now we replace
901 if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
902 fmt->font.fallbacks = eina_stringshare_add(tmp_param);
906 else if (cmd == font_sizestr)
911 if (v != fmt->font.size)
917 else if (cmd == font_sourcestr)
919 if ((!fmt->font.source) ||
920 ((fmt->font.source) && (strcmp(fmt->font.source, tmp_param))))
922 if (fmt->font.source) eina_stringshare_del(fmt->font.source);
923 fmt->font.source = eina_stringshare_add(tmp_param);
927 else if (cmd == colorstr)
928 _format_color_parse(tmp_param,
929 &(fmt->color.normal.r), &(fmt->color.normal.g),
930 &(fmt->color.normal.b), &(fmt->color.normal.a));
931 else if (cmd == underline_colorstr)
932 _format_color_parse(tmp_param,
933 &(fmt->color.underline.r), &(fmt->color.underline.g),
934 &(fmt->color.underline.b), &(fmt->color.underline.a));
935 else if (cmd == underline2_colorstr)
936 _format_color_parse(tmp_param,
937 &(fmt->color.underline2.r), &(fmt->color.underline2.g),
938 &(fmt->color.underline2.b), &(fmt->color.underline2.a));
939 else if (cmd == outline_colorstr)
940 _format_color_parse(tmp_param,
941 &(fmt->color.outline.r), &(fmt->color.outline.g),
942 &(fmt->color.outline.b), &(fmt->color.outline.a));
943 else if (cmd == shadow_colorstr)
944 _format_color_parse(tmp_param,
945 &(fmt->color.shadow.r), &(fmt->color.shadow.g),
946 &(fmt->color.shadow.b), &(fmt->color.shadow.a));
947 else if (cmd == glow_colorstr)
948 _format_color_parse(tmp_param,
949 &(fmt->color.glow.r), &(fmt->color.glow.g),
950 &(fmt->color.glow.b), &(fmt->color.glow.a));
951 else if (cmd == glow2_colorstr)
952 _format_color_parse(tmp_param,
953 &(fmt->color.glow2.r), &(fmt->color.glow2.g),
954 &(fmt->color.glow2.b), &(fmt->color.glow2.a));
955 else if (cmd == backing_colorstr)
956 _format_color_parse(tmp_param,
957 &(fmt->color.backing.r), &(fmt->color.backing.g),
958 &(fmt->color.backing.b), &(fmt->color.backing.a));
959 else if (cmd == strikethrough_colorstr)
960 _format_color_parse(tmp_param,
961 &(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g),
962 &(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a));
963 else if (cmd == alignstr)
965 if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5;
966 else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5;
967 else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0;
968 else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0;
972 double val = strtod(tmp_param, &endptr);
975 while (*endptr && _is_white(*endptr))
981 if (fmt->halign < 0.0) fmt->halign = 0.0;
982 else if (fmt->halign > 1.0) fmt->halign = 1.0;
985 else if (cmd == valignstr)
987 if (!strcmp(tmp_param, "top")) fmt->valign = 0.0;
988 else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5;
989 else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5;
990 else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0;
991 else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0;
992 else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0;
996 double val = strtod(tmp_param, &endptr);
999 while (*endptr && _is_white(*endptr))
1005 if (fmt->valign < 0.0) fmt->valign = 0.0;
1006 else if (fmt->valign > 1.0) fmt->valign = 1.0;
1009 else if (cmd == wrapstr)
1011 if (!strcmp(tmp_param, "word"))
1016 else if (!strcmp(tmp_param, "char"))
1027 else if (cmd == left_marginstr)
1029 if (!strcmp(tmp_param, "reset"))
1033 if (tmp_param[0] == '+')
1034 fmt->margin.l += atoi(&(tmp_param[1]));
1035 else if (tmp_param[0] == '-')
1036 fmt->margin.l -= atoi(&(tmp_param[1]));
1038 fmt->margin.l = atoi(tmp_param);
1039 if (fmt->margin.l < 0) fmt->margin.l = 0;
1042 else if (cmd == right_marginstr)
1044 if (!strcmp(tmp_param, "reset"))
1048 if (tmp_param[0] == '+')
1049 fmt->margin.r += atoi(&(tmp_param[1]));
1050 else if (tmp_param[0] == '-')
1051 fmt->margin.r -= atoi(&(tmp_param[1]));
1053 fmt->margin.r = atoi(tmp_param);
1054 if (fmt->margin.r < 0) fmt->margin.r = 0;
1057 else if (cmd == underlinestr)
1059 if (!strcmp(tmp_param, "off"))
1062 fmt->underline2 = 0;
1064 else if ((!strcmp(tmp_param, "on")) ||
1065 (!strcmp(tmp_param, "single")))
1068 fmt->underline2 = 0;
1070 else if (!strcmp(tmp_param, "double"))
1073 fmt->underline2 = 1;
1076 else if (cmd == strikethroughstr)
1078 if (!strcmp(tmp_param, "off"))
1079 fmt->strikethrough = 0;
1080 else if (!strcmp(tmp_param, "on"))
1081 fmt->strikethrough = 1;
1083 else if (cmd == backingstr)
1085 if (!strcmp(tmp_param, "off"))
1087 else if (!strcmp(tmp_param, "on"))
1090 else if (cmd == stylestr)
1092 if (!strcmp(tmp_param, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1093 else if (!strcmp(tmp_param, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1094 else if (!strcmp(tmp_param, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1095 else if (!strcmp(tmp_param, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW;
1096 else if (!strcmp(tmp_param, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE;
1097 else if (!strcmp(tmp_param, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
1098 else if (!strcmp(tmp_param, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
1099 else if (!strcmp(tmp_param, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
1100 else if (!strcmp(tmp_param, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW;
1101 else if (!strcmp(tmp_param, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW;
1102 else if (!strcmp(tmp_param, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW;
1103 else if (!strcmp(tmp_param, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
1104 else fmt->style = EVAS_TEXT_STYLE_PLAIN;
1106 else if (cmd == tabstopsstr)
1108 fmt->tabstops = atoi(tmp_param);
1109 if (fmt->tabstops < 1) fmt->tabstops = 1;
1111 else if (cmd == linesizestr)
1113 fmt->linesize = atoi(tmp_param);
1114 fmt->linerelsize = 0.0;
1116 else if (cmd == linerelsizestr)
1118 char *endptr = NULL;
1119 double val = strtod(tmp_param, &endptr);
1122 while (*endptr && _is_white(*endptr))
1126 fmt->linerelsize = val / 100.0;
1128 if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0;
1132 else if (cmd == linegapstr)
1134 fmt->linegap = atoi(tmp_param);
1135 fmt->linerelgap = 0.0;
1137 else if (cmd == linerelgapstr)
1139 char *endptr = NULL;
1140 double val = strtod(tmp_param, &endptr);
1143 while (*endptr && _is_white(*endptr))
1147 fmt->linerelgap = val / 100.0;
1149 if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0;
1159 of = fmt->font.font;
1160 if ((fmt->font.name) && (fmt->font.fallbacks))
1162 buf = malloc(strlen(fmt->font.name) + 1 + strlen(fmt->font.fallbacks) + 1);
1163 strcpy(buf, fmt->font.name);
1165 strcat(buf, fmt->font.fallbacks);
1167 else if (fmt->font.name)
1168 buf = strdup(fmt->font.name);
1170 fmt->font.font = evas_font_load(obj->layer->evas,
1171 buf, fmt->font.source,
1172 (int)(((double)fmt->font.size) * obj->cur.scale));
1174 if (of) evas_font_free(obj->layer->evas, of);
1179 _format_is_param(char *item)
1181 if (strchr(item, '=')) return 1;
1186 _format_param_parse(char *item, const char **key, const char **val)
1191 p = strchr(item, '=');
1193 k = eina_stringshare_add(item);
1197 v = eina_stringshare_add(p);
1202 _format_parse(char **s)
1205 char *s1 = NULL, *s2 = NULL;
1208 if (*p == 0) return NULL;
1213 if (*p != ' ') s1 = p;
1218 if ((p > *s) && (p[-1] != '\\'))
1220 if (*p == ' ') s2 = p;
1222 if (*p == 0) s2 = p;
1238 _format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, char *str)
1245 /* get rid of anything +s or -s off the start of the string */
1246 while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
1248 while ((item = _format_parse(&s)))
1250 char tmp_delim = *s;
1252 if (_format_is_param(item))
1254 const char *key = NULL, *val = NULL;
1256 _format_param_parse(item, &key, &val);
1257 _format_command(obj, fmt, key, val);
1258 eina_stringshare_del(key);
1259 eina_stringshare_del(val);
1263 /* immediate - not handled here */
1269 static Evas_Object_Textblock_Format *
1270 _format_dup(Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
1272 Evas_Object_Textblock_Format *fmt2;
1275 fmt2 = calloc(1, sizeof(Evas_Object_Textblock_Format));
1276 memcpy(fmt2, fmt, sizeof(Evas_Object_Textblock_Format));
1278 if (fmt->font.name) fmt2->font.name = eina_stringshare_add(fmt->font.name);
1279 if (fmt->font.fallbacks) fmt2->font.fallbacks = eina_stringshare_add(fmt->font.fallbacks);
1280 if (fmt->font.source) fmt2->font.source = eina_stringshare_add(fmt->font.source);
1282 if ((fmt2->font.name) && (fmt2->font.fallbacks))
1284 buf = malloc(strlen(fmt2->font.name) + 1 + strlen(fmt2->font.fallbacks) + 1);
1285 strcpy(buf, fmt2->font.name);
1287 strcat(buf, fmt2->font.fallbacks);
1289 else if (fmt2->font.name)
1290 buf = strdup(fmt2->font.name);
1291 fmt2->font.font = evas_font_load(obj->layer->evas,
1292 buf, fmt2->font.source,
1293 (int)(((double)fmt2->font.size) * obj->cur.scale));
1307 typedef struct _Ctxt Ctxt;
1312 Evas_Object_Textblock *o;
1314 Evas_Object_Textblock_Line *lines;
1315 Evas_Object_Textblock_Line *ln;
1317 Eina_List *format_stack;
1322 int maxascent, maxdescent;
1323 int marginl, marginr;
1325 int underline_extend;
1326 int have_underline, have_underline2;
1331 _layout_format_ascent_descent_adjust(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1333 int ascent, descent;
1337 // ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font);
1338 // descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font);
1339 ascent = c->ENFN->font_ascent_get(c->ENDT, fmt->font.font);
1340 descent = c->ENFN->font_descent_get(c->ENDT, fmt->font.font);
1341 if (fmt->linesize > 0)
1343 if ((ascent + descent) < fmt->linesize)
1345 ascent = ((fmt->linesize * ascent) / (ascent + descent));
1346 descent = fmt->linesize - ascent;
1349 else if (fmt->linerelsize > 0.0)
1351 descent = ((ascent + descent) * fmt->linerelsize) - (ascent * fmt->linerelsize);
1352 ascent = ascent * fmt->linerelsize;
1354 c->maxdescent += fmt->linegap;
1355 c->maxdescent += ((ascent + descent) * fmt->linerelgap);
1356 if (c->maxascent < ascent) c->maxascent = ascent;
1357 if (c->maxdescent < descent) c->maxdescent = descent;
1362 _layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1364 c->ln = calloc(1, sizeof(Evas_Object_Textblock_Line));
1365 c->align = fmt->halign;
1366 c->marginl = fmt->margin.l;
1367 c->marginr = fmt->margin.r;
1368 c->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->lines), EINA_INLIST_GET(c->ln));
1370 c->maxascent = c->maxdescent = 0;
1371 c->ln->line_no = -1;
1372 _layout_format_ascent_descent_adjust(c, fmt);
1375 static Evas_Object_Textblock_Format *
1376 _layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1380 fmt = _format_dup(c->obj, fmt);
1381 c->format_stack = eina_list_prepend(c->format_stack, fmt);
1385 fmt = calloc(1, sizeof(Evas_Object_Textblock_Format));
1386 c->format_stack = eina_list_prepend(c->format_stack, fmt);
1390 fmt->style = EVAS_TEXT_STYLE_PLAIN;
1393 fmt->linerelsize = 0.0;
1395 fmt->linerelgap = 0.0;
1400 static Evas_Object_Textblock_Format *
1401 _layout_format_pop(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1403 if ((c->format_stack) && (c->format_stack->next))
1405 _format_free(c->obj, fmt);
1406 c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack);
1407 fmt = c->format_stack->data;
1413 _layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, char *item)
1415 const char *key = NULL, *val = NULL;
1417 _format_param_parse(item, &key, &val);
1418 if ((key) && (val)) _format_command(c->obj, fmt, key, val);
1419 if (key) eina_stringshare_del(key);
1420 if (val) eina_stringshare_del(val);
1421 c->align = fmt->halign;
1422 c->marginl = fmt->margin.l;
1423 c->marginr = fmt->margin.r;
1426 #define VSIZE_FULL 0
1427 #define VSIZE_ASCENT 1
1434 _layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1436 Evas_Object_Textblock_Item *it;
1437 Evas_Object_Textblock_Format_Item *fi;
1439 c->maxascent = c->maxdescent = 0;
1441 _layout_format_ascent_descent_adjust(c, fmt);
1442 EINA_INLIST_FOREACH(c->ln->items, it)
1446 if (it->format->font.font)
1447 it->baseline = c->ENFN->font_max_ascent_get(c->ENDT, it->format->font.font);
1448 _layout_format_ascent_descent_adjust(c, it->format);
1449 endx = it->x + it->w;
1450 if (endx > c->ln->w) c->ln->w = endx;
1452 EINA_INLIST_FOREACH(c->ln->format_items, fi)
1456 if (!fi->formatme) continue;
1457 endx = fi->x + fi->w;
1458 if (endx > c->ln->w) c->ln->w = endx;
1466 if (fi->h > (c->maxdescent + c->maxascent))
1468 c->maxascent += fi->h - (c->maxdescent + c->maxascent);
1469 fi->y = -c->maxascent;
1472 fi->y = -(fi->h - c->maxdescent);
1475 if (fi->h > c->maxascent)
1477 c->maxascent = fi->h;
1492 fi->y = -fi->ascent;
1502 c->ln->y = c->y + c->o->style_pad.t;
1503 c->ln->h = c->maxascent + c->maxdescent;
1504 c->ln->baseline = c->maxascent;
1505 if (c->have_underline2)
1507 if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent;
1509 else if (c->have_underline)
1511 if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent;
1513 c->ln->line_no = c->line_no;
1515 c->y += c->maxascent + c->maxdescent;
1518 c->ln->x = c->marginl + c->o->style_pad.l +
1520 c->o->style_pad.l - c->o->style_pad.r -
1521 c->marginl - c->marginr) * c->align);
1522 if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax)
1523 c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l;
1527 c->ln->x = c->marginl + c->o->style_pad.l;
1528 if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax)
1529 c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l;
1531 _layout_line_new(c, fmt);
1534 static Evas_Object_Textblock_Item *
1535 _layout_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt, char *str)
1537 Evas_Object_Textblock_Item *it;
1539 it = calloc(1, sizeof(Evas_Object_Textblock_Item));
1542 it->text = strdup(str);
1547 _layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it)
1551 return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font, it->text,
1563 _layout_item_text_cutoff(Ctxt *c __UNUSED__, Evas_Object_Textblock_Item *it, int cut)
1569 it->text = strdup(ts);
1574 _layout_word_start(char *str, int start)
1579 chr = evas_common_font_utf8_get_next((unsigned char *)(str), &p);
1583 while (_is_white(chr) && (p >= 0))
1586 chr = evas_common_font_utf8_get_next((unsigned char *)(str), &p);
1594 chr = evas_common_font_utf8_get_prev((unsigned char *)(str), &p);
1595 if (_is_white(chr)) break;
1599 if ((p >= 0) && (_is_white(chr)))
1600 evas_common_font_utf8_get_next((unsigned char *)(str), &p);
1605 _layout_ends_with_space(char *str)
1609 p = evas_common_font_utf8_get_last((unsigned char *)(str), strlen(str));
1610 if (p < 0) return 0;
1611 chr = evas_common_font_utf8_get_next((unsigned char *)(str), &p);
1612 return _is_white(chr);
1616 _layout_strip_trailing_whitespace(Ctxt *c, Evas_Object_Textblock_Format *fmt __UNUSED__, Evas_Object_Textblock_Item *it)
1618 int p, tp, chr, adv, tw, th;
1620 p = evas_common_font_utf8_get_last((unsigned char *)(it->text), strlen(it->text));
1624 chr = evas_common_font_utf8_get_prev((unsigned char *)(it->text), &p);
1627 _layout_item_text_cutoff(c, it, tp);
1629 if (it->format->font.font)
1630 adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text);
1632 if (it->format->font.font)
1633 c->ENFN->font_string_size_get(c->ENDT, it->format->font.font, it->text, &tw, &th);
1644 _layout_item_abort(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it)
1646 if (it->text) free(it->text);
1647 _format_free(c->obj, it->format);
1651 it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last;
1652 return _layout_strip_trailing_whitespace(c, fmt, it);
1659 _layout_next_char_jump(Ctxt *c, Evas_Object_Textblock_Item *it, char *str)
1664 evas_common_font_utf8_get_next((unsigned char *)str, &index);
1668 _layout_item_text_cutoff(c, it, index);
1677 _layout_last_item_ends_in_whitespace(Ctxt *c)
1679 Evas_Object_Textblock_Item *it;
1681 if (!c->ln->items) return 1;
1682 it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last;
1683 return _layout_ends_with_space(it->text);
1687 _layout_word_end(char *str, int p)
1692 ch = evas_common_font_utf8_get_next((unsigned char *)str, &tp);
1693 while ((!_is_white(ch)) && (tp >= 0) && (ch != 0))
1696 ch = evas_common_font_utf8_get_next((unsigned char *)str, &tp);
1698 if (ch == 0) return -1;
1703 _layout_word_next(char *str, int p)
1708 ch = evas_common_font_utf8_get_next((unsigned char *)str, &tp);
1709 while ((!_is_white(ch)) && (tp >= 0) && (ch != 0))
1712 ch = evas_common_font_utf8_get_next((unsigned char *)str, &tp);
1714 if (ch == 0) return -1;
1715 while ((_is_white(ch)) && (tp >= 0) && (ch != 0))
1718 ch = evas_common_font_utf8_get_next((unsigned char *)str, &tp);
1720 if (ch == 0) return -1;
1725 _layout_walk_back_to_item_word_redo(Ctxt *c, Evas_Object_Textblock_Item *it)
1727 Evas_Object_Textblock_Item *pit, *new_it = NULL;
1728 Eina_List *remove_items = NULL, *l;
1730 int index, tw, th, inset, adv;
1732 /* it is not appended yet */
1733 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(c->ln->items)), pit)
1735 if (_layout_ends_with_space(pit->text))
1739 index = evas_common_font_utf8_get_last((unsigned char *)(pit->text), strlen(pit->text));
1740 index = _layout_word_start(pit->text, index);
1742 remove_items = eina_list_prepend(remove_items, pit);
1745 new_it = _layout_item_new(c, pit->format, pit->text + index);
1746 new_it->source_node = pit->source_node;
1747 new_it->source_pos = pit->source_pos + index;
1748 _layout_item_text_cutoff(c, pit, index);
1749 _layout_strip_trailing_whitespace(c, pit->format, pit);
1753 EINA_LIST_FOREACH(remove_items, l, data)
1754 c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(c->ln->items), data);
1758 pit = remove_items->data;
1759 _layout_line_advance(c, pit->format);
1763 _layout_line_advance(c, it->format);
1769 if (new_it->format->font.font)
1770 c->ENFN->font_string_size_get(c->ENDT, new_it->format->font.font, new_it->text, &tw, &th);
1774 if (new_it->format->font.font)
1775 inset = c->ENFN->font_inset_get(c->ENDT, new_it->format->font.font, new_it->text);
1776 new_it->inset = inset;
1779 if (new_it->format->font.font)
1780 adv = c->ENFN->font_h_advance_get(c->ENDT, new_it->format->font.font, new_it->text);
1782 c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(new_it));
1784 while (remove_items)
1786 pit = remove_items->data;
1787 remove_items = eina_list_remove_list(remove_items, remove_items);
1790 adv = c->ENFN->font_h_advance_get(c->ENDT, pit->format->font.font, pit->text);
1792 c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(pit));
1799 if (it->format->font.font)
1800 adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text);
1802 c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it));
1807 _layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node *n, const char *repch)
1809 int adv, inset, tw, th, new_line, empty_item;
1810 int wrap, twrap, ch, index, white_stripped;
1813 Evas_Object_Textblock_Item *it;
1817 if ((repch) && (eina_strbuf_length_get(n->text)))
1822 len = evas_common_font_utf8_get_len((unsigned char *) eina_strbuf_string_get(n->text));
1823 chlen = strlen(repch);
1824 str = alloca((len * chlen) + 1);
1826 for (i = 0, ptr = str; i < len; ptr += chlen, i++)
1827 memcpy(ptr, repch, chlen);
1832 str = (char *)eina_strbuf_string_get(n->text);
1841 // printf("add: wrap: %i|%i, width: %i '%s'\n", fmt->wrap_word, fmt->wrap_char, c->w, str);
1846 /* if this is the first line item and it starts with spaces - remove them */
1853 ch = evas_common_font_utf8_get_next((unsigned char *)str, &wrap);
1854 while (_is_white(ch))
1857 ch = evas_common_font_utf8_get_next((unsigned char *)str, &wrap);
1862 it = _layout_item_new(c, fmt, str);
1863 it->source_node = n;
1864 it->source_pos = str - tbase;
1867 c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &tw, &th);
1869 ((fmt->wrap_word) || (fmt->wrap_char)) &&
1871 (c->w - c->o->style_pad.l - c->o->style_pad.r -
1872 c->marginl - c->marginr)))
1874 wrap = _layout_text_cutoff_get(c, fmt, it);
1876 evas_common_font_utf8_get_next((unsigned char *)str, &wrap);
1882 ch = evas_common_font_utf8_get_next((unsigned char *)str, &index);
1884 wrap = _layout_word_start(str, wrap);
1888 ch = evas_common_font_utf8_get_prev((unsigned char *)str, &twrap);
1889 /* the text intersects the wrap point on a whitespace char */
1892 _layout_item_text_cutoff(c, it, wrap);
1894 /*we don't want to move next, that's why it's
1896 * ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap);
1900 /* intersects a word */
1903 /* walk back to start of word */
1904 twrap = _layout_word_start(str, wrap);
1908 ch = evas_common_font_utf8_get_prev((unsigned char *)str, &twrap);
1909 _layout_item_text_cutoff(c, it, twrap);
1915 if (it->text) free(it->text);
1916 _format_free(c->obj, it->format);
1920 it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last;
1921 _layout_strip_trailing_whitespace(c, fmt, it);
1922 twrap = _layout_word_end(str, wrap);
1925 ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap);
1936 /* wrap now is the index of the word START */
1938 ch = evas_common_font_utf8_get_next((unsigned char *)str, &index);
1939 if (!_is_white(ch) &&
1940 (!_layout_last_item_ends_in_whitespace(c)))
1942 _layout_walk_back_to_item_word_redo(c, it);
1945 if (c->ln->items != NULL)
1947 white_stripped = _layout_item_abort(c, fmt, it);
1955 twrap = _layout_word_end(it->text, wrap);
1959 ch = evas_common_font_utf8_get_next((unsigned char *)str, &wrap);
1960 _layout_item_text_cutoff(c, it, twrap);
1972 else if (fmt->wrap_char)
1974 _layout_item_text_cutoff(c, it, wrap);
1981 /* wrap now is the index of the word START */
1984 if (wrap < 0) wrap = 0;
1986 ch = evas_common_font_utf8_get_next((unsigned char *)str, &index);
1987 if (!_is_white(ch) &&
1988 (!_layout_last_item_ends_in_whitespace(c)))
1990 _layout_walk_back_to_item_word_redo(c, it);
1994 if (c->ln->items != NULL)
1996 white_stripped = _layout_item_abort(c, fmt, it);
2005 twrap = _layout_word_end(it->text, wrap);
2006 wrap = _layout_word_next(it->text, wrap);
2008 _layout_item_text_cutoff(c, it, twrap);
2023 c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &tw, &th);
2028 if (empty_item) empty_item = 0;
2035 inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, it->text);
2040 adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, it->text);
2042 c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it));
2048 if (!white_stripped)
2051 ch = evas_common_font_utf8_get_next((unsigned char *)str, &index);
2052 if (_is_white(ch)) str += index;
2056 _layout_line_advance(c, fmt);
2061 static Evas_Object_Textblock_Format_Item *
2062 _layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node *n, char *item)
2064 Evas_Object_Textblock_Format_Item *fi;
2066 fi = calloc(1, sizeof(Evas_Object_Textblock_Format_Item));
2067 fi->item = eina_stringshare_add(item);
2068 fi->source_node = n;
2069 c->ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->format_items),
2070 EINA_INLIST_GET(fi));
2075 _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret)
2077 Evas_Object_Textblock *o;
2079 Evas_Object_Textblock_Line *ln;
2080 Evas_Object_Textblock_Node *n;
2081 Eina_List *removes = NULL;
2082 Evas_Object_Textblock_Format *fmt = NULL;
2083 int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0;
2086 o = (Evas_Object_Textblock *)(obj->object_data);
2088 c->obj = (Evas_Object *)obj;
2090 c->lines = c->ln = NULL;
2091 c->format_stack = NULL;
2095 c->wmax = c->hmax = 0;
2096 c->maxascent = c->maxdescent = 0;
2097 c->marginl = c->marginr = 0;
2098 c->have_underline = 0;
2099 c->have_underline2 = 0;
2100 c->underline_extend = 0;
2104 _format_command_init();
2105 /* setup default base style */
2106 if ((c->o->style) && (c->o->style->default_tag))
2108 fmt = _layout_format_push(c, NULL);
2109 _format_fill(c->obj, fmt, c->o->style->default_tag);
2113 _format_command_shutdown();
2114 if (w_ret) *w_ret = 0;
2115 if (h_ret) *h_ret = 0;
2118 /* run through all text and format nodes generating lines */
2123 _layout_line_new(c, fmt);
2124 _layout_text_append(c, fmt, NULL, NULL);
2125 _layout_line_advance(c, fmt);
2126 // printf("bl:%i | %ix%i\n", c->ln->baseline, c->ln->w, c->ln->h);
2131 c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, "", &tw, &th);
2138 _layout_format_ascent_descent_adjust(c, fmt);
2143 EINA_INLIST_FOREACH(c->o->nodes, n)
2145 if (!c->ln) _layout_line_new(c, fmt);
2146 if ((n->type == NODE_FORMAT) && eina_strbuf_length_get(n->text))
2152 s = (char *)eina_strbuf_string_get(n->text);
2153 if (!strncmp(s, "+ item ", 7))
2156 // item size=20x10 href=name
2157 // item relsize=20x10 href=name
2158 // item abssize=20x10 href=name
2160 // optional arguments:
2164 // size == item size (modifies line size) - can be multiplied by
2166 // relsize == relative size (height is current font height, width
2167 // modified accordingly keeping aspect)
2168 // abssize == absolute size (modifies line size) - never mulitplied by
2170 // href == name of item - to be found and matched later and used for
2172 Evas_Object_Textblock_Format_Item *fi;
2173 int x2, w = 1, h = 1;
2174 int vsize = 0, size = 0;
2178 //href = strstr(s, " href=");
2179 p = strstr(s, " vsize=");
2183 if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL;
2184 else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT;
2186 p = strstr(s, " size=");
2190 if (sscanf(p, "%ix%i", &w, &h) == 2)
2192 w = w * obj->cur.scale;
2193 h = h * obj->cur.scale;
2199 p = strstr(s, " absize=");
2203 if (sscanf(p, "%ix%i", &w, &h) == 2)
2210 p = strstr(s, " relsize=");
2214 if (sscanf(p, "%ix%i", &w, &h) == 2)
2218 if (vsize == VSIZE_FULL)
2220 sz = c->maxdescent + c->maxascent;
2222 else if (vsize == VSIZE_ASCENT)
2236 (c->w - c->o->style_pad.l -
2238 c->marginl - c->marginr))
2240 _layout_line_advance(c, fmt);
2243 fi = _layout_format_item_add(c, n, item);
2250 fi->ascent = c->maxascent;
2251 fi->descent = c->maxdescent;
2259 fmt = _layout_format_push(c, fmt);
2262 else if (s[0] == '-')
2264 fmt = _layout_format_pop(c, fmt);
2267 while ((item = _format_parse(&s)))
2269 char tmp_delim = *s;
2271 if (_format_is_param(item))
2273 _layout_format_value_handle(c, fmt, item);
2277 if ((!strcmp(item, "\n")) || (!strcmp(item, "\\n")))
2279 Evas_Object_Textblock_Format_Item *fi;
2281 fi = _layout_format_item_add(c, n, item);
2284 _layout_line_advance(c, fmt);
2286 else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t")))
2288 Evas_Object_Textblock_Format_Item *fi;
2291 x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops));
2293 (c->w - c->o->style_pad.l -
2295 c->marginl - c->marginr))
2297 _layout_line_advance(c, fmt);
2298 x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops));
2302 Evas_Object_Textblock_Item *it;
2304 it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last;
2305 _layout_strip_trailing_whitespace(c, fmt, it);
2307 fi = _layout_format_item_add(c, n, item);
2317 evas_text_style_pad_get(fmt->style, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b);
2319 if (fmt->underline2)
2320 c->have_underline2 = 1;
2321 else if (fmt->underline)
2322 c->have_underline = 1;
2324 else if ((n->type == NODE_TEXT) && eina_strbuf_length_get(n->text))
2326 _layout_text_append(c, fmt, n, o->repch);
2327 if ((c->have_underline2) || (c->have_underline))
2329 if (style_pad_b < c->underline_extend)
2330 style_pad_b = c->underline_extend;
2331 c->have_underline = 0;
2332 c->have_underline2 = 0;
2333 c->underline_extend = 0;
2337 if ((c->ln) && (c->ln->items) && (fmt))
2338 _layout_line_advance(c, fmt);
2339 while (c->format_stack)
2341 fmt = c->format_stack->data;
2342 c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack);
2343 _format_free(c->obj, fmt);
2345 EINA_INLIST_FOREACH(c->lines, ln)
2347 if (ln->line_no == -1)
2349 removes = eina_list_append(removes, ln);
2353 if ((ln->y + ln->h) > c->hmax) c->hmax = ln->y + ln->h;
2359 c->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(c->lines), EINA_INLIST_GET(ln));
2360 removes = eina_list_remove_list(removes, removes);
2361 _line_free(obj, ln);
2364 if (w_ret) *w_ret = c->wmax;
2365 if (h_ret) *h_ret = c->hmax;
2366 if ((o->style_pad.l != style_pad_l) || (o->style_pad.r != style_pad_r) ||
2367 (o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b))
2369 Evas_Object_Textblock_Line *lines;
2373 o->style_pad.l = style_pad_l;
2374 o->style_pad.r = style_pad_r;
2375 o->style_pad.t = style_pad_t;
2376 o->style_pad.b = style_pad_b;
2377 _layout(obj, calc_only, w, h, w_ret, h_ret);
2378 _lines_clear(obj, lines);
2379 _format_command_shutdown();
2384 o->lines = c->lines;
2385 _format_command_shutdown();
2388 if (c->lines) _lines_clear(obj, c->lines);
2389 _format_command_shutdown();
2393 _relayout(const Evas_Object *obj)
2395 Evas_Object_Textblock *o;
2396 Evas_Object_Textblock_Line *lines;
2398 o = (Evas_Object_Textblock *)(obj->object_data);
2401 o->formatted.valid = 0;
2402 o->native.valid = 0;
2405 obj->cur.geometry.w, obj->cur.geometry.h,
2406 &o->formatted.w, &o->formatted.h);
2407 o->formatted.valid = 1;
2408 if (lines) _lines_clear(obj, lines);
2409 o->last_w = obj->cur.geometry.w;
2415 _find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node *n, int pos, int eol, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
2417 Evas_Object_Textblock_Line *ln;
2418 /* Evas_Object_Textblock_Node *nn; */
2419 Evas_Object_Textblock *o;
2421 o = (Evas_Object_Textblock *)(obj->object_data);
2422 /* EINA_INLIST_FOREACH(o->nodes, nn) */
2424 if ((eol) && (n->type == NODE_TEXT))
2428 evas_common_font_utf8_get_prev((unsigned char *) eina_strbuf_string_get(n->text), &pos2);
2429 if (pos2 < pos) pos = pos2;
2431 EINA_INLIST_FOREACH(o->lines, ln)
2433 Evas_Object_Textblock_Format_Item *fit;
2434 Evas_Object_Textblock_Item *it;
2435 Evas_Object_Textblock_Line *lnn;
2437 lnn = (Evas_Object_Textblock_Line *)(((Eina_Inlist *)ln)->next);
2438 EINA_INLIST_FOREACH(ln->items, it)
2440 if (it->source_node == n)
2442 Evas_Object_Textblock_Item *itn;
2445 itn = (Evas_Object_Textblock_Item *)(((Eina_Inlist *)it)->next);
2446 p = (int)(it->source_pos + strlen(it->text));
2448 ((p == pos) && (!lnn) &&
2450 ((itn) && (itn->source_node != n)))))
2458 EINA_INLIST_FOREACH(ln->format_items, fit)
2460 if (fit->source_node == n)
2463 /* FIXME: Is that really what we want ? */
2464 *itr = (Evas_Object_Textblock_Item *)fit;
2472 _find_layout_format_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node *n, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Format_Item **fir)
2474 Evas_Object_Textblock_Line *ln;
2475 Evas_Object_Textblock *o;
2477 o = (Evas_Object_Textblock *)(obj->object_data);
2478 EINA_INLIST_FOREACH(o->lines, ln)
2480 Evas_Object_Textblock_Format_Item *fi;
2482 EINA_INLIST_FOREACH(ln->format_items, fi)
2484 if (fi->source_node == n)
2494 static Evas_Object_Textblock_Line *
2495 _find_layout_line_num(const Evas_Object *obj, int line)
2497 Evas_Object_Textblock_Line *ln;
2498 Evas_Object_Textblock *o;
2500 o = (Evas_Object_Textblock *)(obj->object_data);
2501 EINA_INLIST_FOREACH(o->lines, ln)
2503 if (ln->line_no == line) return ln;
2509 * Adds a textblock to the given evas.
2510 * @param e The given evas.
2511 * @return The new textblock object.
2514 evas_object_textblock_add(Evas *e)
2518 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2521 obj = evas_object_new(e);
2522 evas_object_textblock_init(obj);
2523 evas_object_inject(obj, e);
2528 * Creates a new textblock style.
2529 * @return The new textblock style.
2531 EAPI Evas_Textblock_Style *
2532 evas_textblock_style_new(void)
2534 Evas_Textblock_Style *ts;
2536 ts = calloc(1, sizeof(Evas_Textblock_Style));
2541 * Destroys a textblock style.
2542 * @param ts The textblock style to free.
2545 evas_textblock_style_free(Evas_Textblock_Style *ts)
2559 * @param ts to be documented.
2560 * @param text to be documented.
2561 * @return Returns no value.
2564 evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text)
2571 EINA_LIST_FOREACH(ts->objects, l, obj)
2573 Evas_Object_Textblock *o;
2575 o = (Evas_Object_Textblock *)(obj->object_data);
2578 free(o->markup_text);
2579 o->markup_text = NULL;
2580 evas_object_textblock_text_markup_get(obj);
2585 if (text) ts->style_text = strdup(text);
2589 // format MUST be KEY='VALUE'[KEY='VALUE']...
2591 char *key_start, *key_stop, *val_start, *val_stop;
2593 key_start = key_stop = val_start = val_stop = NULL;
2604 if ((*p == '=') || (isspace(*p)))
2607 else if (!val_start)
2609 if (((*p) == '\'') && (*(p + 1)))
2614 if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\'))
2617 if ((key_start) && (key_stop) && (val_start) && (val_stop))
2619 char *tags, *replaces;
2620 Evas_Object_Style_Tag *tag;
2621 size_t tag_len = key_stop - key_start;
2622 size_t replace_len = val_stop - val_start;
2624 tags = malloc(tag_len + 1);
2627 memcpy(tags, key_start, tag_len);
2631 replaces = malloc(replace_len + 1);
2634 memcpy(replaces, val_start, replace_len);
2635 replaces[replace_len] = 0;
2637 if ((tags) && (replaces))
2639 if (!strcmp(tags, "DEFAULT"))
2641 ts->default_tag = replaces;
2646 tag = calloc(1, sizeof(Evas_Object_Style_Tag));
2650 tag->replace = replaces;
2651 tag->tag_len = tag_len;
2652 tag->replace_len = replace_len;
2653 ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
2664 if (tags) free(tags);
2665 if (replaces) free(replaces);
2667 key_start = key_stop = val_start = val_stop = NULL;
2673 EINA_LIST_FOREACH(ts->objects, l, obj)
2675 Evas_Object_Textblock *o;
2677 o = (Evas_Object_Textblock *)(obj->object_data);
2682 m = strdup(o->markup_text);
2685 evas_object_textblock_text_markup_set(obj, m);
2694 * @param ts to be documented.
2695 * @return to be documented.
2698 evas_textblock_style_get(const Evas_Textblock_Style *ts)
2700 if (!ts) return NULL;
2701 return ts->style_text;
2704 /* textblock styles */
2707 * @param obj to be documented.
2708 * @param ts to be documented.
2709 * @return Returns no value.
2712 evas_object_textblock_style_set(Evas_Object *obj, Evas_Textblock_Style *ts)
2715 if (ts == o->style) return;
2716 if ((ts) && (ts->delete_me)) return;
2721 free(o->markup_text);
2722 o->markup_text = NULL;
2723 evas_object_textblock_text_markup_get(obj);
2728 Evas_Textblock_Style *old_ts;
2731 old_ts->objects = eina_list_remove(old_ts->objects, obj);
2732 if ((old_ts->delete_me) && (!old_ts->objects))
2733 evas_textblock_style_free(old_ts);
2737 ts->objects = eina_list_append(ts->objects, obj);
2745 o->formatted.valid = 0;
2746 o->native.valid = 0;
2750 free(o->markup_text);
2751 o->markup_text = NULL;
2753 evas_object_change(obj);
2758 * @param obj to be documented.
2759 * @return to be documented.
2761 EAPI const Evas_Textblock_Style *
2762 evas_object_textblock_style_get(const Evas_Object *obj)
2764 TB_HEAD_RETURN(NULL);
2769 * @brief Set the "replacement character" to use for the given textblock object.
2771 * @param obj The given textblock object.
2772 * @param ch The charset name.
2775 evas_object_textblock_replace_char_set(Evas_Object *obj, const char *ch)
2778 if (o->repch) eina_stringshare_del(o->repch);
2779 if (ch) o->repch = eina_stringshare_add(ch);
2780 else o->repch = NULL;
2781 o->formatted.valid = 0;
2782 o->native.valid = 0;
2786 free(o->markup_text);
2787 o->markup_text = NULL;
2789 evas_object_change(obj);
2793 * @brief Get the "replacement character" for given textblock object. Returns
2794 * NULL if no replacement character is in use.
2796 * @param obj The given textblock object
2797 * @return replacement character or NULL
2800 evas_object_textblock_replace_char_get(Evas_Object *obj)
2802 TB_HEAD_RETURN(NULL);
2808 _advance_after_end_of_string(const char **p_buf)
2810 while (**p_buf != 0) (*p_buf)++;
2815 _is_eq_and_advance(const char *s, const char *s_end,
2816 const char **p_m, const char *m_end)
2818 for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++)
2822 _advance_after_end_of_string(p_m);
2828 _advance_after_end_of_string(p_m);
2833 static inline const char *
2834 _escaped_char_match(const char *s, int *adv)
2836 const char *map_itr, *map_end, *mc, *sc;
2838 map_itr = escape_strings;
2839 map_end = map_itr + sizeof(escape_strings);
2841 while (map_itr < map_end)
2847 _advance_after_end_of_string(&map_itr);
2848 if (map_itr >= map_end) break;
2853 while ((*mc) && (*sc))
2855 if ((unsigned char)*sc < (unsigned char)*mc) return NULL;
2856 if (*sc != *mc) match = 0;
2862 *adv = mc - map_itr;
2865 _advance_after_end_of_string(&map_itr);
2870 static inline const char *
2871 _escaped_char_get(const char *s, const char *s_end)
2873 const char *map_itr, *map_end;
2875 map_itr = escape_strings;
2876 map_end = map_itr + sizeof(escape_strings);
2878 while (map_itr < map_end)
2880 if (_is_eq_and_advance(s, s_end, &map_itr, map_end))
2882 if (map_itr < map_end)
2883 _advance_after_end_of_string(&map_itr);
2890 * @param escape to be documented.
2891 * @return to be documented.
2894 evas_textblock_escape_string_get(const char *escape)
2897 return _escaped_char_get(escape, escape + strlen(escape));
2902 * @param escape_start to be documented.
2903 * @param escape_end to be documented.
2904 * @return to be documented.
2907 evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end)
2909 return _escaped_char_get(escape_start, escape_end);
2914 * @param string to be documented.
2915 * @param len_ret to be documented.
2916 * @return to be documented.
2919 evas_textblock_string_escape_get(const char *string, int *len_ret)
2922 return _escaped_char_match(string, len_ret);
2926 _append_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
2931 escape = _escaped_char_get(s, s_end);
2933 evas_textblock_cursor_text_append(cur, escape);
2937 _prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
2942 escape = _escaped_char_get(s, s_end);
2944 evas_textblock_cursor_text_prepend(cur, escape);
2949 * @param obj to be documented.
2950 * @param text to be documented.
2951 * @return Return no value.
2954 evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text)
2957 if ((text != o->markup_text) && (o->markup_text))
2959 free(o->markup_text);
2960 o->markup_text = NULL;
2963 o->formatted.valid = 0;
2964 o->native.valid = 0;
2966 evas_object_change(obj);
2969 if (text != o->markup_text)
2971 if (text) o->markup_text = strdup(text);
2975 evas_textblock_cursor_node_first(o->cursor);
2979 char *tag_start, *tag_end, *esc_start, *esc_end;
2981 tag_start = tag_end = esc_start = esc_end = NULL;
2987 (tag_end) || (esc_end) ||
2988 (tag_start) || (esc_start))
2993 size_t ttag_len = tag_end - tag_start -1;
2995 ttag = malloc(ttag_len + 1);
3001 memcpy(ttag, tag_start + 1, ttag_len);
3003 match = _style_match_tag(o->style, ttag, ttag_len, &replace_len);
3005 evas_textblock_cursor_format_append(o->cursor, match);
3010 ttag2 = malloc(ttag_len + 2 + 1);
3015 strcpy(ttag2, "- ");
3016 strcat(ttag2, ttag + 1);
3020 strcpy(ttag2, "+ ");
3021 strcat(ttag2, ttag);
3023 evas_textblock_cursor_format_append(o->cursor, ttag2);
3029 tag_start = tag_end = NULL;
3033 _append_escaped_char(o->cursor, esc_start, esc_end);
3034 esc_start = esc_end = NULL;
3038 _append_text_run(o, s, p);
3050 _append_text_run(o, s, p);
3068 _append_text_run(o, s, p);
3085 Evas_Textblock_Cursor *data;
3087 evas_textblock_cursor_node_first(o->cursor);
3088 EINA_LIST_FOREACH(o->cursors, l, data)
3089 evas_textblock_cursor_node_first(data);
3095 * @param cur to be documented.
3096 * @param text to be documented.
3097 * @return Return no value.
3100 evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text)
3102 Evas_Object_Textblock *o;
3105 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3108 free(o->markup_text);
3109 o->markup_text = NULL;
3111 o->formatted.valid = 0;
3112 o->native.valid = 0;
3114 evas_object_change(cur->obj);
3115 if (!o->style) return;
3119 char *tag_start, *tag_end, *esc_start, *esc_end;
3121 tag_start = tag_end = esc_start = esc_end = NULL;
3127 (tag_end) || (esc_end) ||
3128 (tag_start) || (esc_start))
3133 size_t ttag_len = tag_end - tag_start - 1;
3135 ttag = malloc(ttag_len + 1);
3141 strncpy(ttag, tag_start + 1, ttag_len);
3143 match = _style_match_tag(o->style, ttag, ttag_len, &replace_len);
3145 evas_textblock_cursor_format_prepend(cur, match);
3150 ttag2 = malloc(ttag_len + 2 + 1);
3155 strcpy(ttag2, "- ");
3156 strcat(ttag2, ttag + 1);
3160 strcpy(ttag2, "+ ");
3161 strcat(ttag2, ttag);
3163 evas_textblock_cursor_format_prepend(o->cursor, ttag2);
3169 tag_start = tag_end = NULL;
3173 _prepend_escaped_char(cur, esc_start, esc_end);
3174 esc_start = esc_end = NULL;
3178 _prepend_text_run(o, s, p);
3190 _prepend_text_run(o, s, p);
3208 _prepend_text_run(o, s, p);
3227 * @param obj to be documented.
3228 * @return to be documented.
3231 evas_object_textblock_text_markup_get(const Evas_Object *obj)
3233 Evas_Object_Textblock_Node *n;
3234 Eina_Strbuf *txt = NULL;
3236 TB_HEAD_RETURN(NULL);
3237 if (o->markup_text) return(o->markup_text);
3238 txt = eina_strbuf_new();
3239 EINA_INLIST_FOREACH(o->nodes, n)
3241 size_t replace_len = eina_strbuf_length_get(n->text);
3242 if ((n->type == NODE_FORMAT) && replace_len)
3245 const char *tag = _style_match_replace(o->style, eina_strbuf_string_get(n->text), replace_len, &tag_len);
3246 eina_strbuf_append_char(txt, '<');
3249 // FIXME: need to escape
3250 eina_strbuf_append_length(txt, tag, tag_len);
3258 // FIXME: need to escape
3259 s = eina_strbuf_string_get(n->text);
3260 if (*s == '+') push = 1;
3261 if (*s == '-') pop = 1;
3262 while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
3263 if (pop) eina_strbuf_append_char(txt, '/');
3264 if (push) eina_strbuf_append(txt, "+ ");
3265 eina_strbuf_append(txt, s);
3267 eina_strbuf_append_char(txt, '>');
3269 else if ((n->type == NODE_TEXT) && eina_strbuf_length_get(n->text))
3271 const char *p = eina_strbuf_string_get(n->text);
3278 escape = _escaped_char_match(p, &adv);
3282 eina_strbuf_append(txt, escape);
3286 eina_strbuf_append_char(txt, *p);
3292 o->markup_text = eina_strbuf_string_steal(txt);
3293 eina_strbuf_free(txt);
3294 return o->markup_text;
3300 * @param obj to be documented.
3301 * @return to be documented.
3303 EAPI const Evas_Textblock_Cursor *
3304 evas_object_textblock_cursor_get(const Evas_Object *obj)
3306 TB_HEAD_RETURN(NULL);
3312 * @param obj to be documented.
3313 * @return to be documented.
3315 EAPI Evas_Textblock_Cursor *
3316 evas_object_textblock_cursor_new(Evas_Object *obj)
3318 Evas_Textblock_Cursor *cur;
3320 TB_HEAD_RETURN(NULL);
3321 cur = calloc(1, sizeof(Evas_Textblock_Cursor));
3323 cur->node = o->nodes;
3326 o->cursors = eina_list_append(o->cursors, cur);
3332 * @param cur to be documented.
3333 * @return Returns no value.
3336 evas_textblock_cursor_free(Evas_Textblock_Cursor *cur)
3338 Evas_Object_Textblock *o;
3341 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3342 if (cur == o->cursor) return;
3343 o->cursors = eina_list_remove(o->cursors, cur);
3349 * @param cur to be documented.
3350 * @return Returns no value.
3353 evas_textblock_cursor_node_first(Evas_Textblock_Cursor *cur)
3355 Evas_Object_Textblock *o;
3358 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3359 cur->node = o->nodes;
3366 * @param cur to be documented.
3367 * @return Returns no value.
3370 evas_textblock_cursor_node_last(Evas_Textblock_Cursor *cur)
3372 Evas_Object_Textblock *o;
3375 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3378 cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(o->nodes))->last);
3381 evas_textblock_cursor_char_last(cur);
3393 * @param cur to be documented.
3394 * @return to be documented.
3397 evas_textblock_cursor_node_next(Evas_Textblock_Cursor *cur)
3399 if (!cur) return EINA_FALSE;
3400 if (!cur->node) return EINA_FALSE;
3401 if ((EINA_INLIST_GET(cur->node))->next)
3403 cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(cur->node))->next);
3413 * @param cur to be documented.
3414 * @return to be documented.
3417 evas_textblock_cursor_node_prev(Evas_Textblock_Cursor *cur)
3419 if (!cur) return EINA_FALSE;
3420 if (!cur->node) return EINA_FALSE;
3421 if ((EINA_INLIST_GET(cur->node))->prev)
3423 cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(cur->node))->prev);
3424 evas_textblock_cursor_char_last(cur);
3432 * @param cur to be documented.
3433 * @return to be documented.
3436 evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
3440 if (!cur) return EINA_FALSE;
3441 if (!cur->node) return EINA_FALSE;
3442 if (cur->node->type == NODE_FORMAT) return EINA_FALSE;
3443 if (!eina_strbuf_length_get(cur->node->text)) return EINA_FALSE;
3446 if (cur->node->type == NODE_TEXT)
3448 Evas_Object_Textblock_Line *ln = NULL;
3449 Evas_Object_Textblock_Item *it = NULL;
3452 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
3455 pos = cur->pos - it->source_pos;
3456 if (pos <= 0) index -= pos;
3459 printf("TB: 'it' not found\n");
3462 ch = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(cur->node->text), &index);
3463 if ((ch == 0) || (index < 0)) return EINA_FALSE;
3464 if (eina_strbuf_string_get(cur->node->text)[index] == 0) return EINA_FALSE;
3472 * @param cur to be documented.
3473 * @return to be documented.
3476 evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
3479 int at_end_of_line = 0;
3480 int at_start_of_line = 0;
3482 if (!cur) return EINA_FALSE;
3483 if (!cur->node) return EINA_FALSE;
3484 if (cur->node->type == NODE_FORMAT) return EINA_FALSE;
3485 if (!eina_strbuf_length_get(cur->node->text)) return EINA_FALSE;
3487 if (index == 0) return EINA_FALSE;
3489 // XXX: FIXME: determine at_end_of_line and at_start_of_line
3491 if (cur->node->type == NODE_TEXT)
3493 Evas_Object_Textblock_Line *ln = NULL;
3494 Evas_Object_Textblock_Item *it = NULL;
3497 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
3500 pos = cur->pos - it->source_pos;
3501 if (pos <= 0) at_start_of_line = 1;
3506 plast = evas_common_font_utf8_get_last((unsigned char *) it->text, strlen(it->text));
3507 if ((index - it->source_pos) == plast) at_end_of_line = 1;
3512 if ((cur->eol) && (at_end_of_line))
3517 evas_common_font_utf8_get_prev((unsigned char *)eina_strbuf_string_get(cur->node->text), &index);
3518 if (/*(ch == 0) || */(index < 0)) return EINA_FALSE;
3520 if (at_start_of_line)
3529 * @param cur to be documented.
3530 * @return Returns no value.
3533 evas_textblock_cursor_char_first(Evas_Textblock_Cursor *cur)
3542 * @param cur to be documented.
3543 * @return Returns no value.
3546 evas_textblock_cursor_char_last(Evas_Textblock_Cursor *cur)
3551 if (!cur->node) return;
3552 if (cur->node->type == NODE_FORMAT)
3557 index = evas_common_font_utf8_get_last((unsigned char *)eina_strbuf_string_get(cur->node->text), eina_strbuf_length_get(cur->node->text));
3558 if (index < 0) cur->pos = 0;
3565 * @param cur to be documented.
3566 * @return Returns no value.
3569 evas_textblock_cursor_line_first(Evas_Textblock_Cursor *cur)
3571 Evas_Object_Textblock *o;
3572 Evas_Object_Textblock_Line *ln = NULL;
3573 Evas_Object_Textblock_Item *it = NULL;
3574 Evas_Object_Textblock_Format_Item *fi = NULL;
3577 if (!cur->node) return;
3578 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3579 if (!o->formatted.valid) _relayout(cur->obj);
3580 if (cur->node->type == NODE_FORMAT)
3581 _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi);
3583 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
3586 it = (Evas_Object_Textblock_Item *)ln->items;
3587 fi = (Evas_Object_Textblock_Format_Item *)ln->format_items;
3590 if (it->x < fi->x) fi = NULL;
3595 cur->pos = it->source_pos;
3596 cur->node = it->source_node;
3601 cur->node = fi->source_node;
3607 * @param cur to be documented.
3608 * @return Returns no value.
3611 evas_textblock_cursor_line_last(Evas_Textblock_Cursor *cur)
3613 Evas_Object_Textblock *o;
3614 Evas_Object_Textblock_Line *ln = NULL;
3615 Evas_Object_Textblock_Item *it = NULL;
3616 Evas_Object_Textblock_Format_Item *fi = NULL;
3619 if (!cur->node) return;
3620 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3621 if (!o->formatted.valid) _relayout(cur->obj);
3622 // kills "click below text" and up/downm arrow. disable
3624 if (cur->node->type == NODE_FORMAT)
3625 _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi);
3627 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
3630 it = (Evas_Object_Textblock_Item *)((EINA_INLIST_GET(ln->items))->last);
3633 if (ln->format_items)
3634 fi = (Evas_Object_Textblock_Format_Item *)((EINA_INLIST_GET(ln->format_items))->last);
3639 if ((it->x + it->w) > (fi->x + fi->w)) fi = NULL;
3646 cur->pos = it->source_pos;
3647 cur->node = it->source_node;
3648 index = evas_common_font_utf8_get_last((unsigned char *)it->text, strlen(it->text));
3649 if ((index >= 0) && (it->text[0] != 0))
3650 evas_common_font_utf8_get_next((unsigned char *)(it->text), &index);
3651 if (index >= 0) cur->pos += index;
3657 cur->node = fi->source_node;
3663 * @param cur to be documented.
3664 * @return to be documented.
3667 evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur)
3669 if (!cur) return -1;
3675 * @param cur to be documented.
3676 * @param pos to be documented.
3679 evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int pos)
3684 if (!cur->node) return;
3685 if (cur->node->type == NODE_FORMAT) pos = 0;
3686 len = eina_strbuf_length_get(cur->node->text);
3687 if (pos < 0) pos = 0;
3688 else if (pos > len) pos = len;
3695 * @param cur to be documented.
3696 * @param line to be documented.
3697 * @return to be documented.
3700 evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line)
3702 Evas_Object_Textblock *o;
3703 Evas_Object_Textblock_Line *ln;
3704 Evas_Object_Textblock_Item *it;
3705 Evas_Object_Textblock_Format_Item *fi;
3707 if (!cur) return EINA_FALSE;
3708 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3709 if (!o->formatted.valid) _relayout(cur->obj);
3711 ln = _find_layout_line_num(cur->obj, line);
3712 if (!ln) return EINA_FALSE;
3713 it = (Evas_Object_Textblock_Item *)ln->items;
3714 fi = (Evas_Object_Textblock_Format_Item *)ln->format_items;
3717 if (it->x < fi->x) fi = NULL;
3722 cur->pos = it->source_pos;
3724 cur->node = it->source_node;
3730 cur->node = fi->source_node;
3736 cur->node = o->nodes;
3743 * @param cur1 to be documented.
3744 * @param cur2 to be documented.
3745 * @return to be documented.
3748 evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
3750 Eina_Inlist *l1, *l2;
3752 if (!cur1) return 0;
3753 if (!cur2) return 0;
3754 if (cur1->obj != cur2->obj) return 0;
3755 if ((!cur1->node) || (!cur2->node)) return 0;
3756 if (cur1->node == cur2->node)
3758 if (cur1->pos < cur2->pos) return -1; /* cur1 < cur2 */
3759 else if (cur1->pos > cur2->pos) return 1; /* cur2 < cur1 */
3760 if ((cur1->eol) == (cur1->eol)) return 0; /* cur1 == cur2 */
3761 if (cur1->eol) return 1; /* cur2 < cur1 */
3762 return -1; /* cur1 < cur2 */
3764 for (l1 = EINA_INLIST_GET(cur1->node),
3765 l2 = EINA_INLIST_GET(cur1->node); (l1) || (l2);)
3767 if (l1 == EINA_INLIST_GET(cur2->node)) return 1; /* cur2 < cur 1 */
3768 else if (l2 == EINA_INLIST_GET(cur2->node)) return -1; /* cur1 < cur 2 */
3769 else if (!l1) return -1; /* cur1 < cur 2 */
3770 else if (!l2) return 1; /* cur2 < cur 1 */
3771 if (l1) l1 = l1->prev;
3772 if (l2) l2 = l2->next;
3779 * @param cur to be documented.
3780 * @param cur_dest to be documented.
3781 * @return Returns no value.
3784 evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest)
3787 if (!cur_dest) return;
3788 if (cur->obj != cur_dest->obj) return;
3789 cur_dest->pos = cur->pos;
3790 cur_dest->node = cur->node;
3791 cur_dest->eol = cur->eol;
3798 * @param cur to be documented.
3799 * @param text to be documented.
3800 * @return Returns no value.
3803 evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text)
3805 Evas_Object_Textblock *o;
3806 Evas_Object_Textblock_Node *n, *nrel;
3810 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3814 Evas_Textblock_Cursor *data;
3816 if (cur != o->cursor)
3818 if (cur->node == o->cursor->node)
3820 if (o->cursor->pos > cur->pos)
3822 o->cursor->pos += strlen(text);
3826 EINA_LIST_FOREACH(o->cursors, l, data)
3830 if (cur->node == data->node)
3832 if (data->pos > cur->pos)
3834 data->pos += strlen(text);
3841 if ((!n) || (n->type == NODE_FORMAT))
3844 n = calloc(1, sizeof(Evas_Object_Textblock_Node));
3845 n->type = NODE_TEXT;
3846 n->text = eina_strbuf_new();
3848 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
3850 EINA_INLIST_GET(nrel));
3852 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
3856 if (eina_strbuf_length_get(n->text))
3858 ch = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(n->text), &index);
3864 if (cur->pos >= (eina_strbuf_length_get(n->text) - 1))
3865 eina_strbuf_append(n->text, (char *)text);
3867 eina_strbuf_insert(n->text, (char *)text, cur->pos);
3868 // XXX: This makes no sense?
3871 cur->pos += strlen(text);
3873 o->formatted.valid = 0;
3874 o->native.valid = 0;
3878 free(o->markup_text);
3879 o->markup_text = NULL;
3881 _nodes_adjacent_merge(cur->obj, n);
3882 evas_object_change(cur->obj);
3887 * @param cur to be documented.
3888 * @param text to be documented.
3889 * @return Returns no value.
3892 evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *text)
3894 Evas_Object_Textblock *o;
3895 Evas_Object_Textblock_Node *n, *nrel;
3898 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3901 Evas_Textblock_Cursor *data;
3903 if (cur != o->cursor)
3905 if (cur->node == o->cursor->node)
3907 if ((o->cursor->node) &&
3908 (o->cursor->node->type == NODE_TEXT) &&
3909 (o->cursor->pos >= cur->pos))
3911 o->cursor->pos += strlen(text);
3915 EINA_LIST_FOREACH(o->cursors, l, data)
3919 if (cur->node == data->node)
3922 (data->node->type == NODE_TEXT) &&
3923 (data->pos >= cur->pos))
3925 data->pos += strlen(text);
3932 if ((!n) || (n->type == NODE_FORMAT))
3935 n = calloc(1, sizeof(Evas_Object_Textblock_Node));
3936 n->type = NODE_TEXT;
3937 n->text = eina_strbuf_new();
3939 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes),
3941 EINA_INLIST_GET(nrel));
3943 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
3945 if (!n->text) n->text = eina_strbuf_new();
3950 if (cur->pos > (eina_strbuf_length_get(n->text) - 1))
3952 eina_strbuf_append(n->text, (char *)text);
3956 eina_strbuf_insert(n->text, (char *)text, cur->pos);
3958 cur->pos += strlen(text);
3960 o->formatted.valid = 0;
3961 o->native.valid = 0;
3965 free(o->markup_text);
3966 o->markup_text = NULL;
3968 _nodes_adjacent_merge(cur->obj, n);
3969 evas_object_change(cur->obj);
3974 * @param cur to be documented.
3975 * @param format to be documented.
3976 * @return Returns no value.
3979 evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
3981 Evas_Object_Textblock *o;
3982 Evas_Object_Textblock_Node *n, *nc, *n2;
3985 if ((!format) || (format[0] == 0)) return;
3986 o = (Evas_Object_Textblock *)(cur->obj->object_data);
3988 n = calloc(1, sizeof(Evas_Object_Textblock_Node));
3989 n->type = NODE_FORMAT;
3990 n->text = eina_strbuf_new();
3991 eina_strbuf_append(n->text, format);
3994 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
3996 else if (nc->type == NODE_FORMAT)
3998 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
4000 EINA_INLIST_GET(nc));
4002 else if (nc->type == NODE_TEXT)
4007 if (eina_strbuf_length_get(nc->text))
4009 ch = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(nc->text), &index);
4013 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
4015 EINA_INLIST_GET(nc));
4016 if ((ch != 0) && (cur->pos < eina_strbuf_length_get(nc->text)))
4018 n2 = calloc(1, sizeof(Evas_Object_Textblock_Node));
4019 n2->type = NODE_TEXT;
4020 n2->text = eina_strbuf_new();
4021 eina_strbuf_append(n2->text, (eina_strbuf_string_get(nc->text) + cur->pos));
4022 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
4023 EINA_INLIST_GET(n2),
4024 EINA_INLIST_GET(n));
4026 eina_strbuf_remove(nc->text, cur->pos, eina_strbuf_length_get(nc->text));
4030 // XXX: This makes no sense
4032 o->formatted.valid = 0;
4033 o->native.valid = 0;
4037 free(o->markup_text);
4038 o->markup_text = NULL;
4040 evas_object_change(cur->obj);
4045 * @param cur to be documented.
4046 * @param format to be documented.
4047 * @return Returns no value.
4050 evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format)
4052 Evas_Object_Textblock *o;
4053 Evas_Object_Textblock_Node *n, *nc, *n2;
4056 if ((!format) || (format[0] == 0)) return;
4057 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4059 n = calloc(1, sizeof(Evas_Object_Textblock_Node));
4060 n->type = NODE_FORMAT;
4061 n->text = eina_strbuf_new();
4062 eina_strbuf_append(n->text, format);
4065 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
4069 else if (nc->type == NODE_FORMAT)
4071 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes),
4073 EINA_INLIST_GET(nc));
4077 else if (nc->type == NODE_TEXT)
4081 len = eina_strbuf_length_get(nc->text);
4083 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes),
4085 EINA_INLIST_GET(nc));
4087 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
4089 EINA_INLIST_GET(nc));
4090 if ((cur->pos < len) && (cur->pos != 0))
4092 n2 = calloc(1, sizeof(Evas_Object_Textblock_Node));
4093 n2->type = NODE_TEXT;
4094 n2->text = eina_strbuf_new();
4095 eina_strbuf_append(n2->text,
4096 (eina_strbuf_string_get(nc->text) + cur->pos));
4097 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes),
4098 EINA_INLIST_GET(n2),
4099 EINA_INLIST_GET(n));
4100 eina_strbuf_remove(nc->text, cur->pos, eina_strbuf_length_get(nc->text));
4105 else if (cur->pos == len)
4107 if (EINA_INLIST_GET(n)->next)
4108 cur->node = EINA_INLIST_GET(n)->next;
4121 o->formatted.valid = 0;
4122 o->native.valid = 0;
4126 free(o->markup_text);
4127 o->markup_text = NULL;
4129 evas_object_change(cur->obj);
4134 * @param cur to be documented.
4135 * @return Returns no value.
4138 evas_textblock_cursor_node_delete(Evas_Textblock_Cursor *cur)
4140 Evas_Object_Textblock *o;
4141 Evas_Object_Textblock_Node *n, *n2;
4144 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4146 if (eina_strbuf_length_get(n->text) && (!strcmp(eina_strbuf_string_get(n->text), "\n")) &&
4147 (!(EINA_INLIST_GET(n))->next)) return;
4148 n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->next);
4156 n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->prev);
4159 evas_textblock_cursor_char_last(cur);
4164 Evas_Textblock_Cursor *data;
4166 if (cur != o->cursor)
4168 if (n == o->cursor->node)
4170 o->cursor->node = cur->node;
4171 o->cursor->pos = cur->pos;
4172 o->cursor->eol = cur->eol;
4175 EINA_LIST_FOREACH(o->cursors, l, data)
4179 if (n == data->node)
4181 data->node = cur->node;
4182 data->pos = cur->pos;
4183 data->eol = cur->eol;
4189 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
4190 if (n->text) eina_strbuf_free(n->text);
4193 if (n2) _nodes_adjacent_merge(cur->obj, n2);
4195 o->formatted.valid = 0;
4196 o->native.valid = 0;
4200 free(o->markup_text);
4201 o->markup_text = NULL;
4203 evas_object_change(cur->obj);
4208 * @param cur to be documented.
4209 * @return Returns no value.
4212 evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
4214 Evas_Object_Textblock *o;
4215 Evas_Object_Textblock_Node *n, *n2;
4216 int chr, index, ppos;
4219 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4221 if (n->type == NODE_FORMAT)
4223 evas_textblock_cursor_node_delete(cur);
4227 chr = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(n->text), &index);
4228 if (chr == 0) return;
4230 eina_strbuf_remove(n->text, cur->pos, index);
4231 if (!eina_strbuf_length_get(n->text))
4233 evas_textblock_cursor_node_delete(cur);
4236 if (cur->pos == eina_strbuf_length_get(n->text))
4238 n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->next);
4247 evas_textblock_cursor_char_last(cur);
4253 Evas_Textblock_Cursor *data;
4255 if (cur != o->cursor)
4257 if ((n == o->cursor->node) &&
4258 (o->cursor->pos > ppos))
4260 o->cursor->pos -= (index - ppos);
4263 EINA_LIST_FOREACH(o->cursors, l, data)
4267 if ((n == data->node) &&
4270 data->pos -= (index - ppos);
4276 o->formatted.valid = 0;
4277 o->native.valid = 0;
4281 free(o->markup_text);
4282 o->markup_text = NULL;
4284 evas_object_change(cur->obj);
4289 * @param cur1 to be documented.
4290 * @param cur2 to be documented.
4291 * @return Returns no value.
4294 evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
4296 Evas_Object_Textblock *o;
4297 Evas_Object_Textblock_Node *n1, *n2, *n, *tn;
4302 if (cur1->obj != cur2->obj) return;
4303 o = (Evas_Object_Textblock *)(cur1->obj->object_data);
4304 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
4306 Evas_Textblock_Cursor *tc;
4314 if ((!n1) || (!n2)) return;
4316 chr = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(n2->text), &index);
4317 // XXX: why was this added? this stops sel to end and
4318 // if (chr == 0) return;
4321 if (n1->type == NODE_TEXT)
4323 if (cur1->pos == cur2->pos)
4325 evas_textblock_cursor_char_delete(cur1);
4326 evas_textblock_cursor_copy(cur1, cur2);
4329 eina_strbuf_remove(n1->text, cur1->pos, index);
4330 if (!eina_strbuf_length_get(n1->text))
4332 evas_textblock_cursor_node_delete(cur1);
4333 evas_textblock_cursor_copy(cur1, cur2);
4336 if (cur1->pos >= eina_strbuf_length_get(n1->text))
4338 n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n1))->next);
4347 evas_textblock_cursor_char_last(cur1);
4352 evas_textblock_cursor_node_delete(cur1);
4353 evas_textblock_cursor_copy(cur1, cur2);
4357 Eina_List *removes, *format_hump = NULL;
4358 Evas_Textblock_Cursor tcur;
4364 chr = evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(n2->text), &index);
4365 if ((chr == 0) || (index >= eina_strbuf_length_get(n2->text)))
4367 tcur.node = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n2))->next;
4375 chr = evas_common_font_utf8_get_prev((unsigned char *)eina_strbuf_string_get(n2->text), &index);
4380 tcur.node = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->prev;
4381 if ((tcur.node) && (tcur.node->type == NODE_TEXT))
4382 tcur.pos = evas_common_font_utf8_get_last((unsigned char *)eina_strbuf_string_get(tcur.node->text), eina_strbuf_length_get(tcur.node->text));
4388 eina_strbuf_remove(n1->text, cur1->pos, eina_strbuf_length_get(n1->text));
4390 for (l = (EINA_INLIST_GET(n1))->next; l != EINA_INLIST_GET(n2); l = l->next)
4391 removes = eina_list_append(removes, l);
4393 if (n1->type == NODE_TEXT)
4395 if (!eina_strbuf_length_get(n1->text))
4396 evas_textblock_cursor_node_delete(cur1);
4400 if (eina_strbuf_length_get(n1->text) && (eina_strbuf_string_get(n1->text)[0] == '+'))
4401 format_hump = eina_list_append(format_hump, n1);
4404 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1));
4405 if (n1->text) eina_strbuf_free(n1->text);
4412 if (n->type == NODE_TEXT)
4414 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n));
4415 if (n->text) eina_strbuf_free(n->text);
4420 if (eina_strbuf_string_get(n->text)[0] == '+')
4422 format_hump = eina_list_append(format_hump, n);
4424 else if (eina_strbuf_string_get(n->text)[0] == '-')
4426 tn = eina_list_data_get(eina_list_last(format_hump));
4429 format_hump = eina_list_remove_list(format_hump, eina_list_last(format_hump));
4430 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4431 EINA_INLIST_GET(tn));
4432 if (tn->text) eina_strbuf_free(tn->text);
4434 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4435 EINA_INLIST_GET(n));
4436 if (n->text) eina_strbuf_free(n->text);
4442 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4443 EINA_INLIST_GET(n));
4444 if (n->text) eina_strbuf_free(n->text);
4448 removes = eina_list_remove_list(removes, removes);
4450 if (n2->type == NODE_TEXT)
4452 eina_strbuf_remove(n2->text, 0, index);
4453 if (!eina_strbuf_length_get(n2->text))
4454 evas_textblock_cursor_node_delete(cur2);
4458 if (tcur.node == n2)
4460 if ((EINA_INLIST_GET(n2))->next)
4462 tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n2))->next;
4467 tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n2))->next;
4470 if (tcur.node->type == NODE_TEXT)
4471 tcur.pos = evas_common_font_utf8_get_last((unsigned char *)eina_strbuf_string_get(tcur.node->text), eina_strbuf_length_get(tcur.node->text));
4477 if (eina_strbuf_string_get(n2->text)[0] == '-')
4479 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4480 EINA_INLIST_GET(n2));
4481 if (n2->text) eina_strbuf_free(n2->text);
4483 n = eina_list_data_get(eina_list_last(format_hump));
4488 if ((EINA_INLIST_GET(n))->next)
4490 tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n))->next;
4495 tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n))->next;
4498 if (tcur.node->type == NODE_TEXT)
4499 tcur.pos = evas_common_font_utf8_get_last((unsigned char *)eina_strbuf_string_get(tcur.node->text), eina_strbuf_length_get(tcur.node->text));
4505 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4506 EINA_INLIST_GET(n));
4507 if (n->text) eina_strbuf_free(n->text);
4513 o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes),
4514 EINA_INLIST_GET(n2));
4515 if (n2->text) eina_strbuf_free(n2->text);
4519 if (format_hump) eina_list_free(format_hump);
4520 cur1->node = tcur.node;
4521 cur1->pos = tcur.pos;
4522 cur2->node = tcur.node;
4523 cur2->pos = tcur.pos;
4526 /* FIXME: adjust cursors that are affected by the change */
4527 /* this is temporary just avoiding segv's - it sets all other cursors to
4528 * the same pos as cur1 and cur2
4532 Evas_Textblock_Cursor *data;
4534 if ((cur1 != o->cursor) && (cur2 != o->cursor))
4536 evas_textblock_cursor_copy(cur1, o->cursor);
4538 EINA_LIST_FOREACH(o->cursors, l, data)
4540 if ((data != cur1) && (data != cur2))
4542 evas_textblock_cursor_copy(cur1, data);
4546 if (cur1->node) _nodes_adjacent_merge(cur1->obj, cur1->node);
4547 if (cur2->node) _nodes_adjacent_merge(cur2->obj, cur2->node);
4549 o->formatted.valid = 0;
4550 o->native.valid = 0;
4554 free(o->markup_text);
4555 o->markup_text = NULL;
4557 evas_object_change(cur1->obj);
4562 * @param cur to be documented.
4563 * @return to be documented.
4566 evas_textblock_cursor_node_text_get(const Evas_Textblock_Cursor *cur)
4568 if (!cur) return NULL;
4569 if (!cur->node) return NULL;
4570 if (cur->node->type == NODE_TEXT)
4572 return eina_strbuf_string_get(cur->node->text);
4579 * @param cur to be documented.
4580 * @return to be documented.
4583 evas_textblock_cursor_node_text_length_get(const Evas_Textblock_Cursor *cur)
4586 if (!cur->node) return 0;
4587 if (cur->node->type == NODE_TEXT)
4589 return eina_strbuf_length_get(cur->node->text);
4596 * @param cur to be documented.
4597 * @return to be documented.
4600 evas_textblock_cursor_node_format_get(const Evas_Textblock_Cursor *cur)
4602 if (!cur) return NULL;
4603 if (!cur->node) return NULL;
4604 if (cur->node->type == NODE_FORMAT)
4606 return eina_strbuf_string_get(cur->node->text);
4613 * @param cur to be documented.
4614 * @return to be documented.
4617 evas_textblock_cursor_node_format_is_visible_get(const Evas_Textblock_Cursor *cur)
4619 Evas_Object_Textblock_Node *n;
4621 if (!cur) return EINA_FALSE;
4623 if (!n) return EINA_FALSE;
4624 if (n->type != NODE_FORMAT) return EINA_FALSE;
4625 if (!eina_strbuf_length_get(n->text)) return EINA_FALSE;
4631 s = (char *)eina_strbuf_string_get(n->text);
4632 if (s[0] == '+' || s[0] == '-')
4636 while ((item = _format_parse(&s)))
4638 char tmp_delim = *s;
4640 if ((!strcmp(item, "\n")) || (!strcmp(item, "\\n")))
4642 else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t")))
4645 if (visible) return EINA_TRUE;
4653 * @param cur1 to be documented.
4654 * @param cur2 to be documented.
4655 * @param format to be documented.
4656 * @return to be documented.
4659 evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format)
4661 Evas_Object_Textblock *o;
4662 Evas_Object_Textblock_Node *n1, *n2, *n;
4667 if (!cur1) return NULL;
4668 if (!cur2) return NULL;
4669 if (cur1->obj != cur2->obj) return NULL;
4670 o = (Evas_Object_Textblock *)(cur1->obj->object_data);
4671 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
4673 const Evas_Textblock_Cursor *tc;
4682 if ((!n1) || (!n2)) return NULL;
4684 evas_common_font_utf8_get_next((unsigned char *)eina_strbuf_string_get(n2->text), &index);
4685 txt = eina_strbuf_new();
4686 EINA_INLIST_FOREACH(n1, n)
4688 if ((n->type == NODE_TEXT) && (n->text))
4690 s = (char *)eina_strbuf_string_get(n->text);
4691 if (format == EVAS_TEXTBLOCK_TEXT_MARKUP)
4693 const char *p, *ps, *pe;
4695 if (eina_strbuf_length_get(n->text))
4697 if ((n == n1) && (n == n2))
4699 ps = eina_strbuf_string_get(n->text) + cur1->pos;
4700 pe = ps + index - cur1->pos;
4704 ps = eina_strbuf_string_get(n->text) + cur1->pos;
4705 pe = ps + strlen(ps);
4709 ps = eina_strbuf_string_get(n->text);
4710 pe = ps + cur2->pos + 1;
4714 ps = eina_strbuf_string_get(n->text);
4715 pe = ps + strlen(ps);
4724 escape = _escaped_char_match(p, &adv);
4728 eina_strbuf_append(txt, escape);
4732 eina_strbuf_append_char(txt, *p);
4740 if ((n == n1) && (n == n2))
4743 eina_strbuf_append_n(txt, s, index - cur1->pos);
4748 eina_strbuf_append(txt, s);
4752 eina_strbuf_append_n(txt, s, index);
4756 eina_strbuf_append(txt, s);
4762 if (format == EVAS_TEXTBLOCK_TEXT_PLAIN)
4764 s = (char *)eina_strbuf_string_get(n->text);
4768 eina_strbuf_append_char(txt, '\n');
4769 else if (*s == '\t')
4770 eina_strbuf_append_char(txt, '\t');
4774 else if (format == EVAS_TEXTBLOCK_TEXT_MARKUP)
4776 size_t tag_len, replace_len = eina_strbuf_length_get(n->text);
4777 const char *tag = _style_match_replace(o->style, eina_strbuf_string_get(n->text), replace_len, &tag_len);
4778 eina_strbuf_append_char(txt, '<');
4781 // FIXME: need to escape
4782 eina_strbuf_append_length(txt, tag, tag_len);
4789 // FIXME: need to escape
4790 s = (char *)eina_strbuf_string_get(n->text);
4791 if (*s == '+') push = 1;
4792 if (*s == '-') pop = 1;
4793 while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
4794 if (pop) eina_strbuf_append_char(txt, '/');
4795 if (push) eina_strbuf_append(txt, "+ ");
4796 eina_strbuf_append(txt, s);
4798 eina_strbuf_append_char(txt, '>');
4803 ret = eina_strbuf_string_steal(txt);
4804 eina_strbuf_free(txt);
4810 * @param cur to be documented.
4811 * @param cx to be documented.
4812 * @param cy to be documented.
4813 * @param cw to be documented.
4814 * @param ch to be documented.
4815 * @return to be documented.
4818 evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
4820 Evas_Object_Textblock *o;
4821 Evas_Object_Textblock_Line *ln = NULL;
4822 Evas_Object_Textblock_Item *it = NULL;
4823 Evas_Object_Textblock_Format_Item *fi = NULL;
4824 int x = 0, y = 0, w = 0, h = 0;
4827 if (!cur) return -1;
4828 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4835 if (cx) *cx = ln->x;
4836 if (cy) *cy = ln->y;
4837 if (cw) *cw = ln->w;
4838 if (ch) *ch = ln->h;
4844 if (!o->formatted.valid) _relayout(cur->obj);
4845 if (cur->node->type == NODE_FORMAT)
4847 _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi);
4851 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
4859 pos = cur->pos - it->source_pos;
4866 evas_common_font_utf8_get_next((unsigned char *)(it->text), &pos2);
4867 if (pos2 > pos) pos = pos2;
4869 if (pos < 0) pos = 0;
4870 if (it->format->font.font)
4871 ret = cur->ENFN->font_char_coords_get(cur->ENDT, it->format->font.font,
4877 if (it->format->font.font)
4878 cur->ENFN->font_string_size_get(cur->ENDT, it->format->font.font,
4884 x = ln->x + it->x - it->inset + x;
4913 * @param cur to be documented.
4914 * @param cx to be documented.
4915 * @param cy to be documented.
4916 * @param cw to be documented.
4917 * @param ch to be documented.
4918 * @return to be documented.
4921 evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
4923 Evas_Object_Textblock *o;
4924 Evas_Object_Textblock_Line *ln = NULL;
4925 Evas_Object_Textblock_Item *it = NULL;
4926 Evas_Object_Textblock_Format_Item *fi = NULL;
4929 if (!cur) return -1;
4930 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4931 if (!o->formatted.valid) _relayout(cur->obj);
4938 if (cur->node->type == NODE_FORMAT)
4939 _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi);
4941 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
4957 * @param cur to be documented.
4958 * @param x to be documented.
4959 * @param y to be documented.
4960 * @return to be documented.
4963 evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
4965 Evas_Object_Textblock *o;
4966 Evas_Object_Textblock_Line *ln;
4967 Evas_Object_Textblock_Item *it = NULL, *it_break = NULL;
4968 Evas_Object_Textblock_Format_Item *fi = NULL;
4970 if (!cur) return EINA_FALSE;
4971 o = (Evas_Object_Textblock *)(cur->obj->object_data);
4972 if (!o->formatted.valid) _relayout(cur->obj);
4973 x += o->style_pad.l;
4974 y += o->style_pad.t;
4975 EINA_INLIST_FOREACH(o->lines, ln)
4977 if (ln->y > y) break;
4978 if ((ln->y <= y) && ((ln->y + ln->h) > y))
4980 EINA_INLIST_FOREACH(ln->items, it)
4982 if ((it->x + ln->x) > x)
4987 if (((it->x + ln->x) <= x) && (((it->x + ln->x) + it->w) > x))
4993 if (it->format->font.font)
4994 pos = cur->ENFN->font_char_at_coords_get(cur->ENDT,
4995 it->format->font.font,
4997 x - it->x - ln->x, 0,
4998 &cx, &cy, &cw, &ch);
5001 cur->pos = pos + it->source_pos;
5002 cur->node = it->source_node;
5006 EINA_INLIST_FOREACH(ln->format_items, fi)
5008 if ((fi->x + ln->x) > x) break;
5009 if (((fi->x + ln->x) <= x) && (((fi->x + ln->x) + fi->w) > x))
5013 cur->node = fi->source_node;
5020 cur->pos = it->source_pos;
5022 cur->node = it->source_node;
5032 * @param cur to be documented.
5033 * @param y to be documented.
5034 * @return to be documented.
5037 evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
5039 Evas_Object_Textblock *o;
5040 Evas_Object_Textblock_Line *ln;
5042 if (!cur) return -1;
5043 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5044 if (!o->formatted.valid) _relayout(cur->obj);
5045 y += o->style_pad.t;
5046 EINA_INLIST_FOREACH(o->lines, ln)
5048 if (ln->y > y) break;
5049 if ((ln->y <= y) && ((ln->y + ln->h) > y))
5051 evas_textblock_cursor_line_set(cur, ln->line_no);
5060 * @param cur1 to be documented.
5061 * @param cur2 to be documented.
5062 * @return to be documented.
5065 evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
5067 Eina_List *rects = NULL;
5068 Evas_Coord cx, cy, cw, ch, lx, ly, lw, lh;
5069 Evas_Textblock_Rectangle *tr;
5072 if (!cur1) return NULL;
5073 if (!cur2) return NULL;
5074 if (cur1->obj != cur2->obj) return NULL;
5075 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
5077 const Evas_Textblock_Cursor *tc;
5083 line = evas_textblock_cursor_char_geometry_get(cur1, &cx, &cy, &cw, &ch);
5084 if (line < 0) return NULL;
5085 line = evas_textblock_cursor_line_geometry_get(cur1, &lx, &ly, &lw, &lh);
5086 if (line < 0) return NULL;
5087 line2 = evas_textblock_cursor_line_geometry_get(cur2, NULL, NULL, NULL, NULL);
5088 if (line2 < 0) return NULL;
5091 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
5092 rects = eina_list_append(rects, tr);
5096 line = evas_textblock_cursor_char_geometry_get(cur2, &cx, &cy, &cw, &ch);
5102 rects = eina_list_remove_list(rects, rects);
5106 tr->w = cx + cw - tr->x;
5110 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
5111 rects = eina_list_append(rects, tr);
5115 tr->w = lx + lw - cx;
5116 for (i = line +1; i < line2; i++)
5118 evas_object_textblock_line_number_geometry_get(cur1->obj, i, &lx, &ly, &lw, &lh);
5119 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
5120 rects = eina_list_append(rects, tr);
5126 line = evas_textblock_cursor_char_geometry_get(cur2, &cx, &cy, &cw, &ch);
5132 rects = eina_list_remove_list(rects, rects);
5136 line = evas_textblock_cursor_line_geometry_get(cur2, &lx, &ly, &lw, &lh);
5142 rects = eina_list_remove_list(rects, rects);
5146 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
5147 rects = eina_list_append(rects, tr);
5151 tr->w = cx + cw - lx;
5158 * @param cur to be documented.
5159 * @param cx to be documented.
5160 * @param cy to be documented.
5161 * @param cw to be documented.
5162 * @param ch to be documented.
5163 * @return to be documented.
5166 evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
5168 Evas_Object_Textblock *o;
5169 Evas_Object_Textblock_Line *ln = NULL;
5170 Evas_Object_Textblock_Format_Item *fi = NULL;
5171 Evas_Coord x, y, w, h;
5174 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5175 if (!o->formatted.valid) _relayout(cur->obj);
5176 _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi);
5177 if ((!ln) || (!fi)) return 0;
5179 y = ln->y + ln->baseline + fi->y;
5192 * FIXME: To be fixed.
5196 evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur)
5198 if (!cur) return EINA_FALSE;
5205 * FIXME: To be fixed.
5209 evas_textblock_cursor_eol_set(Evas_Textblock_Cursor *cur, Eina_Bool eol)
5216 /* general controls */
5219 * @param obj to be documented.
5220 * @param line to be documented.
5221 * @param cx to be documented.
5222 * @param cy to be documented.
5223 * @param cw to be documented.
5224 * @param ch to be documented.
5225 * @return to be documented.
5228 evas_object_textblock_line_number_geometry_get(const Evas_Object *obj, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
5230 Evas_Object_Textblock_Line *ln;
5233 ln = _find_layout_line_num(obj, line);
5234 if (!ln) return EINA_FALSE;
5235 if (cx) *cx = ln->x;
5236 if (cy) *cy = ln->y;
5237 if (cw) *cw = ln->w;
5238 if (ch) *ch = ln->h;
5244 * @param obj to be documented.
5245 * @return Returns no value.
5248 evas_object_textblock_clear(Evas_Object *obj)
5251 Evas_Textblock_Cursor *cur;
5255 o->cursor->node = NULL;
5258 EINA_LIST_FOREACH(o->cursors, l, cur)
5266 _lines_clear(obj, o->lines);
5269 o->formatted.valid = 0;
5270 o->native.valid = 0;
5274 free(o->markup_text);
5275 o->markup_text = NULL;
5277 evas_object_change(obj);
5278 /* FIXME: adjust cursors that are affected by the change */
5283 * @param obj to be documented.
5284 * @param w to be documented.
5285 * @param h to be documented.
5286 * @return Returns no value.
5289 evas_object_textblock_size_formatted_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
5292 if (!o->formatted.valid) _relayout(obj);
5293 if (w) *w = o->formatted.w;
5294 if (h) *h = o->formatted.h;
5299 * @param obj to be documented.
5300 * @param w to be documented.
5301 * @param h to be documented.
5302 * @return Returns no value.
5305 evas_object_textblock_size_native_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
5308 if (!o->native.valid)
5313 &o->native.w, &o->native.h);
5314 o->native.valid = 1;
5316 if (w) *w = o->native.w;
5317 if (h) *h = o->native.h;
5322 * @param obj to be documented.
5323 * @param l to be documented.
5324 * @param r to be documented.
5325 * @param t to be documented.
5326 * @param b to be documented.
5327 * @return Returns no value.
5330 evas_object_textblock_style_insets_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
5333 if (!o->formatted.valid) _relayout(obj);
5334 if (l) *l = o->style_pad.l;
5335 if (r) *r = o->style_pad.r;
5336 if (t) *t = o->style_pad.t;
5337 if (b) *b = o->style_pad.b;
5344 /* all nice and private */
5346 evas_object_textblock_init(Evas_Object *obj)
5348 Evas_Object_Textblock *o;
5350 /* alloc image ob, setup methods and default values */
5351 obj->object_data = evas_object_textblock_new();
5352 /* set up default settings for this kind of object */
5353 obj->cur.color.r = 255;
5354 obj->cur.color.g = 255;
5355 obj->cur.color.b = 255;
5356 obj->cur.color.a = 255;
5357 obj->cur.geometry.x = 0.0;
5358 obj->cur.geometry.y = 0.0;
5359 obj->cur.geometry.w = 0.0;
5360 obj->cur.geometry.h = 0.0;
5362 /* set up object-specific settings */
5363 obj->prev = obj->cur;
5364 /* set up methods (compulsory) */
5365 obj->func = &object_func;
5368 o = (Evas_Object_Textblock *)(obj->object_data);
5369 o->cursor->obj = obj;
5373 evas_object_textblock_new(void)
5375 Evas_Object_Textblock *o;
5377 /* alloc obj private data */
5378 o = calloc(1, sizeof(Evas_Object_Textblock));
5379 o->magic = MAGIC_OBJ_TEXTBLOCK;
5380 o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor));
5385 evas_object_textblock_free(Evas_Object *obj)
5387 Evas_Object_Textblock *o;
5389 evas_object_textblock_clear(obj);
5390 evas_object_textblock_style_set(obj, NULL);
5391 o = (Evas_Object_Textblock *)(obj->object_data);
5395 Evas_Textblock_Cursor *cur;
5397 cur = (Evas_Textblock_Cursor *)o->cursors->data;
5398 o->cursors = eina_list_remove_list(o->cursors, o->cursors);
5401 if (o->repch) eina_stringshare_del(o->repch);
5407 evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
5409 Evas_Object_Textblock_Line *ln;
5410 Evas_Object_Textblock *o;
5412 int pback = 0, backx = 0;
5413 int pline = 0, linex = 0;
5414 int pline2 = 0, line2x = 0;
5415 int pstrike = 0, strikex = 0;
5417 unsigned char r = 0, g = 0, b = 0, a = 0;
5418 unsigned char r2 = 0, g2 = 0, b2 = 0, a2 = 0;
5419 unsigned char r3 = 0, g3 = 0, b3 = 0, a3 = 0;
5420 int cx, cy, cw, ch, clip;
5421 const char vals[5][5] =
5430 /* render object to surface with context, and offxet by x,y */
5431 o = (Evas_Object_Textblock *)(obj->object_data);
5432 obj->layer->evas->engine.func->context_multiplier_unset(output,
5434 clip = ENFN->context_clip_get(output, context, &cx, &cy, &cw, &ch);
5435 #define ITEM_WALK() \
5436 EINA_INLIST_FOREACH(o->lines, ln) \
5438 Evas_Object_Textblock_Item *it; \
5446 if ((obj->cur.geometry.y + y + ln->y + ln->h) < (cy - 20)) \
5448 if ((obj->cur.geometry.y + y + ln->y) > (cy + ch + 20)) \
5451 EINA_INLIST_FOREACH(ln->items, it) \
5455 yoff = ln->baseline; \
5456 if (it->format->valign != -1.0) \
5457 yoff = (it->format->valign * (double)(ln->h - it->h)) + it->baseline; \
5460 if ((obj->cur.geometry.x + x + ln->x + it->x - it->inset + it->w) < (cx - 20)) \
5462 if ((obj->cur.geometry.x + x + ln->x + it->x - it->inset) > (cx + cw + 20)) \
5466 #define ITEM_WALK_END() \
5469 #define COLOR_SET(col) \
5470 ENFN->context_color_set(output, context, \
5471 (obj->cur.cache.clip.r * it->format->color.col.r) / 255, \
5472 (obj->cur.cache.clip.g * it->format->color.col.g) / 255, \
5473 (obj->cur.cache.clip.b * it->format->color.col.b) / 255, \
5474 (obj->cur.cache.clip.a * it->format->color.col.a) / 255);
5475 #define COLOR_SET_AMUL(col, amul) \
5476 ENFN->context_color_set(output, context, \
5477 (obj->cur.cache.clip.r * it->format->color.col.r * (amul)) / 65025, \
5478 (obj->cur.cache.clip.g * it->format->color.col.g * (amul)) / 65025, \
5479 (obj->cur.cache.clip.b * it->format->color.col.b * (amul)) / 65025, \
5480 (obj->cur.cache.clip.a * it->format->color.col.a * (amul)) / 65025);
5481 #define DRAW_TEXT(ox, oy) \
5482 if (it->format->font.font) ENFN->font_draw(output, context, surface, it->format->font.font, \
5483 obj->cur.geometry.x + ln->x + it->x - it->inset + x + (ox), \
5484 obj->cur.geometry.y + ln->y + yoff + y + (oy), \
5485 it->w, it->h, it->w, it->h, it->text);
5487 //#define DRAW_TEXT(ox, oy) \
5488 // if (it->format->font.font) ENFN->font_draw(output, context, surface, it->format->font.font, \
5489 // obj->cur.geometry.x + ln->x + it->x - it->inset + x + (ox), \
5490 // obj->cur.geometry.y + ln->y + yoff + y + (oy), \
5491 // obj->cur.cache.geometry.x + ln->x + it->x - it->inset + x + (ox), \
5492 // obj->cur.cache.geometry.y + ln->y + yoff + y + (oy), \
5493 // it->w, it->h, it->w, it->h, it->text);
5495 #define ITEM_WALK_LINE_SKIP_DROP() \
5496 if ((ln->y + ln->h) <= 0) continue; \
5497 if (ln->y > obj->cur.geometry.h) break
5502 ITEM_WALK_LINE_SKIP_DROP();
5503 if ((it->format->backing) && (!pback) && ((EINA_INLIST_GET(it))->next))
5507 r = it->format->color.backing.r;
5508 g = it->format->color.backing.g;
5509 b = it->format->color.backing.b;
5510 a = it->format->color.backing.a;
5512 else if (((pback) && (!it->format->backing)) ||
5513 (!(EINA_INLIST_GET(it))->next) ||
5514 (it->format->color.backing.r != r) ||
5515 (it->format->color.backing.g != g) ||
5516 (it->format->color.backing.b != b) ||
5517 (it->format->color.backing.a != a))
5519 if ((it->format->backing) && (!pback) && (!(EINA_INLIST_GET(it))->next))
5521 r = it->format->color.backing.r;
5522 g = it->format->color.backing.g;
5523 b = it->format->color.backing.b;
5524 a = it->format->color.backing.a;
5528 if (!it->format->backing) x2 = it->x;
5529 else x2 = it->x + it->w;
5530 if ((pback) && (x2 > backx))
5532 ENFN->context_color_set(output,
5534 (obj->cur.cache.clip.r * r) / 255,
5535 (obj->cur.cache.clip.g * g) / 255,
5536 (obj->cur.cache.clip.b * b) / 255,
5537 (obj->cur.cache.clip.a * a) / 255);
5538 ENFN->rectangle_draw(output,
5541 obj->cur.geometry.x + ln->x + backx + x,
5542 obj->cur.geometry.y + ln->y + y,
5543 //// obj->cur.cache.geometry.x + ln->x + backx + x,
5544 //// obj->cur.cache.geometry.y + ln->y + y,
5548 pback = it->format->backing;
5550 r = it->format->color.backing.r;
5551 g = it->format->color.backing.g;
5552 b = it->format->color.backing.b;
5553 a = it->format->color.backing.a;
5559 ITEM_WALK_LINE_SKIP_DROP();
5560 if (it->format->style == EVAS_TEXT_STYLE_SHADOW)
5565 else if ((it->format->style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
5566 (it->format->style == EVAS_TEXT_STYLE_FAR_SHADOW))
5571 else if ((it->format->style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW) ||
5572 (it->format->style == EVAS_TEXT_STYLE_FAR_SOFT_SHADOW))
5574 for (j = 0; j < 5; j++)
5576 for (i = 0; i < 5; i++)
5578 if (vals[i][j] != 0)
5580 COLOR_SET_AMUL(shadow, vals[i][j] * 50);
5586 else if (it->format->style == EVAS_TEXT_STYLE_SOFT_SHADOW)
5588 for (j = 0; j < 5; j++)
5590 for (i = 0; i < 5; i++)
5592 if (vals[i][j] != 0)
5594 COLOR_SET_AMUL(shadow, vals[i][j] * 50);
5595 DRAW_TEXT(i - 1, j - 1);
5604 ITEM_WALK_LINE_SKIP_DROP();
5605 if (it->format->style == EVAS_TEXT_STYLE_GLOW)
5607 for (j = 0; j < 5; j++)
5609 for (i = 0; i < 5; i++)
5611 if (vals[i][j] != 0)
5613 COLOR_SET_AMUL(glow, vals[i][j] * 50);
5614 DRAW_TEXT(i - 2, j - 2);
5628 ITEM_WALK_LINE_SKIP_DROP();
5629 if ((it->format->style == EVAS_TEXT_STYLE_OUTLINE) ||
5630 (it->format->style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
5631 (it->format->style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
5639 else if (it->format->style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
5641 for (j = 0; j < 5; j++)
5643 for (i = 0; i < 5; i++)
5645 if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
5647 COLOR_SET_AMUL(outline, vals[i][j] * 50);
5648 DRAW_TEXT(i - 2, j - 2);
5657 ITEM_WALK_LINE_SKIP_DROP();
5660 if ((it->format->strikethrough) && (!pstrike) && ((EINA_INLIST_GET(it))->next))
5664 r3 = it->format->color.strikethrough.r;
5665 g3 = it->format->color.strikethrough.g;
5666 b3 = it->format->color.strikethrough.b;
5667 a3 = it->format->color.strikethrough.a;
5669 else if (((pstrike) && (!it->format->strikethrough)) ||
5670 (!(EINA_INLIST_GET(it))->next) ||
5671 (it->format->color.strikethrough.r != r3) ||
5672 (it->format->color.strikethrough.g != g3) ||
5673 (it->format->color.strikethrough.b != b3) ||
5674 (it->format->color.strikethrough.a != a3))
5676 if ((it->format->strikethrough) && (!pstrike))
5679 r3 = it->format->color.strikethrough.r;
5680 g3 = it->format->color.strikethrough.g;
5681 b3 = it->format->color.strikethrough.b;
5682 a3 = it->format->color.strikethrough.a;
5685 if (!it->format->strikethrough)
5692 ENFN->context_color_set(output,
5694 (obj->cur.cache.clip.r * r3) / 255,
5695 (obj->cur.cache.clip.g * g3) / 255,
5696 (obj->cur.cache.clip.b * b3) / 255,
5697 (obj->cur.cache.clip.a * a3) / 255);
5698 ENFN->rectangle_draw(output,
5701 obj->cur.geometry.x + ln->x + strikex + x,
5702 obj->cur.geometry.y + ln->y + y + (ln->h / 2),
5703 //// obj->cur.cache.geometry.x + ln->x + strikex + x,
5704 //// obj->cur.cache.geometry.y + ln->y + y + (ln->h / 2),
5708 if (it->format->strikethrough) pstrike = 1;
5710 r3 = it->format->color.strikethrough.r;
5711 g3 = it->format->color.strikethrough.g;
5712 b3 = it->format->color.strikethrough.b;
5713 a3 = it->format->color.strikethrough.a;
5715 if ((it->format->underline) && (!pline) && ((EINA_INLIST_GET(it))->next))
5719 r = it->format->color.underline.r;
5720 g = it->format->color.underline.g;
5721 b = it->format->color.underline.b;
5722 a = it->format->color.underline.a;
5724 else if (((pline) && (!it->format->underline)) ||
5725 (!(EINA_INLIST_GET(it))->next) ||
5726 (it->format->color.underline.r != r) ||
5727 (it->format->color.underline.g != g) ||
5728 (it->format->color.underline.b != b) ||
5729 (it->format->color.underline.a != a))
5731 if ((it->format->underline) && (!pline))
5734 r = it->format->color.underline.r;
5735 g = it->format->color.underline.g;
5736 b = it->format->color.underline.b;
5737 a = it->format->color.underline.a;
5740 if (!it->format->underline)
5747 ENFN->context_color_set(output,
5749 (obj->cur.cache.clip.r * r) / 255,
5750 (obj->cur.cache.clip.g * g) / 255,
5751 (obj->cur.cache.clip.b * b) / 255,
5752 (obj->cur.cache.clip.a * a) / 255);
5753 ENFN->rectangle_draw(output,
5756 obj->cur.geometry.x + ln->x + linex + x,
5757 obj->cur.geometry.y + ln->y + y + ln->baseline + 1,
5758 //// obj->cur.cache.geometry.x + ln->x + linex + x,
5759 //// obj->cur.cache.geometry.y + ln->y + y + ln->baseline + 1,
5763 if (it->format->underline) pline = 1;
5765 r = it->format->color.underline.r;
5766 g = it->format->color.underline.g;
5767 b = it->format->color.underline.b;
5768 a = it->format->color.underline.a;
5770 if ((it->format->underline2) && (!pline2) && ((EINA_INLIST_GET(it))->next))
5774 r2 = it->format->color.underline2.r;
5775 g2 = it->format->color.underline2.g;
5776 b2 = it->format->color.underline2.b;
5777 a2 = it->format->color.underline2.a;
5779 else if (((pline2) && (!it->format->underline2)) ||
5780 (!(EINA_INLIST_GET(it))->next) ||
5781 (it->format->color.underline2.r != r2) ||
5782 (it->format->color.underline2.g != g2) ||
5783 (it->format->color.underline2.b != b2) ||
5784 (it->format->color.underline2.a != a2))
5786 if ((it->format->underline2) && (!pline2))
5789 r2 = it->format->color.underline2.r;
5790 g2 = it->format->color.underline2.g;
5791 b2 = it->format->color.underline2.b;
5792 a2 = it->format->color.underline2.a;
5795 if (!it->format->underline2)
5802 ENFN->context_color_set(output,
5804 (obj->cur.cache.clip.r * r2) / 255,
5805 (obj->cur.cache.clip.g * g2) / 255,
5806 (obj->cur.cache.clip.b * b2) / 255,
5807 (obj->cur.cache.clip.a * a2) / 255);
5808 ENFN->rectangle_draw(output,
5811 obj->cur.geometry.x + ln->x + line2x + x,
5812 obj->cur.geometry.y + ln->y + y + ln->baseline + 3,
5813 //// obj->cur.cache.geometry.x + ln->x + line2x + x,
5814 //// obj->cur.cache.geometry.y + ln->y + y + ln->baseline + 3,
5818 if (it->format->underline2) pline2 = 1;
5820 r2 = it->format->color.underline2.r;
5821 g2 = it->format->color.underline2.g;
5822 b2 = it->format->color.underline2.b;
5823 a2 = it->format->color.underline2.a;
5829 evas_object_textblock_render_pre(Evas_Object *obj)
5831 Evas_Object_Textblock *o;
5834 /* dont pre-render the obj twice! */
5835 if (obj->pre_render_done) return;
5836 obj->pre_render_done = 1;
5837 /* pre-render phase. this does anything an object needs to do just before */
5838 /* rendering. this could mean loading the image data, retrieving it from */
5839 /* elsewhere, decoding video etc. */
5840 /* then when this is done the object needs to figure if it changed and */
5841 /* if so what and where and add the appropriate redraw textblocks */
5842 o = (Evas_Object_Textblock *)(obj->object_data);
5844 (o->last_w != obj->cur.geometry.w))
5846 Evas_Object_Textblock_Line *lines;
5850 o->formatted.valid = 0;
5851 o->native.valid = 0;
5854 obj->cur.geometry.w, obj->cur.geometry.h,
5855 &o->formatted.w, &o->formatted.h);
5856 o->formatted.valid = 1;
5857 if (lines) _lines_clear(obj, lines);
5858 o->last_w = obj->cur.geometry.w;
5860 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5862 is_v = evas_object_is_visible(obj);
5863 was_v = evas_object_was_visible(obj);
5869 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5871 is_v = evas_object_is_visible(obj);
5872 was_v = evas_object_was_visible(obj);
5875 /* if someone is clipping this obj - go calculate the clipper */
5876 if (obj->cur.clipper)
5878 if (obj->cur.cache.clip.dirty)
5879 evas_object_clip_recalc(obj->cur.clipper);
5880 obj->cur.clipper->func->render_pre(obj->cur.clipper);
5882 /* now figure what changed and add draw rects */
5883 /* if it just became visible or invisible */
5884 is_v = evas_object_is_visible(obj);
5885 was_v = evas_object_was_visible(obj);
5888 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
5891 if ((obj->cur.map != obj->prev.map) ||
5892 (obj->cur.usemap != obj->prev.usemap))
5894 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5897 /* it's not visible - we accounted for it appearing or not so just abort */
5898 if (!is_v) goto done;
5899 /* clipper changed this is in addition to anything else for obj */
5900 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
5901 /* if we restacked (layer or just within a layer) and don't clip anyone */
5904 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5907 /* if it changed color */
5908 if ((obj->cur.color.r != obj->prev.color.r) ||
5909 (obj->cur.color.g != obj->prev.color.g) ||
5910 (obj->cur.color.b != obj->prev.color.b) ||
5911 (obj->cur.color.a != obj->prev.color.a))
5913 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5916 /* if it changed geometry - and obviously not visibility or color */
5917 /* caluclate differences since we have a constant color fill */
5918 /* we really only need to update the differences */
5919 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
5920 (obj->cur.geometry.y != obj->prev.geometry.y) ||
5921 (obj->cur.geometry.w != obj->prev.geometry.w) ||
5922 (obj->cur.geometry.h != obj->prev.geometry.h))
5924 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5929 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
5933 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
5937 evas_object_textblock_render_post(Evas_Object *obj)
5939 /* Evas_Object_Textblock *o; */
5941 /* this moves the current data to the previous state parts of the object */
5942 /* in whatever way is safest for the object. also if we don't need object */
5943 /* data anymore we can free it if the object deems this is a good idea */
5944 /* o = (Evas_Object_Textblock *)(obj->object_data); */
5945 /* remove those pesky changes */
5946 evas_object_clip_changes_clean(obj);
5947 /* move cur to prev safely for object data */
5948 obj->prev = obj->cur;
5949 /* o->prev = o->cur; */
5950 /* o->changed = 0; */
5953 static unsigned int evas_object_textblock_id_get(Evas_Object *obj)
5955 Evas_Object_Textblock *o;
5957 o = (Evas_Object_Textblock *)(obj->object_data);
5959 return MAGIC_OBJ_TEXTBLOCK;
5962 static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj)
5964 Evas_Object_Textblock *o;
5966 o = (Evas_Object_Textblock *)(obj->object_data);
5968 return MAGIC_OBJ_CUSTOM;
5971 static void *evas_object_textblock_engine_data_get(Evas_Object *obj)
5973 Evas_Object_Textblock *o;
5975 o = (Evas_Object_Textblock *)(obj->object_data);
5976 if (!o) return NULL;
5977 return o->engine_data;
5981 evas_object_textblock_is_opaque(Evas_Object *obj)
5983 /* this returns 1 if the internal object data implies that the object is */
5984 /* currently fulyl opque over the entire gradient it occupies */
5989 evas_object_textblock_was_opaque(Evas_Object *obj)
5991 /* this returns 1 if the internal object data implies that the object was */
5992 /* currently fulyl opque over the entire gradient it occupies */
5997 evas_object_textblock_coords_recalc(Evas_Object *obj)
5999 Evas_Object_Textblock *o;
6001 o = (Evas_Object_Textblock *)(obj->object_data);
6002 if (obj->cur.geometry.w != o->last_w)
6004 o->formatted.valid = 0;
6005 o->native.valid = 0;
6011 evas_object_textblock_scale_update(Evas_Object *obj)
6017 _evas_object_textblock_rehint(Evas_Object *obj)
6019 Evas_Object_Textblock *o;
6020 Evas_Object_Textblock_Line *ln;
6022 o = (Evas_Object_Textblock *)(obj->object_data);
6023 EINA_INLIST_FOREACH(o->lines, ln)
6025 Evas_Object_Textblock_Item *it;
6027 EINA_INLIST_FOREACH(ln->items, it)
6029 if (it->format->font.font)
6031 #ifdef EVAS_FRAME_QUEUING
6032 evas_common_pipe_op_text_flush(it->format->font.font);
6034 evas_font_load_hinting_set(obj->layer->evas,
6035 it->format->font.font,
6036 obj->layer->evas->hinting);
6040 o->formatted.valid = 0;
6041 o->native.valid = 0;
6043 evas_object_change(obj);