struct _Evas_Object_Textblock_Paragraph
{
EINA_INLIST;
+ EINA_RBTREE;
Evas_Object_Textblock_Line *lines;
Evas_Object_Textblock_Node_Text *text_node;
Eina_List *logical_items;
int x, y, w, h;
int line_no;
Eina_Bool visible : 1;
+ Eina_Bool indexed : 1;
};
struct _Evas_Object_Textblock_Line
Evas_Object_Textblock_Node_Text *text_nodes;
Evas_Object_Textblock_Node_Format *format_nodes;
Evas_Object_Textblock_Paragraph *paragraphs;
+ Eina_Rbtree *par_index;
Eina_List *anchors_a;
Eina_List *anchors_item;
int last_w, last_h;
_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
* Create a new layout paragraph.
static void
_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);
{
/* If we are the active par of the text node, set to NULL */
if (par->text_node && (par->text_node->par == par))
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);
}
{
Evas_Object_Textblock *o;
o = (Evas_Object_Textblock *)(obj->object_data);
+ o->par_index = NULL;
+
while (pars)
{
Evas_Object_Textblock_Paragraph *par;
{
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 */
static Evas_Object_Textblock_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 *o;
o = (Evas_Object_Textblock *)(obj->object_data);
- EINA_INLIST_FOREACH(o->paragraphs, par)
- {
- if (prev_par && (prev_par->line_no <= line) && (line < par->line_no))
- {
- break;
- }
- prev_par = par;
- }
- if (prev_par)
+
+ par = _layout_find_paragraph_by_line_no(o, line);
+ if (par)
{
- EINA_INLIST_FOREACH(prev_par->lines, ln)
+ EINA_INLIST_FOREACH(par->lines, ln)
{
- if (ln->par->line_no + ln->line_no == line) return ln;
+ if (par->line_no + ln->line_no == line) return ln;
}
}
return NULL;
evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
{
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_Item *it = NULL, *it_break = NULL;
if (!o->formatted.valid) _relayout(cur->obj);
x += o->style_pad.l;
y += o->style_pad.t;
- EINA_INLIST_FOREACH(o->paragraphs, par)
- {
- if ((par->x <= x) && (par->x + par->w > x) &&
- (par->y <= y) && (par->y + par->h > y))
- {
- found_par = par;
- break;
- }
- }
+
+ found_par = _layout_find_paragraph_by_y(o, y);
if (found_par)
{
EINA_INLIST_FOREACH(found_par->lines, ln)
evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
{
Evas_Object_Textblock *o;
- Evas_Object_Textblock_Paragraph *par, *found_par = NULL;
+ Evas_Object_Textblock_Paragraph *found_par;
Evas_Object_Textblock_Line *ln;
if (!cur) return -1;
if (!o->formatted.valid) _relayout(cur->obj);
y += o->style_pad.t;
- EINA_INLIST_FOREACH(o->paragraphs, par)
- {
- if ((par->y <= y) && (par->y + par->h > y))
- {
- found_par = par;
- break;
- }
- }
+ found_par = _layout_find_paragraph_by_y(o, y);
if (found_par)
{
static void
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 *o;
int i, j;
} \
while (0)
- /* Find the first paragraph and start working on that */
- EINA_INLIST_FOREACH(o->paragraphs, par)
{
- if (!par->visible) continue;
-
- if ((par->y + par->h) <= 0) continue;
+ Evas_Coord look_for_y = 0 - (obj->cur.geometry.y + y);
if (clip)
{
- if ((obj->cur.geometry.y + y + par->y + par->h) < (cy - 20))
- continue;
+ Evas_Coord tmp_lfy = cy - (obj->cur.geometry.y + y);
+ 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()
{