diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 7a5615678c..c4dae58857 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -1313,9 +1313,10 @@ typedef void (*Evas_Object_Event_Cb) (void *data, Evas *e, Evas_Object *obj * * @ingroup Evas_Object_Specific */ - typedef struct _Evas_Textblock_Style Evas_Textblock_Style; - typedef struct _Evas_Textblock_Cursor Evas_Textblock_Cursor; - typedef struct _Evas_Textblock_Rectangle Evas_Textblock_Rectangle; + typedef struct _Evas_Textblock_Style Evas_Textblock_Style; + typedef struct _Evas_Textblock_Cursor Evas_Textblock_Cursor; + typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format; + typedef struct _Evas_Textblock_Rectangle Evas_Textblock_Rectangle; struct _Evas_Textblock_Rectangle { @@ -1354,35 +1355,45 @@ typedef void (*Evas_Object_Event_Cb) (void *data, Evas *e, Evas_Object *obj EAPI void evas_textblock_cursor_free(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_node_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_node_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI Eina_Bool evas_textblock_cursor_node_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI Eina_Bool evas_textblock_cursor_node_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI Eina_Bool evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI Eina_Bool evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_first_get(const Evas_Object *obj) EINA_ARG_NONNULL(1); + EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_last_get(const Evas_Object *obj) EINA_ARG_NONNULL(1); + EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1); + EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n) EINA_ARG_NONNULL(1, 2); + EAPI const Evas_Object_Textblock_Node_Format *evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI const char *evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt) EINA_ARG_NONNULL(1, 2); + EAPI Eina_Bool evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; + EAPI Eina_Bool evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI Eina_Bool evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI Eina_Bool evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); EAPI Eina_Bool evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); EAPI Eina_Bool evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_line_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); - EAPI void evas_textblock_cursor_line_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); + EAPI void evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); EAPI int evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; EAPI void evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int pos) EINA_ARG_NONNULL(1); EAPI Eina_Bool evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line) EINA_ARG_NONNULL(1); EAPI int evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2) EINA_PURE; EAPI void evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest) EINA_ARG_NONNULL(1, 2); - EAPI void evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2); - EAPI void evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2); + EAPI size_t evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2); + EAPI size_t evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *text) EINA_ARG_NONNULL(1, 2); - EAPI void evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2); - EAPI void evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2); + EAPI Eina_Bool evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2); + EAPI Eina_Bool evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) EINA_ARG_NONNULL(1, 2); EAPI void evas_textblock_cursor_node_delete(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); EAPI void evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) EINA_ARG_NONNULL(1); EAPI void evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2) EINA_ARG_NONNULL(1, 2); - EAPI const char *evas_textblock_cursor_node_text_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; - EAPI int evas_textblock_cursor_node_text_length_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; - EAPI const char *evas_textblock_cursor_node_format_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; - EAPI Eina_Bool evas_textblock_cursor_node_format_is_visible_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; + EAPI const char *evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; + EAPI int evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; EAPI char *evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2) EINA_PURE; EAPI int evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1); @@ -1393,7 +1404,6 @@ typedef void (*Evas_Object_Event_Cb) (void *data, Evas *e, Evas_Object *obj EAPI Eina_Bool evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) EINA_ARG_NONNULL(1); EAPI Eina_Bool evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; - EAPI void evas_textblock_cursor_eol_set(Evas_Textblock_Cursor *cur, Eina_Bool eol) EINA_ARG_NONNULL(1); EAPI Eina_Bool 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) EINA_ARG_NONNULL(1); EAPI void evas_object_textblock_clear(Evas_Object *obj) EINA_ARG_NONNULL(1); diff --git a/legacy/evas/src/lib/canvas/evas_object_text.c b/legacy/evas/src/lib/canvas/evas_object_text.c index de41599215..310662e794 100644 --- a/legacy/evas/src/lib/canvas/evas_object_text.c +++ b/legacy/evas/src/lib/canvas/evas_object_text.c @@ -25,8 +25,9 @@ struct _Evas_Object_Text unsigned char r, g, b, a; } outline, shadow, glow, glow2; - unsigned char style; - Evas_BiDi_Props intl_props; + unsigned char style; + Evas_BiDi_Props intl_props; + Evas_BiDi_Paragraph_Props paragraph_bidi_props; } cur, prev; float ascent, descent; @@ -349,7 +350,7 @@ evas_object_text_text_set(Evas_Object *obj, const char *_text) /* DO II */ /*Update intl_props*/ #ifdef BIDI_SUPPORT - evas_bidi_update_props(text, &o->cur.intl_props); + evas_bidi_update_props(text, o->cur.intl_props.props); #endif if (o->cur.text) eina_ustringshare_del(o->cur.text); if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text); @@ -1454,8 +1455,9 @@ evas_object_text_new(void) o = calloc(1, sizeof(Evas_Object_Text)); o->magic = MAGIC_OBJ_TEXT; o->prev = o->cur; + o->cur.intl_props.props = &o->cur.paragraph_bidi_props; #ifdef BIDI_SUPPORT - o->cur.intl_props.direction = FRIBIDI_PAR_ON; + o->cur.intl_props.props->direction = FRIBIDI_PAR_ON; #endif return o; } @@ -1476,8 +1478,8 @@ evas_object_text_free(Evas_Object *obj) if (o->cur.font) eina_stringshare_del(o->cur.font); if (o->cur.source) eina_stringshare_del(o->cur.source); if (o->engine_data) evas_font_free(obj->layer->evas, o->engine_data); - if (o->cur.intl_props.embedding_levels) free(o->cur.intl_props.embedding_levels); - if (o->cur.intl_props.char_types) free(o->cur.intl_props.char_types); + if (o->cur.intl_props.props->embedding_levels) free(o->cur.intl_props.props->embedding_levels); + if (o->cur.intl_props.props->char_types) free(o->cur.intl_props.props->char_types); o->magic = 0; free(o); } diff --git a/legacy/evas/src/lib/canvas/evas_object_textblock.c b/legacy/evas/src/lib/canvas/evas_object_textblock.c index 9becf7c084..7ca4941ce7 100644 --- a/legacy/evas/src/lib/canvas/evas_object_textblock.c +++ b/legacy/evas/src/lib/canvas/evas_object_textblock.c @@ -11,12 +11,17 @@ /* private magic number for textblock objects */ static const char o_type[] = "textblock"; +#define EVAS_TEXTBLOCK_REPLACEMENT_CHAR 0xFFFD /* private struct for textblock object internal data */ typedef struct _Evas_Object_Textblock Evas_Object_Textblock; typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; typedef enum _Evas_Object_Textblock_Node_Type Evas_Object_Textblock_Node_Type; -typedef struct _Evas_Object_Textblock_Node Evas_Object_Textblock_Node; +typedef struct _Evas_Object_Textblock_Node_Text Evas_Object_Textblock_Node_Text; +/* + * Defined in Evas.h +typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format; +*/ typedef struct _Evas_Object_Textblock_Paragraph Evas_Object_Textblock_Paragraph; typedef struct _Evas_Object_Textblock_Line Evas_Object_Textblock_Line; typedef struct _Evas_Object_Textblock_Item Evas_Object_Textblock_Item; @@ -42,31 +47,34 @@ struct _Evas_Object_Style_Tag size_t replace_len; }; -struct _Evas_Object_Textblock_Node +struct _Evas_Object_Textblock_Node_Text { EINA_INLIST; - Evas_Object_Textblock_Node_Type type; - union { - struct { - Eina_UStrbuf *unicode; - char * utf8; - } text; - Eina_Strbuf *format; - } data; + Eina_UStrbuf *unicode; + char * utf8; + Evas_Object_Textblock_Node_Format *format_node; + Evas_BiDi_Paragraph_Props bidi_props; }; -#define _NODE_STRBUF_FREE(x) \ - do { \ - if (x->type == NODE_FORMAT) \ - { \ - if (x->data.format) eina_strbuf_free(x->data.format); \ - } \ - else \ - { \ - if (x->data.text.unicode) eina_ustrbuf_free(x->data.text.unicode);\ - if (x->data.text.utf8) free(x->data.text.utf8); \ - } \ - } while(0) +struct _Evas_Object_Textblock_Node_Format +{ + EINA_INLIST; + Eina_Strbuf *format; + Evas_Object_Textblock_Node_Text *text_node; + size_t offset; + Eina_Bool visible; +}; + +#define _NODE_TEXT(x) ((Evas_Object_Textblock_Node_Text *) (x)) +#define _NODE_FORMAT(x) ((Evas_Object_Textblock_Node_Format *) (x)) + +struct _Evas_Object_Textblock_Paragraph +{ + EINA_INLIST; + Evas_Object_Textblock_Line *lines; + int x, y, w, h; + int par_no; +}; struct _Evas_Object_Textblock_Line { @@ -81,26 +89,26 @@ struct _Evas_Object_Textblock_Line struct _Evas_Object_Textblock_Item { EINA_INLIST; - Eina_Unicode *text; - Evas_Object_Textblock_Format *format; - Evas_Object_Textblock_Node *source_node; - int x, w, h; - int inset, baseline; - int source_pos; - unsigned char type; - Evas_BiDi_Props intl_props; + Eina_Unicode *text; + Evas_Object_Textblock_Format *format; + Evas_Object_Textblock_Node_Text *source_node; + int x, w, h; + int inset, baseline; + int source_pos; + unsigned char type; + Evas_BiDi_Props bidi_props; }; struct _Evas_Object_Textblock_Format_Item { EINA_INLIST; - const char *item; - Evas_Object_Textblock_Node *source_node; - int x, w, h, y, ascent, descent; - unsigned char vsize : 2; - unsigned char size : 2; - unsigned char formatme : 1; - unsigned char ___padding___ : 3; + const char *item; + Evas_Object_Textblock_Node_Format *source_node; + int x, w, h, y, ascent, descent; + unsigned char vsize : 2; + unsigned char size : 2; + unsigned char formatme : 1; + unsigned char ___padding___ : 3; }; struct _Evas_Object_Textblock_Format @@ -150,33 +158,35 @@ struct _Evas_Textblock_Style struct _Evas_Textblock_Cursor { - Evas_Object *obj; - int pos; - Evas_Object_Textblock_Node *node; - Eina_Bool eol : 1; + Evas_Object *obj; + int pos; + Evas_Object_Textblock_Node_Text *node; + }; struct _Evas_Object_Textblock { - DATA32 magic; - Evas_Textblock_Style *style; - Evas_Textblock_Cursor *cursor; - Eina_List *cursors; - Evas_Object_Textblock_Node *nodes; - Evas_Object_Textblock_Line *lines; - int last_w; + DATA32 magic; + Evas_Textblock_Style *style; + Evas_Textblock_Cursor *cursor; + Eina_List *cursors; + Evas_Object_Textblock_Node_Text *text_nodes; + Evas_Object_Textblock_Node_Format *format_nodes; + Evas_Object_Textblock_Paragraph *paragraphs; + Evas_Object_Textblock_Line *lines; + int last_w; struct { - int l, r, t, b; + int l, r, t, b; } style_pad; - char *markup_text; - void *engine_data; - const char *repch; + char *markup_text; + void *engine_data; + const char *repch; struct { - int w, h; - unsigned char valid : 1; + int w, h; + unsigned char valid : 1; } formatted, native; - unsigned char redraw : 1; - unsigned char changed : 1; + unsigned char redraw : 1; + unsigned char changed : 1; }; /* private methods for textblock objects */ @@ -252,6 +262,14 @@ static const Evas_Object_Func object_func = * @{ */ + +static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur); +static size_t _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt); +static Eina_Bool _evas_textblock_format_is_visible(const char *s); +static void _evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n); +static void _evas_textblock_node_format_free(Evas_Object_Textblock_Node_Format *n); +static void _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n); +static void _evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj); /* styles */ static void _style_clear(Evas_Textblock_Style *ts) @@ -315,14 +333,21 @@ _nodes_clear(const Evas_Object *obj) Evas_Object_Textblock *o; o = (Evas_Object_Textblock *)(obj->object_data); - while (o->nodes) + while (o->text_nodes) { - Evas_Object_Textblock_Node *n; + Evas_Object_Textblock_Node_Text *n; - n = (Evas_Object_Textblock_Node *)o->nodes; - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - _NODE_STRBUF_FREE(n); - free(n); + n = o->text_nodes; + o->text_nodes = _NODE_TEXT(eina_inlist_remove(EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n))); + _evas_textblock_node_text_free(n); + } + while (o->format_nodes) + { + Evas_Object_Textblock_Node_Format *n; + + n = o->format_nodes; + o->format_nodes = _NODE_FORMAT(eina_inlist_remove(EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n))); + _evas_textblock_node_format_free(n); } } @@ -343,26 +368,23 @@ _line_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln) { while (ln->items) { - Evas_Object_Textblock_Item *it; + Evas_Object_Textblock_Item *it; - it = (Evas_Object_Textblock_Item *)ln->items; - ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items)); - if (it->text) free(it->text); -#ifdef BIDI_SUPPORT - evas_bidi_props_clean(&it->intl_props); -#endif - _format_unref_free(obj, it->format); - free(it); + it = (Evas_Object_Textblock_Item *)ln->items; + ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items)); + if (it->text) free(it->text); + _format_unref_free(obj, it->format); + free(it); } while (ln->format_items) { - Evas_Object_Textblock_Format_Item *fi; + Evas_Object_Textblock_Format_Item *fi; - fi = (Evas_Object_Textblock_Format_Item *)ln->format_items; - ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->format_items), - EINA_INLIST_GET(ln->format_items)); - if (fi->item) eina_stringshare_del(fi->item); - free(fi); + fi = (Evas_Object_Textblock_Format_Item *)ln->format_items; + ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_remove(EINA_INLIST_GET(ln->format_items), + EINA_INLIST_GET(ln->format_items)); + if (fi->item) eina_stringshare_del(fi->item); + free(fi); } if (ln) free(ln); } @@ -372,85 +394,11 @@ _lines_clear(const Evas_Object *obj, Evas_Object_Textblock_Line *lines) { while (lines) { - Evas_Object_Textblock_Line *ln; + Evas_Object_Textblock_Line *ln; - ln = (Evas_Object_Textblock_Line *)lines; - lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(lines), EINA_INLIST_GET(ln)); - _line_free(obj, ln); - } -} - -static void -_nodes_adjacent_merge(const Evas_Object *obj, Evas_Object_Textblock_Node *n1) -{ - Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n0, *n2; - Eina_List *l; - Evas_Textblock_Cursor *data; - int plen; - - if (n1->type != NODE_TEXT) return; - o = (Evas_Object_Textblock *)(obj->object_data); - n0 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->prev; - n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next; - if ((n0) && (n0->type == NODE_TEXT)) - { - plen = eina_ustrbuf_length_get(n0->data.text.unicode); - eina_ustrbuf_append_length(n0->data.text.unicode, eina_ustrbuf_string_get(n1->data.text.unicode), - eina_ustrbuf_length_get(n1->data.text.unicode)); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove - (EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1)); -// (EINA_INLIST_GET(n0))->next = EINA_INLIST_GET(n2); -// if (n2) (EINA_INLIST_GET(n2))->prev = EINA_INLIST_GET(n0); - // fix any cursors in n1 - if (n1 == o->cursor->node) - { - o->cursor->node = n0; - o->cursor->pos += plen; - } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if (n1 == data->node) - { - data->node = n0; - data->pos += plen; - } - } - if (n1->data.text.unicode) eina_ustrbuf_free(n1->data.text.unicode); - if (n1->data.text.utf8) free(n1->data.text.utf8); - free(n1); - n1 = n0; - n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next; - } - if ((n2) && (n2->type == NODE_TEXT)) - { - n0 = n1; - n1 = n2; - n2 = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->next; - plen = eina_ustrbuf_length_get(n0->data.text.unicode); - eina_ustrbuf_append_length(n0->data.text.unicode, eina_ustrbuf_string_get(n1->data.text.unicode), - eina_ustrbuf_length_get(n1->data.text.unicode)); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove - (EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1)); -// (EINA_INLIST_GET(n0))->next = EINA_INLIST_GET(n2); -// if (n2) (EINA_INLIST_GET(n2))->prev = EINA_INLIST_GET(n0); - // fix any cursors in n1 - if (n1 == o->cursor->node) - { - o->cursor->node = n0; - o->cursor->pos += plen; - } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if (n1 == data->node) - { - data->node = n0; - data->pos += plen; - } - } - if (n1->data.text.unicode) eina_ustrbuf_free(n1->data.text.unicode); - if (n1->data.text.utf8) free(n1->data.text.utf8); - free(n1); + ln = (Evas_Object_Textblock_Line *)lines; + lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(lines), EINA_INLIST_GET(ln)); + _line_free(obj, ln); } } @@ -461,155 +409,155 @@ _nodes_adjacent_merge(const Evas_Object *obj, Evas_Object_Textblock_Node *n1) * contains the offsets to the tokens for space efficiency. */ static const char escape_strings[] = - /* most common escaped stuff */ - " \0" "\x20\0" /* NOTE: this here to avoid escaping to   */ - " \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 */ - ""\0" "\x22\0" - "&\0" "\x26\0" - "<\0" "\x3c\0" - ">\0" "\x3e\0" - /* all the rest */ - "¡\0" "\xc2\xa1\0" - "¢\0" "\xc2\xa2\0" - "£\0" "\xc2\xa3\0" - "¤\0" "\xc2\xa4\0" - "¥\0" "\xc2\xa5\0" - "¦\0" "\xc2\xa6\0" - "§\0" "\xc2\xa7\0" - "¨\0" "\xc2\xa8\0" - "©\0" "\xc2\xa9\0" - "ª\0" "\xc2\xaa\0" - "«\0" "\xc2\xab\0" - "¬\0" "\xc2\xac\0" - "®\0" "\xc2\xae\0" - "¯\0" "\xc2\xaf\0" - "°\0" "\xc2\xb0\0" - "±\0" "\xc2\xb1\0" - "²\0" "\xc2\xb2\0" - "³\0" "\xc2\xb3\0" - "´\0" "\xc2\xb4\0" - "µ\0" "\xc2\xb5\0" - "¶\0" "\xc2\xb6\0" - "·\0" "\xc2\xb7\0" - "¸\0" "\xc2\xb8\0" - "¹\0" "\xc2\xb9\0" - "º\0" "\xc2\xba\0" - "»\0" "\xc2\xbb\0" - "¼\0" "\xc2\xbc\0" - "½\0" "\xc2\xbd\0" - "¾\0" "\xc2\xbe\0" - "¿\0" "\xc2\xbf\0" - "À\0" "\xc3\x80\0" - "Á\0" "\xc3\x81\0" - "Â\0" "\xc3\x82\0" - "Ã\0" "\xc3\x83\0" - "Ä\0" "\xc3\x84\0" - "Å\0" "\xc3\x85\0" - "&Aelig;\0" "\xc3\x86\0" - "Ç\0" "\xc3\x87\0" - "È\0" "\xc3\x88\0" - "É\0" "\xc3\x89\0" - "Ê\0" "\xc3\x8a\0" - "Ë\0" "\xc3\x8b\0" - "Ì\0" "\xc3\x8c\0" - "Í\0" "\xc3\x8d\0" - "Î\0" "\xc3\x8e\0" - "Ï\0" "\xc3\x8f\0" - "&Eth;\0" "\xc3\x90\0" - "Ñ\0" "\xc3\x91\0" - "Ò\0" "\xc3\x92\0" - "Ó\0" "\xc3\x93\0" - "Ô\0" "\xc3\x94\0" - "Õ\0" "\xc3\x95\0" - "Ö\0" "\xc3\x96\0" - "×\0" "\xc3\x97\0" - "Ø\0" "\xc3\x98\0" - "Ù\0" "\xc3\x99\0" - "Ú\0" "\xc3\x9a\0" - "Û\0" "\xc3\x9b\0" - "Ý\0" "\xc3\x9d\0" - "&Thorn;\0" "\xc3\x9e\0" - "ß\0" "\xc3\x9f\0" - "à\0" "\xc3\xa0\0" - "á\0" "\xc3\xa1\0" - "â\0" "\xc3\xa2\0" - "ã\0" "\xc3\xa3\0" - "ä\0" "\xc3\xa4\0" - "å\0" "\xc3\xa5\0" - "æ\0" "\xc3\xa6\0" - "ç\0" "\xc3\xa7\0" - "è\0" "\xc3\xa8\0" - "é\0" "\xc3\xa9\0" - "ê\0" "\xc3\xaa\0" - "ë\0" "\xc3\xab\0" - "ì\0" "\xc3\xac\0" - "í\0" "\xc3\xad\0" - "î\0" "\xc3\xae\0" - "ï\0" "\xc3\xaf\0" - "ð\0" "\xc3\xb0\0" - "ñ\0" "\xc3\xb1\0" - "ò\0" "\xc3\xb2\0" - "ó\0" "\xc3\xb3\0" - "ô\0" "\xc3\xb4\0" - "õ\0" "\xc3\xb5\0" - "ö\0" "\xc3\xb6\0" - "÷\0" "\xc3\xb7\0" - "ø\0" "\xc3\xb8\0" - "ù\0" "\xc3\xb9\0" - "ú\0" "\xc3\xba\0" - "û\0" "\xc3\xbb\0" - "ü\0" "\xc3\xbc\0" - "ý\0" "\xc3\xbd\0" - "þ\0" "\xc3\xbe\0" - "ÿ\0" "\xc3\xbf\0" - "α\0" "\xce\x91\0" - "β\0" "\xce\x92\0" - "γ\0" "\xce\x93\0" - "δ\0" "\xce\x94\0" - "ε\0" "\xce\x95\0" - "ζ\0" "\xce\x96\0" - "η\0" "\xce\x97\0" - "θ\0" "\xce\x98\0" - "ι\0" "\xce\x99\0" - "κ\0" "\xce\x9a\0" - "λ\0" "\xce\x9b\0" - "μ\0" "\xce\x9c\0" - "ν\0" "\xce\x9d\0" - "ξ\0" "\xce\x9e\0" - "ο\0" "\xce\x9f\0" - "π\0" "\xce\xa0\0" - "ρ\0" "\xce\xa1\0" - "σ\0" "\xce\xa3\0" - "τ\0" "\xce\xa4\0" - "υ\0" "\xce\xa5\0" - "φ\0" "\xce\xa6\0" - "χ\0" "\xce\xa7\0" - "ψ\0" "\xce\xa8\0" - "ω\0" "\xce\xa9\0" - "…\0" "\xe2\x80\xa6\0" - "€\0" "\xe2\x82\xac\0" - "←\0" "\xe2\x86\x90\0" - "↑\0" "\xe2\x86\x91\0" - "→\0" "\xe2\x86\x92\0" - "↓\0" "\xe2\x86\x93\0" - "↔\0" "\xe2\x86\x94\0" - "←\0" "\xe2\x87\x90\0" - "→\0" "\xe2\x87\x92\0" - "∀\0" "\xe2\x88\x80\0" - "∃\0" "\xe2\x88\x83\0" - "∇\0" "\xe2\x88\x87\0" - "∏\0" "\xe2\x88\x8f\0" - "∑\0" "\xe2\x88\x91\0" - "∧\0" "\xe2\x88\xa7\0" - "∨\0" "\xe2\x88\xa8\0" - "∫\0" "\xe2\x88\xab\0" - "≠\0" "\xe2\x89\xa0\0" - "≡\0" "\xe2\x89\xa1\0" - "⊕\0" "\xe2\x8a\x95\0" - "⊥\0" "\xe2\x8a\xa5\0" - "†\0" "\xe2\x80\xa0\0" - "‡\0" "\xe2\x80\xa1\0" - "•\0" "\xe2\x80\xa2\0" +/* most common escaped stuff */ +" \0" "\x20\0" /* NOTE: this here to avoid escaping to   */ +" \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 */ +""\0" "\x22\0" +"&\0" "\x26\0" +"<\0" "\x3c\0" +">\0" "\x3e\0" +/* all the rest */ +"¡\0" "\xc2\xa1\0" +"¢\0" "\xc2\xa2\0" +"£\0" "\xc2\xa3\0" +"¤\0" "\xc2\xa4\0" +"¥\0" "\xc2\xa5\0" +"¦\0" "\xc2\xa6\0" +"§\0" "\xc2\xa7\0" +"¨\0" "\xc2\xa8\0" +"©\0" "\xc2\xa9\0" +"ª\0" "\xc2\xaa\0" +"«\0" "\xc2\xab\0" +"¬\0" "\xc2\xac\0" +"®\0" "\xc2\xae\0" +"¯\0" "\xc2\xaf\0" +"°\0" "\xc2\xb0\0" +"±\0" "\xc2\xb1\0" +"²\0" "\xc2\xb2\0" +"³\0" "\xc2\xb3\0" +"´\0" "\xc2\xb4\0" +"µ\0" "\xc2\xb5\0" +"¶\0" "\xc2\xb6\0" +"·\0" "\xc2\xb7\0" +"¸\0" "\xc2\xb8\0" +"¹\0" "\xc2\xb9\0" +"º\0" "\xc2\xba\0" +"»\0" "\xc2\xbb\0" +"¼\0" "\xc2\xbc\0" +"½\0" "\xc2\xbd\0" +"¾\0" "\xc2\xbe\0" +"¿\0" "\xc2\xbf\0" +"À\0" "\xc3\x80\0" +"Á\0" "\xc3\x81\0" +"Â\0" "\xc3\x82\0" +"Ã\0" "\xc3\x83\0" +"Ä\0" "\xc3\x84\0" +"Å\0" "\xc3\x85\0" +"&Aelig;\0" "\xc3\x86\0" +"Ç\0" "\xc3\x87\0" +"È\0" "\xc3\x88\0" +"É\0" "\xc3\x89\0" +"Ê\0" "\xc3\x8a\0" +"Ë\0" "\xc3\x8b\0" +"Ì\0" "\xc3\x8c\0" +"Í\0" "\xc3\x8d\0" +"Î\0" "\xc3\x8e\0" +"Ï\0" "\xc3\x8f\0" +"&Eth;\0" "\xc3\x90\0" +"Ñ\0" "\xc3\x91\0" +"Ò\0" "\xc3\x92\0" +"Ó\0" "\xc3\x93\0" +"Ô\0" "\xc3\x94\0" +"Õ\0" "\xc3\x95\0" +"Ö\0" "\xc3\x96\0" +"×\0" "\xc3\x97\0" +"Ø\0" "\xc3\x98\0" +"Ù\0" "\xc3\x99\0" +"Ú\0" "\xc3\x9a\0" +"Û\0" "\xc3\x9b\0" +"Ý\0" "\xc3\x9d\0" +"&Thorn;\0" "\xc3\x9e\0" +"ß\0" "\xc3\x9f\0" +"à\0" "\xc3\xa0\0" +"á\0" "\xc3\xa1\0" +"â\0" "\xc3\xa2\0" +"ã\0" "\xc3\xa3\0" +"ä\0" "\xc3\xa4\0" +"å\0" "\xc3\xa5\0" +"æ\0" "\xc3\xa6\0" +"ç\0" "\xc3\xa7\0" +"è\0" "\xc3\xa8\0" +"é\0" "\xc3\xa9\0" +"ê\0" "\xc3\xaa\0" +"ë\0" "\xc3\xab\0" +"ì\0" "\xc3\xac\0" +"í\0" "\xc3\xad\0" +"î\0" "\xc3\xae\0" +"ï\0" "\xc3\xaf\0" +"ð\0" "\xc3\xb0\0" +"ñ\0" "\xc3\xb1\0" +"ò\0" "\xc3\xb2\0" +"ó\0" "\xc3\xb3\0" +"ô\0" "\xc3\xb4\0" +"õ\0" "\xc3\xb5\0" +"ö\0" "\xc3\xb6\0" +"÷\0" "\xc3\xb7\0" +"ø\0" "\xc3\xb8\0" +"ù\0" "\xc3\xb9\0" +"ú\0" "\xc3\xba\0" +"û\0" "\xc3\xbb\0" +"ü\0" "\xc3\xbc\0" +"ý\0" "\xc3\xbd\0" +"þ\0" "\xc3\xbe\0" +"ÿ\0" "\xc3\xbf\0" +"α\0" "\xce\x91\0" +"β\0" "\xce\x92\0" +"γ\0" "\xce\x93\0" +"δ\0" "\xce\x94\0" +"ε\0" "\xce\x95\0" +"ζ\0" "\xce\x96\0" +"η\0" "\xce\x97\0" +"θ\0" "\xce\x98\0" +"ι\0" "\xce\x99\0" +"κ\0" "\xce\x9a\0" +"λ\0" "\xce\x9b\0" +"μ\0" "\xce\x9c\0" +"ν\0" "\xce\x9d\0" +"ξ\0" "\xce\x9e\0" +"ο\0" "\xce\x9f\0" +"π\0" "\xce\xa0\0" +"ρ\0" "\xce\xa1\0" +"σ\0" "\xce\xa3\0" +"τ\0" "\xce\xa4\0" +"υ\0" "\xce\xa5\0" +"φ\0" "\xce\xa6\0" +"χ\0" "\xce\xa7\0" +"ψ\0" "\xce\xa8\0" +"ω\0" "\xce\xa9\0" +"…\0" "\xe2\x80\xa6\0" +"€\0" "\xe2\x82\xac\0" +"←\0" "\xe2\x86\x90\0" +"↑\0" "\xe2\x86\x91\0" +"→\0" "\xe2\x86\x92\0" +"↓\0" "\xe2\x86\x93\0" +"↔\0" "\xe2\x86\x94\0" +"←\0" "\xe2\x87\x90\0" +"→\0" "\xe2\x87\x92\0" +"∀\0" "\xe2\x88\x80\0" +"∃\0" "\xe2\x88\x83\0" +"∇\0" "\xe2\x88\x87\0" +"∏\0" "\xe2\x88\x8f\0" +"∑\0" "\xe2\x88\x91\0" +"∧\0" "\xe2\x88\xa7\0" +"∨\0" "\xe2\x88\xa8\0" +"∫\0" "\xe2\x88\xab\0" +"≠\0" "\xe2\x89\xa0\0" +"≡\0" "\xe2\x89\xa1\0" +"⊕\0" "\xe2\x8a\x95\0" +"⊥\0" "\xe2\x8a\xa5\0" +"†\0" "\xe2\x80\xa0\0" +"‡\0" "\xe2\x80\xa1\0" +"•\0" "\xe2\x80\xa2\0" ; @@ -633,19 +581,19 @@ _is_white(int c) * 3000 IDEOGRAPHIC SPACE */ if ( - (c == 0x20) || - ((c >= 0x9) && (c <= 0xd)) || - (c == 0x85) || - (c == 0xa0) || - (c == 0x1680) || - (c == 0x180e) || - ((c >= 0x2000) && (c <= 0x200a)) || - (c == 0x2028) || - (c == 0x2029) || - (c == 0x202f) || - (c == 0x205f) || - (c == 0x3000) - ) + (c == 0x20) || + ((c >= 0x9) && (c <= 0xd)) || + (c == 0x85) || + (c == 0xa0) || + (c == 0x1680) || + (c == 0x180e) || + ((c >= 0x2000) && (c <= 0x200a)) || + (c == 0x2028) || + (c == 0x2029) || + (c == 0x202f) || + (c == 0x205f) || + (c == 0x3000) + ) return 1; return 0; } @@ -665,43 +613,43 @@ _clean_white(int clean_start, int clean_end, char *str) ok = 1; while (*p != 0) { - pwhite = white; - if (_is_white(*p)) white = 1; - else white = 0; - if ((pwhite) && (white)) ok = 0; - else - { - if (!clean_start) - { - if ((start) && (pwhite) && (!white)) - { -// *p2 = ' '; -// p2++; - } - } - ok = 1; - if (!white) start = 0; - } - if (clean_start) - { - if ((start) && (ok)) ok = 0; - } - if (ok) - { - *p2 = *p; - p2++; - } - p++; + pwhite = white; + if (_is_white(*p)) white = 1; + else white = 0; + if ((pwhite) && (white)) ok = 0; + else + { + if (!clean_start) + { + if ((start) && (pwhite) && (!white)) + { + // *p2 = ' '; + // p2++; + } + } + ok = 1; + if (!white) start = 0; + } + if (clean_start) + { + if ((start) && (ok)) ok = 0; + } + if (ok) + { + *p2 = *p; + p2++; + } + p++; } *p2 = 0; if (clean_end) { - while (p2 > str2) - { - p2--; - if (!(isspace(*p2) || _is_white(*p2))) break; - *p2 = 0; - } + while (p2 > str2) + { + p2--; + if (!(isspace(*p2) || _is_white(*p2))) break; + *p2 = 0; + } } free(str); return str2; @@ -713,13 +661,13 @@ _append_text_run(Evas_Object_Textblock *o, const char *s, const char *p) { if ((s) && (p > s)) { - char *ts; + char *ts; - ts = alloca(p - s + 1); - strncpy(ts, s, p - s); - ts[p - s] = 0; - ts = _clean_white(0, 0, ts); - evas_textblock_cursor_text_append(o->cursor, ts); + ts = alloca(p - s + 1); + strncpy(ts, s, p - s); + ts[p - s] = 0; + ts = _clean_white(0, 0, ts); + evas_textblock_cursor_text_append(o->cursor, ts); } } @@ -728,13 +676,13 @@ _prepend_text_run(Evas_Object_Textblock *o, const char *s, const char *p) { if ((s) && (p > s)) { - char *ts; + char *ts; - ts = alloca(p - s + 1); - strncpy(ts, s, p - s); - ts[p - s] = 0; - ts = _clean_white(0, 0, ts); - evas_textblock_cursor_text_prepend(o->cursor, ts); + ts = alloca(p - s + 1); + strncpy(ts, s, p - s); + ts[p - s] = 0; + ts = _clean_white(0, 0, ts); + evas_textblock_cursor_text_prepend(o->cursor, ts); } } @@ -758,38 +706,38 @@ _format_color_parse(const char *str, unsigned char *r, unsigned char *g, unsigne if (slen == 7) /* #RRGGBB */ { - *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); - *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); - *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); - *a = 0xff; + *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); + *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); + *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); + *a = 0xff; } else if (slen == 9) /* #RRGGBBAA */ { - *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); - *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); - *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); - *a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8])); + *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); + *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); + *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); + *a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8])); } else if (slen == 4) /* #RGB */ { - *r = _hex_string_get(str[1]); - *r = (*r << 4) | *r; - *g = _hex_string_get(str[2]); - *g = (*g << 4) | *g; - *b = _hex_string_get(str[3]); - *b = (*b << 4) | *b; - *a = 0xff; + *r = _hex_string_get(str[1]); + *r = (*r << 4) | *r; + *g = _hex_string_get(str[2]); + *g = (*g << 4) | *g; + *b = _hex_string_get(str[3]); + *b = (*b << 4) | *b; + *a = 0xff; } else if (slen == 5) /* #RGBA */ { - *r = _hex_string_get(str[1]); - *r = (*r << 4) | *r; - *g = _hex_string_get(str[2]); - *g = (*g << 4) | *g; - *b = _hex_string_get(str[3]); - *b = (*b << 4) | *b; - *a = _hex_string_get(str[4]); - *a = (*a << 4) | *a; + *r = _hex_string_get(str[1]); + *r = (*r << 4) | *r; + *g = _hex_string_get(str[2]); + *g = (*g << 4) | *g; + *b = _hex_string_get(str[3]); + *b = (*b << 4) | *b; + *a = _hex_string_get(str[4]); + *a = (*a << 4) | *a; } *r = (*r * *a) / 255; *g = (*g * *a) / 255; @@ -829,47 +777,79 @@ static const char *linefillstr = NULL; static void _format_command_init(void) { - if (fontstr) return; - fontstr = eina_stringshare_add("font"); - font_fallbacksstr = eina_stringshare_add("font_fallbacks"); - font_sizestr = eina_stringshare_add("font_size"); - font_sourcestr = eina_stringshare_add("font_source"); - colorstr = eina_stringshare_add("color"); - underline_colorstr = eina_stringshare_add("underline_color"); - underline2_colorstr = eina_stringshare_add("underline2_color"); - outline_colorstr = eina_stringshare_add("outline_color"); - shadow_colorstr = eina_stringshare_add("shadow_color"); - glow_colorstr = eina_stringshare_add("glow_color"); - glow2_colorstr = eina_stringshare_add("glow2_color"); - backing_colorstr = eina_stringshare_add("backing_color"); - strikethrough_colorstr = eina_stringshare_add("strikethrough_color"); - alignstr = eina_stringshare_add("align"); - valignstr = eina_stringshare_add("valign"); - wrapstr = eina_stringshare_add("wrap"); - left_marginstr = eina_stringshare_add("left_margin"); - right_marginstr = eina_stringshare_add("right_margin"); - underlinestr = eina_stringshare_add("underline"); - strikethroughstr = eina_stringshare_add("strikethrough"); - backingstr = eina_stringshare_add("backing"); - stylestr = eina_stringshare_add("style"); - tabstopsstr = eina_stringshare_add("tabstops"); - linesizestr = eina_stringshare_add("linesize"); - linerelsizestr = eina_stringshare_add("linerelsize"); - linegapstr = eina_stringshare_add("linegap"); - linerelgapstr = eina_stringshare_add("linerelgap"); - itemstr = eina_stringshare_add("item"); - linefillstr = eina_stringshare_add("linefill"); + if (!fontstr) + { + fontstr = eina_stringshare_add("font"); + font_fallbacksstr = eina_stringshare_add("font_fallbacks"); + font_sizestr = eina_stringshare_add("font_size"); + font_sourcestr = eina_stringshare_add("font_source"); + colorstr = eina_stringshare_add("color"); + underline_colorstr = eina_stringshare_add("underline_color"); + underline2_colorstr = eina_stringshare_add("underline2_color"); + outline_colorstr = eina_stringshare_add("outline_color"); + shadow_colorstr = eina_stringshare_add("shadow_color"); + glow_colorstr = eina_stringshare_add("glow_color"); + glow2_colorstr = eina_stringshare_add("glow2_color"); + backing_colorstr = eina_stringshare_add("backing_color"); + strikethrough_colorstr = eina_stringshare_add("strikethrough_color"); + alignstr = eina_stringshare_add("align"); + valignstr = eina_stringshare_add("valign"); + wrapstr = eina_stringshare_add("wrap"); + left_marginstr = eina_stringshare_add("left_margin"); + right_marginstr = eina_stringshare_add("right_margin"); + underlinestr = eina_stringshare_add("underline"); + strikethroughstr = eina_stringshare_add("strikethrough"); + backingstr = eina_stringshare_add("backing"); + stylestr = eina_stringshare_add("style"); + tabstopsstr = eina_stringshare_add("tabstops"); + linesizestr = eina_stringshare_add("linesize"); + linerelsizestr = eina_stringshare_add("linerelsize"); + linegapstr = eina_stringshare_add("linegap"); + linerelgapstr = eina_stringshare_add("linerelgap"); + itemstr = eina_stringshare_add("item"); + linefillstr = eina_stringshare_add("linefill"); + } + else + { + eina_stringshare_ref(fontstr); + eina_stringshare_ref(font_fallbacksstr); + eina_stringshare_ref(font_sizestr); + eina_stringshare_ref(font_sourcestr); + eina_stringshare_ref(colorstr); + eina_stringshare_ref(underline_colorstr); + eina_stringshare_ref(underline2_colorstr); + eina_stringshare_ref(outline_colorstr); + eina_stringshare_ref(shadow_colorstr); + eina_stringshare_ref(glow_colorstr); + eina_stringshare_ref(glow2_colorstr); + eina_stringshare_ref(backing_colorstr); + eina_stringshare_ref(strikethrough_colorstr); + eina_stringshare_ref(alignstr); + eina_stringshare_ref(valignstr); + eina_stringshare_ref(wrapstr); + eina_stringshare_ref(left_marginstr); + eina_stringshare_ref(right_marginstr); + eina_stringshare_ref(underlinestr); + eina_stringshare_ref(strikethroughstr); + eina_stringshare_ref(backingstr); + eina_stringshare_ref(stylestr); + eina_stringshare_ref(tabstopsstr); + eina_stringshare_ref(linesizestr); + eina_stringshare_ref(linerelsizestr); + eina_stringshare_ref(linegapstr); + eina_stringshare_ref(linerelgapstr); + eina_stringshare_ref(itemstr); + eina_stringshare_ref(linefillstr); + } } -/* FIXME: ATM we don't really use shutdown and init in a sane way - * we just call init EVERY TIME and shutdown the same, and hope for the best. - * There's currently a hack returning on both if already init, more correct would - * be reffing/unreffing or even better, don't init/deinit all the time! - */ static void _format_command_shutdown(void) { return; + /*FIXME: should del, the problem is that it's not possible to know the ref + * count so it's not possible to know when the last textblock finished. + * Should probably just add a refcount here */ eina_stringshare_del(fontstr); eina_stringshare_del(font_fallbacksstr); eina_stringshare_del(font_sizestr); @@ -927,231 +907,231 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char _format_clean_param(tmp_param, param); if (cmd == fontstr) { - if ((!fmt->font.name) || - ((fmt->font.name) && (strcmp(fmt->font.name, tmp_param)))) - { - if (fmt->font.name) eina_stringshare_del(fmt->font.name); - fmt->font.name = eina_stringshare_add(tmp_param); - new_font = 1; - } + if ((!fmt->font.name) || + ((fmt->font.name) && (strcmp(fmt->font.name, tmp_param)))) + { + if (fmt->font.name) eina_stringshare_del(fmt->font.name); + fmt->font.name = eina_stringshare_add(tmp_param); + new_font = 1; + } } else if (cmd == font_fallbacksstr) { - if ((!fmt->font.fallbacks) || - ((fmt->font.fallbacks) && (strcmp(fmt->font.fallbacks, tmp_param)))) - { - /* policy - when we say "fallbacks" do we prepend and use prior - * fallbacks... or should we replace. for now we replace - */ - if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks); - fmt->font.fallbacks = eina_stringshare_add(tmp_param); - new_font = 1; - } + if ((!fmt->font.fallbacks) || + ((fmt->font.fallbacks) && (strcmp(fmt->font.fallbacks, tmp_param)))) + { + /* policy - when we say "fallbacks" do we prepend and use prior + * fallbacks... or should we replace. for now we replace + */ + if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks); + fmt->font.fallbacks = eina_stringshare_add(tmp_param); + new_font = 1; + } } else if (cmd == font_sizestr) { - int v; + int v; - v = atoi(tmp_param); - if (v != fmt->font.size) - { - fmt->font.size = v; - new_font = 1; - } + v = atoi(tmp_param); + if (v != fmt->font.size) + { + fmt->font.size = v; + new_font = 1; + } } else if (cmd == font_sourcestr) { - if ((!fmt->font.source) || - ((fmt->font.source) && (strcmp(fmt->font.source, tmp_param)))) - { - if (fmt->font.source) eina_stringshare_del(fmt->font.source); - fmt->font.source = eina_stringshare_add(tmp_param); - new_font = 1; - } + if ((!fmt->font.source) || + ((fmt->font.source) && (strcmp(fmt->font.source, tmp_param)))) + { + if (fmt->font.source) eina_stringshare_del(fmt->font.source); + fmt->font.source = eina_stringshare_add(tmp_param); + new_font = 1; + } } else if (cmd == colorstr) _format_color_parse(tmp_param, - &(fmt->color.normal.r), &(fmt->color.normal.g), - &(fmt->color.normal.b), &(fmt->color.normal.a)); + &(fmt->color.normal.r), &(fmt->color.normal.g), + &(fmt->color.normal.b), &(fmt->color.normal.a)); else if (cmd == underline_colorstr) _format_color_parse(tmp_param, - &(fmt->color.underline.r), &(fmt->color.underline.g), - &(fmt->color.underline.b), &(fmt->color.underline.a)); + &(fmt->color.underline.r), &(fmt->color.underline.g), + &(fmt->color.underline.b), &(fmt->color.underline.a)); else if (cmd == underline2_colorstr) _format_color_parse(tmp_param, - &(fmt->color.underline2.r), &(fmt->color.underline2.g), - &(fmt->color.underline2.b), &(fmt->color.underline2.a)); + &(fmt->color.underline2.r), &(fmt->color.underline2.g), + &(fmt->color.underline2.b), &(fmt->color.underline2.a)); else if (cmd == outline_colorstr) _format_color_parse(tmp_param, - &(fmt->color.outline.r), &(fmt->color.outline.g), - &(fmt->color.outline.b), &(fmt->color.outline.a)); + &(fmt->color.outline.r), &(fmt->color.outline.g), + &(fmt->color.outline.b), &(fmt->color.outline.a)); else if (cmd == shadow_colorstr) _format_color_parse(tmp_param, - &(fmt->color.shadow.r), &(fmt->color.shadow.g), - &(fmt->color.shadow.b), &(fmt->color.shadow.a)); + &(fmt->color.shadow.r), &(fmt->color.shadow.g), + &(fmt->color.shadow.b), &(fmt->color.shadow.a)); else if (cmd == glow_colorstr) _format_color_parse(tmp_param, - &(fmt->color.glow.r), &(fmt->color.glow.g), - &(fmt->color.glow.b), &(fmt->color.glow.a)); + &(fmt->color.glow.r), &(fmt->color.glow.g), + &(fmt->color.glow.b), &(fmt->color.glow.a)); else if (cmd == glow2_colorstr) _format_color_parse(tmp_param, - &(fmt->color.glow2.r), &(fmt->color.glow2.g), - &(fmt->color.glow2.b), &(fmt->color.glow2.a)); + &(fmt->color.glow2.r), &(fmt->color.glow2.g), + &(fmt->color.glow2.b), &(fmt->color.glow2.a)); else if (cmd == backing_colorstr) _format_color_parse(tmp_param, - &(fmt->color.backing.r), &(fmt->color.backing.g), - &(fmt->color.backing.b), &(fmt->color.backing.a)); + &(fmt->color.backing.r), &(fmt->color.backing.g), + &(fmt->color.backing.b), &(fmt->color.backing.a)); else if (cmd == strikethrough_colorstr) _format_color_parse(tmp_param, - &(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g), - &(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a)); + &(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g), + &(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a)); else if (cmd == alignstr) { - if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5; - else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5; - else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0; - else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0; - else - { - char *endptr = NULL; - double val = strtod(tmp_param, &endptr); - if (endptr) - { - while (*endptr && _is_white(*endptr)) - endptr++; - if (*endptr == '%') - val /= 100.0; - } - fmt->halign = val;; - if (fmt->halign < 0.0) fmt->halign = 0.0; - else if (fmt->halign > 1.0) fmt->halign = 1.0; - } + if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5; + else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5; + else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0; + else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0; + else + { + char *endptr = NULL; + double val = strtod(tmp_param, &endptr); + if (endptr) + { + while (*endptr && _is_white(*endptr)) + endptr++; + if (*endptr == '%') + val /= 100.0; + } + fmt->halign = val;; + if (fmt->halign < 0.0) fmt->halign = 0.0; + else if (fmt->halign > 1.0) fmt->halign = 1.0; + } } else if (cmd == valignstr) { if (!strcmp(tmp_param, "top")) fmt->valign = 0.0; - else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5; - else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5; - else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0; - else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0; - else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0; - else - { - char *endptr = NULL; - double val = strtod(tmp_param, &endptr); - if (endptr) - { - while (*endptr && _is_white(*endptr)) - endptr++; - if (*endptr == '%') - val /= 100.0; - } - fmt->valign = val; - if (fmt->valign < 0.0) fmt->valign = 0.0; - else if (fmt->valign > 1.0) fmt->valign = 1.0; - } + else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5; + else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5; + else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0; + else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0; + else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0; + else + { + char *endptr = NULL; + double val = strtod(tmp_param, &endptr); + if (endptr) + { + while (*endptr && _is_white(*endptr)) + endptr++; + if (*endptr == '%') + val /= 100.0; + } + fmt->valign = val; + if (fmt->valign < 0.0) fmt->valign = 0.0; + else if (fmt->valign > 1.0) fmt->valign = 1.0; + } } else if (cmd == wrapstr) { - if (!strcmp(tmp_param, "word")) - { - fmt->wrap_word = 1; - fmt->wrap_char = 0; - } - else if (!strcmp(tmp_param, "char")) - { - fmt->wrap_word = 0; - fmt->wrap_char = 1; - } - else - { - fmt->wrap_word = 0; - fmt->wrap_char = 0; - } + if (!strcmp(tmp_param, "word")) + { + fmt->wrap_word = 1; + fmt->wrap_char = 0; + } + else if (!strcmp(tmp_param, "char")) + { + fmt->wrap_word = 0; + fmt->wrap_char = 1; + } + else + { + fmt->wrap_word = 0; + fmt->wrap_char = 0; + } } else if (cmd == left_marginstr) { - if (!strcmp(tmp_param, "reset")) - fmt->margin.l = 0; - else - { - if (tmp_param[0] == '+') - fmt->margin.l += atoi(&(tmp_param[1])); - else if (tmp_param[0] == '-') - fmt->margin.l -= atoi(&(tmp_param[1])); - else - fmt->margin.l = atoi(tmp_param); - if (fmt->margin.l < 0) fmt->margin.l = 0; - } + if (!strcmp(tmp_param, "reset")) + fmt->margin.l = 0; + else + { + if (tmp_param[0] == '+') + fmt->margin.l += atoi(&(tmp_param[1])); + else if (tmp_param[0] == '-') + fmt->margin.l -= atoi(&(tmp_param[1])); + else + fmt->margin.l = atoi(tmp_param); + if (fmt->margin.l < 0) fmt->margin.l = 0; + } } else if (cmd == right_marginstr) { - if (!strcmp(tmp_param, "reset")) - fmt->margin.r = 0; - else - { - if (tmp_param[0] == '+') - fmt->margin.r += atoi(&(tmp_param[1])); - else if (tmp_param[0] == '-') - fmt->margin.r -= atoi(&(tmp_param[1])); - else - fmt->margin.r = atoi(tmp_param); - if (fmt->margin.r < 0) fmt->margin.r = 0; - } + if (!strcmp(tmp_param, "reset")) + fmt->margin.r = 0; + else + { + if (tmp_param[0] == '+') + fmt->margin.r += atoi(&(tmp_param[1])); + else if (tmp_param[0] == '-') + fmt->margin.r -= atoi(&(tmp_param[1])); + else + fmt->margin.r = atoi(tmp_param); + if (fmt->margin.r < 0) fmt->margin.r = 0; + } } else if (cmd == underlinestr) { - if (!strcmp(tmp_param, "off")) - { - fmt->underline = 0; - fmt->underline2 = 0; - } - else if ((!strcmp(tmp_param, "on")) || - (!strcmp(tmp_param, "single"))) - { - fmt->underline = 1; - fmt->underline2 = 0; - } - else if (!strcmp(tmp_param, "double")) - { - fmt->underline = 1; - fmt->underline2 = 1; - } + if (!strcmp(tmp_param, "off")) + { + fmt->underline = 0; + fmt->underline2 = 0; + } + else if ((!strcmp(tmp_param, "on")) || + (!strcmp(tmp_param, "single"))) + { + fmt->underline = 1; + fmt->underline2 = 0; + } + else if (!strcmp(tmp_param, "double")) + { + fmt->underline = 1; + fmt->underline2 = 1; + } } else if (cmd == strikethroughstr) { - if (!strcmp(tmp_param, "off")) - fmt->strikethrough = 0; - else if (!strcmp(tmp_param, "on")) - fmt->strikethrough = 1; + if (!strcmp(tmp_param, "off")) + fmt->strikethrough = 0; + else if (!strcmp(tmp_param, "on")) + fmt->strikethrough = 1; } else if (cmd == backingstr) { - if (!strcmp(tmp_param, "off")) - fmt->backing = 0; - else if (!strcmp(tmp_param, "on")) - fmt->backing = 1; + if (!strcmp(tmp_param, "off")) + fmt->backing = 0; + else if (!strcmp(tmp_param, "on")) + fmt->backing = 1; } else if (cmd == stylestr) { - if (!strcmp(tmp_param, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN; - else if (!strcmp(tmp_param, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN; - else if (!strcmp(tmp_param, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN; - else if (!strcmp(tmp_param, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW; - else if (!strcmp(tmp_param, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE; - else if (!strcmp(tmp_param, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE; - else if (!strcmp(tmp_param, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW; - else if (!strcmp(tmp_param, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW; - else if (!strcmp(tmp_param, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW; - else if (!strcmp(tmp_param, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW; - else if (!strcmp(tmp_param, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW; - else if (!strcmp(tmp_param, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW; - else fmt->style = EVAS_TEXT_STYLE_PLAIN; + if (!strcmp(tmp_param, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN; + else if (!strcmp(tmp_param, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN; + else if (!strcmp(tmp_param, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN; + else if (!strcmp(tmp_param, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW; + else if (!strcmp(tmp_param, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE; + else if (!strcmp(tmp_param, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE; + else if (!strcmp(tmp_param, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW; + else if (!strcmp(tmp_param, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW; + else if (!strcmp(tmp_param, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW; + else if (!strcmp(tmp_param, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW; + else if (!strcmp(tmp_param, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW; + else if (!strcmp(tmp_param, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW; + else fmt->style = EVAS_TEXT_STYLE_PLAIN; } else if (cmd == tabstopsstr) { - fmt->tabstops = atoi(tmp_param); - if (fmt->tabstops < 1) fmt->tabstops = 1; + fmt->tabstops = atoi(tmp_param); + if (fmt->tabstops < 1) fmt->tabstops = 1; } else if (cmd == linesizestr) { @@ -1160,18 +1140,18 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char } else if (cmd == linerelsizestr) { - char *endptr = NULL; - double val = strtod(tmp_param, &endptr); - if (endptr) - { - while (*endptr && _is_white(*endptr)) - endptr++; - if (*endptr == '%') - { - fmt->linerelsize = val / 100.0; - fmt->linesize = 0; - if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0; - } + char *endptr = NULL; + double val = strtod(tmp_param, &endptr); + if (endptr) + { + while (*endptr && _is_white(*endptr)) + endptr++; + if (*endptr == '%') + { + fmt->linerelsize = val / 100.0; + fmt->linesize = 0; + if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0; + } } } else if (cmd == linegapstr) @@ -1181,18 +1161,18 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char } else if (cmd == linerelgapstr) { - char *endptr = NULL; - double val = strtod(tmp_param, &endptr); - if (endptr) - { - while (*endptr && _is_white(*endptr)) - endptr++; - if (*endptr == '%') - { - fmt->linerelgap = val / 100.0; - fmt->linegap = 0; - if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0; - } + char *endptr = NULL; + double val = strtod(tmp_param, &endptr); + if (endptr) + { + while (*endptr && _is_white(*endptr)) + endptr++; + if (*endptr == '%') + { + fmt->linerelgap = val / 100.0; + fmt->linegap = 0; + if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0; + } } } else if (cmd == itemstr) @@ -1202,46 +1182,46 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char } else if (cmd == linefillstr) { - char *endptr = NULL; - double val = strtod(tmp_param, &endptr); - if (endptr) - { - while (*endptr && _is_white(*endptr)) - endptr++; - if (*endptr == '%') - { - fmt->linefill = val / 100.0; - if (fmt->linefill < 0.0) fmt->linefill = 0.0; - } + char *endptr = NULL; + double val = strtod(tmp_param, &endptr); + if (endptr) + { + while (*endptr && _is_white(*endptr)) + endptr++; + if (*endptr == '%') + { + fmt->linefill = val / 100.0; + if (fmt->linefill < 0.0) fmt->linefill = 0.0; + } } } if (new_font) { - void *of; - char *buf = NULL; + void *of; + char *buf = NULL; - of = fmt->font.font; - if ((fmt->font.name) && (fmt->font.fallbacks)) - { - buf = malloc(strlen(fmt->font.name) + 1 + strlen(fmt->font.fallbacks) + 1); - strcpy(buf, fmt->font.name); - strcat(buf, ","); - strcat(buf, fmt->font.fallbacks); - } - else if (fmt->font.name) - buf = strdup(fmt->font.name); + of = fmt->font.font; + if ((fmt->font.name) && (fmt->font.fallbacks)) + { + buf = malloc(strlen(fmt->font.name) + 1 + strlen(fmt->font.fallbacks) + 1); + strcpy(buf, fmt->font.name); + strcat(buf, ","); + strcat(buf, fmt->font.fallbacks); + } + else if (fmt->font.name) + buf = strdup(fmt->font.name); - fmt->font.font = evas_font_load(obj->layer->evas, - buf, fmt->font.source, - (int)(((double)fmt->font.size) * obj->cur.scale)); - if (buf) free(buf); - if (of) evas_font_free(obj->layer->evas, of); + fmt->font.font = evas_font_load(obj->layer->evas, + buf, fmt->font.source, + (int)(((double)fmt->font.size) * obj->cur.scale)); + if (buf) free(buf); + if (of) evas_font_free(obj->layer->evas, of); } } static int -_format_is_param(char *item) +_format_is_param(const char *item) { if (strchr(item, '=')) return 1; return 0; @@ -1250,7 +1230,7 @@ _format_is_param(char *item) static void _format_param_parse(char *item, const char **key, const char **val) { - char *p; + char *p, *tmp; const char *k, *v; p = strchr(item, '='); @@ -1259,51 +1239,54 @@ _format_param_parse(char *item, const char **key, const char **val) *key = k; *p = '='; p++; + /* Null terminate before the spaces */ + tmp = strchr(item, ' '); + if (tmp) *tmp = '\0'; v = eina_stringshare_add(p); *val = v; } -static char * -_format_parse(char **s) +static const char * +_format_parse(const char **s) { - char *p, *item; - char *s1 = NULL, *s2 = NULL; + const char *p, *item; + const char *s1 = NULL, *s2 = NULL; p = *s; if (*p == 0) return NULL; for (;;) { - if (!s1) - { - if (*p != ' ') s1 = p; - if (*p == 0) break; - } - else if (!s2) - { - if ((p > *s) && (p[-1] != '\\')) - { - if (*p == ' ') s2 = p; - } - if (*p == 0) s2 = p; - } - p++; - if (s1 && s2) - { - item = s1; + if (!s1) + { + if (*p != ' ') s1 = p; + if (*p == 0) break; + } + else if (!s2) + { + if ((p > *s) && (p[-1] != '\\')) + { + if (*p == ' ') s2 = p; + } + if (*p == 0) s2 = p; + } + p++; + if (s1 && s2) + { + item = s1; - *s = s2; - return item; - } + *s = s2; + return item; + } } *s = p; return NULL; } static void -_format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, char *str) +_format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *str) { - char *s; - char *item; + const char *s; + const char *item; s = str; @@ -1312,22 +1295,23 @@ _format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, char *str) while ((item = _format_parse(&s))) { - char tmp_delim = *s; - *s = '\0'; - if (_format_is_param(item)) - { - const char *key = NULL, *val = NULL; + char tmp_delim = *s; + if (_format_is_param(item)) + { + const char *key = NULL, *val = NULL; + char *tmp = alloca(s - item + 1); + strncpy(tmp, item, s - item); + tmp[s - item] = '\0'; - _format_param_parse(item, &key, &val); - _format_command(obj, fmt, key, val); - eina_stringshare_del(key); - eina_stringshare_del(val); - } - else - { - /* immediate - not handled here */ - } - *s = tmp_delim; + _format_param_parse(tmp, &key, &val); + _format_command(obj, fmt, key, val); + eina_stringshare_del(key); + eina_stringshare_del(val); + } + else + { + /* immediate - not handled here */ + } } } @@ -1346,16 +1330,16 @@ _format_dup(Evas_Object *obj, Evas_Object_Textblock_Format *fmt) if ((fmt2->font.name) && (fmt2->font.fallbacks)) { - buf = malloc(strlen(fmt2->font.name) + 1 + strlen(fmt2->font.fallbacks) + 1); - strcpy(buf, fmt2->font.name); - strcat(buf, ","); - strcat(buf, fmt2->font.fallbacks); + buf = malloc(strlen(fmt2->font.name) + 1 + strlen(fmt2->font.fallbacks) + 1); + strcpy(buf, fmt2->font.name); + strcat(buf, ","); + strcat(buf, fmt2->font.fallbacks); } else if (fmt2->font.name) buf = strdup(fmt2->font.name); fmt2->font.font = evas_font_load(obj->layer->evas, - buf, fmt2->font.source, - (int)(((double)fmt2->font.size) * obj->cur.scale)); + buf, fmt2->font.source, + (int)(((double)fmt2->font.size) * obj->cur.scale)); if (buf) free(buf); return fmt2; } @@ -1364,11 +1348,6 @@ _format_dup(Evas_Object *obj, Evas_Object_Textblock_Format *fmt) - - - - - typedef struct _Ctxt Ctxt; struct _Ctxt @@ -1376,7 +1355,8 @@ struct _Ctxt Evas_Object *obj; Evas_Object_Textblock *o; - Evas_Object_Textblock_Line *lines; + Evas_Object_Textblock_Paragraph *paragraphs; + Evas_Object_Textblock_Paragraph *par; Evas_Object_Textblock_Line *ln; Eina_List *format_stack; @@ -1399,10 +1379,10 @@ _layout_format_ascent_descent_adjust(Ctxt *c, Evas_Object_Textblock_Format *fmt) if (fmt->font.font) { -// ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font); -// descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font); + // ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font); + // descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font); ascent = c->ENFN->font_ascent_get(c->ENDT, fmt->font.font); - descent = c->ENFN->font_descent_get(c->ENDT, fmt->font.font); + descent = c->ENFN->font_descent_get(c->ENDT, fmt->font.font); if (fmt->linesize > 0) { if ((ascent + descent) < fmt->linesize) @@ -1418,12 +1398,12 @@ _layout_format_ascent_descent_adjust(Ctxt *c, Evas_Object_Textblock_Format *fmt) } c->maxdescent += fmt->linegap; c->maxdescent += ((ascent + descent) * fmt->linerelgap); - if (c->maxascent < ascent) c->maxascent = ascent; - if (c->maxdescent < descent) c->maxdescent = descent; + if (c->maxascent < ascent) c->maxascent = ascent; + if (c->maxdescent < descent) c->maxdescent = descent; if (fmt->linefill > 0.0) { int dh; - + dh = c->obj->cur.geometry.h - (c->maxascent + c->maxdescent); if (dh < 0) dh = 0; dh = fmt->linefill * dh; @@ -1441,30 +1421,65 @@ _layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt) c->align = fmt->halign; c->marginl = fmt->margin.l; c->marginr = fmt->margin.r; - c->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->lines), EINA_INLIST_GET(c->ln)); + c->par->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->par->lines), EINA_INLIST_GET(c->ln)); c->x = 0; c->maxascent = c->maxdescent = 0; c->ln->line_no = -1; _layout_format_ascent_descent_adjust(c, fmt); } +static void +_layout_paragraph_new(Ctxt *c) +{ + c->par = calloc(1, sizeof(Evas_Object_Textblock_Paragraph)); + c->paragraphs = (Evas_Object_Textblock_Paragraph *)eina_inlist_append(EINA_INLIST_GET(c->paragraphs), EINA_INLIST_GET(c->par)); + c->x = 0; + c->par->par_no= -1; +} +static void +_paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par) +{ + while (par->lines) + { + Evas_Object_Textblock_Line *ln; + + ln = (Evas_Object_Textblock_Line *) par->lines; + par->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(par->lines), EINA_INLIST_GET(par->lines)); + _line_free(obj, ln); + } + free(par); +} + +static void +_paragraphs_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars) +{ + while (pars) + { + Evas_Object_Textblock_Paragraph *par; + + par = (Evas_Object_Textblock_Paragraph *) pars; + pars = (Evas_Object_Textblock_Paragraph *)eina_inlist_remove(EINA_INLIST_GET(pars), EINA_INLIST_GET(par)); + _paragraph_free(obj, par); + } +} + static Evas_Object_Textblock_Format * _layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt) { if (fmt) { - fmt = _format_dup(c->obj, fmt); - c->format_stack = eina_list_prepend(c->format_stack, fmt); + fmt = _format_dup(c->obj, fmt); + c->format_stack = eina_list_prepend(c->format_stack, fmt); } else { - fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); - c->format_stack = eina_list_prepend(c->format_stack, fmt); - fmt->ref = 1; - fmt->halign = 0.0; - fmt->valign = -1.0; - fmt->style = EVAS_TEXT_STYLE_PLAIN; - fmt->tabstops = 32; + fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); + c->format_stack = eina_list_prepend(c->format_stack, fmt); + fmt->ref = 1; + fmt->halign = 0.0; + fmt->valign = -1.0; + fmt->style = EVAS_TEXT_STYLE_PLAIN; + fmt->tabstops = 32; fmt->linesize = 0; fmt->linerelsize = 0.0; fmt->linegap = 0; @@ -1478,19 +1493,22 @@ _layout_format_pop(Ctxt *c, Evas_Object_Textblock_Format *fmt) { if ((c->format_stack) && (c->format_stack->next)) { - _format_unref_free(c->obj, fmt); - c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack); - fmt = c->format_stack->data; + _format_unref_free(c->obj, fmt); + c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack); + fmt = c->format_stack->data; } return fmt; } static void -_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, char *item) +_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item) { const char *key = NULL, *val = NULL; + char *tmp; + tmp = alloca(strlen(item) + 1); + strcpy(tmp, item); - _format_param_parse(item, &key, &val); + _format_param_parse(tmp, &key, &val); if ((key) && (val)) _format_command(c->obj, fmt, key, val); if (key) eina_stringshare_del(key); if (val) eina_stringshare_del(val); @@ -1517,62 +1535,62 @@ _layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt) _layout_format_ascent_descent_adjust(c, fmt); EINA_INLIST_FOREACH(c->ln->items, it) { - int endx; + int endx; - if (it->format->font.font) - it->baseline = c->ENFN->font_max_ascent_get(c->ENDT, it->format->font.font); - _layout_format_ascent_descent_adjust(c, it->format); - endx = it->x + it->w; - if (endx > c->ln->w) c->ln->w = endx; + if (it->format->font.font) + it->baseline = c->ENFN->font_max_ascent_get(c->ENDT, it->format->font.font); + _layout_format_ascent_descent_adjust(c, it->format); + endx = it->x + it->w; + if (endx > c->ln->w) c->ln->w = endx; } EINA_INLIST_FOREACH(c->ln->format_items, fi) { - int endx; + int endx; if (!fi->formatme) continue; - endx = fi->x + fi->w; - if (endx > c->ln->w) c->ln->w = endx; + endx = fi->x + fi->w; + if (endx > c->ln->w) c->ln->w = endx; switch (fi->size) { - case SIZE: - case SIZE_ABS: - switch (fi->vsize) - { - case VSIZE_FULL: - if (fi->h > (c->maxdescent + c->maxascent)) - { - c->maxascent += fi->h - (c->maxdescent + c->maxascent); - fi->y = -c->maxascent; - } - else - fi->y = -(fi->h - c->maxdescent); - break; - case VSIZE_ASCENT: - if (fi->h > c->maxascent) - { - c->maxascent = fi->h; - fi->y = -fi->h; - } - else - fi->y = -fi->h; - break; - default: - break; - } - break; - case SIZE_REL: - switch (fi->vsize) - { - case VSIZE_FULL: - case VSIZE_ASCENT: - fi->y = -fi->ascent; - break; - default: - break; - } - break; - default: - break; + case SIZE: + case SIZE_ABS: + switch (fi->vsize) + { + case VSIZE_FULL: + if (fi->h > (c->maxdescent + c->maxascent)) + { + c->maxascent += fi->h - (c->maxdescent + c->maxascent); + fi->y = -c->maxascent; + } + else + fi->y = -(fi->h - c->maxdescent); + break; + case VSIZE_ASCENT: + if (fi->h > c->maxascent) + { + c->maxascent = fi->h; + fi->y = -fi->h; + } + else + fi->y = -fi->h; + break; + default: + break; + } + break; + case SIZE_REL: + switch (fi->vsize) + { + case VSIZE_FULL: + case VSIZE_ASCENT: + fi->y = -fi->ascent; + break; + default: + break; + } + break; + default: + break; } } c->ln->y = c->y + c->o->style_pad.t; @@ -1580,29 +1598,29 @@ _layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt) c->ln->baseline = c->maxascent; if (c->have_underline2) { - if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent; + if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent; } else if (c->have_underline) { - if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent; + if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent; } c->ln->line_no = c->line_no; c->line_no++; c->y += c->maxascent + c->maxdescent; if (c->w >= 0) { - c->ln->x = c->marginl + c->o->style_pad.l + - ((c->w - c->ln->w - - c->o->style_pad.l - c->o->style_pad.r - - c->marginl - c->marginr) * c->align); - if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax) - c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l; + c->ln->x = c->marginl + c->o->style_pad.l + + ((c->w - c->ln->w - + c->o->style_pad.l - c->o->style_pad.r - + c->marginl - c->marginr) * c->align); + if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax) + c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l; } else { - c->ln->x = c->marginl + c->o->style_pad.l; - if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax) - c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l; + c->ln->x = c->marginl + c->o->style_pad.l; + if ((c->ln->x + c->ln->w + c->marginr - c->o->style_pad.l) > c->wmax) + c->wmax = c->ln->x + c->ln->w + c->marginl + c->marginr - c->o->style_pad.l; } _layout_line_new(c, fmt); } @@ -1616,12 +1634,6 @@ _layout_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt, const Ei it->format = fmt; it->format->ref++; it->text = eina_unicode_strdup(str); - it->intl_props.char_types = NULL; - it->intl_props.embedding_levels = NULL; -#ifdef BIDI_SUPPORT - it->intl_props.direction = FRIBIDI_PAR_ON; - evas_bidi_update_props(it->text, &it->intl_props); -#endif return it; } @@ -1629,14 +1641,14 @@ static int _layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it) { if (fmt->font.font) - return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font, it->text, &it->intl_props, - c->w - - c->o->style_pad.l - - c->o->style_pad.r - - c->marginl - - c->marginr - - c->x, - 0); + return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font, it->text, &it->bidi_props, + c->w - + c->o->style_pad.l - + c->o->style_pad.r - + c->marginl - + c->marginr - + c->x, + 0); return -1; } @@ -1649,10 +1661,6 @@ _layout_item_text_cutoff(Ctxt *c __UNUSED__, Evas_Object_Textblock_Item *it, int ts[cut] = 0; it->text = eina_unicode_strdup(ts); free(ts); - -#ifdef BIDI_SUPPORT - evas_bidi_update_props(it->text, &it->intl_props); -#endif } static int @@ -1664,21 +1672,21 @@ _layout_word_start(const Eina_Unicode *str, int start) chr = GET_NEXT(str, p); if (_is_white(chr)) { - tp = p; - while (_is_white(chr) && (p >= 0)) - { - tp = p; - chr = GET_NEXT(str, p); - } - return tp; + tp = p; + while (_is_white(chr) && (p >= 0)) + { + tp = p; + chr = GET_NEXT(str, p); + } + return tp; } p = start; tp = p; while (p > 0) { chr = GET_PREV(str, p); - if (_is_white(chr)) break; - tp = p; + if (_is_white(chr)) break; + tp = p; } if (p < 0) p = 0; if ((p >= 0) && (_is_white(chr))) @@ -1708,21 +1716,21 @@ _layout_strip_trailing_whitespace(Ctxt *c, Evas_Object_Textblock_Format *fmt __U tp = p; if (p >= 0) { - chr = GET_PREV(it->text, p); - if (_is_white(chr)) - { - _layout_item_text_cutoff(c, it, tp); - adv = 0; - if (it->format->font.font) - adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text, &it->intl_props); - tw = th = 0; - if (it->format->font.font) - c->ENFN->font_string_size_get(c->ENDT, it->format->font.font, it->text, &it->intl_props, &tw, &th); - it->w = tw; - it->h = th; - c->x = it->x + adv; - return 1; - } + chr = GET_PREV(it->text, p); + if (_is_white(chr)) + { + _layout_item_text_cutoff(c, it, tp); + adv = 0; + if (it->format->font.font) + adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text, &it->bidi_props); + tw = th = 0; + if (it->format->font.font) + c->ENFN->font_string_size_get(c->ENDT, it->format->font.font, it->text, &it->bidi_props, &tw, &th); + it->w = tw; + it->h = th; + c->x = it->x + adv; + return 1; + } } return 0; } @@ -1733,36 +1741,17 @@ _layout_item_abort(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textb if (it->text) free(it->text); _format_unref_free(c->obj, it->format); #ifdef BIDI_SUPPORT - evas_bidi_props_clean(&it->intl_props); + evas_bidi_props_clean(&it->bidi_props); #endif free(it); if (c->ln->items) { - it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last; - return _layout_strip_trailing_whitespace(c, fmt, it); + it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last; + return _layout_strip_trailing_whitespace(c, fmt, it); } return 0; } -#if 0 -static char * -_layout_next_char_jump(Ctxt *c, Evas_Object_Textblock_Item *it, char *str) -{ - int index; - - index = 0; - evas_common_font_utf8_get_next((unsigned char *)str, &index); - if (index >= 0) - { - str = str + index; - _layout_item_text_cutoff(c, it, index); - } - else - str = NULL; - return str; -} -#endif - static int _layout_last_item_ends_with_whitespace(Ctxt *c) { @@ -1782,8 +1771,8 @@ _layout_word_end(const Eina_Unicode *str, int p) ch = GET_NEXT(str, tp); while ((!_is_white(ch)) && (tp >= 0) && (ch != 0)) { - p = tp; - ch = GET_NEXT(str, tp); + p = tp; + ch = GET_NEXT(str, tp); } if (ch == 0) return -1; return p; @@ -1798,14 +1787,14 @@ _layout_word_next(Eina_Unicode *str, int p) ch = GET_NEXT(str, tp); while ((!_is_white(ch)) && (tp >= 0) && (ch != 0)) { - p = tp; - ch = GET_NEXT(str, tp); + p = tp; + ch = GET_NEXT(str, tp); } if (ch == 0) return -1; while ((_is_white(ch)) && (tp >= 0) && (ch != 0)) { - p = tp; - ch = GET_NEXT(str, tp); + p = tp; + ch = GET_NEXT(str, tp); } if (ch == 0) return -1; return p; @@ -1822,83 +1811,86 @@ _layout_walk_back_to_item_word_redo(Ctxt *c, Evas_Object_Textblock_Item *it) /* it is not appended yet */ EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(c->ln->items)), pit) { - if (_str_ends_with_whitespace(pit->text)) - { - break; - } - index = eina_unicode_strlen(pit->text) - 1; + if (_str_ends_with_whitespace(pit->text)) + { + break; + } + index = eina_unicode_strlen(pit->text) - 1; if (index < 0) index = 0; - index = _layout_word_start(pit->text, index); - if (index == 0) - remove_items = eina_list_prepend(remove_items, pit); - else - { - new_it = _layout_item_new(c, pit->format, pit->text + index); - new_it->source_node = pit->source_node; - new_it->source_pos = pit->source_pos + index; - _layout_item_text_cutoff(c, pit, index); - _layout_strip_trailing_whitespace(c, pit->format, pit); - break; - } + index = _layout_word_start(pit->text, index); + if (index == 0) + remove_items = eina_list_prepend(remove_items, pit); + else + { + new_it = _layout_item_new(c, pit->format, pit->text + index); + new_it->source_node = pit->source_node; + new_it->source_pos = pit->source_pos + index; + new_it->bidi_props.start = new_it->source_pos; + new_it->bidi_props.props = &new_it->source_node->bidi_props; + _layout_item_text_cutoff(c, pit, index); + _layout_strip_trailing_whitespace(c, pit->format, pit); + break; + } } EINA_LIST_FOREACH(remove_items, l, data) - c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(c->ln->items), data); + c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_remove(EINA_INLIST_GET(c->ln->items), data); /* new line now */ if (remove_items) { - pit = remove_items->data; - _layout_line_advance(c, pit->format); + pit = remove_items->data; + _layout_line_advance(c, pit->format); } else { - _layout_line_advance(c, it->format); + _layout_line_advance(c, it->format); } if (new_it) { - /* append new_it */ - tw = th = 0; - if (new_it->format->font.font) - c->ENFN->font_string_size_get(c->ENDT, new_it->format->font.font, new_it->text, &it->intl_props, &tw, &th); - new_it->w = tw; - new_it->h = th; - inset = 0; - if (new_it->format->font.font) - inset = c->ENFN->font_inset_get(c->ENDT, new_it->format->font.font, new_it->text); - new_it->inset = inset; - new_it->x = c->x; - adv = 0; - if (new_it->format->font.font) - adv = c->ENFN->font_h_advance_get(c->ENDT, new_it->format->font.font, new_it->text, &new_it->intl_props); - c->x += adv; - c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(new_it)); + /* append new_it */ + tw = th = 0; + if (new_it->format->font.font) + c->ENFN->font_string_size_get(c->ENDT, new_it->format->font.font, new_it->text, &it->bidi_props, &tw, &th); + new_it->w = tw; + new_it->h = th; + inset = 0; + if (new_it->format->font.font) + inset = c->ENFN->font_inset_get(c->ENDT, new_it->format->font.font, new_it->text); + new_it->inset = inset; + new_it->x = c->x; + adv = 0; + if (new_it->format->font.font) + adv = c->ENFN->font_h_advance_get(c->ENDT, new_it->format->font.font, new_it->text, &new_it->bidi_props); + c->x += adv; + c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(new_it)); } while (remove_items) { - pit = remove_items->data; - remove_items = eina_list_remove_list(remove_items, remove_items); - /* append pit */ - pit->x = c->x; - adv = c->ENFN->font_h_advance_get(c->ENDT, pit->format->font.font, pit->text, &pit->intl_props); - c->x += adv; - c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(pit)); + pit = remove_items->data; + remove_items = eina_list_remove_list(remove_items, remove_items); + /* append pit */ + pit->x = c->x; + adv = c->ENFN->font_h_advance_get(c->ENDT, pit->format->font.font, pit->text, &pit->bidi_props); + c->x += adv; + c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(pit)); } if (it) { - /* append it */ - it->x = c->x; - adv = 0; - if (it->format->font.font) - adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text, &it->intl_props); - c->x += adv; - c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it)); + /* append it */ + it->x = c->x; + adv = 0; + if (it->format->font.font) + adv = c->ENFN->font_h_advance_get(c->ENDT, it->format->font.font, it->text, &it->bidi_props); + c->x += adv; + c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it)); } } static void -_layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node *n, const char *repch) +_layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node_Text *n, int start, int off, const char *repch) { int adv, inset, tw, th, new_line, empty_item; int wrap, twrap, ch, index, white_stripped; + Eina_Unicode *alloc_str = NULL; const Eina_Unicode *str = EINA_UNICODE_EMPTY_STRING; const Eina_Unicode *ustr; const Eina_Unicode *tbase; @@ -1906,254 +1898,265 @@ _layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Text if (n) { - if ((repch) && (eina_ustrbuf_length_get(n->data.text.unicode))) + if ((repch) && (eina_ustrbuf_length_get(n->unicode))) { int i, len, ind; Eina_Unicode *ptr; Eina_Unicode urepch; - - len = eina_unicode_strlen(eina_ustrbuf_string_get(n->data.text.unicode)); + + len = eina_unicode_strlen(eina_ustrbuf_string_get(n->unicode)); str = alloca((len + 1) * sizeof(Eina_Unicode)); tbase = str; ind = 0; urepch = evas_common_encoding_utf8_get_next(repch, &ind); for (i = 0, ptr = (Eina_Unicode *)tbase; i < len; ptr++, i++) - *ptr = urepch; + *ptr = urepch; *ptr = 0; } else { - str = eina_ustrbuf_string_get(n->data.text.unicode); - tbase = str; + int len; + len = eina_ustrbuf_length_get(n->unicode); + if (off == 0) return; + else if (off < 0) off = len - start; + + if (start < 0) + { + start = 0; + } + else if ((start >= len) || (off > len)) + { + return; + } + str = eina_ustrbuf_string_get(n->unicode); + alloc_str = eina_unicode_strdup(str + start); + + if (off > 0) + { + alloc_str[off] = 0; + } + tbase = str = alloc_str; } } else { tbase = str; } -// printf("add: wrap: %i|%i, width: %i '%s'\n", fmt->wrap_word, fmt->wrap_char, c->w, str); + // printf("add: wrap: %i|%i, width: %i '%s'\n", fmt->wrap_word, fmt->wrap_char, c->w, str); new_line = 0; empty_item = 0; while (str) { - /* if this is the first line item and it starts with spaces - remove them */ - wrap = 0; - white_stripped = 0; -/* - if (!c->ln->items) - { - twrap = wrap; - ch = evas_common_font_utf8_get_next((unsigned char *)str, &wrap); - while (_is_white(ch)) - { - twrap = wrap; - ch = evas_common_font_utf8_get_next((unsigned char *)str, &wrap); - } - str = str + twrap; - } - */ - it = _layout_item_new(c, fmt, str); - it->source_node = n; - it->source_pos = str - tbase; - tw = th = 0; - if (fmt->font.font) - c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->intl_props, &tw, &th); - if ((c->w >= 0) && - ((fmt->wrap_word) || (fmt->wrap_char)) && - ((c->x + tw) > - (c->w - c->o->style_pad.l - c->o->style_pad.r - - c->marginl - c->marginr))) - { - wrap = _layout_text_cutoff_get(c, fmt, it); + /* if this is the first line item and it starts with spaces - remove them */ + wrap = 0; + white_stripped = 0; + + it = _layout_item_new(c, fmt, str); + it->source_node = n; + it->source_pos = start + str - tbase; + it->bidi_props.start = it->source_pos; + it->bidi_props.props = &it->source_node->bidi_props; + tw = th = 0; + if (fmt->font.font) + c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props, &tw, &th); + if ((c->w >= 0) && + ((fmt->wrap_word) || (fmt->wrap_char)) && + ((c->x + tw) > + (c->w - c->o->style_pad.l - c->o->style_pad.r - + c->marginl - c->marginr))) + { + wrap = _layout_text_cutoff_get(c, fmt, it); if (wrap == 0) GET_NEXT(str, wrap); - if (wrap > 0) - { - if (fmt->wrap_word) - { - index = wrap; - ch = GET_NEXT(str, index); - if (!_is_white(ch)) - wrap = _layout_word_start(str, wrap); - if (wrap > 0) - { - twrap = wrap; - ch = GET_PREV(str, twrap); - /* the text intersects the wrap point on a whitespace char */ - if (_is_white(ch)) - { - _layout_item_text_cutoff(c, it, wrap); - twrap = wrap; - /*we don't want to move next, that's why it's - * commented out. - * ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap); - */ - str += twrap; - } - /* intersects a word */ - else - { - /* walk back to start of word */ - twrap = _layout_word_start(str, wrap); - if (twrap != 0) - { - wrap = twrap; - ch = GET_PREV(str, twrap); - _layout_item_text_cutoff(c, it, twrap); - str += wrap; - } - else - { - empty_item = 1; - if (it->text) free(it->text); - _format_unref_free(c->obj, it->format); - free(it); + if (wrap > 0) + { + if (fmt->wrap_word) + { + index = wrap; + ch = GET_NEXT(str, index); + if (!_is_white(ch)) + wrap = _layout_word_start(str, wrap); + if (wrap > 0) + { + twrap = wrap; + ch = GET_PREV(str, twrap); + /* the text intersects the wrap point on a whitespace char */ + if (_is_white(ch)) + { + _layout_item_text_cutoff(c, it, wrap); + twrap = wrap; + /*we don't want to move next, that's why it's + * commented out. + * ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap); + */ + str += twrap; + } + /* intersects a word */ + else + { + /* walk back to start of word */ + twrap = _layout_word_start(str, wrap); + if (twrap != 0) + { + wrap = twrap; + ch = GET_PREV(str, twrap); + _layout_item_text_cutoff(c, it, twrap); + str += wrap; + } + else + { + empty_item = 1; + if (it->text) free(it->text); + _format_unref_free(c->obj, it->format); + free(it); if (c->ln->items) { it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last; _layout_strip_trailing_whitespace(c, fmt, it); twrap = _layout_word_end(str, wrap); - if (twrap >= 0) - { - ch = GET_NEXT(str, twrap); - str += twrap; - } - else - str = NULL; + if (twrap >= 0) + { + ch = GET_NEXT(str, twrap); + str += twrap; + } + else + str = NULL; } - } - } - } - else - { - /* wrap now is the index of the word START */ - index = wrap; - ch = GET_NEXT(str, index); - if (!_is_white(ch) && - (!_layout_last_item_ends_with_whitespace(c))) - { - _layout_walk_back_to_item_word_redo(c, it); - return; - } - if (c->ln->items != NULL) - { - white_stripped = _layout_item_abort(c, fmt, it); - empty_item = 1; - } - else - { - if (wrap <= 0) - { - wrap = 0; - twrap = _layout_word_end(it->text, wrap); - wrap = twrap; - if (twrap >= 0) - { - ch = GET_NEXT(str, wrap); - _layout_item_text_cutoff(c, it, twrap); - } - if (wrap > 0) - str += wrap; - else - str = NULL; - } - else - str = NULL; - } - } - } - else if (fmt->wrap_char) - { - _layout_item_text_cutoff(c, it, wrap); - str += wrap; - } - new_line = 1; - } - else - { - /* wrap now is the index of the word START */ - if (wrap <= 0) - { - if (wrap < 0) wrap = 0; - index = wrap; - ch = GET_NEXT(str, index); - if (!_is_white(ch) && - (!_layout_last_item_ends_with_whitespace(c))) - { - _layout_walk_back_to_item_word_redo(c, it); - return; - } - } - if (c->ln->items != NULL) - { - white_stripped = _layout_item_abort(c, fmt, it); - empty_item = 1; - new_line = 1; - } - else - { - if (wrap <= 0) - { - wrap = 0; - twrap = _layout_word_end(it->text, wrap); - wrap = _layout_word_next(it->text, wrap); - if (twrap >= 0) - _layout_item_text_cutoff(c, it, twrap); - if (wrap >= 0) - str += wrap; - else - str = NULL; - } - else - str = NULL; - new_line = 1; - } - } - if (!empty_item) - { - tw = th = 0; - if (fmt->font.font) - c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->intl_props, &tw, &th); - } - } - else - str = NULL; - if (empty_item) empty_item = 0; - else - { - it->w = tw; - it->h = th; - inset = 0; - if (fmt->font.font) - inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, it->text); - it->inset = inset; - it->x = c->x; - adv = 0; - if (fmt->font.font) - adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, it->text, &it->intl_props); - c->x += adv; - c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it)); - } - if (new_line) - { - if (str) - { - if (!white_stripped) - { - index = 0; - ch = GET_NEXT(str, index); - if (_is_white(ch)) str += index; - } - } - new_line = 0; - _layout_line_advance(c, fmt); - } + } + } + } + else + { + /* wrap now is the index of the word START */ + index = wrap; + ch = GET_NEXT(str, index); + if (!_is_white(ch) && + (!_layout_last_item_ends_with_whitespace(c))) + { + _layout_walk_back_to_item_word_redo(c, it); + goto end; + } + if (c->ln->items != NULL) + { + white_stripped = _layout_item_abort(c, fmt, it); + empty_item = 1; + } + else + { + if (wrap <= 0) + { + wrap = 0; + twrap = _layout_word_end(it->text, wrap); + wrap = twrap; + if (twrap >= 0) + { + ch = GET_NEXT(str, wrap); + _layout_item_text_cutoff(c, it, twrap); + } + if (wrap > 0) + str += wrap; + else + str = NULL; + } + else + str = NULL; + } + } + } + else if (fmt->wrap_char) + { + _layout_item_text_cutoff(c, it, wrap); + str += wrap; + } + new_line = 1; + } + else + { + /* wrap now is the index of the word START */ + if (wrap <= 0) + { + if (wrap < 0) wrap = 0; + index = wrap; + ch = GET_NEXT(str, index); + if (!_is_white(ch) && + (!_layout_last_item_ends_with_whitespace(c))) + { + _layout_walk_back_to_item_word_redo(c, it); + goto end; + } + } + if (c->ln->items != NULL) + { + white_stripped = _layout_item_abort(c, fmt, it); + empty_item = 1; + new_line = 1; + } + else + { + if (wrap <= 0) + { + wrap = 0; + twrap = _layout_word_end(it->text, wrap); + wrap = _layout_word_next(it->text, wrap); + if (twrap >= 0) + _layout_item_text_cutoff(c, it, twrap); + if (wrap >= 0) + str += wrap; + else + str = NULL; + } + else + str = NULL; + new_line = 1; + } + } + if (!empty_item) + { + tw = th = 0; + if (fmt->font.font) + c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props, &tw, &th); + } + } + else + str = NULL; + if (empty_item) empty_item = 0; + else + { + it->w = tw; + it->h = th; + inset = 0; + if (fmt->font.font) + inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, it->text); + it->inset = inset; + it->x = c->x; + adv = 0; + if (fmt->font.font) + adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props); + c->x += adv; + c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it)); + } + if (new_line) + { + if (str) + { + if (!white_stripped) + { + index = 0; + ch = GET_NEXT(str, index); + if (_is_white(ch)) str += index; + } + } + new_line = 0; + _layout_line_advance(c, fmt); + } } +end: + if (alloc_str) free(alloc_str); } static Evas_Object_Textblock_Format_Item * -_layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node *n, char *item) +_layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const char *item) { Evas_Object_Textblock_Format_Item *fi; @@ -2161,24 +2164,218 @@ _layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node *n, char *item) fi->item = eina_stringshare_add(item); fi->source_node = n; c->ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->format_items), - EINA_INLIST_GET(fi)); + EINA_INLIST_GET(fi)); return fi; } -/* A macro to check if the string is a new line, either the actual char or a +/* A macro to check if the string is a new line, either the actual char or a * relevant escape sequence */ #define _IS_LINE_SEPARATOR(item) \ - (!strcmp(item, "\n") || !strcmp(item, "\\n")) + (!strcmp(item, "\n") || !strcmp(item, "\\n")) /* same as the above just with paragraphs */ #define _IS_PARAGRAPH_SEPARATOR(item) \ - (!strcmp(item, "PS")) /* Paragraph separator */ + (!strcmp(item, "ps")) /* Paragraph separator */ +static void +_layout_do_format(const Evas_Object *obj, Ctxt *c, + Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n, + int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b) +{ + Evas_Object_Textblock_Format *fmt = *_fmt; + + const char *s; + const char *item; + int handled = 0; + + s = eina_strbuf_string_get(n->format); + if (!strncmp(s, "+ item ", 7)) + { + // one of: + // item size=20x10 href=name + // item relsize=20x10 href=name + // item abssize=20x10 href=name + // + // optional arguments: + // vsize=full + // vsize=ascent + // + // size == item size (modifies line size) - can be multiplied by + // scale factor + // relsize == relative size (height is current font height, width + // modified accordingly keeping aspect) + // abssize == absolute size (modifies line size) - never mulitplied by + // scale factor + // href == name of item - to be found and matched later and used for + // positioning + Evas_Object_Textblock_Format_Item *fi; + int x2, w = 1, h = 1; + int vsize = 0, size = 0; + char *p; + + // don't care + //href = strstr(s, " href="); + p = strstr(s, " vsize="); + if (p) + { + p += 7; + if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL; + else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT; + } + p = strstr(s, " size="); + if (p) + { + p += 6; + if (sscanf(p, "%ix%i", &w, &h) == 2) + { + w = w * obj->cur.scale; + h = h * obj->cur.scale; + size = SIZE; + } + } + else + { + p = strstr(s, " absize="); + if (p) + { + p += 8; + if (sscanf(p, "%ix%i", &w, &h) == 2) + { + size = SIZE_ABS; + } + } + else + { + p = strstr(s, " relsize="); + if (p) + { + p += 9; + if (sscanf(p, "%ix%i", &w, &h) == 2) + { + int sz = 1; + size = SIZE_REL; + if (vsize == VSIZE_FULL) + { + sz = c->maxdescent + c->maxascent; + } + else if (vsize == VSIZE_ASCENT) + { + sz = c->maxascent; + } + w = (w * sz) / h; + h = sz; + } + } + } + } + + x2 = c->x + w; + + if (x2 > + (c->w - c->o->style_pad.l - + c->o->style_pad.r - + c->marginl - c->marginr)) + { + _layout_line_advance(c, fmt); + x2 = w; + } + fi = _layout_format_item_add(c, n, NULL); + fi->x = c->x; + fi->vsize = vsize; + fi->size = size; + fi->formatme = 1; + fi->w = w; + fi->h = h; + fi->ascent = c->maxascent; + fi->descent = c->maxdescent; + c->x = x2; + handled = 1; + } + if (!handled) + { + if (s[0] == '+') + { + fmt = _layout_format_push(c, fmt); + s++; + } + else if (s[0] == '-') + { + fmt = _layout_format_pop(c, fmt); + s++; + } + while ((item = _format_parse(&s))) + { + char *tmp = alloca(s - item + 1); + strncpy(tmp, item, s - item); + tmp[s - item] = '\0'; + if (_format_is_param(item)) + { + _layout_format_value_handle(c, fmt, item); + } + else + { + if (_IS_PARAGRAPH_SEPARATOR(item)) + { + Evas_Object_Textblock_Format_Item *fi; + + fi = _layout_format_item_add(c, n, item); + fi->x = c->x; + fi->w = 0; + _layout_line_advance(c, fmt); + + } + else if (_IS_LINE_SEPARATOR(item)) + { + Evas_Object_Textblock_Format_Item *fi; + + fi = _layout_format_item_add(c, n, item); + fi->x = c->x; + fi->w = 0; + _layout_line_advance(c, fmt); + } + else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) + { + Evas_Object_Textblock_Format_Item *fi; + int x2; + + x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops)); + if (x2 > + (c->w - c->o->style_pad.l - + c->o->style_pad.r - + c->marginl - c->marginr)) + { + _layout_line_advance(c, fmt); + x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops)); + } + if (c->ln->items) + { + Evas_Object_Textblock_Item *it; + + it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last; + _layout_strip_trailing_whitespace(c, fmt, it); + } + fi = _layout_format_item_add(c, n, item); + fi->x = c->x; + fi->w = x2 - c->x; + c->x = x2; + } + } + } + } + + evas_text_style_pad_get(fmt->style, style_pad_l, style_pad_r, style_pad_t, style_pad_b); + + if (fmt->underline2) + c->have_underline2 = 1; + else if (fmt->underline) + c->have_underline = 1; + *_fmt = fmt; +} static void _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ret) { Evas_Object_Textblock *o; Ctxt ctxt, *c; Evas_Object_Textblock_Line *ln; - Evas_Object_Textblock_Node *n; + Evas_Object_Textblock_Node_Text *n; Eina_List *removes = NULL; Evas_Object_Textblock_Format *fmt = NULL; int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0; @@ -2188,7 +2385,7 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ c = &ctxt; c->obj = (Evas_Object *)obj; c->o = o; - c->lines = c->ln = NULL; + c->paragraphs = c->par = NULL; c->format_stack = NULL; c->x = c->y = 0; c->w = w; @@ -2201,306 +2398,133 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_ c->underline_extend = 0; c->line_no = 0; c->align = 0.0; + c->ln = NULL; - _format_command_init(); /* setup default base style */ if ((c->o->style) && (c->o->style->default_tag)) { - fmt = _layout_format_push(c, NULL); - _format_fill(c->obj, fmt, c->o->style->default_tag); + fmt = _layout_format_push(c, NULL); + _format_fill(c->obj, fmt, c->o->style->default_tag); } if (!fmt) { - _format_command_shutdown(); - if (w_ret) *w_ret = 0; - if (h_ret) *h_ret = 0; - return; + if (w_ret) *w_ret = 0; + if (h_ret) *h_ret = 0; + return; } /* run through all text and format nodes generating lines */ - if (!c->o->nodes) + if (!c->o->text_nodes && !c->o->format_nodes) { /* If there are no nodes and lines, do the inital creation. */ - if (!c->ln) + if (!c->par && !c->ln) { + _layout_paragraph_new(c); _layout_line_new(c, fmt); - _layout_text_append(c, fmt, NULL, NULL); + _layout_text_append(c, fmt, NULL, 0, 0, NULL); _layout_line_advance(c, fmt); -// printf("bl:%i | %ix%i\n", c->ln->baseline, c->ln->w, c->ln->h); - /* - tw = th = 0; - if (fmt->font.font) - { - c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, "", NULL, &tw, &th); - c->ln->x = 0; - c->ln->y = 0; - c->ln->w = tw; - c->ln->h = th; - c->wmax = tw; - c->hmax = th; - _layout_format_ascent_descent_adjust(c, fmt); - } - */ } } - /* FIXME: Consider splitting FORMAT NODE parsing into a different func */ - EINA_INLIST_FOREACH(c->o->nodes, n) + + EINA_INLIST_FOREACH(c->o->text_nodes, n) { - if (!c->ln) _layout_line_new(c, fmt); - /* Handle format nodes */ - if ((n->type == NODE_FORMAT) && eina_strbuf_length_get(n->data.format)) - { - char *s; - char *item; - int handled = 0; + Evas_Object_Textblock_Node_Format *fnode; + size_t start; + int off; + int first_run; - s = (char *)eina_strbuf_string_get(n->data.format); - if (!strncmp(s, "+ item ", 7)) + /*FIXME-tom: A hack, so we'll only have one paragraph + * until full support is implemented */ + if (!c->par) + { + _layout_paragraph_new(c); /* Each node is a paragraph */ + } + if (!c->ln) _layout_line_new(c, fmt); + + fnode = n->format_node; + start = off = 0; + first_run = 1; + while (fnode && fnode->text_node == n) + { + off += fnode->offset; + /* No need to skip on the first run, or a non-visible one */ + _layout_text_append(c, fmt, n, start, off, o->repch); + _layout_do_format(obj, c, &fmt, fnode, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b); + if ((c->have_underline2) || (c->have_underline)) { - // one of: - // item size=20x10 href=name - // item relsize=20x10 href=name - // item abssize=20x10 href=name - // - // optional arguments: - // vsize=full - // vsize=ascent - // - // size == item size (modifies line size) - can be multiplied by - // scale factor - // relsize == relative size (height is current font height, width - // modified accordingly keeping aspect) - // abssize == absolute size (modifies line size) - never mulitplied by - // scale factor - // href == name of item - to be found and matched later and used for - // positioning - Evas_Object_Textblock_Format_Item *fi; - int x2, w = 1, h = 1; - int vsize = 0, size = 0; - char *p; - - // don't care - //href = strstr(s, " href="); - p = strstr(s, " vsize="); - if (p) - { - p += 7; - if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL; - else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT; - } - p = strstr(s, " size="); - if (p) - { - p += 6; - if (sscanf(p, "%ix%i", &w, &h) == 2) - { - w = w * obj->cur.scale; - h = h * obj->cur.scale; - size = SIZE; - } - } - else - { - p = strstr(s, " absize="); - if (p) - { - p += 8; - if (sscanf(p, "%ix%i", &w, &h) == 2) - { - size = SIZE_ABS; - } - } - else - { - p = strstr(s, " relsize="); - if (p) - { - p += 9; - if (sscanf(p, "%ix%i", &w, &h) == 2) - { - int sz = 1; - size = SIZE_REL; - if (vsize == VSIZE_FULL) - { - sz = c->maxdescent + c->maxascent; - } - else if (vsize == VSIZE_ASCENT) - { - sz = c->maxascent; - } - w = (w * sz) / h; - h = sz; - } - } - } - } - - x2 = c->x + w; - - if (x2 > - (c->w - c->o->style_pad.l - - c->o->style_pad.r - - c->marginl - c->marginr)) - { - _layout_line_advance(c, fmt); - x2 = w; - } - fi = _layout_format_item_add(c, n, NULL); - fi->x = c->x; - fi->vsize = vsize; - fi->size = size; - fi->formatme = 1; - fi->w = w; - fi->h = h; - fi->ascent = c->maxascent; - fi->descent = c->maxdescent; - c->x = x2; - handled = 1; + if (style_pad_b < c->underline_extend) + style_pad_b = c->underline_extend; + c->have_underline = 0; + c->have_underline2 = 0; + c->underline_extend = 0; } - if (!handled) + start += off; + if (fnode->visible) { - if (s[0] == '+') - { - fmt = _layout_format_push(c, fmt); - s++; - } - else if (s[0] == '-') - { - fmt = _layout_format_pop(c, fmt); - s++; - } - while ((item = _format_parse(&s))) - { - char tmp_delim = *s; - *s = '\0'; - if (_format_is_param(item)) - { - _layout_format_value_handle(c, fmt, item); - } - else - { -#if 0 - if (_IS_PARAGRAPH_SEPARATOR(item)) - { - - } - else if (_IS_LINE_SEPARATOR(item)) -#else - if (_IS_LINE_SEPARATOR(item)) -#endif - { - Evas_Object_Textblock_Format_Item *fi; - - fi = _layout_format_item_add(c, n, item); - fi->x = c->x; - fi->w = 0; - _layout_line_advance(c, fmt); - } - else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) - { - Evas_Object_Textblock_Format_Item *fi; - int x2; - - x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops)); - if (x2 > - (c->w - c->o->style_pad.l - - c->o->style_pad.r - - c->marginl - c->marginr)) - { - _layout_line_advance(c, fmt); - x2 = (fmt->tabstops * ((c->x + fmt->tabstops) / fmt->tabstops)); - } - if (c->ln->items) - { - Evas_Object_Textblock_Item *it; - - it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last; - _layout_strip_trailing_whitespace(c, fmt, it); - } - fi = _layout_format_item_add(c, n, item); - fi->x = c->x; - fi->w = x2 - c->x; - c->x = x2; - } - } - *s = tmp_delim; - } + off = -1; + start++; } - - evas_text_style_pad_get(fmt->style, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b); - - if (fmt->underline2) - c->have_underline2 = 1; - else if (fmt->underline) - c->have_underline = 1; - } - /* Handle text nodes */ - else if ((n->type == NODE_TEXT) && eina_ustrbuf_length_get(n->data.text.unicode)) - { - _layout_text_append(c, fmt, n, o->repch); - if ((c->have_underline2) || (c->have_underline)) - { - if (style_pad_b < c->underline_extend) - style_pad_b = c->underline_extend; - c->have_underline = 0; - c->have_underline2 = 0; - c->underline_extend = 0; - } - } + else + { + off = 0; + } + first_run = 0; + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + } + _layout_text_append(c, fmt, n, start, -1, o->repch); } + /* Advance the line so it'll calculate the size */ if ((c->ln) && (c->ln->items) && (fmt)) _layout_line_advance(c, fmt); + /* Clean the rest of the format stack */ while (c->format_stack) { - fmt = c->format_stack->data; - c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack); - _format_unref_free(c->obj, fmt); + fmt = c->format_stack->data; + c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack); + _format_unref_free(c->obj, fmt); } - EINA_INLIST_FOREACH(c->lines, ln) + EINA_INLIST_FOREACH(c->par->lines, ln) { - if (ln->line_no == -1) - { - removes = eina_list_append(removes, ln); - } - else - { - if ((ln->y + ln->h) > c->hmax) c->hmax = ln->y + ln->h; - } + if (ln->line_no == -1) + { + removes = eina_list_append(removes, ln); + } + else + { + if ((ln->y + ln->h) > c->hmax) c->hmax = ln->y + ln->h; + } } while (removes) { - ln = removes->data; - c->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(c->lines), EINA_INLIST_GET(ln)); - removes = eina_list_remove_list(removes, removes); - _line_free(obj, ln); + ln = removes->data; + c->par->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(c->par->lines), EINA_INLIST_GET(ln)); + removes = eina_list_remove_list(removes, removes); + _line_free(obj, ln); } if (w_ret) *w_ret = c->wmax; if (h_ret) *h_ret = c->hmax; if ((o->style_pad.l != style_pad_l) || (o->style_pad.r != style_pad_r) || - (o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b)) + (o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b)) { - Evas_Object_Textblock_Line *lines; + Evas_Object_Textblock_Line *lines; - lines = c->lines; - c->lines = NULL; - o->style_pad.l = style_pad_l; - o->style_pad.r = style_pad_r; - o->style_pad.t = style_pad_t; - o->style_pad.b = style_pad_b; - _layout(obj, calc_only, w, h, w_ret, h_ret); + lines = c->par->lines; + c->par->lines = NULL; + o->style_pad.l = style_pad_l; + o->style_pad.r = style_pad_r; + o->style_pad.t = style_pad_t; + o->style_pad.b = style_pad_b; + _layout(obj, calc_only, w, h, w_ret, h_ret); _lines_clear(obj, lines); - _format_command_shutdown(); - return; + return; } if (!calc_only) { - o->lines = c->lines; - _format_command_shutdown(); - return; + o->lines = c->par->lines; + return; } - if (c->lines) _lines_clear(obj, c->lines); - _format_command_shutdown(); + if (c->paragraphs) _paragraphs_clear(obj, c->paragraphs); } static void @@ -2515,9 +2539,9 @@ _relayout(const Evas_Object *obj) o->formatted.valid = 0; o->native.valid = 0; _layout(obj, - 0, - obj->cur.geometry.w, obj->cur.geometry.h, - &o->formatted.w, &o->formatted.h); + 0, + obj->cur.geometry.w, obj->cur.geometry.h, + &o->formatted.w, &o->formatted.h); o->formatted.valid = 1; if (lines) _lines_clear(obj, lines); o->last_w = obj->cur.geometry.w; @@ -2526,82 +2550,65 @@ _relayout(const Evas_Object *obj) } static void -_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) +_find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Text *n, int pos, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr) { Evas_Object_Textblock_Line *ln; -/* Evas_Object_Textblock_Node *nn; */ Evas_Object_Textblock *o; o = (Evas_Object_Textblock *)(obj->object_data); -/* EINA_INLIST_FOREACH(o->nodes, nn) */ -/* ; */ - if ((eol) && (n->type == NODE_TEXT)) - { - int pos2 = pos; - - GET_PREV(eina_ustrbuf_string_get(n->data.text.unicode), pos2); - if (pos2 < pos) pos = pos2; - } + if (!o->formatted.valid) _relayout(obj); EINA_INLIST_FOREACH(o->lines, ln) { - Evas_Object_Textblock_Format_Item *fit; - Evas_Object_Textblock_Item *it; + Evas_Object_Textblock_Format_Item *fit; + Evas_Object_Textblock_Item *it; Evas_Object_Textblock_Line *lnn; lnn = (Evas_Object_Textblock_Line *)(((Eina_Inlist *)ln)->next); - EINA_INLIST_FOREACH(ln->items, it) - { - if (it->source_node == n) - { + EINA_INLIST_FOREACH(ln->items, it) + { + if (it->source_node == n) + { Evas_Object_Textblock_Item *itn; int p; itn = (Evas_Object_Textblock_Item *)(((Eina_Inlist *)it)->next); p = (int)(it->source_pos + eina_unicode_strlen(it->text)); - if ((p >= pos) || - ((p == pos) && (!lnn) && - ((!itn) | - ((itn) && (itn->source_node != n))))) - { - *lnr = ln; - *itr = it; - return; - } - } - } - EINA_INLIST_FOREACH(ln->format_items, fit) - { - if (fit->source_node == n) - { - *lnr = ln; - /* FIXME: Is that really what we want ? */ - *itr = (Evas_Object_Textblock_Item *)fit; - return; - } - } + /*FIXME: Bad, this sholud be > pos */ + if ((p >= pos) || + ((p == pos) && (!lnn) && + ((!itn) | + ((itn) && (itn->source_node != n))))) + { + *lnr = ln; + *itr = it; + return; + } + } + } } } static void -_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) +_find_layout_format_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Format *n, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Format_Item **fir) { Evas_Object_Textblock_Line *ln; Evas_Object_Textblock *o; o = (Evas_Object_Textblock *)(obj->object_data); + if (!o->formatted.valid) _relayout(obj); EINA_INLIST_FOREACH(o->lines, ln) { - Evas_Object_Textblock_Format_Item *fi; + Evas_Object_Textblock_Format_Item *fi; - EINA_INLIST_FOREACH(ln->format_items, fi) - { - if (fi->source_node == n) - { - *lnr = ln; - *fir = fi; - return; - } - } + EINA_INLIST_FOREACH(ln->format_items, fi) + { + if (fi->source_node == n) + { + *lnr = ln; + *fir = fi; + return; + } + } } } @@ -2614,7 +2621,7 @@ _find_layout_line_num(const Evas_Object *obj, int line) o = (Evas_Object_Textblock *)(obj->object_data); EINA_INLIST_FOREACH(o->lines, ln) { - if (ln->line_no == line) return ln; + if (ln->line_no == line) return ln; } return NULL; } @@ -2661,8 +2668,8 @@ evas_textblock_style_free(Evas_Textblock_Style *ts) if (!ts) return; if (ts->objects) { - ts->delete_me = 1; - return; + ts->delete_me = 1; + return; } _style_clear(ts); free(ts); @@ -2684,15 +2691,15 @@ evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) EINA_LIST_FOREACH(ts->objects, l, obj) { - Evas_Object_Textblock *o; + Evas_Object_Textblock *o; - o = (Evas_Object_Textblock *)(obj->object_data); - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - evas_object_textblock_text_markup_get(obj); - } + o = (Evas_Object_Textblock *)(obj->object_data); + if (o->markup_text) + { + free(o->markup_text); + o->markup_text = NULL; + evas_object_textblock_text_markup_get(obj); + } } _style_clear(ts); @@ -2700,106 +2707,106 @@ evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) if (ts->style_text) { - // format MUST be KEY='VALUE'[KEY='VALUE']... - char *p; - char *key_start, *key_stop, *val_start, *val_stop; + // format MUST be KEY='VALUE'[KEY='VALUE']... + char *p; + char *key_start, *key_stop, *val_start, *val_stop; - key_start = key_stop = val_start = val_stop = NULL; - p = ts->style_text; - while (*p) - { - if (!key_start) - { - if (!isspace(*p)) - key_start = p; - } - else if (!key_stop) - { - if ((*p == '=') || (isspace(*p))) - key_stop = p; - } - else if (!val_start) - { - if (((*p) == '\'') && (*(p + 1))) - val_start = p + 1; - } - else if (!val_stop) - { - if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\')) - val_stop = p; - } - if ((key_start) && (key_stop) && (val_start) && (val_stop)) - { - char *tags, *replaces; - Evas_Object_Style_Tag *tag; - size_t tag_len = key_stop - key_start; - size_t replace_len = val_stop - val_start; + key_start = key_stop = val_start = val_stop = NULL; + p = ts->style_text; + while (*p) + { + if (!key_start) + { + if (!isspace(*p)) + key_start = p; + } + else if (!key_stop) + { + if ((*p == '=') || (isspace(*p))) + key_stop = p; + } + else if (!val_start) + { + if (((*p) == '\'') && (*(p + 1))) + val_start = p + 1; + } + else if (!val_stop) + { + if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\')) + val_stop = p; + } + if ((key_start) && (key_stop) && (val_start) && (val_stop)) + { + char *tags, *replaces; + Evas_Object_Style_Tag *tag; + size_t tag_len = key_stop - key_start; + size_t replace_len = val_stop - val_start; - tags = malloc(tag_len + 1); - if (tags) - { - memcpy(tags, key_start, tag_len); - tags[tag_len] = 0; - } + tags = malloc(tag_len + 1); + if (tags) + { + memcpy(tags, key_start, tag_len); + tags[tag_len] = 0; + } - replaces = malloc(replace_len + 1); - if (replaces) - { - memcpy(replaces, val_start, replace_len); - replaces[replace_len] = 0; - } - if ((tags) && (replaces)) - { - if (!strcmp(tags, "DEFAULT")) - { - ts->default_tag = replaces; - free(tags); - } - else - { - tag = calloc(1, sizeof(Evas_Object_Style_Tag)); - if (tag) - { - tag->tag = tags; - tag->replace = replaces; - tag->tag_len = tag_len; - tag->replace_len = replace_len; - ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); - } - else - { - free(tags); - free(replaces); - } - } - } - else - { - if (tags) free(tags); - if (replaces) free(replaces); - } - key_start = key_stop = val_start = val_stop = NULL; - } - p++; - } + replaces = malloc(replace_len + 1); + if (replaces) + { + memcpy(replaces, val_start, replace_len); + replaces[replace_len] = 0; + } + if ((tags) && (replaces)) + { + if (!strcmp(tags, "DEFAULT")) + { + ts->default_tag = replaces; + free(tags); + } + else + { + tag = calloc(1, sizeof(Evas_Object_Style_Tag)); + if (tag) + { + tag->tag = tags; + tag->replace = replaces; + tag->tag_len = tag_len; + tag->replace_len = replace_len; + ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); + } + else + { + free(tags); + free(replaces); + } + } + } + else + { + if (tags) free(tags); + if (replaces) free(replaces); + } + key_start = key_stop = val_start = val_stop = NULL; + } + p++; + } } EINA_LIST_FOREACH(ts->objects, l, obj) { - Evas_Object_Textblock *o; + Evas_Object_Textblock *o; - o = (Evas_Object_Textblock *)(obj->object_data); - if (o->markup_text) - { - char *m; + o = (Evas_Object_Textblock *)(obj->object_data); + if (o->markup_text) + { + char *m; - m = strdup(o->markup_text); - if (m) - { - evas_object_textblock_text_markup_set(obj, m); - free(m); - } - } + m = strdup(o->markup_text); + if (m) + { + evas_object_textblock_text_markup_set(obj, m); + free(m); + } + } } } @@ -2839,32 +2846,24 @@ evas_object_textblock_style_set(Evas_Object *obj, Evas_Textblock_Style *ts) } if (o->style) { - Evas_Textblock_Style *old_ts; + Evas_Textblock_Style *old_ts; - old_ts = o->style; - old_ts->objects = eina_list_remove(old_ts->objects, obj); - if ((old_ts->delete_me) && (!old_ts->objects)) - evas_textblock_style_free(old_ts); + old_ts = o->style; + old_ts->objects = eina_list_remove(old_ts->objects, obj); + if ((old_ts->delete_me) && (!old_ts->objects)) + evas_textblock_style_free(old_ts); } if (ts) { - ts->objects = eina_list_append(ts->objects, obj); - o->style = ts; + ts->objects = eina_list_append(ts->objects, obj); + o->style = ts; } else { - o->style = NULL; + o->style = NULL; } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(obj); + _evas_textblock_changed(o, obj); } /** @@ -2892,15 +2891,7 @@ evas_object_textblock_replace_char_set(Evas_Object *obj, const char *ch) if (o->repch) eina_stringshare_del(o->repch); if (ch) o->repch = eina_stringshare_add(ch); else o->repch = NULL; - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(obj); + _evas_textblock_changed(o, obj); } /** @@ -2929,15 +2920,15 @@ _escaped_advance_after_end_of_string(const char **p_buf) * there is a match */ static inline int _escaped_is_eq_and_advance(const char *s, const char *s_end, - const char **p_m, const char *m_end) + const char **p_m, const char *m_end) { for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++) { - if (*s != **p_m) - { - _escaped_advance_after_end_of_string(p_m); - return 0; - } + if (*s != **p_m) + { + _escaped_advance_after_end_of_string(p_m); + return 0; + } } if (*p_m < m_end) @@ -2957,29 +2948,29 @@ _escaped_char_match(const char *s, int *adv) while (map_itr < map_end) { - const char *escape; - int match; + const char *escape; + int match; - escape = map_itr; - _escaped_advance_after_end_of_string(&map_itr); - if (map_itr >= map_end) break; + escape = map_itr; + _escaped_advance_after_end_of_string(&map_itr); + if (map_itr >= map_end) break; - mc = map_itr; - sc = s; - match = 1; - while ((*mc) && (*sc)) - { - if ((unsigned char)*sc < (unsigned char)*mc) return NULL; - if (*sc != *mc) match = 0; - mc++; - sc++; - } - if (match) - { - *adv = mc - map_itr; - return escape; - } - _escaped_advance_after_end_of_string(&map_itr); + mc = map_itr; + sc = s; + match = 1; + while ((*mc) && (*sc)) + { + if ((unsigned char)*sc < (unsigned char)*mc) return NULL; + if (*sc != *mc) match = 0; + mc++; + sc++; + } + if (match) + { + *adv = mc - map_itr; + return escape; + } + _escaped_advance_after_end_of_string(&map_itr); } return NULL; } @@ -2994,10 +2985,10 @@ _escaped_char_get(const char *s, const char *s_end) while (map_itr < map_end) { - if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end)) - return map_itr; - if (map_itr < map_end) - _escaped_advance_after_end_of_string(&map_itr); + if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end)) + return map_itr; + if (map_itr < map_end) + _escaped_advance_after_end_of_string(&map_itr); } return NULL; } @@ -3042,7 +3033,7 @@ evas_textblock_string_escape_get(const char *string, int *len_ret) /* Appends the escaped char beteewn s and s_end to the curosr */ static inline void _append_escaped_char(Evas_Textblock_Cursor *cur, const char *s, - const char *s_end) + const char *s_end) { const char *escape; @@ -3053,7 +3044,7 @@ _append_escaped_char(Evas_Textblock_Cursor *cur, const char *s, static inline void _prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s, - const char *s_end) + const char *s_end) { const char *escape; @@ -3062,6 +3053,7 @@ _prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s, evas_textblock_cursor_text_prepend(cur, escape); } + /** * to be documented. * @param obj to be documented. @@ -3074,150 +3066,28 @@ evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text) TB_HEAD(); if ((text != o->markup_text) && (o->markup_text)) { - free(o->markup_text); - o->markup_text = NULL; + free(o->markup_text); + o->markup_text = NULL; } _nodes_clear(obj); - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - evas_object_change(obj); if (!o->style) { - if (text != o->markup_text) - { - if (text) o->markup_text = strdup(text); - } - return; + if (text != o->markup_text) + { + if (text) o->markup_text = strdup(text); + } + return; } - evas_textblock_cursor_node_first(o->cursor); - if (text) - { - char *s, *p; - char *tag_start, *tag_end, *esc_start, *esc_end; + evas_textblock_cursor_paragraph_first(o->cursor); - tag_start = tag_end = esc_start = esc_end = NULL; - p = (char *)text; - s = p; - /* This loop goes through all of the mark up text until it finds format - * tags, escape sequences or the terminating NULL. When it finds either - * of those, it appends the text found up until that point to the textblock - * proccesses whatever found. It repeats itself until the termainating - * NULL is reached. */ - for (;;) - { - /* If we got to the end of string or just finished/started tag - * or escape sequence handling. */ - if ((*p == 0) || - (tag_end) || (esc_end) || - (tag_start) || (esc_start)) - { - if (tag_end) - { - /* If we reached to a tag ending, analyze the tag */ - /* FIXME: Move tag analyzing to a different function */ - char *ttag; - size_t ttag_len = tag_end - tag_start -1; - - ttag = malloc(ttag_len + 1); - if (ttag) - { - const char *match; - size_t replace_len; - - memcpy(ttag, tag_start + 1, ttag_len); - ttag[ttag_len] = 0; - match = _style_match_tag(o->style, ttag, ttag_len, &replace_len); - if (match) - evas_textblock_cursor_format_append(o->cursor, match); - else - { - char *ttag2; - - ttag2 = malloc(ttag_len + 2 + 1); - if (ttag2) - { - if (ttag[0] == '/') - { - strcpy(ttag2, "- "); - strcat(ttag2, ttag + 1); - } - else - { - strcpy(ttag2, "+ "); - strcat(ttag2, ttag); - } - evas_textblock_cursor_format_append(o->cursor, ttag2); - free(ttag2); - } - } - free(ttag); - } - tag_start = tag_end = NULL; - } - else if (esc_end) - { - _append_escaped_char(o->cursor, esc_start, esc_end); - esc_start = esc_end = NULL; - } - else if (*p == 0) - { - _append_text_run(o, s, p); - s = NULL; - } - if (*p == 0) - break; - } - if (*p == '<') - { - if (!esc_start) - { - /* Append the text prior to this to the textblock and mark - * the start of the tag */ - tag_start = p; - tag_end = NULL; - _append_text_run(o, s, p); - s = NULL; - } - } - else if (*p == '>') - { - if (tag_start) - { - tag_end = p; - s = p + 1; - } - } - else if (*p == '&') - { - if (!tag_start) - { - /* Append the text prior to this to the textblock and mark - * the start of the escape sequence */ - esc_start = p; - esc_end = NULL; - _append_text_run(o, s, p); - s = NULL; - } - } - else if (*p == ';') - { - if (esc_start) - { - esc_end = p; - s = p + 1; - } - } - p++; - } - } + evas_object_textblock_text_markup_prepend(o->cursor, text); { Eina_List *l; Evas_Textblock_Cursor *data; - evas_textblock_cursor_node_first(o->cursor); + evas_textblock_cursor_paragraph_first(o->cursor); EINA_LIST_FOREACH(o->cursors, l, data) - evas_textblock_cursor_node_first(data); + evas_textblock_cursor_paragraph_first(data); } } @@ -3230,129 +3100,191 @@ evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text) EAPI void evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text) { - Evas_Object_Textblock *o; - - if (!cur) return; - o = (Evas_Object_Textblock *)(cur->obj->object_data); - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - evas_object_change(cur->obj); - if (!o->style) return; + Evas_Object *obj = cur->obj; + TB_HEAD(); if (text) { - char *s, *p; - char *tag_start, *tag_end, *esc_start, *esc_end; + char *s, *p; + char *tag_start, *tag_end, *esc_start, *esc_end; - tag_start = tag_end = esc_start = esc_end = NULL; - p = (char *)text; - s = p; - for (;;) - { - if ((*p == 0) || - (tag_end) || (esc_end) || - (tag_start) || (esc_start)) - { - if (tag_end) - { - char *ttag; - size_t ttag_len = tag_end - tag_start - 1; + tag_start = tag_end = esc_start = esc_end = NULL; + p = (char *)text; + s = p; + /* This loop goes through all of the mark up text until it finds format + * tags, escape sequences or the terminating NULL. When it finds either + * of those, it appends the text found up until that point to the textblock + * proccesses whatever found. It repeats itself until the termainating + * NULL is reached. */ + for (;;) + { + /* If we got to the end of string or just finished/started tag + * or escape sequence handling. */ + if ((*p == 0) || + (tag_end) || (esc_end) || + (tag_start) || (esc_start)) + { + if (tag_end) + { + /* If we reached to a tag ending, analyze the tag */ + /* FIXME: Move tag analyzing to a different function */ + char *ttag; + size_t ttag_len = tag_end - tag_start -1; - ttag = malloc(ttag_len + 1); - if (ttag) - { - const char *match; - size_t replace_len; - strncpy(ttag, tag_start + 1, ttag_len); - ttag[ttag_len] = 0; - match = _style_match_tag(o->style, ttag, ttag_len, &replace_len); - if (match) - evas_textblock_cursor_format_prepend(cur, match); - else - { - char *ttag2; + ttag = malloc(ttag_len + 1); + if (ttag) + { + const char *match; + size_t replace_len; - ttag2 = malloc(ttag_len + 2 + 1); - if (ttag2) - { - if (ttag[0] == '/') - { - strcpy(ttag2, "- "); - strcat(ttag2, ttag + 1); - } - else - { - strcpy(ttag2, "+ "); - strcat(ttag2, ttag); - } - evas_textblock_cursor_format_prepend(o->cursor, ttag2); - free(ttag2); - } - } - free(ttag); - } - tag_start = tag_end = NULL; - } - else if (esc_end) - { - _prepend_escaped_char(cur, esc_start, esc_end); - esc_start = esc_end = NULL; - } - else if (*p == 0) - { - _prepend_text_run(o, s, p); - s = NULL; - } - if (*p == 0) - break; - } - if (*p == '<') - { - if (!esc_start) - { - tag_start = p; - tag_end = NULL; - _prepend_text_run(o, s, p); - s = NULL; - } - } - else if (*p == '>') - { - if (tag_start) - { - tag_end = p; - s = p + 1; - } - } - else if (*p == '&') - { - if (!tag_start) - { - esc_start = p; - esc_end = NULL; - _prepend_text_run(o, s, p); - s = NULL; - } - } - else if (*p == ';') - { - if (esc_start) - { - esc_end = p; - s = p + 1; - } - } - p++; - } + memcpy(ttag, tag_start + 1, ttag_len); + ttag[ttag_len] = 0; + match = _style_match_tag(o->style, ttag, ttag_len, &replace_len); + if (match) + { + evas_textblock_cursor_format_prepend(o->cursor, match); + } + else + { + char *ttag2; + + ttag2 = malloc(ttag_len + 2 + 1); + if (ttag2) + { + if (ttag[0] == '/') + { + strcpy(ttag2, "- "); + strcat(ttag2, ttag + 1); + } + else + { + strcpy(ttag2, "+ "); + strcat(ttag2, ttag); + } + evas_textblock_cursor_format_prepend(o->cursor, ttag2); + free(ttag2); + } + } + free(ttag); + } + tag_start = tag_end = NULL; + } + else if (esc_end) + { + _prepend_escaped_char(o->cursor, esc_start, esc_end); + esc_start = esc_end = NULL; + } + else if (*p == 0) + { + _prepend_text_run(o, s, p); + s = NULL; + } + if (*p == 0) + break; + } + if (*p == '<') + { + if (!esc_start) + { + /* Append the text prior to this to the textblock and mark + * the start of the tag */ + tag_start = p; + tag_end = NULL; + _prepend_text_run(o, s, p); + s = NULL; + } + } + else if (*p == '>') + { + if (tag_start) + { + tag_end = p; + s = p + 1; + } + } + else if (*p == '&') + { + if (!tag_start) + { + /* Append the text prior to this to the textblock and mark + * the start of the escape sequence */ + esc_start = p; + esc_end = NULL; + _prepend_text_run(o, s, p); + s = NULL; + } + } + else if (*p == ';') + { + if (esc_start) + { + esc_end = p; + s = p + 1; + } + } + p++; + } } + _evas_textblock_changed(o, obj); } +static void +_markup_get_format_append(Evas_Object_Textblock *o, Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode) +{ + size_t replace_len; + size_t tag_len; + const char *tag; + const char *replace; + + replace_len = eina_strbuf_length_get(fnode->format); + replace = eina_strbuf_string_get(fnode->format); + tag = _style_match_replace(o->style, replace, replace_len, &tag_len); + eina_strbuf_append_char(txt, '<'); + if (tag) + { + eina_strbuf_append_length(txt, tag, tag_len); + } + else + { + const char *s; + int push = 0; + int pop = 0; + + // FIXME: need to escape + s = eina_strbuf_string_get(fnode->format); + if (*s == '+') push = 1; + if (*s == '-') pop = 1; + while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; + if (pop) eina_strbuf_append_char(txt, '/'); + eina_strbuf_append(txt, s); + } + eina_strbuf_append_char(txt, '>'); +} + +static void +_markup_get_text_append(Eina_Strbuf *txt, const Eina_Unicode *text) +{ + char *p = evas_common_encoding_unicode_to_utf8(text, NULL); + char *base = p; + while (*p) + { + const char *escape; + int adv; + + escape = _escaped_char_match(p, &adv); + if (escape) + { + p += adv; + eina_strbuf_append(txt, escape); + } + else + { + eina_strbuf_append_char(txt, *p); + p++; + } + } + free(base); +} /** * to be documented. * @param obj to be documented. @@ -3361,72 +3293,305 @@ evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char EAPI const char * evas_object_textblock_text_markup_get(const Evas_Object *obj) { - Evas_Object_Textblock_Node *n; + Evas_Object_Textblock_Node_Text *n; Eina_Strbuf *txt = NULL; TB_HEAD_RETURN(NULL); if (o->markup_text) return(o->markup_text); txt = eina_strbuf_new(); - EINA_INLIST_FOREACH(o->nodes, n) + EINA_INLIST_FOREACH(o->text_nodes, n) { - size_t replace_len; - if ((n->type == NODE_FORMAT) && (replace_len = eina_strbuf_length_get(n->data.format))) - { - size_t tag_len; - const char *tag = _style_match_replace(o->style, eina_strbuf_string_get(n->data.format), replace_len, &tag_len); - eina_strbuf_append_char(txt, '<'); - if (tag) - { - // FIXME: need to escape - eina_strbuf_append_length(txt, tag, tag_len); - } - else - { - const char *s; - int push = 0; - int pop = 0; + Evas_Object_Textblock_Node_Format *fnode; + Eina_Unicode *text_base, *text; + int off; + int first_run; - // FIXME: need to escape - s = eina_strbuf_string_get(n->data.format); - if (*s == '+') push = 1; - if (*s == '-') pop = 1; - while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; - if (pop) eina_strbuf_append_char(txt, '/'); - if (push) eina_strbuf_append(txt, "+ "); - eina_strbuf_append(txt, s); - } - eina_strbuf_append_char(txt, '>'); - } - else if ((n->type == NODE_TEXT) && (replace_len = eina_ustrbuf_length_get(n->data.text.unicode))) - { - char *p = evas_common_encoding_unicode_to_utf8(eina_ustrbuf_string_get(n->data.text.unicode), NULL); - char *base = p; - while (*p) - { - const char *escape; - int adv; - - escape = _escaped_char_match(p, &adv); - if (escape) - { - p += adv; - eina_strbuf_append(txt, escape); - } - else - { - eina_strbuf_append_char(txt, *p); - p++; - } - } - free(base); - } + text_base = text = + eina_unicode_strdup(eina_ustrbuf_string_get(n->unicode)); + fnode = n->format_node; + off = 0; + first_run = 1; + while (fnode && (fnode->text_node == n)) + { + Eina_Unicode tmp_ch; + off += fnode->offset; + /* No need to skip on the first run */ + tmp_ch = text[off]; + text[off] = 0; /* Null terminate the part of the string */ + _markup_get_text_append(txt, text); + _markup_get_format_append(o, txt, fnode); + text[off] = tmp_ch; /* Restore the char */ + text += off; + if (fnode->visible) + { + off = -1; + text++; + } + else + { + off = 0; + } + first_run = 0; + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + } + /* Add the rest, skip replacement */ + _markup_get_text_append(txt, text); + free(text_base); } + + o->markup_text = eina_strbuf_string_steal(txt); eina_strbuf_free(txt); return o->markup_text; } /* cursors */ + +static void +_evas_textblock_node_update_format(Evas_Object_Textblock_Node_Text *n, + Evas_Object_Textblock_Node_Format *fmt) +{ + Evas_Object_Textblock_Node_Text *itr; + itr = n; + while (itr && (itr->format_node->text_node != itr)) + { + itr->format_node = fmt; + } +} + + +/* Merge the current node with the next, no need to remove, already + * not there. */ +static void +_evas_textblock_nodes_merge(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *to, + Evas_Object_Textblock_Node_Text *from) +{ + Evas_Object_Textblock_Node_Format *itr; + Evas_Object_Textblock_Node_Format *pnode; + const Eina_Unicode *text; + int to_len, len; + + if (!to || !from) return; + + to_len = eina_ustrbuf_length_get(to->unicode); + text = eina_ustrbuf_string_get(from->unicode); + len = eina_ustrbuf_length_get(from->unicode); + eina_ustrbuf_append_length(to->unicode, text, len); + + itr = from->format_node; + if (itr && (itr->text_node == from)) + { + pnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->prev); + if (pnode && (pnode->text_node == to)) + { + itr->offset += to_len - _evas_textblock_node_format_pos_get(pnode); + itr->offset -= (pnode->visible) ? 1 : 0; + } + else + { + itr->offset += to_len; + } + } + + while (itr && (itr->text_node == from)) + { + itr->text_node = to; + itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); + } + if (!to->format_node || (to->format_node->text_node != to)) + { + to->format_node = from->format_node; + } + + o->text_nodes = _NODE_TEXT(eina_inlist_remove( + EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(from))); + _evas_textblock_node_text_free(from); +} +static void +_evas_textblock_cursor_nodes_merge(Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Text *nnode; + Evas_Object_Textblock *o; + + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next); + _evas_textblock_nodes_merge(o, cur->node, nnode); + { + Eina_List *l; + Evas_Textblock_Cursor *data; + int len; + len = eina_ustrbuf_length_get(cur->node->unicode); + + if (nnode == o->cursor->node) + { + o->cursor->node = cur->node; + o->cursor->pos += len; + } + EINA_LIST_FOREACH(o->cursors, l, data) + { + if (nnode == data->node) + { + data->node = cur->node; + data->pos += len; + } + } + } +} +/** + * Return the format at a specific position. + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static Evas_Object_Textblock_Node_Format * +_evas_textblock_cursor_node_format_at_pos_get(const Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Format *node; + Evas_Object_Textblock_Node_Format *itr; + size_t position = 0; + + if (!cur->node) return NULL; + + node = cur->node->format_node; + if (!node) return NULL; + /* If there is no exclusive format node to this paragraph return the + * previous's node */ + /* Find the main format node */ + EINA_INLIST_FOREACH(node, itr) + { + if (itr->text_node != cur->node) + { + return NULL; + } + if ((position + itr->offset) == cur->pos) + { + return itr; + } + position += itr->offset; + } + return NULL; +} + +static Evas_Object_Textblock_Node_Format * +_evas_textblock_node_format_last_at_off(const Evas_Object_Textblock_Node_Format *n) +{ + const Evas_Object_Textblock_Node_Format *nnode; + if (!n) return NULL; + nnode = n; + do + { + n = nnode; + nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); + } + while (nnode && (nnode->offset == 0)); + + return (Evas_Object_Textblock_Node_Format *) n; +} + +static Evas_Object_Textblock_Node_Format * +_evas_textblock_node_visible_at_pos_get(const Evas_Object_Textblock_Node_Format *n) +{ + const Evas_Object_Textblock_Node_Format *nnode; + if (!n) return NULL; + + nnode = n; + do + { + n = nnode; + if (n->visible) return (Evas_Object_Textblock_Node_Format *) n; + nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); + } + while (nnode && (nnode->offset == 0)); + + return NULL; +} +/** + * Return the last format that applies to a specific cursor. + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static Evas_Object_Textblock_Node_Format * +_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Format *node, *pitr = NULL; + Evas_Object_Textblock_Node_Format *itr; + size_t position = 0; + + if (!cur->node) return NULL; + + node = cur->node->format_node; + if (!node) return NULL; + /* If there is no exclusive format node to this paragraph return the + * previous's node */ + if (node->text_node != cur->node) + { + return node; + } + else if (node->offset > cur->pos) + { + return _NODE_FORMAT(EINA_INLIST_GET(node)->prev); + } + /* Find the main format node */ + pitr = _NODE_FORMAT(EINA_INLIST_GET(node)->prev); + EINA_INLIST_FOREACH(node, itr) + { + if ((itr->text_node != cur->node) || + ((position + itr->offset) > cur->pos)) + { + return pitr; + } + else if ((position + itr->offset) == cur->pos) + { + return itr; + } + pitr = itr; + position += itr->offset; + } + return pitr; +} +/** + * Returns the last format of a text node that applies to the cursor + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static Evas_Object_Textblock_Node_Format * +_evas_textblock_cursor_node_format_before_pos_get(const Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Format *node, *pitr = NULL; + Evas_Object_Textblock_Node_Format *itr; + size_t position = 0; + + if (!cur->node) return NULL; + + node = cur->node->format_node; + if (!node) return NULL; + /* If there is no exclusive format node to this paragraph return the + * previous's node */ + if (node->text_node != cur->node) + { + return node; + } + else if (node->offset > cur->pos) + { + return _NODE_FORMAT(EINA_INLIST_GET(node)->prev); + } + /* Find the main format node */ + pitr = _NODE_FORMAT(EINA_INLIST_GET(node)->prev); + EINA_INLIST_FOREACH(node, itr) + { + position += itr->offset; + if ((itr->text_node != cur->node) || + (position >= cur->pos)) + { + return pitr; + } + pitr = itr; + } + return pitr; +} /** * to be documented. * @param obj to be documented. @@ -3452,9 +3617,9 @@ evas_object_textblock_cursor_new(Evas_Object *obj) TB_HEAD_RETURN(NULL); cur = calloc(1, sizeof(Evas_Textblock_Cursor)); cur->obj = obj; - cur->node = o->nodes; + cur->node = o->text_nodes; cur->pos = 0; - cur->eol = 0; + o->cursors = eina_list_append(o->cursors, cur); return cur; } @@ -3477,89 +3642,273 @@ evas_textblock_cursor_free(Evas_Textblock_Cursor *cur) } /** + * Returns true if the cursor points to a format. * to be documented. * @param cur to be documented. * @return Returns no value. */ -EAPI void -evas_textblock_cursor_node_first(Evas_Textblock_Cursor *cur) +EAPI Eina_Bool +evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur) { - Evas_Object_Textblock *o; - - if (!cur) return; - o = (Evas_Object_Textblock *)(cur->obj->object_data); - cur->node = o->nodes; - cur->pos = 0; - cur->eol = 0; + if (!cur || !cur->node) return; + if (evas_textblock_cursor_format_is_visible_get(cur)) return EINA_TRUE; + return (_evas_textblock_cursor_node_format_at_pos_get(cur)) ? + EINA_TRUE : EINA_FALSE; } /** + * Returns the first format node. + * + * @param o The textblock, must not be NULL. + * @return Returns the first format node, may be null if there are none. + */ +EAPI const Evas_Object_Textblock_Node_Format * +evas_textblock_node_format_first_get(const Evas_Object *obj) +{ + TB_HEAD_RETURN(NULL); + return o->format_nodes; +} +/** + * Returns the last format node. + * + * @param o The textblock, must not be NULL. + * @return Returns the first format node, may be null if there are none. + */ +EAPI const Evas_Object_Textblock_Node_Format * +evas_textblock_node_format_last_get(const Evas_Object *obj) +{ + TB_HEAD_RETURN(NULL); + if (o->format_nodes) + { + return _NODE_FORMAT(EINA_INLIST_GET(o->format_nodes)->last); + } + return NULL; +} +/** + * Returns the last format node. + * + * @param o The textblock, must not be NULL. + * @return Returns the first format node, may be null if there are none. + */ +EAPI const Evas_Object_Textblock_Node_Format * +evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n) +{ + return _NODE_FORMAT(EINA_INLIST_GET(n)->next); +} +/** + * Returns the last format node. + * + * @param o The textblock, must not be NULL. + * @return Returns the first format node, may be null if there are none. + */ +EAPI const Evas_Object_Textblock_Node_Format * +evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n) +{ + return _NODE_FORMAT(EINA_INLIST_GET(n)->prev); +} +/** + * Sets the cursor to the start of the first text node/visible format. * to be documented. * @param cur to be documented. * @return Returns no value. */ EAPI void -evas_textblock_cursor_node_last(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur) { Evas_Object_Textblock *o; + if (!cur) return; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + cur->node = o->text_nodes; + cur->pos = 0; + +} + +/** + * sets the cursor to the end of the last text node/visible format. + * to be documented. + * @param cur to be documented. + * @return Returns no value. + */ +EAPI void +evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock *o; + Evas_Object_Textblock_Node_Text *node; if (!cur) return; o = (Evas_Object_Textblock *)(cur->obj->object_data); - if (o->nodes) + node = o->text_nodes; + if (node) { - cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(o->nodes))->last); + node = _NODE_TEXT(EINA_INLIST_GET(node)->last); + cur->node = node; cur->pos = 0; - cur->eol = 0; // 1 - evas_textblock_cursor_char_last(cur); + + evas_textblock_cursor_paragraph_char_last(cur); } else { cur->node = NULL; cur->pos = 0; - cur->eol = 0; // 1 + } } /** + * Advances to the next text node * to be documented. * @param cur to be documented. * @return to be documented. */ EAPI Eina_Bool -evas_textblock_cursor_node_next(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur) { if (!cur) return EINA_FALSE; if (!cur->node) return EINA_FALSE; - if ((EINA_INLIST_GET(cur->node))->next) + /* If there is a current text node, return the next text node (if exists) + * otherwise, just return False. */ + if (cur->node) { - cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(cur->node))->next); - cur->pos = 0; - cur->eol = 0; - return EINA_TRUE; + Evas_Object_Textblock_Node_Text *nnode; + nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next); + if (nnode) + { + cur->node = nnode; + cur->pos = 0; + + return EINA_TRUE; + } } return EINA_FALSE; } /** + * Advances to the previous text node. * to be documented. * @param cur to be documented. * @return to be documented. */ EAPI Eina_Bool -evas_textblock_cursor_node_prev(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur) { + Evas_Object_Textblock_Node_Text *node; if (!cur) return EINA_FALSE; if (!cur->node) return EINA_FALSE; - if ((EINA_INLIST_GET(cur->node))->prev) + /* If the current node is a text node, just get the prev if any, + * if it's a format, get the current text node out of the format and return + * the prev text node if any. */ + node = cur->node; + /* If there is a current text node, return the prev text node + * (if exists) otherwise, just return False. */ + if (node) { - cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(cur->node))->prev); - evas_textblock_cursor_char_last(cur); - return EINA_TRUE; + Evas_Object_Textblock_Node_Text *pnode; + pnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->prev); + if (pnode) + { + cur->node = pnode; + evas_textblock_cursor_paragraph_char_last(cur); + return EINA_TRUE; + } + } + return EINA_FALSE; +} +EAPI void +evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n) +{ + if (!cur || !n) return; + cur->node = n->text_node; + cur->pos = _evas_textblock_node_format_pos_get(n); +} +/** + * Advances to the next format node + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI Eina_Bool +evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Format *node; + + if (!cur) return EINA_FALSE; + if (!cur->node) return EINA_FALSE; + /* If the current node is a format node, just get the next if any, + * if it's a text, get the current format node out of the text and return + * the next format node if any. */ + node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); + node = _evas_textblock_node_format_last_at_off(node); + if (!node) + { + if (cur->node->format_node) + { + cur->node = cur->node; + cur->pos = _evas_textblock_node_format_pos_get(node); + + return EINA_TRUE; + } + } + /* If there is a current text node, return the next format node (if exists) + * otherwise, just return False. */ + else + { + Evas_Object_Textblock_Node_Format *nnode; + nnode = _NODE_FORMAT(EINA_INLIST_GET(node)->next); + if (nnode) + { + cur->node = nnode->text_node; + cur->pos = _evas_textblock_node_format_pos_get(nnode); + + return EINA_TRUE; + } } return EINA_FALSE; } /** + * Advances to the previous format node. + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI Eina_Bool +evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) +{ + Evas_Object_Textblock_Node_Format *node; + if (!cur) return EINA_FALSE; + if (!cur->node) return EINA_FALSE; + /* If the current node is a format node, just get the next if any, + * if it's a text, get the current format node out of the text and return + * the next format node if any. */ + node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); + if (evas_textblock_cursor_is_format(cur)) + { + if (node) + { + cur->pos = _evas_textblock_node_format_pos_get(node); + + return EINA_TRUE; + } + } + /* If there is a current text node, return the next text node (if exists) + * otherwise, just return False. */ + if (node) + { + Evas_Object_Textblock_Node_Format *pnode; + pnode = _NODE_FORMAT(EINA_INLIST_GET(node)->prev); + if (pnode) + { + cur->node = pnode->text_node; + cur->pos = _evas_textblock_node_format_pos_get(node); + + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +/** + * Advances 1 char * to be documented. * @param cur to be documented. * @return to be documented. @@ -3567,39 +3916,38 @@ evas_textblock_cursor_node_prev(Evas_Textblock_Cursor *cur) EAPI Eina_Bool evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) { - int index, ch; + int index; + const Eina_Unicode *text; if (!cur) return EINA_FALSE; if (!cur->node) return EINA_FALSE; - if (cur->node->type == NODE_FORMAT) return EINA_FALSE; - if (!eina_ustrbuf_length_get(cur->node->data.text.unicode)) return EINA_FALSE; + index = cur->pos; - - if (cur->node->type == NODE_TEXT) + text = eina_ustrbuf_string_get(cur->node->unicode); + GET_NEXT(text, index); + /* Only allow pointing a null if it's the last paragraph. + * because we don't have a PS there. */ + if (text[index]) { - Evas_Object_Textblock_Line *ln = NULL; - Evas_Object_Textblock_Item *it = NULL; - int pos; - - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); - if (it) + cur->pos = index; + return EINA_TRUE; + } + else + { + if (!evas_textblock_cursor_paragraph_next(cur)) { - pos = cur->pos - it->source_pos; - if (pos <= 0) index -= pos; + cur->pos = index; + return EINA_TRUE; } else - printf("TB: 'it' not found\n"); + { + return EINA_FALSE; + } } - - ch = GET_NEXT(eina_ustrbuf_string_get(cur->node->data.text.unicode), index); - if ((ch == 0) || (index < 0)) return EINA_FALSE; - if (eina_ustrbuf_string_get(cur->node->data.text.unicode)[index] == 0) return EINA_FALSE; - cur->pos = index; - cur->eol = 0; // 1 - return EINA_TRUE; } /** + * Goes back one char (only works on text nodes). * to be documented. * @param cur to be documented. * @return to be documented. @@ -3607,99 +3955,58 @@ evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) EAPI Eina_Bool evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) { - int index; - int at_end_of_line = 0; - int at_start_of_line = 0; - if (!cur) return EINA_FALSE; if (!cur->node) return EINA_FALSE; - if (cur->node->type == NODE_FORMAT) return EINA_FALSE; - if (!eina_ustrbuf_length_get(cur->node->data.text.unicode)) return EINA_FALSE; - index = cur->pos; - if (index == 0) return EINA_FALSE; - // XXX: FIXME: determine at_end_of_line and at_start_of_line - - if (cur->node->type == NODE_TEXT) + if (cur->pos != 0) { - Evas_Object_Textblock_Line *ln = NULL; - Evas_Object_Textblock_Item *it = NULL; - int pos; - - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); - if (it) - { - pos = cur->pos - it->source_pos; - if (pos <= 0) at_start_of_line = 1; - if (it->text) - { - int plast; - - plast = eina_unicode_strlen(it->text) - 1; - if (plast < 0) plast = 0; - if ((index - it->source_pos) == plast) at_end_of_line = 1; - } - } - } - - if ((cur->eol) && (at_end_of_line)) - { - cur->eol = 0; + cur->pos--; return EINA_TRUE; } - GET_PREV(eina_ustrbuf_string_get(cur->node->data.text.unicode), index); - if (/*(ch == 0) || */(index < 0)) return EINA_FALSE; - cur->pos = index; - if (at_start_of_line) - cur->eol =1; - else - cur->eol = 0; - return EINA_TRUE; + return evas_textblock_cursor_paragraph_prev(cur); } /** + * Go to the first char in the node the cursor is pointing on. * to be documented. * @param cur to be documented. * @return Returns no value. */ EAPI void -evas_textblock_cursor_char_first(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur) { if (!cur) return; cur->pos = 0; - cur->eol = 0; + } /** + * Go to the last char in a text node. * to be documented. * @param cur to be documented. * @return Returns no value. */ EAPI void -evas_textblock_cursor_char_last(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur) { int index; if (!cur) return; if (!cur->node) return; - if (cur->node->type == NODE_FORMAT) - { - cur->pos = 0; - return; - } - index = eina_unicode_strlen(eina_ustrbuf_string_get(cur->node->data.text.unicode)) - 1; + index = eina_unicode_strlen(eina_ustrbuf_string_get(cur->node->unicode)) - 1; if (index < 0) cur->pos = 0; cur->pos = index; - cur->eol = 0; // 1 + } /** + * Go to the start of the current line * to be documented. * @param cur to be documented. * @return Returns no value. */ EAPI void -evas_textblock_cursor_line_first(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur) { Evas_Object_Textblock *o; Evas_Object_Textblock_Line *ln = NULL; @@ -3710,12 +4017,20 @@ evas_textblock_cursor_line_first(Evas_Textblock_Cursor *cur) if (!cur->node) return; o = (Evas_Object_Textblock *)(cur->obj->object_data); if (!o->formatted.valid) _relayout(cur->obj); - if (cur->node->type == NODE_FORMAT) - _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi); + if (evas_textblock_cursor_format_is_visible_get(cur)) + { + _find_layout_format_item_line_match(cur->obj, + _evas_textblock_node_visible_at_pos_get( + _evas_textblock_cursor_node_format_before_or_at_pos_get(cur)), + &ln, &fi); + } else - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); + { + _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it); + } + if (!ln) return; - cur->eol = 0; + it = (Evas_Object_Textblock_Item *)ln->items; fi = (Evas_Object_Textblock_Format_Item *)ln->format_items; if ((it) && (fi)) @@ -3730,18 +4045,19 @@ evas_textblock_cursor_line_first(Evas_Textblock_Cursor *cur) } else if (fi) { - cur->pos = 0; - cur->node = fi->source_node; + cur->node = fi->source_node->text_node; + cur->pos = _evas_textblock_node_format_pos_get(fi->source_node); } } /** + * Go to the end of the current line. * to be documented. * @param cur to be documented. * @return Returns no value. */ EAPI void -evas_textblock_cursor_line_last(Evas_Textblock_Cursor *cur) +evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur) { Evas_Object_Textblock *o; Evas_Object_Textblock_Line *ln = NULL; @@ -3753,11 +4069,19 @@ evas_textblock_cursor_line_last(Evas_Textblock_Cursor *cur) o = (Evas_Object_Textblock *)(cur->obj->object_data); if (!o->formatted.valid) _relayout(cur->obj); // kills "click below text" and up/downm arrow. disable -// cur->eol = 1; - if (cur->node->type == NODE_FORMAT) - _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi); + + if (evas_textblock_cursor_format_is_visible_get(cur)) + { + _find_layout_format_item_line_match(cur->obj, + _evas_textblock_node_visible_at_pos_get( + _evas_textblock_cursor_node_format_before_or_at_pos_get(cur)), + &ln, &fi); + } else - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); + { + _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it); + } + if (!ln) return; if (ln->items) it = (Evas_Object_Textblock_Item *)((EINA_INLIST_GET(ln->items))->last); @@ -3786,13 +4110,232 @@ evas_textblock_cursor_line_last(Evas_Textblock_Cursor *cur) } else if (fi) { - cur->pos = 0; - cur->eol = 0; - cur->node = fi->source_node; + cur->node = fi->source_node->text_node; + cur->pos = _evas_textblock_node_format_pos_get(fi->source_node); + } +} + +static Eina_Bool +_evas_textblock_format_is_visible(const char *s) +{ + if (!s) return EINA_FALSE; + const char *item; + + if (s[0] == '+' || s[0] == '-') + { + s++; + } + while ((item = _format_parse(&s))) + { + char *tmp; + tmp = alloca(s - item + 1); + strncpy(tmp, item, s - item); + tmp[s - item] = '\0'; + if (((!strcmp(item, "\n")) || (!strcmp(item, "\\n"))) || + ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) || + (!strcmp(item, "ps")) || + (!strcmp(item, "item"))) + return EINA_TRUE; + } + return EINA_FALSE; +} + +/** + * Sets the cursor to the position of where the fmt points to. + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static void +_evas_textblock_cursor_node_text_at_format(Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Node_Format *fmt) +{ + Evas_Object_Textblock_Node_Text *text; + Evas_Object_Textblock_Node_Format *base_format; + Evas_Object_Textblock_Node_Format *itr; + size_t position = 0; + + if (!cur || !fmt) return; + /* Find the main format node */ + text = fmt->text_node; + cur->node = text; + base_format = text->format_node; + EINA_INLIST_FOREACH(base_format, itr) + { + if (itr == fmt) + { + break; + } + position += itr->offset; + } + cur->pos = position; + +} +/** + * Reduce offset from the next offset FIXME: doc + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static void +_evas_textblock_node_format_adjust_offset(Evas_Object_Textblock *o, + Evas_Object_Textblock_Node_Text *tnode, + Evas_Object_Textblock_Node_Format *fmt, int offset) +{ + size_t position = 0; + + if (fmt) + { + fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next); + } + else + { + fmt = o->format_nodes; + } + if (fmt && (tnode == fmt->text_node)) + { + fmt->offset += offset; } } /** + * Removes a format node + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static void +_evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n) +{ + int visible_adjustment; + /* Update the text nodes about the change */ + { + Evas_Object_Textblock_Node_Format *nnode; + nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->next); + /* If there's a next node that belongs to the same text node + * and the curret node was the main one, advance the format node */ + if (nnode && (nnode->text_node == n->text_node)) + { + if (nnode->text_node->format_node == n) + { + nnode->text_node->format_node = nnode; + } + } + else + { + Evas_Object_Textblock_Node_Text *tnode; + /* If there's no next one update the text nodes */ + nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->prev); + tnode = n->text_node; + while (tnode && (tnode->format_node == n)) + { + tnode->format_node = nnode; + tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next); + } + } + } + /* If it's a visible format, reduce one */ + visible_adjustment = (n->visible) ? 1 : 0; + _evas_textblock_node_format_adjust_offset(o, n->text_node, n, + n->offset - visible_adjustment); + + o->format_nodes = _NODE_FORMAT(eina_inlist_remove( + EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n))); +} +static void +_evas_textblock_node_format_remove_all_at_pos(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n) +{ + Evas_Object_Textblock_Node_Format *nnode; + Evas_Object_Textblock_Node_Text *tnode; + int off; + nnode = n; + tnode = n->text_node; + do + { + Evas_Object_Textblock_Node_Format *curnode; + curnode = nnode; + nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); + off = nnode->offset; + + _evas_textblock_node_format_remove(o, curnode); + } + while (nnode && (nnode->text_node == tnode) && (off == 0)); +} + +/* end = -1 means to the end */ +static void +_evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o, + Evas_Object_Textblock_Node_Text *n, int start, int end) +{ + Evas_Object_Textblock_Node_Format *itr; + int use_end = 1; + int offset = 0; + itr = n->format_node; + if (end < 0) end = 0; + while (itr && (itr->text_node == n)) + { + if ((end <= 0) && use_end) + { + itr->offset += offset; + break; + } + if (start <= 0) + { + offset += itr->offset; + _evas_textblock_node_format_remove(o, itr); + } + else + { + start -= itr->offset; + } + end -= itr->offset; + itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); + } +} + +/** + * Removes a text node + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static void +_evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n) +{ + _evas_textblock_node_text_remove_formats_between(o, n, 0, -1); + o->text_nodes = _NODE_TEXT(eina_inlist_remove( + EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n))); +} +/** + * Return the position where the formats starts at. + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +static size_t +_evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt) +{ + Evas_Object_Textblock_Node_Text *text; + Evas_Object_Textblock_Node_Format *base_format; + Evas_Object_Textblock_Node_Format *itr; + size_t position = 0; + + if (!fmt) return 0; + /* Find the main format node */ + text = fmt->text_node; + base_format = text->format_node; + EINA_INLIST_FOREACH(base_format, itr) + { + if (itr == fmt) + { + break; + } + position += itr->offset; + } + return position + fmt->offset; +} + +/** + * Return the current cursor pos. * to be documented. * @param cur to be documented. * @return to be documented. @@ -3805,6 +4348,7 @@ evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur) } /** + * Set the cursor pos. * to be documented. * @param cur to be documented. * @param pos to be documented. @@ -3816,15 +4360,15 @@ evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int pos) if (!cur) return; if (!cur->node) return; - if (cur->node->type == NODE_FORMAT) pos = 0; - len = eina_ustrbuf_length_get(cur->node->data.text.unicode); + len = eina_ustrbuf_length_get(cur->node->unicode); if (pos < 0) pos = 0; else if (pos > len) pos = len; cur->pos = pos; - cur->eol = 0; + } /** + * Go to the start of the line passed * to be documented. * @param cur to be documented. * @param line to be documented. @@ -3854,25 +4398,25 @@ evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line) if (it) { cur->pos = it->source_pos; - cur->eol = 0; + cur->node = it->source_node; } else if (fi) { - cur->pos = 0; - cur->eol = 0; - cur->node = fi->source_node; + cur->node = fi->source_node->text_node; + cur->pos = _evas_textblock_node_format_pos_get(fi->source_node); } else { cur->pos = 0; - cur->eol = 0; - cur->node = o->nodes; + + cur->node = o->text_nodes; } return EINA_TRUE; } /** + * Compare two cursors. * to be documented. * @param cur1 to be documented. * @param cur2 to be documented. @@ -3891,9 +4435,7 @@ evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Text { if (cur1->pos < cur2->pos) return -1; /* cur1 < cur2 */ else if (cur1->pos > cur2->pos) return 1; /* cur2 < cur1 */ - if ((cur1->eol) == (cur1->eol)) return 0; /* cur1 == cur2 */ - if (cur1->eol) return 1; /* cur2 < cur1 */ - return -1; /* cur1 < cur2 */ + return 0; } for (l1 = EINA_INLIST_GET(cur1->node), l2 = EINA_INLIST_GET(cur1->node); (l1) || (l2);) @@ -3909,6 +4451,7 @@ evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Text } /** + * Make cur_dest point to the same place as cur. * to be documented. * @param cur to be documented. * @param cur_dest to be documented. @@ -3922,94 +4465,107 @@ evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Curs if (cur->obj != cur_dest->obj) return; cur_dest->pos = cur->pos; cur_dest->node = cur->node; - cur_dest->eol = cur->eol; + } /* text controls */ + +static void +_evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n) +{ + if (!n) return; + eina_ustrbuf_free(n->unicode); + if (n->utf8) + free(n->utf8); + free(n); +} + +static Evas_Object_Textblock_Node_Text * +_evas_textblock_node_text_new() +{ + Evas_Object_Textblock_Node_Text *n; + + n = calloc(1, sizeof(Evas_Object_Textblock_Node_Text)); + n->unicode = eina_ustrbuf_new(); +#ifdef BIDI_SUPPORT + n->bidi_props.direction = FRIBIDI_PAR_ON; +#endif + + return n; +} + /** * to be documented. * @param cur to be documented. * @param text to be documented. * @return Returns no value. */ -EAPI void -evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text) +static void +_evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur, + Evas_Object_Textblock_Node_Format *fnode) { Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *nrel; - Eina_Unicode *text; - int index, ch; + Evas_Object_Textblock_Node_Text *n; if (!cur) return; - text = evas_common_encoding_utf8_to_unicode(_text, NULL); o = (Evas_Object_Textblock *)(cur->obj->object_data); - if (text) - { - Eina_List *l; - Evas_Textblock_Cursor *data; - if (cur != o->cursor) - { - if (cur->node == o->cursor->node) - { - if (o->cursor->pos > cur->pos) - { - o->cursor->pos += eina_unicode_strlen(text); - } - } - } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if (data != cur) - { - if (cur->node == data->node) - { - if (data->pos > cur->pos) - { - data->pos += eina_unicode_strlen(text); - } - } - } - } - } - n = cur->node; - if ((!n) || (n->type == NODE_FORMAT)) + n = _evas_textblock_node_text_new(); + o->text_nodes = _NODE_TEXT(eina_inlist_append_relative( + EINA_INLIST_GET(o->text_nodes), + EINA_INLIST_GET(n), + EINA_INLIST_GET(cur->node))); + /* Handle text and format changes. */ + if (cur->node) { - nrel = n; - n = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n->type = NODE_TEXT; - n->data.text.unicode = eina_ustrbuf_new(); - if (nrel) - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nrel)); - else - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - } - cur->node = n; - index = cur->pos; - if (eina_ustrbuf_length_get(n->data.text.unicode)) - { - ch = GET_NEXT(eina_ustrbuf_string_get(n->data.text.unicode), index); - if (ch != 0) + Evas_Object_Textblock_Node_Format *nnode; + size_t len, start; + const Eina_Unicode *text; + + /* If there was a format node in the delete range, + * make it our format and update the text_node fields, + * otherwise, use the paragraph separator + * of the previous paragraph. */ + nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + if (nnode && (nnode->text_node == cur->node)) { - cur->pos = index; + n->format_node = nnode; + nnode->offset--; /* We don't have to take the replacement char + into account anymore */ + while (nnode && (nnode->text_node == cur->node)) + { + nnode->text_node = n; + nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); + } } - } - if (cur->pos >= (eina_ustrbuf_length_get(n->data.text.unicode) - 1)) - { - eina_ustrbuf_append(n->data.text.unicode, text); + else + { + n->format_node = fnode; + } + + /* cur->pos now points to the PS, move after. */ + start = cur->pos + 1; + text = eina_ustrbuf_string_get(cur->node->unicode); + len = eina_ustrbuf_length_get(cur->node->unicode) - start; + eina_ustrbuf_append_length(n->unicode, text + start, len); + eina_ustrbuf_remove(cur->node->unicode, start, start + len); } else { - eina_ustrbuf_insert(n->data.text.unicode, text, cur->pos); - } -// XXX: This makes no sense? - if (text) - { - cur->pos += eina_unicode_strlen(text); + Evas_Object_Textblock_Node_Format *fnode; + fnode = o->format_nodes; + if (fnode) + { + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->last); + } + n->format_node = fnode; } +} + +static void +_evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj) +{ o->formatted.valid = 0; o->native.valid = 0; o->changed = 1; @@ -4018,27 +4574,29 @@ evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text) free(o->markup_text); o->markup_text = NULL; } - _nodes_adjacent_merge(cur->obj, n); - evas_object_change(cur->obj); - free(text); -} + evas_object_change(obj); +} /** * to be documented. * @param cur to be documented. * @param text to be documented. - * @return Returns no value. + * @return Returns the len; */ -EAPI void -evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text) +EAPI size_t +evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text) { Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *nrel; + Evas_Object_Textblock_Node_Text *n; + Evas_Object_Textblock_Node_Format *fnode = NULL; Eina_Unicode *text; + size_t len = 0; - if (!cur) return; - text = evas_common_encoding_utf8_to_unicode(_text, NULL); + if (!cur) return 0; + text = evas_common_encoding_utf8_to_unicode(_text, &len); o = (Evas_Object_Textblock *)(cur->obj->object_data); + /*FIXME: should we? cause we don't. */ + /* Update all the cursors after our position. */ { Eina_List *l; Evas_Textblock_Cursor *data; @@ -4048,308 +4606,254 @@ evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text if (cur->node == o->cursor->node) { if ((o->cursor->node) && - (o->cursor->node->type == NODE_TEXT) && (o->cursor->pos >= cur->pos)) { o->cursor->pos += eina_unicode_strlen(text); } } } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if (data != cur) - { - if (cur->node == data->node) - { - if (data->node && - (data->node->type == NODE_TEXT) && - (data->pos >= cur->pos)) - { - data->pos += eina_unicode_strlen(text); - } - } - } - } } + n = cur->node; - if ((!n) || (n->type == NODE_FORMAT)) + if (n) { - nrel = n; - n = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n->type = NODE_TEXT; - n->data.text.unicode = eina_ustrbuf_new(); - if (nrel) - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nrel)); - else - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - } - if (!n->data.text.unicode) n->data.text.unicode = eina_ustrbuf_new(); - cur->node = n; - - if (text) - { - if (cur->pos > (eina_ustrbuf_length_get(n->data.text.unicode) - 1)) + Evas_Object_Textblock_Node_Format *nnode; + /*FIXME: won't work for invisible formats */ + if (evas_textblock_cursor_format_is_visible_get(cur)) { - eina_ustrbuf_append(n->data.text.unicode, text); + fnode = _evas_textblock_cursor_node_format_before_pos_get(cur); } else { - eina_ustrbuf_insert(n->data.text.unicode, text, cur->pos); + fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); + fnode = _evas_textblock_node_format_last_at_off(fnode); } - cur->pos += eina_unicode_strlen(text); - } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - _nodes_adjacent_merge(cur->obj, n); - evas_object_change(cur->obj); - free(text); -} - -/** - * to be documented. - * @param cur to be documented. - * @param format to be documented. - * @return Returns no value. - */ -EAPI void -evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) -{ - Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *nc, *n2; - - if (!cur) return; - if ((!format) || (format[0] == 0)) return; - o = (Evas_Object_Textblock *)(cur->obj->object_data); - nc = cur->node; - n = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n->type = NODE_FORMAT; - n->data.format = eina_strbuf_new(); - eina_strbuf_append(n->data.format, format); - if (!nc) - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - } - else if (nc->type == NODE_FORMAT) - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nc)); - } - else if (nc->type == NODE_TEXT) - { - int index, ch = 0; - - index = cur->pos; - if (eina_ustrbuf_length_get(nc->data.text.unicode)) - { - ch = GET_NEXT(eina_ustrbuf_string_get(nc->data.text.unicode), index); - if (ch != 0) - cur->pos = index; - } - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nc)); - if ((ch != 0) && (cur->pos < eina_ustrbuf_length_get(nc->data.text.unicode))) - { - n2 = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n2->type = NODE_TEXT; - n2->data.text.unicode = eina_ustrbuf_new(); - eina_ustrbuf_append(n2->data.text.unicode, (eina_ustrbuf_string_get(nc->data.text.unicode) + cur->pos)); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n2), - EINA_INLIST_GET(n)); - - eina_ustrbuf_remove(nc->data.text.unicode, cur->pos, eina_ustrbuf_length_get(nc->data.text.unicode)); - } - } - cur->node = n; -// XXX: This makes no sense - cur->pos = 0; - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(cur->obj); -} - -/** - * to be documented. - * @param cur to be documented. - * @param format to be documented. - * @return Returns no value. - */ -EAPI void -evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) -{ - Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *nc, *n2; - - if (!cur) return; - if ((!format) || (format[0] == 0)) return; - o = (Evas_Object_Textblock *)(cur->obj->object_data); - nc = cur->node; - n = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n->type = NODE_FORMAT; - n->data.format = eina_strbuf_new(); - eina_strbuf_append(n->data.format, format); - if (!nc) - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - cur->node = n; - cur->pos = 0; - } - else if (nc->type == NODE_FORMAT) - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nc)); - cur->node = nc; - cur->pos = 0; - } - else if (nc->type == NODE_TEXT) - { - int len; - - len = eina_ustrbuf_length_get(nc->data.text.unicode); - if (cur->pos == 0) - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_prepend_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nc)); - else - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n), - EINA_INLIST_GET(nc)); - if ((cur->pos < len) && (cur->pos != 0)) - { - n2 = calloc(1, sizeof(Evas_Object_Textblock_Node)); - n2->type = NODE_TEXT; - n2->data.text.unicode = eina_ustrbuf_new(); - eina_ustrbuf_append(n2->data.text.unicode, - (eina_ustrbuf_string_get(nc->data.text.unicode) + cur->pos)); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_append_relative(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n2), - EINA_INLIST_GET(n)); - eina_ustrbuf_remove(nc->data.text.unicode, cur->pos, eina_ustrbuf_length_get(nc->data.text.unicode)); - cur->node = n2; - cur->pos = 0; -// cur->eol = 0; - } - else if (cur->pos == len) - { - if (EINA_INLIST_GET(n)->next) - cur->node = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(n)->next, Evas_Object_Textblock_Node); + /* find the node after the current in the same paragraph + * either we find one and then take the next, or we try to get + * the first for the paragraph which must be after our position */ + if (fnode) + { + nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + if (nnode && (nnode->text_node == n)) + { + fnode = nnode; + } else - cur->node = n; - cur->pos = 0; -// cur->eol = 0; - } - else - { - cur->node = nc; - cur->pos = 0; -// cur->eol = 0; - } - } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(cur->obj); -} - -/** - * to be documented. - * @param cur to be documented. - * @return Returns no value. - */ -EAPI void -evas_textblock_cursor_node_delete(Evas_Textblock_Cursor *cur) -{ - Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *n2; - Eina_Unicode newline[2] = {'\n', 0}; - - if (!cur) return; - o = (Evas_Object_Textblock *)(cur->obj->object_data); - n = cur->node; - if (n->type == NODE_TEXT && eina_ustrbuf_length_get(n->data.text.unicode) && (!eina_unicode_strcmp(eina_ustrbuf_string_get(n->data.text.unicode), newline)) && - (!(EINA_INLIST_GET(n))->next)) return; - else if (n->type == NODE_FORMAT && eina_strbuf_length_get(n->data.format) && (!strcmp(eina_strbuf_string_get(n->data.format), "\n")) && - (!(EINA_INLIST_GET(n))->next)) return; - n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->next); - if (n2) - { - cur->node = n2; - cur->pos = 0; + { + fnode = NULL; + } + } + else + { + fnode = n->format_node; + } } else { - n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->prev); - cur->node = n2; - cur->pos = 0; - evas_textblock_cursor_char_last(cur); + n = _evas_textblock_node_text_new(); + o->text_nodes = _NODE_TEXT(eina_inlist_append( + EINA_INLIST_GET(o->text_nodes), + EINA_INLIST_GET(n))); + cur->node = n; } + eina_ustrbuf_insert_length(n->unicode, text, len, cur->pos); + /* Advance the formats */ + if (fnode && (fnode->text_node == cur->node)) + fnode->offset += len; + + evas_bidi_update_props(eina_ustrbuf_string_get(n->unicode), &n->bidi_props); + + _evas_textblock_changed(o, cur->obj); + free(text); + return len; +} + +/** + * to be documented. + * @param cur to be documented. + * @param text to be documented. + * @return Returns the length of _text + */ +EAPI size_t +evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text) +{ + size_t len; + /*append is essentially prepend without advancing */ + len = evas_textblock_cursor_text_append(cur, _text); + cur->pos += len; /*Advance */ +} +static void +_evas_textblock_node_format_free(Evas_Object_Textblock_Node_Format *n) +{ + if (!n) return; + eina_strbuf_free(n->format); + free(n); +} + +static Evas_Object_Textblock_Node_Format * +_evas_textblock_node_format_new(const char *format) +{ + Evas_Object_Textblock_Node_Format *n; + + n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format)); + n->format = eina_strbuf_new(); + eina_strbuf_append(n->format, format); + n->visible = _evas_textblock_format_is_visible(format); + + return n; +} +/** + * to be documented. + * @param cur to be documented. + * @param format to be documented. + * @return Returns true if visible + */ +EAPI Eina_Bool +evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) +{ + Evas_Object_Textblock *o; + Evas_Object_Textblock_Node_Format *n; + Eina_Bool is_visible; + + if (!cur) return EINA_FALSE; + if ((!format) || (format[0] == 0)) return EINA_FALSE; + o = (Evas_Object_Textblock *)(cur->obj->object_data); + /* We should always have at least one text node */ + if (!o->text_nodes) { + evas_textblock_cursor_text_prepend(cur, ""); + } + + n = _evas_textblock_node_format_new(format); + is_visible = n->visible; + if (!cur->node) + { + o->format_nodes = _NODE_FORMAT(eina_inlist_append( + EINA_INLIST_GET(o->format_nodes), + EINA_INLIST_GET(n))); + cur->pos = 0; + n->text_node = (EINA_INLIST_GET(n)->prev) ? + _NODE_FORMAT(EINA_INLIST_GET(n)->prev)->text_node : + o->text_nodes; + cur->node = n->text_node; + } + else + { + Evas_Object_Textblock_Node_Format *fmt; + fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); + n->text_node = cur->node; + if (!fmt) + { + o->format_nodes = _NODE_FORMAT(eina_inlist_prepend( + EINA_INLIST_GET(o->format_nodes), + EINA_INLIST_GET(n))); + n->offset = cur->pos; + } + else + { + if (evas_textblock_cursor_format_is_visible_get(cur)) + { + o->format_nodes = _NODE_FORMAT(eina_inlist_prepend_relative( + EINA_INLIST_GET(o->format_nodes), + EINA_INLIST_GET(n), + EINA_INLIST_GET(fmt) + )); + n->offset = fmt->offset; + if (fmt->text_node->format_node == fmt) + { + fmt->text_node->format_node = n; + } + } + else + { + fmt = _evas_textblock_node_format_last_at_off(fmt); + o->format_nodes = _NODE_FORMAT(eina_inlist_append_relative( + EINA_INLIST_GET(o->format_nodes), + EINA_INLIST_GET(n), + EINA_INLIST_GET(fmt) + )); + if (fmt->text_node != cur->node) + { + n->offset = cur->pos; + } + else + { + n->offset = cur->pos - + _evas_textblock_node_format_pos_get(fmt); + } + } + } + /* Adjust differently if we insert a format char */ + if (is_visible) + { + _evas_textblock_node_format_adjust_offset(o, cur->node, n, -(n->offset - 1)); + } + else + { + _evas_textblock_node_format_adjust_offset(o, cur->node, n, -n->offset); + } + + if (!fmt || (fmt->text_node != cur->node)) + { + cur->node->format_node = n; + } + } + if (is_visible) + { + eina_ustrbuf_insert_char(cur->node->unicode, + EVAS_TEXTBLOCK_REPLACEMENT_CHAR, cur->pos); + + /*FIXME: should we? because we don't */ + /* Advance all the cursors after our cursor */ Eina_List *l; Evas_Textblock_Cursor *data; if (cur != o->cursor) { - if (n == o->cursor->node) + if (cur->node == o->cursor->node) { - o->cursor->node = cur->node; - o->cursor->pos = cur->pos; - o->cursor->eol = cur->eol; - } - } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if (data != cur) - { - if (n == data->node) - { - data->node = cur->node; - data->pos = cur->pos; - data->eol = cur->eol; - } + if ((o->cursor->node) && + (o->cursor->pos >= cur->pos)) + { + o->cursor->pos++; + } } } } - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - _NODE_STRBUF_FREE(n); - free(n); - - if (n2) _nodes_adjacent_merge(cur->obj, n2); - - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) + if (_IS_PARAGRAPH_SEPARATOR(format)) { - free(o->markup_text); - o->markup_text = NULL; + _evas_textblock_cursor_break_paragraph(cur, n); } - evas_object_change(cur->obj); + + _evas_textblock_changed(o, cur->obj); + + return is_visible; } +/** + * to be documented. + * @param cur to be documented. + * @param format to be documented. + * @return Returns no value. + */ +EAPI Eina_Bool +evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) +{ + Eina_Bool is_visible; + /* append is essentially prepend without advancing */ + is_visible = evas_textblock_cursor_format_append(cur, format); + if (is_visible) + { + /* Advance after the replacement char */ + evas_textblock_cursor_char_next(cur); + } + + return is_visible; +} + + /** * to be documented. * @param cur to be documented. @@ -4359,40 +4863,69 @@ EAPI void evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) { Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n, *n2; + Evas_Object_Textblock_Node_Text *n, *n2; + int merge_nodes = 0; + const Eina_Unicode *text; int chr, index, ppos; if (!cur) return; o = (Evas_Object_Textblock *)(cur->obj->object_data); n = cur->node; - if (n->type == NODE_FORMAT) - { - evas_textblock_cursor_node_delete(cur); - return; - } + + text = eina_ustrbuf_string_get(n->unicode); index = cur->pos; - chr = GET_NEXT(eina_ustrbuf_string_get(n->data.text.unicode), index); + chr = GET_NEXT(text, index); if (chr == 0) return; ppos = cur->pos; - eina_ustrbuf_remove(n->data.text.unicode, cur->pos, index); - if (!eina_ustrbuf_length_get(n->data.text.unicode)) + /* Remove a format node if needed, and remove the char only if the + * fmt node is not visible */ { - evas_textblock_cursor_node_delete(cur); - return; + Evas_Object_Textblock_Node_Format *fmt; + fmt = _evas_textblock_cursor_node_format_at_pos_get(cur); + if (fmt) + { + const char *format = NULL; + Evas_Object_Textblock_Node_Format *itr; + itr = fmt; + do + { + format = eina_strbuf_string_get(fmt->format); + if (format && _IS_PARAGRAPH_SEPARATOR(format)) + { + merge_nodes = 1; + } + itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); + } + while (itr && (itr->text_node == fmt->text_node) && + (itr->offset == 0)); + _evas_textblock_node_format_remove_all_at_pos(o, fmt); + } + /* If the format node is not visible (because visible nodes adjust + * automatically when removing them) adjust */ + if (!evas_textblock_cursor_format_is_visible_get(cur)) + { + fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); + fmt = _evas_textblock_node_format_last_at_off(fmt); + _evas_textblock_node_format_adjust_offset(o, cur->node, fmt, + -(index - cur->pos)); + } } - if (cur->pos == eina_ustrbuf_length_get(n->data.text.unicode)) + eina_ustrbuf_remove(n->unicode, cur->pos, index); + /* If it was a paragraph separator, we should merge the current with the + * next, there must be a next. */ + if (merge_nodes) { - n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->next); + _evas_textblock_cursor_nodes_merge(cur); + } + + if (cur->pos == eina_ustrbuf_length_get(n->unicode)) + { + n2 = _NODE_TEXT(EINA_INLIST_GET(n)->next); if (n2) { cur->node = n2; cur->pos = 0; } - else - { - cur->pos = 0; - evas_textblock_cursor_char_last(cur); - } } { @@ -4420,15 +4953,7 @@ evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) } } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(cur->obj); + _evas_textblock_changed(o, cur->obj); } /** @@ -4441,11 +4966,11 @@ EAPI void evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2) { Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n1, *n2, *n, *tn; - int chr, index; + Evas_Object_Textblock_Node_Text *n1, *n2, *n; + Evas_Object_Textblock_Node_Format *fnode = NULL; - if (!cur1) return; - if (!cur2) return; + if (!cur1 || !cur1->node) return; + if (!cur2 || !cur2->node) return; if (cur1->obj != cur2->obj) return; o = (Evas_Object_Textblock *)(cur1->obj->object_data); if (evas_textblock_cursor_compare(cur1, cur2) > 0) @@ -4458,376 +4983,63 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C } n1 = cur1->node; n2 = cur2->node; - if ((!n1) || (!n2)) return; - index = cur2->pos; - if (n2->type == NODE_TEXT) - chr = GET_NEXT(eina_ustrbuf_string_get(n2->data.text.unicode), index); - else - chr = evas_common_encoding_utf8_get_next((unsigned char *)eina_strbuf_string_get(n2->data.format), &index); -// XXX: why was this added? this stops sel to end and -// if (chr == 0) return; + cur2->pos++; /* Also remove the marked char */ + + /* Find the first format node after cur2 */ + fnode = _evas_textblock_cursor_node_format_before_pos_get(cur2); + { + Evas_Object_Textblock_Node_Text *tnode; + if (fnode) + { + tnode = fnode->text_node; + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + if (fnode && (tnode != fnode->text_node)) + { + fnode = NULL; + } + } + else + { + fnode = o->format_nodes; + } + } if (n1 == n2) { - if (n1->type == NODE_TEXT) + _evas_textblock_node_text_remove_formats_between(o, n1, cur1->pos, + cur2->pos); + eina_ustrbuf_remove(n1->unicode, cur1->pos, cur2->pos); + if (fnode && (fnode->text_node == n1)) { - if (cur1->pos == cur2->pos) - { - evas_textblock_cursor_char_delete(cur1); - evas_textblock_cursor_copy(cur1, cur2); - return; - } - eina_ustrbuf_remove(n1->data.text.unicode, cur1->pos, index); - if (!eina_ustrbuf_length_get(n1->data.text.unicode)) - { - evas_textblock_cursor_node_delete(cur1); - evas_textblock_cursor_copy(cur1, cur2); - return; - } - if (cur1->pos >= eina_ustrbuf_length_get(n1->data.text.unicode)) - { - n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n1))->next); - if (n2) - { - cur1->node = n2; - cur1->pos = 0; - } - else - { - cur1->pos = 0; - evas_textblock_cursor_char_last(cur1); - } - } - } - else - evas_textblock_cursor_node_delete(cur1); - evas_textblock_cursor_copy(cur1, cur2); + fnode->offset -= cur2->pos - cur1->pos; + } } else { - Eina_List *removes, *format_hump = NULL; - Evas_Textblock_Cursor tcur; - Eina_Inlist *l; - - tcur.node = n2; - tcur.pos = 0; - index = cur2->pos; - if (n2->type == NODE_TEXT) - chr = GET_NEXT(eina_ustrbuf_string_get(n2->data.text.unicode), index); - else - chr = evas_common_encoding_utf8_get_next((unsigned char *)eina_strbuf_string_get(n2->data.format), &index); - if ((chr == 0) || - (n2->type == NODE_TEXT && index >= eina_ustrbuf_length_get(n2->data.text.unicode)) || - (n2->type == NODE_FORMAT && index >= eina_strbuf_length_get(n2->data.format))) - { - tcur.node = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n2))->next; - tcur.pos = 0; - if (!tcur.node) - { - if (cur1->pos != 0) - { - tcur.node = n1; - index = cur1->pos; - - if (n2->type == NODE_TEXT) - chr = GET_PREV(eina_ustrbuf_string_get(n2->data.text.unicode), index); - else - chr = evas_common_encoding_utf8_get_prev((unsigned char *)eina_strbuf_string_get(n2->data.format), &index); - tcur.pos = index; - } - else - { - tcur.node = (Evas_Object_Textblock_Node *)(EINA_INLIST_GET(n1))->prev; - if ((tcur.node) && (tcur.node->type == NODE_TEXT)) - { - tcur.pos = eina_unicode_strlen(eina_ustrbuf_string_get(tcur.node->data.text.unicode)) - 1; - if (tcur.pos < 0) tcur.pos = 0; - } - else - { - tcur.pos = 0; - } - } - } - } - eina_ustrbuf_remove(n1->data.text.unicode, cur1->pos, eina_ustrbuf_length_get(n1->data.text.unicode)); - removes = NULL; - for (l = (EINA_INLIST_GET(n1))->next; l != EINA_INLIST_GET(n2); l = l->next) - removes = eina_list_append(removes, l); - format_hump = NULL; - if (n1->type == NODE_TEXT) - { - if (!eina_ustrbuf_length_get(n1->data.text.unicode)) - evas_textblock_cursor_node_delete(cur1); - } - else - { - if (eina_strbuf_length_get(n1->data.format) && (eina_strbuf_string_get(n1->data.format)[0] == '+')) - format_hump = eina_list_append(format_hump, n1); - else - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n1)); - if (n1->data.format) eina_strbuf_free(n1->data.format); - free(n1); - } - } - while (removes) - { - n = removes->data; - if (n->type == NODE_TEXT) - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), EINA_INLIST_GET(n)); - if (n->data.text.unicode) eina_ustrbuf_free(n->data.text.unicode); - if (n->data.text.utf8) free(n->data.text.utf8); - free(n); - } - else - { - if (eina_strbuf_string_get(n->data.format)[0] == '+') - { - format_hump = eina_list_append(format_hump, n); - } - else if (eina_strbuf_string_get(n->data.format)[0] == '-') - { - tn = eina_list_data_get(eina_list_last(format_hump)); - if (tn) - { - format_hump = eina_list_remove_list(format_hump, eina_list_last(format_hump)); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(tn)); - if (tn->data.format) eina_strbuf_free(tn->data.format); - free(tn); - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n)); - if (n->data.format) eina_strbuf_free(n->data.format); - free(n); - } - } - else - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n)); - if (n->data.format) eina_strbuf_free(n->data.format); - free(n); - } - } - removes = eina_list_remove_list(removes, removes); - } - if (n2->type == NODE_TEXT) - { - eina_ustrbuf_remove(n2->data.text.unicode, 0, index); - if (!eina_ustrbuf_length_get(n2->data.text.unicode)) - evas_textblock_cursor_node_delete(cur2); - } - else - { - if (tcur.node == n2) - { - if ((EINA_INLIST_GET(n2))->next) - { - tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n2))->next; - tcur.pos = 0; - } - else - { - tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n2))->next; - if (tcur.node) - { - if (tcur.node->type == NODE_TEXT) - { - tcur.pos = eina_unicode_strlen(eina_ustrbuf_string_get(tcur.node->data.text.unicode)) - 1; - if (tcur.pos < 0) tcur.pos = 0; - } - else - { - tcur.pos = 0; - } - } - } - } - if (eina_strbuf_string_get(n2->data.format)[0] == '-') - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n2)); - if (n2->data.format) eina_strbuf_free(n2->data.format); - free(n2); - n = eina_list_data_get(eina_list_last(format_hump)); - if (n) - { - if (tcur.node == n) - { - if ((EINA_INLIST_GET(n))->next) - { - tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n))->next; - tcur.pos = 0; - } - else - { - tcur.node = (Evas_Object_Textblock_Node *) (EINA_INLIST_GET(n))->next; - if (tcur.node) - { - if (tcur.node->type == NODE_TEXT) - { - tcur.pos = eina_unicode_strlen(eina_ustrbuf_string_get(tcur.node->data.text.unicode)) - 1; - if (tcur.pos < 0) tcur.pos = 0; - } - else - { - tcur.pos = 0; - } - } - } - } - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n)); - if (n->data.format) eina_strbuf_free(n->data.format); - free(n); - } - } - else - { - o->nodes = (Evas_Object_Textblock_Node *)eina_inlist_remove(EINA_INLIST_GET(o->nodes), - EINA_INLIST_GET(n2)); - if (n2->data.format) eina_strbuf_free(n2->data.text.unicode); - free(n2); - } - } - if (format_hump) eina_list_free(format_hump); - cur1->node = tcur.node; - cur1->pos = tcur.pos; - cur2->node = tcur.node; - cur2->pos = tcur.pos; - } - - /* FIXME: adjust cursors that are affected by the change */ - /* this is temporary just avoiding segv's - it sets all other cursors to - * the same pos as cur1 and cur2 - */ - { - Eina_List *l; - Evas_Textblock_Cursor *data; - - if ((cur1 != o->cursor) && (cur2 != o->cursor)) - { - evas_textblock_cursor_copy(cur1, o->cursor); - } - EINA_LIST_FOREACH(o->cursors, l, data) - { - if ((data != cur1) && (data != cur2)) - { - evas_textblock_cursor_copy(cur1, data); - } - } - } - if (cur1->node) _nodes_adjacent_merge(cur1->obj, cur1->node); - if (cur2->node) _nodes_adjacent_merge(cur2->obj, cur2->node); - - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(cur1->obj); -} - -/** - * to be documented. - * @param cur to be documented. - * @return to be documented. - */ -/*FIXME: returns allocated space, fix it! */ -EAPI const char * -evas_textblock_cursor_node_text_get(const Evas_Textblock_Cursor *cur) -{ - if (!cur) return NULL; - if (!cur->node) return NULL; - if (cur->node->type == NODE_TEXT) - { - if (cur->node->data.text.utf8) + int len; + n = _NODE_TEXT(EINA_INLIST_GET(n1)->next); + /* Remove all the text nodes between */ + while (n && (n != n2)) { - free(cur->node->data.text.utf8); + _evas_textblock_node_text_remove(o, n); + n = _NODE_TEXT(EINA_INLIST_GET(n)->next); } - cur->node->data.text.utf8 = evas_common_encoding_unicode_to_utf8( - eina_ustrbuf_string_get(cur->node->data.text.unicode), NULL); - return cur->node->data.text.utf8; + + /* Remove the formats and the strings in the first and last nodes */ + len = eina_ustrbuf_length_get(n1->unicode); + _evas_textblock_node_text_remove_formats_between(o, n1, cur1->pos, + len); + _evas_textblock_node_text_remove_formats_between(o, n2, 0, cur2->pos); + eina_ustrbuf_remove(n1->unicode, cur1->pos, len); + eina_ustrbuf_remove(n2->unicode, 0, cur2->pos); + if (fnode && (fnode->text_node == n2)) + { + fnode->offset -= cur2->pos; + } + /* Merge the nodes because we removed the PS */ + _evas_textblock_nodes_merge(o, n1, n2); } - return NULL; -} - -/** - * to be documented. - * @param cur to be documented. - * @return to be documented. - */ -EAPI int -evas_textblock_cursor_node_text_length_get(const Evas_Textblock_Cursor *cur) -{ - if (!cur) return 0; - if (!cur->node) return 0; - if (cur->node->type == NODE_TEXT) - { - return eina_ustrbuf_length_get(cur->node->data.text.unicode); - } - return 0; -} - -/** - * to be documented. - * @param cur to be documented. - * @return to be documented. - */ -EAPI const char * -evas_textblock_cursor_node_format_get(const Evas_Textblock_Cursor *cur) -{ - if (!cur) return NULL; - if (!cur->node) return NULL; - if (cur->node->type == NODE_FORMAT) - { - return eina_strbuf_string_get(cur->node->data.format); - } - return NULL; -} - -/** - * to be documented. - * @param cur to be documented. - * @return to be documented. - */ -EAPI Eina_Bool -evas_textblock_cursor_node_format_is_visible_get(const Evas_Textblock_Cursor *cur) -{ - Evas_Object_Textblock_Node *n; - - if (!cur) return EINA_FALSE; - n = cur->node; - if (!n) return EINA_FALSE; - if (n->type != NODE_FORMAT) return EINA_FALSE; - if (!eina_strbuf_length_get(n->data.format)) return EINA_FALSE; - { - char *s; - char *item; - int visible = 0; - - s = (char *)eina_strbuf_string_get(n->data.format); - if (s[0] == '+' || s[0] == '-') - { - s++; - } - while ((item = _format_parse(&s))) - { - char tmp_delim = *s; - *s = '\0'; - if ((!strcmp(item, "\n")) || (!strcmp(item, "\\n"))) - visible = 1; - else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) - visible = 1; - *s = tmp_delim; - if (visible) return EINA_TRUE; - } - } - return EINA_FALSE; + evas_textblock_cursor_copy(cur1, cur2); + _evas_textblock_changed(o, cur1->obj); } /** @@ -4837,169 +5049,159 @@ evas_textblock_cursor_node_format_is_visible_get(const Evas_Textblock_Cursor *cu * @param format to be documented. * @return to be documented. */ +/* FIXME: support format and markup */ EAPI char * -evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) +evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2, Evas_Textblock_Text_Type format) { Evas_Object_Textblock *o; - Evas_Object_Textblock_Node *n1, *n2, *n; - Eina_Strbuf *txt; - char *ret; - const Eina_Unicode *s; - int index; + Evas_Object_Textblock_Node_Text *n1, *n2, *n; + const Eina_Unicode *text; + Eina_UStrbuf *buf; + Evas_Textblock_Cursor *cur2; + buf = eina_ustrbuf_new(); - if (!cur1) return NULL; - if (!cur2) return NULL; - if (cur1->obj != cur2->obj) return NULL; + if (!cur1 || !cur1->node) return; + if (!_cur2 || !_cur2->node) return; + if (cur1->obj != _cur2->obj) return; o = (Evas_Object_Textblock *)(cur1->obj->object_data); - if (evas_textblock_cursor_compare(cur1, cur2) > 0) + if (evas_textblock_cursor_compare(cur1, _cur2) > 0) { const Evas_Textblock_Cursor *tc; tc = cur1; - cur1 = cur2; - cur2 = tc; + cur1 = _cur2; + _cur2 = tc; } n1 = cur1->node; - n2 = cur2->node; - index = cur2->pos; - if ((!n1) || (!n2)) return NULL; - if (n2->data.text.unicode) - GET_NEXT(eina_ustrbuf_string_get(n2->data.text.unicode), index); - txt = eina_strbuf_new(); - EINA_INLIST_FOREACH(n1, n) + n2 = _cur2->node; + /* Work on a local copy of the cur */ + cur2 = alloca(sizeof(Evas_Textblock_Cursor)); + cur2->obj = _cur2->obj; + evas_textblock_cursor_copy(_cur2, cur2); + cur2->pos++; /* We want to also copy the pointed to char */ + if (n1 == n2) { - if ((n->type == NODE_TEXT) && (n->data.text.unicode)) - { - s = eina_ustrbuf_string_get(n->data.text.unicode); - if (format == EVAS_TEXTBLOCK_TEXT_MARKUP) - { - const Eina_Unicode *p, *ps, *pe; - - if (eina_ustrbuf_length_get(n->data.text.unicode)) - { - if ((n == n1) && (n == n2)) - { - ps = eina_ustrbuf_string_get(n->data.text.unicode) + cur1->pos; - pe = ps + index - cur1->pos; - } - else if (n == n1) - { - ps = eina_ustrbuf_string_get(n->data.text.unicode) + cur1->pos; - pe = ps + eina_unicode_strlen(ps); - } - else if (n == n2) - { - ps = eina_ustrbuf_string_get(n->data.text.unicode); - pe = ps + cur2->pos + 1; - } - else - { - ps = eina_ustrbuf_string_get(n->data.text.unicode); - pe = ps + eina_unicode_strlen(ps); - } - p = ps; - while (p < pe) - { - const char *escape; - char *tmp; - int adv; - - if (!*p) break; - tmp = evas_common_encoding_unicode_to_utf8(p, NULL); - escape = _escaped_char_match(tmp, &adv); - free(tmp); - if (escape) - { - p += adv; - eina_strbuf_append(txt, escape); - } - else - { - eina_strbuf_append_char(txt, *p); - p++; - } - } - } - } - else - { - /*FIXME: make more efficient */ - char *utf; - utf = evas_common_encoding_unicode_to_utf8(s, NULL); - if ((n == n1) && (n == n2)) - { - s += cur1->pos; - eina_strbuf_append_n(txt, utf, index - cur1->pos); - } - else if (n == n1) - { - s += cur1->pos; - eina_strbuf_append(txt, utf); - } - else if (n == n2) - { - eina_strbuf_append_n(txt, utf, index); - } - else - { - eina_strbuf_append(txt, utf); - } - free(utf); - } - } - else if (n->data.format) - { - if (format == EVAS_TEXTBLOCK_TEXT_PLAIN) - { - const char *tmp; - tmp = eina_strbuf_string_get(n->data.format); - while (*tmp) - { - if (*tmp == '\n') - eina_strbuf_append_char(txt, '\n'); - else if (*tmp == '\t') - eina_strbuf_append_char(txt, '\t'); - tmp++; - } - } - else if (format == EVAS_TEXTBLOCK_TEXT_MARKUP) - { - size_t tag_len, replace_len = eina_strbuf_length_get(n->data.format); - const char *tag = _style_match_replace(o->style, eina_strbuf_string_get(n->data.format), replace_len, &tag_len); - eina_strbuf_append_char(txt, '<'); - if (tag) - { - // FIXME: need to escape - eina_strbuf_append_length(txt, tag, tag_len); - } - else - { - int push = 0; - int pop = 0; - const char *tmp; - - // FIXME: need to escape - tmp = eina_strbuf_string_get(n->data.format); - if (*tmp == '+') push = 1; - if (*tmp == '-') pop = 1; - while ((*tmp == ' ') || (*tmp == '+') || (*tmp == '-')) tmp++; - if (pop) eina_strbuf_append_char(txt, '/'); - if (push) - { - eina_strbuf_append(txt, "+ "); - } - eina_strbuf_append(txt, tmp); - } - eina_ustrbuf_append_char(txt, '>'); - } - } - if (n == n2) break; + text = eina_ustrbuf_string_get(n1->unicode); + eina_ustrbuf_append_length(buf, text, cur2->pos - cur1->pos); + } + else + { + int len; + n = _NODE_TEXT(EINA_INLIST_GET(n1)->next); + /* Add all the text nodes between */ + while (n && (n != n2)) + { + text = eina_ustrbuf_string_get(n->unicode); + eina_ustrbuf_append(buf, text); + n = _NODE_TEXT(EINA_INLIST_GET(n)->next); + } + + len = eina_ustrbuf_length_get(n1->unicode); + text = eina_ustrbuf_string_get(n1->unicode); + eina_ustrbuf_append_length(buf, text, len - cur1->pos); + + len = eina_ustrbuf_length_get(n2->unicode); + text = eina_ustrbuf_string_get(n2->unicode); + eina_ustrbuf_append_length(buf, text + cur2->pos, len - cur2->pos); + } + + /* return the string */ + { + char *ret; + const Eina_Unicode *tmp; + tmp = eina_ustrbuf_string_get(buf); + ret = evas_common_encoding_unicode_to_utf8(tmp, NULL); + eina_ustrbuf_free(buf); + return ret; } - ret = eina_strbuf_string_steal(txt); - eina_strbuf_free(txt); - return ret; } +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI const char * +evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) +{ + if (!cur) return NULL; + if (!cur->node) return NULL; + /*FIXME-tom: strip replace chars */ + if (cur->node->utf8) + { + free(cur->node->utf8); + } + cur->node->utf8 = evas_common_encoding_unicode_to_utf8( + eina_ustrbuf_string_get(cur->node->unicode), NULL); + return cur->node->utf8; +} + +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI int +evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur) +{ + if (!cur) return 0; + if (!cur->node) return 0; + return eina_ustrbuf_length_get(cur->node->unicode); +} + +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI const Evas_Object_Textblock_Node_Format * +evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) +{ + if (!cur) return NULL; + if (!cur->node) return NULL; + return _evas_textblock_cursor_node_format_at_pos_get(cur); +} +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI const char * +evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt) +{ + if (!fmt) return NULL; + return eina_strbuf_string_get(fmt->format); +} +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI void +evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt) +{ + if (!fmt || !cur) return; + cur->node = fmt->text_node; + cur->pos = _evas_textblock_node_format_pos_get(fmt); +} +/** + * to be documented. + * @param cur to be documented. + * @return to be documented. + */ +EAPI Eina_Bool +evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) +{ + const Eina_Unicode *text; + + if (!cur) return EINA_FALSE; + if (!cur->node) return EINA_FALSE; + text = eina_ustrbuf_string_get(cur->node->unicode); + return (text[cur->pos] == EVAS_TEXTBLOCK_REPLACEMENT_CHAR) ? + EINA_TRUE : EINA_FALSE; +} + + /** * to be documented. * @param cur to be documented. @@ -5023,7 +5225,7 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C o = (Evas_Object_Textblock *)(cur->obj->object_data); if (!cur->node) { - if (!o->nodes) + if (!o->text_nodes) { ln = o->lines; if (!ln) return -1; @@ -5037,13 +5239,15 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C return -1; } if (!o->formatted.valid) _relayout(cur->obj); - if (cur->node->type == NODE_FORMAT) + if (evas_textblock_cursor_format_is_visible_get(cur)) { - _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi); + _find_layout_format_item_line_match(cur->obj, + _evas_textblock_cursor_node_format_at_pos_get(cur), + &ln, &fi); } else { - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); + _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it); } if (!ln) { @@ -5051,32 +5255,25 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C } if (it) { - pos = cur->pos - it->source_pos; - ret = -1; - if (cur->eol) - { - int pos2; + pos = cur->pos - it->source_pos; + ret = -1; - pos2 = pos; - GET_NEXT(it->text, pos2); - if (pos2 > pos) pos = pos2; - } if (pos < 0) pos = 0; - if (it->format->font.font) - { - ret = cur->ENFN->font_char_coords_get(cur->ENDT, it->format->font.font, - it->text, &it->intl_props, - pos, - &x, &y, &w, &h); - } - if (ret <= 0) - { - if (it->format->font.font) - cur->ENFN->font_string_size_get(cur->ENDT, it->format->font.font, - it->text, &it->intl_props, &w, &h); - x = w; - y = 0; - w = 0; + if (it->format->font.font) + { + ret = cur->ENFN->font_char_coords_get(cur->ENDT, it->format->font.font, + it->text, &it->bidi_props, + pos, + &x, &y, &w, &h); + } + if (ret <= 0) + { + if (it->format->font.font) + cur->ENFN->font_string_size_get(cur->ENDT, it->format->font.font, + it->text, &it->bidi_props, &w, &h); + x = w; + y = 0; + w = 0; } x = ln->x + it->x - it->inset + x; if (x < ln->x) @@ -5132,10 +5329,17 @@ evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C } else { - if (cur->node->type == NODE_FORMAT) - _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi); + if (evas_textblock_cursor_format_is_visible_get(cur)) + { + _find_layout_format_item_line_match(cur->obj, + _evas_textblock_node_visible_at_pos_get( + _evas_textblock_cursor_node_format_before_or_at_pos_get(cur)), + &ln, &fi); + } else - _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it); + { + _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it); + } } if (!ln) return -1; x = ln->x; @@ -5188,11 +5392,11 @@ evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, E pos = -1; if (it->format->font.font) - pos = cur->ENFN->font_char_at_coords_get(cur->ENDT, - it->format->font.font, - it->text, &it->intl_props, - x - it->x - ln->x, 0, - &cx, &cy, &cw, &ch); + pos = cur->ENFN->font_char_at_coords_get(cur->ENDT, + it->format->font.font, + it->text, &it->bidi_props, + x - it->x - ln->x, 0, + &cx, &cy, &cw, &ch); if (pos < 0) return EINA_FALSE; cur->pos = pos + it->source_pos; @@ -5205,9 +5409,10 @@ evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, E if ((fi->x + ln->x) > x) break; if (((fi->x + ln->x) <= x) && (((fi->x + ln->x) + fi->w) > x)) { - cur->pos = 0; - cur->eol = 0; - cur->node = fi->source_node; + cur->pos = + _evas_textblock_node_format_pos_get(fi->source_node); + + cur->node = fi->source_node->text_node; return EINA_TRUE; } } @@ -5215,7 +5420,7 @@ evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, E { it = it_break; cur->pos = it->source_pos; - cur->eol = 0; + cur->node = it->source_node; return EINA_TRUE; } @@ -5277,12 +5482,14 @@ evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, cons cur1 = cur2; cur2 = tc; } + line = evas_textblock_cursor_char_geometry_get(cur1, &cx, &cy, &cw, &ch); if (line < 0) return NULL; line = evas_textblock_cursor_line_geometry_get(cur1, &lx, &ly, &lw, &lh); if (line < 0) return NULL; line2 = evas_textblock_cursor_line_geometry_get(cur2, NULL, NULL, NULL, NULL); if (line2 < 0) return NULL; + if (line == line2) { tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); @@ -5370,7 +5577,8 @@ evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, if (!cur) return 0; o = (Evas_Object_Textblock *)(cur->obj->object_data); if (!o->formatted.valid) _relayout(cur->obj); - _find_layout_format_item_line_match(cur->obj, cur->node, &ln, &fi); + _find_layout_format_item_line_match(cur->obj, + _evas_textblock_cursor_node_format_before_or_at_pos_get(cur), &ln, &fi); if ((!ln) || (!fi)) return 0; x = ln->x + fi->x; y = ln->y + ln->baseline + fi->y; @@ -5392,24 +5600,19 @@ evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, EAPI Eina_Bool evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur) { + Eina_Bool ret = EINA_FALSE; + Evas_Textblock_Cursor cur2; if (!cur) return EINA_FALSE; - return cur->eol; + /* FIXME: optimize a bit */ + evas_textblock_cursor_copy(cur, &cur2); + evas_textblock_cursor_line_char_last(&cur2); + if (cur2.pos == cur->pos) + { + ret = EINA_TRUE; + } + return ret; } -/** - * To be documented. - * - * FIXME: To be fixed. - * - */ -EAPI void -evas_textblock_cursor_eol_set(Evas_Textblock_Cursor *cur, Eina_Bool eol) -{ - if (!cur) return; - cur->eol = eol; -} - - /* general controls */ /** * to be documented. @@ -5451,28 +5654,19 @@ evas_object_textblock_clear(Evas_Object *obj) _nodes_clear(obj); o->cursor->node = NULL; o->cursor->pos = 0; - o->cursor->eol = 0; EINA_LIST_FOREACH(o->cursors, l, cur) { cur->node = NULL; cur->pos = 0; - cur->eol = 0; + } + /* FIXME: free the paragraphs as well */ if (o->lines) { _lines_clear(obj, o->lines); o->lines = NULL; } - o->formatted.valid = 0; - o->native.valid = 0; - o->changed = 1; - if (o->markup_text) - { - free(o->markup_text); - o->markup_text = NULL; - } - evas_object_change(obj); - /* FIXME: adjust cursors that are affected by the change */ + _evas_textblock_changed(o, obj); } /** @@ -5575,6 +5769,7 @@ evas_object_textblock_new(void) o = calloc(1, sizeof(Evas_Object_Textblock)); o->magic = MAGIC_OBJ_TEXTBLOCK; o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor)); + _format_command_init(); return o; } @@ -5598,6 +5793,7 @@ evas_object_textblock_free(Evas_Object *obj) if (o->repch) eina_stringshare_del(o->repch); o->magic = 0; free(o); + _format_command_shutdown(); } @@ -5680,7 +5876,7 @@ evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void if (it->format->font.font) ENFN->font_draw(output, context, surface, it->format->font.font, \ obj->cur.geometry.x + ln->x + it->x - it->inset + x + (ox), \ obj->cur.geometry.y + ln->y + yoff + y + (oy), \ - it->w, it->h, it->w, it->h, it->text, &it->intl_props); + it->w, it->h, it->w, it->h, it->text, &it->bidi_props); # if 0 #define DRAW_TEXT(ox, oy) \ if (it->format->font.font) ENFN->font_draw(output, context, surface, it->format->font.font, \ @@ -5688,7 +5884,7 @@ evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void obj->cur.geometry.y + ln->y + yoff + y + (oy), \ obj->cur.cache.geometry.x + ln->x + it->x - it->inset + x + (ox), \ obj->cur.cache.geometry.y + ln->y + yoff + y + (oy), \ - it->w, it->h, it->w, it->h, it->text, &it->intl_props); + it->w, it->h, it->w, it->h, it->text, &it->bidi_props); #endif #define ITEM_WALK_LINE_SKIP_DROP() \ if ((ln->y + ln->h) <= 0) continue; \ diff --git a/legacy/evas/src/lib/engines/common/evas_bidi_utils.c b/legacy/evas/src/lib/engines/common/evas_bidi_utils.c index f15f81f760..91f5440a45 100644 --- a/legacy/evas/src/lib/engines/common/evas_bidi_utils.c +++ b/legacy/evas/src/lib/engines/common/evas_bidi_utils.c @@ -40,12 +40,33 @@ evas_bidi_is_rtl_str(const Eina_Unicode *str) return EINA_FALSE; } +Eina_Bool +evas_bidi_shape_string(Eina_Unicode *ustr, const Evas_BiDi_Props *bidi_props, size_t len) +{ + EvasBiDiJoiningType *join_types = NULL; + join_types = (EvasBiDiJoiningType *) malloc(sizeof(EvasBiDiJoiningType) * len); + if (!join_types) + { + return -2; + } + fribidi_get_joining_types(ustr, len, join_types); + + fribidi_join_arabic(bidi_props->props->char_types, len, bidi_props->props->embedding_levels + bidi_props->start, join_types); + + + /* Actually modify the string */ + fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, + bidi_props->props->embedding_levels + bidi_props->start, len, join_types, ustr); + + if (join_types) free(join_types); + return EINA_TRUE; +} + int -evas_bidi_update_props(Eina_Unicode *ustr, Evas_BiDi_Props *intl_props) +evas_bidi_update_props(const Eina_Unicode *ustr, Evas_BiDi_Paragraph_Props *bidi_props) { EvasBiDiCharType *char_types = NULL; EvasBiDiLevel *embedding_levels = NULL; - EvasBiDiJoiningType *join_types = NULL; size_t len; if (!ustr) @@ -74,53 +95,36 @@ evas_bidi_update_props(Eina_Unicode *ustr, Evas_BiDi_Props *intl_props) len = -2; goto cleanup; } - if (!fribidi_get_par_embedding_levels(char_types, len, &intl_props->direction, embedding_levels)) + if (!fribidi_get_par_embedding_levels(char_types, len, &bidi_props->direction, embedding_levels)) { len = -2; goto cleanup; } - join_types = (EvasBiDiJoiningType *) malloc(sizeof(EvasBiDiJoiningType) * len); - if (!join_types) - { - len = -2; - goto cleanup; - } - fribidi_get_joining_types(ustr, len, join_types); - - fribidi_join_arabic(char_types, len, embedding_levels, join_types); - - - /* Actually modify the string */ - fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, embedding_levels, len, join_types, - ustr); /* clean up */ - if (intl_props->embedding_levels) + if (bidi_props->embedding_levels) { - free(intl_props->embedding_levels); + free(bidi_props->embedding_levels); } - intl_props->embedding_levels = embedding_levels; + bidi_props->embedding_levels = embedding_levels; /* clean up */ - if (intl_props->char_types) + if (bidi_props->char_types) { - free(intl_props->char_types); + free(bidi_props->char_types); } - intl_props->char_types = char_types; + bidi_props->char_types = char_types; - if (join_types) free(join_types); - return len; /* Cleanup */ cleanup: - if (join_types) free(join_types); if (char_types) free(char_types); if (embedding_levels) free(embedding_levels); - evas_bidi_props_clean(intl_props); /*Mark that we don't need bidi handling */ + evas_bidi_paragraph_props_clean(bidi_props); /*Mark that we don't need bidi handling */ return len; } @@ -130,7 +134,7 @@ evas_bidi_props_reorder_line(Eina_Unicode *ustr, const Evas_BiDi_Props *intl_pro EvasBiDiStrIndex *v_to_l = NULL; size_t len; - if (!EVAS_BIDI_IS_BIDI_PROP(intl_props)) + if (!EVAS_BIDI_IS_BIDI_PROP(intl_props->props)) return 0; len = eina_unicode_strlen(ustr); @@ -151,9 +155,9 @@ evas_bidi_props_reorder_line(Eina_Unicode *ustr, const Evas_BiDi_Props *intl_pro /* Shaping must be done *BEFORE* breaking to lines so there's no choice but doing it in textblock. */ - if (!fribidi_reorder_line (FRIBIDI_FLAGS_DEFAULT, intl_props->char_types, - len, 0, intl_props->direction, - intl_props->embedding_levels, ustr, v_to_l)) + if (!fribidi_reorder_line (FRIBIDI_FLAGS_DEFAULT, intl_props->props->char_types + intl_props->start, + len, 0, intl_props->props->direction, + intl_props->props->embedding_levels + intl_props->start, ustr, v_to_l)) { goto error; } @@ -194,9 +198,16 @@ evas_bidi_is_rtl_char(EvasBiDiLevel *embedded_level_list, EvasBiDiStrIndex index } void -evas_bidi_props_clean(Evas_BiDi_Props *intl_props) +evas_bidi_paragraph_props_clean(Evas_BiDi_Paragraph_Props *bidi_props) { - _SAFE_FREE(intl_props->embedding_levels); - _SAFE_FREE(intl_props->char_types); + _SAFE_FREE(bidi_props->embedding_levels); + _SAFE_FREE(bidi_props->char_types); +} +void +evas_bidi_props_clean(Evas_BiDi_Props *bidi_props) +{ + if (!bidi_props) return; + evas_bidi_paragraph_props_clean(bidi_props->props); + bidi_props->props = NULL; } #endif diff --git a/legacy/evas/src/lib/engines/common/evas_bidi_utils.h b/legacy/evas/src/lib/engines/common/evas_bidi_utils.h index 3358f2097a..67f9a31926 100644 --- a/legacy/evas/src/lib/engines/common/evas_bidi_utils.h +++ b/legacy/evas/src/lib/engines/common/evas_bidi_utils.h @@ -40,21 +40,27 @@ _EVAS_BIDI_TYPEDEF(StrIndex); _EVAS_BIDI_TYPEDEF(Level); _EVAS_BIDI_TYPEDEF(JoiningType); +typedef struct _Evas_BiDi_Paragraph_Props Evas_BiDi_Paragraph_Props; +typedef struct _Evas_BiDi_Props Evas_BiDi_Props; + /* This structure defines a set of properties of a BiDi string. In case of a * non-bidi string, all values should be NULL. * To check if a structure describes a bidi string or not, use the macro * EVAS_BIDI_IS_BIDI_PROP. RTL-only strings are also treated as bidi ATM. */ -struct _Evas_BiDi_Props { +struct _Evas_BiDi_Paragraph_Props { EvasBiDiCharType *char_types; /* BiDi char types */ EvasBiDiLevel *embedding_levels; /* BiDi embedding levels */ #ifdef USE_FRIBIDI - EvasBiDiParType direction; /* The paragraph direction, FIXME-tom: should be a - pointer to the paragraph structure */ + EvasBiDiParType direction; #endif }; -typedef struct _Evas_BiDi_Props Evas_BiDi_Props; +struct _Evas_BiDi_Props { + Evas_BiDi_Paragraph_Props *props; + size_t start; +}; + #ifdef USE_FRIBIDI @@ -92,13 +98,18 @@ evas_bidi_props_reorder_line(Eina_Unicode *text, const Evas_BiDi_Props *intl_pro * Return value: the length of the string. */ int -evas_bidi_update_props(Eina_Unicode *text, Evas_BiDi_Props *intl_props) EINA_ARG_NONNULL(1, 2); +evas_bidi_update_props(const Eina_Unicode *text, Evas_BiDi_Paragraph_Props *intl_props) EINA_ARG_NONNULL(1, 2); +/* Actually shape the string */ +Eina_Bool +evas_bidi_shape_string(Eina_Unicode *ustr, const Evas_BiDi_Props *intl_props, size_t len); /* Cleans and frees the international properties. - Just the content, not the * poitner itself. */ void evas_bidi_props_clean(Evas_BiDi_Props *intl_props) EINA_ARG_NONNULL(1); +void +evas_bidi_paragraph_props_clean(Evas_BiDi_Paragraph_Props *bidi_props) EINA_ARG_NONNULL(1); #endif diff --git a/legacy/evas/src/lib/engines/common/evas_font_draw.c b/legacy/evas/src/lib/engines/common/evas_font_draw.c index a05244f2d8..a3ff820523 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_draw.c +++ b/legacy/evas/src/lib/engines/common/evas_font_draw.c @@ -544,8 +544,8 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font * index is now the index and the other way around. * There is a slight exception when there are compositing chars * involved.*/ - if (intl_props && - evas_bidi_is_rtl_char(intl_props->embedding_levels, char_index) && + if (intl_props && intl_props->props && + evas_bidi_is_rtl_char(intl_props->props->embedding_levels, char_index) && fg->glyph->advance.x >> 16 > 0) { if (evas_common_font_query_kerning(fi, index, prev_index, &kern)) @@ -872,7 +872,7 @@ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Eva * There is a slight exception when there are compositing chars * involved.*/ if (intl_props && - evas_bidi_is_rtl_char(intl_props->embedding_levels, char_index) && + evas_bidi_is_rtl_char(intl_props->props->embedding_levels, char_index) && ci->fg->glyph->advance.x >> 16 > 0) { if (evas_common_font_query_kerning(fi, ci->index, prev_index, &kern)) diff --git a/legacy/evas/src/lib/engines/common/evas_font_query.c b/legacy/evas/src/lib/engines/common/evas_font_query.c index 26c4486e57..5d3b71b1c9 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_query.c +++ b/legacy/evas/src/lib/engines/common/evas_font_query.c @@ -258,7 +258,7 @@ evas_common_font_query_advance(RGBA_Font *fn, const Eina_Unicode *text, const Ev * There is a slight exception when there are compositing chars * involved.*/ if (intl_props && - evas_bidi_is_rtl_char(intl_props->embedding_levels, char_index) && + evas_bidi_is_rtl_char(intl_props->props->embedding_levels, char_index) && fg->glyph->advance.x >> 16 > 0) { if (evas_common_font_query_kerning(fi, index, prev_index, &kern)) @@ -384,7 +384,7 @@ evas_common_font_query_char_coords(RGBA_Font *fn, const Eina_Unicode *in_text, c * There is a slight exception when there are compositing chars * involved.*/ if (intl_props && - evas_bidi_is_rtl_char(intl_props->embedding_levels, char_index) && + evas_bidi_is_rtl_char(intl_props->props->embedding_levels, char_index) && fg->glyph->advance.x >> 16 > 0) { if (evas_common_font_query_kerning(fi, index, prev_index, &kern)) @@ -541,7 +541,7 @@ evas_common_font_query_char_at_coords(RGBA_Font *fn, const Eina_Unicode *in_text * There is a slight exception when there are compositing chars * involved.*/ if (intl_props && - evas_bidi_is_rtl_char(intl_props->embedding_levels, char_index) && + evas_bidi_is_rtl_char(intl_props->props->embedding_levels, char_index) && fg->glyph->advance.x >> 16 > 0) { if (evas_common_font_query_kerning(fi, index, prev_index, &kern)) diff --git a/legacy/evas/src/lib/imaging/evas_imaging.c b/legacy/evas/src/lib/imaging/evas_imaging.c index 80f902f954..23aa788fcd 100644 --- a/legacy/evas/src/lib/imaging/evas_imaging.c +++ b/legacy/evas/src/lib/imaging/evas_imaging.c @@ -197,16 +197,18 @@ evas_imaging_font_line_advance_get(const Evas_Imaging_Font *fn) EAPI void evas_imaging_font_string_advance_get(const Evas_Imaging_Font *fn, const char *str, int *x, int *y) { - Evas_BiDi_Props intl_props; + Evas_BiDi_Props bidi_props; + Evas_BiDi_Paragraph_Props bidi_par_props; + bidi_props.props = &bidi_par_props; Eina_Unicode *ustr; if (!fn) return; ustr = evas_common_encoding_utf8_to_unicode(str, NULL); #ifdef BIDI_SUPPORT - evas_bidi_update_props(ustr, &intl_props); + evas_bidi_update_props(ustr, &bidi_par_props); #endif - evas_common_font_query_advance(fn->font, ustr, &intl_props, x, y); + evas_common_font_query_advance(fn->font, ustr, &bidi_props, x, y); #ifdef BIDI_SUPPORT - evas_bidi_props_clean(&intl_props); + evas_bidi_props_clean(&bidi_props); #endif if (ustr) free(ustr); } @@ -215,11 +217,13 @@ EAPI void evas_imaging_font_string_size_query(const Evas_Imaging_Font *fn, const char *str, int *w, int *h) { Evas_BiDi_Props intl_props; + Evas_BiDi_Paragraph_Props bidi_paragraph_props; + intl_props.props = &bidi_paragraph_props; Eina_Unicode *ustr; if (!fn) return; ustr = evas_common_encoding_utf8_to_unicode(str, NULL); #ifdef BIDI_SUPPORT - evas_bidi_update_props(ustr, &intl_props); + evas_bidi_update_props(ustr, &bidi_paragraph_props); #endif evas_common_font_query_size(fn->font, ustr, &intl_props, w, h); #ifdef BIDI_SUPPORT @@ -246,11 +250,13 @@ evas_imaging_font_string_char_coords_get(const Evas_Imaging_Font *fn, const char { int ret; Evas_BiDi_Props intl_props; + Evas_BiDi_Paragraph_Props bidi_paragraph_props; + intl_props.props = &bidi_paragraph_props; Eina_Unicode *ustr; if (!fn) return 0; ustr = evas_common_encoding_utf8_to_unicode(str, NULL); #ifdef BIDI_SUPPORT - evas_bidi_update_props(ustr, &intl_props); + evas_bidi_update_props(ustr, &bidi_paragraph_props); #endif ret = evas_common_font_query_char_coords(fn->font, ustr, &intl_props, pos, cx, cy, cw, ch); #ifdef BIDI_SUPPORT @@ -265,11 +271,13 @@ evas_imaging_font_string_char_at_coords_get(const Evas_Imaging_Font *fn, const c { int ret; Evas_BiDi_Props intl_props; + Evas_BiDi_Paragraph_Props bidi_paragraph_props; + intl_props.props = &bidi_paragraph_props; Eina_Unicode *ustr; if (!fn) return -1; ustr = evas_common_encoding_utf8_to_unicode(str, NULL); #ifdef BIDI_SUPPORT - evas_bidi_update_props(ustr, &intl_props); + evas_bidi_update_props(ustr, &bidi_paragraph_props); #endif ret = evas_common_font_query_char_at_coords(fn->font, ustr, &intl_props, x, y, cx, cy, cw, ch); #ifdef BIDI_SUPPORT