Evas textblock: Implement format invalidation points support.

This lets us only relayout what's needed also when inserting formats.
This means inserting <b> </> for example is now as fast as inserting any
other char and doesn't cause a complete relayout.

SVN revision: 58958
This commit is contained in:
Tom Hacohen 2011-04-27 12:41:26 +00:00
parent c2425b1fac
commit 722707547a
1 changed files with 81 additions and 10 deletions

View File

@ -200,7 +200,8 @@ struct _Evas_Object_Textblock_Node_Format
Eina_Strbuf *format;
Evas_Object_Textblock_Node_Text *text_node;
size_t offset;
Eina_Bool visible;
Eina_Bool visible : 1;
Eina_Bool new : 1;
};
/**
@ -385,6 +386,7 @@ struct _Evas_Object_Textblock
unsigned char redraw : 1;
unsigned char changed : 1;
unsigned char content_changed : 1;
Eina_Bool format_changed : 1;
unsigned char have_ellipsis : 1;
Eina_Bool newline_is_ps : 1;
};
@ -3568,6 +3570,68 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_
c->calc_only = !!calc_only;
c->width_changed = (obj->cur.geometry.w != o->last_w);
/* Mark text nodes as dirty if format have changed. */
if (c->o->format_changed)
{
Evas_Object_Textblock_Node_Format *fnode = c->o->format_nodes;
Evas_Object_Textblock_Node_Text *start_n = NULL;
int balance = 0;
while (fnode)
{
if (fnode->new)
{
const char *fstr = eina_strbuf_string_get(fnode->format);
/* balance < 0 means we gave up and everything should be
* invalidated */
if (*fstr == '+')
{
balance++;
if (balance == 1)
start_n = fnode->text_node;
}
else if (*fstr == '-')
{
balance--;
if (balance == 0)
{
Evas_Object_Textblock_Node_Text *f_tnode =
fnode->text_node;
while (start_n)
{
start_n->dirty = EINA_TRUE;
if (start_n == f_tnode)
break;
start_n =
_NODE_TEXT(EINA_INLIST_GET(start_n)->next);
}
start_n = NULL;
}
}
else if (!fnode->visible)
balance = -1;
if (balance < 0)
{
/* if we don't already have a starting point, use the
* current paragraph. */
if (!start_n)
start_n = fnode->text_node;
break;
}
}
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
}
if (balance != 0)
{
while (start_n)
{
start_n->dirty = EINA_TRUE;
start_n = _NODE_TEXT(EINA_INLIST_GET(start_n)->next);
}
}
}
/* Start of logical layout creation */
/* setup default base style */
@ -3633,7 +3697,6 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_
/* Update the format stack according to the node's
* formats */
fnode = n->format_node;
start = off = 0;
while (fnode && (fnode->text_node == n))
{
_layout_do_format(obj, c, &fmt, fnode,
@ -3687,6 +3750,7 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_
{
off = 0;
}
fnode->new = EINA_FALSE;
fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
}
_layout_text_append(c, fmt, n, start, -1, o->repch);
@ -3893,6 +3957,7 @@ _relayout(const Evas_Object *obj)
o->last_h = obj->cur.geometry.h;
o->changed = 0;
o->content_changed = 0;
o->format_changed = EINA_FALSE;
o->redraw = 1;
}
@ -6138,6 +6203,7 @@ _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
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);
cur->node->dirty = EINA_TRUE;
}
else
{
@ -6373,6 +6439,7 @@ _evas_textblock_node_format_new(const char *format)
n->format = eina_strbuf_new();
eina_strbuf_append(n->format, format);
n->visible = _evas_textblock_format_is_visible(format);
n->new = EINA_TRUE;
return n;
}
@ -6486,22 +6553,25 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
eina_ustrbuf_insert_char(cur->node->unicode,
EVAS_TEXTBLOCK_REPLACEMENT_CHAR, cur->pos);
/* Mark as dirty */
cur->node->dirty = EINA_TRUE;
/* Advance all the cursors after our cursor */
_evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1);
if (_IS_PARAGRAPH_SEPARATOR(o, format))
{
_evas_textblock_cursor_break_paragraph(cur, n);
}
else
{
/* Handle visible format nodes here */
cur->node->dirty = EINA_TRUE;
n->new = EINA_FALSE;
}
}
else
{
o->format_changed = EINA_TRUE;
}
_evas_textblock_changed(o, cur->obj);
if (!is_visible)
_evas_textblock_invalidate_all(o);
else if (cur->node)
cur->node->dirty = EINA_TRUE;
return is_visible;
}
@ -7788,6 +7858,7 @@ evas_object_textblock_size_native_get(const Evas_Object *obj, Evas_Coord *w, Eva
&o->native.w, &o->native.h);
o->native.valid = 1;
o->content_changed = 0;
o->format_changed = EINA_FALSE;
}
if (w) *w = o->native.w;
if (h) *h = o->native.h;
@ -8252,7 +8323,7 @@ evas_object_textblock_render_pre(Evas_Object *obj)
/* then when this is done the object needs to figure if it changed and */
/* if so what and where and add the appropriate redraw textblocks */
o = (Evas_Object_Textblock *)(obj->object_data);
if ((o->changed) || (o->content_changed) ||
if ((o->changed) || (o->content_changed) || (o->format_changed) ||
((obj->cur.geometry.w != o->last_w) ||
(((o->valign != 0.0) || (o->have_ellipsis)) &&
(obj->cur.geometry.h != o->last_h))))