diff options
author | Daniel Hirt <hirt.danny@gmail.com> | 2017-09-04 19:16:27 +0300 |
---|---|---|
committer | Daniel Hirt <hirt.danny@gmail.com> | 2017-09-09 13:52:17 +0300 |
commit | 7fce64d46046ebe239839558b1287e2524f3c6d3 (patch) | |
tree | 48b1248ed4a40c092e1ac409b609808dc0c9bae0 | |
parent | 1d7dd42cab86e876d56375a316446f9fe225592b (diff) | |
download | efl-7fce64d46046ebe239839558b1287e2524f3c6d3.tar.gz |
Canvas text: add 'async_layout' method
This method calls for asynchronous layout operation on the textblock
object.
There is some preparation work that may be requires - it will still be
done on the mainloop (due to requirement to load fonts through evas
font cache); afterwards the rest of the visual layout is offloaded to a
thread.
The mainloop and the thread negotiate when accessing the common
resources (i.e. the text layout). There is not wait, though - the work
is deferred.
@feature
-rw-r--r-- | src/lib/evas/canvas/efl_canvas_text.eo | 43 | ||||
-rw-r--r-- | src/lib/evas/canvas/evas_object_textblock.c | 527 |
2 files changed, 425 insertions, 145 deletions
diff --git a/src/lib/evas/canvas/efl_canvas_text.eo b/src/lib/evas/canvas/efl_canvas_text.eo index c765d1a5e9..1d401cdb52 100644 --- a/src/lib/evas/canvas/efl_canvas_text.eo +++ b/src/lib/evas/canvas/efl_canvas_text.eo @@ -2,6 +2,13 @@ import efl_text_types; struct Efl.Canvas.Text.Style; [[EFL text style data structure]] +struct Efl.Canvas.Text.Async_Layout_Event_Info +{ + ret: int; + w: int; + h: int; +} + class Efl.Canvas.Text (Efl.Canvas.Object, Efl.Text, Efl.Text.Properties, Efl.Canvas.Filter.Internal, Efl.Text.Font, Efl.Text.Style, Efl.Text.Format, Efl.Text.Cursor, Efl.Text.Annotate) { @@ -252,6 +259,41 @@ Efl.Text.Font, Efl.Text.Style, Efl.Text.Format, Efl.Text.Cursor, Efl.Text.Annota @since 1.18 ]] } + @property async_enabled { + [[Enables async operations for the text layout. + + If set to $true, the object's behavior will work as it was + asynchornously doing a layout, using locks. + If set to $false, there's no locking performed, thus it is + suggested to not enable this if there isn't an intention to + request for asynchronous layout. + Default value is $false. + + Note that this can only be set on construction. + + @since 1.21 + ]] + set { + legacy: null; + } + get { + legacy: null; + } + values { + enabled: bool; [[$true if enabled, $false otherwise]] + } + } + async_layout { + [[Requests to layout the text off the mainloop. + + This will spawn a work thread to layout the text object. At the + end of the layout, it will emit the aync,layout,complete event. + + Note: a prerequisite is that the object was constructed with the + @.async_enabled flag set to $true. + ]] + legacy: null; + } } implements { Efl.Object.constructor; @@ -339,5 +381,6 @@ Efl.Text.Font, Efl.Text.Style, Efl.Text.Format, Efl.Text.Cursor, Efl.Text.Annota cursor,changed; [[Called when cursor changed]] changed; [[Called when canvas text changed ]] style_insets,changed; [[Called when the property @.style_insets changed.]] + async,layout,complete: Efl.Canvas.Text.Async_Layout_Event_Info; } } diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index 79048e848e..b01e1d4005 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -579,8 +579,10 @@ struct _Efl_Text_Annotate_Annotation /* Size of the index array */ #define TEXTBLOCK_PAR_INDEX_SIZE 10 + struct _Evas_Object_Textblock { + LK(lk); Evas_Textblock_Style *style; Eina_List *styles; Efl_Text_Cursor_Cursor *cursor; @@ -649,6 +651,8 @@ struct _Evas_Object_Textblock Eina_Bool changed_paragraph_direction : 1; Eina_Bool multiline : 1; Eina_Bool wrap_changed : 1; + Eina_Bool layout_busy : 1; + Eina_Bool async_enabled : 1; }; struct _Evas_Textblock_Selection_Iterator @@ -2872,6 +2876,9 @@ struct _Ctxt int underline_extend; int have_underline, have_underline2; double align, valign; + struct { + int l, r, t, b; + } style_pad; Textblock_Position position; Evas_Textblock_Align_Auto align_auto : 2; Eina_Bool width_changed : 1; @@ -6114,12 +6121,17 @@ _layout_split_text_because_format(const Evas_Object_Textblock_Format *fmt, /** FIXME: Document */ static void -_layout_pre(Ctxt *c, int *style_pad_l, int *style_pad_r, int *style_pad_t, - int *style_pad_b) +_layout_pre(Ctxt *c) { + int *style_pad_l, *style_pad_r, *style_pad_t, *style_pad_b; Evas_Object *eo_obj = c->obj; Efl_Canvas_Text_Data *o = c->o; + style_pad_l = &c->style_pad.l; + style_pad_r = &c->style_pad.r; + style_pad_b = &c->style_pad.b; + style_pad_t = &c->style_pad.t; + /* Mark text nodes as dirty if format have changed. */ if (o->format_changed) _format_changes_invalidate_text_nodes(c); @@ -6302,105 +6314,6 @@ _layout_pre(Ctxt *c, int *style_pad_l, int *style_pad_r, int *style_pad_t, if (o->style_pad.t > *style_pad_t) *style_pad_t = o->style_pad.t; if (o->style_pad.b > *style_pad_b) *style_pad_b = o->style_pad.b; } -} - -/** - * @internal - * Create the layout from the nodes. - * - * @param obj the evas object - NOT NULL. - * @param calc_only true if should only calc sizes false if should also create the layout.. It assumes native size is being calculated, doesn't support formatted size atm. - * @param w the object's w, -1 means no wrapping (i.e infinite size) - * @param h the object's h, -1 means inifinte size. - * @param w_ret the object's calculated w. - * @param h_ret the object's calculated h. - */ -static void -_layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) -{ - Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); - Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); - Ctxt ctxt, *c; - Evas *eo_e; - int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0; - - LYDBG("ZZ: layout %p %4ix%4i | w=%4i | last_w=%4i --- '%s'\n", eo_obj, w, h, obj->cur->geometry.w, o->last_w, o->markup_text); - /* setup context */ - c = &ctxt; - c->obj = (Evas_Object *)eo_obj; - c->o = o; - c->paragraphs = c->par = NULL; - c->format_stack = NULL; - c->fmt = NULL; - c->x = c->y = 0; - c->w = w; - c->h = h; - c->wmax = c->hmax = 0; - c->ascent = c->descent = 0; - c->maxascent = c->maxdescent = 0; - c->marginl = c->marginr = 0; - c->have_underline = 0; - c->have_underline2 = 0; - c->underline_extend = 0; - c->line_no = 0; - c->align = 0.0; - c->align_auto = EINA_TRUE; - c->ln = NULL; - c->width_changed = (obj->cur->geometry.w != o->last_w); - c->obs_infos = NULL; - c->hyphen_ti = NULL; - c->handle_obstacles = EINA_FALSE; - - /* Update all obstacles */ - if (c->o->obstacle_changed || c->width_changed) - { - _layout_obstacles_update(c); - c->handle_obstacles = EINA_TRUE; - } - - c->evas_o = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); - eo_e = evas_object_evas_get(eo_obj); - c->evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS); - - /* Start of logical layout creation */ - /* setup default base style */ - { - Eina_List *itr; - Evas_Textblock_Style *style; - Eina_Bool finalize = EINA_FALSE; - if (!c->fmt) - { - c->fmt = _layout_format_push(c, NULL, NULL); - finalize = EINA_TRUE; - } - if ((c->o->style) && (c->o->style->default_tag)) - { - _format_fill(c->obj, c->fmt, c->o->style->default_tag); - finalize = EINA_TRUE; - } - - EINA_LIST_FOREACH(c->o->styles, itr, style) - { - if ((style) && (style->default_tag)) - { - _format_fill(c->obj, c->fmt, style->default_tag); - finalize = EINA_TRUE; - } - } - - if (finalize) - _format_finalize(c->obj, c->fmt); - } - if (!c->fmt) - { - if (w_ret) *w_ret = 0; - if (h_ret) *h_ret = 0; - return; - } - - _layout_pre(c, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b); - c->paragraphs = o->paragraphs; - /* If there are no paragraphs, create the minimum needed, * if the last paragraph has no lines/text, create that as well */ if (!c->paragraphs) @@ -6418,13 +6331,16 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) ti->parent.text_pos = 0; _layout_text_add_logical_item(c, ti, NULL); } - /* End of logical layout creation */ +} +static void +_layout_visual(Ctxt *c) +{ /* Start of visual layout creation */ { Evas_Object_Textblock_Paragraph *last_vis_par = NULL; - int par_index_step = o->num_paragraphs / TEXTBLOCK_PAR_INDEX_SIZE; + int par_index_step = c->o->num_paragraphs / TEXTBLOCK_PAR_INDEX_SIZE; int par_count = 1; /* Force it to take the first one */ int par_index_pos = 0; @@ -6433,7 +6349,7 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) if (par_index_step == 0) par_index_step = 1; /* Clear all of the index */ - memset(o->par_index, 0, sizeof(o->par_index)); + memset(c->o->par_index, 0, sizeof(c->o->par_index)); EINA_INLIST_FOREACH(c->paragraphs, c->par) { @@ -6450,7 +6366,7 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) { par_count = par_index_step; - o->par_index[par_index_pos++] = c->par; + c->o->par_index[par_index_pos++] = c->par; } } @@ -6480,6 +6396,18 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) } } +} + +//#undef LKL +//#undef LKU +//#define LKL(x) printf("%s: **lock**\n", __func__); _on_lock_hook(); eina_lock_take(&(x)) +//#define LKU(x) printf("%s: **unlock**\n", __func__); eina_lock_release(&(x)) +// FWD Declaration +static void _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret); + +static void +_layout_done(Ctxt *c, Evas_Coord *w_ret, Evas_Coord *h_ret) +{ /* Clean the rest of the format stack */ while (c->format_stack) { @@ -6492,9 +6420,9 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) if (h_ret) *h_ret = c->hmax; /* Vertically align the textblock */ - if ((o->valign > 0.0) && (c->h > c->hmax)) + if ((c->o->valign > 0.0) && (c->h > c->hmax)) { - Evas_Coord adjustment = (c->h - c->hmax) * o->valign; + Evas_Coord adjustment = (c->h - c->hmax) * c->o->valign; Evas_Object_Textblock_Paragraph *par; EINA_INLIST_FOREACH(c->paragraphs, par) { @@ -6502,20 +6430,134 @@ _layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) } } - 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)) + if ((c->o->style_pad.l != c->style_pad.l) || (c->o->style_pad.r != c->style_pad.r) || + (c->o->style_pad.t != c->style_pad.t) || (c->o->style_pad.b != c->style_pad.b)) { - 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; + c->o->style_pad.l = c->style_pad.l; + c->o->style_pad.r = c->style_pad.r; + c->o->style_pad.t = c->style_pad.t; + c->o->style_pad.b = c->style_pad.b; _paragraphs_clear(c); LYDBG("ZZ: ... layout #2\n"); - _layout(eo_obj, w, h, w_ret, h_ret); - efl_event_callback_call((Eo *) eo_obj, EFL_CANVAS_TEXT_EVENT_STYLE_INSETS_CHANGED, NULL); + _layout(c->obj, c->w, c->h, w_ret, h_ret); + efl_event_callback_call(c->obj, EFL_CANVAS_TEXT_EVENT_STYLE_INSETS_CHANGED, NULL); + + c->o->obstacle_changed = EINA_FALSE; + } +} + +static Eina_Bool +_layout_setup(Ctxt *c, const Eo *eo_obj, Evas_Coord w, Evas_Coord h) +{ + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + Evas *eo_e; + /* setup context */ + c->obj = (Evas_Object *)eo_obj; + c->o = o; + c->paragraphs = c->par = NULL; + c->format_stack = NULL; + c->fmt = NULL; + c->x = c->y = 0; + c->w = w; + c->h = h; + c->wmax = c->hmax = 0; + c->ascent = c->descent = 0; + c->maxascent = c->maxdescent = 0; + c->marginl = c->marginr = 0; + c->have_underline = 0; + c->have_underline2 = 0; + c->underline_extend = 0; + c->line_no = 0; + c->align = 0.0; + c->align_auto = EINA_TRUE; + c->ln = NULL; + c->width_changed = (obj->cur->geometry.w != o->last_w); + c->obs_infos = NULL; + c->hyphen_ti = NULL; + c->handle_obstacles = EINA_FALSE; + c->w = w; + c->h = h; + c->style_pad.r = c->style_pad.l = c->style_pad.t = c->style_pad.b = 0; + + /* Update all obstacles */ + if (c->o->obstacle_changed || c->width_changed) + { + _layout_obstacles_update(c); + c->handle_obstacles = EINA_TRUE; } - c->o->obstacle_changed = EINA_FALSE; + c->evas_o = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + eo_e = evas_object_evas_get(eo_obj); + c->evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS); + + /* Start of logical layout creation */ + /* setup default base style */ + { + Eina_List *itr; + Evas_Textblock_Style *style; + Eina_Bool finalize = EINA_FALSE; + if (!c->fmt) + { + c->fmt = _layout_format_push(c, NULL, NULL); + finalize = EINA_TRUE; + } + if ((c->o->style) && (c->o->style->default_tag)) + { + _format_fill(c->obj, c->fmt, c->o->style->default_tag); + finalize = EINA_TRUE; + } + + EINA_LIST_FOREACH(c->o->styles, itr, style) + { + if ((style) && (style->default_tag)) + { + _format_fill(c->obj, c->fmt, style->default_tag); + finalize = EINA_TRUE; + } + } + + if (finalize) + _format_finalize(c->obj, c->fmt); + } + if (!c->fmt) + { + return EINA_FALSE; + } + + c->paragraphs = o->paragraphs; + + return EINA_TRUE; +} + +/** + * @internal + * Create the layout from the nodes. + * + * @param obj the evas object - NOT NULL. + * @param calc_only true if should only calc sizes false if should also create the layout.. It assumes native size is being calculated, doesn't support formatted size atm. + * @param w the object's w, -1 means no wrapping (i.e infinite size) + * @param h the object's h, -1 means inifinte size. + * @param w_ret the object's calculated w. + * @param h_ret the object's calculated h. + */ +static void +_layout(const Evas_Object *eo_obj, int w, int h, int *w_ret, int *h_ret) +{ + Ctxt ctxt, *c; + c = &ctxt; + + LYDBG("ZZ: layout %p %4ix%4i | w=%4i | last_w=%4i --- '%s'\n", eo_obj, w, h, obj->cur->geometry.w, o->last_w, o->markup_text); + + if (!_layout_setup(c, eo_obj, w, h)) + { + if (w_ret) *w_ret = 0; + if (h_ret) *h_ret = 0; + return; + } + _layout_pre(c); + _layout_visual(c); + _layout_done(c, w_ret, h_ret); } /* @@ -6559,17 +6601,41 @@ _relayout(const Evas_Object *eo_obj) * @internal * Check if the object needs a relayout, and if so, execute it. */ -static inline void -_relayout_if_needed(Evas_Object *eo_obj, const Efl_Canvas_Text_Data *o) +static Eina_Bool +_relayout_if_needed(Evas_Object *eo_obj, Efl_Canvas_Text_Data *o) { Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); - evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); - if (!o->formatted.valid) + if (o->async_enabled) { - LYDBG("ZZ: relayout\n"); - _relayout(eo_obj); + LKL(o->lk); + + evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); + if (o->formatted.valid) + { + LKU(o->lk); + return EINA_TRUE; + } + if (o->layout_busy) + { + LKU(o->lk); + return EINA_FALSE; + } + o->layout_busy = EINA_TRUE; + LKU(o->lk); + } + else + { + evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); + if (o->formatted.valid) + { + return EINA_TRUE; + } } + LYDBG("ZZ: relayout\n"); + _relayout(eo_obj); + o->layout_busy = EINA_FALSE; + return EINA_TRUE; } /** @@ -6710,6 +6776,8 @@ _efl_canvas_text_efl_object_constructor(Eo *eo_obj, Efl_Canvas_Text_Data *class_ _FMT(password) = 1; _FMT(ellipsis) = -1; + LKI(o->lk); + return eo_obj; } @@ -7947,12 +8015,12 @@ _layout_obstacles_update(Ctxt *c) } static Evas_Textblock_Obstacle * -_obstacle_find(Efl_Canvas_Text_Data *obj, Eo *eo_obs) +_obstacle_find(Efl_Canvas_Text_Data *o, Eo *eo_obs) { Evas_Textblock_Obstacle *obs; Eina_List *i; - EINA_LIST_FOREACH(obj->obstacles, i, obs) + EINA_LIST_FOREACH(o->obstacles, i, obs) { if (eo_obs == obs->eo_obs) return obs; @@ -7964,19 +8032,19 @@ void _obstacle_del_cb(void *data, const Efl_Event *event) { Eo *eo_obj = data; - Efl_Canvas_Text_Data *obj = efl_data_scope_get(eo_obj, MY_CLASS); + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); Eina_List *i; Evas_Textblock_Obstacle *obs; - EINA_LIST_FOREACH(obj->obstacles, i, obs) + EINA_LIST_FOREACH(o->obstacles, i, obs) { if (event->object == obs->eo_obs) break; } - obj->obstacles = eina_list_remove_list(obj->obstacles, i); + o->obstacles = eina_list_remove_list(o->obstacles, i); free(obs); - _evas_textblock_changed(obj, data); - obj->obstacle_changed = EINA_TRUE; + _evas_textblock_changed(o, data); + o->obstacle_changed = EINA_TRUE; } static void @@ -7993,11 +8061,11 @@ _obstacle_free(Eo *eo_obj, Evas_Textblock_Obstacle *obs) } static void -_obstacles_free(Eo *eo_obj, Efl_Canvas_Text_Data *obj) +_obstacles_free(Eo *eo_obj, Efl_Canvas_Text_Data *o) { Evas_Textblock_Obstacle *obs; - EINA_LIST_FREE(obj->obstacles, obs) + EINA_LIST_FREE(o->obstacles, obs) { _obstacle_free(eo_obj, obs); } @@ -8005,13 +8073,13 @@ _obstacles_free(Eo *eo_obj, Efl_Canvas_Text_Data *obj) EOLIAN static Eina_Bool _efl_canvas_text_obstacle_add(Eo *eo_obj, - Efl_Canvas_Text_Data *obj, Eo *eo_obs) + Efl_Canvas_Text_Data *o, Eo *eo_obs) { Evas_Textblock_Obstacle *obs; if (!efl_isa(eo_obs, EFL_CANVAS_OBJECT_CLASS)) return EINA_FALSE; - obs = _obstacle_find(obj, eo_obs); + obs = _obstacle_find(o, eo_obs); if (obs) return EINA_FALSE; obs = calloc(1, sizeof(Evas_Textblock_Obstacle)); @@ -8020,15 +8088,15 @@ _efl_canvas_text_obstacle_add(Eo *eo_obj, obs->eo_obs = eo_obs; efl_event_callback_add(eo_obs, EFL_EVENT_DEL, _obstacle_del_cb, eo_obj); - obj->obstacles = eina_list_append(obj->obstacles, obs); + o->obstacles = eina_list_append(o->obstacles, obs); _obstacle_update(obs, eo_obj); - _evas_textblock_changed(obj, eo_obj); - obj->obstacle_changed = EINA_TRUE; + _evas_textblock_changed(o, eo_obj); + o->obstacle_changed = EINA_TRUE; return EINA_TRUE; } EOLIAN static Eina_Bool -_efl_canvas_text_obstacle_del(Eo *eo_obj, Efl_Canvas_Text_Data *obj, +_efl_canvas_text_obstacle_del(Eo *eo_obj, Efl_Canvas_Text_Data *o, Eo *eo_obs EINA_UNUSED) { Evas_Textblock_Obstacle *obs; @@ -8037,7 +8105,7 @@ _efl_canvas_text_obstacle_del(Eo *eo_obj, Efl_Canvas_Text_Data *obj, if (!efl_isa(eo_obs, EFL_CANVAS_OBJECT_CLASS)) return EINA_FALSE; - EINA_LIST_FOREACH(obj->obstacles, i, obs) + EINA_LIST_FOREACH(o->obstacles, i, obs) { if (eo_obs == obs->eo_obs) { @@ -8045,10 +8113,10 @@ _efl_canvas_text_obstacle_del(Eo *eo_obj, Efl_Canvas_Text_Data *obj, } } if (!i) return EINA_FALSE; - obj->obstacles = eina_list_remove_list(obj->obstacles, i); + o->obstacles = eina_list_remove_list(o->obstacles, i); _obstacle_free(eo_obj, obs); - _evas_textblock_changed(obj, eo_obj); - obj->obstacle_changed = EINA_TRUE; + _evas_textblock_changed(o, eo_obj); + o->obstacle_changed = EINA_TRUE; return EINA_TRUE; } @@ -11233,7 +11301,7 @@ _efl_canvas_text_efl_text_cursor_cursor_geometry_get(Eo *eo_obj EINA_UNUSED, Efl Evas_Object_Protected_Data *obj = efl_data_scope_get(cur->obj, EFL_CANVAS_OBJECT_CLASS); evas_object_async_block(obj); - _relayout_if_needed(cur->obj, o); + if (!_relayout_if_needed(cur->obj, o)) return EINA_FALSE; if (ctype == EFL_TEXT_CURSOR_TYPE_UNDER) { @@ -13168,6 +13236,19 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Textblock_Item *itr; Evas_Object_Textblock_Line *ln, *cur_ln = NULL; Efl_Canvas_Text_Data *o = type_private_data; + if (o->async_enabled) + { + LKL(o->lk); + { + if (o->layout_busy) + { + LKU(o->lk); + return; + } + o->layout_busy = EINA_TRUE; + } + LKU(o->lk); + } Eina_List *shadows = NULL; Eina_List *glows = NULL; Eina_List *outlines = NULL; @@ -13197,7 +13278,10 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, /* If there are no paragraphs and thus there are no lines, * there's nothing left to do. */ - if (!o->paragraphs) return; + if (!o->paragraphs) + { + goto end; + } /* render object to surface with context, and offxet by x,y */ ENFN->context_multiplier_unset(engine, context); @@ -13859,6 +13943,8 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED, } ITEM_WALK_END(); ENFN->context_multiplier_unset(engine, context); +end: + o->layout_busy = EINA_FALSE; } EOLIAN static void @@ -14160,11 +14246,19 @@ evas_object_textblock_render_pre(Evas_Object *eo_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 */ - evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); + //evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); + if (!_relayout_if_needed(eo_obj, o)) + { + o->redraw = 0; + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, + eo_obj, obj); + is_v = evas_object_is_visible(eo_obj, obj); + was_v = evas_object_was_visible(eo_obj, obj); + goto done; + } if (o->changed) { LYDBG("ZZ: relayout 16\n"); - _relayout(eo_obj); o->redraw = 0; evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); @@ -15759,4 +15853,147 @@ _efl_canvas_text_efl_text_cursor_cursor_free(Eo *eo_obj EINA_UNUSED, Efl_Canvas_ evas_textblock_cursor_free(cur); } +/* Async Layout */ + +#include "Ecore.h" +typedef struct _Text_Async_Data Text_Async_Data; +struct _Text_Async_Data +{ + int ret; + Ctxt *c; + Evas_Coord style_pad_l, style_pad_r, style_pad_t, style_pad_b; + Evas_Coord *w_ret, *h_ret; +}; + +typedef struct _Async_Layout_Cb_Info Async_Layout_Cb_Info; +struct _Async_Layout_Cb_Info +{ + int ret; + Evas_Coord w_ret, h_ret; +}; + +static void +_text_layout_async_done(void *todo, Ecore_Thread *thread EINA_UNUSED) +{ + Async_Layout_Cb_Info data; + Text_Async_Data *td = todo; + Ctxt *c = td->c; + Evas_Coord w_ret, h_ret; + _layout_done(c, &w_ret, &h_ret); + +#if 1 + // Copied from _relayout + c->o->formatted.valid = 1; + c->o->formatted.oneline_h = 0; + c->o->last_w = c->evas_o->cur->geometry.w; + c->o->wrap_changed = EINA_FALSE; + LYDBG("ZZ: --------- layout %p @ %ix%i = %ix%i\n", eo_obj, obj->cur->geometry.w, obj->cur->geometry.h, c->o->formatted.w, c->o->formatted.h); + c->o->last_h = c->evas_o->cur->geometry.h; + if ((c->o->paragraphs) && (!EINA_INLIST_GET(c->o->paragraphs)->next) && + (c->o->paragraphs->lines) && (!EINA_INLIST_GET(c->o->paragraphs->lines)->next)) + { + if (c->evas_o->cur->geometry.h < c->o->formatted.h) + { + LYDBG("ZZ: 1 line only... lasth == formatted h (%i)\n", c->o->formatted.h); + c->o->formatted.oneline_h = c->o->formatted.h; + } + } + c->o->changed = 0; + c->o->content_changed = 0; + c->o->format_changed = EINA_FALSE; + c->o->redraw = 1; +#ifdef BIDI_SUPPORT + c->o->changed_paragraph_direction = EINA_FALSE; +#endif + +#endif + data.w_ret = c->wmax; + data.h_ret = c->hmax; + //TODO: callback event with ret: 0 x 0 + efl_event_callback_call(c->obj, EFL_CANVAS_TEXT_EVENT_ASYNC_LAYOUT_COMPLETE, &data); + // Cleanup + c->o->layout_busy = EINA_FALSE; + c->o->changed = EINA_TRUE; + evas_object_change(c->obj, c->evas_o); + free(c); + free(td); +} + +static void +_text_layout_async_do(void *todo, Ecore_Thread *thread EINA_UNUSED) +{ + Text_Async_Data *td = todo; + _layout_visual(td->c); +} + +EOLIAN static void +_efl_canvas_text_async_enabled_set(Eo *eo_obj, Efl_Canvas_Text_Data *o, + Eina_Bool enabled) +{ + if (efl_finalized_get(eo_obj)) + { + ERR("Can't change the async state after construction."); + return; + } + o->async_enabled = enabled; +} + +EOLIAN static Eina_Bool +_efl_canvas_text_async_enabled_get(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o) +{ + return o->async_enabled; +} + +EOLIAN static void +_efl_canvas_text_async_layout(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o EINA_UNUSED) +{ + Text_Async_Data *td; + Ctxt *c; + Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + + if (!o->async_enabled) + { + ERR("Unimplemented unless async_enabled is TRUE"); + return; + } + + LKL(o->lk); + evas_object_textblock_coords_recalc(eo_obj, obj, obj->private_data); + if (o->formatted.valid) + { + LKU(o->lk); + return; + } + + if (o->layout_busy) + { + LKU(o->lk); + return; + } + o->layout_busy = EINA_TRUE; + LKU(o->lk); + + c = calloc(1, sizeof(*c)); + + if (!_layout_setup(c, eo_obj, + obj->cur->geometry.w, obj->cur->geometry.h)) + { + Async_Layout_Cb_Info data; + data.w_ret = 0; + data.h_ret = 0; + LKU(o->lk); + efl_event_callback_call(eo_obj, EFL_CANVAS_TEXT_EVENT_ASYNC_LAYOUT_COMPLETE, &data); + return; + } + _layout_pre(c); + td = calloc(1, sizeof(*td)); + td->c = c; + ecore_thread_run(_text_layout_async_do, _text_layout_async_done, + NULL, td); + + // NOTE: Unlocks on async_done function +} + +//#undef LKL +//#undef LKU #include "canvas/efl_canvas_text.eo.c" |