diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/evas/src/lib/canvas/evas_object_textblock.c | 909 |
1 files changed, 648 insertions, 261 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_object_textblock.c b/libraries/evas/src/lib/canvas/evas_object_textblock.c index 7941a45..568911c 100644 --- a/libraries/evas/src/lib/canvas/evas_object_textblock.c +++ b/libraries/evas/src/lib/canvas/evas_object_textblock.c | |||
@@ -61,13 +61,13 @@ | |||
61 | * @subsection textblock_layout The layout system | 61 | * @subsection textblock_layout The layout system |
62 | * @todo write @ref textblock_layout | 62 | * @todo write @ref textblock_layout |
63 | */ | 63 | */ |
64 | #include <stdlib.h> | ||
65 | |||
66 | #include "evas_common.h" | 64 | #include "evas_common.h" |
67 | #include "evas_private.h" | 65 | #include "evas_private.h" |
66 | #include <stdlib.h> | ||
68 | 67 | ||
69 | #ifdef HAVE_LINEBREAK | 68 | #ifdef HAVE_LINEBREAK |
70 | #include "linebreak.h" | 69 | #include "linebreak.h" |
70 | #include "wordbreak.h" | ||
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | /* save typing */ | 73 | /* save typing */ |
@@ -78,12 +78,19 @@ | |||
78 | static const char o_type[] = "textblock"; | 78 | static const char o_type[] = "textblock"; |
79 | 79 | ||
80 | /* The char to be inserted instead of visible formats */ | 80 | /* The char to be inserted instead of visible formats */ |
81 | #define EVAS_TEXTBLOCK_REPLACEMENT_CHAR 0xFFFC | 81 | #define _REPLACEMENT_CHAR 0xFFFC |
82 | #define _PARAGRAPH_SEPARATOR 0x2029 | 82 | #define _PARAGRAPH_SEPARATOR 0x2029 |
83 | #define _NEWLINE '\n' | ||
84 | #define _TAB '\t' | ||
85 | |||
86 | #define _REPLACEMENT_CHAR_UTF8 "\xEF\xBF\xBC" | ||
87 | #define _PARAGRAPH_SEPARATOR_UTF8 "\xE2\x80\xA9" | ||
88 | #define _NEWLINE_UTF8 "\n" | ||
89 | #define _TAB_UTF8 "\t" | ||
83 | #define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \ | 90 | #define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \ |
84 | (((ch) == EVAS_TEXTBLOCK_REPLACEMENT_CHAR) || \ | 91 | (((ch) == _REPLACEMENT_CHAR) || \ |
85 | ((ch) == '\n') || \ | 92 | ((ch) == _NEWLINE) || \ |
86 | ((ch) == '\t') || \ | 93 | ((ch) == _TAB) || \ |
87 | ((ch) == _PARAGRAPH_SEPARATOR)) | 94 | ((ch) == _PARAGRAPH_SEPARATOR)) |
88 | 95 | ||
89 | /* private struct for textblock object internal data */ | 96 | /* private struct for textblock object internal data */ |
@@ -101,6 +108,12 @@ typedef struct _Evas_Object_Textblock Evas_Object_Textblock; | |||
101 | typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; | 108 | typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; |
102 | /** | 109 | /** |
103 | * @internal | 110 | * @internal |
111 | * @typedef Evas_Object_Style_Tag | ||
112 | * The structure used for finding style tags. | ||
113 | */ | ||
114 | typedef struct _Evas_Object_Style_Tag_Base Evas_Object_Style_Tag_Base; | ||
115 | /** | ||
116 | * @internal | ||
104 | * @typedef Evas_Object_Textblock_Node_Text | 117 | * @typedef Evas_Object_Textblock_Node_Text |
105 | * A text node. | 118 | * A text node. |
106 | */ | 119 | */ |
@@ -195,21 +208,26 @@ typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format; | |||
195 | * Returns true if closer is the closer of base. | 208 | * Returns true if closer is the closer of base. |
196 | */ | 209 | */ |
197 | #define _FORMAT_IS_CLOSER_OF(base, closer, closer_len) \ | 210 | #define _FORMAT_IS_CLOSER_OF(base, closer, closer_len) \ |
198 | (!strncmp(base + 1, closer, closer_len) && \ | 211 | (!strncmp(base, closer, closer_len) && \ |
199 | (!base[closer_len + 1] || \ | 212 | (!base[closer_len] || \ |
200 | (base[closer_len + 1] == '=') || \ | 213 | (base[closer_len] == '=') || \ |
201 | _is_white(base[closer_len + 1]))) | 214 | _is_white(base[closer_len]))) |
202 | 215 | ||
203 | /*FIXME: document the structs and struct items. */ | 216 | /*FIXME: document the structs and struct items. */ |
204 | struct _Evas_Object_Style_Tag | 217 | struct _Evas_Object_Style_Tag_Base |
205 | { | 218 | { |
206 | EINA_INLIST; | ||
207 | char *tag; | 219 | char *tag; |
208 | char *replace; | 220 | char *replace; |
209 | size_t tag_len; | 221 | size_t tag_len; |
210 | size_t replace_len; | 222 | size_t replace_len; |
211 | }; | 223 | }; |
212 | 224 | ||
225 | struct _Evas_Object_Style_Tag | ||
226 | { | ||
227 | EINA_INLIST; | ||
228 | Evas_Object_Style_Tag_Base tag; | ||
229 | }; | ||
230 | |||
213 | struct _Evas_Object_Textblock_Node_Text | 231 | struct _Evas_Object_Textblock_Node_Text |
214 | { | 232 | { |
215 | EINA_INLIST; | 233 | EINA_INLIST; |
@@ -229,11 +247,18 @@ struct _Evas_Object_Textblock_Node_Format | |||
229 | Evas_Object_Textblock_Node_Text *text_node; | 247 | Evas_Object_Textblock_Node_Text *text_node; |
230 | size_t offset; | 248 | size_t offset; |
231 | unsigned char anchor : 2; | 249 | unsigned char anchor : 2; |
250 | Eina_Bool opener : 1; | ||
251 | Eina_Bool own_closer : 1; | ||
232 | Eina_Bool visible : 1; | 252 | Eina_Bool visible : 1; |
233 | Eina_Bool format_change : 1; | 253 | Eina_Bool format_change : 1; |
234 | Eina_Bool is_new : 1; | 254 | Eina_Bool is_new : 1; |
235 | }; | 255 | }; |
236 | 256 | ||
257 | /* The default tags to use */ | ||
258 | static const Evas_Object_Style_Tag_Base default_tags[] = { | ||
259 | { "b", "+ font_weight=Bold", 1, 18 }, | ||
260 | { "i", "+ font_style=Italic", 1, 19 }}; | ||
261 | |||
237 | #define ANCHOR_NONE 0 | 262 | #define ANCHOR_NONE 0 |
238 | #define ANCHOR_A 1 | 263 | #define ANCHOR_A 1 |
239 | #define ANCHOR_ITEM 2 | 264 | #define ANCHOR_ITEM 2 |
@@ -538,8 +563,8 @@ _style_replace(Evas_Textblock_Style *ts, const char *style_text) | |||
538 | 563 | ||
539 | tag = (Evas_Object_Style_Tag *)ts->tags; | 564 | tag = (Evas_Object_Style_Tag *)ts->tags; |
540 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); | 565 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); |
541 | free(tag->tag); | 566 | free(tag->tag.tag); |
542 | free(tag->replace); | 567 | free(tag->tag.replace); |
543 | free(tag); | 568 | free(tag); |
544 | } | 569 | } |
545 | ts->default_tag = NULL; | 570 | ts->default_tag = NULL; |
@@ -567,19 +592,38 @@ _style_clear(Evas_Textblock_Style *ts) | |||
567 | * @return The replacement string found. | 592 | * @return The replacement string found. |
568 | */ | 593 | */ |
569 | static inline const char * | 594 | static inline const char * |
570 | _style_match_tag(Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len) | 595 | _style_match_tag(const Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len) |
571 | { | 596 | { |
572 | Evas_Object_Style_Tag *tag; | 597 | Evas_Object_Style_Tag *tag; |
573 | 598 | ||
599 | /* Try the style tags */ | ||
574 | EINA_INLIST_FOREACH(ts->tags, tag) | 600 | EINA_INLIST_FOREACH(ts->tags, tag) |
575 | { | 601 | { |
576 | if (tag->tag_len != tag_len) continue; | 602 | if (tag->tag.tag_len != tag_len) continue; |
577 | if (!strncmp(tag->tag, s, tag_len)) | 603 | if (!strncmp(tag->tag.tag, s, tag_len)) |
578 | { | 604 | { |
579 | *replace_len = tag->replace_len; | 605 | *replace_len = tag->tag.replace_len; |
580 | return tag->replace; | 606 | return tag->tag.replace; |
581 | } | 607 | } |
582 | } | 608 | } |
609 | |||
610 | /* Try the default tags */ | ||
611 | { | ||
612 | size_t i; | ||
613 | const Evas_Object_Style_Tag_Base *btag; | ||
614 | for (btag = default_tags, i = 0 ; | ||
615 | i < (sizeof(default_tags) / sizeof(default_tags[0])) ; | ||
616 | btag++, i++) | ||
617 | { | ||
618 | if (btag->tag_len != tag_len) continue; | ||
619 | if (!strncmp(btag->tag, s, tag_len)) | ||
620 | { | ||
621 | *replace_len = btag->replace_len; | ||
622 | return btag->replace; | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
583 | *replace_len = 0; | 627 | *replace_len = 0; |
584 | return NULL; | 628 | return NULL; |
585 | } | 629 | } |
@@ -1689,8 +1733,8 @@ _format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *st | |||
1689 | 1733 | ||
1690 | s = str; | 1734 | s = str; |
1691 | 1735 | ||
1692 | /* get rid of anything +s or -s off the start of the string */ | 1736 | /* get rid of any spaces at the start of the string */ |
1693 | while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; | 1737 | while (*s == ' ') s++; |
1694 | 1738 | ||
1695 | while ((item = _format_parse(&s))) | 1739 | while ((item = _format_parse(&s))) |
1696 | { | 1740 | { |
@@ -2131,7 +2175,6 @@ _layout_format_pop(Ctxt *c, const char *format) | |||
2131 | if ((c->format_stack) && (c->format_stack->next)) | 2175 | if ((c->format_stack) && (c->format_stack->next)) |
2132 | { | 2176 | { |
2133 | Eina_List *redo_nodes = NULL; | 2177 | Eina_List *redo_nodes = NULL; |
2134 | format++; /* Skip the '-' */ | ||
2135 | 2178 | ||
2136 | /* Generic pop, should just pop. */ | 2179 | /* Generic pop, should just pop. */ |
2137 | if (((format[0] == ' ') && !format[1]) || | 2180 | if (((format[0] == ' ') && !format[1]) || |
@@ -2994,21 +3037,29 @@ _format_finalize(Evas_Object *obj, Evas_Object_Textblock_Format *fmt) | |||
2994 | * @def _IS_TAB(item) | 3037 | * @def _IS_TAB(item) |
2995 | */ | 3038 | */ |
2996 | #define _IS_TAB(item) \ | 3039 | #define _IS_TAB(item) \ |
2997 | (!strcmp(item, "\t") || !strcmp(item, "\\t")) | 3040 | (!strcmp(item, "tab") || !strcmp(item, "\t") || !strcmp(item, "\\t")) |
2998 | /** | 3041 | /** |
2999 | * @internal | 3042 | * @internal |
3000 | * Returns true if the item is a line spearator, false otherwise | 3043 | * Returns true if the item is a line spearator, false otherwise |
3001 | * @def _IS_LINE_SEPARATOR(item) | 3044 | * @def _IS_LINE_SEPARATOR(item) |
3002 | */ | 3045 | */ |
3003 | #define _IS_LINE_SEPARATOR(item) \ | 3046 | #define _IS_LINE_SEPARATOR(item) \ |
3004 | (!strcmp(item, "\n") || !strcmp(item, "\\n")) | 3047 | (!strcmp(item, "br") || !strcmp(item, "\n") || !strcmp(item, "\\n")) |
3005 | /** | 3048 | /** |
3006 | * @internal | 3049 | * @internal |
3007 | * Returns true if the item is a paragraph separator, false otherwise | 3050 | * Returns true if the item is a paragraph separator, false otherwise |
3008 | * @def _IS_PARAGRAPH_SEPARATOR(item) | 3051 | * @def _IS_PARAGRAPH_SEPARATOR(item) |
3009 | */ | 3052 | */ |
3053 | #define _IS_PARAGRAPH_SEPARATOR_SIMPLE(item) \ | ||
3054 | (!strcmp(item, "ps")) | ||
3055 | /** | ||
3056 | * @internal | ||
3057 | * Returns true if the item is a paragraph separator, false otherwise | ||
3058 | * takes legacy mode into account. | ||
3059 | * @def _IS_PARAGRAPH_SEPARATOR(item) | ||
3060 | */ | ||
3010 | #define _IS_PARAGRAPH_SEPARATOR(o, item) \ | 3061 | #define _IS_PARAGRAPH_SEPARATOR(o, item) \ |
3011 | (!strcmp(item, "ps") || \ | 3062 | (_IS_PARAGRAPH_SEPARATOR_SIMPLE(item) || \ |
3012 | (o->legacy_newline && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */ | 3063 | (o->legacy_newline && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */ |
3013 | 3064 | ||
3014 | /** | 3065 | /** |
@@ -3041,7 +3092,7 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c, | |||
3041 | int handled = 0; | 3092 | int handled = 0; |
3042 | 3093 | ||
3043 | s = n->format; | 3094 | s = n->format; |
3044 | if (!strncmp(s, "+ item ", 7)) | 3095 | if (!strncmp(s, "item ", 5)) |
3045 | { | 3096 | { |
3046 | // one of: | 3097 | // one of: |
3047 | // item size=20x10 href=name | 3098 | // item size=20x10 href=name |
@@ -3133,16 +3184,14 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c, | |||
3133 | if (!handled) | 3184 | if (!handled) |
3134 | { | 3185 | { |
3135 | Eina_Bool push_fmt = EINA_FALSE; | 3186 | Eina_Bool push_fmt = EINA_FALSE; |
3136 | if (s[0] == '+') | 3187 | if (n->opener && !n->own_closer) |
3137 | { | 3188 | { |
3138 | fmt = _layout_format_push(c, fmt, n); | 3189 | fmt = _layout_format_push(c, fmt, n); |
3139 | s++; | ||
3140 | push_fmt = EINA_TRUE; | 3190 | push_fmt = EINA_TRUE; |
3141 | } | 3191 | } |
3142 | else if (s[0] == '-') | 3192 | else if (!n->opener) |
3143 | { | 3193 | { |
3144 | fmt = _layout_format_pop(c, n->orig_format); | 3194 | fmt = _layout_format_pop(c, n->orig_format); |
3145 | s++; | ||
3146 | } | 3195 | } |
3147 | while ((item = _format_parse(&s))) | 3196 | while ((item = _format_parse(&s))) |
3148 | { | 3197 | { |
@@ -3166,7 +3215,7 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c, | |||
3166 | 3215 | ||
3167 | fi->parent.w = fi->parent.adv = 0; | 3216 | fi->parent.w = fi->parent.adv = 0; |
3168 | } | 3217 | } |
3169 | else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) | 3218 | else if (_IS_TAB(item)) |
3170 | { | 3219 | { |
3171 | Evas_Object_Textblock_Format_Item *fi; | 3220 | Evas_Object_Textblock_Format_Item *fi; |
3172 | 3221 | ||
@@ -3215,28 +3264,33 @@ _layout_update_par(Ctxt *c) | |||
3215 | /* -1 means no wrap */ | 3264 | /* -1 means no wrap */ |
3216 | static int | 3265 | static int |
3217 | _layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | 3266 | _layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, |
3218 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | 3267 | const Evas_Object_Textblock_Item *it, size_t line_start, |
3219 | const char *breaks) | 3268 | const char *breaks) |
3220 | { | 3269 | { |
3221 | int wrap; | 3270 | int wrap; |
3222 | size_t uwrap; | 3271 | size_t uwrap; |
3223 | size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode); | 3272 | size_t len = eina_ustrbuf_length_get(it->text_node->unicode); |
3224 | /* Currently not being used, because it doesn't contain relevant | 3273 | /* Currently not being used, because it doesn't contain relevant |
3225 | * information */ | 3274 | * information */ |
3226 | (void) breaks; | 3275 | (void) breaks; |
3227 | 3276 | ||
3228 | { | 3277 | { |
3229 | wrap = _layout_text_cutoff_get(c, fmt, ti); | 3278 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) |
3279 | wrap = 0; | ||
3280 | else | ||
3281 | wrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it)); | ||
3282 | |||
3230 | if (wrap < 0) | 3283 | if (wrap < 0) |
3231 | return -1; | 3284 | return -1; |
3232 | uwrap = (size_t) wrap + ti->parent.text_pos; | 3285 | uwrap = (size_t) wrap + it->text_pos; |
3233 | } | 3286 | } |
3234 | 3287 | ||
3235 | 3288 | ||
3236 | if (uwrap == line_start) | 3289 | if ((uwrap == line_start) && (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)) |
3237 | { | 3290 | { |
3238 | uwrap = ti->parent.text_pos + | 3291 | uwrap = it->text_pos + |
3239 | (size_t) evas_common_text_props_cluster_next(&ti->text_props, wrap); | 3292 | (size_t) evas_common_text_props_cluster_next( |
3293 | &_ITEM_TEXT(it)->text_props, wrap); | ||
3240 | } | 3294 | } |
3241 | if ((uwrap <= line_start) || (uwrap > len)) | 3295 | if ((uwrap <= line_start) || (uwrap > len)) |
3242 | return -1; | 3296 | return -1; |
@@ -3259,16 +3313,16 @@ _layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | |||
3259 | #endif | 3313 | #endif |
3260 | static int | 3314 | static int |
3261 | _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, | 3315 | _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, |
3262 | const Evas_Object_Textblock_Text_Item *ti, Eina_Bool mixed_wrap, | 3316 | const Evas_Object_Textblock_Item *it, Eina_Bool mixed_wrap, |
3263 | size_t line_start, const char *breaks) | 3317 | size_t line_start, const char *breaks) |
3264 | { | 3318 | { |
3265 | Eina_Bool wrap_after = EINA_FALSE; | 3319 | Eina_Bool wrap_after = EINA_FALSE; |
3266 | size_t wrap; | 3320 | size_t wrap; |
3267 | size_t orig_wrap; | 3321 | size_t orig_wrap; |
3268 | const Eina_Unicode *str = eina_ustrbuf_string_get( | 3322 | const Eina_Unicode *str = eina_ustrbuf_string_get( |
3269 | ti->parent.text_node->unicode); | 3323 | it->text_node->unicode); |
3270 | int item_start = ti->parent.text_pos; | 3324 | int item_start = it->text_pos; |
3271 | size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode); | 3325 | size_t len = eina_ustrbuf_length_get(it->text_node->unicode); |
3272 | #ifndef HAVE_LINEBREAK | 3326 | #ifndef HAVE_LINEBREAK |
3273 | /* Not used without liblinebreak ATM. */ | 3327 | /* Not used without liblinebreak ATM. */ |
3274 | (void) breaks; | 3328 | (void) breaks; |
@@ -3276,7 +3330,10 @@ _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, | |||
3276 | 3330 | ||
3277 | { | 3331 | { |
3278 | int swrap = -1; | 3332 | int swrap = -1; |
3279 | swrap = _layout_text_cutoff_get(c, fmt, ti); | 3333 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) |
3334 | swrap = 0; | ||
3335 | else | ||
3336 | swrap = _layout_text_cutoff_get(c, fmt, _ITEM_TEXT(it)); | ||
3280 | /* Avoiding too small textblocks to even contain one char. | 3337 | /* Avoiding too small textblocks to even contain one char. |
3281 | * FIXME: This can cause breaking inside ligatures. */ | 3338 | * FIXME: This can cause breaking inside ligatures. */ |
3282 | 3339 | ||
@@ -3331,7 +3388,7 @@ _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, | |||
3331 | { | 3388 | { |
3332 | if (mixed_wrap) | 3389 | if (mixed_wrap) |
3333 | { | 3390 | { |
3334 | return _layout_get_charwrap(c, fmt, ti, | 3391 | return _layout_get_charwrap(c, fmt, it, |
3335 | line_start, breaks); | 3392 | line_start, breaks); |
3336 | } | 3393 | } |
3337 | else | 3394 | else |
@@ -3362,20 +3419,20 @@ _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, | |||
3362 | /* -1 means no wrap */ | 3419 | /* -1 means no wrap */ |
3363 | static int | 3420 | static int |
3364 | _layout_get_wordwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | 3421 | _layout_get_wordwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, |
3365 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | 3422 | const Evas_Object_Textblock_Item *it, size_t line_start, |
3366 | const char *breaks) | 3423 | const char *breaks) |
3367 | { | 3424 | { |
3368 | return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_FALSE, line_start, | 3425 | return _layout_get_word_mixwrap_common(c, fmt, it, EINA_FALSE, line_start, |
3369 | breaks); | 3426 | breaks); |
3370 | } | 3427 | } |
3371 | 3428 | ||
3372 | /* -1 means no wrap */ | 3429 | /* -1 means no wrap */ |
3373 | static int | 3430 | static int |
3374 | _layout_get_mixedwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | 3431 | _layout_get_mixedwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, |
3375 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | 3432 | const Evas_Object_Textblock_Item *it, size_t line_start, |
3376 | const char *breaks) | 3433 | const char *breaks) |
3377 | { | 3434 | { |
3378 | return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_TRUE, line_start, | 3435 | return _layout_get_word_mixwrap_common(c, fmt, it, EINA_TRUE, line_start, |
3379 | breaks); | 3436 | breaks); |
3380 | } | 3437 | } |
3381 | 3438 | ||
@@ -3503,7 +3560,7 @@ _layout_paragraph_reorder_lines(Evas_Object_Textblock_Paragraph *par) | |||
3503 | 3560 | ||
3504 | static void | 3561 | static void |
3505 | _layout_paragraph_render(Evas_Object_Textblock *o, | 3562 | _layout_paragraph_render(Evas_Object_Textblock *o, |
3506 | Evas_Object_Textblock_Paragraph *par) | 3563 | Evas_Object_Textblock_Paragraph *par) |
3507 | { | 3564 | { |
3508 | if (par->rendered) | 3565 | if (par->rendered) |
3509 | return; | 3566 | return; |
@@ -3521,6 +3578,8 @@ _layout_paragraph_render(Evas_Object_Textblock *o, | |||
3521 | par->bidi_props = NULL; | 3578 | par->bidi_props = NULL; |
3522 | } | 3579 | } |
3523 | } | 3580 | } |
3581 | #else | ||
3582 | (void) o; | ||
3524 | #endif | 3583 | #endif |
3525 | } | 3584 | } |
3526 | 3585 | ||
@@ -3656,120 +3715,127 @@ _layout_par(Ctxt *c) | |||
3656 | else if ((it->format->wrap_word || it->format->wrap_char || | 3715 | else if ((it->format->wrap_word || it->format->wrap_char || |
3657 | it->format->wrap_mixed) && it->text_node) | 3716 | it->format->wrap_mixed) && it->text_node) |
3658 | { | 3717 | { |
3659 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | 3718 | size_t line_start; |
3719 | size_t it_len; | ||
3720 | |||
3721 | it_len = (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) ? | ||
3722 | 1 : _ITEM_TEXT(it)->text_props.text_len; | ||
3723 | |||
3724 | |||
3725 | #ifdef HAVE_LINEBREAK | ||
3726 | /* If we haven't calculated the linebreaks yet, | ||
3727 | * do */ | ||
3728 | if (!line_breaks) | ||
3660 | { | 3729 | { |
3661 | /* Don't wrap if it's the only item */ | 3730 | /* Only relevant in those cases */ |
3662 | if (c->ln->items) | 3731 | if (it->format->wrap_word || it->format->wrap_mixed) |
3663 | { | 3732 | { |
3664 | /*FIXME: I should handle format correctly, | 3733 | const char *lang; |
3665 | i.e verify we are allowed to break here */ | 3734 | lang = (it->format->font.fdesc) ? |
3666 | _layout_line_advance(c, it->format); | 3735 | it->format->font.fdesc->lang : ""; |
3667 | wrap = -1; | 3736 | size_t len = |
3737 | eina_ustrbuf_length_get( | ||
3738 | it->text_node->unicode); | ||
3739 | line_breaks = malloc(len); | ||
3740 | set_linebreaks_utf32((const utf32_t *) | ||
3741 | eina_ustrbuf_string_get( | ||
3742 | it->text_node->unicode), | ||
3743 | len, lang, line_breaks); | ||
3668 | } | 3744 | } |
3669 | } | 3745 | } |
3746 | #endif | ||
3747 | if (c->ln->items) | ||
3748 | line_start = c->ln->items->text_pos; | ||
3670 | else | 3749 | else |
3671 | { | 3750 | line_start = it->text_pos; |
3672 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
3673 | size_t line_start; | ||
3674 | 3751 | ||
3675 | #ifdef HAVE_LINEBREAK | 3752 | adv_line = 1; |
3676 | /* If we haven't calculated the linebreaks yet, | 3753 | /* If we don't already have a wrap point from before */ |
3677 | * do */ | 3754 | if (wrap < 0) |
3678 | if (!line_breaks) | 3755 | { |
3679 | { | 3756 | if (it->format->wrap_word) |
3680 | /* Only relevant in those cases */ | 3757 | wrap = _layout_get_wordwrap(c, it->format, it, |
3681 | if (it->format->wrap_word || it->format->wrap_mixed) | 3758 | line_start, line_breaks); |
3682 | { | 3759 | else if (it->format->wrap_char) |
3683 | const char *lang; | 3760 | wrap = _layout_get_charwrap(c, it->format, it, |
3684 | lang = (it->format->font.fdesc) ? | 3761 | line_start, line_breaks); |
3685 | it->format->font.fdesc->lang : ""; | 3762 | else if (it->format->wrap_mixed) |
3686 | size_t len = | 3763 | wrap = _layout_get_mixedwrap(c, it->format, it, |
3687 | eina_ustrbuf_length_get( | 3764 | line_start, line_breaks); |
3688 | it->text_node->unicode); | ||
3689 | line_breaks = malloc(len); | ||
3690 | set_linebreaks_utf32((const utf32_t *) | ||
3691 | eina_ustrbuf_string_get( | ||
3692 | it->text_node->unicode), | ||
3693 | len, lang, line_breaks); | ||
3694 | } | ||
3695 | } | ||
3696 | #endif | ||
3697 | if (c->ln->items) | ||
3698 | line_start = c->ln->items->text_pos; | ||
3699 | else | 3765 | else |
3700 | line_start = ti->parent.text_pos; | 3766 | wrap = -1; |
3701 | 3767 | } | |
3702 | adv_line = 1; | ||
3703 | /* If we don't already have a wrap point from before */ | ||
3704 | if (wrap < 0) | ||
3705 | { | ||
3706 | if (it->format->wrap_word) | ||
3707 | wrap = _layout_get_wordwrap(c, it->format, ti, | ||
3708 | line_start, line_breaks); | ||
3709 | else if (it->format->wrap_char) | ||
3710 | wrap = _layout_get_charwrap(c, it->format, ti, | ||
3711 | line_start, line_breaks); | ||
3712 | else if (it->format->wrap_mixed) | ||
3713 | wrap = _layout_get_mixedwrap(c, it->format, ti, | ||
3714 | line_start, line_breaks); | ||
3715 | else | ||
3716 | wrap = -1; | ||
3717 | } | ||
3718 | 3768 | ||
3719 | /* If it's before the item, rollback and apply. | 3769 | /* If it's before the item, rollback and apply. |
3720 | if it's in the item, cut. | 3770 | if it's in the item, cut. |
3721 | If it's after the item, delay the cut */ | 3771 | If it's after the item, delay the cut */ |
3722 | if (wrap > 0) | 3772 | if (wrap > 0) |
3773 | { | ||
3774 | size_t uwrap = (size_t) wrap; | ||
3775 | if (uwrap < it->text_pos) | ||
3723 | { | 3776 | { |
3724 | size_t uwrap = (size_t) wrap; | 3777 | /* Rollback latest additions, and cut that |
3725 | if (uwrap < ti->parent.text_pos) | 3778 | item */ |
3779 | i = eina_list_prev(i); | ||
3780 | it = eina_list_data_get(i); | ||
3781 | while (uwrap < it->text_pos) | ||
3726 | { | 3782 | { |
3727 | /* Rollback latest additions, and cut that | ||
3728 | item */ | ||
3729 | i = eina_list_prev(i); | ||
3730 | it = eina_list_data_get(i); | ||
3731 | while (uwrap < it->text_pos) | ||
3732 | { | ||
3733 | c->ln->items = _ITEM( | ||
3734 | eina_inlist_remove( | ||
3735 | EINA_INLIST_GET(c->ln->items), | ||
3736 | EINA_INLIST_GET(it))); | ||
3737 | i = eina_list_prev(i); | ||
3738 | it = eina_list_data_get(i); | ||
3739 | } | ||
3740 | c->x = it->x; | ||
3741 | c->ln->items = _ITEM( | 3783 | c->ln->items = _ITEM( |
3742 | eina_inlist_remove( | 3784 | eina_inlist_remove( |
3743 | EINA_INLIST_GET(c->ln->items), | 3785 | EINA_INLIST_GET(c->ln->items), |
3744 | EINA_INLIST_GET(it))); | 3786 | EINA_INLIST_GET(it))); |
3745 | continue; | 3787 | i = eina_list_prev(i); |
3788 | it = eina_list_data_get(i); | ||
3746 | } | 3789 | } |
3747 | /* If it points to the end, it means the previous | 3790 | c->x = it->x; |
3748 | * char is a whitespace we should remove, so this | 3791 | c->ln->items = _ITEM( |
3749 | * is a wanted cutting point. */ | 3792 | eina_inlist_remove( |
3750 | else if (uwrap > ti->parent.text_pos + | 3793 | EINA_INLIST_GET(c->ln->items), |
3751 | ti->text_props.text_len) | 3794 | EINA_INLIST_GET(it))); |
3752 | wrap = -1; /* Delay the cut in a smart way | 3795 | continue; |
3753 | i.e use the item_pos as the line_start, because | ||
3754 | there's already no cut before*/ | ||
3755 | else | ||
3756 | wrap -= ti->parent.text_pos; /* Cut here */ | ||
3757 | } | 3796 | } |
3758 | 3797 | /* If it points to the end, it means the previous | |
3759 | if (wrap > 0) | 3798 | * char is a whitespace we should remove, so this |
3799 | * is a wanted cutting point. */ | ||
3800 | else if (uwrap > it->text_pos + it_len) | ||
3760 | { | 3801 | { |
3761 | _layout_item_text_split_strip_white(c, ti, i, wrap); | 3802 | /* FIXME: Should redo the ellipsis handling. |
3762 | } | 3803 | * If we can do ellipsis, just cut here. */ |
3763 | else if (wrap == 0) | 3804 | if (it->format->ellipsis == 1.0) |
3805 | { | ||
3806 | _layout_handle_ellipsis(c, it, i); | ||
3807 | ret = 1; | ||
3808 | goto end; | ||
3809 | } | ||
3810 | else | ||
3811 | { | ||
3812 | /* Delay the cut in a smart way i.e use the | ||
3813 | item_pos as the line_start, because | ||
3814 | there's already no cut before*/ | ||
3815 | wrap = -1; | ||
3816 | } | ||
3817 | } | ||
3818 | else | ||
3819 | wrap -= it->text_pos; /* Cut here */ | ||
3820 | } | ||
3821 | |||
3822 | if (wrap > 0) | ||
3823 | { | ||
3824 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
3764 | { | 3825 | { |
3765 | /* Should wrap before the item */ | 3826 | _layout_item_text_split_strip_white(c, |
3766 | adv_line = 0; | 3827 | _ITEM_TEXT(it), i, wrap); |
3767 | redo_item = 1; | ||
3768 | _layout_line_advance(c, it->format); | ||
3769 | } | 3828 | } |
3770 | /* Reset wrap */ | ||
3771 | wrap = -1; | ||
3772 | } | 3829 | } |
3830 | else if (wrap == 0) | ||
3831 | { | ||
3832 | /* Should wrap before the item */ | ||
3833 | adv_line = 0; | ||
3834 | redo_item = 1; | ||
3835 | _layout_line_advance(c, it->format); | ||
3836 | } | ||
3837 | /* Reset wrap */ | ||
3838 | wrap = -1; | ||
3773 | } | 3839 | } |
3774 | } | 3840 | } |
3775 | 3841 | ||
@@ -3844,18 +3910,16 @@ _format_changes_invalidate_text_nodes(Ctxt *c) | |||
3844 | const char *fstr = fnode->orig_format; | 3910 | const char *fstr = fnode->orig_format; |
3845 | /* balance < 0 means we gave up and everything should be | 3911 | /* balance < 0 means we gave up and everything should be |
3846 | * invalidated */ | 3912 | * invalidated */ |
3847 | if (*fstr == '+') | 3913 | if (fnode->opener && !fnode->own_closer) |
3848 | { | 3914 | { |
3849 | balance++; | 3915 | balance++; |
3850 | if (!fstack) | 3916 | if (!fstack) |
3851 | start_n = fnode->text_node; | 3917 | start_n = fnode->text_node; |
3852 | fstack = eina_list_prepend(fstack, fnode); | 3918 | fstack = eina_list_prepend(fstack, fnode); |
3853 | } | 3919 | } |
3854 | else if (*fstr == '-') | 3920 | else if (!fnode->opener) |
3855 | { | 3921 | { |
3856 | size_t fstr_len; | 3922 | size_t fstr_len; |
3857 | /* Skip the '-' */ | ||
3858 | fstr++; | ||
3859 | fstr_len = strlen(fstr); | 3923 | fstr_len = strlen(fstr); |
3860 | /* Generic popper, just pop */ | 3924 | /* Generic popper, just pop */ |
3861 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | 3925 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) |
@@ -4429,12 +4493,12 @@ evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) | |||
4429 | { | 4493 | { |
4430 | if (!key_start) | 4494 | if (!key_start) |
4431 | { | 4495 | { |
4432 | if (!isspace(*p)) | 4496 | if (!isspace((unsigned char)(*p))) |
4433 | key_start = p; | 4497 | key_start = p; |
4434 | } | 4498 | } |
4435 | else if (!key_stop) | 4499 | else if (!key_stop) |
4436 | { | 4500 | { |
4437 | if ((*p == '=') || (isspace(*p))) | 4501 | if ((*p == '=') || (isspace((unsigned char)(*p)))) |
4438 | key_stop = p; | 4502 | key_stop = p; |
4439 | } | 4503 | } |
4440 | else if (!val_start) | 4504 | else if (!val_start) |
@@ -4479,10 +4543,10 @@ evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) | |||
4479 | tag = calloc(1, sizeof(Evas_Object_Style_Tag)); | 4543 | tag = calloc(1, sizeof(Evas_Object_Style_Tag)); |
4480 | if (tag) | 4544 | if (tag) |
4481 | { | 4545 | { |
4482 | tag->tag = tags; | 4546 | tag->tag.tag = tags; |
4483 | tag->replace = replaces; | 4547 | tag->tag.replace = replaces; |
4484 | tag->tag_len = tag_len; | 4548 | tag->tag.tag_len = tag_len; |
4485 | tag->replace_len = replace_len; | 4549 | tag->tag.replace_len = replace_len; |
4486 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); | 4550 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); |
4487 | } | 4551 | } |
4488 | else | 4552 | else |
@@ -4689,7 +4753,11 @@ _escaped_char_match(const char *s, int *adv) | |||
4689 | while ((*mc) && (*sc)) | 4753 | while ((*mc) && (*sc)) |
4690 | { | 4754 | { |
4691 | if ((unsigned char)*sc < (unsigned char)*mc) return NULL; | 4755 | if ((unsigned char)*sc < (unsigned char)*mc) return NULL; |
4692 | if (*sc != *mc) match = 0; | 4756 | if (*sc != *mc) |
4757 | { | ||
4758 | match = 0; | ||
4759 | break; | ||
4760 | } | ||
4693 | mc++; | 4761 | mc++; |
4694 | sc++; | 4762 | sc++; |
4695 | } | 4763 | } |
@@ -4723,7 +4791,7 @@ _escaped_char_get(const char *s, const char *s_end) | |||
4723 | int base = 10; | 4791 | int base = 10; |
4724 | s += 2; /* Skip "&#" */ | 4792 | s += 2; /* Skip "&#" */ |
4725 | 4793 | ||
4726 | if (tolower(*s) == 'x') | 4794 | if (tolower((unsigned char)(*s)) == 'x') |
4727 | { | 4795 | { |
4728 | s++; | 4796 | s++; |
4729 | base = 16; | 4797 | base = 16; |
@@ -4876,6 +4944,7 @@ evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char | |||
4876 | * NULL is reached. */ | 4944 | * NULL is reached. */ |
4877 | for (;;) | 4945 | for (;;) |
4878 | { | 4946 | { |
4947 | size_t text_len; | ||
4879 | /* If we got to the end of string or just finished/started tag | 4948 | /* If we got to the end of string or just finished/started tag |
4880 | * or escape sequence handling. */ | 4949 | * or escape sequence handling. */ |
4881 | if ((*p == 0) || | 4950 | if ((*p == 0) || |
@@ -4953,14 +5022,22 @@ evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char | |||
4953 | } | 5022 | } |
4954 | } | 5023 | } |
4955 | /* Unicode object replcament char */ | 5024 | /* Unicode object replcament char */ |
4956 | else if (!strncmp("\xEF\xBF\xBC", p, 3)) | 5025 | else if (!strncmp(_REPLACEMENT_CHAR_UTF8, p, |
5026 | text_len = strlen(_REPLACEMENT_CHAR_UTF8)) || | ||
5027 | !strncmp(_NEWLINE_UTF8, p, | ||
5028 | text_len = strlen(_NEWLINE_UTF8)) || | ||
5029 | !strncmp(_TAB_UTF8, p, | ||
5030 | text_len = strlen(_TAB_UTF8)) || | ||
5031 | !strncmp(_PARAGRAPH_SEPARATOR_UTF8, p, | ||
5032 | text_len = strlen(_PARAGRAPH_SEPARATOR_UTF8))) | ||
4957 | { | 5033 | { |
4958 | /*FIXME: currently just remove them, maybe do something | 5034 | /*FIXME: currently just remove them, maybe do something |
4959 | * fancier in the future, atm it breaks if this char | 5035 | * fancier in the future, atm it breaks if this char |
4960 | * is inside <> */ | 5036 | * is inside <> */ |
4961 | _prepend_text_run(cur, s, p); | 5037 | _prepend_text_run(cur, s, p); |
4962 | p += 2; /* it's also advanced later in this loop need +3 | 5038 | /* it's also advanced later in this loop need +text_len |
4963 | * in total*/ | 5039 | in total*/ |
5040 | p += text_len - 1; | ||
4964 | s = p + 1; /* One after the end of the replacement char */ | 5041 | s = p + 1; /* One after the end of the replacement char */ |
4965 | } | 5042 | } |
4966 | p++; | 5043 | p++; |
@@ -4979,19 +5056,19 @@ evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char | |||
4979 | * @param fnode the format node to process. | 5056 | * @param fnode the format node to process. |
4980 | */ | 5057 | */ |
4981 | static void | 5058 | static void |
4982 | _markup_get_format_append(Evas_Object_Textblock *o __UNUSED__, Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode) | 5059 | _markup_get_format_append(Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode) |
4983 | { | 5060 | { |
4984 | eina_strbuf_append_char(txt, '<'); | 5061 | eina_strbuf_append_char(txt, '<'); |
4985 | { | 5062 | { |
4986 | const char *s; | 5063 | const char *s; |
4987 | int pop = 0; | ||
4988 | 5064 | ||
4989 | // FIXME: need to escape | 5065 | // FIXME: need to escape |
4990 | s = fnode->orig_format; | 5066 | s = fnode->orig_format; |
4991 | if (*s == '-') pop = 1; | 5067 | if (!fnode->opener && !fnode->own_closer) |
4992 | while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; | 5068 | eina_strbuf_append_char(txt, '/'); |
4993 | if (pop) eina_strbuf_append_char(txt, '/'); | ||
4994 | eina_strbuf_append(txt, s); | 5069 | eina_strbuf_append(txt, s); |
5070 | if (fnode->own_closer) | ||
5071 | eina_strbuf_append_char(txt, '/'); | ||
4995 | } | 5072 | } |
4996 | eina_strbuf_append_char(txt, '>'); | 5073 | eina_strbuf_append_char(txt, '>'); |
4997 | } | 5074 | } |
@@ -5061,7 +5138,7 @@ evas_object_textblock_text_markup_get(const Evas_Object *obj) | |||
5061 | tmp_ch = text[off]; | 5138 | tmp_ch = text[off]; |
5062 | text[off] = 0; /* Null terminate the part of the string */ | 5139 | text[off] = 0; /* Null terminate the part of the string */ |
5063 | _markup_get_text_append(txt, text); | 5140 | _markup_get_text_append(txt, text); |
5064 | _markup_get_format_append(o, txt, fnode); | 5141 | _markup_get_format_append(txt, fnode); |
5065 | text[off] = tmp_ch; /* Restore the char */ | 5142 | text[off] = tmp_ch; /* Restore the char */ |
5066 | text += off; | 5143 | text += off; |
5067 | if (fnode->visible) | 5144 | if (fnode->visible) |
@@ -5086,6 +5163,190 @@ evas_object_textblock_text_markup_get(const Evas_Object *obj) | |||
5086 | return o->markup_text; | 5163 | return o->markup_text; |
5087 | } | 5164 | } |
5088 | 5165 | ||
5166 | EAPI char * | ||
5167 | evas_textblock_text_markup_to_utf8(const Evas_Object *obj, const char *text) | ||
5168 | { | ||
5169 | /* FIXME: Redundant and awful, should be merged with markup_prepend */ | ||
5170 | Eina_Strbuf *sbuf; | ||
5171 | char *s, *p, *ret; | ||
5172 | char *tag_start, *tag_end, *esc_start, *esc_end; | ||
5173 | |||
5174 | if (!text) return NULL; | ||
5175 | |||
5176 | |||
5177 | tag_start = tag_end = esc_start = esc_end = NULL; | ||
5178 | sbuf = eina_strbuf_new(); | ||
5179 | p = (char *)text; | ||
5180 | s = p; | ||
5181 | /* This loop goes through all of the mark up text until it finds format | ||
5182 | * tags, escape sequences or the terminating NULL. When it finds either | ||
5183 | * of those, it appends the text found up until that point to the textblock | ||
5184 | * proccesses whatever found. It repeats itself until the termainating | ||
5185 | * NULL is reached. */ | ||
5186 | for (;;) | ||
5187 | { | ||
5188 | /* If we got to the end of string or just finished/started tag | ||
5189 | * or escape sequence handling. */ | ||
5190 | if ((*p == 0) || | ||
5191 | (tag_end) || (esc_end) || | ||
5192 | (tag_start) || (esc_start)) | ||
5193 | { | ||
5194 | if (tag_end) | ||
5195 | { | ||
5196 | /* If we reached to a tag ending, analyze the tag */ | ||
5197 | char *ttag; | ||
5198 | size_t ttag_len; | ||
5199 | |||
5200 | tag_start++; /* Skip the < */ | ||
5201 | tag_end--; /* Skip the > */ | ||
5202 | if ((tag_end > tag_start) && (*(tag_end - 1) == '/')) | ||
5203 | { | ||
5204 | tag_end --; /* Skip the terminating '/' */ | ||
5205 | while (*(tag_end - 1) == ' ') | ||
5206 | tag_end--; /* skip trailing ' ' */ | ||
5207 | } | ||
5208 | |||
5209 | ttag_len = tag_end - tag_start; | ||
5210 | |||
5211 | ttag = malloc(ttag_len + 1); | ||
5212 | if (ttag) | ||
5213 | { | ||
5214 | const char *match = NULL; | ||
5215 | size_t replace_len; | ||
5216 | memcpy(ttag, tag_start, ttag_len); | ||
5217 | ttag[ttag_len] = 0; | ||
5218 | |||
5219 | |||
5220 | if (obj) | ||
5221 | { | ||
5222 | match = _style_match_tag( | ||
5223 | evas_object_textblock_style_get(obj), | ||
5224 | ttag, ttag_len, &replace_len); | ||
5225 | } | ||
5226 | |||
5227 | if (!match) match = ttag; | ||
5228 | |||
5229 | if (_IS_PARAGRAPH_SEPARATOR_SIMPLE(match)) | ||
5230 | eina_strbuf_append(sbuf, _PARAGRAPH_SEPARATOR_UTF8); | ||
5231 | else if (_IS_LINE_SEPARATOR(match)) | ||
5232 | eina_strbuf_append(sbuf, _NEWLINE_UTF8); | ||
5233 | else if (_IS_TAB(match)) | ||
5234 | eina_strbuf_append(sbuf, _TAB_UTF8); | ||
5235 | else if (!strncmp(match, "item", 4)) | ||
5236 | eina_strbuf_append(sbuf, _REPLACEMENT_CHAR_UTF8); | ||
5237 | |||
5238 | free(ttag); | ||
5239 | } | ||
5240 | tag_start = tag_end = NULL; | ||
5241 | } | ||
5242 | else if (esc_end) | ||
5243 | { | ||
5244 | const char *escape; | ||
5245 | |||
5246 | escape = _escaped_char_get(esc_start, esc_end + 1); | ||
5247 | eina_strbuf_append(sbuf, escape); | ||
5248 | esc_start = esc_end = NULL; | ||
5249 | } | ||
5250 | else if (*p == 0) | ||
5251 | { | ||
5252 | eina_strbuf_append_length(sbuf, s, p - s); | ||
5253 | s = NULL; | ||
5254 | } | ||
5255 | if (*p == 0) | ||
5256 | break; | ||
5257 | } | ||
5258 | if (*p == '<') | ||
5259 | { | ||
5260 | if (!esc_start) | ||
5261 | { | ||
5262 | /* Append the text prior to this to the textblock and | ||
5263 | * mark the start of the tag */ | ||
5264 | tag_start = p; | ||
5265 | tag_end = NULL; | ||
5266 | eina_strbuf_append_length(sbuf, s, p - s); | ||
5267 | s = NULL; | ||
5268 | } | ||
5269 | } | ||
5270 | else if (*p == '>') | ||
5271 | { | ||
5272 | if (tag_start) | ||
5273 | { | ||
5274 | tag_end = p + 1; | ||
5275 | s = p + 1; | ||
5276 | } | ||
5277 | } | ||
5278 | else if (*p == '&') | ||
5279 | { | ||
5280 | if (!tag_start) | ||
5281 | { | ||
5282 | /* Append the text prior to this to the textblock and mark | ||
5283 | * the start of the escape sequence */ | ||
5284 | esc_start = p; | ||
5285 | esc_end = NULL; | ||
5286 | eina_strbuf_append_length(sbuf, s, p - s); | ||
5287 | s = NULL; | ||
5288 | } | ||
5289 | } | ||
5290 | else if (*p == ';') | ||
5291 | { | ||
5292 | if (esc_start) | ||
5293 | { | ||
5294 | esc_end = p; | ||
5295 | s = p + 1; | ||
5296 | } | ||
5297 | } | ||
5298 | p++; | ||
5299 | } | ||
5300 | |||
5301 | ret = eina_strbuf_string_steal(sbuf); | ||
5302 | eina_strbuf_free(sbuf); | ||
5303 | return ret; | ||
5304 | } | ||
5305 | |||
5306 | EAPI char * | ||
5307 | evas_textblock_text_utf8_to_markup(const Evas_Object *obj, const char *text) | ||
5308 | { | ||
5309 | Eina_Strbuf *sbuf; | ||
5310 | char *str = NULL; | ||
5311 | int ch, pos = 0, pos2 = 0; | ||
5312 | |||
5313 | (void) obj; | ||
5314 | |||
5315 | if (!text) return NULL; | ||
5316 | |||
5317 | sbuf = eina_strbuf_new(); | ||
5318 | |||
5319 | for (;;) | ||
5320 | { | ||
5321 | pos = pos2; | ||
5322 | pos2 = evas_string_char_next_get(text, pos2, &ch); | ||
5323 | if ((ch <= 0) || (pos2 <= 0)) break; | ||
5324 | |||
5325 | if (ch == _NEWLINE) | ||
5326 | eina_strbuf_append(sbuf, "<br/>"); | ||
5327 | else if (ch == _TAB) | ||
5328 | eina_strbuf_append(sbuf, "<tab/>"); | ||
5329 | else if (ch == '<') | ||
5330 | eina_strbuf_append(sbuf, "<"); | ||
5331 | else if (ch == '>') | ||
5332 | eina_strbuf_append(sbuf, ">"); | ||
5333 | else if (ch == '&') | ||
5334 | eina_strbuf_append(sbuf, "&"); | ||
5335 | else if (ch == _PARAGRAPH_SEPARATOR) | ||
5336 | eina_strbuf_append(sbuf, "<ps/>"); | ||
5337 | else if (ch == _REPLACEMENT_CHAR) | ||
5338 | eina_strbuf_append(sbuf, ""); | ||
5339 | else | ||
5340 | { | ||
5341 | eina_strbuf_append_length(sbuf, text + pos, pos2 - pos); | ||
5342 | } | ||
5343 | } | ||
5344 | str = eina_strbuf_string_steal(sbuf); | ||
5345 | eina_strbuf_free(sbuf); | ||
5346 | return str; | ||
5347 | |||
5348 | } | ||
5349 | |||
5089 | /* cursors */ | 5350 | /* cursors */ |
5090 | 5351 | ||
5091 | /** | 5352 | /** |
@@ -5453,15 +5714,13 @@ evas_textblock_node_format_remove_pair(Evas_Object *obj, | |||
5453 | { | 5714 | { |
5454 | const char *fstr = fmt->orig_format; | 5715 | const char *fstr = fmt->orig_format; |
5455 | 5716 | ||
5456 | if (fstr && (*fstr == '+')) | 5717 | if (fmt->opener && !fmt->own_closer) |
5457 | { | 5718 | { |
5458 | fstack = eina_list_prepend(fstack, fmt); | 5719 | fstack = eina_list_prepend(fstack, fmt); |
5459 | } | 5720 | } |
5460 | else if (fstr && (*fstr == '-')) | 5721 | else if (fstr && !fmt->opener) |
5461 | { | 5722 | { |
5462 | size_t fstr_len; | 5723 | size_t fstr_len; |
5463 | /* Skip the '-' */ | ||
5464 | fstr++; | ||
5465 | fstr_len = strlen(fstr); | 5724 | fstr_len = strlen(fstr); |
5466 | /* Generic popper, just pop */ | 5725 | /* Generic popper, just pop */ |
5467 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | 5726 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) |
@@ -5708,6 +5967,111 @@ evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) | |||
5708 | return EINA_FALSE; | 5967 | return EINA_FALSE; |
5709 | } | 5968 | } |
5710 | 5969 | ||
5970 | #ifdef HAVE_LINEBREAK | ||
5971 | |||
5972 | /* BREAK_AFTER: true if we can break after the current char. | ||
5973 | * Both macros assume str[i] is not the terminating nul */ | ||
5974 | #define BREAK_AFTER(i) \ | ||
5975 | (breaks[i] == WORDBREAK_BREAK) | ||
5976 | |||
5977 | #else | ||
5978 | |||
5979 | #define BREAK_AFTER(i) \ | ||
5980 | ((!str[i + 1]) || \ | ||
5981 | (_is_white(str[i]) && !_is_white(str[i + 1])) || \ | ||
5982 | (!_is_white(str[i]) && _is_white(str[i + 1]))) | ||
5983 | |||
5984 | #endif | ||
5985 | |||
5986 | EAPI Eina_Bool | ||
5987 | evas_textblock_cursor_word_start(Evas_Textblock_Cursor *cur) | ||
5988 | { | ||
5989 | const Eina_Unicode *text; | ||
5990 | size_t i; | ||
5991 | #ifdef HAVE_LINEBREAK | ||
5992 | char *breaks; | ||
5993 | #endif | ||
5994 | |||
5995 | if (!cur) return EINA_FALSE; | ||
5996 | if (!cur->node) return EINA_FALSE; | ||
5997 | |||
5998 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
5999 | |||
6000 | #ifdef HAVE_LINEBREAK | ||
6001 | { | ||
6002 | const char *lang = ""; /* FIXME: get lang */ | ||
6003 | size_t len = eina_ustrbuf_length_get(cur->node->unicode); | ||
6004 | breaks = malloc(len); | ||
6005 | set_wordbreaks_utf32((const utf32_t *) text, len, lang, breaks); | ||
6006 | } | ||
6007 | #endif | ||
6008 | |||
6009 | i = cur->pos; | ||
6010 | |||
6011 | /* Skip the first one. This ensures we don't point to the nul, and also | ||
6012 | * we just don't care about it anyway. */ | ||
6013 | if (i > 0) i--; | ||
6014 | |||
6015 | for ( ; i > 0 ; i--) | ||
6016 | { | ||
6017 | if (BREAK_AFTER(i)) | ||
6018 | { | ||
6019 | /* Advance to the current char */ | ||
6020 | i++; | ||
6021 | break; | ||
6022 | } | ||
6023 | } | ||
6024 | |||
6025 | cur->pos = i; | ||
6026 | |||
6027 | #ifdef HAVE_LINEBREAK | ||
6028 | free(breaks); | ||
6029 | #endif | ||
6030 | return EINA_TRUE; | ||
6031 | } | ||
6032 | |||
6033 | EAPI Eina_Bool | ||
6034 | evas_textblock_cursor_word_end(Evas_Textblock_Cursor *cur) | ||
6035 | { | ||
6036 | const Eina_Unicode *text; | ||
6037 | size_t i; | ||
6038 | #ifdef HAVE_LINEBREAK | ||
6039 | char *breaks; | ||
6040 | #endif | ||
6041 | |||
6042 | if (!cur) return EINA_FALSE; | ||
6043 | if (!cur->node) return EINA_FALSE; | ||
6044 | |||
6045 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
6046 | |||
6047 | #ifdef HAVE_LINEBREAK | ||
6048 | { | ||
6049 | const char *lang = ""; /* FIXME: get lang */ | ||
6050 | size_t len = eina_ustrbuf_length_get(cur->node->unicode); | ||
6051 | breaks = malloc(len); | ||
6052 | set_wordbreaks_utf32((const utf32_t *) text, len, lang, breaks); | ||
6053 | } | ||
6054 | #endif | ||
6055 | |||
6056 | i = cur->pos; | ||
6057 | |||
6058 | for ( ; text[i] ; i++) | ||
6059 | { | ||
6060 | if (BREAK_AFTER(i)) | ||
6061 | { | ||
6062 | /* This is the one to break after. */ | ||
6063 | break; | ||
6064 | } | ||
6065 | } | ||
6066 | |||
6067 | cur->pos = i; | ||
6068 | |||
6069 | #ifdef HAVE_LINEBREAK | ||
6070 | free(breaks); | ||
6071 | #endif | ||
6072 | return EINA_TRUE;; | ||
6073 | } | ||
6074 | |||
5711 | EAPI Eina_Bool | 6075 | EAPI Eina_Bool |
5712 | evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) | 6076 | evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) |
5713 | { | 6077 | { |
@@ -5887,10 +6251,9 @@ _evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode, | |||
5887 | fnode->anchor = ANCHOR_NONE; | 6251 | fnode->anchor = ANCHOR_NONE; |
5888 | if (!s) return; | 6252 | if (!s) return; |
5889 | 6253 | ||
5890 | if (s[0] == '+' || s[0] == '-') | 6254 | if (!fnode->own_closer) |
5891 | { | 6255 | { |
5892 | is_opener = (s[0] == '+'); | 6256 | is_opener = fnode->opener; |
5893 | s++; | ||
5894 | fnode->format_change = EINA_TRUE; | 6257 | fnode->format_change = EINA_TRUE; |
5895 | } | 6258 | } |
5896 | 6259 | ||
@@ -5902,6 +6265,8 @@ _evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode, | |||
5902 | * closing */ | 6265 | * closing */ |
5903 | if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) || | 6266 | if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) || |
5904 | (!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) || | 6267 | (!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) || |
6268 | (!strncmp(item, "br", itlen) && (itlen >= 2)) || | ||
6269 | (!strncmp(item, "tab", itlen) && (itlen >= 3)) || | ||
5905 | (!strncmp(item, "ps", itlen) && (itlen >= 2)) || | 6270 | (!strncmp(item, "ps", itlen) && (itlen >= 2)) || |
5906 | (!strncmp(item, "item", itlen) && (itlen >= 4) && is_opener)) | 6271 | (!strncmp(item, "item", itlen) && (itlen >= 4) && is_opener)) |
5907 | { | 6272 | { |
@@ -5986,19 +6351,17 @@ _evas_textblock_node_format_remove_matching(Evas_Object_Textblock *o, | |||
5986 | } | 6351 | } |
5987 | 6352 | ||
5988 | 6353 | ||
5989 | if (fstr && (*fstr == '+')) | 6354 | if (fmt->opener && !fmt->own_closer) |
5990 | { | 6355 | { |
5991 | formats = eina_list_prepend(formats, fmt); | 6356 | formats = eina_list_prepend(formats, fmt); |
5992 | } | 6357 | } |
5993 | else if (fstr && (*fstr == '-')) | 6358 | else if (fstr && !fmt->opener) |
5994 | { | 6359 | { |
5995 | Evas_Object_Textblock_Node_Format *fnode; | 6360 | Evas_Object_Textblock_Node_Format *fnode; |
5996 | size_t fstr_len; | 6361 | size_t fstr_len; |
5997 | /* Skip the '-' */ | ||
5998 | fstr++; | ||
5999 | fstr_len = strlen(fstr); | 6362 | fstr_len = strlen(fstr); |
6000 | /* Generic popper, just pop */ | 6363 | /* Generic popper, just pop (if there's anything to pop). */ |
6001 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | 6364 | if (formats && (((fstr[0] == ' ') && !fstr[1]) || !fstr[0])) |
6002 | { | 6365 | { |
6003 | fnode = eina_list_data_get(formats); | 6366 | fnode = eina_list_data_get(formats); |
6004 | formats = eina_list_remove_list(formats, formats); | 6367 | formats = eina_list_remove_list(formats, formats); |
@@ -6855,6 +7218,7 @@ _evas_textblock_node_format_new(Evas_Object_Textblock *o, const char *_format) | |||
6855 | { | 7218 | { |
6856 | Evas_Object_Textblock_Node_Format *n; | 7219 | Evas_Object_Textblock_Node_Format *n; |
6857 | const char *format = _format; | 7220 | const char *format = _format; |
7221 | const char *pre_stripped_format = NULL; | ||
6858 | 7222 | ||
6859 | n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format)); | 7223 | n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format)); |
6860 | /* Create orig_format and format */ | 7224 | /* Create orig_format and format */ |
@@ -6866,62 +7230,80 @@ _evas_textblock_node_format_new(Evas_Object_Textblock *o, const char *_format) | |||
6866 | 7230 | ||
6867 | format++; /* Advance after '<' */ | 7231 | format++; /* Advance after '<' */ |
6868 | format_len = strlen(format); | 7232 | format_len = strlen(format); |
6869 | if (format[format_len - 1] == '>') | 7233 | if ((format_len > 0) && format[format_len - 1] == '>') |
6870 | format_len--; /* We don't care about '>' */ | 7234 | { |
7235 | format_len--; /* We don't care about '>' */ | ||
7236 | /* Check if it closes itself. Skip the </> case. */ | ||
7237 | if ((format_len > 1) && format[format_len - 1] == '/') | ||
7238 | { | ||
7239 | format_len--; /* We don't care about '/' */ | ||
7240 | n->own_closer = EINA_TRUE; | ||
7241 | } | ||
7242 | } | ||
6871 | 7243 | ||
6872 | match = _style_match_tag(o->style, format, format_len, &replace_len); | 7244 | match = _style_match_tag(o->style, format, format_len, &replace_len); |
6873 | if (match) | 7245 | if (match) |
6874 | { | 7246 | { |
6875 | if ((match[0] == '+') || (match[0] == '-')) | 7247 | if (match[0] != '-') |
6876 | { | ||
6877 | char *norm_format; | ||
6878 | norm_format = malloc(format_len + 2 + 1); | ||
6879 | memcpy(norm_format, match, 2); | ||
6880 | memcpy(norm_format + 2, format, format_len); | ||
6881 | norm_format[format_len + 2] = '\0'; | ||
6882 | n->orig_format = | ||
6883 | eina_stringshare_add_length(norm_format, format_len + 2); | ||
6884 | free(norm_format); | ||
6885 | } | ||
6886 | else | ||
6887 | { | 7248 | { |
6888 | n->orig_format = | 7249 | n->opener = EINA_TRUE; |
6889 | eina_stringshare_add_length(format, format_len); | 7250 | if (match[0] != '+') |
7251 | { | ||
7252 | n->own_closer = EINA_TRUE; | ||
7253 | } | ||
6890 | } | 7254 | } |
6891 | n->format = eina_stringshare_add(match); | 7255 | |
7256 | pre_stripped_format = match; | ||
6892 | } | 7257 | } |
6893 | else | 7258 | else |
6894 | { | 7259 | { |
6895 | char *norm_format; | 7260 | if (format[0] == '/') |
6896 | |||
6897 | norm_format = malloc(format_len + 2 + 1); | ||
6898 | if (norm_format) | ||
6899 | { | 7261 | { |
6900 | if (format[0] == '/') | 7262 | format++; |
6901 | { | 7263 | format_len--; |
6902 | memcpy(norm_format, "- ", 2); | 7264 | } |
6903 | memcpy(norm_format + 2, format + 1, format_len - 1); | 7265 | else |
6904 | norm_format[format_len + 2 - 1] = '\0'; | 7266 | { |
6905 | } | 7267 | n->opener = EINA_TRUE; |
6906 | else | ||
6907 | { | ||
6908 | memcpy(norm_format, "+ ", 2); | ||
6909 | memcpy(norm_format + 2, format, format_len); | ||
6910 | norm_format[format_len + 2] = '\0'; | ||
6911 | } | ||
6912 | n->orig_format = eina_stringshare_add(norm_format); | ||
6913 | free(norm_format); | ||
6914 | } | 7268 | } |
6915 | n->format = eina_stringshare_ref(n->orig_format); | ||
6916 | } | 7269 | } |
7270 | |||
7271 | n->orig_format = eina_stringshare_add_length(format, format_len); | ||
7272 | |||
7273 | if (!pre_stripped_format) | ||
7274 | pre_stripped_format = n->orig_format; | ||
6917 | } | 7275 | } |
6918 | /* Just use as is, it's a special format. */ | 7276 | /* Just use as is, it's a special format. */ |
6919 | else | 7277 | else |
6920 | { | 7278 | { |
6921 | n->orig_format = eina_stringshare_add(format); | 7279 | const char *tmp = format; |
6922 | n->format = eina_stringshare_ref(n->orig_format); | 7280 | if (format[0] != '-') |
7281 | { | ||
7282 | n->opener = EINA_TRUE; | ||
7283 | if (format[0] != '+') | ||
7284 | { | ||
7285 | n->own_closer = EINA_TRUE; | ||
7286 | } | ||
7287 | } | ||
7288 | if ((*tmp == '+') || (*tmp == '-')) | ||
7289 | { | ||
7290 | tmp++; | ||
7291 | while (*tmp == ' ') tmp++; | ||
7292 | } | ||
7293 | n->orig_format = eina_stringshare_add(tmp); | ||
7294 | pre_stripped_format = n->orig_format; | ||
6923 | } | 7295 | } |
6924 | 7296 | ||
7297 | /* Strip format */ | ||
7298 | { | ||
7299 | const char *tmp = pre_stripped_format; | ||
7300 | if ((*tmp == '+') || (*tmp == '-')) | ||
7301 | { | ||
7302 | tmp++; | ||
7303 | while (*tmp == ' ') tmp++; | ||
7304 | } | ||
7305 | n->format = eina_stringshare_add(tmp); | ||
7306 | } | ||
6925 | format = n->format; | 7307 | format = n->format; |
6926 | 7308 | ||
6927 | _evas_textblock_format_is_visible(n, format); | 7309 | _evas_textblock_format_is_visible(n, format); |
@@ -7051,11 +7433,11 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form | |||
7051 | if (_IS_PARAGRAPH_SEPARATOR(o, format)) | 7433 | if (_IS_PARAGRAPH_SEPARATOR(o, format)) |
7052 | insert_char = _PARAGRAPH_SEPARATOR; | 7434 | insert_char = _PARAGRAPH_SEPARATOR; |
7053 | else if (_IS_LINE_SEPARATOR(format)) | 7435 | else if (_IS_LINE_SEPARATOR(format)) |
7054 | insert_char = '\n'; | 7436 | insert_char = _NEWLINE; |
7055 | else if (_IS_TAB(format)) | 7437 | else if (_IS_TAB(format)) |
7056 | insert_char = '\t'; | 7438 | insert_char = _TAB; |
7057 | else | 7439 | else |
7058 | insert_char = EVAS_TEXTBLOCK_REPLACEMENT_CHAR; | 7440 | insert_char = _REPLACEMENT_CHAR; |
7059 | 7441 | ||
7060 | eina_ustrbuf_insert_char(cur->node->unicode, insert_char, cur->pos); | 7442 | eina_ustrbuf_insert_char(cur->node->unicode, insert_char, cur->pos); |
7061 | 7443 | ||
@@ -7142,7 +7524,7 @@ evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) | |||
7142 | should_merge = EINA_TRUE; | 7524 | should_merge = EINA_TRUE; |
7143 | } | 7525 | } |
7144 | /* If a singnular, mark as invisible, so we'll delete it. */ | 7526 | /* If a singnular, mark as invisible, so we'll delete it. */ |
7145 | if (!format || ((*format != '+') && (*format != '-'))) | 7527 | if (!format || last_fmt->own_closer) |
7146 | { | 7528 | { |
7147 | last_fmt->visible = EINA_FALSE; | 7529 | last_fmt->visible = EINA_FALSE; |
7148 | } | 7530 | } |
@@ -7271,60 +7653,40 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C | |||
7271 | EAPI char * | 7653 | EAPI char * |
7272 | evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) | 7654 | evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) |
7273 | { | 7655 | { |
7274 | const Eina_Unicode *ustr; | ||
7275 | Eina_Unicode buf[2]; | ||
7276 | char *s; | ||
7277 | if (!cur || !cur->node) return NULL; | 7656 | if (!cur || !cur->node) return NULL; |
7278 | if (evas_textblock_cursor_format_is_visible_get(cur)) | 7657 | if (evas_textblock_cursor_format_is_visible_get(cur)) |
7279 | { | 7658 | { |
7280 | size_t len; | 7659 | Eina_Strbuf *buf; |
7281 | const char *fstr; | 7660 | Evas_Object_Textblock_Node_Format *fnode; |
7282 | char *ret; | 7661 | char *ret; |
7283 | int pop = 0; | 7662 | fnode = _evas_textblock_node_visible_at_pos_get( |
7284 | fstr = evas_textblock_node_format_text_get( | 7663 | evas_textblock_cursor_format_get(cur)); |
7285 | _evas_textblock_node_visible_at_pos_get( | ||
7286 | evas_textblock_cursor_format_get(cur))); | ||
7287 | |||
7288 | if (!fstr) | ||
7289 | return NULL; | ||
7290 | 7664 | ||
7291 | if (*fstr == '-') pop = 1; | 7665 | buf = eina_strbuf_new(); |
7292 | while ((*fstr == ' ') || (*fstr == '+') || (*fstr == '-')) fstr++; | 7666 | _markup_get_format_append(buf, fnode); |
7293 | len = strlen(fstr); | 7667 | ret = eina_strbuf_string_steal(buf); |
7294 | 7668 | eina_strbuf_free(buf); | |
7295 | { | ||
7296 | char *tmp; | ||
7297 | if (pop) | ||
7298 | { | ||
7299 | ret = tmp = malloc(len + 3 + 1); /* </> and the null */ | ||
7300 | memcpy(tmp, "</", 2); | ||
7301 | tmp += 2; | ||
7302 | } | ||
7303 | else | ||
7304 | { | ||
7305 | ret = tmp = malloc(len + 2 + 1); /* <> and the null */ | ||
7306 | *tmp = '<'; | ||
7307 | tmp++; | ||
7308 | } | ||
7309 | memcpy(tmp, fstr, len); | ||
7310 | memcpy(tmp + len, ">", 2); /* Including the null */ | ||
7311 | } | ||
7312 | 7669 | ||
7313 | return ret; | 7670 | return ret; |
7314 | } | 7671 | } |
7672 | else | ||
7673 | { | ||
7674 | const Eina_Unicode *ustr; | ||
7675 | Eina_Unicode buf[2]; | ||
7676 | char *s; | ||
7315 | 7677 | ||
7316 | ustr = eina_ustrbuf_string_get(cur->node->unicode); | 7678 | ustr = eina_ustrbuf_string_get(cur->node->unicode); |
7317 | buf[0] = ustr[cur->pos]; | 7679 | buf[0] = ustr[cur->pos]; |
7318 | buf[1] = 0; | 7680 | buf[1] = 0; |
7319 | s = eina_unicode_unicode_to_utf8(buf, NULL); | 7681 | s = eina_unicode_unicode_to_utf8(buf, NULL); |
7320 | 7682 | ||
7321 | return s; | 7683 | return s; |
7684 | } | ||
7322 | } | 7685 | } |
7323 | 7686 | ||
7324 | static char * | 7687 | static char * |
7325 | _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2) | 7688 | _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2) |
7326 | { | 7689 | { |
7327 | Evas_Object_Textblock *o; | ||
7328 | Evas_Object_Textblock_Node_Text *tnode; | 7690 | Evas_Object_Textblock_Node_Text *tnode; |
7329 | Eina_Strbuf *buf; | 7691 | Eina_Strbuf *buf; |
7330 | Evas_Textblock_Cursor *cur2; | 7692 | Evas_Textblock_Cursor *cur2; |
@@ -7333,7 +7695,6 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, | |||
7333 | if (!cur1 || !cur1->node) return NULL; | 7695 | if (!cur1 || !cur1->node) return NULL; |
7334 | if (!_cur2 || !_cur2->node) return NULL; | 7696 | if (!_cur2 || !_cur2->node) return NULL; |
7335 | if (cur1->obj != _cur2->obj) return NULL; | 7697 | if (cur1->obj != _cur2->obj) return NULL; |
7336 | o = (Evas_Object_Textblock *)(cur1->obj->object_data); | ||
7337 | if (evas_textblock_cursor_compare(cur1, _cur2) > 0) | 7698 | if (evas_textblock_cursor_compare(cur1, _cur2) > 0) |
7338 | { | 7699 | { |
7339 | const Evas_Textblock_Cursor *tc; | 7700 | const Evas_Textblock_Cursor *tc; |
@@ -7401,7 +7762,7 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, | |||
7401 | tmp_ch = text[off]; | 7762 | tmp_ch = text[off]; |
7402 | text[off] = 0; /* Null terminate the part of the string */ | 7763 | text[off] = 0; /* Null terminate the part of the string */ |
7403 | _markup_get_text_append(buf, text); | 7764 | _markup_get_text_append(buf, text); |
7404 | _markup_get_format_append(o, buf, fnode); | 7765 | _markup_get_format_append(buf, fnode); |
7405 | text[off] = tmp_ch; /* Restore the char */ | 7766 | text[off] = tmp_ch; /* Restore the char */ |
7406 | text += off; | 7767 | text += off; |
7407 | if (fnode->visible) | 7768 | if (fnode->visible) |
@@ -7623,8 +7984,27 @@ evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) | |||
7623 | EAPI const char * | 7984 | EAPI const char * |
7624 | evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt) | 7985 | evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt) |
7625 | { | 7986 | { |
7987 | static char *ret = NULL; | ||
7988 | char *tmp; | ||
7989 | |||
7626 | if (!fmt) return NULL; | 7990 | if (!fmt) return NULL; |
7627 | return fmt->orig_format; | 7991 | |
7992 | if (ret) free(ret); | ||
7993 | ret = malloc(strlen(fmt->orig_format) + 2 + 1); | ||
7994 | tmp = ret; | ||
7995 | |||
7996 | if (fmt->opener && !fmt->own_closer) | ||
7997 | { | ||
7998 | *(tmp++) = '+'; | ||
7999 | *(tmp++) = ' '; | ||
8000 | } | ||
8001 | else if (!fmt->opener) | ||
8002 | { | ||
8003 | *(tmp++) = '-'; | ||
8004 | *(tmp++) = ' '; | ||
8005 | } | ||
8006 | strcpy(tmp, fmt->orig_format); | ||
8007 | return ret; | ||
7628 | } | 8008 | } |
7629 | 8009 | ||
7630 | EAPI void | 8010 | EAPI void |
@@ -7673,7 +8053,9 @@ evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord | |||
7673 | * the position of the previous */ | 8053 | * the position of the previous */ |
7674 | if ((cur->pos > 0) && !_evas_textblock_cursor_is_at_the_end(cur)) | 8054 | if ((cur->pos > 0) && !_evas_textblock_cursor_is_at_the_end(cur)) |
7675 | { | 8055 | { |
8056 | #ifdef BIDI_SUPPORT | ||
7676 | Eina_Bool before_char = EINA_FALSE; | 8057 | Eina_Bool before_char = EINA_FALSE; |
8058 | #endif | ||
7677 | cur2.obj = cur->obj; | 8059 | cur2.obj = cur->obj; |
7678 | evas_textblock_cursor_copy(cur, &cur2); | 8060 | evas_textblock_cursor_copy(cur, &cur2); |
7679 | evas_textblock_cursor_char_prev(&cur2); | 8061 | evas_textblock_cursor_char_prev(&cur2); |
@@ -7683,12 +8065,16 @@ evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord | |||
7683 | if (!fmt || !_IS_LINE_SEPARATOR(fmt->format)) | 8065 | if (!fmt || !_IS_LINE_SEPARATOR(fmt->format)) |
7684 | { | 8066 | { |
7685 | dir_cur = &cur2; | 8067 | dir_cur = &cur2; |
8068 | #ifdef BIDI_SUPPORT | ||
7686 | before_char = EINA_FALSE; | 8069 | before_char = EINA_FALSE; |
8070 | #endif | ||
7687 | } | 8071 | } |
8072 | #ifdef BIDI_SUPPORT | ||
7688 | else | 8073 | else |
7689 | { | 8074 | { |
7690 | before_char = EINA_TRUE; | 8075 | before_char = EINA_TRUE; |
7691 | } | 8076 | } |
8077 | #endif | ||
7692 | ret = evas_textblock_cursor_pen_geometry_get( | 8078 | ret = evas_textblock_cursor_pen_geometry_get( |
7693 | dir_cur, &x, &y, &w, &h); | 8079 | dir_cur, &x, &y, &w, &h); |
7694 | #ifdef BIDI_SUPPORT | 8080 | #ifdef BIDI_SUPPORT |
@@ -8788,6 +9174,7 @@ evas_object_textblock_init(Evas_Object *obj) | |||
8788 | { | 9174 | { |
8789 | linebreak_init = EINA_TRUE; | 9175 | linebreak_init = EINA_TRUE; |
8790 | init_linebreak(); | 9176 | init_linebreak(); |
9177 | init_wordbreak(); | ||
8791 | } | 9178 | } |
8792 | #endif | 9179 | #endif |
8793 | 9180 | ||