/* 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;
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;
+};
+
+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_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)
+#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
{
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
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 */
* @{
*/
+
+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)
Evas_Object_Textblock *o;
o = (Evas_Object_Textblock *)(obj->object_data);
- while (o->nodes)
+ while (o->text_nodes)
+ {
+ Evas_Object_Textblock_Node_Text *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 *n;
+ Evas_Object_Textblock_Node_Format *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->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);
}
}
{
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);
}
{
while (lines)
{
- 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;
+ Evas_Object_Textblock_Line *ln;
- 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);
}
}
* 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"
;
* 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;
}
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;
{
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);
}
}
{
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);
}
}
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;
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");
-}
-
-/* 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!
- */
+ 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);
+ }
+}
+
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);
_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)
{
}
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)
}
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)
}
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;
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, '=');
*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;
while ((item = _format_parse(&s)))
{
- char tmp_delim = *s;
- *s = '\0';
- if (_format_is_param(item))
- {
- const char *key = NULL, *val = NULL;
-
- _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;
+ 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(tmp, &key, &val);
+ _format_command(obj, fmt, key, val);
+ eina_stringshare_del(key);
+ eina_stringshare_del(val);
+ }
+ else
+ {
+ /* immediate - not handled here */
+ }
}
}
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;
}
-
-
-
-
-
typedef struct _Ctxt Ctxt;
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;
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)
}
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;
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;
{
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);
_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;
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);
}
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;
}
_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;
}
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
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)))
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;
}
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)
+static int
+_layout_last_item_ends_with_whitespace(Ctxt *c)
{
- 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)
-{
- Evas_Object_Textblock_Item *it;
+ Evas_Object_Textblock_Item *it;
if (!c->ln->items) return 1;
it = (Evas_Object_Textblock_Item *)(EINA_INLIST_GET(c->ln->items))->last;
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;
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;
/* 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;
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;
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;
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;
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))
- {
- // 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;
- }
- }
- }
- }
+ /*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);
- 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;
+ 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))
+ {
+ 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
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;
}
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;
+ }
+ }
}
}
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;
}
if (!ts) return;
if (ts->objects)
{
- ts->delete_me = 1;
- return;
+ ts->delete_me = 1;
+ return;
}
_style_clear(ts);
free(ts);
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);
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);
+ }
+ }
}
}
}
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);
}
/**
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);
}
/**
* 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)
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;
}
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;
}
/* 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;
static inline void
_prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
- const char *s_end)
+ const char *s_end)
{
const char *escape;
evas_textblock_cursor_text_prepend(cur, escape);
}
+
/**
* to be documented.
* @param obj to be documented.
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);
}
}
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;
-
- 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;
-
- 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++;
- }
- }
-}
+ 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;
-/**
- * to be documented.
- * @param obj to be documented.
+
+ 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_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.
* @return to be documented.
*/
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)
- {
- 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;
-
- // 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);
- }
+ EINA_INLIST_FOREACH(o->text_nodes, n)
+ {
+ Evas_Object_Textblock_Node_Format *fnode;
+ Eina_Unicode *text_base, *text;
+ int off;
+ int first_run;
+
+ 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.
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;
}
}
/**
+ * Returns true if the cursor points to a format.
+ * to be documented.
+ * @param cur to be documented.
+ * @return Returns no value.
+ */
+EAPI Eina_Bool
+evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur)
+{
+ 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_first(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->nodes;
+ cur->node = o->text_nodes;
cur->pos = 0;
- cur->eol = 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_node_last(Evas_Textblock_Cursor *cur)
+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)
- {
- cur->node = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(cur->node))->prev);
- evas_textblock_cursor_char_last(cur);
- return EINA_TRUE;
+ /* 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)
+ {
+ 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_char_next(Evas_Textblock_Cursor *cur)
+evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur)
{
- int index, ch;
+ Evas_Object_Textblock_Node_Format *node;
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 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);
- if (cur->node->type == NODE_TEXT)
+ 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_Line *ln = NULL;
- Evas_Object_Textblock_Item *it = NULL;
- int pos;
+ 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;
+}
- _find_layout_item_line_match(cur->obj, cur->node, cur->pos, cur->eol, &ln, &it);
- if (it)
+/**
+ * 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)
{
- pos = cur->pos - it->source_pos;
- if (pos <= 0) index -= pos;
+ cur->pos = _evas_textblock_node_format_pos_get(node);
+
+ return EINA_TRUE;
}
- else
- printf("TB: 'it' not found\n");
}
+ /* 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);
- 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;
+ return EINA_TRUE;
+ }
+ }
+ return EINA_FALSE;
}
/**
+ * Advances 1 char
* to be documented.
* @param cur to be documented.
* @return to be documented.
*/
EAPI Eina_Bool
-evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
+evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
{
int index;
- int at_end_of_line = 0;
- int at_start_of_line = 0;
+ 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 (index == 0) return EINA_FALSE;
-
- // XXX: FIXME: determine at_end_of_line and at_start_of_line
- if (cur->node->type == NODE_TEXT)
+ index = cur->pos;
+ 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) 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;
- }
+ cur->pos = index;
+ return EINA_TRUE;
+ }
+ else
+ {
+ return EINA_FALSE;
}
}
+}
+
+/**
+ * Goes back one char (only works on text nodes).
+ * to be documented.
+ * @param cur to be documented.
+ * @return to be documented.
+ */
+EAPI Eina_Bool
+evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
+{
+ if (!cur) return EINA_FALSE;
+ if (!cur->node) return EINA_FALSE;
- if ((cur->eol) && (at_end_of_line))
+ if (cur->pos != 0)
{
- 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;
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))
}
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;
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);
}
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.
}
/**
+ * Set the cursor pos.
* to be documented.
* @param cur to be documented.
* @param pos to be documented.
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.
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.
{
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);)
}
/**
+ * Make cur_dest point to the same place as cur.
* to be documented.
* @param cur to be documented.
* @param cur_dest to be documented.
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))
- {
- 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)
+ 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)
+ {
+ 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))
+ {
+ 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);
+ }
+ }
+ else
{
- cur->pos = index;
+ n->format_node = fnode;
}
- }
- if (cur->pos >= (eina_ustrbuf_length_get(n->data.text.unicode) - 1))
- {
- eina_ustrbuf_append(n->data.text.unicode, text);
+
+ /* 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;
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;
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))
- {
- 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 (n)
{
- 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))
+ {
+ fnode = _evas_textblock_cursor_node_format_before_pos_get(cur);
+ }
+ else
{
- eina_ustrbuf_append(n->data.text.unicode, text);
+ fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
+ fnode = _evas_textblock_node_format_last_at_off(fnode);
+ }
+ /* 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
+ {
+ fnode = NULL;
+ }
}
else
{
- eina_ustrbuf_insert(n->data.text.unicode, text, cur->pos);
+ fnode = n->format_node;
}
- cur->pos += eina_unicode_strlen(text);
}
- o->formatted.valid = 0;
- o->native.valid = 0;
- o->changed = 1;
- if (o->markup_text)
+ else
{
- free(o->markup_text);
- o->markup_text = NULL;
+ 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;
}
- _nodes_adjacent_merge(cur->obj, n);
- evas_object_change(cur->obj);
+
+ 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 format to be documented.
- * @return Returns no value.
+ * @param text to be documented.
+ * @return Returns the length of _text
*/
-EAPI void
-evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
+EAPI size_t
+evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text)
{
- Evas_Object_Textblock *o;
- Evas_Object_Textblock_Node *n, *nc, *n2;
+ 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);
+}
- 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;
+static Evas_Object_Textblock_Node_Format *
+_evas_textblock_node_format_new(const char *format)
+{
+ Evas_Object_Textblock_Node_Format *n;
- 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);
-}
+ 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 no value.
+ * @return Returns true if visible
*/
-EAPI void
-evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format)
+EAPI Eina_Bool
+evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
{
Evas_Object_Textblock *o;
- Evas_Object_Textblock_Node *n, *nc, *n2;
+ Evas_Object_Textblock_Node_Format *n;
+ Eina_Bool is_visible;
- if (!cur) return;
- if ((!format) || (format[0] == 0)) return;
+ if (!cur) return EINA_FALSE;
+ if ((!format) || (format[0] == 0)) return EINA_FALSE;
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)
+ /* We should always have at least one text node */
+ if (!o->text_nodes)
{
- 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;
+ evas_textblock_cursor_text_prepend(cur, "");
}
- 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);
- 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)
+ n = _evas_textblock_node_format_new(format);
+ is_visible = n->visible;
+ if (!cur->node)
{
- 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;
+ 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
{
- n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->prev);
- cur->node = n2;
- cur->pos = 0;
- evas_textblock_cursor_char_last(cur);
- }
+ 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)
- {
- 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 (cur->node == o->cursor->node)
{
- 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 (_IS_PARAGRAPH_SEPARATOR(format))
+ {
+ _evas_textblock_cursor_break_paragraph(cur, n);
+ }
- if (n2) _nodes_adjacent_merge(cur->obj, n2);
+ _evas_textblock_changed(o, cur->obj);
- o->formatted.valid = 0;
- o->native.valid = 0;
- o->changed = 1;
- if (o->markup_text)
+ 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)
{
- free(o->markup_text);
- o->markup_text = NULL;
+ /* Advance after the replacement char */
+ evas_textblock_cursor_char_next(cur);
}
- evas_object_change(cur->obj);
+
+ return is_visible;
}
+
/**
* to be documented.
* @param cur to be documented.
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_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));
+ }
+ }
+ 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)
{
- evas_textblock_cursor_node_delete(cur);
- return;
+ _evas_textblock_cursor_nodes_merge(cur);
}
- if (cur->pos == eina_ustrbuf_length_get(n->data.text.unicode))
+
+ if (cur->pos == eina_ustrbuf_length_get(n->unicode))
{
- n2 = (Evas_Object_Textblock_Node *)((EINA_INLIST_GET(n))->next);
+ 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);
- }
}
{
}
}
}
-
- o->formatted.valid = 0;
- o->native.valid = 0;
- o->changed = 1;
- if (o->markup_text)
+
+ _evas_textblock_changed(o, cur->obj);
+}
+
+/**
+ * to be documented.
+ * @param cur1 to be documented.
+ * @param cur2 to be documented.
+ * @return Returns no value.
+ */
+EAPI void
+evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
+{
+ Evas_Object_Textblock *o;
+ Evas_Object_Textblock_Node_Text *n1, *n2, *n;
+ Evas_Object_Textblock_Node_Format *fnode = 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)
+ {
+ Evas_Textblock_Cursor *tc;
+
+ tc = cur1;
+ cur1 = cur2;
+ cur2 = tc;
+ }
+ n1 = cur1->node;
+ n2 = cur2->node;
+ 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)
+ {
+ _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))
+ {
+ fnode->offset -= cur2->pos - cur1->pos;
+ }
+ }
+ else
{
- free(o->markup_text);
- o->markup_text = NULL;
+ int len;
+ n = _NODE_TEXT(EINA_INLIST_GET(n1)->next);
+ /* Remove all the text nodes between */
+ while (n && (n != n2))
+ {
+ _evas_textblock_node_text_remove(o, n);
+ n = _NODE_TEXT(EINA_INLIST_GET(n)->next);
+ }
+
+ /* 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);
}
- evas_object_change(cur->obj);
+ evas_textblock_cursor_copy(cur1, cur2);
+ _evas_textblock_changed(o, cur1->obj);
}
/**
* to be documented.
* @param cur1 to be documented.
* @param cur2 to be documented.
- * @return Returns no value.
+ * @param format to be documented.
+ * @return to be documented.
*/
-EAPI void
-evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
+/* 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_Object_Textblock *o;
- Evas_Object_Textblock_Node *n1, *n2, *n, *tn;
- int chr, index;
-
- if (!cur1) return;
- if (!cur2) return;
- if (cur1->obj != cur2->obj) return;
+ 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 || !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)
{
- Evas_Textblock_Cursor *tc;
+ const Evas_Textblock_Cursor *tc;
tc = cur1;
- cur1 = cur2;
- cur2 = tc;
+ cur1 = _cur2;
+ _cur2 = tc;
}
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;
+ 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 (n1->type == NODE_TEXT)
- {
- 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);
+ text = eina_ustrbuf_string_get(n1->unicode);
+ eina_ustrbuf_append_length(buf, text, 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;
- }
+ 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);
+ }
- /* 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;
+ len = eina_ustrbuf_length_get(n1->unicode);
+ text = eina_ustrbuf_string_get(n1->unicode);
+ eina_ustrbuf_append_length(buf, text, len - cur1->pos);
- 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);
- }
- }
+ 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);
}
- 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)
+ /* return the string */
{
- free(o->markup_text);
- o->markup_text = NULL;
+ 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;
}
- evas_object_change(cur1->obj);
}
/**
* @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)
+evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur)
{
if (!cur) return NULL;
if (!cur->node) return NULL;
- if (cur->node->type == NODE_TEXT)
+ /*FIXME-tom: strip replace chars */
+ if (cur->node->utf8)
{
- if (cur->node->data.text.utf8)
- {
- free(cur->node->data.text.utf8);
- }
- 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;
+ free(cur->node->utf8);
}
- return NULL;
+ cur->node->utf8 = evas_common_encoding_unicode_to_utf8(
+ eina_ustrbuf_string_get(cur->node->unicode), NULL);
+ return cur->node->utf8;
}
/**
* @return to be documented.
*/
EAPI int
-evas_textblock_cursor_node_text_length_get(const Evas_Textblock_Cursor *cur)
+evas_textblock_cursor_paragraph_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;
+ return eina_ustrbuf_length_get(cur->node->unicode);
}
/**
* @param cur to be documented.
* @return to be documented.
*/
-EAPI const char *
-evas_textblock_cursor_node_format_get(const Evas_Textblock_Cursor *cur)
+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;
- if (cur->node->type == NODE_FORMAT)
- {
- return eina_strbuf_string_get(cur->node->data.format);
- }
- 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 Eina_Bool
-evas_textblock_cursor_node_format_is_visible_get(const Evas_Textblock_Cursor *cur)
+EAPI const char *
+evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt)
{
- 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;
+ if (!fmt) return NULL;
+ return eina_strbuf_string_get(fmt->format);
}
-
/**
* to be documented.
- * @param cur1 to be documented.
- * @param cur2 to be documented.
- * @param format to be documented.
+ * @param cur to be documented.
* @return to be documented.
*/
-EAPI char *
-evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format)
+EAPI void
+evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt)
{
- Evas_Object_Textblock *o;
- Evas_Object_Textblock_Node *n1, *n2, *n;
- Eina_Strbuf *txt;
- char *ret;
- const Eina_Unicode *s;
- int index;
-
- if (!cur1) return NULL;
- if (!cur2) return NULL;
- if (cur1->obj != cur2->obj) return NULL;
- o = (Evas_Object_Textblock *)(cur1->obj->object_data);
- if (evas_textblock_cursor_compare(cur1, cur2) > 0)
- {
- const Evas_Textblock_Cursor *tc;
-
- tc = cur1;
- 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)
- {
- 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 (!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 (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;
- }
- ret = eina_strbuf_string_steal(txt);
- eina_strbuf_free(txt);
- return ret;
+ 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.
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;
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)
{
}
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)
}
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;
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;
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;
}
}
{
it = it_break;
cur->pos = it->source_pos;
- cur->eol = 0;
+
cur->node = it->source_node;
return EINA_TRUE;
}
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));
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;
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;
-}
-
-/**
- * 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;
+ /* 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;
}
-
/* general controls */
/**
* to be documented.
_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);
}
/**
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;
}
if (o->repch) eina_stringshare_del(o->repch);
o->magic = 0;
free(o);
+ _format_command_shutdown();
}
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, \
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; \