From d5e579c2e9aeaaa71084fd5851bba236a6dce0d6 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Mon, 9 Aug 2010 16:24:17 +0000 Subject: [PATCH] Evas: Redesigned the textblock object. Sorry, but full documented code will be committed tomorrow, this commit is needed for the API stabilization. Major changes in this commit: 1. Changed the textblock node system there is now a linked list for the format nodes and a linked list for the text nodes. Format and text nodes point to one anoter in a matter that will be explained in the source file (will be committed tomorrow). Each text node now represents a paragraph and each format node points to a specific location in a text node. 2. Text/Format nodes are now two distinct data types. 3. The concept of nodes is no longer exposed in the API except for the format nodes which are only slightly exposed just to enable users of the API to cycle all the formats in order to find stuff like anchors. 4. Every node has a PS (paragraph separator) format node pointing to it's end, except for the last one which has nothing. Nodes are only broken by PS's. 5. Changed the BiDi functions to work nicely with offsets in big chunks of text. More is explained in the email with the subject 'Evas Textblock redesign + edje_entry adjustments' that will be sent tomorrow because of technical issues. For full documentation about this object wait for the next commit. SVN revision: 50930 --- legacy/evas/src/lib/Evas.h | 50 +- legacy/evas/src/lib/canvas/evas_object_text.c | 14 +- .../src/lib/canvas/evas_object_textblock.c | 6118 +++++++++-------- .../src/lib/engines/common/evas_bidi_utils.c | 79 +- .../src/lib/engines/common/evas_bidi_utils.h | 21 +- .../src/lib/engines/common/evas_font_draw.c | 6 +- .../src/lib/engines/common/evas_font_query.c | 6 +- legacy/evas/src/lib/imaging/evas_imaging.c | 22 +- 8 files changed, 3277 insertions(+), 3039 deletions(-) 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