forked from enlightenment/efl
Evas textblock: Added an rbtree index for the layout paragraphs.
This can be used with both coordinates and line numbers, this is a faster way to find layout paragraphs in the textblock which means we should now be a lot faster with big textblocks. SVN revision: 59527
This commit is contained in:
parent
3227929fcf
commit
359e67f68a
|
@ -261,6 +261,7 @@ struct _Evas_Object_Textblock_Node_Format
|
||||||
struct _Evas_Object_Textblock_Paragraph
|
struct _Evas_Object_Textblock_Paragraph
|
||||||
{
|
{
|
||||||
EINA_INLIST;
|
EINA_INLIST;
|
||||||
|
EINA_RBTREE;
|
||||||
Evas_Object_Textblock_Line *lines;
|
Evas_Object_Textblock_Line *lines;
|
||||||
Evas_Object_Textblock_Node_Text *text_node;
|
Evas_Object_Textblock_Node_Text *text_node;
|
||||||
Eina_List *logical_items;
|
Eina_List *logical_items;
|
||||||
|
@ -268,6 +269,7 @@ struct _Evas_Object_Textblock_Paragraph
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
int line_no;
|
int line_no;
|
||||||
Eina_Bool visible : 1;
|
Eina_Bool visible : 1;
|
||||||
|
Eina_Bool indexed : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _Evas_Object_Textblock_Line
|
struct _Evas_Object_Textblock_Line
|
||||||
|
@ -393,6 +395,7 @@ struct _Evas_Object_Textblock
|
||||||
Evas_Object_Textblock_Node_Text *text_nodes;
|
Evas_Object_Textblock_Node_Text *text_nodes;
|
||||||
Evas_Object_Textblock_Node_Format *format_nodes;
|
Evas_Object_Textblock_Node_Format *format_nodes;
|
||||||
Evas_Object_Textblock_Paragraph *paragraphs;
|
Evas_Object_Textblock_Paragraph *paragraphs;
|
||||||
|
Eina_Rbtree *par_index;
|
||||||
Eina_List *anchors_a;
|
Eina_List *anchors_a;
|
||||||
Eina_List *anchors_item;
|
Eina_List *anchors_item;
|
||||||
int last_w, last_h;
|
int last_w, last_h;
|
||||||
|
@ -1839,6 +1842,75 @@ _layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt)
|
||||||
_layout_format_ascent_descent_adjust(c, fmt);
|
_layout_format_ascent_descent_adjust(c, fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* par index functions */
|
||||||
|
static Eina_Rbtree_Direction
|
||||||
|
_par_index_node_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right,
|
||||||
|
void *data __UNUSED__)
|
||||||
|
{
|
||||||
|
Evas_Object_Textblock_Paragraph *lpar, *rpar;
|
||||||
|
lpar = EINA_RBTREE_CONTAINER_GET(left, Evas_Object_Textblock_Paragraph);
|
||||||
|
rpar = EINA_RBTREE_CONTAINER_GET(right, Evas_Object_Textblock_Paragraph);
|
||||||
|
/* Because they can't be equal or overlap, we don't need to compare
|
||||||
|
* anything except for the y position */
|
||||||
|
return (lpar->y < rpar->y) ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_par_index_y_key_cmp(const Eina_Rbtree *node, const void *key,
|
||||||
|
int length __UNUSED__, void *data __UNUSED__)
|
||||||
|
{
|
||||||
|
Evas_Coord y = *((const Evas_Coord *) key);
|
||||||
|
Evas_Object_Textblock_Paragraph *par;
|
||||||
|
par = EINA_RBTREE_CONTAINER_GET(node, Evas_Object_Textblock_Paragraph);
|
||||||
|
|
||||||
|
if (y < par->y)
|
||||||
|
return 1;
|
||||||
|
else if ((par->y <= y) && (y < par->y + par->h))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_par_index_line_no_key_cmp(const Eina_Rbtree *node, const void *key,
|
||||||
|
int length __UNUSED__, void *data __UNUSED__)
|
||||||
|
{
|
||||||
|
int line_no = *((const int *) key);
|
||||||
|
Evas_Object_Textblock_Paragraph *par, *npar;
|
||||||
|
par = EINA_RBTREE_CONTAINER_GET(node, Evas_Object_Textblock_Paragraph);
|
||||||
|
npar = (Evas_Object_Textblock_Paragraph *) EINA_INLIST_GET(par)->next;
|
||||||
|
|
||||||
|
if (line_no < par->line_no)
|
||||||
|
return 1;
|
||||||
|
else if ((par->line_no <= par->line_no) &&
|
||||||
|
(!npar || (line_no < npar->line_no)))
|
||||||
|
return 0;
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Evas_Object_Textblock_Paragraph *
|
||||||
|
_layout_find_paragraph_by_y(Evas_Object_Textblock *o, Evas_Coord y)
|
||||||
|
{
|
||||||
|
Eina_Rbtree *tmp = eina_rbtree_inline_lookup(o->par_index, &y, 0,
|
||||||
|
_par_index_y_key_cmp, NULL);
|
||||||
|
|
||||||
|
return (tmp) ?
|
||||||
|
EINA_RBTREE_CONTAINER_GET(tmp, Evas_Object_Textblock_Paragraph) :
|
||||||
|
NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Evas_Object_Textblock_Paragraph *
|
||||||
|
_layout_find_paragraph_by_line_no(Evas_Object_Textblock *o, int line_no)
|
||||||
|
{
|
||||||
|
Eina_Rbtree *tmp = eina_rbtree_inline_lookup(o->par_index,
|
||||||
|
&line_no, 0, _par_index_line_no_key_cmp, NULL);
|
||||||
|
|
||||||
|
return (tmp) ?
|
||||||
|
EINA_RBTREE_CONTAINER_GET(tmp, Evas_Object_Textblock_Paragraph) :
|
||||||
|
NULL;
|
||||||
|
}
|
||||||
|
/* End of rbtree index functios */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* Create a new layout paragraph.
|
* Create a new layout paragraph.
|
||||||
|
@ -1932,6 +2004,8 @@ _paragraph_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
||||||
static void
|
static void
|
||||||
_paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
_paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
||||||
{
|
{
|
||||||
|
Evas_Object_Textblock *o;
|
||||||
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
||||||
_paragraph_clear(obj, par);
|
_paragraph_clear(obj, par);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1950,6 +2024,9 @@ _paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
|
||||||
/* If we are the active par of the text node, set to NULL */
|
/* If we are the active par of the text node, set to NULL */
|
||||||
if (par->text_node && (par->text_node->par == par))
|
if (par->text_node && (par->text_node->par == par))
|
||||||
par->text_node->par = NULL;
|
par->text_node->par = NULL;
|
||||||
|
o->par_index = eina_rbtree_inline_remove(o->par_index,
|
||||||
|
EINA_RBTREE_GET(par), _par_index_node_cmp, NULL);
|
||||||
|
|
||||||
free(par);
|
free(par);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1987,6 +2064,8 @@ _paragraphs_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock *o;
|
Evas_Object_Textblock *o;
|
||||||
o = (Evas_Object_Textblock *)(obj->object_data);
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
||||||
|
o->par_index = NULL;
|
||||||
|
|
||||||
while (pars)
|
while (pars)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock_Paragraph *par;
|
Evas_Object_Textblock_Paragraph *par;
|
||||||
|
@ -3028,6 +3107,16 @@ _layout_update_par(Ctxt *c)
|
||||||
{
|
{
|
||||||
c->par->y = 0;
|
c->par->y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Insert it to the index now that we calculated it's y
|
||||||
|
* We don't need to reinsert even if y (they key) changed, because the
|
||||||
|
* order remains the same. */
|
||||||
|
if (!c->calc_only && !c->par->indexed)
|
||||||
|
{
|
||||||
|
c->o->par_index = eina_rbtree_inline_insert(c->o->par_index,
|
||||||
|
EINA_RBTREE_GET(c->par), _par_index_node_cmp, NULL);
|
||||||
|
c->par->indexed = EINA_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -1 means no wrap */
|
/* -1 means no wrap */
|
||||||
|
@ -4089,24 +4178,18 @@ _find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Text *
|
||||||
static Evas_Object_Textblock_Line *
|
static Evas_Object_Textblock_Line *
|
||||||
_find_layout_line_num(const Evas_Object *obj, int line)
|
_find_layout_line_num(const Evas_Object *obj, int line)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock_Paragraph *par, *prev_par = NULL;
|
Evas_Object_Textblock_Paragraph *par;
|
||||||
Evas_Object_Textblock_Line *ln;
|
Evas_Object_Textblock_Line *ln;
|
||||||
Evas_Object_Textblock *o;
|
Evas_Object_Textblock *o;
|
||||||
|
|
||||||
o = (Evas_Object_Textblock *)(obj->object_data);
|
o = (Evas_Object_Textblock *)(obj->object_data);
|
||||||
EINA_INLIST_FOREACH(o->paragraphs, par)
|
|
||||||
|
par = _layout_find_paragraph_by_line_no(o, line);
|
||||||
|
if (par)
|
||||||
{
|
{
|
||||||
if (prev_par && (prev_par->line_no <= line) && (line < par->line_no))
|
EINA_INLIST_FOREACH(par->lines, ln)
|
||||||
{
|
{
|
||||||
break;
|
if (par->line_no + ln->line_no == line) return ln;
|
||||||
}
|
|
||||||
prev_par = par;
|
|
||||||
}
|
|
||||||
if (prev_par)
|
|
||||||
{
|
|
||||||
EINA_INLIST_FOREACH(prev_par->lines, ln)
|
|
||||||
{
|
|
||||||
if (ln->par->line_no + ln->line_no == line) return ln;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -7384,7 +7467,7 @@ EAPI Eina_Bool
|
||||||
evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
|
evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock *o;
|
Evas_Object_Textblock *o;
|
||||||
Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
|
Evas_Object_Textblock_Paragraph *found_par;
|
||||||
Evas_Object_Textblock_Line *ln;
|
Evas_Object_Textblock_Line *ln;
|
||||||
Evas_Object_Textblock_Item *it = NULL, *it_break = NULL;
|
Evas_Object_Textblock_Item *it = NULL, *it_break = NULL;
|
||||||
|
|
||||||
|
@ -7393,15 +7476,8 @@ evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, E
|
||||||
if (!o->formatted.valid) _relayout(cur->obj);
|
if (!o->formatted.valid) _relayout(cur->obj);
|
||||||
x += o->style_pad.l;
|
x += o->style_pad.l;
|
||||||
y += o->style_pad.t;
|
y += o->style_pad.t;
|
||||||
EINA_INLIST_FOREACH(o->paragraphs, par)
|
|
||||||
{
|
found_par = _layout_find_paragraph_by_y(o, y);
|
||||||
if ((par->x <= x) && (par->x + par->w > x) &&
|
|
||||||
(par->y <= y) && (par->y + par->h > y))
|
|
||||||
{
|
|
||||||
found_par = par;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found_par)
|
if (found_par)
|
||||||
{
|
{
|
||||||
EINA_INLIST_FOREACH(found_par->lines, ln)
|
EINA_INLIST_FOREACH(found_par->lines, ln)
|
||||||
|
@ -7475,7 +7551,7 @@ EAPI int
|
||||||
evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
|
evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock *o;
|
Evas_Object_Textblock *o;
|
||||||
Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
|
Evas_Object_Textblock_Paragraph *found_par;
|
||||||
Evas_Object_Textblock_Line *ln;
|
Evas_Object_Textblock_Line *ln;
|
||||||
|
|
||||||
if (!cur) return -1;
|
if (!cur) return -1;
|
||||||
|
@ -7483,14 +7559,7 @@ evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
|
||||||
if (!o->formatted.valid) _relayout(cur->obj);
|
if (!o->formatted.valid) _relayout(cur->obj);
|
||||||
y += o->style_pad.t;
|
y += o->style_pad.t;
|
||||||
|
|
||||||
EINA_INLIST_FOREACH(o->paragraphs, par)
|
found_par = _layout_find_paragraph_by_y(o, y);
|
||||||
{
|
|
||||||
if ((par->y <= y) && (par->y + par->h > y))
|
|
||||||
{
|
|
||||||
found_par = par;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_par)
|
if (found_par)
|
||||||
{
|
{
|
||||||
|
@ -8075,7 +8144,7 @@ evas_object_textblock_free(Evas_Object *obj)
|
||||||
static void
|
static void
|
||||||
evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
|
evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
|
||||||
{
|
{
|
||||||
Evas_Object_Textblock_Paragraph *par, *start;
|
Evas_Object_Textblock_Paragraph *par, *start = NULL;
|
||||||
Evas_Object_Textblock_Line *ln;
|
Evas_Object_Textblock_Line *ln;
|
||||||
Evas_Object_Textblock *o;
|
Evas_Object_Textblock *o;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -8214,21 +8283,21 @@ evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void
|
||||||
} \
|
} \
|
||||||
while (0)
|
while (0)
|
||||||
|
|
||||||
/* Find the first paragraph and start working on that */
|
|
||||||
EINA_INLIST_FOREACH(o->paragraphs, par)
|
|
||||||
{
|
{
|
||||||
if (!par->visible) continue;
|
Evas_Coord look_for_y = 0 - (obj->cur.geometry.y + y);
|
||||||
|
|
||||||
if ((par->y + par->h) <= 0) continue;
|
|
||||||
if (clip)
|
if (clip)
|
||||||
{
|
{
|
||||||
if ((obj->cur.geometry.y + y + par->y + par->h) < (cy - 20))
|
Evas_Coord tmp_lfy = cy - (obj->cur.geometry.y + y);
|
||||||
continue;
|
if (tmp_lfy > look_for_y)
|
||||||
|
look_for_y = tmp_lfy;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = par;
|
if (look_for_y >= 0)
|
||||||
|
start = _layout_find_paragraph_by_y(o, look_for_y);
|
||||||
|
|
||||||
|
if (!start)
|
||||||
|
start = o->paragraphs;
|
||||||
|
}
|
||||||
|
|
||||||
ITEM_WALK()
|
ITEM_WALK()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue