Evas textblock: Fixed _format_append to parse tags + incomplete stuff.

Added the first step to allow <b> </b> exact matching when handling formats.
I.e making "<b>a<i>b</b>c</i>d" behave like expected.

SVN revision: 61746
This commit is contained in:
Tom Hacohen 2011-07-26 11:47:19 +00:00
parent ab5e8633df
commit 681e4bfa8c
1 changed files with 135 additions and 41 deletions

View File

@ -215,6 +215,7 @@ struct _Evas_Object_Textblock_Node_Format
{
EINA_INLIST;
const char *format;
const char *orig_format;
Evas_Object_Textblock_Node_Text *text_node;
size_t offset;
unsigned char anchor : 2;
@ -333,6 +334,7 @@ struct _Evas_Object_Textblock_Format_Item
struct _Evas_Object_Textblock_Format
{
Evas_Object_Textblock_Node_Format *fnode;
double halign;
double valign;
struct {
@ -1748,6 +1750,7 @@ struct _Ctxt
static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, Eina_List *rel);
static void _text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti);
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, Eina_Bool create_item);
/**
* @internal
* Adjust the ascent/descent of the format and context.
@ -2067,12 +2070,14 @@ _paragraphs_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
* @see _layout_format_pop()
*/
static Evas_Object_Textblock_Format *
_layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt)
_layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt,
Evas_Object_Textblock_Node_Format *fnode)
{
if (fmt)
{
fmt = _format_dup(c->obj, fmt);
c->format_stack = eina_list_prepend(c->format_stack, fmt);
fmt->fnode = fnode;
}
else
{
@ -2099,18 +2104,81 @@ _layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt)
* and set it to point to the next item instead, else return fmt.
*
* @param c the context to work on - Not NULL.
* @param fmt the format to free.
* @param format - the text of the format to free (assured to start with '-').
* @return the next format in the stack, or format if there's none.
* @see _layout_format_push()
*/
static Evas_Object_Textblock_Format *
_layout_format_pop(Ctxt *c, Evas_Object_Textblock_Format *fmt)
_layout_format_pop(Ctxt *c, const char *format)
{
Evas_Object_Textblock_Format *fmt = eina_list_data_get(c->format_stack);
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;
Eina_List *redo_nodes = NULL;
format++; /* Skip the '-' */
/* Generic pop, should just pop. */
if (((format[1] == ' ') && !format[2]) ||
!format[1])
{
_format_unref_free(c->obj, fmt);
c->format_stack =
eina_list_remove_list(c->format_stack, c->format_stack);
}
else
{
size_t len = strlen(format);
Eina_List *i, *i_next;
/* Remove only the matching format. */
EINA_LIST_FOREACH_SAFE(c->format_stack, i, i_next, fmt)
{
/* Stop when we reach the base item */
if (!i_next)
break;
c->format_stack =
eina_list_remove_list(c->format_stack, c->format_stack);
/* Make sure the ending tag matches the starting tag.
* I.e whole of the ending tag matches the start of the
* starting tag, and the starting tag's next char is either
* NULL or white. Skip the starting '+'. */
if (!strncmp(fmt->fnode->orig_format + 1, format, len) &&
(!fmt->fnode->orig_format[len + 1] ||
(fmt->fnode->orig_format[len + 1] == '=') ||
_is_white(fmt->fnode->orig_format[len + 1])))
{
_format_unref_free(c->obj, fmt);
break;
}
else
{
redo_nodes = eina_list_prepend(redo_nodes, fmt->fnode);
_format_unref_free(c->obj, fmt);
}
}
}
/* Redo all the nodes needed to be redone */
{
Evas_Object_Textblock_Node_Format *fnode;
Eina_List *i, *i_next;
EINA_LIST_FOREACH_SAFE(redo_nodes, i, i_next, fnode)
{
/* FIXME: Actually do something with the new acquired padding,
* the can be different and affect our padding! */
Evas_Coord style_pad_l, style_pad_r, style_pad_t, style_pad_b;
redo_nodes = eina_list_remove_list(redo_nodes, i);
fmt = eina_list_data_get(c->format_stack);
_layout_do_format(c->obj, c, &fmt, fnode,
&style_pad_l, &style_pad_r,
&style_pad_t, &style_pad_b, EINA_FALSE);
}
}
fmt = eina_list_data_get(c->format_stack);
}
return fmt;
}
@ -3034,7 +3102,7 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c,
fi->parent.h = h;
}
/* Not sure if it's the best handling, but will do it for now. */
fmt = _layout_format_push(c, fmt);
fmt = _layout_format_push(c, fmt, n);
handled = 1;
}
@ -3043,13 +3111,13 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c,
Eina_Bool push_fmt = EINA_FALSE;
if (s[0] == '+')
{
fmt = _layout_format_push(c, fmt);
fmt = _layout_format_push(c, fmt, n);
s++;
push_fmt = EINA_TRUE;
}
else if (s[0] == '-')
{
fmt = _layout_format_pop(c, fmt);
fmt = _layout_format_pop(c, n->orig_format);
s++;
}
while ((item = _format_parse(&s)))
@ -4022,7 +4090,7 @@ _layout(const Evas_Object *obj, int w, int h, int *w_ret, int *h_ret)
/* setup default base style */
if ((c->o->style) && (c->o->style->default_tag))
{
c->fmt = _layout_format_push(c, NULL);
c->fmt = _layout_format_push(c, NULL, NULL);
_format_fill(c->obj, c->fmt, c->o->style->default_tag);
}
if (!c->fmt)
@ -4777,38 +4845,9 @@ evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char
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(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(cur, ttag2);
free(ttag2);
}
}
free(ttag);
evas_textblock_cursor_format_prepend(cur, ttag);
}
tag_start = tag_end = NULL;
}
@ -6702,6 +6741,7 @@ _evas_textblock_node_format_free(Evas_Object_Textblock *o,
{
if (!n) return;
eina_stringshare_del(n->format);
eina_stringshare_del(n->orig_format);
if (n->anchor == ANCHOR_ITEM)
o->anchors_item = eina_list_remove(o->anchors_item, n);
else if (n->anchor == ANCHOR_A)
@ -6723,7 +6763,61 @@ _evas_textblock_node_format_new(Evas_Object_Textblock *o, const char *format)
Evas_Object_Textblock_Node_Format *n;
n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format));
n->format = eina_stringshare_add(format);
/* Create orig_format and format */
{
const char *match;
size_t format_len = strlen(format);
size_t replace_len;
match = _style_match_tag(o->style, format, format_len, &replace_len);
if (match)
{
if ((match[0] == '+') || (match[0] == '-'))
{
char *norm_format;
norm_format = malloc(format_len + 2 + 1);
memcpy(norm_format, match, 2);
memcpy(norm_format + 2, format, format_len);
norm_format[format_len + 2] = '\0';
n->orig_format =
eina_stringshare_add_length(norm_format, format_len + 2);
free(norm_format);
}
else
{
n->orig_format =
eina_stringshare_add_length(format, format_len);
}
n->format = eina_stringshare_add(match);
}
else
{
char *norm_format;
norm_format = malloc(format_len + 2 + 1);
if (norm_format)
{
if (format[0] == '/')
{
memcpy(norm_format, "- ", 2);
memcpy(norm_format + 2, format + 1, format_len - 1);
norm_format[format_len + 2 - 1] = '\0';
}
else
{
memcpy(norm_format, "+ ", 2);
memcpy(norm_format + 2, format, format_len);
norm_format[format_len + 2] = '\0';
}
n->orig_format = eina_stringshare_add(norm_format);
free(norm_format);
}
n->format = eina_stringshare_ref(n->orig_format);
}
}
format = n->format;
_evas_textblock_format_is_visible(n, format);
if (n->anchor == ANCHOR_A)
{