From fba098df3824c287819b4ae6a9f980b99786c58c Mon Sep 17 00:00:00 2001 From: Yeongjong Lee Date: Fri, 22 Nov 2019 06:13:25 +0000 Subject: [PATCH 01/10] eo: add move tag to iterator It is impossible to reuse iterator after `EINA_ITERATOR_FOREACH`(`eina_iterator_next`). E.g. ``` eina_init(); eina_file_dir_list("/home/", EINA_FALSE, _print_cb, NULL); it = eina_file_ls("/home/"); EINA_ITERATOR_FOREACH(it, f_name) { printf("%s\n", f_name); eina_stringshare_del(f_name); } EINA_ITERATOR_FOREACH(it, f_name) { printf("Again %s\n", f_name); eina_stringshare_del(f_name); } eina_iterator_free(it); ``` `Agian ...` is never printed. Therefore, iterator always need `@move` tag to avoid unexpected behavior without any error message. Reviewed-by: Marcel Hollerbach Differential Revision: https://phab.enlightenment.org/D10719 --- src/lib/ecore/efl_boolean_model.eo | 2 +- src/lib/ecore/efl_core_env.eo | 2 +- src/lib/efl/interfaces/efl_gfx_image.eo | 4 ++-- src/lib/efl/interfaces/efl_ui_view_factory.eo | 2 +- src/lib/elementary/efl_access_object.eo | 2 +- src/lib/elementary/efl_ui_focus_manager.eo | 4 ++-- src/lib/elementary/efl_ui_view_model.c | 1 + src/lib/elementary/efl_ui_view_model.eo | 4 ++-- src/lib/elementary/efl_ui_win.eo | 2 +- 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/lib/ecore/efl_boolean_model.eo b/src/lib/ecore/efl_boolean_model.eo index f8ee356713..fa5b1405c0 100644 --- a/src/lib/ecore/efl_boolean_model.eo +++ b/src/lib/ecore/efl_boolean_model.eo @@ -25,7 +25,7 @@ class @beta Efl.Boolean_Model extends Efl.Composite_Model @in name: string; [[The name of the property to examine.]] @in request: bool; [[The value to look for.]] } - return: iterator; [[The iterator that is valid until any change is made on the model.]] + return: iterator @move; [[The iterator that is valid until any change is made on the model.]] } } implements { diff --git a/src/lib/ecore/efl_core_env.eo b/src/lib/ecore/efl_core_env.eo index 593a3a3cf5..c17e0a1440 100644 --- a/src/lib/ecore/efl_core_env.eo +++ b/src/lib/ecore/efl_core_env.eo @@ -47,7 +47,7 @@ class @beta Efl.Core.Env extends Efl.Object implements Efl.Duplicate { } values { - iter : iterator; + iter : iterator @move; } } } diff --git a/src/lib/efl/interfaces/efl_gfx_image.eo b/src/lib/efl/interfaces/efl_gfx_image.eo index 40ee6ed76f..b9d962b9ab 100644 --- a/src/lib/efl/interfaces/efl_gfx_image.eo +++ b/src/lib/efl/interfaces/efl_gfx_image.eo @@ -217,9 +217,9 @@ interface Efl.Gfx.Image } get {} values { - horizontal: iterator(null); [[Representation of areas that are + horizontal: iterator(null) @move; [[Representation of areas that are stretchable in the image horizontal space.]] - vertical: iterator(null); [[Representation of areas that are + vertical: iterator(null) @move; [[Representation of areas that are stretchable in the image vertical space.]] } } diff --git a/src/lib/efl/interfaces/efl_ui_view_factory.eo b/src/lib/efl/interfaces/efl_ui_view_factory.eo index 728c25907c..f4774300a5 100644 --- a/src/lib/efl/interfaces/efl_ui_view_factory.eo +++ b/src/lib/efl/interfaces/efl_ui_view_factory.eo @@ -10,7 +10,7 @@ class @beta Efl.Ui.View_Factory params { factory: Efl.Ui.Factory; [[The factory to use for requesting the new object from and generating the created event onto.]] - models: iterator; [[Efl iterator providing the model to be associated to the new item. It should + models: iterator @move; [[Efl iterator providing the model to be associated to the new item. It should remain valid until the end of the function call.]] } return: future; [[Created UI object]] diff --git a/src/lib/elementary/efl_access_object.eo b/src/lib/elementary/efl_access_object.eo index d7392f275e..fc16ea2194 100644 --- a/src/lib/elementary/efl_access_object.eo +++ b/src/lib/elementary/efl_access_object.eo @@ -263,7 +263,7 @@ mixin @beta Efl.Access.Object requires Efl.Object } relations_get @protected @beta @const { [[Gets an all relations between accessible object and other accessible objects.]] - return: iterator; [[Accessible relation set]] + return: iterator @move; [[Accessible relation set]] } @property role @beta { [[The role of the object in accessibility domain.]] diff --git a/src/lib/elementary/efl_ui_focus_manager.eo b/src/lib/elementary/efl_ui_focus_manager.eo index 1b0256f663..5bb11e7036 100644 --- a/src/lib/elementary/efl_ui_focus_manager.eo +++ b/src/lib/elementary/efl_ui_focus_manager.eo @@ -92,7 +92,7 @@ interface Efl.Ui.Focus.Manager { ]] get {} values { - border_elements : iterator; [[An iterator + border_elements : iterator @move; [[An iterator over the border objects.]] } } @@ -107,7 +107,7 @@ interface Efl.Ui.Focus.Manager { viewport : Eina.Rect; [[The rectangle defining the viewport.]] } values { - viewport_elements : iterator; [[An iterator over the viewport border objects.]] + viewport_elements : iterator @move; [[An iterator over the viewport border objects.]] } } @property root { diff --git a/src/lib/elementary/efl_ui_view_model.c b/src/lib/elementary/efl_ui_view_model.c index 0580ff7d41..0194e47a87 100644 --- a/src/lib/elementary/efl_ui_view_model.c +++ b/src/lib/elementary/efl_ui_view_model.c @@ -183,6 +183,7 @@ _efl_ui_view_model_property_logic_add(Eo *obj, Efl_Ui_View_Model_Data *pd, logic->sources = eina_list_append(logic->sources, eina_stringshare_add(source)); efl_ui_view_model_property_bind(obj, source, property); } + eina_iterator_free(bound); return 0; } diff --git a/src/lib/elementary/efl_ui_view_model.eo b/src/lib/elementary/efl_ui_view_model.eo index d296c8c4ae..d5dcdbeaf8 100644 --- a/src/lib/elementary/efl_ui_view_model.eo +++ b/src/lib/elementary/efl_ui_view_model.eo @@ -76,8 +76,8 @@ class Efl.Ui.View_Model extends Efl.Composite_Model with the above property name.]] set: EflUiViewModelPropertySet; [[Define the set callback called when the @Efl.Model.property.set is called with the above property name.]] - binded: iterator; [[Iterator of property name to bind with this defined property see - @.property_bind.]] + binded: iterator @move; [[Iterator of property name to bind with this defined property see + @.property_bind.]] } return: Eina.Error; } diff --git a/src/lib/elementary/efl_ui_win.eo b/src/lib/elementary/efl_ui_win.eo index bca1b4a574..602acf506b 100644 --- a/src/lib/elementary/efl_ui_win.eo +++ b/src/lib/elementary/efl_ui_win.eo @@ -721,7 +721,7 @@ class Efl.Ui.Win extends Efl.Ui.Widget implements Efl.Canvas.Scene, Efl.Access.W hover: bool @optional; [[$false by default, $true means to include fingers that are currently hovering.]] } - return: iterator; [[Iterator to pointer positions]] + return: iterator @move; [[Iterator to pointer positions]] } @property win_rotation @beta { [[The rotation of this window From a21f615a197e7a1c46a122c0c0d6cf21178f19a1 Mon Sep 17 00:00:00 2001 From: Yeongjong Lee Date: Fri, 22 Nov 2019 07:29:27 +0000 Subject: [PATCH 02/10] eo: add missing move tag `efl_access_action_actions_get` the list is created by `eina_list_append` `efl_ui_format_values_set` the accessor is freed in that function. `efl_ui_format_values_get` The accessor is created by `eina_inarray_accessor_new` `efl_core_command_line_command_access` The accessor is created by `eina_array_accessor_new` Reviewed-by: Marcel Hollerbach Differential Revision: https://phab.enlightenment.org/D10720 --- src/lib/ecore/efl_core_command_line.eo | 2 +- src/lib/elementary/efl_access_action.eo | 2 +- src/lib/elementary/efl_ui_format.eo | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/ecore/efl_core_command_line.eo b/src/lib/ecore/efl_core_command_line.eo index 6eec372954..24849be70d 100644 --- a/src/lib/ecore/efl_core_command_line.eo +++ b/src/lib/ecore/efl_core_command_line.eo @@ -50,7 +50,7 @@ mixin @beta Efl.Core.Command_Line requires Efl.Object { } command_access { [[ Get the accessor which enables access to each argument that got passed to this object. ]] - return : accessor; + return : accessor @move; } @property command_array { [[ Use an array to fill this object diff --git a/src/lib/elementary/efl_access_action.eo b/src/lib/elementary/efl_access_action.eo index acaad80188..8f70f0efb1 100644 --- a/src/lib/elementary/efl_access_action.eo +++ b/src/lib/elementary/efl_access_action.eo @@ -47,7 +47,7 @@ mixin @beta Efl.Access.Action get @pure_virtual { } values { - actions: list; + actions: list @move; [[Contains statically allocated strings.]] } } diff --git a/src/lib/elementary/efl_ui_format.eo b/src/lib/elementary/efl_ui_format.eo index a05cc0b071..3e2bd287bb 100644 --- a/src/lib/elementary/efl_ui_format.eo +++ b/src/lib/elementary/efl_ui_format.eo @@ -81,7 +81,7 @@ mixin Efl.Ui.Format requires Efl.Object performance reasons. ]] values { - values: accessor; [[Accessor over a list of value-text pairs. + values: accessor @move; [[Accessor over a list of value-text pairs. The method will dispose of the accessor, but not of its contents. For convenience, Eina offers a range of helper From 09fd7ca8d60fc61a43891c0ace99e4741f787b17 Mon Sep 17 00:00:00 2001 From: Hosang Kim Date: Fri, 22 Nov 2019 09:16:47 +0000 Subject: [PATCH 03/10] ecore_timer: add NULL checking for timer data. When timer is not created, a crash occurs. For example, when user create ecore timer in the pthread.. Of course this is not the correct usage, but printing ERR message is enough. Reviewed-by: Marcel Hollerbach Differential Revision: https://phab.enlightenment.org/D10714 --- src/lib/ecore/ecore_timer.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c index e07aa9f666..5713313a1b 100644 --- a/src/lib/ecore/ecore_timer.c +++ b/src/lib/ecore/ecore_timer.c @@ -15,6 +15,17 @@ #define ECORE_TIMER_CHECK(obj) if (!efl_isa((obj), MY_CLASS)) return +#define EFL_LOOP_TIMER_DATA_GET(o, td) \ + Efl_Loop_Timer_Data *td = efl_data_scope_safe_get(o, EFL_LOOP_TIMER_CLASS) + +#define EFL_LOOP_TIMER_DATA_GET_OR_RETURN(o, ptr, ...) \ + EFL_LOOP_TIMER_DATA_GET(o, ptr); \ + if (EINA_UNLIKELY(!ptr)) \ + { \ + ERR("No data for timer %p", o); \ + return __VA_ARGS__; \ + } + struct _Ecore_Timer_Legacy { Ecore_Task_Cb func; @@ -178,7 +189,6 @@ EAPI Ecore_Timer * ecore_timer_add(double in, Ecore_Task_Cb func, const void *data) { Ecore_Timer_Legacy *legacy; - Efl_Loop_Timer_Data *td; Eo *timer; EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); @@ -194,7 +204,7 @@ ecore_timer_add(double in, Ecore_Task_Cb func, const void *data) timer = efl_add(MY_CLASS, efl_main_loop_get(), efl_event_callback_array_add(efl_added, legacy_timer(), legacy), efl_loop_timer_interval_set(efl_added, in)); - td = efl_data_scope_get(timer, MY_CLASS); + EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL); td->legacy = legacy; return timer; } @@ -203,7 +213,6 @@ EAPI Ecore_Timer * ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data) { Ecore_Timer_Legacy *legacy; - Efl_Loop_Timer_Data *td; Eo *timer; EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); @@ -220,7 +229,7 @@ ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data) efl_event_callback_array_add(efl_added, legacy_timer(), legacy), efl_loop_timer_loop_reset(efl_added), efl_loop_timer_interval_set(efl_added, in)); - td = efl_data_scope_get(timer, MY_CLASS); + EFL_LOOP_TIMER_DATA_GET_OR_RETURN(timer, td, NULL); td->legacy = legacy; return timer; } @@ -228,14 +237,12 @@ ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data) EAPI void * ecore_timer_del(Ecore_Timer *timer) { - Efl_Loop_Timer_Data *td; void *data; if (!timer) return NULL; EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); - - td = efl_data_scope_safe_get(timer, MY_CLASS); + EFL_LOOP_TIMER_DATA_GET(timer, td); // If legacy == NULL, this means double free or something if ((!td) || (!td->legacy)) { From 11094aeaaf001241fb2d5bc8e74e23e8db944a2d Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:13:47 -0300 Subject: [PATCH 04/10] csharp: Add more since tags to members Summary: - Class constructors and other members - Aliases fields ref T8359 Reviewers: felipealmeida, segfaultxavi, brunobelo, woohyun Reviewed By: felipealmeida Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8359 Differential Revision: https://phab.enlightenment.org/D10419 --- .../eolian/mono/alias_definition.hh | 12 +++++- .../eolian_mono/eolian/mono/documentation.hh | 18 ++++++++- src/bin/eolian_mono/eolian/mono/klass.hh | 40 +++++++++++++++---- src/lib/eolian_cxx/grammar/indentation.hpp | 11 +++++ 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/bin/eolian_mono/eolian/mono/alias_definition.hh b/src/bin/eolian_mono/eolian/mono/alias_definition.hh index 31d86fe10d..d7fda07cb5 100644 --- a/src/bin/eolian_mono/eolian/mono/alias_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/alias_definition.hh @@ -56,6 +56,10 @@ struct alias_definition_generator alias_type_doc = utils::replace_all(alias_type, "<", "<"); alias_type_doc = utils::replace_all(alias_type_doc, ">", ">"); + std::string alias_since; + if (!documentation_helpers::generate_since_tag_line(std::back_inserter(alias_since), alias.documentation, scope_tab, context)) + return false; + std::string const alias_name = utils::remove_all(alias.eolian_name, '_'); if (!as_generator( documentation @@ -63,7 +67,9 @@ struct alias_definition_generator << "{\n" << scope_tab << "private " << alias_type << " payload;\n\n" - << scope_tab << "/// Converts an instance of " << alias_type_doc << " to this struct.\n" + << scope_tab << "/// Converts an instance of " << alias_type_doc << " to this struct.\n" + << alias_since + << scope_tab << "/// \n" << scope_tab << "/// The value to be converted.\n" << scope_tab << "/// A struct with the given value.\n" << scope_tab << "public static implicit operator " << alias_name << "(" << alias_type << " value)\n" @@ -71,7 +77,9 @@ struct alias_definition_generator << scope_tab << scope_tab << "return new " << alias_name << "{payload=value};\n" << scope_tab << "}\n\n" - << scope_tab << "/// Converts an instance of this struct to " << alias_type_doc << ".\n" + << scope_tab << "/// Converts an instance of this struct to " << alias_type_doc << ".\n" + << alias_since + << scope_tab << "/// \n" << scope_tab << "/// The value to be converted packed in this struct.\n" << scope_tab << "/// The actual value the alias is wrapping.\n" << scope_tab << "public static implicit operator " << alias_type << "(" << alias_name << " value)\n" diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh index b57dc4a6de..0a2179b167 100644 --- a/src/bin/eolian_mono/eolian/mono/documentation.hh +++ b/src/bin/eolian_mono/eolian/mono/documentation.hh @@ -649,8 +649,24 @@ struct documentation_string_generator } const documentation_string {}; -} // namespace eolian_mono +namespace documentation_helpers +{ +template +bool generate_since_tag_line(OutputIterator sink, attributes::documentation_def const& doc, Indent indentation, Context context) +{ + if (doc.since.empty()) + return true; + + return as_generator + ( + indentation << ("/// Since EFL " + doc.since + ".\n") + ).generate(sink, attributes::unused, context); +} + +} // documentation_helpers + +} // namespace eolian_mono namespace efl { namespace eolian { namespace grammar { diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh index 81d5956535..653acc78fc 100644 --- a/src/bin/eolian_mono/eolian/mono/klass.hh +++ b/src/bin/eolian_mono/eolian/mono/klass.hh @@ -410,6 +410,10 @@ struct klass auto implementable_methods = helpers::get_all_registerable_methods(cls, context); bool root = !helpers::has_regular_ancestor(cls); auto const& indent = current_indentation(inative_cxt); + std::string klass_since; + + if (!documentation_helpers::generate_since_tag_line(std::back_inserter(klass_since), cls.documentation, indent, context)) + return false; std::string base_name; if(!root) @@ -421,7 +425,10 @@ struct klass if(!as_generator ( indent << lit("/// Wrapper for native methods and virtual method delegates.\n") - << indent << "/// For internal use by generated code only.\n" + << indent << "/// For internal use by generated code only.\n" + << klass_since + << indent << "/// \n" + << indent << "[EditorBrowsable(EditorBrowsableState.Never)]\n" << indent << "internal new class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n" << indent << "{\n" ).generate(sink, attributes::unused, inative_cxt)) @@ -437,7 +444,9 @@ struct klass } if(!as_generator( - indent << scope_tab << "/// Gets the list of Eo operations to override.\n" + indent << scope_tab << "/// Gets the list of Eo operations to override.\n" + << klass_since + << indent << "/// \n" << indent << scope_tab << "/// The list of Eo operations to be overload.\n" << indent << scope_tab << "internal override System.Collections.Generic.List GetEoOps(System.Type type, bool includeInherited)\n" << indent << scope_tab << "{\n" @@ -485,9 +494,14 @@ struct klass ).generate(sink, attributes::unused, inative_cxt)) return false; + if (!klass_since.empty()) + klass_since = static_cast(scope_tab) + klass_since; + // Attribute getter of the native 'Efl_Class *' handle (for proper inheritance from additional explicit interfaces) if(!as_generator( - indent << scope_tab << "/// Returns the Eo class for the native methods of this class.\n" + indent << scope_tab << "/// Returns the Eo class for the native methods of this class.\n" + << klass_since + << indent << scope_tab << "/// \n" << indent << scope_tab << "/// The native class pointer.\n" << indent << scope_tab << "internal override IntPtr GetEflClass()\n" << indent << scope_tab << "{\n" @@ -558,9 +572,15 @@ struct klass return !blacklist::is_function_blacklisted(ctor.function, context); }); + std::string klass_since; + if (!documentation_helpers::generate_since_tag_line(std::back_inserter(klass_since), cls.documentation, scope_tab, context)) + return false; + // Public (API) constructors if (!as_generator( - scope_tab << "/// Initializes a new instance of the class.\n" + scope_tab << "/// Initializes a new instance of the class.\n" + << klass_since + << scope_tab << "/// \n" << scope_tab << "/// Parent instance.\n" << *(documentation) // For constructors with arguments, the parent is also required, as optional parameters can't come before non-optional paramenters. @@ -572,13 +592,17 @@ struct klass << scope_tab << scope_tab << "FinishInstantiation();\n" << scope_tab << "}\n\n" << scope_tab << "/// Subclasses should override this constructor if they are expected to be instantiated from native code.\n" - << scope_tab << "/// Do not call this constructor directly.\n" + << scope_tab << "/// Do not call this constructor directly.\n" + << klass_since + << scope_tab << "/// \n" << scope_tab << "/// Tag struct storing the native handle of the object being constructed.\n" << scope_tab << "protected " << inherit_name << "(ConstructingHandle ch) : base(ch)\n" << scope_tab << "{\n" << scope_tab << "}\n\n" << scope_tab << "/// Initializes a new instance of the class.\n" - << scope_tab << "/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.\n" + << scope_tab << "/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.\n" + << klass_since + << scope_tab << "/// \n" << scope_tab << "/// The native pointer to be wrapped.\n" << scope_tab << "internal " << inherit_name << "(Efl.Eo.WrappingHandle wh) : base(wh)\n" << scope_tab << "{\n" @@ -605,7 +629,9 @@ struct klass return as_generator( scope_tab << "/// Initializes a new instance of the class.\n" - << scope_tab << "/// Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.\n" + << scope_tab << "/// Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.\n" + << klass_since + << scope_tab << "/// \n" << scope_tab << "/// The pointer to the base native Eo class.\n" << scope_tab << "/// The Efl.Object parent of this instance.\n" << scope_tab << "protected " << inherit_name << "(IntPtr baseKlass, Efl.Object parent) : base(baseKlass, parent)\n" diff --git a/src/lib/eolian_cxx/grammar/indentation.hpp b/src/lib/eolian_cxx/grammar/indentation.hpp index b88a14d392..3bf5d07dbe 100644 --- a/src/lib/eolian_cxx/grammar/indentation.hpp +++ b/src/lib/eolian_cxx/grammar/indentation.hpp @@ -53,6 +53,11 @@ struct scope_tab_generator int n; int m; + + explicit operator std::string() const + { + return std::string(n * m, ' '); + } }; template <> @@ -71,6 +76,12 @@ struct scope_tab_terminal { return {1}; } + + explicit operator std::string() const + { + return static_cast(scope_tab_generator{1}); + } + } const scope_tab = {}; template <> From 0acc840f1970d60b1c610a1d5b83e17abd49f17f Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:55:01 -0300 Subject: [PATCH 05/10] pyolian: full_inherit must recurse parent too Test Plan: run tests Reviewers: segfaultxavi, herb, DaveMDS, felipealmeida Reviewed By: felipealmeida Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D10420 --- src/scripts/pyolian/eolian.py | 1 + src/scripts/pyolian/test_eolian.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/scripts/pyolian/eolian.py b/src/scripts/pyolian/eolian.py index 9ab6abd01e..31f4f06f44 100644 --- a/src/scripts/pyolian/eolian.py +++ b/src/scripts/pyolian/eolian.py @@ -739,6 +739,7 @@ class Class(Object): def do_class_recursive(cls): if cls.parent: li.append(cls.parent) + do_class_recursive(cls.parent) for other in cls.extensions: if other not in li: li.append(other) diff --git a/src/scripts/pyolian/test_eolian.py b/src/scripts/pyolian/test_eolian.py index 4aa4588640..b6090c661e 100755 --- a/src/scripts/pyolian/test_eolian.py +++ b/src/scripts/pyolian/test_eolian.py @@ -699,3 +699,8 @@ class TestEolianExpression(object): # exp.binary_operator # TODO find a better test (only works for BINARY expr) # exp.binary_lhs # TODO find a better test (only works for BINARY expr) # exp.binary_rhs # TODO find a better test (only works for BINARY expr) + +class TestEolianInherits(object): + def test_inherits_full(self, eolian_db): + cls = eolian_db.class_by_name_get('Efl.Ui.Widget') + assert 'Efl.Object' in cls.inherits_full From abaa90cfc20529f1507864e7b2d38ef69a16ded4 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:56:31 -0300 Subject: [PATCH 06/10] pyolian: Add a method to get the hierarchy of extensions Summary: To be used by the test generator Depends on D10420 Test Plan: test in the diff Reviewers: DaveMDS, herb, segfaultxavi, felipealmeida Reviewed By: felipealmeida Subscribers: cedric, brunobelo, #reviewers, felipealmeida, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D10421 --- src/scripts/pyolian/eolian.py | 17 +++++++++++++++++ src/scripts/pyolian/test_eolian.py | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/src/scripts/pyolian/eolian.py b/src/scripts/pyolian/eolian.py index 31f4f06f44..eababfadba 100644 --- a/src/scripts/pyolian/eolian.py +++ b/src/scripts/pyolian/eolian.py @@ -732,6 +732,23 @@ class Class(Object): def extensions(self): return Iterator(Class, lib.eolian_class_extensions_get(self)) + @cached_property + def extensions_hierarchy(self): + visited = set() + queue = [ext for ext in self.extensions] + + while queue: + current = queue.pop() + + if current in visited: + continue + + visited.add(current) + + queue.extend(current.extensions) + + return visited + @cached_property def inherits_full(self): li = [] diff --git a/src/scripts/pyolian/test_eolian.py b/src/scripts/pyolian/test_eolian.py index b6090c661e..133b279084 100755 --- a/src/scripts/pyolian/test_eolian.py +++ b/src/scripts/pyolian/test_eolian.py @@ -704,3 +704,11 @@ class TestEolianInherits(object): def test_inherits_full(self, eolian_db): cls = eolian_db.class_by_name_get('Efl.Ui.Widget') assert 'Efl.Object' in cls.inherits_full + + def test_extensions_hierarchy(self, eolian_db): + cls = eolian_db.class_by_name_get('Efl.Ui.Widget') + + # inherited extension + assert any(x.name == 'Efl.Gfx.Stack' for x in cls.extensions_hierarchy) + # direct extension + assert any(x.name == 'Efl.Access.Object' for x in cls.extensions_hierarchy) From bb3f741990dee47292c23936c05b80326ea49e45 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:56:41 -0300 Subject: [PATCH 07/10] pyolian: Add helper functions for simple scripts Summary: These two functions encapsulate some code that commonly is repeated through pyolian scripts. With these, a minimal example (provided `src/scripts/pyolian` is in the PYTHONPATH) could be done with: ``` import os from pyolian import eolian SCAN_FOLDER = os.path.join(eolian.in_tree_src_dir(), 'src', 'lib') eolian_db = eolian.parse_folders(SCAN_FOLDER) for cls in eolian_db.classes: print(cls) ``` Reviewers: segfaultxavi, DaveMDS, felipealmeida Reviewed By: felipealmeida Subscribers: cedric, #reviewers, #committers, felipealmeida, brunobelo Tags: #efl Differential Revision: https://phab.enlightenment.org/D10589 --- src/scripts/pyolian/eolian.py | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/scripts/pyolian/eolian.py b/src/scripts/pyolian/eolian.py index eababfadba..e7681208c7 100644 --- a/src/scripts/pyolian/eolian.py +++ b/src/scripts/pyolian/eolian.py @@ -23,6 +23,7 @@ a way that this folder will be available on PYTHON_PATH, fe: from pyolian.generator import Template """ +import os from enum import IntEnum import atexit from ctypes import cast, byref, c_char_p, c_void_p, c_int @@ -520,6 +521,44 @@ class Eolian_State(Eolian_Unit): return bool(lib.eolian_state_check(self)) +# Helper functions ################################################### + +def parse_folders(folders): + """Loads a new database scanning the given folders. + + For example: + + SCAN_FOLDER = os.path.join(eolian.in_tree_src_dir(), 'src', 'lib') + eolian_db = eolian.parse_folders(SCAN_FOLDER) + """ + + db = Eolian_State() + if not isinstance(db, Eolian_State): + raise (RuntimeError('Eolian, failed to create Eolian state')) + + if isinstance(folders, str): + folders = [folders] + + for folder in folders: + # eolian source tree scan + if not db.directory_add(folder): + raise (RuntimeError('Eolian, failed to scan source dirsectory')) + + # Parse all known eo files + if not db.all_eot_files_parse(): + raise (RuntimeError('Eolian, failed to parse all EOT files')) + + if not db.all_eo_files_parse(): + raise (RuntimeError('Eolian, failed to parse all EO files')) + + return db + +def in_tree_src_dir(): + """Returns the root folder of this script's source tree""" + script_path = os.path.dirname(os.path.realpath(__file__)) + return os.path.abspath(os.path.join(script_path, '..', '..', '..')) + + # Namespace Utility Class ################################################### class Namespace(object): From aacd2fa82d68de26ae27c2056a6ac17cc3421b04 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:56:51 -0300 Subject: [PATCH 08/10] csharp: Iterate more in GC-dependent test Summary: The inheritance test depends on the objects being actively destroyed. Currently this happens in a two step process, where first the C# object is collected from the GC. As this happens in a separate thread, we schedule a callback to run in the main loop to actually unref the EO object. This commit adds more iterations to make sure the EO of the parent is unref'd and releases the child. This should be the last C#-related CI test failure Ref T8313 Reviewers: stefan_schmidt, brunobelo, felipealmeida Reviewed By: felipealmeida Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8313 Differential Revision: https://phab.enlightenment.org/D10612 --- src/tests/efl_mono/Inheritance.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/efl_mono/Inheritance.cs b/src/tests/efl_mono/Inheritance.cs index 1595759994..852a639029 100644 --- a/src/tests/efl_mono/Inheritance.cs +++ b/src/tests/efl_mono/Inheritance.cs @@ -142,9 +142,9 @@ class TestInheritance CreateAndCheckInheritedObjects(out parentWRef, out childWRef); - // Two invocations to iterate a the child wasn't being released with a single one - Test.CollectAndIterate(); - Test.CollectAndIterate(); + // We need some extra iterations of the main loop to allow the async callbacks + // registered from the Dispose method to the main loop to run. + Test.CollectAndIterate(10, 10); var parent = (Dummy.TestObject) parentWRef.Target; var child = (Dummy.TestObject) childWRef.Target; From f10c91cda9795a43e6984814b7394383cf9da812 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Tue, 26 Nov 2019 11:56:57 -0300 Subject: [PATCH 09/10] csharp: CA1717 - Add [Flags] for enums Summary: Using the naive approach of checking if the name ends with `Flags`. Ref T8411 Depends on D10708 Reviewers: brunobelo, segfaultxavi, felipealmeida, YOhoho Reviewed By: felipealmeida Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8411 Differential Revision: https://phab.enlightenment.org/D10709 --- .../eolian_mono/eolian/mono/enum_definition.hh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/bin/eolian_mono/eolian/mono/enum_definition.hh b/src/bin/eolian_mono/eolian/mono/enum_definition.hh index 76bad3baa2..2c304fcd0f 100644 --- a/src/bin/eolian_mono/eolian/mono/enum_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/enum_definition.hh @@ -40,15 +40,21 @@ struct enum_definition_generator if(!name_helpers::open_namespaces(sink, enum_.namespaces, context)) return false; - if(!as_generator(documentation).generate(sink, enum_, context)) - return false; + std::string enum_name = name_helpers::typedecl_managed_name(enum_); + std::string flags_attribute; + + // CA1717 + if (utils::ends_with(enum_name, "Flags") || utils::ends_with(enum_name, "InputHints")) // Special provision while Text api is revamped + flags_attribute = "[Flags]"; if(!as_generator ( - "[Efl.Eo.BindingEntity]\n" - "public enum " << string << "\n{\n" + documentation + << flags_attribute + << "[Efl.Eo.BindingEntity]\n" + "public enum " << enum_name << "\n{\n" ) - .generate(sink, name_helpers::typedecl_managed_name(enum_), context)) + .generate(sink, enum_, context)) return false; // iterate enum fiels From c7f37fe61852ea45dce071e0f80f98adcce08981 Mon Sep 17 00:00:00 2001 From: Ali Alzyod Date: Wed, 27 Nov 2019 13:04:31 +0900 Subject: [PATCH 10/10] Efl.Text.Attribute_Factory Summary: Implementation of new Efl.Text.Attribute_Factory class which replace the annotation interface. Currently, we have two public methods: ``` void efl_text_attribute_factory_attribute_insert(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end, const char *format) unsigned int efl_text_attribute_factory_attribute_clear(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end); ``` Other methods will be internal methods, for the time being, we will redesign internal methods Reviewers: woohyun, tasn, segfaultxavi, bu5hm4n, zmike Subscribers: zmike, q66, cedric, segfaultxavi, bu5hm4n, a.srour, #committers, #reviewers Tags: #efl Differential Revision: https://phab.enlightenment.org/D10646 --- src/bin/elementary/test.c | 2 - src/bin/elementary/test_efl_ui_text.c | 162 +--------- src/lib/efl/Efl.h | 3 +- src/lib/efl/interfaces/efl_interfaces_main.c | 1 - src/lib/efl/interfaces/efl_text_annotate.eo | 137 -------- src/lib/efl/interfaces/efl_text_types.eot | 4 +- src/lib/efl/interfaces/meson.build | 1 - .../efl_ui_internal_text_interactive.c | 1 + src/lib/elementary/efl_ui_text.c | 78 +++-- src/lib/evas/Efl_Canvas.h | 1 + src/lib/evas/Evas_Eo.h | 1 + src/lib/evas/Evas_Internal.h | 11 + src/lib/evas/canvas/efl_canvas_text.eo | 11 +- .../evas/canvas/efl_canvas_text_internal.h | 104 +++++- .../evas/canvas/efl_text_attribute_factory.c | 133 ++++++++ .../evas/canvas/efl_text_attribute_factory.eo | 37 +++ src/lib/evas/canvas/efl_text_cursor.c | 10 +- src/lib/evas/canvas/efl_text_cursor.eo | 13 - src/lib/evas/canvas/evas_object_textblock.c | 305 +++++------------- src/lib/evas/canvas/meson.build | 4 +- src/tests/evas/evas_test_textblock.c | 224 ++----------- 21 files changed, 432 insertions(+), 811 deletions(-) delete mode 100644 src/lib/efl/interfaces/efl_text_annotate.eo create mode 100644 src/lib/evas/canvas/efl_text_attribute_factory.c create mode 100644 src/lib/evas/canvas/efl_text_attribute_factory.eo diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index a78850aa31..1d91bf5a4b 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -366,7 +366,6 @@ void test_code_diff_inline(void *data, Evas_Object *obj, void *event_info); void test_efl_ui_text(void *data, Evas_Object *obj, void *event_info); void test_efl_ui_text_inputfield(void *data, Evas_Object *obj, void *event_info); void test_efl_ui_text_label(void *data, Evas_Object *obj, void *event_info); -void test_ui_text_item_factory(void *data, Evas_Object *obj, void *event_info); void test_evas_mask(void *data, Edje_Object *obj, void *event_info); void test_gfx_filters(void *data, Evas_Object *obj, void *event_info); void test_evas_snapshot(void *data, Evas_Object *obj, void *event_info); @@ -941,7 +940,6 @@ add_tests: ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text", test_efl_ui_text); ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text Input Field", test_efl_ui_text_inputfield); ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text Label", test_efl_ui_text_label); - ADD_TEST_EO(NULL, "Entries", "Ui.Text Item Factory", test_ui_text_item_factory); ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Tags", test_ui_tags); //------------------------------// diff --git a/src/bin/elementary/test_efl_ui_text.c b/src/bin/elementary/test_efl_ui_text.c index d56fddb78d..e06006703e 100644 --- a/src/bin/elementary/test_efl_ui_text.c +++ b/src/bin/elementary/test_efl_ui_text.c @@ -5,6 +5,7 @@ #include #include #include "elm_priv.h" //FIXME remove this once efl.ui.text doesn't need elm_general.h + static void _apply_style(Eo *obj, size_t start_pos, size_t end_pos, const char *style) { @@ -16,7 +17,7 @@ _apply_style(Eo *obj, size_t start_pos, size_t end_pos, const char *style) efl_text_cursor_position_set(start, start_pos); efl_text_cursor_position_set(end, end_pos); - efl_text_annotation_insert(obj, efl_text_cursor_handle_get(start), efl_text_cursor_handle_get(end), style); + efl_text_attribute_factory_attribute_insert(start, end, style); efl_del(start); efl_del(end); @@ -235,162 +236,3 @@ test_efl_ui_text_inputfield(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 200)); } - -#define IMAGES_SZ 5 - -static const char *images[IMAGES_SZ] = { - "sky", "logo", "dog", "eet_rock", "eet_plant" }; - -static void -_on_factory_bt_image_clicked(void *data, const Efl_Event *event EINA_UNUSED) -{ - Evas_Object *en = data; - static int image_idx = 0; - - image_idx = (image_idx + 1) % IMAGES_SZ; - - efl_text_cursor_item_insert(en, efl_text_cursor_handle_get(efl_text_interactive_main_cursor_get(en)), - images[image_idx], "size=32x32"); - printf("Inserted image: key = %s\n", images[image_idx]); -} - -static void -_on_factory_bt_emoticon_clicked(void *data, const Efl_Event *event EINA_UNUSED) -{ - Evas_Object *en = data; - efl_text_cursor_item_insert(en, efl_text_cursor_handle_get(efl_text_interactive_main_cursor_get(en)), - "emoticon/evil-laugh", "size=32x32"); -} - -static struct -{ - const char *name; - Eo *item_factory; -} factories[3]; - -static void -_on_factory_bt_factory_clicked(void *data, const Efl_Event *event EINA_UNUSED) -{ - Evas_Object *en = data; - static int item_factory_idx = 0; - - item_factory_idx = (item_factory_idx + 1) % 3; - efl_ui_text_item_factory_set(en, factories[item_factory_idx].item_factory); - printf("Factory set to: %s\n", factories[item_factory_idx].name); -} - -#define FACTORY_NONE 0 -#define FACTORY_IMAGE 1 -#define FACTORY_EMOTICON 2 - -void -test_ui_text_item_factory(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) -{ - Evas_Object *win, *bx, *bx2, *bt, *en; - Efl_Text_Cursor *main_cur, *cur; - char buf[128]; - Eina_File *f; - - win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), - efl_text_set(efl_added, "Efl Ui Text Item Factory"), - efl_ui_win_autodel_set(efl_added, EINA_TRUE)); - - bx = efl_add(EFL_UI_BOX_CLASS, win); - efl_content_set(win, bx); - - en = efl_add(EFL_UI_TEXT_CLASS, bx, - efl_text_multiline_set(efl_added, EINA_TRUE)); - - factories[FACTORY_NONE].name = "None (Fallback)"; - factories[FACTORY_NONE].item_factory = NULL; - - factories[FACTORY_IMAGE].name = "Image Factory"; - factories[FACTORY_IMAGE].item_factory = - efl_add(EFL_UI_TEXT_FACTORY_IMAGES_CLASS, en); - - factories[FACTORY_EMOTICON].name = "Emoticon Factory"; - factories[FACTORY_EMOTICON].item_factory = - efl_add(EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS, en); - - // Test assigning file path source - snprintf(buf, sizeof(buf), "%s/images/sky_01.jpg", elm_app_data_dir_get()); - efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory, - images[0], buf, NULL); - snprintf(buf, sizeof(buf), "%s/images/logo.png", elm_app_data_dir_get()); - efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory, - images[1], buf, NULL); - snprintf(buf, sizeof(buf), "%s/images/mystrale.jpg", elm_app_data_dir_get()); - efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory, - images[2], buf, NULL); - - // Open EET source w/ key - snprintf(buf, sizeof(buf), "%s/images/image_items.eet", elm_app_data_dir_get()); - f = eina_file_open(buf, EINA_FALSE); - if (f) - { - efl_ui_text_factory_images_matches_mmap_add( - factories[FACTORY_IMAGE].item_factory, - "eet_rock", f, "rock"); - efl_ui_text_factory_images_matches_mmap_add( - factories[FACTORY_IMAGE].item_factory, - "eet_plant", f, "plant"); - eina_file_close(f); - } - else - { - printf("Error loading test file. Please review test."); - } - - - printf("Added Efl.Ui.Text object\n"); - efl_text_set(en, "Hello world! Goodbye world! This is a test text for the" - " new UI Text widget.\xE2\x80\xA9This is the next paragraph.\nThis" - " is the next line.\nThis is Yet another line! Line and paragraph" - " separators are actually different!"); - efl_text_font_set(en, "Sans", 14); - efl_text_normal_color_set(en, 255, 255, 255, 255); - - main_cur = efl_text_interactive_main_cursor_get(en); - cur = efl_ui_text_cursor_create(en); - - efl_text_cursor_position_set(cur, 2); - efl_text_cursor_item_insert(en, efl_text_cursor_handle_get(cur), "emoticon/happy", "size=32x32"); - efl_text_cursor_position_set(cur, 50); - - snprintf(buf, sizeof(buf), "file://%s/images/sky_01.jpg", elm_app_data_dir_get()); - efl_text_cursor_item_insert(en, efl_text_cursor_handle_get(cur), buf, "size=32x32"); - efl_text_cursor_position_set(main_cur, 5); - - efl_text_interactive_editable_set(en, EINA_TRUE); - efl_ui_text_scrollable_set(en, EINA_TRUE); - efl_pack(bx, en); - elm_object_focus_set(en, EINA_TRUE); - - bx2 = efl_add(EFL_UI_BOX_CLASS, bx); - efl_gfx_hint_weight_set(bx2, EFL_GFX_HINT_EXPAND, EFL_GFX_HINT_EXPAND); - efl_ui_layout_orientation_set(bx2, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL); - - bt = efl_add(EFL_UI_BUTTON_CLASS, bx2); - efl_text_set(bt, "Image"); - efl_event_callback_add(bt, EFL_INPUT_EVENT_CLICKED, _on_factory_bt_image_clicked, en); - efl_gfx_hint_weight_set(bt, EFL_GFX_HINT_EXPAND, 0.0); - efl_pack(bx2, bt); - elm_object_focus_allow_set(bt, EINA_FALSE); - - bt = efl_add(EFL_UI_BUTTON_CLASS, bx2); - efl_text_set(bt, "Emoticon"); - efl_event_callback_add(bt, EFL_INPUT_EVENT_CLICKED, _on_factory_bt_emoticon_clicked, en); - efl_gfx_hint_weight_set(bt, EFL_GFX_HINT_EXPAND, 0.0); - efl_pack(bx2, bt); - elm_object_focus_allow_set(bt, EINA_FALSE); - - bt = efl_add(EFL_UI_BUTTON_CLASS, bx2); - efl_text_set(bt, "Factory"); - efl_event_callback_add(bt, EFL_INPUT_EVENT_CLICKED, _on_factory_bt_factory_clicked, en); - efl_gfx_hint_weight_set(bt, EFL_GFX_HINT_EXPAND, 0.0); - efl_pack(bx2, bt); - elm_object_focus_allow_set(bt, EINA_FALSE); - - efl_pack(bx, bx2); - efl_gfx_entity_size_set(win, EINA_SIZE2D(480, 320)); -} diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h index c78d105c5b..a9970e21ca 100644 --- a/src/lib/efl/Efl.h +++ b/src/lib/efl/Efl.h @@ -70,7 +70,7 @@ typedef struct tm Efl_Time; typedef struct _Efl_Text_Cursor_Handle Efl_Text_Cursor_Handle; typedef struct _Efl_Text_Cursor_Handle _Efl_Text_Cursor_Handle; -typedef struct _Efl_Text_Annotate_Annotation Efl_Text_Annotate_Annotation; +typedef struct _Efl_Text_Attribute_Handle Efl_Text_Attribute_Handle; #include "interfaces/efl_types.eot.h" @@ -211,7 +211,6 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command; #include "interfaces/efl_text_font.eo.h" #include "interfaces/efl_text_style.eo.h" #include "interfaces/efl_text_format.eo.h" -#include "interfaces/efl_text_annotate.eo.h" #include "interfaces/efl_text_markup.eo.h" #include "interfaces/efl_text_markup_util.eo.h" diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c index 71162b94fe..3e94adcb5e 100644 --- a/src/lib/efl/interfaces/efl_interfaces_main.c +++ b/src/lib/efl/interfaces/efl_interfaces_main.c @@ -24,7 +24,6 @@ #include "interfaces/efl_text_font.eo.c" #include "interfaces/efl_text_style.eo.c" #include "interfaces/efl_text_format.eo.c" -#include "interfaces/efl_text_annotate.eo.c" #include "interfaces/efl_text_markup.eo.c" #include "interfaces/efl_gfx_entity.eo.c" diff --git a/src/lib/efl/interfaces/efl_text_annotate.eo b/src/lib/efl/interfaces/efl_text_annotate.eo deleted file mode 100644 index 5ca1df8eb8..0000000000 --- a/src/lib/efl/interfaces/efl_text_annotate.eo +++ /dev/null @@ -1,137 +0,0 @@ -import efl_text_types; - -interface @beta Efl.Text_Annotate { - [[Cursor API - ]] - c_prefix: efl_text; - methods { - // Annotation - @property annotation { - [[A new format for $annotation. - - This will replace the format applied by $annotation with $format. - Assumes that $annotation is a handle for an existing annotation, - i.e. one that was added using @.annotation_insert to this object. - Otherwise, this will fail and return $false. - ]] - set { - return: bool; [[$true on success, $false otherwise.]] - } - get { - } - keys { - annotation: ptr(Efl.Text_Annotate_Annotation); [[Given annotation]] - } - values { - format: string; [[The new format for the given annotation]] - } - } - range_annotations_get @const { - [[Returns an iterator of all the handles in a range. - ]] - params { - @in start: ptr(const(Efl.Text_Cursor_Handle)); [[Start of range]] - @in end: ptr(const(Efl.Text_Cursor_Handle)); [[End of range]] - } - return: iterator @move; [[Handle of the Annotation]] - } - annotation_insert { - [[Inserts an annotation format in a specified range [$start, $end - 1]. - - The $format will be applied to the given range, and the $annotation - handle will be returned for further handling. - ]] - params { - @in start: ptr(Efl.Text_Cursor_Handle); [[Start of range]] - @in end: ptr(Efl.Text_Cursor_Handle); [[End of range]] - @in format: string; [[Annotation format]] - } - return: ptr(Efl.Text_Annotate_Annotation); [[Handle of inserted annotation]] - } - annotation_del { - [[Deletes given annotation. - - All formats applied by $annotation will be removed and it will be - deleted. - ]] - params { - @in annotation: ptr(Efl.Text_Annotate_Annotation); [[Annotation to be - removed]] - } - return: bool; [[$true on success, $false otherwise.]] - } - annotation_positions_get { - [[Sets given cursors to the start and end positions of the annotation. - - The cursors $start and $end will be set to the start and end - positions of the given annotation $annotation. - ]] - params { - @in annotation: ptr(const(Efl.Text_Annotate_Annotation)); [[Annotation - handle to query]] - @in start: ptr(Efl.Text_Cursor_Handle); [[Cursor to be set to the start - position of the annotation in the text]] - @in end: ptr(Efl.Text_Cursor_Handle); [[Cursor to be set to the end - position of the annotation in the text]] - } - } - annotation_is_item { - [[Whether this is an "item" type of annotation. Should be used before - querying the annotation's geometry, as only "item" annotations have - a geometry. - - see @.cursor_item_insert - see @.item_geometry_get - ]] - params { - annotation: ptr(Efl.Text_Annotate_Annotation); [[Given annotation]] - } - return: bool; [[$true if given annotation is an object item, $false otherwise]] - } - item_geometry_get { - [[Queries a given object item for its geometry. - - Note that the provided annotation should be an object item type. - ]] - params { - @in an: ptr(const(Efl.Text_Annotate_Annotation)); [[Given annotation to query]] - @out x: int; [[X coordinate of the annotation]] - @out y: int; [[Y coordinate of the annotation]] - @out w: int; [[Width of the annotation]] - @out h: int; [[Height of the annotation]] - } - return: bool; [[$true if given annotation is an object item, $false otherwise]] - } - // Cursor - @property cursor_item_annotation { - [[The object-item annotation at the cursor's position.]] - get { - } - values { - annotation: ptr(Efl.Text_Annotate_Annotation); [[Annotation]] - } - keys { - cur: ptr(Efl.Text_Cursor_Handle); [[Cursor object]] - } - } - cursor_item_insert { - [[Inserts a object item at specified position. - - This adds a placeholder to be queried by higher-level code, - which in turn place graphics on top of it. It essentially places an - OBJECT REPLACEMENT CHARACTER and set a special annotation to it. - ]] - params { - cur: ptr(Efl.Text_Cursor_Handle); [[Cursor object]] - @in item: string; [[Item key to be used in higher-up - code to query and decided what image, emoticon - etc. to embed.]] - @in format: string; [[Size format of the inserted item. - This hints how to size the item in the text.]] - } - return: ptr(Efl.Text_Annotate_Annotation); [[The annotation handle of the - inserted item.]] - } - } -} - diff --git a/src/lib/efl/interfaces/efl_text_types.eot b/src/lib/efl/interfaces/efl_text_types.eot index 64eb39329e..159975ea8c 100644 --- a/src/lib/efl/interfaces/efl_text_types.eot +++ b/src/lib/efl/interfaces/efl_text_types.eot @@ -22,6 +22,4 @@ struct @beta Efl.Ui.Text_Change_Info { merge: bool; [[$true if can be merged with the previous one. Used for example with insertion when something is already selected]] } -type @extern @beta Efl.Text_Annotate_Annotation: __undefined_type; [[EFL text annotations data structure]] - -struct @beta Efl.Text_Cursor_Handle; [[Opaque handle for Text cursors.]] +struct @extern @beta Efl.Text_Attribute_Handle; [[EFL text annotations data structure]] \ No newline at end of file diff --git a/src/lib/efl/interfaces/meson.build b/src/lib/efl/interfaces/meson.build index f45e743f94..a823e01b0c 100644 --- a/src/lib/efl/interfaces/meson.build +++ b/src/lib/efl/interfaces/meson.build @@ -44,7 +44,6 @@ pub_eo_files = [ 'efl_text_font.eo', 'efl_text_style.eo', 'efl_text_format.eo', - 'efl_text_annotate.eo', 'efl_text_markup.eo', 'efl_text_markup_util.eo', 'efl_gfx_stack.eo', diff --git a/src/lib/elementary/efl_ui_internal_text_interactive.c b/src/lib/elementary/efl_ui_internal_text_interactive.c index 5f623f83d5..608f6729fe 100644 --- a/src/lib/elementary/efl_ui_internal_text_interactive.c +++ b/src/lib/elementary/efl_ui_internal_text_interactive.c @@ -4,6 +4,7 @@ #include "elm_priv.h" #include "efl_ui_internal_text_interactive.h" +#include "efl_canvas_text_internal.h" #define MY_CLASS EFL_UI_INTERNAL_TEXT_INTERACTIVE_CLASS diff --git a/src/lib/elementary/efl_ui_text.c b/src/lib/elementary/efl_ui_text.c index e57fc9c23d..73f010e7af 100644 --- a/src/lib/elementary/efl_ui_text.c +++ b/src/lib/elementary/efl_ui_text.c @@ -153,7 +153,7 @@ struct _Anchor { Eo *obj; char *name; - Efl_Text_Annotate_Annotation *annotation; + Efl_Text_Attribute_Handle *annotation; Eina_List *rects; int gen; Eina_Bool item : 1; @@ -3180,13 +3180,12 @@ _efl_ui_text_efl_access_text_range_extents_get(const Eo *obj, Efl_Ui_Text_Data * } static Efl_Access_Text_Attribute* -_textblock_node_format_to_atspi_text_attr(const Eo *obj, - Efl_Text_Annotate_Annotation *annotation) +_textblock_node_format_to_atspi_text_attr(Efl_Text_Attribute_Handle *annotation) { Efl_Access_Text_Attribute *ret; const char *txt; - txt = efl_text_annotation_get(obj, annotation); + txt = efl_text_attribute_factory_attribute_get(annotation); if (!txt) return NULL; ret = calloc(1, sizeof(Efl_Access_Text_Attribute)); @@ -3202,34 +3201,35 @@ _textblock_node_format_to_atspi_text_attr(const Eo *obj, EOLIAN static Eina_Bool _efl_ui_text_efl_access_text_attribute_get(const Eo *obj, Efl_Ui_Text_Data *_pd EINA_UNUSED, const char *attr_name EINA_UNUSED, int *start_offset, int *end_offset, char **value) { - Evas_Textblock_Cursor *cur1, *cur2; + Efl_Text_Cursor *cur1, *cur2; Efl_Access_Text_Attribute *attr; Eina_Iterator *annotations; - Efl_Text_Annotate_Annotation *an; + Efl_Text_Attribute_Handle *an; - cur1 = evas_object_textblock_cursor_new(obj); + Eo *mobj = (Eo *)obj; + cur1 = efl_ui_text_cursor_create(mobj); if (!cur1) return EINA_FALSE; - cur2 = evas_object_textblock_cursor_new(obj); + cur2 = efl_ui_text_cursor_create(mobj); if (!cur2) { - evas_textblock_cursor_free(cur1); + efl_del(cur1); return EINA_FALSE; } - evas_textblock_cursor_pos_set(cur1, *start_offset); - evas_textblock_cursor_pos_set(cur2, *end_offset); + efl_text_cursor_position_set(cur1, *start_offset); + efl_text_cursor_position_set(cur2, *end_offset); - annotations = efl_text_range_annotations_get(obj, cur1, cur2); + annotations = efl_text_attribute_factory_range_attributes_get(cur1, cur2); - evas_textblock_cursor_free(cur1); - evas_textblock_cursor_free(cur2); + efl_del(cur1); + efl_del(cur2); if (!annotations) return EINA_FALSE; EINA_ITERATOR_FOREACH(annotations, an) { - attr = _textblock_node_format_to_atspi_text_attr(obj, an); + attr = _textblock_node_format_to_atspi_text_attr(an); if (!attr) continue; if (!strcmp(attr->name, attr_name)) { @@ -3247,35 +3247,35 @@ _efl_ui_text_efl_access_text_attribute_get(const Eo *obj, Efl_Ui_Text_Data *_pd EOLIAN static Eina_List* _efl_ui_text_efl_access_text_text_attributes_get(const Eo *obj, Efl_Ui_Text_Data *pd EINA_UNUSED, int *start_offset, int *end_offset) { - Evas_Textblock_Cursor *cur1, *cur2; + Efl_Text_Cursor *cur1, *cur2; Eina_List *ret = NULL; Efl_Access_Text_Attribute *attr; Eina_Iterator *annotations; - Efl_Text_Annotate_Annotation *an; - - cur1 = evas_object_textblock_cursor_new(obj); + Efl_Text_Attribute_Handle *an; + Eo *mobj = (Eo *)obj; + cur1 = efl_ui_text_cursor_create(mobj); if (!cur1) return NULL; - cur2 = evas_object_textblock_cursor_new(obj); + cur2 = efl_ui_text_cursor_create(mobj); if (!cur2) { - evas_textblock_cursor_free(cur1); + efl_del(cur1); return NULL; } - evas_textblock_cursor_pos_set(cur1, *start_offset); - evas_textblock_cursor_pos_set(cur2, *end_offset); + efl_text_cursor_position_set(cur1, *start_offset); + efl_text_cursor_position_set(cur2, *end_offset); - annotations = efl_text_range_annotations_get(obj, cur1, cur2); + annotations = efl_text_attribute_factory_range_attributes_get(cur1, cur2); - evas_textblock_cursor_free(cur1); - evas_textblock_cursor_free(cur2); + efl_del(cur1); + efl_del(cur2); if (!annotations) return NULL; EINA_ITERATOR_FOREACH(annotations, an) { - attr = _textblock_node_format_to_atspi_text_attr(obj, an); + attr = _textblock_node_format_to_atspi_text_attr(an); if (!attr) continue; ret = eina_list_append(ret, attr); } @@ -3291,7 +3291,7 @@ _efl_ui_text_efl_access_text_default_attributes_get(const Eo *obj, Efl_Ui_Text_D Efl_Access_Text_Attribute *attr; Efl_Text_Cursor *start, *end; Eina_Iterator *annotations; - Efl_Text_Annotate_Annotation *an; + Efl_Text_Attribute_Handle *an; /* Retrieve all annotations in the text. */ Eo *mobj = (Eo *)obj; /* XXX const */ @@ -3301,11 +3301,11 @@ _efl_ui_text_efl_access_text_default_attributes_get(const Eo *obj, Efl_Ui_Text_D efl_text_cursor_move(start, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_FIRST); efl_text_cursor_move(end, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_LAST); - annotations = efl_text_range_annotations_get(obj, efl_text_cursor_handle_get(start), efl_text_cursor_handle_get(end)); + annotations = efl_text_attribute_factory_range_attributes_get(start, end); EINA_ITERATOR_FOREACH(annotations, an) { - attr = _textblock_node_format_to_atspi_text_attr(obj, an); + attr = _textblock_node_format_to_atspi_text_attr(an); if (!attr) continue; ret = eina_list_append(ret, attr); } @@ -3659,20 +3659,20 @@ _anchor_format_parse(const char *item) } static Anchor * -_anchor_get(Eo *obj, Efl_Ui_Text_Data *sd, Efl_Text_Annotate_Annotation *an) +_anchor_get(Eo *obj, Efl_Ui_Text_Data *sd, Efl_Text_Attribute_Handle *an) { Anchor *anc; Eina_List *i; const char *str; - str = efl_text_annotation_get(obj, an); + str = efl_text_attribute_factory_attribute_get(an); EINA_LIST_FOREACH(sd->anchors, i, anc) { if (anc->annotation == an) break; } - if (!anc && (efl_text_annotation_is_item(obj, an) || !strncmp(str, "a ", 2))) + if (!anc && (efl_text_attribute_factory_attribute_is_item(an) || !strncmp(str, "a ", 2))) { const char *p; @@ -3681,7 +3681,7 @@ _anchor_get(Eo *obj, Efl_Ui_Text_Data *sd, Efl_Text_Annotate_Annotation *an) { anc->obj = obj; anc->annotation = an; - anc->item = efl_text_annotation_is_item(obj, an); + anc->item = efl_text_attribute_factory_attribute_is_item(an); p = strstr(str, "href="); if (p) { @@ -3705,7 +3705,7 @@ _anchors_update(Eo *obj, Efl_Ui_Text_Data *sd) Eina_Iterator *it; Eina_Position2D off; Efl_Text_Cursor *start, *end; - Efl_Text_Annotate_Annotation *an; + Efl_Text_Attribute_Handle *an; Eina_List *i, *ii; Anchor *anc; @@ -3723,7 +3723,7 @@ _anchors_update(Eo *obj, Efl_Ui_Text_Data *sd) efl_text_cursor_move(start, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_FIRST); efl_text_cursor_move(end, EFL_TEXT_CURSOR_MOVE_TYPE_PARAGRAPH_LAST); - it = efl_text_range_annotations_get(obj, efl_text_cursor_handle_get(start), efl_text_cursor_handle_get(end)); + it = efl_text_attribute_factory_range_attributes_get(start, end); efl_del(start); efl_del(end); @@ -3765,8 +3765,7 @@ _anchors_update(Eo *obj, Efl_Ui_Text_Data *sd) } rect = eina_list_data_get(anc->rects); - efl_text_item_geometry_get(sd->text_obj, - anc->annotation, &cx, &cy, &cw, &ch); + efl_text_attribute_factory_item_geometry_get(anc->annotation, &cx, &cy, &cw, &ch); efl_gfx_entity_size_set(rect->obj, EINA_SIZE2D(cw, ch)); efl_gfx_entity_position_set(rect->obj, EINA_POSITION2D(off.x + cx, off.y + cy)); @@ -3780,8 +3779,7 @@ _anchors_update(Eo *obj, Efl_Ui_Text_Data *sd) size_t count; start = efl_ui_text_cursor_create(obj); end = efl_ui_text_cursor_create(obj); - efl_text_annotation_positions_get(obj, anc->annotation, - efl_text_cursor_handle_get(start), efl_text_cursor_handle_get(end)); + efl_text_attribute_factory_attribute_cursors_get(anc->annotation, start, end); range = efl_text_cursor_range_geometry_get(start, end); count = eina_list_count(eina_iterator_container_get(range)); diff --git a/src/lib/evas/Efl_Canvas.h b/src/lib/evas/Efl_Canvas.h index a82d6a31cd..ed300478e0 100644 --- a/src/lib/evas/Efl_Canvas.h +++ b/src/lib/evas/Efl_Canvas.h @@ -84,6 +84,7 @@ extern "C" { */ #include #include +#include #include #include #include diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index 7b5db77653..56971d0a14 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -155,6 +155,7 @@ struct _Efl_Canvas_Object_Animation_Event * @{ */ #include "canvas/efl_text_cursor.eo.h" +#include "canvas/efl_text_attribute_factory.eo.h" #include "canvas/efl_canvas_text.eo.h" #include "canvas/efl_canvas_text_factory.eo.h" /** diff --git a/src/lib/evas/Evas_Internal.h b/src/lib/evas/Evas_Internal.h index d631cdcde5..0fa833c362 100644 --- a/src/lib/evas/Evas_Internal.h +++ b/src/lib/evas/Evas_Internal.h @@ -318,6 +318,17 @@ EWAPI extern const Efl_Event_Description _EFL_ANIMATION_PLAYER_EVENT_PRE_STARTED */ EAPI Eina_Bool evas_textblock_cursor_at_cluster_as_single_glyph(Evas_Textblock_Cursor *cur,Eina_Bool forward); + + + +/*Attribute Factory Internal function*/ +EAPI const char * efl_text_attribute_factory_attribute_get(Efl_Text_Attribute_Handle *annotation); +EAPI Eina_Iterator * efl_text_attribute_factory_range_attributes_get(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end); +EAPI void efl_text_attribute_factory_attribute_cursors_get(const Efl_Text_Attribute_Handle *handle, Efl_Text_Cursor *start, Efl_Text_Cursor *end); +EAPI void efl_text_attribute_factory_remove(Efl_Text_Attribute_Handle *annotation); +EAPI Eina_Bool efl_text_attribute_factory_attribute_is_item(Efl_Text_Attribute_Handle *annotation); +EAPI Eina_Bool efl_text_attribute_factory_item_geometry_get(const Efl_Text_Attribute_Handle *annotation, int *x, int *y, int *w, int *h); + #ifdef __cplusplus } #endif diff --git a/src/lib/evas/canvas/efl_canvas_text.eo b/src/lib/evas/canvas/efl_canvas_text.eo index 1e53fdbc93..10c43c71e8 100644 --- a/src/lib/evas/canvas/efl_canvas_text.eo +++ b/src/lib/evas/canvas/efl_canvas_text.eo @@ -3,7 +3,7 @@ import efl_text_types; class @beta Efl.Canvas.Text extends Efl.Canvas.Object implements Efl.Text, Efl.Canvas.Filter.Internal, Efl.Text_Font, Efl.Text_Style, Efl.Text_Format, - Efl.Text_Annotate, Efl.Text_Markup, Efl.Ui.I18n + Efl.Text_Markup, Efl.Ui.I18n { [[Efl canvas text class]] methods { @@ -236,15 +236,6 @@ class @beta Efl.Canvas.Text extends Efl.Canvas.Object implements Efl.Text, Efl.Text_Format.tabstops { get; set; } Efl.Text_Format.password { get; set; } Efl.Text_Format.replacement_char { get; set; } - Efl.Text_Annotate.annotation { set; get; } - Efl.Text_Annotate.range_annotations_get; - Efl.Text_Annotate.annotation_insert; - Efl.Text_Annotate.annotation_del; - Efl.Text_Annotate.annotation_is_item; - Efl.Text_Annotate.item_geometry_get; - Efl.Text_Annotate.annotation_positions_get; - Efl.Text_Annotate.cursor_item_annotation { get; } - Efl.Text_Annotate.cursor_item_insert; Efl.Text_Markup.markup { set; get; } Efl.Gfx.Entity.scale { set; } } diff --git a/src/lib/evas/canvas/efl_canvas_text_internal.h b/src/lib/evas/canvas/efl_canvas_text_internal.h index 64659ec887..9871008d5a 100644 --- a/src/lib/evas/canvas/efl_canvas_text_internal.h +++ b/src/lib/evas/canvas/efl_canvas_text_internal.h @@ -83,10 +83,10 @@ typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format; typedef struct _Evas_Textblock_Selection_Iterator Evas_Textblock_Selection_Iterator; /** * @internal - * @typedef Efl_Text_Annotate_Annotation_Iterator + * @typedef Efl_Text_Attribute_Handle_Iterator * A textblock annotation iterator. */ -typedef struct _Efl_Text_Annotate_Annotation_Iterator Efl_Text_Annotate_Annotation_Iterator; +typedef struct _Efl_Text_Attribute_Handle_Iterator Efl_Text_Attribute_Handle_Iterator; /** * @internal * @typedef Efl_Canvas_Text_Filter @@ -143,7 +143,7 @@ struct _Evas_Textblock_Node_Format const char *format; /**< Cached, parsed and translated version of orig_format. */ const char *orig_format; /**< Original format information. */ Evas_Object_Textblock_Node_Text *text_node; /**< The text node it's pointing to. */ - Efl_Text_Annotate_Annotation *annotation; /**< Pointer to this node's annotation handle (if exists). */ + Efl_Text_Attribute_Handle *annotation; /**< Pointer to this node's annotation handle (if exists). */ size_t offset; /**< Offset from the last format node of the same text. */ struct { unsigned char l, r, t, b; @@ -166,8 +166,17 @@ struct _Efl_Text_Cursor_Handle Eina_Bool changed : 1; }; +struct _Efl_Text_Attribute_Handle +{ + EINA_INLIST; + Evas_Object *obj; + Evas_Object_Textblock_Node_Format *start_node, *end_node; + Eina_Bool is_item : 1; /**< indicates it is an item/object placeholder */ +}; + void evas_textblock_cursor_line_jump_by(Efl_Text_Cursor_Handle *cur, int by); int _cursor_text_append(Efl_Text_Cursor_Handle *cur, const char *text); +void evas_textblock_async_block(Evas_Object *eo_object); // Used in Efl.Text.Cursor, where multible objects can have same handle. @@ -177,6 +186,76 @@ evas_textblock_cursor_ref(Efl_Text_Cursor_Handle *cursor, Eo * cursor_obj); // Used in Efl.Text.Cursor, where multible objects can have same handle. void evas_textblock_cursor_unref(Efl_Text_Cursor_Handle *cursor, Eo * cursor_obj); +void _evas_textblock_cursor_init(Efl_Text_Cursor_Handle *cur, const Evas_Object *tb); + +/*Annoation Functions*/ +/** + * @internal + * Returns the value of the current data of list node, + * and goes to the next list node. + * + * @param it the iterator. + * @param data the data of the current list node. + * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE. + */ +Eina_Bool +_evas_textblock_annotation_iterator_next(Efl_Text_Attribute_Handle_Iterator *it, void **data); + +/** + * @internal + * Frees the annotation iterator. + * @param it the iterator to free + * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE. + */ +void +_evas_textblock_annotation_iterator_free(Efl_Text_Attribute_Handle_Iterator *it); + + +/** + * @internal + * Creates newly allocated iterator associated to a list. + * @param list The list. + * @return If the memory cannot be allocated, NULL is returned. + * Otherwise, a valid iterator is returned. + */ +Eina_Iterator * +_evas_textblock_annotation_iterator_new(Eina_List *list); + + + +void +_textblock_cursor_pos_at_fnode_set(Efl_Text_Cursor_Handle *cur, + Evas_Object_Textblock_Node_Format *fnode); + + +Eina_Bool +_evas_textblock_annotations_set(Evas_Object *eo_obj, + Efl_Text_Attribute_Handle *an, + Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, + const char *format, Eina_Bool is_item); + +void +_evas_textblock_annotation_remove(Evas_Object *eo_obj, Efl_Canvas_Text_Data *o, + Efl_Text_Attribute_Handle *an, Eina_Bool remove_nodes, Eina_Bool invalidate); + +void +_evas_textblock_annotations_clear(const Evas_Object *eo_obj); + + +Efl_Text_Attribute_Handle * +_evas_textblock_annotations_insert(Eo *eo_obj, + Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, + const char *format, Eina_Bool is_item); + + +Eina_Inlist * +_evas_textblock_annotations_get(Evas_Object *o); + +void +_evas_textblock_annotations_node_format_remove(Evas_Object *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment); + +void +_evas_textblock_relayout_if_needed(Evas_Object *o); #ifdef EAPI # undef EAPI @@ -213,7 +292,24 @@ evas_textblock_cursor_unref(Efl_Text_Cursor_Handle *cursor, Eo * cursor_obj); */ EAPI void efl_text_cursor_text_object_set(Eo *cursor, Eo *canvas_text_obj, Eo *text_obj); + +/** + * Internally sets cursor handle(legacy textblock cursor) into cursor object. + * + * @param obj the cursor object. + * @param handle the text cursor handle. + */ +EAPI void efl_text_cursor_handle_set(Eo *obj, Efl_Text_Cursor_Handle *handle); + +/** + * Internally gets cursor handle(legacy textblock cursor) from cursor object. + * + * @param obj the cursor object. + * @return the internal text cursor handle. + */ +EAPI Efl_Text_Cursor_Handle *efl_text_cursor_handle_get(const Eo *obj); + #undef EAPI #define EAPI -#endif \ No newline at end of file +#endif//#ifndef _EFL_CANVAS_TEXT_INTERNAL_H diff --git a/src/lib/evas/canvas/efl_text_attribute_factory.c b/src/lib/evas/canvas/efl_text_attribute_factory.c new file mode 100644 index 0000000000..2e01ee8cae --- /dev/null +++ b/src/lib/evas/canvas/efl_text_attribute_factory.c @@ -0,0 +1,133 @@ +//#define EFL_BETA_API_SUPPORT +#include "evas_common_private.h" +#include "evas_private.h" +#include "efl_canvas_text_internal.h" +#include "efl_text_cursor.eo.h" + +#define MY_CLASS EFL_TEXT_ATTRIBUTE_FACTORY_CLASS + +typedef struct +{ + +} Efl_Text_Attribute_Factory_Data; + +EOLIAN static void +_efl_text_attribute_factory_attribute_insert(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end, const char *format) +{ + EINA_SAFETY_ON_TRUE_RETURN(!efl_text_cursor_handle_get(start) || + !efl_text_cursor_handle_get(end) || + efl_text_cursor_handle_get(start)->obj != efl_text_cursor_handle_get(end)->obj); + + Eo *eo_obj= efl_text_cursor_handle_get(start)->obj; + evas_textblock_async_block(eo_obj); + + _evas_textblock_annotations_insert(eo_obj, efl_text_cursor_handle_get(start), efl_text_cursor_handle_get(end), format, + EINA_FALSE); + efl_event_callback_legacy_call(eo_obj, EFL_CANVAS_TEXT_EVENT_CHANGED, NULL); +} + +EOLIAN static unsigned int +_efl_text_attribute_factory_attribute_clear(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end) +{ + unsigned int ret = 0; + Eina_Iterator *annotations; + Efl_Text_Attribute_Handle *an; + annotations = efl_text_attribute_factory_range_attributes_get(start, end); + + if (!annotations) return ret; + + EINA_ITERATOR_FOREACH(annotations, an) + { + ret++; + efl_text_attribute_factory_remove(an); + } + eina_iterator_free(annotations); + + return ret; +} + +const char * +efl_text_attribute_factory_attribute_get(Efl_Text_Attribute_Handle *annotation) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!annotation || !(annotation->obj), NULL); + + return (annotation->start_node ? annotation->start_node->format : NULL); +} + +Eina_Iterator * +efl_text_attribute_factory_range_attributes_get(const Efl_Text_Cursor *start, const Efl_Text_Cursor *end) +{ + Eina_List *lst = NULL; + Efl_Text_Attribute_Handle *it; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(!efl_text_cursor_handle_get(start) || + !efl_text_cursor_handle_get(end) || + efl_text_cursor_handle_get(start)->obj != efl_text_cursor_handle_get(end)->obj, NULL); + + Eina_Inlist *annotations = _evas_textblock_annotations_get(efl_text_cursor_handle_get(start)->obj); + + EINA_INLIST_FOREACH(annotations, it) + { + Efl_Text_Cursor_Handle start2, end2; + _evas_textblock_cursor_init(&start2, efl_text_cursor_handle_get(start)->obj); + _evas_textblock_cursor_init(&end2, efl_text_cursor_handle_get(start)->obj); + + if (!it->start_node || !it->end_node) continue; + _textblock_cursor_pos_at_fnode_set(&start2, it->start_node); + _textblock_cursor_pos_at_fnode_set(&end2, it->end_node); + evas_textblock_cursor_char_prev(&end2); + if (!((evas_textblock_cursor_compare(&start2, efl_text_cursor_handle_get(end)) > 0) || + (evas_textblock_cursor_compare(&end2, efl_text_cursor_handle_get(start)) < 0))) + { + lst = eina_list_append(lst, it); + } + } + return _evas_textblock_annotation_iterator_new(lst); +} + +void +efl_text_attribute_factory_attribute_cursors_get(const Efl_Text_Attribute_Handle *handle, Efl_Text_Cursor *start, Efl_Text_Cursor *end) +{ + EINA_SAFETY_ON_TRUE_RETURN (!handle || !(handle->obj)); + + efl_text_cursor_text_object_set(start, handle->obj, handle->obj); + efl_text_cursor_text_object_set(end, handle->obj, handle->obj); + _textblock_cursor_pos_at_fnode_set(efl_text_cursor_handle_get(start), handle->start_node); + _textblock_cursor_pos_at_fnode_set(efl_text_cursor_handle_get(end), handle->end_node); +} + +void +efl_text_attribute_factory_remove(Efl_Text_Attribute_Handle *annotation) +{ + EINA_SAFETY_ON_TRUE_RETURN (!annotation || !(annotation->obj)); + + evas_textblock_async_block(annotation->obj); + _evas_textblock_annotation_remove(annotation->obj, NULL, annotation, EINA_TRUE, EINA_TRUE); +} + +Eina_Bool +efl_text_attribute_factory_attribute_is_item(Efl_Text_Attribute_Handle *annotation) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!annotation || !(annotation->obj), EINA_FALSE); + + return annotation->is_item; +} + +Eina_Bool +efl_text_attribute_factory_item_geometry_get(const Efl_Text_Attribute_Handle *annotation, int *x, int *y, int *w, int *h) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!annotation || !(annotation->obj), EINA_FALSE); + + Efl_Text_Cursor_Handle cur; + + Eo *eo_obj = annotation->obj; + Evas_Object_Protected_Data *obj_data = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + evas_object_async_block(obj_data); + _evas_textblock_relayout_if_needed(eo_obj); + + _evas_textblock_cursor_init(&cur, eo_obj); + _textblock_cursor_pos_at_fnode_set(&cur, annotation->start_node); + return evas_textblock_cursor_format_item_geometry_get(&cur, x, y, w, h); +} + +#include "efl_text_attribute_factory.eo.c" diff --git a/src/lib/evas/canvas/efl_text_attribute_factory.eo b/src/lib/evas/canvas/efl_text_attribute_factory.eo new file mode 100644 index 0000000000..52bc871880 --- /dev/null +++ b/src/lib/evas/canvas/efl_text_attribute_factory.eo @@ -0,0 +1,37 @@ +import efl_text_types; + +abstract @beta Efl.Text.Attribute.Factory extends Efl.Object { + [[Attribute factory API to manage text attributes. + Use it to insert and remove style attributes (font, size, color, ...) using @Efl.Text.Cursor on EFL Widgets. + + Attributes can be assigned to character ranges, selected using two @Efl.Text.Cursor instances. + Cursor instances are already bound to a text object so there's no need to provide it to this class. + Style is specified using format strings as described in Efl.Canvas.Text.style_set. + + There is no need to instantiate this class. Use directly the @.attribute_insert and @.attribute_clear static methods.]] + methods { + attribute_insert @static { + [[Inserts an attribute format in a specified range [$start, $end - 1]. + + The $format will be applied to the given range. + The passed cursors must belong to same textObject, else insertion will be ignored. + Passed format parameter uses same format as style in Efl.Canvas.Text.style_set. + ]] + params { + start: const(Efl.Text.Cursor); [[Start of range.]] + end: const(Efl.Text.Cursor); [[End of range.]] + format: string; [[Attribute format.]] + } + } + + attribute_clear @static { + [[Clear(remove) attributes at specified range [$start, $end - 1]. + ]] + params { + start: const(Efl.Text.Cursor); [[Start of range.]] + end: const(Efl.Text.Cursor); [[End of range.]] + } + return: uint; [[Number of removed attributes.]] + } + } +} diff --git a/src/lib/evas/canvas/efl_text_cursor.c b/src/lib/evas/canvas/efl_text_cursor.c index cfa87d7bba..238c9529b3 100644 --- a/src/lib/evas/canvas/efl_text_cursor.c +++ b/src/lib/evas/canvas/efl_text_cursor.c @@ -406,9 +406,10 @@ _efl_text_cursor_range_delete(Eo *obj EINA_UNUSED, Efl_Text_Cursor_Data *pd, Efl evas_textblock_cursor_range_delete(pd->handle, efl_text_cursor_handle_get(cur2)); } -EOLIAN static void -_efl_text_cursor_handle_set(Eo *obj, Efl_Text_Cursor_Data *pd, Efl_Text_Cursor_Handle *handle) +EAPI void +efl_text_cursor_handle_set(Eo *obj, Efl_Text_Cursor_Handle *handle) { + Efl_Text_Cursor_Data *pd = efl_data_scope_get(obj, MY_CLASS); if (handle == pd->handle) return; @@ -422,9 +423,10 @@ _efl_text_cursor_handle_set(Eo *obj, Efl_Text_Cursor_Data *pd, Efl_Text_Cursor_H } } -EOLIAN static Efl_Text_Cursor_Handle * -_efl_text_cursor_handle_get(const Eo *obj EINA_UNUSED, Efl_Text_Cursor_Data *pd) +EAPI Efl_Text_Cursor_Handle * +efl_text_cursor_handle_get(const Eo *obj) { + Efl_Text_Cursor_Data *pd = efl_data_scope_get(obj, MY_CLASS); return pd->handle; } diff --git a/src/lib/evas/canvas/efl_text_cursor.eo b/src/lib/evas/canvas/efl_text_cursor.eo index 0485eb9e06..01c77fc688 100644 --- a/src/lib/evas/canvas/efl_text_cursor.eo +++ b/src/lib/evas/canvas/efl_text_cursor.eo @@ -215,19 +215,6 @@ class @beta Efl.Text.Cursor extends Efl.Object implements Efl.Duplicate{ } } - @property handle { - [[This method should rarely be used by users. It gives you a lightweight handle to a cursor. - - You can either replace the handle to change the object this is working on, or get it for caching - - The handle is freed when the object is freed if set, but otherwise it remains under the control of the caller.]] - set { } - get { } - values { - handle: Efl.Text_Cursor_Handle @by_ref; [[The handle of the cursor object.]] - } - } - @property text_object { [[The text object this cursor is associated with.]] get { } diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index e854d167e2..98cfc9f1f2 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -419,13 +419,6 @@ typedef struct _User_Style_Entry Evas_Textblock_Style *st; const char *key; } User_Style_Entry; -struct _Efl_Text_Annotate_Annotation -{ - EINA_INLIST; - Evas_Object *obj; - Evas_Object_Textblock_Node_Format *start_node, *end_node; - Eina_Bool is_item : 1; /**< indicates it is an item/object placeholder */ -}; #define _FMT(x) (o->default_format.format.x) #define _FMT_INFO(x) (o->default_format.info.x) @@ -461,7 +454,7 @@ struct _Evas_Object_Textblock Eina_List *anchors_item; Eina_List *obstacles; Eina_List *hyphen_items; /* Hyphen items storage to free when clearing lines */ - Efl_Text_Annotate_Annotation *annotations; /* All currently applied annotations on the text. */ + Efl_Text_Attribute_Handle *annotations; /* All currently applied annotations on the text. */ int last_w, last_h; struct { int l, r, t, b; @@ -524,7 +517,7 @@ struct _Evas_Textblock_Selection_Iterator Eina_List *current; /**< Current node in loop. */ }; -struct _Efl_Text_Annotate_Annotation_Iterator +struct _Efl_Text_Attribute_Handle_Iterator { Eina_Iterator iterator; /**< Eina Iterator. */ Eina_List *list; /**< Head of list. */ @@ -604,12 +597,9 @@ static void _evas_textblock_changed(Efl_Canvas_Text_Data *o, Evas_Object *eo_obj static void _evas_textblock_invalidate_all(Efl_Canvas_Text_Data *o); static void _evas_textblock_cursors_update_offset(const Efl_Text_Cursor_Handle *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset); static void _evas_textblock_cursors_set_node(Efl_Canvas_Text_Data *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node); -static void _evas_textblock_annotations_clear(Efl_Canvas_Text_Data *o); -static void _evas_textblock_annotation_remove(Efl_Canvas_Text_Data *o, Efl_Text_Annotate_Annotation *an, Eina_Bool remove_nodes); static Eina_Bool _evas_textblock_cursor_format_is_visible_get(const Efl_Text_Cursor_Handle *cur); static void _evas_textblock_cursor_at_format_set(Efl_Text_Cursor_Handle *cur, const Evas_Object_Textblock_Node_Format *fmt); -static void _evas_textblock_cursor_init(Efl_Text_Cursor_Handle *cur, const Evas_Object *tb); static Evas_Filter_Program *_format_filter_program_get(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Format *fmt); static const char *_textblock_format_node_from_style_tag(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Node_Format *fnode, const char *format, size_t format_len); #ifdef HAVE_HYPHEN @@ -619,7 +609,6 @@ static const char *_textblock_format_node_from_style_tag(Efl_Canvas_Text_Data *o static Eina_Bool _evas_textblock_cursor_format_append(Efl_Text_Cursor_Handle *cur, const char *format, Evas_Object_Textblock_Node_Format **_fnode, Eina_Bool is_item); EAPI Eina_Bool evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur); -static void _evas_textblock_cursor_init(Efl_Text_Cursor_Handle *cur, const Evas_Object *tb); static Eina_Bool _evas_textblock_cursor_format_is_visible_get(const Efl_Text_Cursor_Handle *cur); static void _find_layout_item_line_match(Evas_Object *eo_obj, Evas_Object_Textblock_Node_Text *n, size_t pos, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr); static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_at_pos_get(const Efl_Text_Cursor_Handle *cur); @@ -803,7 +792,7 @@ _nodes_clear(const Evas_Object *eo_obj) Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); /* First, clear all annotations that may have spawned format nodes. */ - _evas_textblock_annotations_clear(o); + _evas_textblock_annotations_clear(eo_obj); while (o->text_nodes) { @@ -6966,6 +6955,13 @@ _relayout_if_needed(const Evas_Object *eo_obj, Efl_Canvas_Text_Data *o) return EINA_TRUE; } +void +_evas_textblock_relayout_if_needed(Evas_Object *eo_obj) +{ + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + _relayout_if_needed(eo_obj, o); +} + /** * @internal * Find the layout item and line that match the text node and position passed. @@ -8953,7 +8949,7 @@ _find_layout_item_match(const Efl_Text_Cursor_Handle *cur, Evas_Object_Textblock return previous_format; } -static void +void _evas_textblock_cursor_init(Efl_Text_Cursor_Handle *cur, const Evas_Object *tb) { memset(cur, 0, sizeof(Efl_Text_Cursor_Handle)); @@ -10082,7 +10078,7 @@ _evas_textblock_node_format_remove_matching(Efl_Canvas_Text_Data *o, if (_FORMAT_IS_CLOSER_OF( fnode->orig_format, fstr + 1, fstr_len - 1)) { - Efl_Text_Annotate_Annotation *an = fmt->annotation; + Efl_Text_Attribute_Handle *an = fmt->annotation; fnode = eina_list_data_get(i); formats = eina_list_remove_list(formats, i); @@ -10092,7 +10088,7 @@ _evas_textblock_node_format_remove_matching(Efl_Canvas_Text_Data *o, if (an) { _evas_textblock_annotation_remove( - o, an, EINA_FALSE); + NULL, o, an, EINA_FALSE, EINA_FALSE); } break; } @@ -10190,6 +10186,13 @@ _evas_textblock_node_format_remove(Efl_Canvas_Text_Data *o, Evas_Object_Textbloc _evas_textblock_node_format_free(o, n); } +void +_evas_textblock_annotations_node_format_remove(Evas_Object *eo_obj, Evas_Object_Textblock_Node_Format *n, int visual_adjustment) +{ + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + _evas_textblock_node_format_remove(o, n, visual_adjustment); +} + /** * @internal * Sets all the offsets of the format nodes between start and end in the text @@ -15219,6 +15222,12 @@ _efl_canvas_text_efl_text_text_get(const Eo *eo_obj, Efl_Canvas_Text_Data *o) return o->utf8; } +void evas_textblock_async_block(Evas_Object *eo_obj) +{ + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + ASYNC_BLOCK; +} + /** * @internal * Returns the value of the current data of list node, @@ -15228,8 +15237,8 @@ _efl_canvas_text_efl_text_text_get(const Eo *eo_obj, Efl_Canvas_Text_Data *o) * @param data the data of the current list node. * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE. */ -static Eina_Bool -_evas_textblock_annotation_iterator_next(Efl_Text_Annotate_Annotation_Iterator *it, void **data) +Eina_Bool +_evas_textblock_annotation_iterator_next(Efl_Text_Attribute_Handle_Iterator *it, void **data) { if (!it->current) return EINA_FALSE; @@ -15246,8 +15255,8 @@ _evas_textblock_annotation_iterator_next(Efl_Text_Annotate_Annotation_Iterator * * @param it the iterator to free * @return EINA_FALSE if unsuccessful. Otherwise, returns EINA_TRUE. */ -static void -_evas_textblock_annotation_iterator_free(Efl_Text_Annotate_Annotation_Iterator *it) +void +_evas_textblock_annotation_iterator_free(Efl_Text_Attribute_Handle_Iterator *it) { EINA_MAGIC_SET(&it->iterator, 0); it->current = NULL; @@ -15267,7 +15276,7 @@ _evas_textblock_annotation_iterator_new(Eina_List *list) { Evas_Textblock_Selection_Iterator *it; - it = calloc(1, sizeof(Efl_Text_Annotate_Annotation_Iterator)); + it = calloc(1, sizeof(Efl_Text_Attribute_Handle_Iterator)); if (!it) return NULL; EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); @@ -15283,24 +15292,24 @@ _evas_textblock_annotation_iterator_new(Eina_List *list) return &it->iterator; } -static void -_textblock_cursor_pos_at_fnode_set(const Eo *eo_obj EINA_UNUSED, - Efl_Text_Cursor_Handle *cur, +void +_textblock_cursor_pos_at_fnode_set(Efl_Text_Cursor_Handle *cur, Evas_Object_Textblock_Node_Format *fnode) { cur->node = fnode->text_node; cur->pos = _evas_textblock_node_format_pos_get(fnode); } -static Eina_Bool -_textblock_annotation_set(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o, - Efl_Text_Annotate_Annotation *an, +Eina_Bool +_evas_textblock_annotations_set(Eo *eo_obj, + Efl_Text_Attribute_Handle *an, Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, const char *format, Eina_Bool is_item) { int len; char *buf; Evas_Textblock_Node_Format *fnode; + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); if (an->is_item) { @@ -15332,60 +15341,20 @@ _textblock_annotation_set(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o, return EINA_TRUE; } -EOLIAN static const char * -_efl_canvas_text_efl_text_annotate_annotation_get(const Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o EINA_UNUSED, - Efl_Text_Annotate_Annotation *annotation) +Eina_Inlist * +_evas_textblock_annotations_get(Eo *eo_obj) { - if (!annotation || (annotation->obj != eo_obj)) - { - ERR("Used invalid handle or of a different object"); - return NULL; - } - - return (annotation->start_node ? annotation->start_node->format : NULL); + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + return (Eina_Inlist*)o->annotations; } -EOLIAN static Eina_Bool -_efl_canvas_text_efl_text_annotate_annotation_set(Eo *eo_obj, - Efl_Canvas_Text_Data *o, Efl_Text_Annotate_Annotation *annotation, - const char *format) +void +_evas_textblock_annotation_remove(Eo *eo_obj, Efl_Canvas_Text_Data *o, + Efl_Text_Attribute_Handle *an, Eina_Bool remove_nodes, Eina_Bool invalidate) { - ASYNC_BLOCK; - Efl_Text_Cursor_Handle start, end; - Eina_Bool ret = EINA_TRUE; + if (!o) + o = efl_data_scope_get(eo_obj, MY_CLASS); - if (!annotation || (annotation->obj != eo_obj)) - { - ERR("Used invalid handle or of a different object"); - return EINA_FALSE; - } - - if (!annotation->start_node || !annotation->end_node) return EINA_FALSE; - if (!format || (format[0] == '\0')) return EINA_FALSE; - - _evas_textblock_cursor_init(&start, eo_obj); - _evas_textblock_cursor_init(&end, eo_obj); - - /* XXX: Not efficient but works and saves code */ - _textblock_cursor_pos_at_fnode_set(eo_obj, &start, annotation->start_node); - _textblock_cursor_pos_at_fnode_set(eo_obj, &end, annotation->end_node); - - _evas_textblock_node_format_remove(o, annotation->start_node, 0); - _evas_textblock_node_format_remove(o, annotation->end_node, 0); - - if (!_textblock_annotation_set(eo_obj, o, annotation, &start, &end, format, - EINA_FALSE)) - { - ret = EINA_FALSE; - } - - return ret; -} - -static void -_evas_textblock_annotation_remove(Efl_Canvas_Text_Data *o, - Efl_Text_Annotate_Annotation *an, Eina_Bool remove_nodes) -{ if (remove_nodes) { if (an->is_item) @@ -15393,64 +15362,53 @@ _evas_textblock_annotation_remove(Efl_Canvas_Text_Data *o, /* Remove the OBJ character along with the cursor. */ Efl_Text_Cursor_Handle cur; _evas_textblock_cursor_init(&cur, an->obj); - _textblock_cursor_pos_at_fnode_set(an->obj, &cur, an->start_node); + _textblock_cursor_pos_at_fnode_set(&cur, an->start_node); evas_textblock_cursor_char_delete(&cur); return; // 'an' should be deleted after char deletion. } _evas_textblock_node_format_remove(o, an->start_node, 0); _evas_textblock_node_format_remove(o, an->end_node, 0); } - o->annotations = (Efl_Text_Annotate_Annotation *) + o->annotations = (Efl_Text_Attribute_Handle *) eina_inlist_remove(EINA_INLIST_GET(o->annotations), EINA_INLIST_GET(an)); free(an); + if (invalidate) + { + o->format_changed = EINA_TRUE; + + //XXX: It's a workaround. The underlying problem is that only new format + // nodes are checks when their respective text nodes are invalidated (see + // _format_changes_invalidate_text_nodes). Complete removal of the format + // nodes was not handled properly (as formats could only be removed via + // text changes e.g. deleting characters). + _evas_textblock_invalidate_all(o); + + _evas_textblock_changed(o, eo_obj); + } } -static void -_evas_textblock_annotations_clear(Efl_Canvas_Text_Data *o) +void +_evas_textblock_annotations_clear(const Eo *eo_obj) { - Efl_Text_Annotate_Annotation *an; + Efl_Text_Attribute_Handle *an; + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); EINA_INLIST_FREE(o->annotations, an) { - _evas_textblock_annotation_remove(o, an, EINA_TRUE); + _evas_textblock_annotation_remove(NULL, o, an, EINA_TRUE, EINA_FALSE); } } -EOLIAN static Eina_Bool -_efl_canvas_text_efl_text_annotate_annotation_del(Eo *eo_obj EINA_UNUSED, - Efl_Canvas_Text_Data *o, Efl_Text_Annotate_Annotation *annotation) -{ - ASYNC_BLOCK; - if (!annotation || (annotation->obj != eo_obj)) - { - ERR("Used invalid handle or of a different object"); - return EINA_FALSE; - } - - _evas_textblock_annotation_remove(o, annotation, EINA_TRUE); - o->format_changed = EINA_TRUE; - - //XXX: It's a workaround. The underlying problem is that only new format - // nodes are checks when their respective text nodes are invalidated (see - // _format_changes_invalidate_text_nodes). Complete removal of the format - // nodes was not handled properly (as formats could only be removed via - // text changes e.g. deleting characters). - _evas_textblock_invalidate_all(o); - - _evas_textblock_changed(o, eo_obj); - return EINA_TRUE; -} - -static Efl_Text_Annotate_Annotation * -_textblock_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o, - Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, +Efl_Text_Attribute_Handle * +_evas_textblock_annotations_insert(Eo *eo_obj, Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, const char *format, Eina_Bool is_item) { - Efl_Text_Annotate_Annotation *ret = NULL; + Efl_Text_Attribute_Handle *ret = NULL; Eina_Strbuf *buf; Eina_Bool first = EINA_TRUE; const char *item; + Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); if (!format || (format[0] == '\0') || evas_textblock_cursor_compare(start, end) > 0) @@ -15489,15 +15447,15 @@ _textblock_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o, format = eina_strbuf_string_get(buf); if (format && (format[0] != '\0')) { - ret = calloc(1, sizeof(Efl_Text_Annotate_Annotation)); + ret = calloc(1, sizeof(Efl_Text_Attribute_Handle)); ret->obj = eo_obj; - o->annotations = (Efl_Text_Annotate_Annotation *) + o->annotations = (Efl_Text_Attribute_Handle *) eina_inlist_append(EINA_INLIST_GET(o->annotations), EINA_INLIST_GET(ret)); - _textblock_annotation_set(eo_obj, o, ret, start, end, format, is_item); + _evas_textblock_annotations_set(eo_obj, ret, start, end, format, is_item); ret->is_item = is_item; _evas_textblock_changed(o, eo_obj); } @@ -15507,123 +15465,6 @@ _textblock_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o, return ret; } -EOLIAN static Efl_Text_Annotate_Annotation * -_efl_canvas_text_efl_text_annotate_annotation_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o, - Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end, - const char *format) -{ - ASYNC_BLOCK; - Efl_Text_Annotate_Annotation *ret; - - ret = _textblock_annotation_insert(eo_obj, o, start, end, format, - EINA_FALSE); - efl_event_callback_legacy_call(eo_obj, EFL_CANVAS_TEXT_EVENT_CHANGED, NULL); - return ret; -} - -EOLIAN static Eina_Iterator * -_efl_canvas_text_efl_text_annotate_range_annotations_get(const Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED, - const Evas_Textblock_Cursor *start, const Evas_Textblock_Cursor *end) -{ - Eina_List *lst = NULL; - Efl_Text_Annotate_Annotation *it; - - EINA_INLIST_FOREACH(o->annotations, it) - { - Efl_Text_Cursor_Handle start2, end2; - _evas_textblock_cursor_init(&start2, eo_obj); - _evas_textblock_cursor_init(&end2, eo_obj); - - if (!it->start_node || !it->end_node) continue; - _textblock_cursor_pos_at_fnode_set(eo_obj, &start2, it->start_node); - _textblock_cursor_pos_at_fnode_set(eo_obj, &end2, it->end_node); - evas_textblock_cursor_char_prev(&end2); - if (!((evas_textblock_cursor_compare(&start2, end) > 0) || - (evas_textblock_cursor_compare(&end2, start) < 0))) - { - lst = eina_list_append(lst, it); - } - } - return _evas_textblock_annotation_iterator_new(lst); -} - -EOLIAN static Efl_Text_Annotate_Annotation * -_efl_canvas_text_efl_text_annotate_cursor_item_insert(Eo *eo_obj, - Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Handle *cur, - const char *item, const char *format) -{ - Eina_Strbuf *buf = eina_strbuf_new(); - - eina_strbuf_append_printf(buf, "%s href=%s", format, item); - - Efl_Text_Annotate_Annotation *ret = - _textblock_annotation_insert(cur->obj, o, cur, cur, - eina_strbuf_string_get(buf), EINA_TRUE); - eina_strbuf_free(buf); - efl_event_callback_legacy_call(eo_obj, EFL_CANVAS_TEXT_EVENT_CHANGED, NULL); - return ret; -} - -EOLIAN static Efl_Text_Annotate_Annotation * -_efl_canvas_text_efl_text_annotate_cursor_item_annotation_get(const Eo *eo_obj EINA_UNUSED, - Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Handle *cur) -{ - Eina_Iterator *it; - Efl_Text_Annotate_Annotation *data, *ret = NULL; - - it = efl_text_range_annotations_get(cur->obj, - cur, cur); - EINA_ITERATOR_FOREACH(it, data) - { - if (data->is_item) - { - ret = data; - break; - } - } - eina_iterator_free(it); - return ret; -} - -EOLIAN static Eina_Bool -_efl_canvas_text_efl_text_annotate_annotation_is_item(Eo *eo_obj EINA_UNUSED, - Efl_Canvas_Text_Data *o EINA_UNUSED, - Efl_Text_Annotate_Annotation *annotation) -{ - if (!annotation || (annotation->obj != eo_obj)) - { - ERR("Used invalid handle or of a different object"); - return EINA_FALSE; - } - - return annotation->is_item; -} - -EOLIAN static Eina_Bool -_efl_canvas_text_efl_text_annotate_item_geometry_get(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED, - const Efl_Text_Annotate_Annotation *an, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) -{ - Efl_Text_Cursor_Handle cur; - - Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); - evas_object_async_block(obj); - _relayout_if_needed(eo_obj, o); - - _evas_textblock_cursor_init(&cur, eo_obj); - _textblock_cursor_pos_at_fnode_set(eo_obj, &cur, an->start_node); - return _evas_textblock_cursor_format_item_geometry_get(&cur, cx, cy, cw, ch); -} - -EOLIAN static void -_efl_canvas_text_efl_text_annotate_annotation_positions_get(Eo *eo_obj, - Efl_Canvas_Text_Data *o EINA_UNUSED, - const Efl_Text_Annotate_Annotation *annotation, - Efl_Text_Cursor_Handle *start, Efl_Text_Cursor_Handle *end) -{ - _textblock_cursor_pos_at_fnode_set(eo_obj, start, annotation->start_node); - _textblock_cursor_pos_at_fnode_set(eo_obj, end, annotation->end_node); -} - static void _canvas_text_format_changed(Eo *eo_obj, Efl_Canvas_Text_Data *o) { diff --git a/src/lib/evas/canvas/meson.build b/src/lib/evas/canvas/meson.build index d9e6798b9b..07dd725b28 100644 --- a/src/lib/evas/canvas/meson.build +++ b/src/lib/evas/canvas/meson.build @@ -56,6 +56,7 @@ pub_eo_files = [ 'efl_canvas_event_grabber.eo', 'efl_text_cursor.eo', 'efl_canvas_text.eo', + 'efl_text_attribute_factory.eo', 'efl_canvas_object_animation.eo', ] @@ -208,7 +209,8 @@ evas_src += files([ 'evas_canvas3d_node_callback.h', 'evas_canvas3d_eet.c', 'efl_canvas_object_animation.c', - 'efl_text_cursor.c' + 'efl_text_cursor.c', + 'efl_text_attribute_factory.c' ]) evas_include_directories += include_directories('.') diff --git a/src/tests/evas/evas_test_textblock.c b/src/tests/evas/evas_test_textblock.c index 860c674397..163d403ef2 100644 --- a/src/tests/evas/evas_test_textblock.c +++ b/src/tests/evas/evas_test_textblock.c @@ -37,6 +37,7 @@ static const char *style_buf = Evas_Object *tb; \ Evas_Textblock_Style *st; \ Evas_Textblock_Cursor *cur; \ + Efl_Text_Cursor *cur_obj; \ evas = EVAS_TEST_INIT_EVAS(); \ evas_font_hinting_set(evas, EVAS_FONT_HINTING_AUTO); \ tb = evas_object_textblock_add(evas); \ @@ -48,6 +49,9 @@ static const char *style_buf = fail_if(strcmp(style_buf, evas_textblock_style_get(st))); \ evas_object_textblock_style_set(tb, st); \ cur = evas_object_textblock_cursor_new(tb); \ + cur_obj =efl_canvas_text_cursor_create(tb);\ + (void) cur_obj;\ + (void) cur;\ do \ { \ } \ @@ -58,6 +62,7 @@ do \ { \ evas_textblock_cursor_free(cur); \ evas_object_del(tb); \ + efl_del(cur_obj); \ evas_textblock_style_free(st); \ evas_free(evas); \ } \ @@ -4304,43 +4309,6 @@ EFL_START_TEST(evas_textblock_text_iface) } EFL_END_TEST; -static void -_test_check_annotation(Evas_Object *tb, - size_t start_pos, size_t end_pos, - size_t len, const char **formats) -{ - Efl_Text_Annotate_Annotation *an; - Efl_Text_Cursor_Handle *start, *end; - - start = evas_object_textblock_cursor_new(tb); - end = evas_object_textblock_cursor_new(tb); - - evas_textblock_cursor_pos_set(start, start_pos); - evas_textblock_cursor_pos_set(end, end_pos); - - Eina_Iterator *it = - efl_text_range_annotations_get(tb, start, end); - - evas_textblock_cursor_free(start); - evas_textblock_cursor_free(end); - - size_t i = 0; - EINA_ITERATOR_FOREACH(it, an) - { - const char *fmt = efl_text_annotation_get(tb, - an); - ck_assert_msg((i < len), - "No formats to check but current annotation is: %s\n", fmt); - ck_assert_str_eq(fmt, *formats); - formats++; - i++; - } - ck_assert_msg((i == len), - "Expected next format (index %lu): %s, but reached end of annotations\n", - i, *formats); - - eina_iterator_free(it); -} #define _COMP_STR(...) ((const char *[]) { __VA_ARGS__ }) #define _CREATE_PARAMS(X) (sizeof(X) / sizeof(X[0])), (X) @@ -4349,11 +4317,10 @@ _test_check_annotation(Evas_Object *tb, EFL_START_TEST(evas_textblock_annotation) { START_TB_TEST(); - Efl_Text_Annotate_Annotation *an, *an2; - Efl_Text_Cursor_Handle *start, *end; + Efl_Text_Cursor *start, *end; - start = evas_object_textblock_cursor_new(tb); - end = evas_object_textblock_cursor_new(tb); + start = efl_canvas_text_cursor_create(tb); + end = efl_canvas_text_cursor_create(tb); const char *buf = "This text will check annotation." @@ -4365,167 +4332,21 @@ EFL_START_TEST(evas_textblock_annotation) efl_text_set(tb, buf); /* Check some trivial cases */ - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 3); - ck_assert(!efl_text_annotation_insert(tb, start, end, NULL)); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 3); - ck_assert(!efl_text_annotation_insert(tb, start, end, "")); - evas_textblock_cursor_pos_set(start, 1); - evas_textblock_cursor_pos_set(end, 0); - ck_assert(!efl_text_annotation_insert(tb, start, end, "color=#fff")); - /* Insert and check correct positions */ - _test_check_annotation(tb, 0, 10, _COMP_PARAMS()); + efl_text_cursor_position_set(start, 0); + efl_text_cursor_position_set(end, 3); + efl_text_attribute_factory_attribute_insert(start, end, "font_size=80"); + efl_text_cursor_position_set(start, 1); + efl_text_cursor_position_set(end, 2); + efl_text_attribute_factory_attribute_insert(start, end, "font=arial"); + efl_text_cursor_position_set(start, 2); + efl_text_cursor_position_set(end, 3); + efl_text_attribute_factory_attribute_insert(start, end, "color=#fff"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 3); - efl_text_annotation_insert(tb, start, end, "font_weight=bold"); - _test_check_annotation(tb, 0, 2, _COMP_PARAMS("font_weight=bold")); - _test_check_annotation(tb, 0, 2, _COMP_PARAMS("font_weight=bold")); - _test_check_annotation(tb, 4, 10, _COMP_PARAMS()); - - evas_textblock_cursor_pos_set(start, 50); - evas_textblock_cursor_pos_set(end, 60); - efl_text_annotation_insert(tb, start, end, "color=#0ff"); - _test_check_annotation(tb, 0, 49, _COMP_PARAMS("font_weight=bold")); - _test_check_annotation(tb, 0, 50, _COMP_PARAMS("font_weight=bold", "color=#0ff")); - _test_check_annotation(tb, 0, 55, _COMP_PARAMS("font_weight=bold", "color=#0ff")); - _test_check_annotation(tb, 0, 59, _COMP_PARAMS("font_weight=bold", "color=#0ff")); - _test_check_annotation(tb, 40, 50, _COMP_PARAMS("color=#0ff")); - _test_check_annotation(tb, 40, 51, _COMP_PARAMS("color=#0ff")); - _test_check_annotation(tb, 40, 61, _COMP_PARAMS("color=#0ff")); - _test_check_annotation(tb, 59, 60, _COMP_PARAMS("color=#0ff")); - _test_check_annotation(tb, 60, 61, _COMP_PARAMS()); - - /* See that annotation's positions are updated as text is inserted */ - efl_text_set(tb, "hello"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 2); - an = efl_text_annotation_insert(tb, start, end, "color=#fff"); - _test_check_annotation(tb, 2, 3, _COMP_PARAMS()); - evas_textblock_cursor_pos_set(cur, 0); - evas_textblock_cursor_text_append(cur, "a"); - _test_check_annotation(tb, 2, 3, _COMP_PARAMS("color=#fff")); - _test_check_annotation(tb, 3, 4, _COMP_PARAMS()); - - /* Replace annotations's format */ - efl_text_annotation_set(tb, an, "font_size=14"); - _test_check_annotation(tb, 2, 3, _COMP_PARAMS("font_size=14")); - _test_check_annotation(tb, 3, 4, _COMP_PARAMS()); - - efl_text_set(tb, "hello world"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 2); - an = efl_text_annotation_insert(tb, start, end, "color=#fff"); - evas_textblock_cursor_pos_set(start, 2); - evas_textblock_cursor_pos_set(end, 3); - an2 = efl_text_annotation_insert(tb, start, end, "font_size=14"); - _test_check_annotation(tb, 0, 1, _COMP_PARAMS("color=#fff")); - _test_check_annotation(tb, 2, 3, _COMP_PARAMS("font_size=14")); - _test_check_annotation(tb, 0, 3, _COMP_PARAMS("color=#fff", "font_size=14")); - efl_text_annotation_set(tb, an, "font_size=10"); - efl_text_annotation_set(tb, an2, "color=#000"); - _test_check_annotation(tb, 2, 3, _COMP_PARAMS("color=#000")); - _test_check_annotation(tb, 0, 1, _COMP_PARAMS("font_size=10")); - _test_check_annotation(tb, 0, 3, _COMP_PARAMS("font_size=10", "color=#000")); - - /* Delete annotations directly */ - efl_text_set(tb, "hello world"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 2); - an = efl_text_annotation_insert(tb, start, end, "color=#fff"); - evas_textblock_cursor_pos_set(start, 3); - evas_textblock_cursor_pos_set(end, 4); - an2 = efl_text_annotation_insert(tb, start, end, "font_size=14"); - efl_text_annotation_del(tb, an); - _test_check_annotation(tb, 0, 3, _COMP_PARAMS("font_size=14")); - efl_text_annotation_del(tb, an2); - _test_check_annotation(tb, 0, 3, _COMP_PARAMS()); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 1); - an = efl_text_annotation_insert(tb, start, end, "color=#fff"); - _test_check_annotation(tb, 1, 3, _COMP_PARAMS()); - _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff")); - efl_text_annotation_del(tb, an); - _test_check_annotation(tb, 0, 0, _COMP_PARAMS()); - - /* Check blocking of "item formats" */ - efl_text_set(tb, "hello world"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 1); - efl_text_annotation_insert(tb, start, end, "ps"); - _test_check_annotation(tb, 0, 1, _COMP_PARAMS()); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 1); - efl_text_annotation_insert(tb, start, end, "color=#fff"); - _test_check_annotation(tb, 0, 1, _COMP_PARAMS("color=#fff")); - evas_textblock_cursor_pos_set(start, 2); - evas_textblock_cursor_pos_set(end, 3); - efl_text_annotation_insert(tb, start, end, "br"); - evas_textblock_cursor_pos_set(start, 6); - evas_textblock_cursor_pos_set(end, 7); - efl_text_annotation_insert(tb, start, end, "item"); - _test_check_annotation(tb, 0, 8, _COMP_PARAMS("color=#fff")); - - /* Check "item" annotations */ - efl_text_set(tb, "abcd"); - evas_textblock_cursor_pos_set(cur, 4); - an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16"); - _test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16 href=")); - - /* Check that format is not extended if it's an "object item" */ - evas_textblock_cursor_pos_set(cur, 5); - evas_textblock_cursor_text_prepend(cur, "a"); - _test_check_annotation(tb, 5, 7, _COMP_PARAMS()); - _test_check_annotation(tb, 0, 3, _COMP_PARAMS()); - - /* Remove annotation of "item" also removes the OBJ character */ - { - int blen, len; - evas_textblock_cursor_pos_set(cur, 5); - blen = evas_textblock_cursor_paragraph_text_length_get(cur); - efl_text_annotation_del(tb, an); - len = evas_textblock_cursor_paragraph_text_length_get(cur); - ck_assert_int_eq(len, blen - 1); - _test_check_annotation(tb, 0, 5, _COMP_PARAMS()); - } - - /* Using annotations with new text API */ - efl_text_set(tb, "hello"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 5); - efl_text_annotation_insert(tb, start, end, "color=#fff"); - _test_check_annotation(tb, 3, 3, _COMP_PARAMS("color=#fff")); - /* Old API */ - evas_textblock_cursor_pos_set(cur, 5); - evas_textblock_cursor_text_prepend(cur, "a"); - _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff")); - _test_check_annotation(tb, 5, 5, _COMP_PARAMS()); - - /* Specific case with PS */ - efl_text_set(tb, "hello\nworld"); - evas_textblock_cursor_pos_set(start, 0); - evas_textblock_cursor_pos_set(end, 5); - efl_text_annotation_insert(tb, start, end, "color=#fff"); - _test_check_annotation(tb, 4, 4, _COMP_PARAMS("color=#fff")); - evas_textblock_cursor_pos_set(cur, 4); - /* Cursor position is now: hello|\nworld */ - evas_textblock_cursor_text_prepend(cur, "a"); - _test_check_annotation(tb, 0, 0, _COMP_PARAMS("color=#fff")); - _test_check_annotation(tb, 5, 5, _COMP_PARAMS("color=#fff")); - - /* Test getting of object item */ - evas_textblock_cursor_pos_set(cur, 4); - an = efl_text_cursor_item_annotation_get(tb, cur); - ck_assert(!an); - an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16"); - evas_textblock_cursor_pos_set(cur, 4); - an = efl_text_cursor_item_annotation_get(tb, cur); - ck_assert(an); - ck_assert_str_eq("size=16x16 href=", efl_text_annotation_get(tb, an)); - - END_TB_TEST(); + efl_text_cursor_position_set(start, 0); + efl_text_cursor_position_set(end, 3); + unsigned int count = efl_text_attribute_factory_attribute_clear(start, end); + fail_if(count != 3); } EFL_END_TEST; @@ -4543,7 +4364,7 @@ EFL_END_TEST; fail_if(!efl_canvas_text_style_get(txt, NULL) || \ strcmp(style_buf, efl_canvas_text_style_get(txt, NULL))); \ cur_obj = efl_canvas_text_cursor_create(txt);\ - cur = efl_text_cursor_handle_get(cur_obj); \ + cur = evas_object_textblock_cursor_new(txt); \ fail_if(!cur); \ do \ { \ @@ -4554,6 +4375,7 @@ while (0) do \ { \ efl_del(cur_obj); \ + evas_textblock_cursor_free(cur); \ efl_del(txt); \ evas_free(evas); \ } \