diff --git a/AUTHORS b/AUTHORS index 8db85383b2..b283554660 100644 --- a/AUTHORS +++ b/AUTHORS @@ -77,6 +77,14 @@ Eo -- Tom Hacohen +Cedric Bail + +Ector +----- + +Cedric Bail +Jorge Luis Zapata Muga +Jose O Gonzalez Evas ---- diff --git a/NOTES b/NOTES new file mode 100644 index 0000000000..bb565c266b --- /dev/null +++ b/NOTES @@ -0,0 +1,31 @@ +Evas_VG_Color_List + - List of color + +Evas_VG_Gradient + gradient_type_set (radial, linear) + color_list_set + point_set (i, x, y) + +Evas_VG_Fill + - abstract + +Evas_VG_Root_Node (only one at the top, Evas_VG_Container) + +Evas_VG_Shape + fill + stroke_scale + stroke_color + stroke_fill + stroke_width + stroke_location + stroke_dash(length[], gap[]) + stroke_marker(Evas_VG_Shape *) + stroke_cap + stroke_join + +Evas_VG_Filter + ?? + +bounds_get -> Evas_VG_Node + +Eina_Matrix3 diff --git a/configure.ac b/configure.ac index 8c27ca465c..9f4b269a6e 100644 --- a/configure.ac +++ b/configure.ac @@ -1212,9 +1212,54 @@ EFL_PLATFORM_DEPEND([EFL], [evil]) EFL_INTERNAL_DEPEND_PKG([EFL], [eina]) EFL_INTERNAL_DEPEND_PKG([EFL], [eo]) +EFL_ADD_LIBS([EFL], [-lm]) + EFL_LIB_END([Efl]) #### End of Efl +#### Ector + +EFL_LIB_START([Ector]) + + +### Default values + +### Additional options to configure + +### Checks for programs + +### Checks for libraries + +## Compatibility layers + +EFL_PLATFORM_DEPEND([ECTOR], [evil]) + +EFL_INTERNAL_DEPEND_PKG([ECTOR], [eina]) +EFL_INTERNAL_DEPEND_PKG([ECTOR], [eo]) +EFL_INTERNAL_DEPEND_PKG([ECTOR], [efl]) + +EFL_ADD_LIBS([ECTOR], [-lm]) + +EFL_EVAL_PKGS([ECTOR]) + +### Checks for header files + +### Checks for types + +### Checks for structures + +### Checks for compiler characteristics + +### Checks for linker characteristics + +### Checks for library functions + +### Check availability + +EFL_LIB_END([ECTOR]) + +#### End of Ector + #### Evas EFL_LIB_START([Evas]) @@ -1676,6 +1721,7 @@ EFL_INTERNAL_DEPEND_PKG([EVAS], [eet]) EFL_INTERNAL_DEPEND_PKG([EVAS], [eina]) EFL_INTERNAL_DEPEND_PKG([EVAS], [efl]) EFL_INTERNAL_DEPEND_PKG([EVAS], [emile]) +EFL_INTERNAL_DEPEND_PKG([EVAS], [ector]) EFL_ADD_LIBS([EVAS], [-lm]) @@ -4524,6 +4570,7 @@ pc/ecore-imf-evas.pc pc/ecore-audio.pc pc/ecore-audio-cxx.pc pc/ecore-avahi.pc +pc/ector.pc pc/embryo.pc pc/eio.pc pc/eldbus.pc @@ -4691,6 +4738,7 @@ fi echo "Ecore_Audio.....: ${efl_lib_optional_ecore_audio} (${features_ecore_audio})" echo "Ecore_Avahi.....: yes (${features_ecore_avahi})" echo "Ecore_Evas......: yes (${features_ecore_evas})" +echo "Ector...........: yes" echo "Eeze............: ${efl_lib_optional_eeze} (${features_eeze})" echo "EPhysics........: ${efl_lib_optional_ephysics}" echo "Edje............: yes (${features_edje})" diff --git a/pc/.gitignore b/pc/.gitignore index 4aaaa1359c..25049d8fa9 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -17,6 +17,7 @@ /ecore-win32.pc /ecore-x.pc /ecore.pc +/ector.pc /edje.pc /eet.pc /eeze.pc diff --git a/pc/ector.pc.in b/pc/ector.pc.in new file mode 100644 index 0000000000..43d2db10f4 --- /dev/null +++ b/pc/ector.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ector +Description: Enlightenned retained mode drawing library +Requires.private: @requirements_pc_ector@ +Version: @VERSION@ +Libs: -L${libdir} -lector +Libs.private: @requirements_libs_ector@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ector-@VMAJ@ diff --git a/src/Makefile.am b/src/Makefile.am index 580911a31a..77403a7d87 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ BUILT_SOURCES = EOLIAN_FLAGS = -I$(srcdir)\ -I$(srcdir)/lib/eo \ + -I$(srcdir)/lib/ector \ -I$(srcdir)/lib/evas/canvas \ -I$(srcdir)/lib/edje \ -I$(srcdir)/lib/efl/interfaces \ @@ -34,6 +35,7 @@ include Makefile_Efl.am include Makefile_Emile.am include Makefile_Eet.am include Makefile_Eolian.am +include Makefile_Ector.am include Makefile_Evas.am include Makefile_Ecore.am include Makefile_Ecore_Con.am diff --git a/src/Makefile_Ecore_Evas.am b/src/Makefile_Ecore_Evas.am index 1be87466e9..e61aa2ad75 100644 --- a/src/Makefile_Ecore_Evas.am +++ b/src/Makefile_Ecore_Evas.am @@ -282,7 +282,8 @@ endif bin_PROGRAMS += \ bin/ecore_evas/ecore_evas_convert \ -bin/ecore_evas/eetpack +bin/ecore_evas/eetpack \ +bin/ecore_evas/ecore_evas_svg bin_ecore_evas_ecore_evas_convert_SOURCES = bin/ecore_evas/ecore_evas_convert.c bin_ecore_evas_ecore_evas_convert_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_EVAS_CFLAGS@ @@ -293,3 +294,8 @@ bin_ecore_evas_eetpack_SOURCES = bin/ecore_evas/eetpack.c bin_ecore_evas_eetpack_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_EVAS_CFLAGS@ @EINA_CFLAGS@ @EET_CFLAGS@ @EVAS_CFLAGS@ bin_ecore_evas_eetpack_LDADD = @USE_ECORE_EVAS_LIBS@ @USE_EINA_LIBS@ @USE_EET_LIBS@ @USE_EVAS_LIBS@ bin_ecore_evas_eetpack_DEPENDENCIES = @USE_ECORE_EVAS_INTERNAL_LIBS@ @USE_EINA_INTERNAL_LIBS@ @USE_EET_INTERNAL_LIBS@ @USE_EVAS_INTERNAL_LIBS@ + +bin_ecore_evas_ecore_evas_svg_SOURCES = bin/ecore_evas/ecore_evas_svg.c +bin_ecore_evas_ecore_evas_svg_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_EVAS_CFLAGS@ +bin_ecore_evas_ecore_evas_svg_LDADD = @USE_ECORE_EVAS_LIBS@ +bin_ecore_evas_ecore_evas_svg_DEPENDENCIES = @USE_ECORE_EVAS_INTERNAL_LIBS@ diff --git a/src/Makefile_Ector.am b/src/Makefile_Ector.am new file mode 100644 index 0000000000..a39c3f7cca --- /dev/null +++ b/src/Makefile_Ector.am @@ -0,0 +1,138 @@ + +### Library +ector_eolian_files = \ + lib/ector/ector_generic_surface.eo \ + lib/ector/ector_renderer_generic_base.eo \ + lib/ector/ector_renderer_generic_shape.eo \ + lib/ector/ector_renderer_generic_gradient.eo \ + lib/ector/ector_renderer_generic_gradient_radial.eo \ + lib/ector/ector_renderer_generic_gradient_linear.eo + +# Handle cairo backend +ector_eolian_files += \ + lib/ector/cairo/ector_cairo_surface.eo \ + lib/ector/cairo/ector_renderer_cairo_base.eo \ + lib/ector/cairo/ector_renderer_cairo_shape.eo \ + lib/ector/cairo/ector_renderer_cairo_gradient_linear.eo \ + lib/ector/cairo/ector_renderer_cairo_gradient_radial.eo + +# Handle FreeType rasterizer +ector_eolian_files += \ + lib/ector/software/ector_software_surface.eo \ + lib/ector/software/ector_renderer_software_base.eo \ + lib/ector/software/ector_renderer_software_shape.eo \ + lib/ector/software/ector_renderer_software_gradient_radial.eo \ + lib/ector/software/ector_renderer_software_gradient_linear.eo + +ector_eolian_c = $(ector_eolian_files:%.eo=%.eo.c) +ector_eolian_h = $(ector_eolian_files:%.eo=%.eo.h) + +BUILT_SOURCES += \ + $(ector_eolian_c) \ + $(ector_eolian_h) + +CLEANFILES += \ + $(ector_eolian_c) \ + $(ector_eolian_h) + +ectoreolianfilesdir = $(datadir)/eolian/include/ector-@VMAJ@ +ectoreolianfiles_DATA = $(ector_eolian_files) + +EXTRA_DIST += $(ectoreolianfiles_DATA) + +lib_LTLIBRARIES += lib/ector/libector.la + +installed_ectormainheadersdir = $(includedir)/ector-@VMAJ@ +dist_installed_ectormainheaders_DATA = \ +lib/ector/Ector.h \ +lib/ector/ector_util.h \ +lib/ector/ector_surface.h \ +lib/ector/ector_renderer.h \ +lib/ector/cairo/Ector_Cairo.h \ +lib/ector/software/Ector_Software.h + +# And the generic implementation + +lib_ector_libector_la_SOURCES = \ +lib/ector/ector_main.c \ +lib/ector/ector_surface.c \ +lib/ector/ector_renderer_shape.c \ +lib/ector/ector_renderer_base.c \ +lib/ector/ector_renderer_gradient.c \ +lib/ector/ector_renderer_gradient_radial.c \ +lib/ector/ector_renderer_gradient_linear.c + +# And now the cairo backend +lib_ector_libector_la_SOURCES += \ +lib/ector/cairo/ector_renderer_cairo_gradient_linear.c \ +lib/ector/cairo/ector_renderer_cairo_gradient_radial.c \ +lib/ector/cairo/ector_renderer_cairo_shape.c \ +lib/ector/cairo/ector_renderer_cairo_base.c \ +lib/ector/cairo/ector_cairo_surface.c + +# And the Freetype rasterizer + +lib_ector_libector_la_SOURCES += \ +lib/ector/software/ector_renderer_software_gradient_linear.c \ +lib/ector/software/ector_renderer_software_gradient_radial.c \ +lib/ector/software/ector_renderer_software_shape.c \ +lib/ector/software/ector_software_gradient.c \ +lib/ector/software/ector_software_rasterizer.c \ +lib/ector/software/ector_software_surface.c \ +lib/ector/software/sw_ft_math.c \ +lib/ector/software/sw_ft_raster.c \ +lib/ector/software/sw_ft_stroker.c + +lib_ector_libector_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/lib/ector \ +-I$(top_builddir)/src/lib/ector/cairo \ +-I$(top_builddir)/src/lib/ector/software \ +@ECTOR_CFLAGS@ \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/ector\" \ +@VALGRIND_CFLAGS@ + +lib_ector_libector_la_LIBADD = @ECTOR_LIBS@ @DL_LIBS@ +lib_ector_libector_la_DEPENDENCIES = @ECTOR_INTERNAL_LIBS@ @DL_INTERNAL_LIBS@ +lib_ector_libector_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ + +### Unit tests + +if EFL_ENABLE_TESTS + +check_PROGRAMS += tests/ector/ector_suite tests/ector/cxx_compile_test +TESTS += tests/ector/ector_suite + +tests_ector_ector_suite_SOURCES = \ +tests/ector/ector_suite.c \ +tests/ector/ector_suite.h \ +tests/ector/ector_test_init.c + +tests_ector_cxx_compile_test_SOURCES = tests/ector/cxx_compile_test.cxx +tests_ector_cxx_compile_test_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECTOR_CFLAGS@ +tests_ector_cxx_compile_test_LDADD = @USE_ECTOR_LIBS@ +tests_ector_cxx_compile_test_DEPENDENCIES = @USE_ECTOR_INTERNAL_LIBS@ + + +tests_ector_ector_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/ector\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/ector\" \ +-DTESTS_BUILD_DIR=PACKAGE_BUILD_DIR \ +@CHECK_CFLAGS@ \ +@ECTOR_CFLAGS@ +tests_ector_ector_suite_LDADD = @CHECK_LIBS@ @USE_ECTOR_LIBS@ +tests_ector_ector_suite_DEPENDENCIES = @USE_ECTOR_INTERNAL_LIBS@ + +endif + +EXTRA_DIST += \ +lib/ector/ector_private.h \ +lib/ector/cairo/ector_cairo_private.h \ +lib/ector/software/ector_blend_private.h \ +lib/ector/software/ector_software_private.h \ +lib/ector/software/sw_ft_math.h \ +lib/ector/software/sw_ft_raster.h \ +lib/ector/software/sw_ft_stroker.h \ +lib/ector/software/sw_ft_types.h diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am index 5533dce961..b65dafc406 100644 --- a/src/Makefile_Efl.am +++ b/src/Makefile_Efl.am @@ -4,7 +4,15 @@ efl_eolian_files = \ lib/efl/interfaces/efl_image.eo \ lib/efl/interfaces/efl_player.eo \ lib/efl/interfaces/efl_text.eo \ - lib/efl/interfaces/efl_text_properties.eo + lib/efl/interfaces/efl_text_properties.eo \ + lib/efl/interfaces/efl_gfx_base.eo \ + lib/efl/interfaces/efl_gfx_stack.eo \ + lib/efl/interfaces/efl_gfx_fill.eo \ + lib/efl/interfaces/efl_gfx_view.eo \ + lib/efl/interfaces/efl_gfx_shape.eo \ + lib/efl/interfaces/efl_gfx_gradient_base.eo \ + lib/efl/interfaces/efl_gfx_gradient_linear.eo \ + lib/efl/interfaces/efl_gfx_gradient_radial.eo efl_eolian_files_h = $(efl_eolian_files:%.eo=%.eo.h) efl_eolian_files_c = $(efl_eolian_files:%.eo=%.eo.c) @@ -27,7 +35,10 @@ efleolianfiles_DATA = $(efl_eolian_files) lib_LTLIBRARIES += lib/efl/libefl.la -lib_efl_libefl_la_SOURCES = lib/efl/interfaces/efl_interfaces_main.c +lib_efl_libefl_la_SOURCES = \ +lib/efl/interfaces/efl_interfaces_main.c \ +lib/efl/interfaces/efl_gfx_shape.c + lib_efl_libefl_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_srcdir)/src/lib/efl @EFL_CFLAGS@ lib_efl_libefl_la_LIBADD = @EFL_LIBS@ lib_efl_libefl_la_DEPENDENCIES = @EFL_INTERNAL_LIBS@ @@ -39,7 +50,8 @@ dist_installed_eflheaders_DATA = \ lib/efl/Efl.h installed_eflinterfacesdir = $(includedir)/efl-@VMAJ@/interfaces -nodist_installed_eflinterfaces_DATA = $(efl_eolian_files_h) +nodist_installed_eflinterfaces_DATA = \ +$(efl_eolian_files_h) if HAVE_ELUA diff --git a/src/Makefile_Efl_Cxx.am b/src/Makefile_Efl_Cxx.am index 1ddd25dc49..fbcc5632ca 100644 --- a/src/Makefile_Efl_Cxx.am +++ b/src/Makefile_Efl_Cxx.am @@ -8,7 +8,15 @@ generated_efl_cxx_bindings = \ lib/efl/interfaces/efl_image.eo.hh \ lib/efl/interfaces/efl_player.eo.hh \ lib/efl/interfaces/efl_text.eo.hh \ - lib/efl/interfaces/efl_text_properties.eo.hh + lib/efl/interfaces/efl_text_properties.eo.hh \ + lib/efl/interfaces/efl_gfx_base.eo.hh \ + lib/efl/interfaces/efl_gfx_stack.eo.hh \ + lib/efl/interfaces/efl_gfx_fill.eo.hh \ + lib/efl/interfaces/efl_gfx_view.eo.hh \ + lib/efl/interfaces/efl_gfx_shape.eo.hh \ + lib/efl/interfaces/efl_gfx_gradient_base.eo.hh \ + lib/efl/interfaces/efl_gfx_gradient_linear.eo.hh \ + lib/efl/interfaces/efl_gfx_gradient_radial.eo.hh lib/efl/Efl.hh: $(generated_efl_cxx_bindings) @echo @ECHO_E@ "#ifndef EFL_CXX_EDJE_HH\n#define EFL_CXX_EDJE_HH\n" > $(top_builddir)/src/lib/efl/Efl.hh diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index 6341cd1268..ae41cc8090 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -85,7 +85,9 @@ lib/eina/eina_tmpstr.h \ lib/eina/eina_alloca.h \ lib/eina/eina_cow.h \ lib/eina/eina_inline_unicode.x \ -lib/eina/eina_thread_queue.h +lib/eina/eina_thread_queue.h \ +lib/eina/eina_matrix.h \ +lib/eina/eina_quad.h # Will be back for developper after 1.2. # lib/eina/eina_model.h @@ -144,7 +146,9 @@ lib/eina/eina_xattr.c \ lib/eina/eina_share_common.h \ lib/eina/eina_private.h \ lib/eina/eina_strbuf_common.h \ -lib/eina/eina_thread_queue.c +lib/eina/eina_thread_queue.c \ +lib/eina/eina_matrix.c \ +lib/eina/eina_quad.c # Will be back for developper after 1.2 # lib/eina/eina_model.c \ diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index bd3d377757..af8343ff9d 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -31,7 +31,15 @@ evas_eolian_files = \ lib/evas/canvas/evas_3d_mesh.eo\ lib/evas/canvas/evas_3d_node.eo\ lib/evas/canvas/evas_3d_scene.eo\ - lib/evas/canvas/evas_3d_object.eo + lib/evas/canvas/evas_3d_object.eo \ + lib/evas/canvas/evas_vg.eo \ + lib/evas/canvas/efl_vg_base.eo \ + lib/evas/canvas/efl_vg_container.eo \ + lib/evas/canvas/efl_vg_shape.eo \ + lib/evas/canvas/efl_vg_root_node.eo \ + lib/evas/canvas/efl_vg_gradient.eo \ + lib/evas/canvas/efl_vg_gradient_radial.eo \ + lib/evas/canvas/efl_vg_gradient_linear.eo evas_eolian_c = $(evas_eolian_files:%.eo=%.eo.c) evas_eolian_h = $(evas_eolian_files:%.eo=%.eo.h) \ @@ -76,7 +84,8 @@ lib/evas/include/evas_macros.h \ lib/evas/include/evas_mmx.h \ lib/evas/include/evas_common_private.h \ lib/evas/include/evas_blend_ops.h \ -lib/evas/include/evas_filter.h +lib/evas/include/evas_filter.h \ +lib/evas/canvas/evas_vg_private.h # Linebreak @@ -176,6 +185,7 @@ lib/evas/file/evas_path.h lib_evas_libevas_la_SOURCES += \ $(lib_evas_file_SOURCES) +# Evas_3D noinst_HEADERS += \ lib/evas/include/evas_3d_utils.h @@ -201,6 +211,18 @@ modules/evas/model_savers/obj/evas_model_save_obj.c \ modules/evas/model_savers/ply/evas_model_save_ply.c \ lib/evas/canvas/evas_3d_eet.c +# Evas_VG +lib_evas_libevas_la_SOURCES += \ +lib/evas/canvas/evas_object_vg.c \ +lib/evas/canvas/evas_vg_node.c \ +lib/evas/canvas/evas_vg_container.c \ +lib/evas/canvas/evas_vg_root_node.c \ +lib/evas/canvas/evas_vg_gradient.c \ +lib/evas/canvas/evas_vg_gradient_linear.c \ +lib/evas/canvas/evas_vg_gradient_radial.c \ +lib/evas/canvas/evas_vg_utils.c \ +lib/evas/canvas/evas_vg_shape.c + # Engine lib_evas_libevas_la_SOURCES += \ lib/evas/common/evas_op_copy_main_.c \ @@ -293,6 +315,9 @@ lib_evas_libevas_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -I$(top_srcdir)/src/lib/evas/file \ -I$(top_srcdir)/src/lib/evas/include \ -I$(top_srcdir)/src/static_libs/libunibreak \ +-I$(top_builddir)/src/lib/evas/canvas \ +-I$(top_builddir)/src/modules/evas/engines/software_generic \ +-I$(top_builddir)/src/modules/evas/engines/gl_generic \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/evas\" \ @@ -492,10 +517,18 @@ lib/evas/filters/blur/blur_box_rgba_i386.c \ lib/evas/filters/blur/blur_box_rgba_sse3.c \ lib/evas/filters/blur/blur_box_rgba_neon.c +### Vector surface helper + +EXTRA_DIST += \ +modules/evas/engines/software_generic/ector_cairo_software_surface.eo \ +modules/evas/engines/gl_generic/ector_cairo_software_surface.eo ### Engines if EVAS_STATIC_BUILD_SOFTWARE_GENERIC +BUILT_SOURCES += \ +modules/evas/engines/software_generic/ector_cairo_software_surface.eo.c \ +modules/evas/engines/software_generic/ector_cairo_software_surface.eo.h lib_evas_libevas_la_SOURCES += modules/evas/engines/software_generic/evas_engine.c modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h lib_evas_libevas_la_LIBADD += else @@ -511,6 +544,7 @@ modules_evas_engines_software_generic_module_la_SOURCES = modules/evas/engines/s modules_evas_engines_software_generic_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -I$(top_srcdir)/src/lib/evas/include \ -I$(top_srcdir)/src/lib/evas/cserve2 \ +-I$(top_builddir)/src/modules/evas/engines/software_generic \ @EVAS_CFLAGS@ modules_evas_engines_software_generic_module_la_LIBADD = @USE_EVAS_LIBS@ modules_evas_engines_software_generic_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @@ -584,6 +618,10 @@ endif endif if BUILD_ENGINE_GL_COMMON +BUILT_SOURCES += \ +modules/evas/engines/gl_generic/ector_cairo_software_surface.eo.c \ +modules/evas/engines/gl_generic/ector_cairo_software_surface.eo.h + GL_COMMON_SOURCES = \ modules/evas/engines/gl_common/evas_gl_private.h \ modules/evas/engines/gl_common/evas_gl_common.h \ @@ -695,6 +733,7 @@ modules_evas_engines_gl_generic_module_la_CFLAGS = \ -I$(top_srcdir)/src/lib/evas/include \ -I$(top_srcdir)/src/lib/evas/cserve2 \ -I$(top_srcdir)/src/modules/evas/engines/gl_common \ +-I$(top_builddir)/src/modules/evas/engines/gl_generic \ @evas_engine_gl_common_cflags@ \ @EVAS_CFLAGS@ modules_evas_engines_gl_generic_module_la_LIBADD = \ diff --git a/src/Makefile_Evas_Cxx.am b/src/Makefile_Evas_Cxx.am index 59e0d35ba2..26848c4205 100644 --- a/src/Makefile_Evas_Cxx.am +++ b/src/Makefile_Evas_Cxx.am @@ -33,7 +33,16 @@ lib/evas/canvas/evas_3d_mesh.eo.hh \ lib/evas/canvas/evas_3d_node.eo.hh \ lib/evas/canvas/evas_3d_object.eo.hh \ lib/evas/canvas/evas_3d_scene.eo.hh \ -lib/evas/canvas/evas_3d_texture.eo.hh +lib/evas/canvas/evas_3d_texture.eo.hh \ +lib/evas/canvas/evas_vg.eo.hh \ +lib/evas/canvas/efl_vg_base.eo.hh \ +lib/evas/canvas/efl_vg_container.eo.hh \ +lib/evas/canvas/efl_vg_shape.eo.hh \ +lib/evas/canvas/efl_vg_root_node.eo.hh \ +lib/evas/canvas/efl_vg_gradient.eo.hh \ +lib/evas/canvas/efl_vg_gradient_radial.eo.hh \ +lib/evas/canvas/efl_vg_gradient_linear.eo.hh \ +lib/evas/canvas/efl_vg_image.eo.hh lib/evas/Evas.hh: $(generated_evas_canvas_cxx_bindings) @echo @ECHO_E@ "#ifndef EFL_CXX_EVAS_HH\n#define EFL_CXX_EVAS_HH\n" > $(top_builddir)/src/lib/evas/Evas.hh diff --git a/src/bin/ecore_evas/.gitignore b/src/bin/ecore_evas/.gitignore index 7f6f9cb40f..c6d0740831 100644 --- a/src/bin/ecore_evas/.gitignore +++ b/src/bin/ecore_evas/.gitignore @@ -1,2 +1,3 @@ /ecore_evas_convert /eetpack +/ecore_evas_svg diff --git a/src/bin/ecore_evas/ecore_evas_svg.c b/src/bin/ecore_evas/ecore_evas_svg.c new file mode 100644 index 0000000000..bd95a0618a --- /dev/null +++ b/src/bin/ecore_evas/ecore_evas_svg.c @@ -0,0 +1,198 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include +#include +#include +#include +#include + +#undef EINA_LOG_DOMAIN_DEFAULT +#define EINA_LOG_DOMAIN_DEFAULT _log_dom +static int _log_dom = -1; + +static void +_cb_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static unsigned char +_parse_color(const Ecore_Getopt *parser EINA_UNUSED, + const Ecore_Getopt_Desc *desc EINA_UNUSED, + const char *str, + void *data EINA_UNUSED, Ecore_Getopt_Value *storage) +{ + unsigned char *color = (unsigned char *)storage->ptrp; + + if (sscanf(str, "%hhu,%hhu,%hhu", color, color + 1, color + 2) != 3) + { + fprintf(stderr, "ERROR: incorrect color value '%s'\n", str); + return 0; + } + + return 1; +} + +const Ecore_Getopt optdesc = { + "ecore_evas_svg", + "%prog [options] []", + PACKAGE_VERSION, + "(C) 2014 Enlightenment", + "BSD with advertisement clause", + "Simple application to display or convert SVG in their vector form.", + 0, + { + ECORE_GETOPT_STORE_INT('q', "quality", "define encoding quality in percent."), + ECORE_GETOPT_STORE_TRUE('c', "compress", "define if data should be compressed."), + ECORE_GETOPT_STORE_STR('c', "codec", "define the codec (for TGV files: etc1, etc2)"), + ECORE_GETOPT_CALLBACK_NOARGS('E', "list-engines", "list Ecore-Evas engines", + ecore_getopt_callback_ecore_evas_list_engines, NULL), + ECORE_GETOPT_STORE_STR('e', "engine", "The Ecore-Evas engine to use (see --list-engines)"), + ECORE_GETOPT_CALLBACK_ARGS('c', "bg-color", + "Color of the background (if not shaped or alpha)", + "RRGGBB", _parse_color, NULL), + ECORE_GETOPT_CALLBACK_ARGS('Z', "size", "size to use in wxh form.", "WxH", + ecore_getopt_callback_size_parse, NULL), + ECORE_GETOPT_STORE_TRUE('a', "alpha", "Display window with alpha channel " + " (needs composite manager!)"), + ECORE_GETOPT_STORE_STR('t', "title", "Define the window title string"), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int +main(int argc, char *argv[]) +{ + Ecore_Evas *ee; + Evas *e; + Evas_Object *im = NULL; + Evas_Object *vg; + Evas_Object *r; + char *encoding = NULL; + char *engine = NULL; + char *title = NULL; + Eina_Rectangle size = { 0, 0, 800, 600 }; + unsigned char color[3] = { 0, 0, 0 }; + + int arg_index; + int quality = -1; + + Eina_Bool compress = 1; + Eina_Bool quit_option = EINA_FALSE; + Eina_Bool display = EINA_FALSE; + Eina_Bool alpha = EINA_FALSE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_INT(quality), + ECORE_GETOPT_VALUE_BOOL(compress), + ECORE_GETOPT_VALUE_STR(encoding), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_STR(engine), + ECORE_GETOPT_VALUE_PTR_CAST(color), + ECORE_GETOPT_VALUE_PTR_CAST(size), + ECORE_GETOPT_VALUE_BOOL(alpha), + ECORE_GETOPT_VALUE_STR(title), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_NONE + }; + + eina_init(); + _log_dom = eina_log_domain_register(argv[0], EINA_COLOR_CYAN); + + ecore_init(); + ecore_evas_init(); + + arg_index = ecore_getopt_parse(&optdesc, values, argc, argv); + if (quit_option) goto end; + + if (arg_index < 0) + { + EINA_LOG_ERR("Could not parse argument."); + goto end; + } + if (arg_index + 1 == argc) + { + display = EINA_TRUE; + } + else if (arg_index + 2 != argc) + { + EINA_LOG_ERR("File not correctly specified."); + goto end; + } + + if (!display) + { + Ecore_Evas *sub_ee; + + ee = ecore_evas_buffer_new(1, 1); + im = ecore_evas_object_image_new(ee); + sub_ee = ecore_evas_object_ecore_evas_get(im); + ecore_evas_resize(sub_ee, size.w, size.h); + + e = ecore_evas_object_evas_get(im); + } + else + { + ee = ecore_evas_new(engine, 0, 0, size.w, size.h, NULL); + + e = ecore_evas_get(ee); + } + + ecore_evas_alpha_set(ee, alpha); + ecore_evas_callback_delete_request_set(ee, _cb_delete); + ecore_evas_title_set(ee, title ? title : "Ecore Evas SVG"); + + + r = eo_add(EVAS_RECTANGLE_CLASS, e, + efl_gfx_color_set(color[0], color[1], color[2], alpha ? 0 : 255), + efl_gfx_visible_set(EINA_TRUE)); + ecore_evas_object_associate(ee, r, ECORE_EVAS_OBJECT_ASSOCIATE_BASE); + + vg = eo_add(EVAS_VG_CLASS, e, + efl_file_set(argv[arg_index], NULL), + efl_gfx_visible_set(EINA_TRUE)); + ecore_evas_object_associate(ee, vg, ECORE_EVAS_OBJECT_ASSOCIATE_BASE); + + if (display) + { + ecore_evas_show(ee); + + ecore_main_loop_begin(); + } + else + { + Eina_Strbuf *flags = NULL; + + flags = eina_strbuf_new(); + eina_strbuf_append_printf(flags, "compress=%d", compress); + if (quality >= 0) + eina_strbuf_append_printf(flags, " quality=%d", quality); + if (encoding) + eina_strbuf_append_printf(flags, " encoding=%s", encoding); + + evas_object_image_save(im, argv[arg_index + 1], + NULL, eina_strbuf_string_get(flags)); + eina_strbuf_free(flags); + } + + ecore_evas_free(ee); + end: + ecore_evas_shutdown(); + ecore_shutdown(); + eina_shutdown(); + + return 0; +} diff --git a/src/bindings/eo_cxx/eo_inherit_bindings.hh b/src/bindings/eo_cxx/eo_inherit_bindings.hh index e560b06adf..73fc2b1554 100644 --- a/src/bindings/eo_cxx/eo_inherit_bindings.hh +++ b/src/bindings/eo_cxx/eo_inherit_bindings.hh @@ -235,23 +235,23 @@ template EAPI void inherit_constructor(void* this_, Args args) { typedef void (*func_t)(Eo *, void *, void*, Args); - Eo_Op_Call_Data call; + Eo_Op_Call_Data ___call; static Eo_Op op = EO_NOOP; if ( op == EO_NOOP ) op = _eo_api_op_id_get (reinterpret_cast (static_cast(&detail::inherit_constructor)), ::eina_main_loop_is(), __FILE__, __LINE__); - if (!_eo_call_resolve("detail::inherit_constructor", op, &call, + if (!_eo_call_resolve("detail::inherit_constructor", op, &___call, ::eina_main_loop_is(), __FILE__, __LINE__)) { - assert(_eo_call_resolve("detail::inherit_constructor", op, &call, + assert(_eo_call_resolve("detail::inherit_constructor", op, &___call, ::eina_main_loop_is(), __FILE__, __LINE__)); return; } - func_t func = (func_t) call.func; + func_t func = (func_t) ___call.func; EO_HOOK_CALL_PREPARE(eo_hook_call_pre, ""); - func(call.obj, call.data, this_, args); + func(___call.obj, ___call.data, this_, args); EO_HOOK_CALL_PREPARE(eo_hook_call_post, ""); } diff --git a/src/examples/eolian_cxx/eolian_cxx_complex_types_01.cc b/src/examples/eolian_cxx/eolian_cxx_complex_types_01.cc index 8dd5d29d87..fc488980ce 100644 --- a/src/examples/eolian_cxx/eolian_cxx_complex_types_01.cc +++ b/src/examples/eolian_cxx/eolian_cxx_complex_types_01.cc @@ -70,20 +70,20 @@ example_complex_types() bg.color_set(255, 255, 255, 255); bg.position_set(0, 0); bg.size_set(500, 250); - bg.visibility_set(true); + bg.visible_set(true); efl::evas::grid grid(efl::eo::parent = canvas); grid.position_set(0, 0); grid.object_smart::color_set(0, 0, 0, 255); grid.size_set(5, 5); - grid.visibility_set(true); + grid.visible_set(true); efl::evas::text text1(efl::eo::parent = canvas); text1.style_set(EVAS_TEXT_STYLE_OUTLINE); text1.color_set(255, 0, 0, 255); text1.font_set("DejaVu", 32); text1.text_set("EFL++ Examples"); - text1.visibility_set(true); + text1.visible_set(true); int t1w, t1h; text1.size_get(&t1w, &t1h); grid.pack(text1, 1, 1, t1w, t1h); @@ -96,7 +96,7 @@ example_complex_types() std::stringstream ss; ss << "version " << EFL_VERSION_MAJOR << "." << EFL_VERSION_MINOR; text2.text_set(ss.str().c_str()); - text2.visibility_set(true); + text2.visible_set(true); int t2w, t2h; text2.size_get(&t2w, &t2h); diff --git a/src/examples/eolian_cxx/eolian_cxx_eo_events_01.cc b/src/examples/eolian_cxx/eolian_cxx_eo_events_01.cc index 3cce90c655..ca9f28422e 100644 --- a/src/examples/eolian_cxx/eolian_cxx_eo_events_01.cc +++ b/src/examples/eolian_cxx/eolian_cxx_eo_events_01.cc @@ -73,7 +73,7 @@ example_complex_types() bg.color_set(255, 255, 255, 255); bg.position_set(0, 0); bg.size_set(500, 250); - bg.visibility_set(true); + bg.visible_set(true); efl::eo::signal_connection conn = bg.callback_mouse_down_add diff --git a/src/examples/evas/.gitignore b/src/examples/evas/.gitignore index 05fc412455..129d8dfc4d 100644 --- a/src/examples/evas/.gitignore +++ b/src/examples/evas/.gitignore @@ -39,3 +39,5 @@ /evas_3d_mmap /evas_3d_shadows /evas_3d_parallax_occlusion +/evas_vg_simple +/evas_vg_batman diff --git a/src/examples/evas/Makefile.am b/src/examples/evas/Makefile.am index 5e27afa438..0218472979 100644 --- a/src/examples/evas/Makefile.am +++ b/src/examples/evas/Makefile.am @@ -7,9 +7,11 @@ AM_CPPFLAGS = \ -I$(top_builddir)/src/lib/efl/interfaces \ -I$(top_srcdir)/src/lib/eina \ -I$(top_srcdir)/src/lib/eo \ +-I$(top_srcdir)/src/lib/ector \ -I$(top_srcdir)/src/lib/evas \ -I$(top_builddir)/src/lib/eina \ -I$(top_builddir)/src/lib/eo \ +-I$(top_builddir)/src/lib/ector \ -I$(top_builddir)/src/lib/evas \ @EVAS_CFLAGS@ @@ -30,6 +32,7 @@ evas_init_shutdown_LDADD = $(top_builddir)/src/lib/evas/libevas.la @EVAS_LDFLAGS ECORE_EVAS_COMMON_CPPFLAGS = \ -I$(top_srcdir)/src/lib/eina \ -I$(top_srcdir)/src/lib/eo \ +-I$(top_srcdir)/src/lib/ector \ -I$(top_srcdir)/src/lib/evas \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_srcdir)/src/lib/ecore_file \ @@ -38,6 +41,7 @@ ECORE_EVAS_COMMON_CPPFLAGS = \ -I$(top_builddir)/src/lib/efl \ -I$(top_builddir)/src/lib/eina \ -I$(top_builddir)/src/lib/eo \ +-I$(top_builddir)/src/lib/ector \ -I$(top_builddir)/src/lib/evas \ -I$(top_builddir)/src/lib/ecore \ -I$(top_builddir)/src/lib/ecore_file \ @@ -54,6 +58,7 @@ $(top_builddir)/src/lib/ecore/libecore.la \ $(top_builddir)/src/lib/ecore_file/libecore_file.la \ $(top_builddir)/src/lib/ecore_input/libecore_input.la \ $(top_builddir)/src/lib/ecore_evas/libecore_evas.la \ +$(top_builddir)/src/lib/ector/libector.la \ $(top_builddir)/src/lib/evas/libevas.la \ @EVAS_LDFLAGS@ -lm @@ -66,7 +71,9 @@ EDJE_COMMON_CPPFLAGS = \ -I$(top_builddir)/src/lib/eo \ -I$(top_srcdir)/src/lib/eet \ -I$(top_builddir)/src/lib/eet \ +-I$(top_srcdir)/src/lib/ector \ -I$(top_srcdir)/src/lib/evas \ +-I$(top_builddir)/src/lib/ector \ -I$(top_builddir)/src/lib/evas \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_builddir)/src/lib/ecore \ @@ -282,6 +289,16 @@ evas_gl_SOURCES = evas-gl.c evas_gl_LDADD = $(ECORE_EVAS_COMMON_LDADD) @EFL_PTHREAD_LIBS@ evas_gl_CPPFLAGS = $(ECORE_EVAS_COMMON_CPPFLAGS) +EXTRA_PROGRAMS += evas_vg_simple +evas_vg_simple_SOURCES = evas-vg-simple.c +evas_vg_simple_LDADD = $(ECORE_EVAS_COMMON_LDADD) +evas_vg_simple_CPPFLAGS = $(ECORE_EVAS_COMMON_CPPFLAGS) + +EXTRA_PROGRAMS += evas_vg_batman +evas_vg_batman_SOURCES = evas-vg-batman.c +evas_vg_batman_LDADD = $(ECORE_EVAS_COMMON_LDADD) +evas_vg_batman_CPPFLAGS = $(ECORE_EVAS_COMMON_CPPFLAGS) + .edc.edj: $(AM_V_EDJ)$(EDJE_CC) $(EDJE_CC_FLAGS) $< $(builddir)/$(@F) @@ -324,7 +341,9 @@ evas-smart-object.c \ evas-stacking.c \ evas-table.c \ evas-multi-touch.c \ -evas-text.c +evas-text.c \ +evas-vg-simple.c \ +evas-vg-batman.c DATA_FILES = \ resources/images/enlightenment.png \ diff --git a/src/examples/evas/evas-3d-aabb.c b/src/examples/evas/evas-3d-aabb.c index 8791b755fb..9f9488a1e4 100644 --- a/src/examples/evas/evas-3d-aabb.c +++ b/src/examples/evas/evas-3d-aabb.c @@ -112,8 +112,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -243,14 +243,14 @@ main(void) background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); evas_object_focus_set(image, EINA_TRUE); eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-blending.c b/src/examples/evas/evas-3d-blending.c index d45248362d..5e47739ee7 100644 --- a/src/examples/evas/evas-3d-blending.c +++ b/src/examples/evas/evas-3d-blending.c @@ -136,8 +136,8 @@ _on_canvas_resize(Ecore_Evas *ee) ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); evas_object_resize(background, w, h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool diff --git a/src/examples/evas/evas-3d-colorpick.c b/src/examples/evas/evas-3d-colorpick.c index 9a7b5ff1cc..3fb7adb9a4 100644 --- a/src/examples/evas/evas-3d-colorpick.c +++ b/src/examples/evas/evas-3d-colorpick.c @@ -121,8 +121,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(bg, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(bg, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -409,8 +409,8 @@ int main(int argc, char **argv) image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); evas_object_focus_set(image, EINA_TRUE); eo_do(image, evas_obj_image_scene_set(globalscene.scene)); diff --git a/src/examples/evas/evas-3d-cube.c b/src/examples/evas/evas-3d-cube.c index bfe57e8680..14a5ec8319 100644 --- a/src/examples/evas/evas-3d-cube.c +++ b/src/examples/evas/evas-3d-cube.c @@ -110,8 +110,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -260,15 +260,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(data.scene)); diff --git a/src/examples/evas/evas-3d-cube2.c b/src/examples/evas/evas-3d-cube2.c index 4a1afaaf07..aff4fdbe68 100644 --- a/src/examples/evas/evas-3d-cube2.c +++ b/src/examples/evas/evas-3d-cube2.c @@ -79,8 +79,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -259,15 +259,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(data.scene)); diff --git a/src/examples/evas/evas-3d-eet.c b/src/examples/evas/evas-3d-eet.c index 18dc2e4620..4178a4eff4 100644 --- a/src/examples/evas/evas-3d-eet.c +++ b/src/examples/evas/evas-3d-eet.c @@ -93,8 +93,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } int @@ -214,15 +214,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-md2.c b/src/examples/evas/evas-3d-md2.c index d48926c9ee..428379da40 100644 --- a/src/examples/evas/evas-3d-md2.c +++ b/src/examples/evas/evas-3d-md2.c @@ -68,8 +68,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } int @@ -178,15 +178,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-mmap-set.c b/src/examples/evas/evas-3d-mmap-set.c index 0855d7604c..ea9308101b 100644 --- a/src/examples/evas/evas-3d-mmap-set.c +++ b/src/examples/evas/evas-3d-mmap-set.c @@ -34,7 +34,7 @@ extention##_file = eina_file_open(buffer , 0); \ mesh_##extention = eo_add(EVAS_3D_MESH_CLASS, evas); \ eo_do(mesh_##extention, \ - evas_3d_mesh_mmap_set(extention##_file, NULL), \ + efl_file_mmap_set(extention##_file, NULL), \ evas_3d_mesh_frame_material_set(0, material), \ evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG)); \ node_##extention = eo_add(EVAS_3D_NODE_CLASS, evas, \ @@ -161,8 +161,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } int @@ -258,15 +258,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(20, 20, 200, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(20, 20, 200, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-obj.c b/src/examples/evas/evas-3d-obj.c index 9676dff0af..406ac7fda0 100644 --- a/src/examples/evas/evas-3d-obj.c +++ b/src/examples/evas/evas-3d-obj.c @@ -139,8 +139,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } int @@ -235,15 +235,15 @@ main(void) /* Add a background rectangle MESHES. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-parallax-occlusion.c b/src/examples/evas/evas-3d-parallax-occlusion.c index ca08c55b8b..60af0d181e 100644 --- a/src/examples/evas/evas-3d-parallax-occlusion.c +++ b/src/examples/evas/evas-3d-parallax-occlusion.c @@ -80,8 +80,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -259,15 +259,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE), evas_object_focus_set(image, EINA_TRUE)); /* Set the image object as render target for 3D scene. */ diff --git a/src/examples/evas/evas-3d-pick.c b/src/examples/evas/evas-3d-pick.c index bcd9c8473e..49eda2ce20 100644 --- a/src/examples/evas/evas-3d-pick.c +++ b/src/examples/evas/evas-3d-pick.c @@ -199,15 +199,15 @@ main(void) /* Add evas objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); image = evas_object_image_filled_add(evas); eo_do(image, evas_obj_image_scene_set(scene), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); evas_object_event_callback_add(image, EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, NULL); diff --git a/src/examples/evas/evas-3d-ply.c b/src/examples/evas/evas-3d-ply.c index a64263b0fb..502b3d6312 100644 --- a/src/examples/evas/evas-3d-ply.c +++ b/src/examples/evas/evas-3d-ply.c @@ -91,8 +91,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } int @@ -227,15 +227,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(100, 100, 100, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(100, 100, 100, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Set the image object as render target for 3D scene. */ eo_do(image, evas_obj_image_scene_set(scene)); diff --git a/src/examples/evas/evas-3d-proxy.c b/src/examples/evas/evas-3d-proxy.c index 7fbe8e3096..71ef979faf 100644 --- a/src/examples/evas/evas-3d-proxy.c +++ b/src/examples/evas/evas-3d-proxy.c @@ -56,8 +56,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static Eina_Bool @@ -218,23 +218,23 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add a background image. */ source = evas_object_image_filled_add(evas); eo_do(source, - evas_obj_image_size_set(IMG_WIDTH, IMG_HEIGHT), - evas_obj_position_set((WIDTH / 2), (HEIGHT / 2)), - evas_obj_size_set((WIDTH / 2), (HEIGHT / 2)), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_view_size_set(IMG_WIDTH, IMG_HEIGHT), + efl_gfx_position_set((WIDTH / 2), (HEIGHT / 2)), + efl_gfx_size_set((WIDTH / 2), (HEIGHT / 2)), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set((WIDTH / 2), (HEIGHT / 2)), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set((WIDTH / 2), (HEIGHT / 2)), + efl_gfx_visible_set(EINA_TRUE)); /* Setup scene */ _scene_setup(&data); diff --git a/src/examples/evas/evas-3d-shadows.c b/src/examples/evas/evas-3d-shadows.c index d53f435127..c1eb0875d5 100644 --- a/src/examples/evas/evas-3d-shadows.c +++ b/src/examples/evas/evas-3d-shadows.c @@ -147,8 +147,8 @@ _on_canvas_resize(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(background, evas_obj_size_set(w, h)); - eo_do(image, evas_obj_size_set(w, h)); + eo_do(background, efl_gfx_size_set(w, h)); + eo_do(image, efl_gfx_size_set(w, h)); } static void @@ -525,15 +525,15 @@ main(void) /* Add a background rectangle objects. */ background = eo_add(EVAS_RECTANGLE_CLASS, evas); eo_do(background, - evas_obj_color_set(0, 0, 0, 255), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_color_set(0, 0, 0, 255), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); /* Add an image object for 3D scene rendering. */ image = evas_object_image_filled_add(evas); eo_do(image, - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); evas_object_focus_set(image, EINA_TRUE); /* Set the image object as render target for 3D scene. */ diff --git a/src/examples/evas/evas-object-manipulation-eo.c b/src/examples/evas/evas-object-manipulation-eo.c index 6bb2cbd978..9f17ee8313 100644 --- a/src/examples/evas/evas-object-manipulation-eo.c +++ b/src/examples/evas/evas-object-manipulation-eo.c @@ -59,7 +59,7 @@ _canvas_resize_cb(Ecore_Evas *ee) int w, h; ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); - eo_do(d.bg, evas_obj_size_set(w, h)); + eo_do(d.bg, efl_gfx_size_set(w, h)); } static void @@ -80,7 +80,7 @@ _on_keydown(void *data EINA_UNUSED, { int alpha, r, g, b; - eo_do(d.clipper, evas_obj_color_get(&r, &g, &b, &alpha)); + eo_do(d.clipper, efl_gfx_color_get(&r, &g, &b, &alpha)); evas_color_argb_unpremul(alpha, &r, &g, &b); alpha -= 20; @@ -88,7 +88,7 @@ _on_keydown(void *data EINA_UNUSED, alpha = 255; evas_color_argb_premul(alpha, &r, &g, &b); - eo_do(d.clipper, evas_obj_color_set(r, g, b, alpha)); + eo_do(d.clipper, efl_gfx_color_set(r, g, b, alpha)); fprintf(stdout, "Changing clipper's opacity: %d%%\n", (int)((alpha / 255.0) * 100)); @@ -102,7 +102,7 @@ _on_keydown(void *data EINA_UNUSED, fprintf(stdout, "Changing clipper's color to"); - eo_do(d.clipper, evas_obj_color_get(&r, &g, &b, &alpha)); + eo_do(d.clipper, efl_gfx_color_get(&r, &g, &b, &alpha)); evas_color_argb_unpremul(alpha, &r, &g, &b); if (g > 0) @@ -117,7 +117,7 @@ _on_keydown(void *data EINA_UNUSED, } evas_color_argb_premul(alpha, &r, &g, &b); - eo_do(d.clipper, evas_obj_color_set(r, g, b, alpha)); + eo_do(d.clipper, efl_gfx_color_set(r, g, b, alpha)); return; } @@ -145,8 +145,8 @@ _on_keydown(void *data EINA_UNUSED, Eina_Bool visibility; /* Don't use "get"-"set" expressions in one eo_do call, * if you pass parameter to "set" by value. */ - eo_do(d.clipper, visibility = evas_obj_visibility_get()); - eo_do(d.clipper, evas_obj_visibility_set(!visibility)); + eo_do(d.clipper, visibility = efl_gfx_visible_get()); + eo_do(d.clipper, efl_gfx_visible_set(!visibility)); fprintf(stdout, "Clipper is now %s\n", visibility ? "hidden" : "visible"); return; } @@ -178,10 +178,10 @@ main(void) /* Eo-styled way to perform actions on an object*/ eo_do(d.bg, evas_obj_name_set("background rectangle"), - evas_obj_color_set(255, 255, 255, 255), /* white bg */ - evas_obj_position_set(0, 0), /* at canvas' origin */ - evas_obj_size_set(WIDTH, HEIGHT), /* covers full canvas */ - evas_obj_visibility_set(EINA_TRUE), + efl_gfx_color_set(255, 255, 255, 255), /* white bg */ + efl_gfx_position_set(0, 0), /* at canvas' origin */ + efl_gfx_size_set(WIDTH, HEIGHT), /* covers full canvas */ + efl_gfx_visible_set(EINA_TRUE), evas_obj_focus_set(EINA_TRUE)); evas_object_event_callback_add( @@ -204,9 +204,9 @@ main(void) } else { - eo_do(d.img, evas_obj_position_set(0, 0), - evas_obj_size_set(WIDTH, HEIGHT), - evas_obj_visibility_set(EINA_TRUE)); + eo_do(d.img, efl_gfx_position_set(0, 0), + efl_gfx_size_set(WIDTH, HEIGHT), + efl_gfx_visible_set(EINA_TRUE)); const char *type = NULL; eo_do(d.img, type = evas_obj_type_get()); @@ -228,9 +228,9 @@ main(void) eo_do(d.clipper_border, evas_obj_image_border_set(3, 3, 3, 3), evas_obj_image_border_center_fill_set(EVAS_BORDER_FILL_NONE), - evas_obj_position_set((WIDTH / 4) -3, (HEIGHT / 4) - 3), - evas_obj_size_set((WIDTH / 2) + 6, (HEIGHT / 2) + 6), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_position_set((WIDTH / 4) -3, (HEIGHT / 4) - 3), + efl_gfx_size_set((WIDTH / 2) + 6, (HEIGHT / 2) + 6), + efl_gfx_visible_set(EINA_TRUE)); } /* solid white clipper (note that it's the default color for a * rectangle) - it won't change clippees' colors, then (multiplying @@ -238,9 +238,9 @@ main(void) d.clipper = eo_add(EVAS_RECTANGLE_CLASS, d.canvas); eo_do(d.clipper, - evas_obj_position_set( WIDTH / 4, HEIGHT / 4), - evas_obj_size_set(WIDTH / 2, HEIGHT / 2), - evas_obj_visibility_set(EINA_TRUE)); + efl_gfx_position_set( WIDTH / 4, HEIGHT / 4), + efl_gfx_size_set(WIDTH / 2, HEIGHT / 2), + efl_gfx_visible_set(EINA_TRUE)); eo_do(d.img, evas_obj_clip_set(d.clipper)); diff --git a/src/examples/evas/evas-vg-batman.c b/src/examples/evas/evas-vg-batman.c new file mode 100644 index 0000000000..116150ae2f --- /dev/null +++ b/src/examples/evas/evas-vg-batman.c @@ -0,0 +1,171 @@ +/** + * Simple Evas example illustrating the use of Evas_VG animation + * + * You'll need at least one engine built for it (excluding the buffer + * one). See stdout/stderr for output. + * + * @verbatim + * gcc -o evas_vg_batman evas-vg-batman.c `pkg-config --libs --cflags evas ecore ecore-evas eina ector eo efl` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define PACKAGE_EXAMPLES_DIR "." +#endif + +#define WIDTH 800 +#define HEIGHT 600 + +#ifndef EFL_BETA_API_SUPPORT +#define EFL_BETA_API_SUPPORT 1 +#endif + +#include +#include +#include +#include +#include + +#include +#include + +static Evas_Object *background = NULL; +static Evas_Object *vg = NULL; +static Efl_VG *batman = NULL; + +static int animation_position = 0; +static Ecore_Animator *animation = NULL; + +static Efl_VG **batmans_vg = NULL; +static const char *batmans_path[] = { + "M 256,213 C 245,181 206,187 234,262 147,181 169,71.2 233,18 220,56 235,81 283,88 285,78.7 286,69.3 288,60 289,61.3 290,62.7 291,64 291,64 297,63 300,63 303,63 309,64 309,64 310,62.7 311,61.3 312,60 314,69.3 315,78.7 317,88 365,82 380,56 367,18 431,71 453,181 366,262 394,187 356,181 344,213 328,185 309,184 300,284 291,184 272,185 256,213 Z", + "M 212,220 C 197,171 156,153 123,221 109,157 120,109 159,63.6 190,114 234,115 254,89.8 260,82.3 268,69.6 270,60.3 273,66.5 275,71.6 280,75.6 286,79.5 294,79.8 300,79.8 306,79.8 314,79.5 320,75.6 325,71.6 327,66.5 330,60.3 332,69.6 340,82.3 346,89.8 366,115 410,114 441,63.6 480,109 491,157 477,221 444,153 403,171 388,220 366,188 316,200 300,248 284,200 234,188 212,220 Z", + "M 213,222 C 219,150 165,139 130,183 125,123 171,73.8 247,51.6 205,78 236,108 280,102 281,90.3 282,79 286,68.2 287,72 288,75.8 289,79.7 293,79.7 296,79.7 300,79.7 304,79.7 307,79.7 311,79.7 312,75.8 313,72 314,68.2 318,79 319,90.3 320,102 364,108 395,78 353,51.6 429,73.8 475,123 470,183 435,139 381,150 387,222 364,176 315,172 300,248 285,172 236,176 213,222 Z", + "M 218,231 C 191,238 165,252 140,266 144,209 156,153 193,93.7 218,106 249,105 280,102 282,90.3 284,78.6 289,67.8 290,71.6 291,75.8 292,79.7 292,79.7 297,79.7 300,79.7 303,79.7 308,79.7 308,79.7 309,75.8 310,71.6 311,67.8 316,78.6 318,90.3 320,102 351,105 382,106 407,93.7 444,153 456,209 460,266 435,252 409,238 382,231 355,224 328,223 300,223 272,223 245,224 218,231 Z", + "M 258,243 C 220,201 221,220 253,281 154,243 150,108 229,61.9 242,83 257,98.1 275,110 278,88 282,65.8 285,43.6 287,49.9 288,56.2 290,62.5 293,62.7 297,62.9 300,62.9 303,62.9 307,62.7 310,62.5 312,56.2 313,49.9 315,43.6 318,65.8 322,88 325,110 343,98.1 358,83 371,61.9 450,108 446,243 347,281 379,220 380,201 342,243 330,187 329,202 300,271 271,202 270,187 258,243 Z", + "M 235,210 C 214,139 143,145 183,229 108,175 135,70.1 242,48.3 190,85.6 245,142 278,95.5 281,80.2 281,62.7 284,48.7 287,53.9 287,59.1 289,64.5 292,64.7 297,64.2 300,64.2 303,64.2 308,64.7 311,64.5 313,59.1 313,53.9 316,48.7 319,62.7 319,80.2 322,95.5 355,142 410,85.6 358,48.3 465,70.1 492,175 417,229 457,145 386,139 365,210 357,147 309,190 300,271 291,190 243,147 235,210 Z", + "M 249,157 C 214,157 201,203 273,255 157,221 157,69 274,32.8 188,87.2 211,140 256,140 291,140 289,128 291,98.1 293,107 293,116 295,125 297,125 298,125 300,125 302,125 305,125 305,125 307,116 307,107 309,98.1 311,128 309,140 344,140 389,140 412,87.2 326,32.8 443,69 443,221 327,255 399,203 386,157 351,157 317,157 300,195 300,238 300,195 283,157 249,157 Z", + "M 264,212 C 213,138 150,171 232,244 101,217 112,55.1 257,36.9 182,86.6 222,106 266,106 285,106 284,66.7 286,36.8 288,42.6 289,48.4 291,54.2 291,54.2 297,54.2 300,54.2 303,54.2 309,54.2 309,54.2 311,48.4 312,42.6 314,36.8 316,66.7 315,106 334,106 378,106 418,86.6 343,36.9 488,55.1 499,217 368,244 450,171 387,138 336,212 354,161 300,163 300,249 300,163 246,161 264,212 Z", + "M 223,217 C 194,153 165,168 133,219 143,158 161,99.2 189,38.4 214,69.8 241,84.7 272,86.2 272,70.2 273,53.5 273,37.5 275,47.9 278,58.4 280,68.8 287,64.9 292,62.4 300,62.4 308,62.4 313,64.9 320,68.8 322,58.4 325,47.9 327,37.5 327,53.5 328,70.2 328,86.2 359,84.7 386,69.8 411,38.4 439,99.2 457,158 467,219 435,168 406,153 377,217 350,162 319,176 300,245 281,176 250,162 223,217 Z", + "M 231,185 C 186,159 161,180 190,215 86.2,180 92.6,99.6 211,68.9 195,112 254,141 279,96.7 279,83.2 279,69.8 279,56.3 283,63.6 288,70.8 292,78.1 295,78.1 297,78.1 300,78.1 303,78.1 305,78.1 308,78.1 312,70.8 317,63.6 321,56.3 321,69.8 321,83.2 321,96.7 346,141 405,112 389,68.9 507,99.6 514,180 410,215 439,180 414,159 369,185 351,165 324,167 300,216 276,167 249,165 231,185 Z", + "M 194,146 C 192,107 164,76.4 136,45.6 166,55.7 196,65.7 226,75.8 238,107 265,163 279,136 282,130 281,108 281,94.8 285,103 288,111 293,115 295,116 298,117 300,117 302,117 305,116 307,115 312,111 315,103 319,94.8 319,108 318,130 321,136 335,163 362,107 374,75.8 404,65.7 434,55.7 464,45.6 436,76.4 408,107 406,146 355,158 323,189 300,231 277,189 245,158 194,146 Z", + "M 209,182 C 184,132 176,138 113,161 140,136 168,111 196,86.5 221,104 247,115 278,115 281,99.9 285,85.5 287,70.2 289,78.5 292,88.4 294,96.7 296,96.7 298,96.7 300,96.7 302,96.7 304,96.7 306,96.7 308,88.4 311,78.5 313,70.2 315,85.5 319,99.9 322,115 353,115 379,104 404,86.5 432,111 460,136 487,161 424,138 416,132 391,182 332,150 341,161 300,214 259,161 268,150 209,182 Z", + "M 198,171 C 189,131 150,120 113,140 142,104 182,74.4 249,70.2 208,89 248,125 278,106 285,101 286,93.5 286,74.2 288,78.1 291,81.5 294,83.2 296,84.2 298,84.7 300,84.7 302,84.7 304,84.2 306,83.2 309,81.5 312,78.1 314,74.2 314,93.5 315,101 322,106 352,125 392,89 351,70.2 418,74.4 458,104 487,140 450,120 411,131 402,171 357,147 322,171 300,214 278,171 243,147 198,171 Z", + "M 202,170 C 188,115 157,108 124,105 146,84.3 171,71.5 199,70.2 211,98.6 243,103 277,106 279,99.3 281,92.6 283,86 285,91.9 287,97.9 290,104 293,104 297,104 300,104 303,104 307,104 310,104 313,97.9 315,91.9 317,86 319,92.6 321,99.3 323,106 357,103 389,98.6 401,70.2 429,71.5 454,84.3 476,105 443,108 412,115 398,170 349,157 318,175 300,214 282,175 251,157 202,170 Z", + "M 220,179 C 200,127 150,130 123,175 122,110 160,85.1 201,64 208,99.2 243,111 268,92.9 278,86.1 284,68.2 287,40.7 289,49.6 292,58.4 294,67.3 296,67.3 298,67.3 300,67.3 302,67.3 304,67.3 306,67.3 308,58.4 311,49.6 313,40.7 316,68.2 322,86.1 332,92.9 357,111 392,99.3 399,64 440,85.1 478,110 477,175 450,130 400,127 380,179 355,155 305,208 300,247 295,208 245,155 220,179 Z", + "M 166,154 C 179,119 154,95.4 114,79.3 155,79.1 197,78.9 239,78.7 242,103 250,109 283,109 289,109 290,93.9 291,83.7 292,88.3 292,92.9 293,97.5 295,97.5 298,97.5 300,97.5 302,97.5 305,97.5 307,97.5 308,92.9 308,88.3 309,83.7 310,93.9 311,109 317,109 350,109 358,103 361,78.7 403,78.9 445,79.1 486,79.3 446,95.4 421,119 434,154 377,151 320,151 300,207 280,151 223,151 166,154 Z", +}; + +static void +_on_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void +_on_resize(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + evas_object_resize(background, w, h); + evas_object_resize(vg, w, h); +} + +static Eina_Bool +_animator(void *data EINA_UNUSED, double pos) +{ + int next = (animation_position + 1) % (sizeof (batmans_path) / sizeof (batmans_path[0])); + + evas_vg_shape_shape_interpolate(batman, + batmans_vg[next], + batmans_vg[animation_position], + ecore_animator_pos_map(pos, ECORE_POS_MAP_SINUSOIDAL, 0.0, 0.0)); + + if (pos == 1.0) + { + animation_position = next; + animation = ecore_animator_timeline_add(1, _animator, NULL); + } + + return EINA_TRUE; +} + +int +main(void) +{ + Ecore_Evas *ee; + Evas *e; + Efl_VG *circle; + Efl_VG *root; + unsigned int i; + + if (!ecore_evas_init()) + return -1; + //setenv("ECORE_EVAS_ENGINE", "opengl_x11", 1); + ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!ee) return -1; + + ecore_evas_callback_delete_request_set(ee, _on_delete); + ecore_evas_callback_resize_set(ee, _on_resize); + ecore_evas_show(ee); + + e = ecore_evas_get(ee); + background = evas_object_rectangle_add(e); + evas_object_color_set(background, 70, 70, 70, 255); + evas_object_show(background); + + vg = evas_object_vg_add(e); + evas_object_show(vg); + + _on_resize(ee); + + batmans_vg = malloc(sizeof (Efl_VG*) * + sizeof (batmans_path) / sizeof (batmans_path[0])); + if (!batmans_vg) return -1; + + for (i = 0; i < sizeof (batmans_path) / sizeof (batmans_path[0]); i++) + { + batmans_vg[i] = evas_vg_shape_add(NULL); + evas_vg_node_color_set(batmans_vg[i], 0, 0, 0, 255); + evas_vg_shape_stroke_color_set(batmans_vg[i], 128, 10,10, 128); + evas_vg_shape_stroke_width_set(batmans_vg[i], 4.0); + evas_vg_shape_stroke_join_set(batmans_vg[i], EFL_GFX_JOIN_MITER); + if(i % 2) + { + evas_vg_shape_stroke_color_set(batmans_vg[i], 10, 10,128, 128); + evas_vg_shape_stroke_width_set(batmans_vg[i], 2.0); + evas_vg_node_color_set(batmans_vg[i], 120, 120, 120, 255); + evas_vg_shape_stroke_join_set(batmans_vg[i], EFL_GFX_JOIN_ROUND); + } + evas_vg_shape_shape_append_svg_path(batmans_vg[i], batmans_path[i]); + } + + animation = ecore_animator_timeline_add(1, _animator, NULL); + + root = evas_object_vg_root_node_get(vg); + + Eina_Matrix3 matrix; + eina_matrix3_scale(&matrix, 1.1, 1.1); + evas_vg_node_transformation_set(root, &matrix); + + + circle = evas_vg_shape_add(root); + evas_vg_shape_shape_append_circle(circle, WIDTH / 2, HEIGHT / 2, 200); + evas_vg_node_color_set(circle, 255, 255, 255, 255); + evas_vg_shape_stroke_width_set(circle, 1); + evas_vg_shape_stroke_color_set(circle, 255, 0, 0, 255); + + batman = evas_vg_shape_add(root); + evas_vg_node_color_set(batman, 0, 0, 0, 255); + evas_vg_node_origin_set(batman, 100, 150); + evas_vg_shape_shape_append_move_to(batman, 256, 213); + evas_vg_shape_shape_dup(batman, batmans_vg[0]); + + ecore_main_loop_begin(); + + ecore_evas_shutdown(); + return 0; +} diff --git a/src/examples/evas/evas-vg-simple.c b/src/examples/evas/evas-vg-simple.c new file mode 100644 index 0000000000..b125e3f2a0 --- /dev/null +++ b/src/examples/evas/evas-vg-simple.c @@ -0,0 +1,572 @@ +/** + * Simple Evas example illustrating a Evas_VG basic node usage. + * + * You'll need at least one engine built for it (excluding the buffer + * one). See stdout/stderr for output. + * + * @verbatim + * gcc -o evas_vg_simple evas-vg-simple.c `pkg-config --libs --cflags evas ecore ecore-evas eina ector eo efl` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#else +#define PACKAGE_EXAMPLES_DIR "." +#endif + +#define WIDTH 400 +#define HEIGHT 400 + +#ifndef EFL_BETA_API_SUPPORT +#define EFL_BETA_API_SUPPORT 1 +#endif + +#ifndef EFL_EO_API_SUPPORT +#define EFL_EO_API_SUPPORT 1 +#endif + +#include +#include +#include +#include +#include + + +#include +#include + +#define PATH_KAPPA 0.5522847498 +#define PI 3.1415926535 + +typedef struct _Bezier +{ +float x1, y1, x2, y2, x3, y3, x4, y4; +}Bezier; + +typedef struct _Point +{ + int x; + int y; +}Point; + +static +Bezier bezierFromPoints(Point p1, Point p2, + Point p3, Point p4) +{ + Bezier b; + b.x1 = p1.x; + b.y1 = p1.y; + b.x2 = p2.x; + b.y2 = p2.y; + b.x3 = p3.x; + b.y3 = p3.y; + b.x4 = p4.x; + b.y4 = p4.y; + return b; +} + +inline void +parameterSplitLeft(Bezier *b, float t, Bezier *left) +{ + left->x1 = b->x1; + left->y1 = b->y1; + + left->x2 = b->x1 + t * ( b->x2 - b->x1 ); + left->y2 = b->y1 + t * ( b->y2 - b->y1 ); + + left->x3 = b->x2 + t * ( b->x3 - b->x2 ); // temporary holding spot + left->y3 = b->y2 + t * ( b->y3 - b->y2 ); // temporary holding spot + + b->x3 = b->x3 + t * ( b->x4 - b->x3 ); + b->y3 = b->y3 + t * ( b->y4 - b->y3 ); + + b->x2 = left->x3 + t * ( b->x3 - left->x3); + b->y2 = left->y3 + t * ( b->y3 - left->y3); + + left->x3 = left->x2 + t * ( left->x3 - left->x2 ); + left->y3 = left->y2 + t * ( left->y3 - left->y2 ); + + left->x4 = b->x1 = left->x3 + t * (b->x2 - left->x3); + left->y4 = b->y1 = left->y3 + t * (b->y2 - left->y3); +} +static +Bezier bezierOnInterval(Bezier *b, float t0, float t1) +{ + if (t0 == 0 && t1 == 1) + return *b; + + Bezier result; + parameterSplitLeft(b, t0, &result); + float trueT = (t1-t0)/(1-t0); + parameterSplitLeft(b, trueT, &result); + + return result; +} + +inline void +_bezier_coefficients(float t, float *ap, float *bp, float *cp, float *dp) +{ + float a,b,c,d; + float m_t = 1. - t; + b = m_t * m_t; + c = t * t; + d = c * t; + a = b * m_t; + b *= 3. * t; + c *= 3. * m_t; + *ap = a; + *bp = b; + *cp = c; + *dp = d; +} + +static +float _t_for_arc_angle(float angle) +{ + if (angle < 0.00001) + return 0; + + if (angle == 90.0) + return 1; + + float radians = PI * angle / 180; + float cosAngle = cos(radians); + float sinAngle = sin(radians); + + // initial guess + float tc = angle / 90; + // do some iterations of newton's method to approximate cosAngle + // finds the zero of the function b.pointAt(tc).x() - cosAngle + tc -= ((((2-3*PATH_KAPPA) * tc + 3*(PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value + / (((6-9*PATH_KAPPA) * tc + 6*(PATH_KAPPA-1)) * tc); // derivative + tc -= ((((2-3*PATH_KAPPA) * tc + 3*(PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value + / (((6-9*PATH_KAPPA) * tc + 6*(PATH_KAPPA-1)) * tc); // derivative + + // initial guess + float ts = tc; + // do some iterations of newton's method to approximate sinAngle + // finds the zero of the function b.pointAt(tc).y() - sinAngle + ts -= ((((3*PATH_KAPPA-2) * ts - 6*PATH_KAPPA + 3) * ts + 3*PATH_KAPPA) * ts - sinAngle) + / (((9*PATH_KAPPA-6) * ts + 12*PATH_KAPPA - 6) * ts + 3*PATH_KAPPA); + ts -= ((((3*PATH_KAPPA-2) * ts - 6*PATH_KAPPA + 3) * ts + 3*PATH_KAPPA) * ts - sinAngle) + / (((9*PATH_KAPPA-6) * ts + 12*PATH_KAPPA - 6) * ts + 3*PATH_KAPPA); + + // use the average of the t that best approximates cosAngle + // and the t that best approximates sinAngle + float t = 0.5 * (tc + ts); + return t; +} + +static void +_find_ellipse_coords(int x, int y, int w, int h, float angle, float length, + Point* startPoint, Point *endPoint) +{ + if (!w || !h ) { + if (startPoint) + startPoint->x = 0 , startPoint->y = 0; + if (endPoint) + endPoint->x = 0 , endPoint->y = 0; + return; + } + + int w2 = w / 2; + int h2 = h / 2; + + float angles[2] = { angle, angle + length }; + Point *points[2] = { startPoint, endPoint }; + int i =0; + for (i = 0; i < 2; ++i) { + if (!points[i]) + continue; + + float theta = angles[i] - 360 * floor(angles[i] / 360); + float t = theta / 90; + // truncate + int quadrant = (int)t; + t -= quadrant; + + t = _t_for_arc_angle(90 * t); + + // swap x and y? + if (quadrant & 1) + t = 1 - t; + + float a, b, c, d; + _bezier_coefficients(t, &a, &b, &c, &d); + float px = a + b + c*PATH_KAPPA; + float py = d + c + b*PATH_KAPPA; + + // left quadrants + if (quadrant == 1 || quadrant == 2) + px = -px; + + // top quadrants + if (quadrant == 0 || quadrant == 1) + py = -py; + int cx = x+w/2; + int cy = y+h/2; + points[i]->x = cx + w2 * px; + points[i]->y = cy + h2 * py; + } +} + + +//// The return value is the starting point of the arc +static +Point _curves_for_arc(int x, int y, int w, int h, + float startAngle, float sweepLength, + Point *curves, int *point_count) +{ + *point_count = 0; + int w2 = w / 2; + int w2k = w2 * PATH_KAPPA; + + int h2 = h / 2; + int h2k = h2 * PATH_KAPPA; + + Point points[16] = + { + // start point + { x + w, y + h2 }, + + // 0 -> 270 degrees + { x + w, y + h2 + h2k }, + { x + w2 + w2k, y + h }, + { x + w2, y + h }, + + // 270 -> 180 degrees + { x + w2 - w2k, y + h }, + { x, y + h2 + h2k }, + { x, y + h2 }, + + // 180 -> 90 degrees + { x, y + h2 - h2k }, + { x + w2 - w2k, y }, + { x + w2, y }, + + // 90 -> 0 degrees + { x + w2 + w2k, y }, + { x + w, y + h2 - h2k }, + { x + w, y + h2 } + }; + + if (sweepLength > 360) sweepLength = 360; + else if (sweepLength < -360) sweepLength = -360; + + // Special case fast paths + if (startAngle == 0) { + if (sweepLength == 360) { + int i; + for (i = 11; i >= 0; --i) + curves[(*point_count)++] = points[i]; + return points[12]; + } else if (sweepLength == -360) { + int i ; + for (i = 1; i <= 12; ++i) + curves[(*point_count)++] = points[i]; + return points[0]; + } + } + + int startSegment = (int)(floor(startAngle / 90)); + int endSegment = (int)(floor((startAngle + sweepLength) / 90)); + + float startT = (startAngle - startSegment * 90) / 90; + float endT = (startAngle + sweepLength - endSegment * 90) / 90; + + int delta = sweepLength > 0 ? 1 : -1; + if (delta < 0) { + startT = 1 - startT; + endT = 1 - endT; + } + + // avoid empty start segment + if (startT == 1.0) { + startT = 0; + startSegment += delta; + } + + // avoid empty end segment + if (endT == 0) { + endT = 1; + endSegment -= delta; + } + + startT = _t_for_arc_angle(startT * 90); + endT = _t_for_arc_angle(endT * 90); + + Eina_Bool splitAtStart = !(fabs(startT) <= 0.00001f); + Eina_Bool splitAtEnd = !(fabs(endT - 1.0) <= 0.00001f); + + const int end = endSegment + delta; + + // empty arc? + if (startSegment == end) { + const int quadrant = 3 - ((startSegment % 4) + 4) % 4; + const int j = 3 * quadrant; + return delta > 0 ? points[j + 3] : points[j]; + } + + + Point startPoint, endPoint; + _find_ellipse_coords(x, y, w, h, startAngle, sweepLength, &startPoint, &endPoint); + int i; + for (i = startSegment; i != end; i += delta) { + const int quadrant = 3 - ((i % 4) + 4) % 4; + const int j = 3 * quadrant; + + Bezier b; + if (delta > 0) + b = bezierFromPoints(points[j + 3], points[j + 2], points[j + 1], points[j]); + else + b = bezierFromPoints(points[j], points[j + 1], points[j + 2], points[j + 3]); + + // empty arc? + if (startSegment == endSegment && (startT == endT)) + return startPoint; + + if (i == startSegment) { + if (i == endSegment && splitAtEnd) + b = bezierOnInterval(&b, startT, endT); + else if (splitAtStart) + b = bezierOnInterval(&b, startT, 1); + } else if (i == endSegment && splitAtEnd) { + b = bezierOnInterval(&b, 0, endT); + } + + // push control points + curves[(*point_count)].x = b.x2; + curves[(*point_count)++].y = b.y2; + curves[(*point_count)].x = b.x3; + curves[(*point_count)++].y = b.y3; + curves[(*point_count)].x = b.x4; + curves[(*point_count)++].y = b.y4; + } + + curves[*(point_count)-1] = endPoint; + + return startPoint; +} + +void _arcto(Efl_VG *obj, int x, int y, int width, int height, int startAngle, int sweepLength) +{ + int point_count; + + Point pts[15]; + Point curve_start = _curves_for_arc(x, y, width, height, startAngle, sweepLength, pts, &point_count); + int cx = x + (width)/2; + int cy = y + (height)/2; + int i; + + evas_vg_shape_shape_append_move_to(obj, cx, cy); + evas_vg_shape_shape_append_line_to(obj, curve_start.x, curve_start.y); + for (i = 0; i < point_count; i += 3) + { + evas_vg_shape_shape_append_cubic_to(obj, + pts[i+2].x, pts[i+2].y, + pts[i].x, pts[i].y, + pts[i+1].x, pts[i+1].y); + } + evas_vg_shape_shape_append_close(obj); +} + +void _rect_add(Efl_VG *obj, int x, int y, int w, int h) +{ + evas_vg_shape_shape_append_move_to(obj, x, y); + evas_vg_shape_shape_append_line_to(obj, x + w, y); + evas_vg_shape_shape_append_line_to(obj, x + w, y +h); + evas_vg_shape_shape_append_line_to(obj, x, y +h); + evas_vg_shape_shape_append_close(obj); +} + + +struct example_data +{ + Ecore_Evas *ee; + Evas *evas; + Evas_Object *bg; + Evas_Object *vg; +}; + +static struct example_data d; + +static void +_on_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void /* adjust canvas' contents on resizes */ +_canvas_resize_cb(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + evas_object_resize(d.bg, w, h); + evas_object_resize(d.vg, w, h); +} + +static void +vector_set(int x, int y, int w, int h) +{ + int vg_w = w, vg_h = h; + + //Create VG Object + + Evas_Object *tmp = evas_object_rectangle_add(d.evas); + evas_object_resize(tmp, vg_w, vg_h); + evas_object_color_set(tmp, 100, 100, 50, 100); + evas_object_move(tmp, x,y); + evas_object_show(tmp); + + d.vg = evas_object_vg_add(d.evas); + evas_object_resize(d.vg, vg_w, vg_h); + evas_object_move(d.vg, x,y); + evas_object_show(d.vg); + evas_object_clip_set(d.vg, tmp); + + // Applying map on the evas_object_vg +// Evas_Map *m = evas_map_new(4); +// evas_map_smooth_set(m, EINA_TRUE); +// evas_map_util_points_populate_from_object_full(m, d.vg, 0); +// evas_map_util_rotate(m, 10, 0,0); +// evas_object_map_enable_set(d.vg, EINA_TRUE); +// evas_object_map_set(d.vg, m); + + // apply some transformation + double radian = 30.0 * 2 * 3.141 / 360.0; + Eina_Matrix3 matrix; + eina_matrix3_rotate(&matrix, radian); + + Efl_VG *root = evas_object_vg_root_node_get(d.vg); + //eo_do(root, evas_vg_node_transformation_set(&matrix)); + + Efl_VG *bg = eo_add(EFL_VG_SHAPE_CLASS, root); + _rect_add(bg, 0, 0 , vg_w, vg_h); + evas_vg_node_origin_set(bg, 0,0); + evas_vg_shape_stroke_width_set(bg, 1.0); + evas_vg_node_color_set(bg, 80, 80, 80, 80); + + Efl_VG *shape = eo_add(EFL_VG_SHAPE_CLASS, root); + Efl_VG *rgradient = eo_add(EFL_VG_GRADIENT_RADIAL_CLASS, root); + Efl_VG *lgradient = eo_add(EFL_VG_GRADIENT_LINEAR_CLASS, root); + + _arcto(shape, 0, 0, 100, 100, 25, 330); + + Efl_Gfx_Gradient_Stop stops[3]; + stops[0].r = 255; + stops[0].g = 0; + stops[0].b = 0; + stops[0].a = 255; + stops[0].offset = 0; + stops[1].r = 0; + stops[1].g = 255; + stops[1].b = 0; + stops[1].a = 255; + stops[1].offset = 0.5; + stops[2].r = 0; + stops[2].g = 0; + stops[2].b = 255; + stops[2].a = 255; + stops[2].offset = 1; + + evas_vg_node_origin_set(rgradient, 10, 10); + evas_vg_gradient_spread_set(rgradient, EFL_GFX_GRADIENT_SPREAD_REFLECT); + evas_vg_gradient_stop_set(rgradient, stops, 3); + evas_vg_gradient_radial_center_set(rgradient, 30, 30); + evas_vg_gradient_radial_radius_set(rgradient, 80); + + evas_vg_node_origin_set(lgradient, 10, 10); + evas_vg_gradient_stop_set(lgradient, stops, 3); + evas_vg_gradient_spread_set(lgradient, EFL_GFX_GRADIENT_SPREAD_REFLECT); + evas_vg_gradient_stop_set(lgradient, stops, 3); + evas_vg_gradient_linear_start_set(lgradient, 10, 10); + evas_vg_gradient_linear_end_set(lgradient, 50, 50); + + evas_vg_node_origin_set(shape, 10, 10); + evas_vg_shape_fill_set(shape, rgradient); + evas_vg_shape_stroke_scale_set(shape, 2.0); + evas_vg_shape_stroke_width_set(shape, 1.0); + evas_vg_node_color_set(shape, 0, 0, 255, 255); + evas_vg_shape_stroke_color_set(shape, 0, 0, 255, 128); + + Efl_VG *rect = eo_add(EFL_VG_SHAPE_CLASS, root); + _rect_add(rect, 0, 0, 100, 100); + evas_vg_node_origin_set(rect, 100, 100); + evas_vg_shape_fill_set(rect, lgradient); + evas_vg_shape_stroke_width_set(rect, 2.0); + evas_vg_shape_stroke_join_set(rect, EFL_GFX_JOIN_ROUND); + evas_vg_shape_stroke_color_set(rect, 255, 255, 255, 255); + + Efl_VG *rect1 = eo_add(EFL_VG_SHAPE_CLASS, root); + _rect_add(rect1, 0, 0, 70, 70); + evas_vg_node_origin_set(rect1, 50, 70); + evas_vg_shape_stroke_scale_set(rect1, 2); + evas_vg_shape_stroke_width_set(rect1, 8.0); + evas_vg_shape_stroke_join_set(rect1, EFL_GFX_JOIN_ROUND); + evas_vg_shape_stroke_color_set(rect1, 0, 100, 80, 100); + + Efl_VG *circle = eo_add(EFL_VG_SHAPE_CLASS, root); + _arcto(circle, 0, 0, 250, 100, 30, 300); + evas_vg_shape_fill_set(circle, lgradient); + //evas_vg_node_transformation_set(&matrix), + evas_vg_node_origin_set(circle, 50,50); + evas_vg_node_color_set(circle, 50, 0, 0, 50); + + // Foreground + Efl_VG *fg = eo_add(EFL_VG_SHAPE_CLASS, root); + _rect_add(fg, 0, 0, vg_w, vg_h); + evas_vg_node_origin_set(fg, 0, 0); + evas_vg_shape_stroke_width_set(fg, 5.0); + evas_vg_shape_stroke_join_set(fg, EFL_GFX_JOIN_ROUND); + evas_vg_shape_stroke_color_set(fg, 70, 70, 0, 70); + + Efl_VG *tst = eo_add(EFL_VG_SHAPE_CLASS, root); + evas_vg_shape_shape_append_rect(tst, 50, 25, 200, 200, 3, 5); + evas_vg_node_color_set(tst, 0, 0, 200, 200); + evas_vg_shape_stroke_width_set(tst, 2); + evas_vg_shape_stroke_color_set(tst, 255, 0, 0, 255); + + Efl_VG *vc = eo_add(EFL_VG_SHAPE_CLASS, root); + evas_vg_shape_shape_append_circle(vc, 100, 100, 23); + evas_vg_node_color_set(vc, 0, 200, 0, 255); + evas_vg_shape_stroke_width_set(vc, 4); + evas_vg_shape_stroke_color_set(vc, 255, 0, 0, 255); +} + +int +main(void) +{ + if (!ecore_evas_init()) + return EXIT_FAILURE; + + /* this will give you a window with an Evas canvas under the first + * engine available */ + d.ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!d.ee) + goto error; + + ecore_evas_callback_delete_request_set(d.ee, _on_delete); + ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb); + ecore_evas_show(d.ee); + + d.evas = ecore_evas_get(d.ee); + + d.bg = evas_object_rectangle_add(d.evas); + evas_object_color_set(d.bg, 70, 70, 70, 255); /* white bg */ + evas_object_show(d.bg); + + _canvas_resize_cb(d.ee); + + vector_set(50, 50, 300 ,300); + //vector_set(30, 90, 300 ,300); + + ecore_main_loop_begin(); + ecore_evas_shutdown(); + return 0; + +error: + ecore_evas_shutdown(); + return -1; +} diff --git a/src/examples/evas/evas_cxx_rectangle.cc b/src/examples/evas/evas_cxx_rectangle.cc index d307200a8b..d41902f109 100644 --- a/src/examples/evas/evas_cxx_rectangle.cc +++ b/src/examples/evas/evas_cxx_rectangle.cc @@ -44,7 +44,7 @@ int main() rect.color_set(255, 0, 0, 255); rect.position_set(10, 10); rect.size_set(100, 100); - rect.visibility_set(true); + rect.visible_set(true); canvas.render(); } diff --git a/src/lib/ector/Ector.h b/src/lib/ector/Ector.h new file mode 100644 index 0000000000..e08c2ed4bc --- /dev/null +++ b/src/lib/ector/Ector.h @@ -0,0 +1,190 @@ +#ifndef ECTOR_H_ +#define ECTOR_H_ + +#include +#include +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECTOR_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EO_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page ector_main Ector + * + * @date 2014 (created) + * + * @section toc Table of Contents + * + * @li @ref ector_main_intro + * @li @ref ector_main_compiling + * @li @ref ector_main_next_steps + * @li @ref ector_main_intro_example + * + * @section ector_main_intro Introduction + * + * Ector is a retained mode drawing library that is designed to work + * for and with an scenegraph like Evas. + * + * @section ector_main_compiling How to compile + * + * Ector is a library your application links to. The procedure for this is + * very simple. You simply have to compile your application with the + * appropriate compiler flags that the @c pkg-config script outputs. For + * example: + * + * Compiling C or C++ files into object files: + * + * @verbatim + gcc -c -o main.o main.c `pkg-config --cflags ector` + @endverbatim + * + * Linking object files into a binary executable: + * + * @verbatim + gcc -o my_application main.o `pkg-config --libs ector` + @endverbatim + * + * See @ref pkgconfig + * + * @section ector_main_next_steps Next Steps + * + * After you understood what Ector is and installed it in your system + * you should proceed understanding the programming interface. + * + * Recommended reading: + * + * @li @ref Ector_Surface + * @li @ref Ector_Renderer + * + * @section ector_main_intro_example Introductory Example + * + * @ref Ector_Tutorial + * + * + * @addtogroup Ector + * @{ + */ + +#ifdef EFL_BETA_API_SUPPORT + +/** + * @typedef Ector_Surface + * The base type to render content into. + */ +typedef Eo Ector_Surface; + +/** + * @typedef Ector_Renderer + * The base type describing what to render. + */ +typedef Eo Ector_Renderer; + +/** + * @typedef Ector_Colorspace + * The definiton of colorspace. + */ + // FIXME: Enable that when we have merged Emile +/* typedef Evas_Colorspace Ector_Colorspace; */ + +/** + * Raster operations at pixel level + */ +typedef enum _Ector_Rop +{ + ECTOR_ROP_BLEND, /**< D = S + D(1 - Sa) */ + ECTOR_ROP_COPY, /**< D = S */ + ECTOR_ROP_LAST +} Ector_Rop; + +/** + * Quality values + */ +typedef enum _Ector_Quality +{ + ECTOR_QUALITY_BEST, /**< Best quality */ + ECTOR_QUALITY_GOOD, /**< Good quality */ + ECTOR_QUALITY_FAST, /**< Lower quality, fastest */ + ECTOR_QUALITY_LAST +} Ector_Quality; + +/** + * Priorities + */ +typedef enum _Ector_Priority +{ + ECTOR_PRIORITY_NONE = 0, + ECTOR_PRIORITY_MARGINAL = 64, + ECTOR_PRIORITY_SECONDARY = 128, + ECTOR_PRIORITY_PRIMARY = 256, +} Ector_Priority; + +/** + * What kind of update is being pushed + */ +typedef enum _Ector_Update_Type +{ + ECTOR_UPDATE_BACKGROUND = 1, /* All the previous state in that area is reset to the new updated profile */ + ECTOR_UPDATE_EMPTY = 2, /* Pushing empty area (no visible pixels at all, no need to read this surface to render it) */ + ECTOR_UPDATE_ALPHA = 4, /* Pushing some transparent pixels (this impact the under layer and will require to read back the surface where this surface is blitted) */ + ECTOR_UPDATE_OPAQUE = 8 /* Pushing some opaque pixels (this means that their is no need to read the under layer when blitting this surface) */ +} Ector_Update_Type; + +/** + * @brief Init the ector subsystem + * @return @c EINA_TRUE on success. + * + * @see ector_shutfown() + */ +EAPI int ector_init(void); + +/** + * @brief Shutdown the ector subsystem + * @return @c EINA_TRUE on success. + * + * @see ector_init() + */ +EAPI int ector_shutdown(void); + +#include "ector_surface.h" +#include "ector_renderer.h" +#include "ector_util.h" + +#endif + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ector/cairo/Ector_Cairo.h b/src/lib/ector/cairo/Ector_Cairo.h new file mode 100644 index 0000000000..e368ca2803 --- /dev/null +++ b/src/lib/ector/cairo/Ector_Cairo.h @@ -0,0 +1,15 @@ +#ifndef ECTOR_CAIRO_H_ +# define ECTOR_CAIRO_H_ + +#include + +typedef Eo Ector_Cairo_Surface; +typedef struct _cairo_t cairo_t; + +#include "cairo/ector_cairo_surface.eo.h" +#include "cairo/ector_renderer_cairo_base.eo.h" +#include "cairo/ector_renderer_cairo_shape.eo.h" +#include "cairo/ector_renderer_cairo_gradient_linear.eo.h" +#include "cairo/ector_renderer_cairo_gradient_radial.eo.h" + +#endif diff --git a/src/lib/ector/cairo/ector_cairo_private.h b/src/lib/ector/cairo/ector_cairo_private.h new file mode 100644 index 0000000000..b5782ffafc --- /dev/null +++ b/src/lib/ector/cairo/ector_cairo_private.h @@ -0,0 +1,75 @@ +#ifndef ECTOR_CAIRO_PRIVATE_H_ +# define ECTOR_CAIRO_PRIVATE_H_ + +typedef void cairo_pattern_t; + +typedef struct { + double xx; double yx; + double xy; double yy; + double x0; double y0; +} cairo_matrix_t; + +typedef struct _Ector_Cairo_Surface_Data Ector_Cairo_Surface_Data; +typedef struct _Ector_Renderer_Cairo_Base_Data Ector_Renderer_Cairo_Base_Data; + +struct _Ector_Cairo_Surface_Data +{ + cairo_t *cairo; + struct { + double x, y; + } current; + + Eina_Bool internal : 1; +}; + +struct _Ector_Renderer_Cairo_Base_Data +{ + Ector_Cairo_Surface_Data *parent; + Ector_Renderer_Generic_Base_Data *generic; + + cairo_matrix_t *m; +}; + +typedef enum _cairo_extend { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD +} cairo_extend_t; + +static inline cairo_extend_t +_ector_cairo_extent_get(Efl_Gfx_Gradient_Spread s) +{ + switch (s) + { + case EFL_GFX_GRADIENT_SPREAD_PAD: + return CAIRO_EXTEND_PAD; + case EFL_GFX_GRADIENT_SPREAD_REFLECT: + return CAIRO_EXTEND_REFLECT; + case EFL_GFX_GRADIENT_SPREAD_REPEAT: + return CAIRO_EXTEND_REPEAT; + default: + return CAIRO_EXTEND_NONE; + } +} + +#define CHECK_CAIRO(Parent) (!(Parent && Parent->cairo)) + +#define USE(Obj, Sym, Error) \ + if (!Sym) Sym = _ector_cairo_symbol_get(Obj, #Sym); \ + if (!Sym) return Error; + +static inline void * +_ector_cairo_symbol_get(Eo *obj, const char *name) +{ + Eo *parent; + void *sym; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return NULL; + + eo_do(parent, sym = ector_cairo_surface_symbol_get(name)); + return sym; +} + +#endif diff --git a/src/lib/ector/cairo/ector_cairo_surface.c b/src/lib/ector/cairo/ector_cairo_surface.c new file mode 100644 index 0000000000..377fbbd0ca --- /dev/null +++ b/src/lib/ector/cairo/ector_cairo_surface.c @@ -0,0 +1,145 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_cairo_private.h" + +static unsigned int _cairo_count = 0; +static Eina_Module *_cairo_so = NULL; + +static void * +_ector_cairo_surface_symbol_get(Eo *obj EINA_UNUSED, + Ector_Cairo_Surface_Data *pd EINA_UNUSED, + const char *name) +{ + if (!_cairo_so) + { +#define LOAD(x) \ + if (!_cairo_so) \ + { \ + _cairo_so = eina_module_new(x); \ + if (_cairo_so && \ + !eina_module_load(_cairo_so)) \ + { \ + eina_module_free(_cairo_so); \ + _cairo_so = NULL; \ + } \ + } +#if defined(_WIN32) || defined(__CYGWIN__) + LOAD("libcairo.dll"); +#elif defined(__APPLE__) && defined(__MACH__) + LOAD("libcairo.dylib"); + LOAD("libcairo.so"); +#else + LOAD("libcairo.so"); +#endif + +#undef LOAD + } + + if (!_cairo_so) + { + ERR("Couldn't find cairo library. Please make sure that your system can locate it."); + return NULL; + } + + return eina_module_symbol_get(_cairo_so, name); +} + +#undef USE +#define USE(Obj, Sym, Error) \ + if (!Sym) Sym = _ector_cairo_surface_symbol_get(Obj, NULL, #Sym); \ + if (!Sym) return Error; + +static Ector_Renderer * +_ector_cairo_surface_ector_generic_surface_renderer_factory_new(Eo *obj, + Ector_Cairo_Surface_Data *pd EINA_UNUSED, + const Eo_Class *type) +{ + if (type == ECTOR_RENDERER_GENERIC_SHAPE_MIXIN) + return eo_add(ECTOR_RENDERER_CAIRO_SHAPE_CLASS, obj); + else if (type == ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN) + return eo_add(ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, obj); + else if (type == ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN) + return eo_add(ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, obj); + ERR("Couldn't find class for type: %s\n", eo_class_name_get(type)); + return NULL; +} + +typedef struct _cairo_surface_t cairo_surface_t; + +static void (*cairo_destroy)(cairo_t *cr) = NULL; +static cairo_surface_t *(*cairo_image_surface_create)(int format, + int width, + int height) = NULL; +static cairo_t *(*cairo_create)(cairo_surface_t *target) = NULL; + +static cairo_surface_t *internal = NULL; + +static void +_ector_cairo_surface_context_set(Eo *obj, + Ector_Cairo_Surface_Data *pd, + cairo_t *ctx) +{ + if (pd->internal) + { + USE(obj, cairo_destroy, ); + + if (pd->cairo) cairo_destroy(pd->cairo); + pd->internal = EINA_FALSE; + } + if (!ctx) + { + USE(obj, cairo_image_surface_create, ); + USE(obj, cairo_create, ); + + if (!internal) internal = cairo_image_surface_create(0, 1, 1); + ctx = cairo_create(internal); + } + pd->current.x = pd->current.y = 0; + pd->cairo = ctx; +} + +static cairo_t * +_ector_cairo_surface_context_get(Eo *obj EINA_UNUSED, + Ector_Cairo_Surface_Data *pd) +{ + return pd->cairo; +} + +static void +_ector_cairo_surface_ector_generic_surface_reference_point_set(Eo *obj EINA_UNUSED, + Ector_Cairo_Surface_Data *pd, + int x, int y) +{ + pd->current.x = x; + pd->current.y = y; +} + +static void +_ector_cairo_surface_eo_base_constructor(Eo *obj, + Ector_Cairo_Surface_Data *pd) +{ + eo_do_super(obj, ECTOR_CAIRO_SURFACE_CLASS, eo_constructor()); + _cairo_count++; + + _ector_cairo_surface_context_set(obj, pd, NULL); +} + +static void +_ector_cairo_surface_eo_base_destructor(Eo *obj EINA_UNUSED, + Ector_Cairo_Surface_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, ECTOR_CAIRO_SURFACE_CLASS, eo_destructor()); + + if (--_cairo_count) return ; + if (_cairo_so) eina_module_free(_cairo_so); + _cairo_so = NULL; +} + +#include "ector_cairo_surface.eo.c" diff --git a/src/lib/ector/cairo/ector_cairo_surface.eo b/src/lib/ector/cairo/ector_cairo_surface.eo new file mode 100644 index 0000000000..298c681d78 --- /dev/null +++ b/src/lib/ector/cairo/ector_cairo_surface.eo @@ -0,0 +1,30 @@ +class Ector.Cairo.Surface (Ector.Generic.Surface) +{ + eo_prefix: ector_cairo_surface; + legacy_prefix: null; + properties { + context { + set { + } + get { + } + values { + cairo_t *ctx; + } + } + } + methods { + symbol_get { + return: void * @warn_unused; + params { + @in const(char)* name; + } + } + } + implements { + Ector.Generic.Surface.renderer_factory_new; + Ector.Generic.Surface.reference_point.set; + Eo.Base.destructor; + Eo.Base.constructor; + } +} diff --git a/src/lib/ector/cairo/ector_renderer_cairo_base.c b/src/lib/ector/cairo/ector_renderer_cairo_base.c new file mode 100644 index 0000000000..795b57cce5 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_base.c @@ -0,0 +1,217 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "ector_private.h" +#include "ector_cairo_private.h" + +typedef enum { + CAIRO_OPERATOR_CLEAR, + + CAIRO_OPERATOR_SOURCE, + CAIRO_OPERATOR_OVER, + CAIRO_OPERATOR_IN, + CAIRO_OPERATOR_OUT, + CAIRO_OPERATOR_ATOP, + + CAIRO_OPERATOR_DEST, + CAIRO_OPERATOR_DEST_OVER, + CAIRO_OPERATOR_DEST_IN, + CAIRO_OPERATOR_DEST_OUT, + CAIRO_OPERATOR_DEST_ATOP, + + CAIRO_OPERATOR_XOR, + CAIRO_OPERATOR_ADD, + CAIRO_OPERATOR_SATURATE, + + CAIRO_OPERATOR_MULTIPLY, + CAIRO_OPERATOR_SCREEN, + CAIRO_OPERATOR_OVERLAY, + CAIRO_OPERATOR_DARKEN, + CAIRO_OPERATOR_LIGHTEN, + CAIRO_OPERATOR_COLOR_DODGE, + CAIRO_OPERATOR_COLOR_BURN, + CAIRO_OPERATOR_HARD_LIGHT, + CAIRO_OPERATOR_SOFT_LIGHT, + CAIRO_OPERATOR_DIFFERENCE, + CAIRO_OPERATOR_EXCLUSION, + CAIRO_OPERATOR_HSL_HUE, + CAIRO_OPERATOR_HSL_SATURATION, + CAIRO_OPERATOR_HSL_COLOR, + CAIRO_OPERATOR_HSL_LUMINOSITY +} cairo_operator_t; + +static void (*cairo_translate)(cairo_t *cr, double tx, double ty) = NULL; +static void (*cairo_matrix_init)(cairo_matrix_t *matrix, + double xx, double yx, + double xy, double yy, + double x0, double y0) = NULL; +static void (*cairo_transform)(cairo_t *cr, const cairo_matrix_t *matrix) = NULL; +static void (*cairo_set_source_rgba)(cairo_t *cr, + double red, double green, double blue, + double alpha) = NULL; +static void (*cairo_set_operator)(cairo_t *cr, cairo_operator_t op) = NULL; +static void (*cairo_matrix_init_identity)(cairo_matrix_t *matrix) = NULL; + +static void (*cairo_new_path)(cairo_t *cr) = NULL; +static void (*cairo_rectangle)(cairo_t *cr, double x, double y, double width, double height) = NULL; +static void (*cairo_clip)(cairo_t *cr) = NULL; +static void (*cairo_device_to_user)(cairo_t *cr, double *x, double *y) = NULL; + +static cairo_matrix_t identity; + +// Cairo need unpremul color, so force unpremul here +void +_ector_renderer_cairo_base_ector_renderer_generic_base_color_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Cairo_Base_Data *pd, + int r, int g, int b, int a) +{ + pd->generic->color.r = r; + pd->generic->color.g = g; + pd->generic->color.b = b; + pd->generic->color.a = a; +} + +void +_ector_renderer_cairo_base_ector_renderer_generic_base_color_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Cairo_Base_Data *pd, + int *r, int *g, int *b, int *a) +{ + if (r) *r = pd->generic->color.r; + if (g) *g = pd->generic->color.g; + if (b) *b = pd->generic->color.b; + if (a) *a = pd->generic->color.a; +} + +static Eina_Bool +_ector_renderer_cairo_base_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Cairo_Base_Data *pd) +{ + if (!pd->parent) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->parent = eo_data_xref(parent, ECTOR_CAIRO_SURFACE_CLASS, obj); + } + if (pd->generic->m) + { + USE(obj, cairo_matrix_init, EINA_FALSE); + + if (!pd->m) pd->m = malloc(sizeof (cairo_matrix_t)); + cairo_matrix_init(pd->m, + pd->generic->m->xx, pd->generic->m->yx, + pd->generic->m->xy, pd->generic->m->yy, + pd->generic->m->xz, pd->generic->m->yz); + } + else + { + free(pd->m); + pd->m = NULL; + } + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_cairo_base_ector_renderer_generic_base_draw(Eo *obj, + Ector_Renderer_Cairo_Base_Data *pd, + Ector_Rop op, + Eina_Array *clips EINA_UNUSED, + unsigned int mul_col) +{ + int r, g, b, a; + cairo_operator_t cop; + double cx, cy; + + USE(obj, cairo_translate, EINA_FALSE); + USE(obj, cairo_set_source_rgba, EINA_FALSE); + USE(obj, cairo_transform, EINA_FALSE); + USE(obj, cairo_set_operator, EINA_FALSE); + + switch (op) + { + case ECTOR_ROP_BLEND: + cop = CAIRO_OPERATOR_OVER; + break; + case ECTOR_ROP_COPY: + default: + cop = CAIRO_OPERATOR_SOURCE; + break; + } + + r = ((pd->generic->color.r * R_VAL(&mul_col)) >> 8); + g = ((pd->generic->color.g * G_VAL(&mul_col)) >> 8); + b = ((pd->generic->color.b * B_VAL(&mul_col)) >> 8); + a = ((pd->generic->color.a * A_VAL(&mul_col)) >> 8); + ector_color_argb_unpremul(a, &r, &g, &b); + + cairo_set_operator(pd->parent->cairo, cop); + cairo_transform(pd->parent->cairo, &identity); + cx = pd->generic->origin.x + pd->parent->current.x; + cy = pd->generic->origin.y + pd->parent->current.y; + + cairo_translate(pd->parent->cairo, cx, cy); + + if (pd->m) cairo_transform(pd->parent->cairo, pd->m); + + cairo_set_source_rgba(pd->parent->cairo, r/255.0, g/255.0, b/255.0, a/255.0); + + USE(obj, cairo_new_path, EINA_FALSE); + USE(obj, cairo_rectangle, EINA_FALSE); + USE(obj, cairo_clip, EINA_FALSE); + USE(obj, cairo_device_to_user, EINA_FALSE); + if (clips) + { + int clip_count = eina_array_count(clips); + int i=0; + for (; i < clip_count ; i++) + { + Eina_Rectangle *clip = (Eina_Rectangle *)eina_array_data_get(clips, i); + double x = (double)clip->x; + double y = (double)clip->y; + + cairo_new_path(pd->parent->cairo); + cairo_device_to_user(pd->parent->cairo, &x, &y); + cairo_rectangle(pd->parent->cairo, x, y, clip->w, clip->h); + } + cairo_clip(pd->parent->cairo); + } + + return EINA_TRUE; +} + +static void +_ector_renderer_cairo_base_eo_base_constructor(Eo *obj, Ector_Renderer_Cairo_Base_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, ECTOR_RENDERER_CAIRO_BASE_CLASS, eo_constructor()); + + pd->generic = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_BASE_CLASS, obj); + + USE(obj, cairo_matrix_init_identity, ); + + cairo_matrix_init_identity(&identity); +} + +static void +_ector_renderer_cairo_base_eo_base_destructor(Eo *obj, Ector_Renderer_Cairo_Base_Data *pd) +{ + Eo *parent; + + free(pd->m); + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->parent, obj); + eo_data_xunref(obj, pd->generic, obj); + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_BASE_CLASS, eo_destructor()); +} + +#include "ector_renderer_cairo_base.eo.c" diff --git a/src/lib/ector/cairo/ector_renderer_cairo_base.eo b/src/lib/ector/cairo/ector_renderer_cairo_base.eo new file mode 100644 index 0000000000..c34b9a847b --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_base.eo @@ -0,0 +1,18 @@ +abstract Ector.Renderer.Cairo.Base (Ector.Renderer.Generic.Base) +{ + legacy_prefix: null; + methods { + fill { + return: bool; + } + } + implements { + @virtual .fill; + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Generic.Base.color.set; + Ector.Renderer.Generic.Base.color.get; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c new file mode 100644 index 0000000000..15b4e42c31 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.c @@ -0,0 +1,165 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_cairo_private.h" + +static cairo_pattern_t *(*cairo_pattern_create_linear)(double x0, double y0, + double x1, double y1) = NULL; +static void (*cairo_set_source)(cairo_t *cr, cairo_pattern_t *source) = NULL; +static void (*cairo_fill)(cairo_t *cr) = NULL; +static void (*cairo_rectangle)(cairo_t *cr, + double x, double y, + double width, double height) = NULL; +static void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, + double red, double green, double blue, double alpha) = NULL; +static void (*cairo_pattern_destroy)(cairo_pattern_t *pattern) = NULL; + +static void (*cairo_pattern_set_extend)(cairo_pattern_t *pattern, cairo_extend_t extend) = NULL; + +typedef struct _Ector_Renderer_Cairo_Gradient_Linear_Data Ector_Renderer_Cairo_Gradient_Linear_Data; +struct _Ector_Renderer_Cairo_Gradient_Linear_Data +{ + Ector_Cairo_Surface_Data *parent; + cairo_pattern_t *pat; +}; + +static Eina_Bool +_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_prepare(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd) +{ + Ector_Renderer_Generic_Gradient_Linear_Data *gld; + Ector_Renderer_Generic_Gradient_Data *gd; + unsigned int i; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, ector_renderer_prepare()); + + if (pd->pat) return EINA_FALSE; + + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN); + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!gld || !gd) return EINA_FALSE; + + USE(obj, cairo_pattern_create_linear, EINA_FALSE); + USE(obj, cairo_pattern_add_color_stop_rgba, EINA_FALSE); + + pd->pat = cairo_pattern_create_linear(gld->start.x, gld->start.y, + gld->end.x, gld->end.y); + int r,g,b,a; + for (i = 0; i < gd->colors_count; i++) + { + r = gd->colors[i].r; + g = gd->colors[i].g; + b = gd->colors[i].b; + a = gd->colors[i].a; + ector_color_argb_unpremul(a, &r, &g, &b); + cairo_pattern_add_color_stop_rgba(pd->pat, gd->colors[i].offset, r/255.0, g/255.0, b/255.0, a/255.0); + } + + USE(obj, cairo_pattern_set_extend, EINA_FALSE); + cairo_pattern_set_extend(pd->pat, _ector_cairo_extent_get(gd->s)); + + if (!pd->parent) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->parent = eo_data_xref(parent, ECTOR_CAIRO_SURFACE_CLASS, obj); + } + + return EINA_FALSE; +} + +static Eina_Bool +_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_draw(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd, + Ector_Rop op, Eina_Array *clips, unsigned int mul_col) +{ + if (pd->pat) return EINA_FALSE; + + Ector_Renderer_Generic_Gradient_Linear_Data *gld; + + // FIXME: don't ignore clipping ! + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN); + if (!pd->pat || !gld) return EINA_FALSE; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, ector_renderer_draw(op, clips, mul_col)); + + USE(obj, cairo_rectangle, EINA_FALSE); + USE(obj, cairo_fill, EINA_FALSE); + + cairo_rectangle(pd->parent->cairo, gld->start.x, gld->start.y, + gld->end.x - gld->start.x, + gld->end.y - gld->start.y); + eo_do(obj, ector_renderer_cairo_base_fill()); + cairo_fill(pd->parent->cairo); + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_cairo_gradient_linear_ector_renderer_cairo_base_fill(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd) +{ + if (!pd->pat) return EINA_FALSE; + + USE(obj, cairo_set_source, EINA_FALSE); + + cairo_set_source(pd->parent->cairo, pd->pat); + + return EINA_TRUE; +} + +static void +_ector_renderer_cairo_gradient_linear_ector_renderer_generic_base_bounds_get(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd EINA_UNUSED, + Eina_Rectangle *r) +{ + Ector_Renderer_Generic_Gradient_Linear_Data *gld; + Ector_Renderer_Cairo_Base_Data *bd; + + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + bd = eo_data_scope_get(obj, ECTOR_RENDERER_CAIRO_BASE_CLASS); + EINA_RECTANGLE_SET(r, + bd->generic->origin.x + gld->start.x, + bd->generic->origin.y + gld->start.y, + gld->end.x - gld->start.x, + gld->end.y - gld->start.x); +} + +void +_ector_renderer_cairo_gradient_linear_eo_base_destructor(Eo *obj, + Ector_Renderer_Cairo_Gradient_Linear_Data *pd) +{ + Eo *parent; + + USE(obj, cairo_pattern_destroy, ); + + if (pd->pat) cairo_pattern_destroy(pd->pat); + pd->pat = NULL; + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->parent, obj); + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, eo_destructor()); +} + +void +_ector_renderer_cairo_gradient_linear_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Cairo_Gradient_Linear_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +{ + USE(obj, cairo_pattern_destroy, ); + + if (pd->pat) cairo_pattern_destroy(pd->pat); + pd->pat = NULL; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_LINEAR_CLASS, + efl_gfx_gradient_stop_set(colors, length)); +} + +#include "ector_renderer_cairo_gradient_linear.eo.c" diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.eo b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.eo new file mode 100644 index 0000000000..64c60561c5 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_linear.eo @@ -0,0 +1,13 @@ +class Ector.Renderer.Cairo.Gradient_Linear (Ector.Renderer.Cairo.Base, Ector.Renderer.Generic.Gradient, Ector.Renderer.Generic.Gradient_Linear) +{ + eo_prefix: ector_renderer_cairo_gradient_linear; + legacy_prefix: null; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Generic.Base.bounds_get; + Ector.Renderer.Cairo.Base.fill; + Eo.Base.destructor; + Efl.Gfx.Gradient.Base.stop.set; + } +} diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c new file mode 100644 index 0000000000..34a6d707f5 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.c @@ -0,0 +1,169 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_cairo_private.h" + +static cairo_pattern_t *(*cairo_pattern_create_radial)(double cx0, double cy0, + double radius0, + double cx1, double cy1, + double radius1) = NULL; +static void (*cairo_set_source)(cairo_t *cr, cairo_pattern_t *source) = NULL; +static void (*cairo_fill)(cairo_t *cr) = NULL; +static void (*cairo_arc)(cairo_t *cr, + double xc, double yc, + double radius, + double angle1, double angle2) = NULL; +static void (*cairo_pattern_add_color_stop_rgba)(cairo_pattern_t *pattern, double offset, + double red, double green, double blue, double alpha) = NULL; +static void (*cairo_pattern_destroy)(cairo_pattern_t *pattern) = NULL; + +static void (*cairo_pattern_set_extend)(cairo_pattern_t *pattern, cairo_extend_t extend) = NULL; + +// FIXME: as long as it is not possible to directly access the parent structure +// this will be duplicated from the linear gradient renderer +typedef struct _Ector_Renderer_Cairo_Gradient_Radial_Data Ector_Renderer_Cairo_Gradient_Radial_Data; +struct _Ector_Renderer_Cairo_Gradient_Radial_Data +{ + Ector_Cairo_Surface_Data *parent; + cairo_pattern_t *pat; +}; + +static Eina_Bool +_ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd) +{ + Ector_Renderer_Generic_Gradient_Radial_Data *grd; + Ector_Renderer_Generic_Gradient_Data *gd; + unsigned int i; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, ector_renderer_prepare()); + + if (pd->pat) return EINA_FALSE; + + grd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + gd = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN); + if (!grd || !gd) return EINA_FALSE; + + USE(obj, cairo_pattern_create_radial, EINA_FALSE); + USE(obj, cairo_pattern_add_color_stop_rgba, EINA_FALSE); + + pd->pat = cairo_pattern_create_radial(grd->focal.x, grd->focal.y, 0, + grd->radial.x, grd->radial.y, grd->radius); + + int r,g,b,a; + for (i = 0; i < gd->colors_count; i++) + { + r = gd->colors[i].r; + g = gd->colors[i].g; + b = gd->colors[i].b; + a = gd->colors[i].a; + ector_color_argb_unpremul(a, &r, &g, &b); + cairo_pattern_add_color_stop_rgba(pd->pat, gd->colors[i].offset, r/255.0, g/255.0, b/255.0, a/255.0); + } + + USE(obj, cairo_pattern_set_extend, EINA_FALSE); + cairo_pattern_set_extend(pd->pat, _ector_cairo_extent_get(gd->s)); + + if (!pd->parent) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->parent = eo_data_xref(parent, ECTOR_CAIRO_SURFACE_CLASS, obj); + } + + return EINA_FALSE; +} + +// Clearly duplicated and should be in a common place... +static Eina_Bool +_ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_draw(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col) +{ + if (pd->pat) return EINA_FALSE; + + Ector_Renderer_Generic_Gradient_Radial_Data *gld; + + // FIXME: don't ignore clipping ! + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + if (!pd->pat || !gld) return EINA_FALSE; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, ector_renderer_draw(op, clips, mul_col)); + + USE(obj, cairo_arc, EINA_FALSE); + USE(obj, cairo_fill, EINA_FALSE); + + cairo_arc(pd->parent->cairo, + gld->radial.x, gld->radial.y, + gld->radius, + 0, 2 * M_PI); + eo_do(obj, ector_renderer_cairo_base_fill()); + cairo_fill(pd->parent->cairo); + + return EINA_TRUE; +} + +// Clearly duplicated and should be in a common place... +static Eina_Bool +_ector_renderer_cairo_gradient_radial_ector_renderer_cairo_base_fill(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd) +{ + if (!pd->pat) return EINA_FALSE; + + USE(obj, cairo_set_source, EINA_FALSE); + + cairo_set_source(pd->parent->cairo, pd->pat); + + return EINA_TRUE; +} + +static void +_ector_renderer_cairo_gradient_radial_ector_renderer_generic_base_bounds_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Cairo_Gradient_Radial_Data *pd EINA_UNUSED, + Eina_Rectangle *r) +{ + Ector_Renderer_Generic_Gradient_Radial_Data *gld; + Ector_Renderer_Cairo_Base_Data *bd; + + gld = eo_data_scope_get(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN); + bd = eo_data_scope_get(obj, ECTOR_RENDERER_CAIRO_BASE_CLASS); + EINA_RECTANGLE_SET(r, + bd->generic->origin.x + gld->radial.x - gld->radius, + bd->generic->origin.y + gld->radial.y - gld->radius, + gld->radius * 2, gld->radius * 2); +} + +void +_ector_renderer_cairo_gradient_radial_eo_base_destructor(Eo *obj, + Ector_Renderer_Cairo_Gradient_Radial_Data *pd) +{ + Eo *parent; + + USE(obj, cairo_pattern_destroy, ); + + if (pd->pat) cairo_pattern_destroy(pd->pat); + pd->pat = NULL; + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->parent, obj); + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, eo_destructor()); +} + +void +_ector_renderer_cairo_gradient_radial_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Cairo_Gradient_Radial_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +{ + USE(obj, cairo_pattern_destroy, ); + + if (pd->pat) cairo_pattern_destroy(pd->pat); + pd->pat = NULL; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_GRADIENT_RADIAL_CLASS, + efl_gfx_gradient_stop_set(colors, length)); +} + +#include "ector_renderer_cairo_gradient_radial.eo.c" diff --git a/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.eo b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.eo new file mode 100644 index 0000000000..c05ad9ea05 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_gradient_radial.eo @@ -0,0 +1,13 @@ +class Ector.Renderer.Cairo.Gradient_Radial (Ector.Renderer.Cairo.Base, Ector.Renderer.Generic.Gradient, Ector.Renderer.Generic.Gradient_Radial) +{ + eo_prefix: ector_renderer_cairo_gradient_radial; + legacy_prefix: null; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Generic.Base.bounds_get; + Ector.Renderer.Cairo.Base.fill; + Eo.Base.destructor; + Efl.Gfx.Gradient.Base.stop.set; + } +} diff --git a/src/lib/ector/cairo/ector_renderer_cairo_shape.c b/src/lib/ector/cairo/ector_renderer_cairo_shape.c new file mode 100644 index 0000000000..de6aa6d184 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_shape.c @@ -0,0 +1,277 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "ector_private.h" +#include "ector_cairo_private.h" + +typedef struct _cairo_path_t cairo_path_t; + +typedef enum _cairo_line_cap { + CAIRO_LINE_CAP_BUTT, + CAIRO_LINE_CAP_ROUND, + CAIRO_LINE_CAP_SQUARE +} cairo_line_cap_t; + +typedef enum _cairo_line_join { + CAIRO_LINE_JOIN_MITER, + CAIRO_LINE_JOIN_ROUND, + CAIRO_LINE_JOIN_BEVEL +} cairo_line_join_t; + +static void (*cairo_move_to)(cairo_t *cr, double x, double y) = NULL; +static void (*cairo_line_to)(cairo_t *cr, double x, double y) = NULL; +static void (*cairo_curve_to)(cairo_t *cr, + double x1, double y1, + double x2, double y2, + double x3, double y3) = NULL; +static void (*cairo_close_path)(cairo_t *cr) = NULL; + +static void (*cairo_fill)(cairo_t *cr) = NULL; +static void (*cairo_fill_preserve)(cairo_t *cr) = NULL; +static void (*cairo_stroke)(cairo_t *cr) = NULL; + +static void (*cairo_set_source_rgba)(cairo_t *cr, + double red, double green, + double blue, double alpha) = NULL; + + +static cairo_path_t *(*cairo_copy_path)(cairo_t *cr) = NULL; +static void (*cairo_path_destroy)(cairo_path_t *path) = NULL; +static void (*cairo_new_path)(cairo_t *cr) = NULL; +static void (*cairo_append_path)(cairo_t *cr, const cairo_path_t *path) = NULL; + +static void (*cairo_set_line_width)(cairo_t *cr, double width) = NULL; +static void (*cairo_set_line_cap)(cairo_t *cr, cairo_line_cap_t line_cap) = NULL; +static void (*cairo_set_line_join)(cairo_t *cr, cairo_line_join_t line_join) = NULL; + +static void (*cairo_save)(cairo_t *cr) = NULL; +static void (*cairo_restore)(cairo_t *cr) = NULL; + +typedef struct _Ector_Renderer_Cairo_Shape_Data Ector_Renderer_Cairo_Shape_Data; +struct _Ector_Renderer_Cairo_Shape_Data +{ + Ector_Cairo_Surface_Data *parent; + Ector_Renderer_Generic_Shape_Data *shape; + Ector_Renderer_Generic_Base_Data *base; + cairo_path_t *path; +}; + +static Eina_Bool +_ector_renderer_cairo_shape_path_changed(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Ector_Renderer_Cairo_Shape_Data *pd = data; + + USE(obj, cairo_path_destroy, EINA_TRUE); + + if (pd->path) cairo_path_destroy(pd->path); + pd->path = NULL; + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_cairo_shape_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Cairo_Shape_Data *pd) +{ + const Efl_Gfx_Path_Command *cmds = NULL; + const double *pts = NULL; + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_SHAPE_CLASS, ector_renderer_prepare()); + + if (pd->shape->fill) + eo_do(pd->shape->fill, ector_renderer_prepare()); + if (pd->shape->stroke.fill) + eo_do(pd->shape->stroke.fill, ector_renderer_prepare()); + if (pd->shape->stroke.marker) + eo_do(pd->shape->stroke.marker, ector_renderer_prepare()); + + // shouldn't that be moved to the cairo base object + if (!pd->parent) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->parent = eo_data_xref(parent, ECTOR_CAIRO_SURFACE_CLASS, obj); + if (!pd->parent) return EINA_FALSE; + } + + eo_do(obj, efl_gfx_shape_path_get(&cmds, &pts)); + if (!pd->path && cmds) + { + USE(obj, cairo_new_path, EINA_FALSE); + + cairo_new_path(pd->parent->cairo); + + for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + USE(obj, cairo_move_to, EINA_FALSE); + + cairo_move_to(pd->parent->cairo, pts[0], pts[1]); + + pts += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + USE(obj, cairo_line_to, EINA_FALSE); + + cairo_line_to(pd->parent->cairo, pts[0], pts[1]); + + pts += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + USE(obj, cairo_curve_to, EINA_FALSE); + + // Be careful, we do have a different order than + // cairo, first is destination point, followed by + // the control point. The opposite of cairo. + cairo_curve_to(pd->parent->cairo, + pts[2], pts[3], pts[4], pts[5], // control points + pts[0], pts[1]); // destination point + + pts += 6; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: + USE(obj, cairo_close_path, EINA_FALSE); + + cairo_close_path(pd->parent->cairo); + break; + case EFL_GFX_PATH_COMMAND_TYPE_LAST: + case EFL_GFX_PATH_COMMAND_TYPE_END: + break; + } + } + + USE(obj, cairo_copy_path, EINA_FALSE); + + pd->path = cairo_copy_path(pd->parent->cairo); + } + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_cairo_shape_ector_renderer_generic_base_draw(Eo *obj, Ector_Renderer_Cairo_Shape_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col) +{ + int r, g, b, a; + if (pd->path == NULL) return EINA_FALSE; + + USE(obj, cairo_save, EINA_FALSE); + cairo_save(pd->parent->cairo); + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_SHAPE_CLASS, ector_renderer_draw(op, clips, mul_col)); + + USE(obj, cairo_new_path, EINA_FALSE); + USE(obj, cairo_append_path, EINA_FALSE); + + cairo_new_path(pd->parent->cairo); + cairo_append_path(pd->parent->cairo, pd->path); + + if (pd->shape->fill) + eo_do(pd->shape->fill, ector_renderer_cairo_base_fill()); + + if (pd->shape->stroke.fill || pd->shape->stroke.color.a > 0) + { + USE(obj, cairo_fill_preserve, EINA_FALSE); + USE(obj, cairo_set_source_rgba, EINA_FALSE); + USE(obj, cairo_stroke, EINA_FALSE); + USE(obj, cairo_set_line_width, EINA_FALSE); + USE(obj, cairo_set_line_cap, EINA_FALSE); + USE(obj, cairo_set_line_join, EINA_FALSE); + + cairo_fill_preserve(pd->parent->cairo); + + if (pd->shape->stroke.fill) + eo_do(pd->shape->stroke.fill, ector_renderer_cairo_base_fill()); + else + { + r = (((pd->shape->stroke.color.r * R_VAL(&mul_col)) + 0xff) >> 8); + g = (((pd->shape->stroke.color.g * G_VAL(&mul_col)) + 0xff) >> 8); + b = (((pd->shape->stroke.color.b * B_VAL(&mul_col)) + 0xff) >> 8); + a = (((pd->shape->stroke.color.a * A_VAL(&mul_col)) + 0xff) >> 8); + ector_color_argb_unpremul(a, &r, &g, &b); + cairo_set_source_rgba(pd->parent->cairo, r/255.0, g/255.0, b/255.0, a/255.0); + } + + // Set dash, cap and join + cairo_set_line_width(pd->parent->cairo, (pd->shape->stroke.width * pd->shape->stroke.scale * 2)); + cairo_set_line_cap(pd->parent->cairo, pd->shape->stroke.cap); + cairo_set_line_join(pd->parent->cairo, pd->shape->stroke.join); + cairo_stroke(pd->parent->cairo); + } + else + { + USE(obj, cairo_fill, EINA_FALSE); + cairo_fill(pd->parent->cairo); + } + + USE(obj, cairo_restore, EINA_FALSE); + cairo_restore(pd->parent->cairo); + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_cairo_shape_ector_renderer_cairo_base_fill(Eo *obj EINA_UNUSED, + Ector_Renderer_Cairo_Shape_Data *pd EINA_UNUSED) +{ + // FIXME: let's find out how to fill a shape with a shape later. + // I need to read SVG specification and see how to map that with cairo. +#warning "fill for a shape object is unhandled at this moment in cairo backend." + ERR("fill with shape not implemented\n"); + return EINA_FALSE; +} + +static void +_ector_renderer_cairo_shape_ector_renderer_generic_base_bounds_get(Eo *obj, + Ector_Renderer_Cairo_Shape_Data *pd EINA_UNUSED, + Eina_Rectangle *r) +{ + Ector_Renderer_Cairo_Base_Data *bd; + + // FIXME: It should be possible to actually ask cairo about that + eo_do(obj, efl_gfx_shape_bounds_get(r)); + + bd = eo_data_scope_get(obj, ECTOR_RENDERER_CAIRO_BASE_CLASS); + r->x += bd->generic->origin.x; + r->y += bd->generic->origin.y; +} + +void +_ector_renderer_cairo_shape_eo_base_constructor(Eo *obj, Ector_Renderer_Cairo_Shape_Data *pd) +{ + eo_do_super(obj, ECTOR_RENDERER_CAIRO_SHAPE_CLASS, eo_constructor()); + pd->shape = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_SHAPE_MIXIN, obj); + pd->base = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_BASE_CLASS, obj); + + eo_do(obj, + eo_event_callback_add(EFL_GFX_PATH_CHANGED, _ector_renderer_cairo_shape_path_changed, pd)); +} + +void +_ector_renderer_cairo_shape_eo_base_destructor(Eo *obj, Ector_Renderer_Cairo_Shape_Data *pd) +{ + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->parent, obj); + + eo_data_xunref(obj, pd->shape, obj); + eo_data_xunref(obj, pd->base, obj); + + eo_do_super(obj, ECTOR_RENDERER_CAIRO_SHAPE_CLASS, eo_destructor()); + + USE(obj, cairo_path_destroy, ); + if (pd->path) cairo_path_destroy(pd->path); +} + + +#include "ector_renderer_cairo_shape.eo.c" diff --git a/src/lib/ector/cairo/ector_renderer_cairo_shape.eo b/src/lib/ector/cairo/ector_renderer_cairo_shape.eo new file mode 100644 index 0000000000..e9d4a173c7 --- /dev/null +++ b/src/lib/ector/cairo/ector_renderer_cairo_shape.eo @@ -0,0 +1,13 @@ +class Ector.Renderer.Cairo.Shape (Ector.Renderer.Cairo.Base, Ector.Renderer.Generic.Shape) +{ + eo_prefix: ector_renderer_cairo_shape; + legacy_prefix: null; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Generic.Base.bounds_get; + Ector.Renderer.Cairo.Base.fill; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/ector/ector_generic_surface.eo b/src/lib/ector/ector_generic_surface.eo new file mode 100644 index 0000000000..5415079906 --- /dev/null +++ b/src/lib/ector/ector_generic_surface.eo @@ -0,0 +1,39 @@ +abstract Ector.Generic.Surface (Eo.Base) +{ + eo_prefix: ector_surface; + properties { + size { + set { + /*@ Changes the size of the given Evas object. */ + } + get { + /*@ Retrieves the (rectangular) size of the given Evas object. */ + } + values { + int w; /*@ in */ + int h; /*@ in */ + } + } + reference_point { + set { + /*@ This define where is (0,0) in pixels coordinate inside the surface */ + } + values { + int x; + int y; + } + } + } + methods { + renderer_factory_new { + return: Ector_Renderer *; + params { + @in const(Eo_Class) * type @nonull; + } + } + } + implements { + @virtual .renderer_factory_new; + @virtual .reference_point.set; + } +} diff --git a/src/lib/ector/ector_main.c b/src/lib/ector/ector_main.c new file mode 100644 index 0000000000..fa7413eb37 --- /dev/null +++ b/src/lib/ector/ector_main.c @@ -0,0 +1,81 @@ +/* ECTOR - EFL retained mode drawing library + * Copyright (C) 2014 Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "ector_private.h" + +int _ector_log_dom_global = 0; + +static int _ector_main_count = 0; + +EAPI int +ector_init(void) +{ + if (EINA_LIKELY(_ector_main_count > 0)) + return ++_ector_main_count; + + eina_init(); + eo_init(); + + _ector_log_dom_global = eina_log_domain_register("ector", ECTOR_DEFAULT_LOG_COLOR); + if (_ector_log_dom_global < 0) + { + EINA_LOG_ERR("Could not register log domain: ector"); + goto on_error; + } + + _ector_main_count = 1; + + eina_log_timing(_ector_log_dom_global, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); + + return _ector_main_count; + + on_error: + eo_shutdown(); + eina_shutdown(); + + return 0; +} + +EAPI int +ector_shutdown(void) +{ + if (_ector_main_count <= 0) + { + EINA_LOG_ERR("Init count not greater than 0 in shutdown of ector."); + return 0; + } + + _ector_main_count--; + if (EINA_LIKELY(_ector_main_count > 0)) + return _ector_main_count; + + eina_log_timing(_ector_log_dom_global, + EINA_LOG_STATE_START, + EINA_LOG_STATE_SHUTDOWN); + + eo_shutdown(); + + eina_log_domain_unregister(_ector_log_dom_global); + + eina_shutdown(); + return _ector_main_count; +} diff --git a/src/lib/ector/ector_private.h b/src/lib/ector/ector_private.h new file mode 100644 index 0000000000..ff97f77a81 --- /dev/null +++ b/src/lib/ector/ector_private.h @@ -0,0 +1,148 @@ +#ifndef ECTOR_PRIVATE_H_ +#define ECTOR_PRIVATE_H_ + +/* + * variable and macros used for the eina_log module + */ +extern int _ector_log_dom_global; + +/* + * Macros that are used everywhere + * + * the first four macros are the general macros for the lib + */ +#ifdef ECTOR_DEFAULT_LOG_COLOR +# undef ECTOR_DEFAULT_LOG_COLOR +#endif /* ifdef ECTOR_DEFAULT_LOG_COLOR */ +#define ECTOR_DEFAULT_LOG_COLOR EINA_COLOR_CYAN +#ifdef ERR +# undef ERR +#endif /* ifdef ERR */ +#define ERR(...) EINA_LOG_DOM_ERR(_ector_log_dom_global, __VA_ARGS__) +#ifdef DBG +# undef DBG +#endif /* ifdef DBG */ +#define DBG(...) EINA_LOG_DOM_DBG(_ector_log_dom_global, __VA_ARGS__) +#ifdef INF +# undef INF +#endif /* ifdef INF */ +#define INF(...) EINA_LOG_DOM_INFO(_ector_log_dom_global, __VA_ARGS__) +#ifdef WRN +# undef WRN +#endif /* ifdef WRN */ +#define WRN(...) EINA_LOG_DOM_WARN(_ector_log_dom_global, __VA_ARGS__) +#ifdef CRI +# undef CRI +#endif /* ifdef CRI */ +#define CRI(...) EINA_LOG_DOM_CRIT(_ector_log_dom_global, __VA_ARGS__) + +/* The following macro are internal to Ector only at this stage */ + +typedef unsigned char DATA8; +typedef unsigned short DATA16; + +#ifndef WORDS_BIGENDIAN +/* x86 */ +#define A_VAL(p) (((DATA8 *)(p))[3]) +#define R_VAL(p) (((DATA8 *)(p))[2]) +#define G_VAL(p) (((DATA8 *)(p))[1]) +#define B_VAL(p) (((DATA8 *)(p))[0]) +#define AR_VAL(p) ((DATA16 *)(p)[1]) +#define GB_VAL(p) ((DATA16 *)(p)[0]) +#else +/* ppc */ +#define A_VAL(p) (((DATA8 *)(p))[0]) +#define R_VAL(p) (((DATA8 *)(p))[1]) +#define G_VAL(p) (((DATA8 *)(p))[2]) +#define B_VAL(p) (((DATA8 *)(p))[3]) +#define AR_VAL(p) ((DATA16 *)(p)[0]) +#define GB_VAL(p) ((DATA16 *)(p)[1]) +#endif + +#define RGB_JOIN(r,g,b) \ + (((r) << 16) + ((g) << 8) + (b)) + +#define ARGB_JOIN(a,r,g,b) \ + (((a) << 24) + ((r) << 16) + ((g) << 8) + (b)) + +static inline void +_ector_renderer_replace(Ector_Renderer **d, const Ector_Renderer *s) +{ + Ector_Renderer *tmp = *d; + + *d = eo_ref(s); + eo_unref(tmp); +} + +typedef struct _Ector_Renderer_Generic_Base_Data Ector_Renderer_Generic_Base_Data; +typedef struct _Ector_Renderer_Generic_Gradient_Data Ector_Renderer_Generic_Gradient_Data; +typedef struct _Ector_Renderer_Generic_Gradient_Linear_Data Ector_Renderer_Generic_Gradient_Linear_Data; +typedef struct _Ector_Renderer_Generic_Gradient_Radial_Data Ector_Renderer_Generic_Gradient_Radial_Data; +typedef struct _Ector_Renderer_Generic_Shape_Data Ector_Renderer_Generic_Shape_Data; + +struct _Ector_Renderer_Generic_Base_Data +{ + Eina_Matrix3 *m; + + struct { + double x; + double y; + } origin; + + struct { + int r, g, b, a; + } color; + + Ector_Renderer *mask; + + Ector_Quality q; + Eina_Bool visibility; +}; + +struct _Ector_Renderer_Generic_Gradient_Data +{ + Efl_Gfx_Gradient_Stop *colors; + unsigned int colors_count; + + Efl_Gfx_Gradient_Spread s; +}; + +struct _Ector_Renderer_Generic_Gradient_Linear_Data +{ + struct { + double x, y; + } start, end; +}; + +struct _Ector_Renderer_Generic_Gradient_Radial_Data +{ + struct { + double x, y; + } radial, focal; + double radius; +}; + +struct _Ector_Renderer_Generic_Shape_Data +{ + Ector_Renderer *fill; + struct { + Ector_Renderer *fill; + Ector_Renderer *marker; + + double scale; + double width; + double centered; + + struct { + int r, g, b, a; + } color; + + Efl_Gfx_Dash *dash; + unsigned int dash_length; + + Efl_Gfx_Cap cap; + Efl_Gfx_Cap join; + } stroke; +}; + +#endif diff --git a/src/lib/ector/ector_renderer.h b/src/lib/ector/ector_renderer.h new file mode 100644 index 0000000000..4c69a41cce --- /dev/null +++ b/src/lib/ector/ector_renderer.h @@ -0,0 +1,10 @@ +#ifndef ECTOR_RENDERER_H +#define ECTOR_RENDERER_H + +#include "ector_renderer_generic_base.eo.h" +#include "ector_renderer_generic_shape.eo.h" +#include "ector_renderer_generic_gradient.eo.h" +#include "ector_renderer_generic_gradient_linear.eo.h" +#include "ector_renderer_generic_gradient_radial.eo.h" + +#endif diff --git a/src/lib/ector/ector_renderer_base.c b/src/lib/ector/ector_renderer_base.c new file mode 100644 index 0000000000..b4c44c9801 --- /dev/null +++ b/src/lib/ector/ector_renderer_base.c @@ -0,0 +1,138 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +static void +_ector_renderer_generic_base_eo_base_destructor(Eo *obj, Ector_Renderer_Generic_Base_Data *pd) +{ + if (pd->m) free(pd->m); + eo_do_super(obj, ECTOR_RENDERER_GENERIC_BASE_CLASS, eo_destructor()); +} + +static void +_ector_renderer_generic_base_transformation_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + const Eina_Matrix3 *m) +{ + if (!m) + { + free(pd->m); + pd->m = NULL; + } + else + { + if (!pd->m) pd->m = malloc(sizeof (Eina_Matrix3)); + if (!pd->m) return ; + + memcpy(pd->m, m, sizeof (Eina_Matrix3)); + } +} + +static const Eina_Matrix3 * +_ector_renderer_generic_base_transformation_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd) +{ + return pd->m; +} + +static void +_ector_renderer_generic_base_origin_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + double x, double y) +{ + pd->origin.x = x; + pd->origin.y = y; +} + +static void +_ector_renderer_generic_base_origin_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->origin.x; + if (y) *y = pd->origin.y; +} + +static void +_ector_renderer_generic_base_visibility_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + Eina_Bool v) +{ + pd->visibility = v; +} + +static Eina_Bool +_ector_renderer_generic_base_visibility_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd) +{ + return pd->visibility; +} + +static void +_ector_renderer_generic_base_color_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + int r, int g, int b, int a) +{ + pd->color.r = r; + pd->color.g = g; + pd->color.b = b; + pd->color.a = a; +} + +static void +_ector_renderer_generic_base_color_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + int *r, int *g, int *b, int *a) +{ + if (r) *r = pd->color.r; + if (g) *g = pd->color.g; + if (b) *b = pd->color.b; + if (a) *a = pd->color.a; +} + +static void +_ector_renderer_generic_base_mask_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + Ector_Renderer *r) +{ + _ector_renderer_replace(&pd->mask, r); +} + +static Ector_Renderer * +_ector_renderer_generic_base_mask_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd) +{ + return pd->mask; +} + +static void +_ector_renderer_generic_base_quality_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd, + Ector_Quality q) +{ + pd->q = q; +} + +static Ector_Quality +_ector_renderer_generic_base_quality_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd) +{ + return pd->q; +} + +static Eina_Bool +_ector_renderer_generic_base_prepare(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Base_Data *pd) +{ + if (pd->mask) + eo_do(pd->mask, ector_renderer_prepare()); + + return EINA_TRUE; +} + +#include "ector_renderer_generic_base.eo.c" diff --git a/src/lib/ector/ector_renderer_generic_base.eo b/src/lib/ector/ector_renderer_generic_base.eo new file mode 100644 index 0000000000..2e42feaa98 --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_base.eo @@ -0,0 +1,116 @@ +abstract Ector.Renderer.Generic.Base (Eo.Base) +{ + eo_prefix: ector_renderer; + legacy_prefix: null; + properties { + transformation { + set { + } + get { + } + values { + const(Eina_Matrix3) *m; + } + } + origin { + set { + } + get { + } + values { + double x; + double y; + } + } + visibility { + set { + /*@ Makes the given Ector renderer visible or invisible. */ + } + get { + /*@ Retrieves whether or not the given Ector renderer is visible. */ + } + values { + bool v; /*@ @c EINA_TRUE if to make the object visible, @c EINA_FALSE otherwise */ + } + } + color { + set { + /*@ + Sets the general/main color of the given Ector renderer to the given + one. + + @note These color values are expected to be premultiplied by @p a. + + @ingroup Ector_Renderer_Group_Basic */ + } + get { + /*@ + Retrieves the general/main color of the given Ector renderer. + + Retrieves the “main” color's RGB component (and alpha channel) + values, which range from 0 to 255. For the alpha channel, + which defines the object's transparency level, 0 means totally + transparent, while 255 means opaque. These color values are + premultiplied by the alpha value. + + @note Use @c NULL pointers on the components you're not interested + in: they'll be ignored by the function. + + @ingroup Ector_Renderer_Group_Basic */ + } + values { + int r; /*@ The red component of the given color. */ + int g; /*@ The green component of the given color. */ + int b; /*@ The blue component of the given color. */ + int a; /*@ The alpha component of the given color. */ + } + } + mask { + set { + } + get { + } + values { + Ector_Renderer *r; + } + } + quality { + set { + } + get { + } + values { + Ector_Quality q; + } + } + } + methods { + bounds_get { + params { + @out Eina_Rectangle r; + } + } + draw { + return: bool @warn_unused; + params { + @in Ector_Rop op; + @in array *clips; /*@ array of Eina_Rectangle clip */ + @in uint mul_col; + } + } + prepare { + return: bool @warn_unused; + params { + } + } + done { + return: bool @warn_unused; + } + } + implements { + Eo.Base.destructor; + @virtual .draw; + @virtual .bounds_get; + @virtual .done; + } +} diff --git a/src/lib/ector/ector_renderer_generic_gradient.eo b/src/lib/ector/ector_renderer_generic_gradient.eo new file mode 100644 index 0000000000..2c0cc83894 --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_gradient.eo @@ -0,0 +1,11 @@ +mixin Ector.Renderer.Generic.Gradient (Efl.Gfx.Gradient.Base) +{ + eo_prefix: ector_renderer_gradient; + legacy_prefix: null; + implements { + Efl.Gfx.Gradient.Base.stop.set; + Efl.Gfx.Gradient.Base.stop.get; + Efl.Gfx.Gradient.Base.spread.set; + Efl.Gfx.Gradient.Base.spread.get; + } +} diff --git a/src/lib/ector/ector_renderer_generic_gradient_linear.eo b/src/lib/ector/ector_renderer_generic_gradient_linear.eo new file mode 100644 index 0000000000..13ab2e6bfc --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_gradient_linear.eo @@ -0,0 +1,11 @@ +mixin Ector.Renderer.Generic.Gradient_Linear (Efl.Gfx.Gradient.Linear) +{ + eo_prefix: ector_renderer_gradient_linear; + legacy_prefix: null; + implements { + Efl.Gfx.Gradient.Linear.start.set; + Efl.Gfx.Gradient.Linear.start.get; + Efl.Gfx.Gradient.Linear.end.set; + Efl.Gfx.Gradient.Linear.end.get; + } +} diff --git a/src/lib/ector/ector_renderer_generic_gradient_radial.eo b/src/lib/ector/ector_renderer_generic_gradient_radial.eo new file mode 100644 index 0000000000..cef25eb953 --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_gradient_radial.eo @@ -0,0 +1,13 @@ +mixin Ector.Renderer.Generic.Gradient_Radial (Efl.Gfx.Gradient.Radial) +{ + eo_prefix: ector_renderer_gradient_radial; + legacy_prefix: null; + implements { + Efl.Gfx.Gradient.Radial.center.set; + Efl.Gfx.Gradient.Radial.center.get; + Efl.Gfx.Gradient.Radial.radius.set; + Efl.Gfx.Gradient.Radial.radius.get; + Efl.Gfx.Gradient.Radial.focal.set; + Efl.Gfx.Gradient.Radial.focal.get; + } +} diff --git a/src/lib/ector/ector_renderer_generic_shape.eo b/src/lib/ector/ector_renderer_generic_shape.eo new file mode 100644 index 0000000000..2205b7985c --- /dev/null +++ b/src/lib/ector/ector_renderer_generic_shape.eo @@ -0,0 +1,43 @@ +mixin Ector.Renderer.Generic.Shape (Efl.Gfx.Shape) +{ + eo_prefix: ector_renderer_shape; + legacy_prefix: null; + properties { + fill { + set { + } + get { + } + values { + const(Ector_Renderer) *r; + } + } + stroke_fill { + set { + } + get { + } + values { + const(Ector_Renderer) *r; + } + } + stroke_marker { + set { + } + get { + } + values { + const(Ector_Renderer) *r; + } + } + } + implements { + Efl.Gfx.Shape.stroke_scale; + Efl.Gfx.Shape.stroke_color; + Efl.Gfx.Shape.stroke_width; + Efl.Gfx.Shape.stroke_location; + Efl.Gfx.Shape.stroke_dash; + Efl.Gfx.Shape.stroke_cap; + Efl.Gfx.Shape.stroke_join; + } +} \ No newline at end of file diff --git a/src/lib/ector/ector_renderer_gradient.c b/src/lib/ector/ector_renderer_gradient.c new file mode 100644 index 0000000000..6cf676fbb0 --- /dev/null +++ b/src/lib/ector/ector_renderer_gradient.c @@ -0,0 +1,53 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +static void +_ector_renderer_generic_gradient_efl_gfx_gradient_base_stop_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Data *pd, + const Efl_Gfx_Gradient_Stop *colors, + unsigned int length) +{ + pd->colors = realloc(pd->colors, length * sizeof(Efl_Gfx_Gradient_Stop)); + if (!pd->colors) + { + pd->colors_count = 0; + return ; + } + + memcpy(pd->colors, colors, length * sizeof(Efl_Gfx_Gradient_Stop)); + pd->colors_count = length; +} + +static void +_ector_renderer_generic_gradient_efl_gfx_gradient_base_stop_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Data *pd, + const Efl_Gfx_Gradient_Stop **colors, + unsigned int *length) +{ + if (colors) *colors = pd->colors; + if (length) *length = pd->colors_count; +} + +static void +_ector_renderer_generic_gradient_efl_gfx_gradient_base_spread_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Data *pd, + Efl_Gfx_Gradient_Spread s) +{ + pd->s = s; +} + +static Efl_Gfx_Gradient_Spread +_ector_renderer_generic_gradient_efl_gfx_gradient_base_spread_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Data *pd) +{ + return pd->s; +} + + +#include "ector_renderer_generic_gradient.eo.c" diff --git a/src/lib/ector/ector_renderer_gradient_linear.c b/src/lib/ector/ector_renderer_gradient_linear.c new file mode 100644 index 0000000000..925fb53951 --- /dev/null +++ b/src/lib/ector/ector_renderer_gradient_linear.c @@ -0,0 +1,46 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +static void +_ector_renderer_generic_gradient_linear_efl_gfx_gradient_linear_start_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Linear_Data *pd, + double x, double y) +{ + pd->start.x = x; + pd->start.y = y; +} + +static void +_ector_renderer_generic_gradient_linear_efl_gfx_gradient_linear_start_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Linear_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->start.x; + if (y) *y = pd->start.y; +} + +static void +_ector_renderer_generic_gradient_linear_efl_gfx_gradient_linear_end_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Linear_Data *pd, + double x, double y) +{ + pd->end.x = x; + pd->end.y = y; +} + +static void +_ector_renderer_generic_gradient_linear_efl_gfx_gradient_linear_end_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Linear_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->end.x; + if (y) *y = pd->end.y; +} + +#include "ector_renderer_generic_gradient_linear.eo.c" diff --git a/src/lib/ector/ector_renderer_gradient_radial.c b/src/lib/ector/ector_renderer_gradient_radial.c new file mode 100644 index 0000000000..3c1782cf73 --- /dev/null +++ b/src/lib/ector/ector_renderer_gradient_radial.c @@ -0,0 +1,62 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +static void +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_center_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd, + double x, double y) +{ + pd->radial.x = x; + pd->radial.y = y; +} + +static void +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_center_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->radial.x; + if (y) *y = pd->radial.y; +} + +static void +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_radius_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd, + double r) +{ + pd->radius = r; +} + +static double +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_radius_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd) +{ + return pd->radius; +} + + +static void +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_focal_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd, + double x, double y) +{ + pd->focal.x = x; + pd->focal.y = y; +} + +static void +_ector_renderer_generic_gradient_radial_efl_gfx_gradient_radial_focal_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Gradient_Radial_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->focal.x; + if (y) *y = pd->focal.y; +} + +#include "ector_renderer_generic_gradient_radial.eo.c" diff --git a/src/lib/ector/ector_renderer_shape.c b/src/lib/ector/ector_renderer_shape.c new file mode 100644 index 0000000000..cda749d1dc --- /dev/null +++ b/src/lib/ector/ector_renderer_shape.c @@ -0,0 +1,186 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +static void +_ector_renderer_generic_shape_fill_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + const Ector_Renderer *r) +{ + _ector_renderer_replace(&pd->fill, r); +} + +static const Ector_Renderer * +_ector_renderer_generic_shape_fill_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->fill; +} + +static void +_ector_renderer_generic_shape_stroke_fill_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + const Ector_Renderer *r) +{ + _ector_renderer_replace(&pd->stroke.fill, r); +} + +static const Ector_Renderer * +_ector_renderer_generic_shape_stroke_fill_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.fill; +} + +static void +_ector_renderer_generic_shape_stroke_marker_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + const Ector_Renderer *r) +{ + _ector_renderer_replace(&pd->stroke.marker, r); +} + +static const Ector_Renderer * +_ector_renderer_generic_shape_stroke_marker_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.marker; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_scale_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + double s) +{ + pd->stroke.scale = s; +} + +static double +_ector_renderer_generic_shape_efl_gfx_shape_stroke_scale_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.scale; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_color_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + int r, int g, int b, int a) +{ + pd->stroke.color.r = r; + pd->stroke.color.g = g; + pd->stroke.color.b = b; + pd->stroke.color.a = a; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_color_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + int *r, int *g, int *b, int *a) +{ + if (r) *r = pd->stroke.color.r; + if (g) *g = pd->stroke.color.g; + if (b) *b = pd->stroke.color.b; + if (a) *a = pd->stroke.color.a; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_width_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + double w) +{ + pd->stroke.width = w; +} + +static double +_ector_renderer_generic_shape_efl_gfx_shape_stroke_width_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.width; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_location_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + double centered) +{ + pd->stroke.centered = centered; +} + +static double +_ector_renderer_generic_shape_efl_gfx_shape_stroke_location_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.centered; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_dash_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + const Efl_Gfx_Dash *dash, + unsigned int length) +{ + Efl_Gfx_Dash *tmp; + + if (!dash) + { + free(pd->stroke.dash); + pd->stroke.dash = NULL; + pd->stroke.dash_length = 0; + return ; + } + + tmp = realloc(pd->stroke.dash, length * sizeof (Efl_Gfx_Dash)); + if (!tmp && length) return ; + memcpy(tmp, dash, length * sizeof (Efl_Gfx_Dash)); + + pd->stroke.dash = tmp; + pd->stroke.dash_length = length; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_dash_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + const Efl_Gfx_Dash **dash, + unsigned int *length) +{ + if (dash) *dash = pd->stroke.dash; + if (length) *length = pd->stroke.dash_length; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_cap_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + Efl_Gfx_Cap c) +{ + pd->stroke.cap = c; +} + +static Efl_Gfx_Cap +_ector_renderer_generic_shape_efl_gfx_shape_stroke_cap_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.cap; +} + +static void +_ector_renderer_generic_shape_efl_gfx_shape_stroke_join_set(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd, + Efl_Gfx_Join j) +{ + pd->stroke.join = j; +} + +static Efl_Gfx_Join +_ector_renderer_generic_shape_efl_gfx_shape_stroke_join_get(Eo *obj EINA_UNUSED, + Ector_Renderer_Generic_Shape_Data *pd) +{ + return pd->stroke.join; +} + +#include "ector_renderer_generic_shape.eo.c" diff --git a/src/lib/ector/ector_surface.c b/src/lib/ector/ector_surface.c new file mode 100644 index 0000000000..23ad7eb2fd --- /dev/null +++ b/src/lib/ector/ector_surface.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" + +typedef struct _Ector_Generic_Surface_Data Ector_Generic_Surface_Data; +struct _Ector_Generic_Surface_Data +{ + int w, h; +}; + +void +_ector_generic_surface_size_set(Eo *obj EINA_UNUSED, + Ector_Generic_Surface_Data *pd, + int w, int h) +{ + pd->w = w; + pd->h = h; +} + +void +_ector_generic_surface_size_get(Eo *obj EINA_UNUSED, + Ector_Generic_Surface_Data *pd, + int *w, int *h) +{ + if (w) *w = pd->w; + if (h) *h = pd->h; +} + +#include "ector_generic_surface.eo.c" diff --git a/src/lib/ector/ector_surface.h b/src/lib/ector/ector_surface.h new file mode 100644 index 0000000000..424726a235 --- /dev/null +++ b/src/lib/ector/ector_surface.h @@ -0,0 +1,6 @@ +#ifndef ECTOR_SURFACE_H +#define ECTOR_SURFACE_H + +#include "ector_generic_surface.eo.h" + +#endif diff --git a/src/lib/ector/ector_util.h b/src/lib/ector/ector_util.h new file mode 100644 index 0000000000..2dafaafae1 --- /dev/null +++ b/src/lib/ector/ector_util.h @@ -0,0 +1,32 @@ +#ifndef ECTOR_UTIL_H +# define ECTOR_UTIL_H + +static inline void +ector_color_argb_premul(int a, int *r, int *g, int *b) +{ + a++; + if (r) { *r = (a * *r) >> 8; } + if (g) { *g = (a * *g) >> 8; } + if (b) { *b = (a * *b) >> 8; } +} + +static inline void +ector_color_argb_unpremul(int a, int *r, int *g, int *b) +{ + if (!a) return; + if (r) { *r = (255 * *r) / a; } + if (g) { *g = (255 * *g) / a; } + if (b) { *b = (255 * *b) / a; } +} + + +static inline unsigned int +ector_color_multiply(unsigned int c1, unsigned int c2) +{ + return ( ((((((c1) >> 16) & 0xff00) * (((c2) >> 16) & 0xff00)) + 0xff0000) & 0xff000000) + + ((((((c1) >> 8) & 0xff00) * (((c2) >> 16) & 0xff)) + 0xff00) & 0xff0000) + + ((((((c1) & 0xff00) * ((c2) & 0xff00)) + 0xff0000) >> 16) & 0xff00) + + (((((c1) & 0xff) * ((c2) & 0xff)) + 0xff) >> 8) ); +} + +#endif diff --git a/src/lib/ector/software/Ector_Software.h b/src/lib/ector/software/Ector_Software.h new file mode 100644 index 0000000000..7d003cc3ff --- /dev/null +++ b/src/lib/ector/software/Ector_Software.h @@ -0,0 +1,15 @@ +#ifndef ECTOR_SOFTWARE_H_ +#define ECTOR_SOFTWARE_H_ + +#include + +typedef Eo Ector_Software_Surface; +typedef struct _Software_Rasterizer Software_Rasterizer; + +#include "software/ector_software_surface.eo.h" +#include "software/ector_renderer_software_base.eo.h" +#include "software/ector_renderer_software_shape.eo.h" +#include "software/ector_renderer_software_gradient_linear.eo.h" +#include "software/ector_renderer_software_gradient_radial.eo.h" + +#endif diff --git a/src/lib/ector/software/ector_blend_private.h b/src/lib/ector/software/ector_blend_private.h new file mode 100644 index 0000000000..0082baa5eb --- /dev/null +++ b/src/lib/ector/software/ector_blend_private.h @@ -0,0 +1,105 @@ +#ifndef ECTOR_BLEND_PRIVATE_H +#define ECTOR_BLEND_PRIVATE_H + +#ifndef MIN +#define MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#endif + +#define ECTOR_ARGB_JOIN(a,r,g,b) \ + (((a) << 24) + ((r) << 16) + ((g) << 8) + (b)) + +#define ECTOR_MUL4_SYM(x, y) \ + ( ((((((x) >> 16) & 0xff00) * (((y) >> 16) & 0xff00)) + 0xff0000) & 0xff000000) + \ + ((((((x) >> 8) & 0xff00) * (((y) >> 16) & 0xff)) + 0xff00) & 0xff0000) + \ + ((((((x) & 0xff00) * ((y) & 0xff00)) + 0xff0000) >> 16) & 0xff00) + \ + (((((x) & 0xff) * ((y) & 0xff)) + 0xff) >> 8) ) + +#define ECTOR_MUL_256(c, a) \ + ( (((((c) >> 8) & 0x00ff00ff) * (a)) & 0xff00ff00) + \ + (((((c) & 0x00ff00ff) * (a)) >> 8) & 0x00ff00ff) ) + + +static inline void +_ector_memfill(DATA32 *dest, uint value, int count) +{ + if (!count) + return; + + int n = (count + 7) / 8; + switch (count & 0x07) + { + case 0: do { *dest++ = value; + case 7: *dest++ = value; + case 6: *dest++ = value; + case 5: *dest++ = value; + case 4: *dest++ = value; + case 3: *dest++ = value; + case 2: *dest++ = value; + case 1: *dest++ = value; + } while (--n > 0); + } +} + + +static inline void +_ector_comp_func_source_over_mul_c(uint *dest, uint *src, DATA32 c, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + uint s = src[i]; + DATA32 sc = ECTOR_MUL4_SYM(c, s); + uint a = (~sc) >> 24; + dest[i] = sc + ECTOR_MUL_256(dest[i], a); + } + } else { + for (int i = 0; i < length; ++i) { + uint s = src[i]; + DATA32 sc = ECTOR_MUL4_SYM(c, s); + sc = ECTOR_MUL_256(sc, const_alpha); + uint a = (~sc) >> 24; + dest[i] = sc + ECTOR_MUL_256(dest[i], a); + } + } +} + + +static inline void +_ector_comp_func_source_over(uint *dest, uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + uint s = src[i]; + if (s >= 0xff000000) + dest[i] = s; + else if (s != 0) { + uint a = (~s) >> 24; + dest[i] = s + ECTOR_MUL_256(dest[i], a); + } + } + } else { + for (int i = 0; i < length; ++i) { + uint s = ECTOR_MUL_256(src[i], const_alpha); + uint a = (~s) >> 24; + dest[i] = s + ECTOR_MUL_256(dest[i], a); + } + } +} + +static inline uint +INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { + uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; + t >>= 8; + t &= 0xff00ff; + + x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b; + x &= 0xff00ff00; + x |= t; + return x; +} + + +#endif \ No newline at end of file diff --git a/src/lib/ector/software/ector_renderer_software_base.eo b/src/lib/ector/software/ector_renderer_software_base.eo new file mode 100644 index 0000000000..6055be585c --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_base.eo @@ -0,0 +1,12 @@ +class Ector.Renderer.Software.Base (Ector.Renderer.Generic.Base) +{ + legacy_prefix: null; + methods { + fill { + return: bool; + } + } + implements { + @virtual .fill; + } +} diff --git a/src/lib/ector/software/ector_renderer_software_gradient_linear.c b/src/lib/ector/software/ector_renderer_software_gradient_linear.c new file mode 100644 index 0000000000..a6e32b008b --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_gradient_linear.c @@ -0,0 +1,109 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" + + +static void +_update_linear_data(Ector_Renderer_Software_Gradient_Data *gdata) +{ + update_color_table(gdata); + gdata->linear.x1 = gdata->gld->start.x; + gdata->linear.y1 = gdata->gld->start.y; + + gdata->linear.x2 = gdata->gld->end.x; + gdata->linear.y2 = gdata->gld->end.y; + + gdata->linear.dx = gdata->linear.x2 - gdata->linear.x1; + gdata->linear.dy = gdata->linear.y2 - gdata->linear.y1; + gdata->linear.l = gdata->linear.dx * gdata->linear.dx + gdata->linear.dy * gdata->linear.dy; + gdata->linear.off = 0; + + if (gdata->linear.l != 0) + { + gdata->linear.dx /= gdata->linear.l; + gdata->linear.dy /= gdata->linear.l; + gdata->linear.off = -gdata->linear.dx * gdata->linear.x1 - gdata->linear.dy * gdata->linear.y1; + } +} + + +static Eina_Bool +_ector_renderer_software_gradient_linear_ector_renderer_generic_base_prepare(Eo *obj, + Ector_Renderer_Software_Gradient_Data *pd) +{ + if (!pd->surface) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->surface = eo_data_xref(parent, ECTOR_SOFTWARE_SURFACE_CLASS, obj); + } + + _update_linear_data(pd); + + + return EINA_FALSE; +} + +static Eina_Bool +_ector_renderer_software_gradient_linear_ector_renderer_generic_base_draw(Eo *obj EINA_UNUSED, + Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED, + Ector_Rop op EINA_UNUSED, Eina_Array *clips EINA_UNUSED, + unsigned int mul_col EINA_UNUSED) +{ + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_software_gradient_linear_ector_renderer_software_base_fill(Eo *obj EINA_UNUSED, + Ector_Renderer_Software_Gradient_Data *pd) +{ + ector_software_rasterizer_linear_gradient_set(pd->surface->software, pd); + + return EINA_TRUE; +} + +void +_ector_renderer_software_gradient_linear_eo_base_constructor(Eo *obj, + Ector_Renderer_Software_Gradient_Data *pd) +{ + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS, eo_constructor()); + pd->gd = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN, obj); + pd->gld = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN, obj); +} + +void +_ector_renderer_software_gradient_linear_eo_base_destructor(Eo *obj, + Ector_Renderer_Software_Gradient_Data *pd) +{ + Eo *parent; + + destroy_color_table(pd); + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->surface, obj); + + eo_data_xunref(obj, pd->gd, obj); + eo_data_xunref(obj, pd->gld, obj); + + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS, eo_destructor()); +} + +void +_ector_renderer_software_gradient_linear_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +{ + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS, + efl_gfx_gradient_stop_set(colors, length)); + + destroy_color_table(pd); +} + +#include "ector_renderer_software_gradient_linear.eo.c" diff --git a/src/lib/ector/software/ector_renderer_software_gradient_linear.eo b/src/lib/ector/software/ector_renderer_software_gradient_linear.eo new file mode 100644 index 0000000000..32f83df016 --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_gradient_linear.eo @@ -0,0 +1,14 @@ +class Ector.Renderer.Software.Gradient_Linear (Ector.Renderer.Software.Base, Ector.Renderer.Generic.Gradient, Ector.Renderer.Generic.Gradient_Linear) +{ + eo_prefix: ector_renderer_software_gradient_linear; + legacy_prefix: null; + data: Ector_Renderer_Software_Gradient_Data; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Software.Base.fill; + Eo.Base.constructor; + Eo.Base.destructor; + Efl.Gfx.Gradient.Base.stop.set; + } +} diff --git a/src/lib/ector/software/ector_renderer_software_gradient_radial.c b/src/lib/ector/software/ector_renderer_software_gradient_radial.c new file mode 100644 index 0000000000..a05b4874f4 --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_gradient_radial.c @@ -0,0 +1,117 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" + +static void +_update_radial_data(Ector_Renderer_Software_Gradient_Data *gdata) +{ + update_color_table(gdata); + + gdata->radial.cx = gdata->grd->radial.x; + gdata->radial.cy = gdata->grd->radial.y; + gdata->radial.cradius = gdata->grd->radius; + + if (!gdata->grd->focal.x) + gdata->radial.fx = gdata->grd->radial.x; + else + gdata->radial.fx = gdata->grd->focal.x; + + if (!gdata->grd->focal.y) + gdata->radial.fy = gdata->grd->radial.y; + else + gdata->radial.fy = gdata->grd->focal.y; + + gdata->radial.fradius = 0; + + gdata->radial.dx = gdata->radial.cx - gdata->radial.fx; + gdata->radial.dy = gdata->radial.cy - gdata->radial.fy; + + gdata->radial.dr = gdata->radial.cradius - gdata->radial.fradius; + gdata->radial.sqrfr = gdata->radial.fradius * gdata->radial.fradius; + + gdata->radial.a = gdata->radial.dr * gdata->radial.dr - + gdata->radial.dx * gdata->radial.dx - + gdata->radial.dy * gdata->radial.dy; + gdata->radial.inv2a = 1 / (2 * gdata->radial.a); + + gdata->radial.extended = (gdata->radial.fradius >= 0.00001f) || gdata->radial.a >= 0.00001f; +} + + +static Eina_Bool +_ector_renderer_software_gradient_radial_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd) +{ + if (!pd->surface) + { + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->surface = eo_data_xref(parent, ECTOR_SOFTWARE_SURFACE_CLASS, obj); + } + + _update_radial_data(pd); + return EINA_FALSE; +} + +// Clearly duplicated and should be in a common place... +static Eina_Bool +_ector_renderer_software_gradient_radial_ector_renderer_generic_base_draw(Eo *obj EINA_UNUSED, + Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED, + Ector_Rop op EINA_UNUSED, Eina_Array *clips EINA_UNUSED, + unsigned int mul_col EINA_UNUSED) +{ + return EINA_TRUE; +} + +// Clearly duplicated and should be in a common place... +static Eina_Bool +_ector_renderer_software_gradient_radial_ector_renderer_software_base_fill(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Gradient_Data *pd) +{ + ector_software_rasterizer_radial_gradient_set(pd->surface->software, pd); + return EINA_TRUE; +} + +void +_ector_renderer_software_gradient_radial_eo_base_constructor(Eo *obj, + Ector_Renderer_Software_Gradient_Data *pd) +{ + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, eo_constructor()); + pd->gd = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_GRADIENT_MIXIN, obj); + pd->gld = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN, obj); +} + +void +_ector_renderer_software_gradient_radial_eo_base_destructor(Eo *obj, + Ector_Renderer_Software_Gradient_Data *pd) +{ + Eo *parent; + + destroy_color_table(pd); + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->surface, obj); + + eo_data_xunref(obj, pd->gd, obj); + eo_data_xunref(obj, pd->gld, obj); + + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, eo_destructor()); +} + +void +_ector_renderer_software_gradient_radial_efl_gfx_gradient_base_stop_set(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +{ + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, + efl_gfx_gradient_stop_set(colors, length)); + + destroy_color_table(pd); +} + +#include "ector_renderer_software_gradient_radial.eo.c" diff --git a/src/lib/ector/software/ector_renderer_software_gradient_radial.eo b/src/lib/ector/software/ector_renderer_software_gradient_radial.eo new file mode 100644 index 0000000000..85625f341f --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_gradient_radial.eo @@ -0,0 +1,14 @@ +class Ector.Renderer.Software.Gradient_Radial (Ector.Renderer.Software.Base, Ector.Renderer.Generic.Gradient, Ector.Renderer.Generic.Gradient_Radial) +{ + eo_prefix: ector_renderer_software_gradient_radial; + legacy_prefix: null; + data: Ector_Renderer_Software_Gradient_Data; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Software.Base.fill; + Eo.Base.constructor; + Eo.Base.destructor; + Efl.Gfx.Gradient.Base.stop.set; + } +} diff --git a/src/lib/ector/software/ector_renderer_software_shape.c b/src/lib/ector/software/ector_renderer_software_shape.c new file mode 100644 index 0000000000..2e4fbea5aa --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_shape.c @@ -0,0 +1,392 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" + + +typedef struct _Ector_Renderer_Software_Shape_Data Ector_Renderer_Software_Shape_Data; +struct _Ector_Renderer_Software_Shape_Data +{ + Ector_Software_Surface_Data *surface; + Ector_Renderer_Generic_Shape_Data *shape; + Ector_Renderer_Generic_Base_Data *base; + Shape_Rle_Data *shape_data; + Shape_Rle_Data *outline_data; +}; + +typedef struct _Outline +{ + SW_FT_Outline ft_outline; + int points_alloc; + int contours_alloc; +}Outline; + +static Outline * +_outline_create() +{ + Outline *outline = (Outline *) calloc(1, sizeof(Outline)); + + outline->ft_outline.points = (SW_FT_Vector *) calloc(50, sizeof(SW_FT_Vector)); + outline->ft_outline.tags = (char *) calloc(50, sizeof(char)); + + outline->ft_outline.contours = (short *) calloc(5, sizeof(short)); + + outline->points_alloc = 50; + outline->contours_alloc = 5; + return outline; +} + +static +void _outline_destroy(Outline *outline) +{ + if (outline) + { + free(outline->ft_outline.points); + free(outline->ft_outline.tags); + free(outline->ft_outline.contours); + free(outline); + outline = NULL; + } +} + +static void +_outline_move_to(Outline *outline, double x, double y) +{ + SW_FT_Outline *ft_outline = &outline->ft_outline; + + if (ft_outline->n_contours == outline->contours_alloc) + { + outline->contours_alloc += 5; + ft_outline->contours = (short *) realloc(ft_outline->contours, outline->contours_alloc * sizeof(short)); + } + ft_outline->points[ft_outline->n_points].x = x; + ft_outline->points[ft_outline->n_points].y = y; + ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON; + + if (ft_outline->n_points) + { + ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1; + ft_outline->n_contours++; + } + + ft_outline->n_points++; +} + +static void +_outline_end(Outline *outline) +{ + SW_FT_Outline *ft_outline = &outline->ft_outline; + + if (ft_outline->n_contours == outline->contours_alloc) + { + outline->contours_alloc += 1; + ft_outline->contours = (short *) realloc(ft_outline->contours, outline->contours_alloc * sizeof(short)); + } + + if (ft_outline->n_points) + { + ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1; + ft_outline->n_contours++; + } +} + + +static void _outline_line_to(Outline *outline, double x, double y) +{ + SW_FT_Outline *ft_outline = &outline->ft_outline; + + if (ft_outline->n_points == outline->points_alloc) + { + outline->points_alloc += 50; + ft_outline->points = (SW_FT_Vector *) realloc(ft_outline->points, outline->points_alloc * sizeof(SW_FT_Vector)); + ft_outline->tags = (char *) realloc(ft_outline->tags, outline->points_alloc * sizeof(char)); + } + ft_outline->points[ft_outline->n_points].x = x; + ft_outline->points[ft_outline->n_points].y = y; + ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON; + ft_outline->n_points++; +} + + +static Eina_Bool +_outline_close_path(Outline *outline) +{ + SW_FT_Outline *ft_outline = &outline->ft_outline; + int index ; + + if (ft_outline->n_contours) + { + index = ft_outline->contours[ft_outline->n_contours - 1] + 1; + } + else + { + // first path + index = 0; + } + + // make sure there is atleast one point in the current path + if (ft_outline->n_points == index) return EINA_FALSE; + + _outline_line_to(outline, ft_outline->points[index].x, ft_outline->points[index].y); + return EINA_TRUE; +} + + +static void _outline_cubic_to(Outline *outline, double cx1, double cy1, double cx2, double cy2, double x, double y) +{ + SW_FT_Outline *ft_outline = &outline->ft_outline; + + if (ft_outline->n_points == outline->points_alloc) + { + outline->points_alloc += 50; + ft_outline->points = (SW_FT_Vector *) realloc(ft_outline->points, outline->points_alloc * sizeof(SW_FT_Vector)); + ft_outline->tags = (char *) realloc(ft_outline->tags, outline->points_alloc * sizeof(char)); + } + + ft_outline->points[ft_outline->n_points].x = cx1; + ft_outline->points[ft_outline->n_points].y = cy1; + ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC; + ft_outline->n_points++; + + ft_outline->points[ft_outline->n_points].x = cx2; + ft_outline->points[ft_outline->n_points].y = cy2; + ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC; + ft_outline->n_points++; + + ft_outline->points[ft_outline->n_points].x = x; + ft_outline->points[ft_outline->n_points].y = y; + ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON; + ft_outline->n_points++; +} + +static void _outline_transform(Outline *outline, Eina_Matrix3 *m) +{ + int i; + SW_FT_Outline *ft_outline = &outline->ft_outline; + + if (m) + { + double x, y; + for (i = 0; i < ft_outline->n_points; i++) + { + eina_matrix3_point_transform(m, ft_outline->points[i].x, ft_outline->points[i].y, &x, &y); + ft_outline->points[i].x = (int)(x * 64);// to freetype 26.6 coordinate. + ft_outline->points[i].y = (int)(y * 64); + } + } + else + { + for (i = 0; i < ft_outline->n_points; i++) + { + ft_outline->points[i].x = ft_outline->points[i].x <<6;// to freetype 26.6 coordinate. + ft_outline->points[i].y = ft_outline->points[i].y <<6; + } + } +} + + +static Eina_Bool +_ector_renderer_software_shape_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Software_Shape_Data *pd) +{ + const Efl_Gfx_Path_Command *cmds = NULL; + const double *pts = NULL; + + // FIXME: shouldn't that be part of the shape generic implementation ? + if (pd->shape->fill) + eo_do(pd->shape->fill, ector_renderer_prepare()); + if (pd->shape->stroke.fill) + eo_do(pd->shape->stroke.fill, ector_renderer_prepare()); + if (pd->shape->stroke.marker) + eo_do(pd->shape->stroke.marker, ector_renderer_prepare()); + + // shouldn't that be moved to the software base object + if (!pd->surface) + { + Eo *parent; + eo_do(obj, parent = eo_parent_get()); + if (!parent) return EINA_FALSE; + pd->surface = eo_data_xref(parent, ECTOR_SOFTWARE_SURFACE_CLASS, obj); + if (!pd->surface) return EINA_FALSE; + } + + eo_do(obj, efl_gfx_shape_path_get(&cmds, &pts)); + if (!pd->shape_data && cmds) + { + Eina_Bool close_path = EINA_FALSE; + Outline * outline = _outline_create(); + + for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++) + { + switch (*cmds) + { + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + + _outline_move_to(outline, pts[0], pts[1]); + + pts += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + + _outline_line_to(outline, pts[0], pts[1]); + + pts += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + + // Be careful, we do have a different order than + // cairo, first is destination point, followed by + // the control point. The opposite of cairo. + _outline_cubic_to(outline, + pts[2], pts[3], pts[4], pts[5], // control points + pts[0], pts[1]); // destination point + pts += 6; + break; + + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: + + close_path = _outline_close_path(outline); + break; + + case EFL_GFX_PATH_COMMAND_TYPE_LAST: + case EFL_GFX_PATH_COMMAND_TYPE_END: + break; + } + } + + _outline_end(outline); + _outline_transform(outline, pd->base->m); + + // generate the shape data. + pd->shape_data = ector_software_rasterizer_generate_rle_data(pd->surface->software, &outline->ft_outline); + if (!pd->outline_data) + { + ector_software_rasterizer_stroke_set(pd->surface->software, (pd->shape->stroke.width * pd->shape->stroke.scale), pd->shape->stroke.cap, + pd->shape->stroke.join); + pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software, &outline->ft_outline, close_path); + } + + _outline_destroy(outline); + } + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_software_shape_ector_renderer_generic_base_draw(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Shape_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col) +{ + int x, y; + + // adjust the offset + x = pd->surface->x + (int)pd->base->origin.x; + y = pd->surface->y + (int)pd->base->origin.y; + + // fill the span_data structure + ector_software_rasterizer_clip_rect_set(pd->surface->software, clips); + ector_software_rasterizer_transform_set(pd->surface->software, pd->base->m); + + if (pd->shape->fill) + { + eo_do(pd->shape->fill, ector_renderer_software_base_fill()); + ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->shape_data); + } + else + { + if (pd->base->color.a > 0) + { + ector_software_rasterizer_color_set(pd->surface->software, pd->base->color.r, pd->base->color.g, pd->base->color.b, pd->base->color.a); + ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->shape_data); + } + } + + if (pd->shape->stroke.fill) + { + eo_do(pd->shape->stroke.fill, ector_renderer_software_base_fill()); + ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->outline_data); + } + else + { + if (pd->shape->stroke.color.a > 0) + { + ector_software_rasterizer_color_set(pd->surface->software, + pd->shape->stroke.color.r, pd->shape->stroke.color.g, + pd->shape->stroke.color.b, pd->shape->stroke.color.a); + ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->outline_data); + } + } + + return EINA_TRUE; +} + +static Eina_Bool +_ector_renderer_software_shape_ector_renderer_software_base_fill(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Shape_Data *pd EINA_UNUSED) +{ + // FIXME: let's find out how to fill a shape with a shape later. + // I need to read SVG specification and see how to map that with software. + return EINA_FALSE; +} + +static void +_ector_renderer_software_shape_efl_gfx_shape_path_set(Eo *obj, Ector_Renderer_Software_Shape_Data *pd, + const Efl_Gfx_Path_Command *op, const double *points) +{ + if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data); + if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data); + pd->shape_data = NULL; + pd->outline_data = NULL; + + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS, efl_gfx_shape_path_set(op, points)); +} + + +static Eina_Bool +_ector_renderer_software_shape_path_changed(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ector_Renderer_Software_Shape_Data *pd = data; + + if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data); + if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data); + + pd->shape_data = NULL; + pd->outline_data = NULL; + + return EINA_TRUE; +} + +void +_ector_renderer_software_shape_eo_base_constructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd) +{ + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS, eo_constructor()); + pd->shape = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_SHAPE_MIXIN, obj); + pd->base = eo_data_xref(obj, ECTOR_RENDERER_GENERIC_BASE_CLASS, obj); + eo_do(obj, + eo_event_callback_add(EFL_GFX_PATH_CHANGED, _ector_renderer_software_shape_path_changed, pd)); +} + +void +_ector_renderer_software_shape_eo_base_destructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd) +{ + Eo *parent; + + if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data); + if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data); + + eo_do(obj, parent = eo_parent_get()); + eo_data_xunref(parent, pd->surface, obj); + + eo_data_xunref(obj, pd->shape, obj); + eo_data_xunref(obj, pd->base, obj); + eo_do_super(obj, ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS, eo_destructor()); +} + + +#include "ector_renderer_software_shape.eo.c" diff --git a/src/lib/ector/software/ector_renderer_software_shape.eo b/src/lib/ector/software/ector_renderer_software_shape.eo new file mode 100644 index 0000000000..267ef7cc7e --- /dev/null +++ b/src/lib/ector/software/ector_renderer_software_shape.eo @@ -0,0 +1,13 @@ +class Ector.Renderer.Software.Shape (Ector.Renderer.Software.Base, Ector.Renderer.Generic.Shape) +{ + eo_prefix: ector_renderer_software_shape; + legacy_prefix: null; + implements { + Ector.Renderer.Generic.Base.prepare; + Ector.Renderer.Generic.Base.draw; + Ector.Renderer.Software.Base.fill; + Efl.Gfx.Shape.path.set; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/ector/software/ector_software_gradient.c b/src/lib/ector/software/ector_software_gradient.c new file mode 100644 index 0000000000..5c3bcde3b4 --- /dev/null +++ b/src/lib/ector/software/ector_software_gradient.c @@ -0,0 +1,266 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +//Remove +#include + +#include +#include + +#include +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" +#include "ector_blend_private.h" + + +#define GRADIENT_STOPTABLE_SIZE 1024 +#define FIXPT_BITS 8 +#define FIXPT_SIZE (1<gd->s == EFL_GFX_GRADIENT_SPREAD_REPEAT) + { + ipos = ipos % GRADIENT_STOPTABLE_SIZE; + ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; + } + else if (data->gd->s == EFL_GFX_GRADIENT_SPREAD_REFLECT) + { + const int limit = GRADIENT_STOPTABLE_SIZE * 2; + ipos = ipos % limit; + ipos = ipos < 0 ? limit + ipos : ipos; + ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos; + } + else + { + if (ipos < 0) + ipos = 0; + else if (ipos >= GRADIENT_STOPTABLE_SIZE) + ipos = GRADIENT_STOPTABLE_SIZE-1; + } + + return ipos; +} + + +static uint +_gradient_pixel_fixed(const Ector_Renderer_Software_Gradient_Data *data, int fixed_pos) +{ + int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + return data->color_table[_gradient_clamp(data, ipos)]; +} + +static inline uint +_gradient_pixel(const Ector_Renderer_Software_Gradient_Data *data, float pos) +{ + int ipos = (int)(pos * (GRADIENT_STOPTABLE_SIZE - 1) + (float)(0.5)); + return data->color_table[_gradient_clamp(data, ipos)]; +} + +typedef double (*BLEND_FUNC)(double progress); + +static double +_ease_linear(double t) +{ + return t; +} + +static void +_generate_gradient_color_table(Efl_Gfx_Gradient_Stop *gradient_stops, int stop_count, uint *color_table, int size) +{ + int pos = 0; + Efl_Gfx_Gradient_Stop *curr, *next; + assert(stop_count > 0); + + curr = gradient_stops; + uint current_color = ECTOR_ARGB_JOIN(curr->a, curr->r, curr->g, curr->b); + double incr = 1.0 / (double)size; + double fpos = 1.5 * incr; + + color_table[pos++] = current_color; + + while (fpos <= curr->offset) + { + color_table[pos] = color_table[pos - 1]; + pos++; + fpos += incr; + } + + for (int i = 0; i < stop_count - 1; ++i) + { + curr = (gradient_stops + i); + next = (gradient_stops + i + 1); + double delta = 1/(next->offset - curr->offset); + uint next_color = ECTOR_ARGB_JOIN(next->a, next->r, next->g, next->b); + BLEND_FUNC func = &_ease_linear; + while (fpos < next->offset && pos < size) + { + double t = func((fpos - curr->offset) * delta); + int dist = (int)(256 * t); + int idist = 256 - dist; + color_table[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist); + ++pos; + fpos += incr; + } + current_color = next_color; + } + + for (;pos < size; ++pos) + color_table[pos] = current_color; + + // Make sure the last color stop is represented at the end of the table + color_table[size-1] = current_color; +} + + +void +update_color_table(Ector_Renderer_Software_Gradient_Data *gdata) +{ + if(gdata->color_table) return; + + gdata->color_table = malloc(GRADIENT_STOPTABLE_SIZE * 4); + _generate_gradient_color_table(gdata->gd->colors, gdata->gd->colors_count, gdata->color_table, GRADIENT_STOPTABLE_SIZE); +} + +void +destroy_color_table(Ector_Renderer_Software_Gradient_Data *gdata) +{ + if (gdata->color_table) + { + free(gdata->color_table); + gdata->color_table = NULL; + } +} + + +void +fetch_linear_gradient(uint *buffer, Span_Data *data, int y, int x, int length) +{ + Ector_Renderer_Software_Gradient_Data *g_data = data->gradient; + float t, inc; + float rx=0, ry=0; + + if (g_data->linear.l == 0) + { + t = inc = 0; + } + else + { + rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5); + ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5); + t = g_data->linear.dx*rx + g_data->linear.dy*ry + g_data->linear.off; + inc = g_data->linear.dx * data->inv.xx + g_data->linear.dx * data->inv.yx; + + t *= (GRADIENT_STOPTABLE_SIZE - 1); + inc *= (GRADIENT_STOPTABLE_SIZE - 1); + } + + uint *end = buffer + length; + if (inc > (float)(-1e-5) && inc < (float)(1e-5)) + { + _ector_memfill(buffer, _gradient_pixel_fixed(g_data, (int)(t * FIXPT_SIZE)), length); + } + else + { + if (t + inc*length < (float)(INT_MAX >> (FIXPT_BITS + 1)) && + t+inc*length > (float)(INT_MIN >> (FIXPT_BITS + 1))) + { + // we can use fixed point math + int t_fixed = (int)(t * FIXPT_SIZE); + int inc_fixed = (int)(inc * FIXPT_SIZE); + // #ifdef BUILD_SSE3 + // if (evas_common_cpu_has_feature(CPU_FEATURE_SSE3)) { + // _fetch_linear_sse3(buffer, length, g_data, t_fixed, inc_fixed); + // } else + // #endif + { + while (buffer < end) + { + *buffer++ = _gradient_pixel_fixed(g_data, t_fixed); + t_fixed += inc_fixed; + } + } + } + else + { + // we have to fall back to float math + while (buffer < end) { + *buffer++ = _gradient_pixel(g_data, t/GRADIENT_STOPTABLE_SIZE); + t += inc; + } + } + } +} + +static void +_radial_helper_generic(uint *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, float det, + float delta_det, float delta_delta_det, float b, float delta_b) +{ + for (int i = 0 ; i < length ; i++) + { + *buffer++ = _gradient_pixel(g_data, sqrt(det) - b); + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } +} + +void +fetch_radial_gradient(uint *buffer, Span_Data *data, int y, int x, int length) +{ + Ector_Renderer_Software_Gradient_Data *g_data = data->gradient; + + // avoid division by zero + if (abs(g_data->radial.a) <= 0.00001f) + { + _ector_memfill(buffer, 0, length); + return; + } + + float rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5); + float ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5); + + rx -= g_data->radial.fx; + ry -= g_data->radial.fy; + + float inv_a = 1 / (float)(2 * g_data->radial.a); + + const float delta_rx = data->inv.xx; + const float delta_ry = data->inv.yx; + + float b = 2*(g_data->radial.dr*g_data->radial.fradius + rx * g_data->radial.dx + ry * g_data->radial.dy); + float delta_b = 2*(delta_rx * g_data->radial.dx + delta_ry * g_data->radial.dy); + const float b_delta_b = 2 * b * delta_b; + const float delta_b_delta_b = 2 * delta_b * delta_b; + + const float bb = b * b; + const float delta_bb = delta_b * delta_b; + b *= inv_a; + delta_b *= inv_a; + + const float rxrxryry = rx * rx + ry * ry; + const float delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; + const float rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); + const float delta_rx_plus_ry = 2 * delta_rxrxryry; + + inv_a *= inv_a; + + float det = (bb - 4 * g_data->radial.a * (g_data->radial.sqrfr - rxrxryry)) * inv_a; + float delta_det = (b_delta_b + delta_bb + 4 * g_data->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; + const float delta_delta_det = (delta_b_delta_b + 4 * g_data->radial.a * delta_rx_plus_ry) * inv_a; + + // #ifdef BUILD_SSE3 + // if (evas_common_cpu_has_feature(CPU_FEATURE_SSE3)) { + // _radial_helper_sse3(buffer, length, g_data, det, delta_det, delta_delta_det, b, delta_b); + // } else + // #endif + { // generic fallback + _radial_helper_generic(buffer, length, g_data, det, delta_det, delta_delta_det, b, delta_b); + } +} diff --git a/src/lib/ector/software/ector_software_private.h b/src/lib/ector/software/ector_software_private.h new file mode 100644 index 0000000000..2e1ca1ce8a --- /dev/null +++ b/src/lib/ector/software/ector_software_private.h @@ -0,0 +1,152 @@ +#ifndef ECTOR_SOFTWARE_PRIVATE_H_ +# define ECTOR_SOFTWARE_PRIVATE_H_ + +#include "sw_ft_raster.h" +#include "sw_ft_stroker.h" + +#ifndef DATA32 +typedef unsigned int DATA32; +#endif + +#ifndef uint +typedef unsigned int uint; +#endif + +typedef struct _Ector_Software_Surface_Data Ector_Software_Surface_Data; + +#define CHECK_SOFTWARE(Parent) (!(Parent && Parent->software)) + +// Gradient related structure +typedef struct _Software_Gradient_Linear_Data +{ + float x1, y1, x2, y2; + float dx, dy, l, off; +} Software_Gradient_Linear_Data; + +typedef struct _Software_Gradient_Radial_Data +{ + float cx, cy, fx, fy, cradius, fradius; + float dx, dy, dr, sqrfr, a, inv2a; + Eina_Bool extended; +} Software_Gradient_Radial_Data; + +typedef struct _Ector_Renderer_Software_Gradient_Data +{ + Ector_Software_Surface_Data *surface; + Ector_Renderer_Generic_Gradient_Data *gd; + union { + Ector_Renderer_Generic_Gradient_Linear_Data *gld; + Ector_Renderer_Generic_Gradient_Radial_Data *grd; + }; + union { + Software_Gradient_Linear_Data linear; + Software_Gradient_Radial_Data radial; + }; + uint* color_table; +} Ector_Renderer_Software_Gradient_Data; + + +// Rasterizer related structure +typedef struct _Raster_Buffer +{ + int width; + int height; + DATA32 *buffer; +} Raster_Buffer; + +typedef struct _Shape_Rle_Data +{ + unsigned short alloc; + unsigned short size; + SW_FT_Span *spans;// array of Scanlines. +} Shape_Rle_Data; + +typedef struct _Clip_Data +{ + Eina_Array *clips; //Eina_Rectangle + Shape_Rle_Data *path; + unsigned int enabled : 1; + unsigned int has_rect_clip : 1; + unsigned int has_path_clip : 1; +} Clip_Data; + + +typedef enum _Span_Data_Type { + None, + Solid, + LinearGradient, + RadialGradient, + Image +} Span_Data_Type; + +typedef struct _Span_Data +{ + Raster_Buffer raster_buffer; + + SW_FT_SpanFunc blend; + SW_FT_SpanFunc unclipped_blend; + + int offx, offy; + Clip_Data clip; + Eina_Matrix3 inv; + Span_Data_Type type; + Eina_Bool fast_matrix ; + DATA32 mul_col; + Ector_Rop op; + union { + DATA32 color; + Ector_Renderer_Software_Gradient_Data *gradient; + //ImageData texture; + }; +} Span_Data; + +typedef struct _Software_Rasterizer +{ + SW_FT_Raster raster; + SW_FT_Stroker stroker; + + Span_Data fill_data; + Eina_Matrix3 *transform; + Eina_Rectangle system_clip; + +} Software_Rasterizer; + +struct _Ector_Software_Surface_Data +{ + Software_Rasterizer *software; + int x; + int y; +}; + + +void ector_software_rasterizer_init(Software_Rasterizer *rasterizer); +void ector_software_rasterizer_done(Software_Rasterizer *rasterizer); + +void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width, + Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style); + +void ector_software_rasterizer_transform_set(Software_Rasterizer *rasterizer, Eina_Matrix3 *t); +void ector_software_rasterizer_color_set(Software_Rasterizer *rasterizer, int r, int g, int b, int a); +void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *linear); +void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *radial); +void ector_software_rasterizer_clip_rect_set(Software_Rasterizer *rasterizer, Eina_Array *clips); +void ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, Shape_Rle_Data *clip); + + + +Shape_Rle_Data * ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline); +Shape_Rle_Data * ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath); + +void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer, int x, int y, uint mul_col, Ector_Rop op, Shape_Rle_Data* rle); + +void ector_software_rasterizer_destroy_rle_data(Shape_Rle_Data *rle); + + + +// Gradient Api +void update_color_table(Ector_Renderer_Software_Gradient_Data *gdata); +void destroy_color_table(Ector_Renderer_Software_Gradient_Data *gdata); +void fetch_linear_gradient(uint *buffer, Span_Data *data, int y, int x, int length); +void fetch_radial_gradient(uint *buffer, Span_Data *data, int y, int x, int length); + +#endif diff --git a/src/lib/ector/software/ector_software_rasterizer.c b/src/lib/ector/software/ector_software_rasterizer.c new file mode 100644 index 0000000000..71eaa1f688 --- /dev/null +++ b/src/lib/ector/software/ector_software_rasterizer.c @@ -0,0 +1,516 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" +#include "ector_blend_private.h" + +static void +_blend_color_argb(int count, const SW_FT_Span *spans, void *user_data) +{ + Span_Data *data = (Span_Data *)(user_data); + + // multiply the color with mul_col if any + uint color = ECTOR_MUL4_SYM(data->color, data->mul_col); + Eina_Bool solid_source = ((color >> 24) == 255); + + // move to the offset location + uint *buffer = data->raster_buffer.buffer + (data->raster_buffer.width * data->offy + data->offx); + + if (solid_source) + { + while (count--) + { + uint *target = buffer + (data->raster_buffer.width * spans->y + spans->x); + if (spans->coverage == 255) + { + _ector_memfill(target, color, spans->len); + } + else + { + uint c = ECTOR_MUL_256(color, spans->coverage); + int ialpha = 255 - spans->coverage; + for (int i = 0; i < spans->len; ++i) + target[i] = c + ECTOR_MUL_256(target[i], ialpha); + } + ++spans; + } + return; + } + + while (count--) + { + uint *target = buffer + (data->raster_buffer.width * spans->y + spans->x); + uint c = ECTOR_MUL_256(color, spans->coverage); + int ialpha = (~c) >> 24; + + for (int i = 0; i < spans->len; ++i) + target[i] = c + ECTOR_MUL_256(target[i], ialpha); + ++spans; + } +} + +int buffer_size = 2048; + +typedef void (*src_fetch) (unsigned int *buffer, Span_Data *data, int y, int x, int length); + +static void +_blend_gradient(int count, const SW_FT_Span *spans, void *user_data) +{ + Span_Data *data = (Span_Data *)(user_data); + src_fetch fetchfunc = NULL; + + if(data->type == LinearGradient) fetchfunc = &fetch_linear_gradient; + if(data->type == RadialGradient) fetchfunc = &fetch_radial_gradient; + + unsigned int buffer[buffer_size]; + + // move to the offset location + unsigned int *destbuffer = data->raster_buffer.buffer + (data->raster_buffer.width * data->offy + data->offx); + + while (count--) + { + unsigned int *target = destbuffer + (data->raster_buffer.width * spans->y + spans->x); + int length = spans->len; + while (length) + { + int l = MIN(length, buffer_size); + fetchfunc(buffer, data, spans->y, spans->x, l); + if (data->mul_col == 0xffffffff) + _ector_comp_func_source_over(target, buffer, l, spans->coverage); // TODO use proper composition func + else + _ector_comp_func_source_over_mul_c(target, buffer, data->mul_col, l, spans->coverage); + target += l; + length -= l; + } + ++spans; + } +} + + +/*! + \internal + spans must be sorted on y +*/ +static const +SW_FT_Span *_intersect_spans_rect(const Eina_Rectangle *clip, const SW_FT_Span *spans, const SW_FT_Span *end, + SW_FT_Span **out_spans, int available) +{ + SW_FT_Span *out = *out_spans; + const short minx = clip->x; + const short miny = clip->y; + const short maxx = minx + clip->w - 1; + const short maxy = miny + clip->h - 1; + + while (available && spans < end ) + { + if (spans->y > maxy) + { + spans = end;// update spans so that we can breakout + break; + } + if (spans->y < miny + || spans->x > maxx + || spans->x + spans->len <= minx) + { + ++spans; + continue; + } + if (spans->x < minx) + { + out->len = MIN(spans->len - (minx - spans->x), maxx - minx + 1); + out->x = minx; + } + else + { + out->x = spans->x; + out->len = MIN(spans->len, (maxx - spans->x + 1)); + } + if (out->len != 0) + { + out->y = spans->y; + out->coverage = spans->coverage; + ++out; + } + + ++spans; + --available; + } + + *out_spans = out; + + return spans; +} + +static inline int +_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } + +static const +SW_FT_Span *_intersect_spans_region(const Shape_Rle_Data *clip, int *currentClip, + const SW_FT_Span *spans, const SW_FT_Span *end, + SW_FT_Span **out_spans, int available) +{ + SW_FT_Span *out = *out_spans; + + const SW_FT_Span *clipSpans = clip->spans + *currentClip; + const SW_FT_Span *clipEnd = clip->spans + clip->size; + + while (available && spans < end ) { + if (clipSpans >= clipEnd) { + spans = end; + break; + } + if (clipSpans->y > spans->y) { + ++spans; + continue; + } + if (spans->y != clipSpans->y) { + ++clipSpans; + continue; + } + //assert(spans->y == clipSpans->y); + + int sx1 = spans->x; + int sx2 = sx1 + spans->len; + int cx1 = clipSpans->x; + int cx2 = cx1 + clipSpans->len; + + if (cx1 < sx1 && cx2 < sx1) { + ++clipSpans; + continue; + } else if (sx1 < cx1 && sx2 < cx1) { + ++spans; + continue; + } + int x = MAX(sx1, cx1); + int len = MIN(sx2, cx2) - x; + if (len) { + out->x = MAX(sx1, cx1); + out->len = MIN(sx2, cx2) - out->x; + out->y = spans->y; + out->coverage = _div_255(spans->coverage * clipSpans->coverage); + ++out; + --available; + } + if (sx2 < cx2) { + ++spans; + } else { + ++clipSpans; + } + } + + *out_spans = out; + *currentClip = clipSpans - clip->spans; + return spans; +} + +static void +_span_fill_clipRect(int span_count, const SW_FT_Span *spans, void *user_data) +{ + const int NSPANS = 256; + int clip_count, i; + SW_FT_Span cspans[NSPANS]; + Span_Data *fill_data = (Span_Data *) user_data; + Clip_Data clip = fill_data->clip; + + clip_count = eina_array_count(clip.clips); + for (i = 0; i < clip_count ; i ++) + { + Eina_Rectangle *rect = (Eina_Rectangle *)eina_array_data_get(clip.clips, i); + Eina_Rectangle tmpRect; + + // invert transform the offset + tmpRect.x = rect->x - fill_data->offx; + tmpRect.y = rect->y - fill_data->offy; + tmpRect.w = rect->w; + tmpRect.h = rect->h; + const SW_FT_Span *end = spans + span_count; + + while (spans < end) + { + SW_FT_Span *clipped = cspans; + spans = _intersect_spans_rect(&tmpRect,spans, end, &clipped, NSPANS); + if (clipped - cspans) + fill_data->unclipped_blend(clipped - cspans, cspans, fill_data); + } + } +} + +static void +_span_fill_clipPath(int span_count, const SW_FT_Span *spans, void *user_data) +{ + const int NSPANS = 256; + int current_clip = 0; + SW_FT_Span cspans[NSPANS]; + Span_Data *fill_data = (Span_Data *) user_data; + Clip_Data clip = fill_data->clip; + + //TODO take clip path offset into account. + + const SW_FT_Span *end = spans + span_count; + while (spans < end) + { + SW_FT_Span *clipped = cspans; + spans = _intersect_spans_region(clip.path, ¤t_clip, spans, end, &clipped, NSPANS); + if (clipped - cspans) + fill_data->unclipped_blend(clipped - cspans, cspans, fill_data); + } +} + +static void +_adjust_span_fill_methods(Span_Data *spdata) +{ + switch(spdata->type) + { + case None: + spdata->unclipped_blend = 0; + break; + case Solid: + spdata->unclipped_blend = &_blend_color_argb; + break; + case LinearGradient: + case RadialGradient: + spdata->unclipped_blend = &_blend_gradient; + break; + case Image: + spdata->unclipped_blend = 0;//&_blend_image; + break; + } + + // setup clipping + if (!spdata->unclipped_blend) + { + spdata->blend = 0; + } + else if (!spdata->clip.enabled) + { + spdata->blend = spdata->unclipped_blend; + } + else if (spdata->clip.has_rect_clip) + { + spdata->blend = &_span_fill_clipRect; + } + else + { + spdata->blend = &_span_fill_clipPath; + } +} + + + +void ector_software_rasterizer_init(Software_Rasterizer *rasterizer) +{ + // initialize the rasterizer and stroker + unsigned char* renderPool = (unsigned char*) malloc(1024 * 100); + sw_ft_grays_raster.raster_new(&rasterizer->raster); + sw_ft_grays_raster.raster_reset(rasterizer->raster, renderPool, 1024*100); + + SW_FT_Stroker_New(&rasterizer->stroker); + SW_FT_Stroker_Set(rasterizer->stroker, 1<<6,SW_FT_STROKER_LINECAP_BUTT,SW_FT_STROKER_LINEJOIN_MITER,0); + + //initialize the span data. + rasterizer->fill_data.raster_buffer.buffer = NULL; + rasterizer->fill_data.clip.enabled = EINA_FALSE; + rasterizer->fill_data.unclipped_blend = 0; + rasterizer->fill_data.blend = 0; +} + +void ector_software_rasterizer_done(Software_Rasterizer *rasterizer) +{ + sw_ft_grays_raster.raster_done(rasterizer->raster); + SW_FT_Stroker_Done(rasterizer->stroker); + //TODO free the pool memory +} + + +void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width, + Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style) +{ + SW_FT_Stroker_LineCap cap; + SW_FT_Stroker_LineJoin join; + + switch (cap_style) + { + case EFL_GFX_CAP_SQUARE: + cap = SW_FT_STROKER_LINECAP_SQUARE; + break; + case EFL_GFX_CAP_ROUND: + cap = SW_FT_STROKER_LINECAP_ROUND; + break; + default: + cap = SW_FT_STROKER_LINECAP_BUTT; + break; + } + + switch (join_style) + { + case EFL_GFX_JOIN_BEVEL: + join = SW_FT_STROKER_LINEJOIN_BEVEL; + break; + case EFL_GFX_JOIN_ROUND: + join = SW_FT_STROKER_LINEJOIN_ROUND; + break; + default: + join = SW_FT_STROKER_LINEJOIN_MITER; + break; + } + + int stroke_width = (int)(width * 64); + SW_FT_Stroker_Set(rasterizer->stroker, stroke_width, cap, join, 0); +} + +static void +_rle_generation_cb( int count, const SW_FT_Span* spans,void *user) +{ + Shape_Rle_Data *rle = (Shape_Rle_Data *) user; + int newsize = rle->size + count; + + // allocate enough memory for new spans + // alloc is required to prevent free and reallocation + // when the rle needs to be regenerated because of attribute change. + if(rle->alloc < newsize) + { + rle->spans = (SW_FT_Span *) realloc(rle->spans, newsize * sizeof(SW_FT_Span)); + rle->alloc = newsize; + } + + // copy the new spans to the allocated memory + SW_FT_Span *lastspan = (rle->spans + rle->size); + memcpy(lastspan,spans, count * sizeof(SW_FT_Span)); + + // update the size + rle->size = newsize; +} + +Shape_Rle_Data * +ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline) +{ + Shape_Rle_Data *rle_data = (Shape_Rle_Data *) calloc(1, sizeof(Shape_Rle_Data)); + SW_FT_Raster_Params params; + + params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ; + params.gray_spans = &_rle_generation_cb; + params.user = rle_data; + params.source = outline; + + sw_ft_grays_raster.raster_render(rasterizer->raster, ¶ms); + + return rle_data; +} + +Shape_Rle_Data * +ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath) +{ + uint points,contors; + + SW_FT_Stroker_ParseOutline(rasterizer->stroker, outline, !closePath); + SW_FT_Stroker_GetCounts(rasterizer->stroker,&points, &contors); + + SW_FT_Outline strokeOutline = {0}; + strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector)); + strokeOutline.tags = (char *) calloc(points, sizeof(char)); + strokeOutline.contours = (short *) calloc(contors, sizeof(short)); + + SW_FT_Stroker_Export(rasterizer->stroker, &strokeOutline); + + Shape_Rle_Data *rle_data = ector_software_rasterizer_generate_rle_data(rasterizer, &strokeOutline); + + // cleanup the outline data. + free(strokeOutline.points); + free(strokeOutline.tags); + free(strokeOutline.contours); + + return rle_data; +} + +void ector_software_rasterizer_destroy_rle_data(Shape_Rle_Data *rle) +{ + if (rle) + { + if (rle->spans) + free(rle->spans); + free(rle); + } +} + +static +void _setup_span_fill_matrix(Software_Rasterizer *rasterizer) +{ + if (rasterizer->transform) + { + eina_matrix3_inverse(rasterizer->transform, &rasterizer->fill_data.inv); + } + else + { + eina_matrix3_identity(&rasterizer->fill_data.inv); + eina_matrix3_identity(&rasterizer->fill_data.inv); + } +} + +void ector_software_rasterizer_transform_set(Software_Rasterizer *rasterizer, Eina_Matrix3 *t) +{ + rasterizer->transform = t; +} + +void ector_software_rasterizer_clip_rect_set(Software_Rasterizer *rasterizer, Eina_Array *clips) +{ + if (clips) + { + rasterizer->fill_data.clip.clips = clips; + rasterizer->fill_data.clip.has_rect_clip = EINA_TRUE; + rasterizer->fill_data.clip.enabled = EINA_TRUE; + } + else + { + rasterizer->fill_data.clip.clips = NULL; + rasterizer->fill_data.clip.has_rect_clip = EINA_FALSE; + rasterizer->fill_data.clip.enabled = EINA_FALSE; + } +} + +void ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, Shape_Rle_Data *clip) +{ + rasterizer->fill_data.clip.path = clip; + rasterizer->fill_data.clip.has_path_clip = EINA_TRUE; + rasterizer->fill_data.clip.enabled = EINA_TRUE; +} + +void ector_software_rasterizer_color_set(Software_Rasterizer *rasterizer, int r, int g, int b, int a) +{ + rasterizer->fill_data.color = ECTOR_ARGB_JOIN(a, r, g, b); + rasterizer->fill_data.type = Solid; +} +void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *linear) +{ + rasterizer->fill_data.gradient = linear; + rasterizer->fill_data.type = LinearGradient; +} +void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *radial) +{ + rasterizer->fill_data.gradient = radial; + rasterizer->fill_data.type = RadialGradient; +} + + +void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer, + int x, int y, uint mul_col, Ector_Rop op, Shape_Rle_Data* rle) +{ + // check for NULL rle data + if (!rle) return; + + rasterizer->fill_data.offx = x; + rasterizer->fill_data.offy = y; + rasterizer->fill_data.mul_col = mul_col; + rasterizer->fill_data.op = op; + + _setup_span_fill_matrix(rasterizer); + _adjust_span_fill_methods(&rasterizer->fill_data); + + if(rasterizer->fill_data.blend) + rasterizer->fill_data.blend(rle->size, rle->spans, &rasterizer->fill_data); +} diff --git a/src/lib/ector/software/ector_software_surface.c b/src/lib/ector/software/ector_software_surface.c new file mode 100644 index 0000000000..02d93c39df --- /dev/null +++ b/src/lib/ector/software/ector_software_surface.c @@ -0,0 +1,103 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "ector_private.h" +#include "ector_software_private.h" + +static unsigned int _software_count = 0; + +typedef struct _Ector_Renderer_Software_Base_Data Ector_Renderer_Software_Base_Data; +struct _Ector_Renderer_Software_Base_Data +{ +}; + +static Ector_Renderer * +_ector_software_surface_ector_generic_surface_renderer_factory_new(Eo *obj, + Ector_Software_Surface_Data *pd EINA_UNUSED, + const Eo_Class *type) +{ + if (type == ECTOR_RENDERER_GENERIC_SHAPE_MIXIN) + return eo_add(ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS, obj); + else if (type == ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN) + return eo_add(ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS, obj); + else if (type == ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN) + return eo_add(ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, obj); + ERR("Couldn't find class for type: %s\n", eo_class_name_get(type)); + return NULL; +} + +static void +_ector_software_surface_context_set(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd, + Software_Rasterizer *ctx) +{ + pd->software = ctx; +} + +static Software_Rasterizer * +_ector_software_surface_context_get(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd) +{ + return pd->software; +} + +void +_ector_software_surface_surface_set(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd, + void *pixels, unsigned int width, unsigned int height) +{ + pd->software->fill_data.raster_buffer.buffer = pixels; + pd->software->fill_data.raster_buffer.width = width; + pd->software->fill_data.raster_buffer.height = height; +} + +void +_ector_software_surface_surface_get(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd, + void **pixels, unsigned int *width, unsigned int *height) +{ + *pixels = pd->software->fill_data.raster_buffer.buffer; + *width = pd->software->fill_data.raster_buffer.width; + *height = pd->software->fill_data.raster_buffer.height; +} + +static void +_ector_software_surface_eo_base_constructor(Eo *obj, + Ector_Software_Surface_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, ECTOR_SOFTWARE_SURFACE_CLASS, eo_constructor()); + if(_software_count == 0) + { + pd->software = (Software_Rasterizer *) calloc(1, sizeof(Software_Rasterizer)); + ector_software_rasterizer_init(pd->software); + } + _software_count++; +} + +static void +_ector_software_surface_eo_base_destructor(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd EINA_UNUSED) +{ + --_software_count; + if (_software_count > 0) return; + ector_software_rasterizer_done(pd->software); + free(pd->software); + pd->software = NULL; + eo_do_super(obj, ECTOR_SOFTWARE_SURFACE_CLASS, eo_destructor()); +} + +static void +_ector_software_surface_ector_generic_surface_reference_point_set(Eo *obj EINA_UNUSED, + Ector_Software_Surface_Data *pd, + int x, int y) +{ + pd->x = x; + pd->y = y; +} + +#include "ector_software_surface.eo.c" +#include "ector_renderer_software_base.eo.c" diff --git a/src/lib/ector/software/ector_software_surface.eo b/src/lib/ector/software/ector_software_surface.eo new file mode 100644 index 0000000000..3ed863c0c8 --- /dev/null +++ b/src/lib/ector/software/ector_software_surface.eo @@ -0,0 +1,34 @@ +class Ector.Software.Surface (Ector.Generic.Surface) +{ + eo_prefix: ector_software_surface; + legacy_prefix: null; + properties { + context { + set { + } + get { + } + values { + Software_Rasterizer *ctx; + } + } + surface { + set { + } + get { + } + values { + void *pixels; + uint width; + uint height; + } + } + } + + implements { + Ector.Generic.Surface.renderer_factory_new; + Ector.Generic.Surface.reference_point.set; + Eo.Base.destructor; + Eo.Base.constructor; + } +} diff --git a/src/lib/ector/software/sw_ft_math.c b/src/lib/ector/software/sw_ft_math.c new file mode 100755 index 0000000000..9b3894ff8d --- /dev/null +++ b/src/lib/ector/software/sw_ft_math.c @@ -0,0 +1,528 @@ +/***************************************************************************/ +/* */ +/* fttrigon.c */ +/* */ +/* FreeType trigonometric functions (body). */ +/* */ +/* Copyright 2001-2005, 2012-2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include +#include "sw_ft_math.h" + + +#define SW_FT_MSB( x ) ( 31 - __builtin_clz( x ) ) + +#define SW_FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) +#define SW_FT_PAD_ROUND( x, n ) SW_FT_PAD_FLOOR( (x) + ((n)/2), n ) +#define SW_FT_PAD_CEIL( x, n ) SW_FT_PAD_FLOOR( (x) + ((n)-1), n ) + + +#define SW_FT_BEGIN_STMNT do { +#define SW_FT_END_STMNT } while ( 0 ) +/* transfer sign leaving a positive number */ +#define SW_FT_MOVE_SIGN( x, s ) \ +SW_FT_BEGIN_STMNT \ + if ( x < 0 ) \ + { \ + x = -x; \ + s = -s; \ + } \ +SW_FT_END_STMNT + + + + +SW_FT_Long +SW_FT_MulFix( SW_FT_Long a, + SW_FT_Long b ) +{ + SW_FT_Int s = 1; + SW_FT_Long c; + + + SW_FT_MOVE_SIGN( a, s ); + SW_FT_MOVE_SIGN( b, s ); + + c = (SW_FT_Long)( ( (SW_FT_Int64)a * b + 0x8000L ) >> 16 ); + + return ( s > 0 ) ? c : -c; +} + +SW_FT_Long +SW_FT_MulDiv( SW_FT_Long a, + SW_FT_Long b, + SW_FT_Long c ) +{ + SW_FT_Int s = 1; + SW_FT_Long d; + + + SW_FT_MOVE_SIGN( a, s ); + SW_FT_MOVE_SIGN( b, s ); + SW_FT_MOVE_SIGN( c, s ); + + d = (SW_FT_Long)( c > 0 ? ( (SW_FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + + return ( s > 0 ) ? d : -d; +} + +SW_FT_Long +SW_FT_DivFix( SW_FT_Long a, + SW_FT_Long b ) +{ + SW_FT_Int s = 1; + SW_FT_Long q; + + + SW_FT_MOVE_SIGN( a, s ); + SW_FT_MOVE_SIGN( b, s ); + + q = (SW_FT_Long)( b > 0 ? ( ( (SW_FT_UInt64)a << 16 ) + ( b >> 1 ) ) / b + : 0x7FFFFFFFL ); + + return ( s < 0 ? -q : q ); +} + + +/*************************************************************************/ +/* */ +/* This is a fixed-point CORDIC implementation of trigonometric */ +/* functions as well as transformations between Cartesian and polar */ +/* coordinates. The angles are represented as 16.16 fixed-point values */ +/* in degrees, i.e., the angular resolution is 2^-16 degrees. Note that */ +/* only vectors longer than 2^16*180/pi (or at least 22 bits) on a */ +/* discrete Cartesian grid can have the same or better angular */ +/* resolution. Therefore, to maintain this precision, some functions */ +/* require an interim upscaling of the vectors, whereas others operate */ +/* with 24-bit long vectors directly. */ +/* */ +/*************************************************************************/ + + /* the Cordic shrink factor 0.858785336480436 * 2^32 */ +#define SW_FT_TRIG_SCALE 0xDBD95B16UL + + /* the highest bit in overflow-safe vector components, */ + /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ +#define SW_FT_TRIG_SAFE_MSB 29 + + /* this table was generated for SW_FT_PI = 180L << 16, i.e. degrees */ +#define SW_FT_TRIG_MAX_ITERS 23 + + static const SW_FT_Fixed + ft_trig_arctan_table[] = + { + 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, + 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L + }; + + /* multiply a given value by the CORDIC shrink factor */ + static SW_FT_Fixed + ft_trig_downscale( SW_FT_Fixed val ) + { + SW_FT_Fixed s; + SW_FT_Int64 v; + + + s = val; + val = SW_FT_ABS( val ); + + v = ( val * (SW_FT_Int64)SW_FT_TRIG_SCALE ) + 0x100000000UL; + val = (SW_FT_Fixed)( v >> 32 ); + + return ( s >= 0 ) ? val : -val; + } + + + + /* undefined and never called for zero vector */ + static SW_FT_Int + ft_trig_prenorm( SW_FT_Vector* vec ) + { + SW_FT_Pos x, y; + SW_FT_Int shift; + + + x = vec->x; + y = vec->y; + + shift = SW_FT_MSB( SW_FT_ABS( x ) | SW_FT_ABS( y ) ); + + if ( shift <= SW_FT_TRIG_SAFE_MSB ) + { + shift = SW_FT_TRIG_SAFE_MSB - shift; + vec->x = (SW_FT_Pos)( (SW_FT_ULong)x << shift ); + vec->y = (SW_FT_Pos)( (SW_FT_ULong)y << shift ); + } + else + { + shift -= SW_FT_TRIG_SAFE_MSB; + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } + + return shift; + } + + + static void + ft_trig_pseudo_rotate( SW_FT_Vector* vec, + SW_FT_Angle theta ) + { + SW_FT_Int i; + SW_FT_Fixed x, y, xtemp, b; + const SW_FT_Fixed *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Rotate inside [-PI/4,PI/4] sector */ + while ( theta < -SW_FT_ANGLE_PI4 ) + { + xtemp = y; + y = -x; + x = xtemp; + theta += SW_FT_ANGLE_PI2; + } + + while ( theta > SW_FT_ANGLE_PI4 ) + { + xtemp = -y; + y = x; + x = xtemp; + theta -= SW_FT_ANGLE_PI2; + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( theta < 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + vec->x = x; + vec->y = y; + } + + + static void + ft_trig_pseudo_polarize( SW_FT_Vector* vec ) + { + SW_FT_Angle theta; + SW_FT_Int i; + SW_FT_Fixed x, y, xtemp, b; + const SW_FT_Fixed *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Get the vector into [-PI/4,PI/4] sector */ + if ( y > x ) + { + if ( y > -x ) + { + theta = SW_FT_ANGLE_PI2; + xtemp = y; + y = -x; + x = xtemp; + } + else + { + theta = y > 0 ? SW_FT_ANGLE_PI : -SW_FT_ANGLE_PI; + x = -x; + y = -y; + } + } + else + { + if ( y < -x ) + { + theta = -SW_FT_ANGLE_PI2; + xtemp = -y; + y = x; + x = xtemp; + } + else + { + theta = 0; + } + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( y > 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + /* round theta */ + if ( theta >= 0 ) + theta = SW_FT_PAD_ROUND( theta, 32 ); + else + theta = -SW_FT_PAD_ROUND( -theta, 32 ); + + vec->x = x; + vec->y = theta; + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Fixed + SW_FT_Cos( SW_FT_Angle angle ) + { + SW_FT_Vector v; + + + v.x = SW_FT_TRIG_SCALE >> 8; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + + return ( v.x + 0x80L ) >> 8; + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Fixed + SW_FT_Sin( SW_FT_Angle angle ) + { + return SW_FT_Cos( SW_FT_ANGLE_PI2 - angle ); + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Fixed + SW_FT_Tan( SW_FT_Angle angle ) + { + SW_FT_Vector v; + + + v.x = SW_FT_TRIG_SCALE >> 8; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + + return SW_FT_DivFix( v.y, v.x ); + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Angle + SW_FT_Atan2( SW_FT_Fixed dx, + SW_FT_Fixed dy ) + { + SW_FT_Vector v; + + + if ( dx == 0 && dy == 0 ) + return 0; + + v.x = dx; + v.y = dy; + ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + void + SW_FT_Vector_Unit( SW_FT_Vector* vec, + SW_FT_Angle angle ) + { + vec->x = SW_FT_TRIG_SCALE >> 8; + vec->y = 0; + ft_trig_pseudo_rotate( vec, angle ); + vec->x = ( vec->x + 0x80L ) >> 8; + vec->y = ( vec->y + 0x80L ) >> 8; + } + + + /* these macros return 0 for positive numbers, + and -1 for negative ones */ +#define SW_FT_SIGN_LONG( x ) ( (x) >> ( SW_FT_SIZEOF_LONG * 8 - 1 ) ) +#define SW_FT_SIGN_INT( x ) ( (x) >> ( SW_FT_SIZEOF_INT * 8 - 1 ) ) +#define SW_FT_SIGN_INT32( x ) ( (x) >> 31 ) +#define SW_FT_SIGN_INT16( x ) ( (x) >> 15 ) + + + /* documentation is in fttrigon.h */ + + void + SW_FT_Vector_Rotate( SW_FT_Vector* vec, + SW_FT_Angle angle ) + { + SW_FT_Int shift; + SW_FT_Vector v; + + + v.x = vec->x; + v.y = vec->y; + + if ( angle && ( v.x != 0 || v.y != 0 ) ) + { + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); + + if ( shift > 0 ) + { + SW_FT_Int32 half = (SW_FT_Int32)1L << ( shift - 1 ); + + + vec->x = ( v.x + half + SW_FT_SIGN_LONG( v.x ) ) >> shift; + vec->y = ( v.y + half + SW_FT_SIGN_LONG( v.y ) ) >> shift; + } + else + { + shift = -shift; + vec->x = (SW_FT_Pos)( (SW_FT_ULong)v.x << shift ); + vec->y = (SW_FT_Pos)( (SW_FT_ULong)v.y << shift ); + } + } + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Fixed + SW_FT_Vector_Length( SW_FT_Vector* vec ) + { + SW_FT_Int shift; + SW_FT_Vector v; + + + v = *vec; + + /* handle trivial cases */ + if ( v.x == 0 ) + { + return SW_FT_ABS( v.y ); + } + else if ( v.y == 0 ) + { + return SW_FT_ABS( v.x ); + } + + /* general case */ + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + if ( shift > 0 ) + return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift; + + return (SW_FT_Fixed)( (SW_FT_UInt32)v.x << -shift ); + } + + + /* documentation is in fttrigon.h */ + + void + SW_FT_Vector_Polarize( SW_FT_Vector* vec, + SW_FT_Fixed *length, + SW_FT_Angle *angle ) + { + SW_FT_Int shift; + SW_FT_Vector v; + + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + *length = ( shift >= 0 ) ? ( v.x >> shift ) + : (SW_FT_Fixed)( (SW_FT_UInt32)v.x << -shift ); + *angle = v.y; + } + + + /* documentation is in fttrigon.h */ + + void + SW_FT_Vector_From_Polar( SW_FT_Vector* vec, + SW_FT_Fixed length, + SW_FT_Angle angle ) + { + vec->x = length; + vec->y = 0; + + SW_FT_Vector_Rotate( vec, angle ); + } + + + /* documentation is in fttrigon.h */ + + SW_FT_Angle + SW_FT_Angle_Diff( SW_FT_Angle angle1, + SW_FT_Angle angle2 ) + { + SW_FT_Angle delta = angle2 - angle1; + + + delta %= SW_FT_ANGLE_2PI; + if ( delta < 0 ) + delta += SW_FT_ANGLE_2PI; + + if ( delta > SW_FT_ANGLE_PI ) + delta -= SW_FT_ANGLE_2PI; + + return delta; + } + + +/* END */ + diff --git a/src/lib/ector/software/sw_ft_math.h b/src/lib/ector/software/sw_ft_math.h new file mode 100755 index 0000000000..b844834a3b --- /dev/null +++ b/src/lib/ector/software/sw_ft_math.h @@ -0,0 +1,438 @@ +#ifndef SW_FT_MATH_H +#define SW_FT_MATH_H + +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 2005, 2007, 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include "sw_ft_types.h" + + +/*************************************************************************/ +/* */ +/* The min and max functions missing in C. As usual, be careful not to */ +/* write things like SW_FT_MIN( a++, b++ ) to avoid side effects. */ +/* */ +#define SW_FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define SW_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define SW_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + +/* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +#define SW_FT_HYPOT( x, y ) \ + ( x = SW_FT_ABS( x ), \ + y = SW_FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_MulFix */ +/* */ +/* */ +/* A very simple function used to perform the computation */ +/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */ +/* used to multiply a given value by a 16.16 fixed-point factor. */ +/* */ +/* */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. Use a 16.16 factor here whenever */ +/* possible (see note below). */ +/* */ +/* */ +/* The result of `(a*b)/0x10000'. */ +/* */ +/* */ +/* This function has been optimized for the case where the absolute */ +/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ +/* As this happens mainly when scaling from notional units to */ +/* fractional pixels in FreeType, it resulted in noticeable speed */ +/* improvements between versions 2.x and 1.x. */ +/* */ +/* As a conclusion, always try to place a 16.16 factor as the */ +/* _second_ argument of this function; this can make a great */ +/* difference. */ +/* */ +SW_FT_Long +SW_FT_MulFix( SW_FT_Long a, + SW_FT_Long b ); + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_MulDiv */ +/* */ +/* */ +/* A very simple function used to perform the computation `(a*b)/c' */ +/* with maximum accuracy (it uses a 64-bit intermediate integer */ +/* whenever necessary). */ +/* */ +/* This function isn't necessarily as fast as some processor specific */ +/* operations, but is at least completely portable. */ +/* */ +/* */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. */ +/* c :: The divisor. */ +/* */ +/* */ +/* The result of `(a*b)/c'. This function never traps when trying to */ +/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ +/* on the signs of `a' and `b'. */ +/* */ +SW_FT_Long +SW_FT_MulDiv( SW_FT_Long a, + SW_FT_Long b, + SW_FT_Long c ); + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_DivFix */ +/* */ +/* */ +/* A very simple function used to perform the computation */ +/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */ +/* used to divide a given value by a 16.16 fixed-point factor. */ +/* */ +/* */ +/* a :: The numerator. */ +/* b :: The denominator. Use a 16.16 factor here. */ +/* */ +/* */ +/* The result of `(a*0x10000)/b'. */ +/* */ +SW_FT_Long +SW_FT_DivFix( SW_FT_Long a, + SW_FT_Long b ); + + + + /*************************************************************************/ + /* */ + /*
*/ + /* computations */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * SW_FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed-point value expressed in degrees. + * + */ + typedef SW_FT_Fixed SW_FT_Angle; + + + /************************************************************************* + * + * @macro: + * SW_FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @SW_FT_Angle units. + * + */ +#define SW_FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************* + * + * @macro: + * SW_FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @SW_FT_Angle units. + * + */ +#define SW_FT_ANGLE_2PI ( SW_FT_ANGLE_PI * 2 ) + + + /************************************************************************* + * + * @macro: + * SW_FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @SW_FT_Angle units. + * + */ +#define SW_FT_ANGLE_PI2 ( SW_FT_ANGLE_PI / 2 ) + + + /************************************************************************* + * + * @macro: + * SW_FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @SW_FT_Angle units. + * + */ +#define SW_FT_ANGLE_PI4 ( SW_FT_ANGLE_PI / 4 ) + + + /************************************************************************* + * + * @function: + * SW_FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @SW_FT_Vector_Unit. + * + */ + SW_FT_Fixed + SW_FT_Sin( SW_FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @SW_FT_Vector_Unit. + * + */ + SW_FT_Fixed + SW_FT_Cos( SW_FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + SW_FT_Fixed + SW_FT_Tan( SW_FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + SW_FT_Angle + SW_FT_Atan2( SW_FT_Fixed x, + SW_FT_Fixed y ); + + + /************************************************************************* + * + * @function: + * SW_FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ + SW_FT_Angle + SW_FT_Angle_Diff( SW_FT_Angle angle1, + SW_FT_Angle angle2 ); + + + /************************************************************************* + * + * @function: + * SW_FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + void + SW_FT_Vector_Unit( SW_FT_Vector* vec, + SW_FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + void + SW_FT_Vector_Rotate( SW_FT_Vector* vec, + SW_FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + SW_FT_Fixed + SW_FT_Vector_Length( SW_FT_Vector* vec ); + + + /************************************************************************* + * + * @function: + * SW_FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + void + SW_FT_Vector_Polarize( SW_FT_Vector* vec, + SW_FT_Fixed *length, + SW_FT_Angle *angle ); + + + /************************************************************************* + * + * @function: + * SW_FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + void + SW_FT_Vector_From_Polar( SW_FT_Vector* vec, + SW_FT_Fixed length, + SW_FT_Angle angle ); + + +#endif // SW_FT_MATH_H diff --git a/src/lib/ector/software/sw_ft_raster.c b/src/lib/ector/software/sw_ft_raster.c new file mode 100644 index 0000000000..2956123b10 --- /dev/null +++ b/src/lib/ector/software/sw_ft_raster.c @@ -0,0 +1,1846 @@ +/***************************************************************************/ +/* */ +/* ftgrays.c */ +/* */ +/* A new `perfect' anti-aliasing renderer (body). */ +/* */ +/* Copyright 2000-2003, 2005-2014 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* This is a new anti-aliasing scan-converter for FreeType 2. The */ + /* algorithm used here is _very_ different from the one in the standard */ + /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ + /* coverage of the outline on each pixel cell. */ + /* */ + /* It is based on ideas that I initially found in Raph Levien's */ + /* excellent LibArt graphics library (see http://www.levien.com/libart */ + /* for more information, though the web pages do not tell anything */ + /* about the renderer; you'll have to dive into the source code to */ + /* understand how it works). */ + /* */ + /* Note, however, that this is a _very_ different implementation */ + /* compared to Raph's. Coverage information is stored in a very */ + /* different way, and I don't use sorted vector paths. Also, it doesn't */ + /* use floating point values. */ + /* */ + /* This renderer has the following advantages: */ + /* */ + /* - It doesn't need an intermediate bitmap. Instead, one can supply a */ + /* callback function that will be called by the renderer to draw gray */ + /* spans on any target surface. You can thus do direct composition on */ + /* any kind of bitmap, provided that you give the renderer the right */ + /* callback. */ + /* */ + /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ + /* each pixel cell. */ + /* */ + /* - It performs a single pass on the outline (the `standard' FT2 */ + /* renderer makes two passes). */ + /* */ + /* - It can easily be modified to render to _any_ number of gray levels */ + /* cheaply. */ + /* */ + /* - For small (< 20) pixel sizes, it is faster than the standard */ + /* renderer. */ + /* */ + /*************************************************************************/ + + +#include "sw_ft_raster.h" +#include "sw_ft_math.h" + + /* Auxiliary macros for token concatenation. */ +#define SW_FT_ERR_XCAT( x, y ) x ## y +#define SW_FT_ERR_CAT( x, y ) SW_FT_ERR_XCAT( x, y ) + +#define SW_FT_BEGIN_STMNT do { +#define SW_FT_END_STMNT } while ( 0 ) + + +#include +#include +#include +#include +#define SW_FT_UINT_MAX UINT_MAX +#define SW_FT_INT_MAX INT_MAX + +#define ft_memset memset + +#define ft_setjmp setjmp +#define ft_longjmp longjmp +#define ft_jmp_buf jmp_buf + +typedef ptrdiff_t SW_FT_PtrDist; + + +#define ErrRaster_Invalid_Mode -2 +#define ErrRaster_Invalid_Outline -1 +#define ErrRaster_Invalid_Argument -3 +#define ErrRaster_Memory_Overflow -4 + +#define SW_FT_BEGIN_HEADER +#define SW_FT_END_HEADER + + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define SW_FT_UNUSED( x ) (x) = (x) + + +#define SW_FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ +#define SW_FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ +#define SW_FT_ERROR( x ) do { } while ( 0 ) /* nothing */ +#define SW_FT_THROW( e ) SW_FT_ERR_CAT( ErrRaster_, e ) + + + +typedef int +(*SW_FT_Outline_MoveToFunc)( const SW_FT_Vector* to, + void* user ); + +#define SW_FT_Outline_MoveTo_Func SW_FT_Outline_MoveToFunc + +typedef int +(*SW_FT_Outline_LineToFunc)( const SW_FT_Vector* to, + void* user ); + +#define SW_FT_Outline_LineTo_Func SW_FT_Outline_LineToFunc + + +typedef int +(*SW_FT_Outline_ConicToFunc)( const SW_FT_Vector* control, + const SW_FT_Vector* to, + void* user ); + +#define SW_FT_Outline_ConicTo_Func SW_FT_Outline_ConicToFunc + +typedef int +(*SW_FT_Outline_CubicToFunc)( const SW_FT_Vector* control1, + const SW_FT_Vector* control2, + const SW_FT_Vector* to, + void* user ); + +#define SW_FT_Outline_CubicTo_Func SW_FT_Outline_CubicToFunc + +typedef struct SW_FT_Outline_Funcs_ +{ + SW_FT_Outline_MoveToFunc move_to; + SW_FT_Outline_LineToFunc line_to; + SW_FT_Outline_ConicToFunc conic_to; + SW_FT_Outline_CubicToFunc cubic_to; + + int shift; + SW_FT_Pos delta; + +} SW_FT_Outline_Funcs; + + + +#define SW_FT_DEFINE_OUTLINE_FUNCS( class_, \ + move_to_, line_to_, \ + conic_to_, cubic_to_, \ + shift_, delta_ ) \ + static const SW_FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; + +#define SW_FT_DEFINE_RASTER_FUNCS( class_, \ + raster_new_, raster_reset_, \ + raster_render_, \ + raster_done_ ) \ + const SW_FT_Raster_Funcs class_ = \ + { \ + raster_new_, \ + raster_reset_, \ + raster_render_, \ + raster_done_ \ + }; + + +#ifndef SW_FT_MEM_SET +#define SW_FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef SW_FT_MEM_ZERO +#define SW_FT_MEM_ZERO( dest, count ) SW_FT_MEM_SET( dest, 0, count ) +#endif + + /* as usual, for the speed hungry :-) */ + +#undef RAS_ARG +#undef RAS_ARG_ +#undef RAS_VAR +#undef RAS_VAR_ + +#ifndef SW_FT_STATIC_RASTER + +#define RAS_ARG gray_PWorker worker +#define RAS_ARG_ gray_PWorker worker, + +#define RAS_VAR worker +#define RAS_VAR_ worker, + +#else /* SW_FT_STATIC_RASTER */ + +#define RAS_ARG /* empty */ +#define RAS_ARG_ /* empty */ +#define RAS_VAR /* empty */ +#define RAS_VAR_ /* empty */ + +#endif /* SW_FT_STATIC_RASTER */ + + + /* must be at least 6 bits! */ +#define PIXEL_BITS 5 + +#undef FLOOR +#undef CEILING +#undef TRUNC +#undef SCALED + +#define ONE_PIXEL ( 1L << PIXEL_BITS ) +#define PIXEL_MASK ( -1L << PIXEL_BITS ) +#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) +#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) +#define FLOOR( x ) ( (x) & -ONE_PIXEL ) +#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) +#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) +#endif + + + /* Compute `dividend / divisor' and return both its quotient and */ + /* remainder, cast to a specific type. This macro also ensures that */ + /* the remainder is always positive. */ +#define SW_FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + SW_FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) % (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + SW_FT_END_STMNT + +#ifdef __arm__ + /* Work around a bug specific to GCC which make the compiler fail to */ + /* optimize a division and modulo operation on the same parameters */ + /* into a single call to `__aeabi_idivmod'. See */ + /* */ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ +#undef SW_FT_DIV_MOD +#define SW_FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + SW_FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + SW_FT_END_STMNT +#endif /* __arm__ */ + + + /*************************************************************************/ + /* */ + /* TYPE DEFINITIONS */ + /* */ + + /* don't change the following types to SW_FT_Int or SW_FT_Pos, since we might */ + /* need to define them to "float" or "double" when experimenting with */ + /* new algorithms */ + + typedef long TCoord; /* integer scanline/pixel coordinate */ + typedef long TPos; /* sub-pixel coordinate */ + + /* determine the type used to store cell areas. This normally takes at */ + /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ + /* `long' instead of `int', otherwise bad things happen */ + +#if PIXEL_BITS <= 7 + + typedef int TArea; + +#else /* PIXEL_BITS >= 8 */ + + /* approximately determine the size of integers using an ANSI-C header */ +#if SW_FT_UINT_MAX == 0xFFFFU + typedef long TArea; +#else + typedef int TArea; +#endif + +#endif /* PIXEL_BITS >= 8 */ + + + /* maximum number of gray spans in a call to the span callback */ +#define SW_FT_MAX_GRAY_SPANS 256 + + + typedef struct TCell_* PCell; + + typedef struct TCell_ + { + TPos x; /* same with gray_TWorker.ex */ + TCoord cover; /* same with gray_TWorker.cover */ + TArea area; + PCell next; + + } TCell; + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `structure was padded due to */ + /* __declspec(align())' in order to compile cleanly with */ + /* the maximum level of warnings. */ +#pragma warning( push ) +#pragma warning( disable : 4324 ) +#endif /* _MSC_VER */ + + typedef struct gray_TWorker_ + { + TCoord ex, ey; + TPos min_ex, max_ex; + TPos min_ey, max_ey; + TPos count_ex, count_ey; + + TArea area; + TCoord cover; + int invalid; + + PCell cells; + SW_FT_PtrDist max_cells; + SW_FT_PtrDist num_cells; + + TCoord cx, cy; + TPos x, y; + + TPos last_ey; + + SW_FT_Vector bez_stack[32 * 3 + 1]; + int lev_stack[32]; + + SW_FT_Outline outline; + SW_FT_BBox clip_box; + + SW_FT_Span gray_spans[SW_FT_MAX_GRAY_SPANS]; + int num_gray_spans; + + SW_FT_Raster_Span_Func render_span; + void* render_span_data; + int span_y; + + int band_size; + int band_shoot; + + ft_jmp_buf jump_buffer; + + void* buffer; + long buffer_size; + + PCell* ycells; + TPos ycount; + + } gray_TWorker, *gray_PWorker; + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + + +#ifndef SW_FT_STATIC_RASTER +#define ras (*worker) +#else + static gray_TWorker ras; +#endif + + + typedef struct gray_TRaster_ + { + void* buffer; + long buffer_size; + int band_size; + void* memory; + gray_PWorker worker; + + } gray_TRaster, *gray_PRaster; + + + + /*************************************************************************/ + /* */ + /* Initialize the cells table. */ + /* */ + static void + gray_init_cells( RAS_ARG_ void* buffer, + long byte_size ) + { + ras.buffer = buffer; + ras.buffer_size = byte_size; + + ras.ycells = (PCell*) buffer; + ras.cells = NULL; + ras.max_cells = 0; + ras.num_cells = 0; + ras.area = 0; + ras.cover = 0; + ras.invalid = 1; + } + + + /*************************************************************************/ + /* */ + /* Compute the outline bounding box. */ + /* */ + static void + gray_compute_cbox( RAS_ARG ) + { + SW_FT_Outline* outline = &ras.outline; + SW_FT_Vector* vec = outline->points; + SW_FT_Vector* limit = vec + outline->n_points; + + + if ( outline->n_points <= 0 ) + { + ras.min_ex = ras.max_ex = 0; + ras.min_ey = ras.max_ey = 0; + return; + } + + ras.min_ex = ras.max_ex = vec->x; + ras.min_ey = ras.max_ey = vec->y; + + vec++; + + for ( ; vec < limit; vec++ ) + { + TPos x = vec->x; + TPos y = vec->y; + + + if ( x < ras.min_ex ) ras.min_ex = x; + if ( x > ras.max_ex ) ras.max_ex = x; + if ( y < ras.min_ey ) ras.min_ey = y; + if ( y > ras.max_ey ) ras.max_ey = y; + } + + /* truncate the bounding box to integer pixels */ + ras.min_ex = ras.min_ex >> 6; + ras.min_ey = ras.min_ey >> 6; + ras.max_ex = ( ras.max_ex + 63 ) >> 6; + ras.max_ey = ( ras.max_ey + 63 ) >> 6; + } + + + /*************************************************************************/ + /* */ + /* Record the current cell in the table. */ + /* */ + static PCell + gray_find_cell( RAS_ARG ) + { + PCell *pcell, cell; + TPos x = ras.ex; + + + if ( x > ras.count_ex ) + x = ras.count_ex; + + pcell = &ras.ycells[ras.ey]; + for (;;) + { + cell = *pcell; + if ( cell == NULL || cell->x > x ) + break; + + if ( cell->x == x ) + goto Exit; + + pcell = &cell->next; + } + + if ( ras.num_cells >= ras.max_cells ) + ft_longjmp( ras.jump_buffer, 1 ); + + cell = ras.cells + ras.num_cells++; + cell->x = x; + cell->area = 0; + cell->cover = 0; + + cell->next = *pcell; + *pcell = cell; + + Exit: + return cell; + } + + + static void + gray_record_cell( RAS_ARG ) + { + if ( ras.area | ras.cover ) + { + PCell cell = gray_find_cell( RAS_VAR ); + + + cell->area += ras.area; + cell->cover += ras.cover; + } + } + + + /*************************************************************************/ + /* */ + /* Set the current cell to a new position. */ + /* */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + /* Move the cell pointer to a new position. We set the `invalid' */ + /* flag to indicate that the cell isn't part of those we're interested */ + /* in during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + /* All cells that are on the left of the clipping region go to the */ + /* min_ex - 1 horizontal position. */ + ey -= ras.min_ey; + + if ( ex > ras.max_ex ) + ex = ras.max_ex; + + ex -= ras.min_ex; + if ( ex < 0 ) + ex = -1; + + /* are we moving to a different cell ? */ + if ( ex != ras.ex || ey != ras.ey ) + { + /* record the current one if it is valid */ + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + + ras.area = 0; + ras.cover = 0; + ras.ex = ex; + ras.ey = ey; + } + + ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || + ex >= ras.count_ex ); + } + + + /*************************************************************************/ + /* */ + /* Start a new contour at a given cell. */ + /* */ + static void + gray_start_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + if ( ex > ras.max_ex ) + ex = (TCoord)( ras.max_ex ); + + if ( ex < ras.min_ex ) + ex = (TCoord)( ras.min_ex - 1 ); + + ras.area = 0; + ras.cover = 0; + ras.ex = ex - ras.min_ex; + ras.ey = ey - ras.min_ey; + ras.last_ey = SUBPIXELS( ey ); + ras.invalid = 0; + + gray_set_cell( RAS_VAR_ ex, ey ); + } + + + /*************************************************************************/ + /* */ + /* Render a scanline as one or more cells. */ + /* */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, delta, mod; + long p, first, dx; + int incr; + + + dx = x2 - x1; + + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); + fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + { + delta = y2 - y1; + ras.area += (TArea)(( fx1 + fx2 ) * delta); + ras.cover += delta; + return; + } + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); + first = ONE_PIXEL; + incr = 1; + + if ( dx < 0 ) + { + p = fx1 * ( y2 - y1 ); + first = 0; + incr = -1; + dx = -dx; + } + + SW_FT_DIV_MOD( TCoord, p, dx, delta, mod ); + + ras.area += (TArea)(( fx1 + first ) * delta); + ras.cover += delta; + + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + y1 += delta; + + if ( ex1 != ex2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * ( y2 - y1 + delta ); + SW_FT_DIV_MOD( TCoord, p, dx, lift, rem ); + + mod -= (int)dx; + + while ( ex1 != ex2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (TCoord)dx; + delta++; + } + + ras.area += (TArea)(ONE_PIXEL * delta); + ras.cover += delta; + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } + } + + delta = y2 - y1; + ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta); + ras.cover += delta; + } + + + /*************************************************************************/ + /* */ + /* Render a given line as a series of scanlines. */ + /* */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2, mod; + TPos dx, dy, x, x2; + long p, first; + int delta, rem, lift, incr; + + + ey1 = TRUNC( ras.last_ey ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + fy1 = (TCoord)( ras.y - ras.last_ey ); + fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* perform vertical clipping */ + { + TCoord min, max; + + + min = ey1; + max = ey2; + if ( ey1 > ey2 ) + { + min = ey2; + max = ey1; + } + if ( min >= ras.max_ey || max < ras.min_ey ) + goto End; + } + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } + + /* vertical line - avoid calling gray_render_scanline */ + incr = 1; + + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); + TArea area; + + + first = ONE_PIXEL; + if ( dy < 0 ) + { + first = 0; + incr = -1; + } + + delta = (int)( first - fy1 ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + + delta = (int)( first + first - ONE_PIXEL ); + area = (TArea)two_fx * delta; + while ( ey1 != ey2 ) + { + ras.area += area; + ras.cover += delta; + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + } + + delta = (int)( fy2 - ONE_PIXEL + first ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + + goto End; + } + + /* ok, we have to render several scanlines */ + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + + if ( dy < 0 ) + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + SW_FT_DIV_MOD( int, p, dy, delta, mod ); + + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + + if ( ey1 != ey2 ) + { + p = ONE_PIXEL * dx; + SW_FT_DIV_MOD( int, p, dy, lift, rem ); + mod -= (int)dy; + + while ( ey1 != ey2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (int)dy; + delta++; + } + + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), x2, + (TCoord)first ); + x = x2; + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } + } + + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), to_x, + fy2 ); + + End: + ras.x = to_x; + ras.y = to_y; + ras.last_ey = SUBPIXELS( ey2 ); + } + + + static void + gray_split_conic( SW_FT_Vector* base ) + { + TPos a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + + + static void + gray_render_conic( RAS_ARG_ const SW_FT_Vector* control, + const SW_FT_Vector* to ) + { + TPos dx, dy; + TPos min, max, y; + int top, level; + int* levels; + SW_FT_Vector* arc; + + + levels = ras.lev_stack; + + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + top = 0; + + dx = SW_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); + dy = SW_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); + if ( dx < dy ) + dx = dy; + + if ( dx < ONE_PIXEL / 4 ) + goto Draw; + + /* short-cut the arc that crosses the current band */ + min = max = arc[0].y; + + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) + goto Draw; + + level = 0; + do + { + dx >>= 2; + level++; + } while ( dx > ONE_PIXEL / 4 ); + + levels[0] = level; + + do + { + level = levels[top]; + if ( level > 0 ) + { + gray_split_conic( arc ); + arc += 2; + top++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + + Draw: + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + top--; + arc -= 2; + + } while ( top >= 0 ); + } + + + static void + gray_split_cubic( SW_FT_Vector* base ) + { + TPos a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + + + static void + gray_render_cubic( RAS_ARG_ const SW_FT_Vector* control1, + const SW_FT_Vector* control2, + const SW_FT_Vector* to ) + { + SW_FT_Vector* arc; + TPos min, max, y; + + + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; + + /* Short-cut the arc that crosses the current band. */ + min = max = arc[0].y; + + y = arc[1].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + + y = arc[2].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + + y = arc[3].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) + goto Draw; + + for (;;) + { + /* Decide whether to split or draw. See `Rapid Termination */ + /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ + /* F. Hain, at */ + /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ + + { + TPos dx, dy, dx_, dy_; + TPos dx1, dy1, dx2, dy2; + TPos L, s, s_limit; + + + /* dx and dy are x and y components of the P0-P3 chord vector. */ + dx = dx_ = arc[3].x - arc[0].x; + dy = dy_ = arc[3].y - arc[0].y; + + L = SW_FT_HYPOT( dx_, dy_ ); + + /* Avoid possible arithmetic overflow below by splitting. */ + if ( L > 32767 ) + goto Split; + + /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ + s_limit = L * (TPos)( ONE_PIXEL / 6 ); + + /* s is L * the perpendicular distance from P1 to the line P0-P3. */ + dx1 = arc[1].x - arc[0].x; + dy1 = arc[1].y - arc[0].y; + s = SW_FT_ABS( dy * dx1 - dx * dy1 ); + + if ( s > s_limit ) + goto Split; + + /* s is L * the perpendicular distance from P2 to the line P0-P3. */ + dx2 = arc[2].x - arc[0].x; + dy2 = arc[2].y - arc[0].y; + s = SW_FT_ABS( dy * dx2 - dx * dy2 ); + + if ( s > s_limit ) + goto Split; + + /* Split super curvy segments where the off points are so far + from the chord that the angles P0-P1-P3 or P0-P2-P3 become + acute as detected by appropriate dot products. */ + if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 || + dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 ) + goto Split; + + /* No reason to split. */ + goto Draw; + } + + Split: + gray_split_cubic( arc ); + arc += 3; + continue; + + Draw: + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + + if ( arc == ras.bez_stack ) + return; + + arc -= 3; + } + } + + + static int + gray_move_to( const SW_FT_Vector* to, + gray_PWorker worker ) + { + TPos x, y; + + + /* record current cell, if any */ + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + + gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); + + worker->x = x; + worker->y = y; + return 0; + } + + + static int + gray_line_to( const SW_FT_Vector* to, + gray_PWorker worker ) + { + gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); + return 0; + } + + + static int + gray_conic_to( const SW_FT_Vector* control, + const SW_FT_Vector* to, + gray_PWorker worker ) + { + gray_render_conic( RAS_VAR_ control, to ); + return 0; + } + + + static int + gray_cubic_to( const SW_FT_Vector* control1, + const SW_FT_Vector* control2, + const SW_FT_Vector* to, + gray_PWorker worker ) + { + gray_render_cubic( RAS_VAR_ control1, control2, to ); + return 0; + } + + + static void + gray_hline( RAS_ARG_ TCoord x, + TCoord y, + TPos area, + TCoord acount ) + { + int coverage; + + + /* compute the coverage line's coverage, depending on the */ + /* outline fill rule */ + /* */ + /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ + /* */ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); + /* use range 0..256 */ + if ( coverage < 0 ) + coverage = -coverage; + + if ( ras.outline.flags & SW_FT_OUTLINE_EVEN_ODD_FILL ) + { + coverage &= 511; + + if ( coverage > 256 ) + coverage = 512 - coverage; + else if ( coverage == 256 ) + coverage = 255; + } + else + { + /* normal non-zero winding rule */ + if ( coverage >= 256 ) + coverage = 255; + } + + y += (TCoord)ras.min_ey; + x += (TCoord)ras.min_ex; + + /* SW_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ + if ( x >= 32767 ) + x = 32767; + + /* SW_FT_Span.y is an integer, so limit our coordinates appropriately */ + if ( y >= SW_FT_INT_MAX ) + y = SW_FT_INT_MAX; + + if ( coverage ) + { + SW_FT_Span* span; + int count; + + + /* see whether we can add this span to the current list */ + count = ras.num_gray_spans; + span = ras.gray_spans + count - 1; + if ( count > 0 && + ras.span_y == y && + (int)span->x + span->len == (int)x && + span->coverage == coverage ) + { + span->len = (unsigned short)( span->len + acount ); + return; + } + + if ( count >= SW_FT_MAX_GRAY_SPANS ) + { + if ( ras.render_span && count > 0 ) + ras.render_span(count, ras.gray_spans, + ras.render_span_data ); + + #ifdef DEBUG_GRAYS + + if ( 1 ) + { + int n; + + + fprintf( stderr, "count = %3d ", count ); + span = ras.gray_spans; + for ( n = 0; n < count; n++, span++ ) + fprintf( stderr, "[%d , %d..%d] : %d ", + span->y, span->x, span->x + span->len - 1, span->coverage ); + fprintf( stderr, "\n" ); + } + + #endif /* DEBUG_GRAYS */ + + ras.num_gray_spans = 0; + //ras.span_y = (int)y; + + span = ras.gray_spans; + } + else + span++; + + /* add a gray span to the current list */ + span->x = (short)x; + span->y = (short)y; + span->len = (unsigned short)acount; + span->coverage = (unsigned char)coverage; + + ras.num_gray_spans++; + } + } + + static void + gray_sweep( RAS_ARG) + { + int yindex; + + if ( ras.num_cells == 0 ) + return; + + ras.num_gray_spans = 0; + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + { + PCell cell = ras.ycells[yindex]; + TCoord cover = 0; + TCoord x = 0; + + + for ( ; cell != NULL; cell = cell->next ) + { + TPos area; + + + if ( cell->x > x && cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + cell->x - x ); + + cover += cell->cover; + area = cover * ( ONE_PIXEL * 2 ) - cell->area; + + if ( area != 0 && cell->x >= 0 ) + gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); + + x = cell->x + 1; + } + + if ( cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + ras.count_ex - x ); + } + + if ( ras.render_span && ras.num_gray_spans > 0 ) + ras.render_span(ras.num_gray_spans, + ras.gray_spans, ras.render_span_data ); + } + + + /*************************************************************************/ + /* */ + /* The following function should only compile in stand-alone mode, */ + /* i.e., when building this component without the rest of FreeType. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Outline_Decompose */ + /* */ + /* */ + /* Walk over an outline's structure to decompose it into individual */ + /* segments and Bézier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* */ + /* outline :: A pointer to the source target. */ + /* */ + /* func_interface :: A table of `emitters', i.e., function pointers */ + /* called during decomposition to indicate path */ + /* operations. */ + /* */ + /* */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + static int + SW_FT_Outline_Decompose( const SW_FT_Outline* outline, + const SW_FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + + SW_FT_Vector v_last; + SW_FT_Vector v_control; + SW_FT_Vector v_start; + + SW_FT_Vector* point; + SW_FT_Vector* limit; + char* tags; + + int error; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + char tag; /* current point's state */ + + int shift; + TPos delta; + + + if ( !outline || !func_interface ) + return SW_FT_THROW( Invalid_Argument ); + + shift = func_interface->shift; + delta = func_interface->delta; + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + int last; /* index of last point in contour */ + + + SW_FT_TRACE5(( "SW_FT_Outline_Decompose: Outline %d\n", n )); + + last = outline->contours[n]; + if ( last < 0 ) + goto Invalid_Outline; + limit = outline->points + last; + + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = SW_FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == SW_FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == SW_FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( SW_FT_CURVE_TAG( outline->tags[last] ) == SW_FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + SW_FT_TRACE5(( " move to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = SW_FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ + { + SW_FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + SW_FT_TRACE5(( " line to (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + SW_FT_Vector vec; + SW_FT_Vector v_middle; + + + point++; + tags++; + tag = SW_FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == SW_FT_CURVE_TAG_ON ) + { + SW_FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != SW_FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + SW_FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_middle.x / 64.0, v_middle.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + SW_FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* SW_FT_CURVE_TAG_CUBIC */ + { + SW_FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + SW_FT_CURVE_TAG( tags[1] ) != SW_FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + SW_FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + SW_FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + SW_FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + SW_FT_TRACE5(( " line to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + + first = last + 1; + } + + SW_FT_TRACE5(( "SW_FT_Outline_Decompose: Done\n", n )); + return 0; + + Exit: + SW_FT_TRACE5(( "SW_FT_Outline_Decompose: Error %d\n", error )); + return error; + + Invalid_Outline: + return SW_FT_THROW( Invalid_Outline ); + } + + + typedef struct gray_TBand_ + { + TPos min, max; + + } gray_TBand; + + + + SW_FT_DEFINE_OUTLINE_FUNCS(func_interface, + (SW_FT_Outline_MoveTo_Func) gray_move_to, + (SW_FT_Outline_LineTo_Func) gray_line_to, + (SW_FT_Outline_ConicTo_Func)gray_conic_to, + (SW_FT_Outline_CubicTo_Func)gray_cubic_to, + 0, + 0 + ) + + static int + gray_convert_glyph_inner( RAS_ARG ) + { + + volatile int error = 0; + + if ( ft_setjmp( ras.jump_buffer ) == 0 ) + { + error = SW_FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + } + else + error = SW_FT_THROW( Memory_Overflow ); + + return error; + } + + + static int + gray_convert_glyph( RAS_ARG ) + { + gray_TBand bands[40]; + gray_TBand* volatile band; + int volatile n, num_bands; + TPos volatile min, max, max_y; + SW_FT_BBox* clip; + + + /* Set up state in the raster object */ + gray_compute_cbox( RAS_VAR ); + + /* clip to target bitmap, exit if nothing to do */ + clip = &ras.clip_box; + + if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || + ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) + return 0; + + if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; + if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; + + if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; + if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; + + ras.count_ex = ras.max_ex - ras.min_ex; + ras.count_ey = ras.max_ey - ras.min_ey; + + /* set up vertical bands */ + num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); + if ( num_bands == 0 ) + num_bands = 1; + if ( num_bands >= 39 ) + num_bands = 39; + + ras.band_shoot = 0; + + min = ras.min_ey; + max_y = ras.max_ey; + + for ( n = 0; n < num_bands; n++, min = max ) + { + max = min + ras.band_size; + if ( n == num_bands - 1 || max > max_y ) + max = max_y; + + bands[0].min = min; + bands[0].max = max; + band = bands; + + while ( band >= bands ) + { + TPos bottom, top, middle; + int error; + + { + PCell cells_max; + int yindex; + long cell_start, cell_end, cell_mod; + + + ras.ycells = (PCell*)ras.buffer; + ras.ycount = band->max - band->min; + + cell_start = sizeof ( PCell ) * ras.ycount; + cell_mod = cell_start % sizeof ( TCell ); + if ( cell_mod > 0 ) + cell_start += sizeof ( TCell ) - cell_mod; + + cell_end = ras.buffer_size; + cell_end -= cell_end % sizeof ( TCell ); + + cells_max = (PCell)( (char*)ras.buffer + cell_end ); + ras.cells = (PCell)( (char*)ras.buffer + cell_start ); + if ( ras.cells >= cells_max ) + goto ReduceBands; + + ras.max_cells = cells_max - ras.cells; + if ( ras.max_cells < 2 ) + goto ReduceBands; + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + ras.ycells[yindex] = NULL; + } + + ras.num_cells = 0; + ras.invalid = 1; + ras.min_ey = band->min; + ras.max_ey = band->max; + ras.count_ey = band->max - band->min; + + error = gray_convert_glyph_inner( RAS_VAR ); + + if ( !error ) + { + gray_sweep( RAS_VAR); + band--; + continue; + } + else if ( error != ErrRaster_Memory_Overflow ) + return 1; + + ReduceBands: + /* render pool overflow; we will reduce the render band by half */ + bottom = band->min; + top = band->max; + middle = bottom + ( ( top - bottom ) >> 1 ); + + /* This is too complex for a single scanline; there must */ + /* be some problems. */ + if ( middle == bottom ) + { +#ifdef SW_FT_DEBUG_LEVEL_TRACE + SW_FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); +#endif + return 1; + } + + if ( bottom-top >= ras.band_size ) + ras.band_shoot++; + + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + band++; + } + } + + if ( ras.band_shoot > 8 && ras.band_size > 16 ) + ras.band_size = ras.band_size / 2; + + return 0; + } + + + static int + gray_raster_render( gray_PRaster raster, + const SW_FT_Raster_Params* params ) + { + const SW_FT_Outline* outline = (const SW_FT_Outline*)params->source; + gray_PWorker worker; + + + if ( !raster || !raster->buffer || !raster->buffer_size ) + return SW_FT_THROW( Invalid_Argument ); + + if ( !outline ) + return SW_FT_THROW( Invalid_Outline ); + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return 0; + + if ( !outline->contours || !outline->points ) + return SW_FT_THROW( Invalid_Outline ); + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return SW_FT_THROW( Invalid_Outline ); + + worker = raster->worker; + + /* this version does not support monochrome rendering */ + if ( !( params->flags & SW_FT_RASTER_FLAG_AA ) ) + return SW_FT_THROW( Invalid_Mode ); + + if ( params->flags & SW_FT_RASTER_FLAG_CLIP ) + ras.clip_box = params->clip_box; + else + { + ras.clip_box.xMin = -32768L; + ras.clip_box.yMin = -32768L; + ras.clip_box.xMax = 32767L; + ras.clip_box.yMax = 32767L; + } + + gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size ); + + ras.outline = *outline; + ras.num_cells = 0; + ras.invalid = 1; + ras.band_size = raster->band_size; + ras.num_gray_spans = 0; + + ras.render_span = (SW_FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + + return gray_convert_glyph( RAS_VAR ); + } + + + /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ + /**** a static object. *****/ + + static int + gray_raster_new(SW_FT_Raster* araster ) + { + static gray_TRaster the_raster; + + *araster = (SW_FT_Raster)&the_raster; + SW_FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); + + return 0; + } + + + static void + gray_raster_done( SW_FT_Raster raster ) + { + /* nothing */ + SW_FT_UNUSED( raster ); + } + + static void + gray_raster_reset( SW_FT_Raster raster, + char* pool_base, + long pool_size ) + { + gray_PRaster rast = (gray_PRaster)raster; + + + if ( raster ) + { + if ( pool_base && pool_size >= (long)sizeof ( gray_TWorker ) + 2048 ) + { + gray_PWorker worker = (gray_PWorker)pool_base; + + + rast->worker = worker; + rast->buffer = pool_base + + ( ( sizeof ( gray_TWorker ) + + sizeof ( TCell ) - 1 ) & + ~( sizeof ( TCell ) - 1 ) ); + rast->buffer_size = (long)( ( pool_base + pool_size ) - + (char*)rast->buffer ) & + ~( sizeof ( TCell ) - 1 ); + rast->band_size = (int)( rast->buffer_size / + ( sizeof ( TCell ) * 8 ) ); + } + else + { + rast->buffer = NULL; + rast->buffer_size = 0; + rast->worker = NULL; + } + } + } + + + SW_FT_DEFINE_RASTER_FUNCS(sw_ft_grays_raster, + + (SW_FT_Raster_New_Func) gray_raster_new, + (SW_FT_Raster_Reset_Func) gray_raster_reset, + (SW_FT_Raster_Render_Func) gray_raster_render, + (SW_FT_Raster_Done_Func) gray_raster_done + ) + + +/* END */ diff --git a/src/lib/ector/software/sw_ft_raster.h b/src/lib/ector/software/sw_ft_raster.h new file mode 100755 index 0000000000..cb323d030c --- /dev/null +++ b/src/lib/ector/software/sw_ft_raster.h @@ -0,0 +1,607 @@ +#ifndef SW_FT_IMG_H +#define SW_FT_IMG_H +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2010, 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Note: A `raster' is simply a scan-line converter, used to render */ + /* SW_FT_Outlines into SW_FT_Bitmaps. */ + /* */ + /*************************************************************************/ + +#include "sw_ft_types.h" + + /*************************************************************************/ + /* */ + /* */ + /* FT_BBox */ + /* */ + /* */ + /* A structure used to hold an outline's bounding box, i.e., the */ + /* coordinates of its extrema in the horizontal and vertical */ + /* directions. */ + /* */ + /* */ + /* xMin :: The horizontal minimum (left-most). */ + /* */ + /* yMin :: The vertical minimum (bottom-most). */ + /* */ + /* xMax :: The horizontal maximum (right-most). */ + /* */ + /* yMax :: The vertical maximum (top-most). */ + /* */ + /* */ + /* The bounding box is specified with the coordinates of the lower */ + /* left and the upper right corner. In PostScript, those values are */ + /* often called (llx,lly) and (urx,ury), respectively. */ + /* */ + /* If `yMin' is negative, this value gives the glyph's descender. */ + /* Otherwise, the glyph doesn't descend below the baseline. */ + /* Similarly, if `ymax' is positive, this value gives the glyph's */ + /* ascender. */ + /* */ + /* `xMin' gives the horizontal distance from the glyph's origin to */ + /* the left edge of the glyph's bounding box. If `xMin' is negative, */ + /* the glyph extends to the left of the origin. */ + /* */ + typedef struct SW_FT_BBox_ + { + SW_FT_Pos xMin, yMin; + SW_FT_Pos xMax, yMax; + + } SW_FT_BBox; + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Outline */ +/* */ +/* */ +/* This structure is used to describe an outline to the scan-line */ +/* converter. */ +/* */ +/* */ +/* n_contours :: The number of contours in the outline. */ +/* */ +/* n_points :: The number of points in the outline. */ +/* */ +/* points :: A pointer to an array of `n_points' @SW_FT_Vector */ +/* elements, giving the outline's point coordinates. */ +/* */ +/* tags :: A pointer to an array of `n_points' chars, giving */ +/* each outline point's type. */ +/* */ +/* If bit~0 is unset, the point is `off' the curve, */ +/* i.e., a Bézier control point, while it is `on' if */ +/* set. */ +/* */ +/* Bit~1 is meaningful for `off' points only. If set, */ +/* it indicates a third-order Bézier arc control point; */ +/* and a second-order control point if unset. */ +/* */ +/* If bit~2 is set, bits 5-7 contain the drop-out mode */ +/* (as defined in the OpenType specification; the value */ +/* is the same as the argument to the SCANMODE */ +/* instruction). */ +/* */ +/* Bits 3 and~4 are reserved for internal purposes. */ +/* */ +/* contours :: An array of `n_contours' shorts, giving the end */ +/* point of each contour within the outline. For */ +/* example, the first contour is defined by the points */ +/* `0' to `contours[0]', the second one is defined by */ +/* the points `contours[0]+1' to `contours[1]', etc. */ +/* */ +/* flags :: A set of bit flags used to characterize the outline */ +/* and give hints to the scan-converter and hinter on */ +/* how to convert/grid-fit it. See @SW_FT_OUTLINE_FLAGS.*/ +/* */ +typedef struct SW_FT_Outline_ +{ + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + SW_FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + +} SW_FT_Outline; + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_OUTLINE_FLAGS */ + /* */ + /* */ + /* A list of bit-field constants use for the flags in an outline's */ + /* `flags' field. */ + /* */ + /* */ + /* SW_FT_OUTLINE_NONE :: */ + /* Value~0 is reserved. */ + /* */ + /* SW_FT_OUTLINE_OWNER :: */ + /* If set, this flag indicates that the outline's field arrays */ + /* (i.e., `points', `flags', and `contours') are `owned' by the */ + /* outline object, and should thus be freed when it is destroyed. */ + /* */ + /* SW_FT_OUTLINE_EVEN_ODD_FILL :: */ + /* By default, outlines are filled using the non-zero winding rule. */ + /* If set to 1, the outline will be filled using the even-odd fill */ + /* rule (only works with the smooth rasterizer). */ + /* */ + /* SW_FT_OUTLINE_REVERSE_FILL :: */ + /* By default, outside contours of an outline are oriented in */ + /* clock-wise direction, as defined in the TrueType specification. */ + /* This flag is set if the outline uses the opposite direction */ + /* (typically for Type~1 fonts). This flag is ignored by the scan */ + /* converter. */ + /* */ + /* */ + /* */ + /* There exists a second mechanism to pass the drop-out mode to the */ + /* B/W rasterizer; see the `tags' field in @SW_FT_Outline. */ + /* */ + /* Please refer to the description of the `SCANTYPE' instruction in */ + /* the OpenType specification (in file `ttinst1.doc') how simple */ + /* drop-outs, smart drop-outs, and stubs are defined. */ + /* */ +#define SW_FT_OUTLINE_NONE 0x0 +#define SW_FT_OUTLINE_OWNER 0x1 +#define SW_FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define SW_FT_OUTLINE_REVERSE_FILL 0x4 + + /* */ + +#define SW_FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define SW_FT_CURVE_TAG_ON 1 +#define SW_FT_CURVE_TAG_CONIC 0 +#define SW_FT_CURVE_TAG_CUBIC 2 + + +#define SW_FT_Curve_Tag_On SW_FT_CURVE_TAG_ON +#define SW_FT_Curve_Tag_Conic SW_FT_CURVE_TAG_CONIC +#define SW_FT_Curve_Tag_Cubic SW_FT_CURVE_TAG_CUBIC + + /*************************************************************************/ + /* */ + /* A raster is a scan converter, in charge of rendering an outline into */ + /* a a bitmap. This section contains the public API for rasters. */ + /* */ + /* Note that in FreeType 2, all rasters are now encapsulated within */ + /* specific modules called `renderers'. See `ftrender.h' for more */ + /* details on renderers. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster */ + /* */ + /* */ + /* A handle (pointer) to a raster object. Each object can be used */ + /* independently to convert an outline into a bitmap or pixmap. */ + /* */ + typedef struct SW_FT_RasterRec_* SW_FT_Raster; + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Span */ + /* */ + /* */ + /* A structure used to model a single span of gray (or black) pixels */ + /* when rendering a monochrome or anti-aliased bitmap. */ + /* */ + /* */ + /* x :: The span's horizontal start position. */ + /* */ + /* len :: The span's length in pixels. */ + /* */ + /* coverage :: The span color/coverage, ranging from 0 (background) */ + /* to 255 (foreground). Only used for anti-aliased */ + /* rendering. */ + /* */ + /* */ + /* This structure is used by the span drawing callback type named */ + /* @SW_FT_SpanFunc that takes the y~coordinate of the span as a */ + /* parameter. */ + /* */ + /* The coverage value is always between 0 and 255. If you want less */ + /* gray values, the callback function has to reduce them. */ + /* */ + typedef struct SW_FT_Span_ + { + short x; + short y; + unsigned short len; + unsigned char coverage; + + } SW_FT_Span; + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_SpanFunc */ + /* */ + /* */ + /* A function used as a call-back by the anti-aliased renderer in */ + /* order to let client applications draw themselves the gray pixel */ + /* spans on each scan line. */ + /* */ + /* */ + /* y :: The scanline's y~coordinate. */ + /* */ + /* count :: The number of spans to draw on this scanline. */ + /* */ + /* spans :: A table of `count' spans to draw on the scanline. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* */ + /* This callback allows client applications to directly render the */ + /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ + /* */ + /* This can be used to write anti-aliased outlines directly to a */ + /* given background bitmap, and even perform translucency. */ + /* */ + /* Note that the `count' field cannot be greater than a fixed value */ + /* defined by the `SW_FT_MAX_GRAY_SPANS' configuration macro in */ + /* `ftoption.h'. By default, this value is set to~32, which means */ + /* that if there are more than 32~spans on a given scanline, the */ + /* callback is called several times with the same `y' parameter in */ + /* order to draw all callbacks. */ + /* */ + /* Otherwise, the callback is only called once per scan-line, and */ + /* only for those scanlines that do have `gray' pixels on them. */ + /* */ + typedef void + (*SW_FT_SpanFunc)( int count, + const SW_FT_Span* spans, + void* user ); + +#define SW_FT_Raster_Span_Func SW_FT_SpanFunc + + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_RASTER_FLAG_XXX */ + /* */ + /* */ + /* A list of bit flag constants as used in the `flags' field of a */ + /* @SW_FT_Raster_Params structure. */ + /* */ + /* */ + /* SW_FT_RASTER_FLAG_DEFAULT :: This value is 0. */ + /* */ + /* SW_FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ + /* anti-aliased glyph image should be */ + /* generated. Otherwise, it will be */ + /* monochrome (1-bit). */ + /* */ + /* SW_FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ + /* rendering. In this mode, client */ + /* applications must provide their own span */ + /* callback. This lets them directly */ + /* draw or compose over an existing bitmap. */ + /* If this bit is not set, the target */ + /* pixmap's buffer _must_ be zeroed before */ + /* rendering. */ + /* */ + /* Note that for now, direct rendering is */ + /* only possible with anti-aliased glyphs. */ + /* */ + /* SW_FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ + /* rendering mode. If set, the output will */ + /* be clipped to a box specified in the */ + /* `clip_box' field of the */ + /* @SW_FT_Raster_Params structure. */ + /* */ + /* Note that by default, the glyph bitmap */ + /* is clipped to the target pixmap, except */ + /* in direct rendering mode where all spans */ + /* are generated if no clipping box is set. */ + /* */ +#define SW_FT_RASTER_FLAG_DEFAULT 0x0 +#define SW_FT_RASTER_FLAG_AA 0x1 +#define SW_FT_RASTER_FLAG_DIRECT 0x2 +#define SW_FT_RASTER_FLAG_CLIP 0x4 + + /* deprecated */ +#define ft_raster_flag_default SW_FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa SW_FT_RASTER_FLAG_AA +#define ft_raster_flag_direct SW_FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip SW_FT_RASTER_FLAG_CLIP + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_Params */ + /* */ + /* */ + /* A structure to hold the arguments used by a raster's render */ + /* function. */ + /* */ + /* */ + /* target :: The target bitmap. */ + /* */ + /* source :: A pointer to the source glyph image (e.g., an */ + /* @SW_FT_Outline). */ + /* */ + /* flags :: The rendering flags. */ + /* */ + /* gray_spans :: The gray span drawing callback. */ + /* */ + /* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ + /* */ + /* bit_test :: The bit test callback. UNIMPLEMENTED! */ + /* */ + /* bit_set :: The bit set callback. UNIMPLEMENTED! */ + /* */ + /* user :: User-supplied data that is passed to each drawing */ + /* callback. */ + /* */ + /* clip_box :: An optional clipping box. It is only used in */ + /* direct rendering mode. Note that coordinates here */ + /* should be expressed in _integer_ pixels (and not in */ + /* 26.6 fixed-point units). */ + /* */ + /* */ + /* An anti-aliased glyph bitmap is drawn if the @SW_FT_RASTER_FLAG_AA */ + /* bit flag is set in the `flags' field, otherwise a monochrome */ + /* bitmap is generated. */ + /* */ + /* If the @SW_FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ + /* raster will call the `gray_spans' callback to draw gray pixel */ + /* spans, in the case of an aa glyph bitmap, it will call */ + /* `black_spans', and `bit_test' and `bit_set' in the case of a */ + /* monochrome bitmap. This allows direct composition over a */ + /* pre-existing bitmap through user-provided callbacks to perform the */ + /* span drawing/composition. */ + /* */ + /* Note that the `bit_test' and `bit_set' callbacks are required when */ + /* rendering a monochrome bitmap, as they are crucial to implement */ + /* correct drop-out control as defined in the TrueType specification. */ + /* */ + typedef struct SW_FT_Raster_Params_ + { + const void* source; + int flags; + SW_FT_SpanFunc gray_spans; + void* user; + SW_FT_BBox clip_box; + + } SW_FT_Raster_Params; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Outline_Check */ +/* */ +/* */ +/* Check the contents of an outline descriptor. */ +/* */ +/* */ +/* outline :: A handle to a source outline. */ +/* */ +/* */ +/* FreeType error code. 0~means success. */ +/* */ +SW_FT_Error +SW_FT_Outline_Check( SW_FT_Outline* outline ); + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Outline_Get_CBox */ +/* */ +/* */ +/* Return an outline's `control box'. The control box encloses all */ +/* the outline's points, including Bézier control points. Though it */ +/* coincides with the exact bounding box for most glyphs, it can be */ +/* slightly larger in some situations (like when rotating an outline */ +/* that contains Bézier outside arcs). */ +/* */ +/* Computing the control box is very fast, while getting the bounding */ +/* box can take much more time as it needs to walk over all segments */ +/* and arcs in the outline. To get the latter, you can use the */ +/* `ftbbox' component, which is dedicated to this single task. */ +/* */ +/* */ +/* outline :: A pointer to the source outline descriptor. */ +/* */ +/* */ +/* acbox :: The outline's control box. */ +/* */ +/* */ +/* See @SW_FT_Glyph_Get_CBox for a discussion of tricky fonts. */ +/* */ +void +SW_FT_Outline_Get_CBox( const SW_FT_Outline* outline, + SW_FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_NewFunc */ + /* */ + /* */ + /* A function used to create a new raster object. */ + /* */ + /* */ + /* memory :: A handle to the memory allocator. */ + /* */ + /* */ + /* raster :: A handle to the new raster object. */ + /* */ + /* */ + /* Error code. 0~means success. */ + /* */ + /* */ + /* The `memory' parameter is a typeless pointer in order to avoid */ + /* un-wanted dependencies on the rest of the FreeType code. In */ + /* practice, it is an @SW_FT_Memory object, i.e., a handle to the */ + /* standard FreeType memory allocator. However, this field can be */ + /* completely ignored by a given raster implementation. */ + /* */ + typedef int + (*SW_FT_Raster_NewFunc)( SW_FT_Raster* raster ); + +#define SW_FT_Raster_New_Func SW_FT_Raster_NewFunc + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_DoneFunc */ + /* */ + /* */ + /* A function used to destroy a given raster object. */ + /* */ + /* */ + /* raster :: A handle to the raster object. */ + /* */ + typedef void + (*SW_FT_Raster_DoneFunc)( SW_FT_Raster raster ); + +#define SW_FT_Raster_Done_Func SW_FT_Raster_DoneFunc + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_ResetFunc */ + /* */ + /* */ + /* FreeType provides an area of memory called the `render pool', */ + /* available to all registered rasters. This pool can be freely used */ + /* during a given scan-conversion but is shared by all rasters. Its */ + /* content is thus transient. */ + /* */ + /* This function is called each time the render pool changes, or just */ + /* after a new raster object is created. */ + /* */ + /* */ + /* raster :: A handle to the new raster object. */ + /* */ + /* pool_base :: The address in memory of the render pool. */ + /* */ + /* pool_size :: The size in bytes of the render pool. */ + /* */ + /* */ + /* Rasters can ignore the render pool and rely on dynamic memory */ + /* allocation if they want to (a handle to the memory allocator is */ + /* passed to the raster constructor). However, this is not */ + /* recommended for efficiency purposes. */ + /* */ + typedef void + (*SW_FT_Raster_ResetFunc)( SW_FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define SW_FT_Raster_Reset_Func SW_FT_Raster_ResetFunc + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_RenderFunc */ + /* */ + /* */ + /* Invoke a given raster to scan-convert a given glyph image into a */ + /* target bitmap. */ + /* */ + /* */ + /* raster :: A handle to the raster object. */ + /* */ + /* params :: A pointer to an @SW_FT_Raster_Params structure used to */ + /* store the rendering parameters. */ + /* */ + /* */ + /* Error code. 0~means success. */ + /* */ + /* */ + /* The exact format of the source image depends on the raster's glyph */ + /* format defined in its @SW_FT_Raster_Funcs structure. It can be an */ + /* @SW_FT_Outline or anything else in order to support a large array of */ + /* glyph formats. */ + /* */ + /* Note also that the render function can fail and return a */ + /* `SW_FT_Err_Unimplemented_Feature' error code if the raster used does */ + /* not support direct composition. */ + /* */ + /* XXX: For now, the standard raster doesn't support direct */ + /* composition but this should change for the final release (see */ + /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ + /* for examples of distinct implementations that support direct */ + /* composition). */ + /* */ + typedef int + (*SW_FT_Raster_RenderFunc)( SW_FT_Raster raster, + const SW_FT_Raster_Params* params ); + +#define SW_FT_Raster_Render_Func SW_FT_Raster_RenderFunc + + + /*************************************************************************/ + /* */ + /* */ + /* SW_FT_Raster_Funcs */ + /* */ + /* */ + /* A structure used to describe a given raster class to the library. */ + /* */ + /* */ + /* glyph_format :: The supported glyph format for this raster. */ + /* */ + /* raster_new :: The raster constructor. */ + /* */ + /* raster_reset :: Used to reset the render pool within the raster. */ + /* */ + /* raster_render :: A function to render a glyph into a given bitmap. */ + /* */ + /* raster_done :: The raster destructor. */ + /* */ + typedef struct SW_FT_Raster_Funcs_ + { + SW_FT_Raster_NewFunc raster_new; + SW_FT_Raster_ResetFunc raster_reset; + SW_FT_Raster_RenderFunc raster_render; + SW_FT_Raster_DoneFunc raster_done; + + } SW_FT_Raster_Funcs; + + +extern const SW_FT_Raster_Funcs sw_ft_grays_raster; + +#endif // SW_FT_IMG_H diff --git a/src/lib/ector/software/sw_ft_stroker.c b/src/lib/ector/software/sw_ft_stroker.c new file mode 100755 index 0000000000..d1c31e8b10 --- /dev/null +++ b/src/lib/ector/software/sw_ft_stroker.c @@ -0,0 +1,2292 @@ + +/***************************************************************************/ +/* */ +/* ftstroke.c */ +/* */ +/* FreeType path stroker (body). */ +/* */ +/* Copyright 2002-2006, 2008-2011, 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "sw_ft_math.h" +#include "sw_ft_stroker.h" +#include +#include +#include + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BEZIER COMPUTATIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define SW_FT_SMALL_CONIC_THRESHOLD ( SW_FT_ANGLE_PI / 6 ) +#define SW_FT_SMALL_CUBIC_THRESHOLD ( SW_FT_ANGLE_PI / 8 ) + +#define SW_FT_EPSILON 2 + +#define SW_FT_IS_SMALL( x ) ( (x) > -SW_FT_EPSILON && (x) < SW_FT_EPSILON ) + + + static SW_FT_Pos + ft_pos_abs( SW_FT_Pos x ) + { + return x >= 0 ? x : -x; + } + + + static void + ft_conic_split( SW_FT_Vector* base ) + { + SW_FT_Pos a, b; + + + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + + + static SW_FT_Bool + ft_conic_is_small_enough( SW_FT_Vector* base, + SW_FT_Angle *angle_in, + SW_FT_Angle *angle_out ) + { + SW_FT_Vector d1, d2; + SW_FT_Angle theta; + SW_FT_Int close1, close2; + + + d1.x = base[1].x - base[2].x; + d1.y = base[1].y - base[2].y; + d2.x = base[0].x - base[1].x; + d2.y = base[0].y - base[1].y; + + close1 = SW_FT_IS_SMALL( d1.x ) && SW_FT_IS_SMALL( d1.y ); + close2 = SW_FT_IS_SMALL( d2.x ) && SW_FT_IS_SMALL( d2.y ); + + if ( close1 ) + { + if ( close2 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else + { + *angle_in = + *angle_out = SW_FT_Atan2( d2.x, d2.y ); + } + } + else /* !close1 */ + { + if ( close2 ) + { + *angle_in = + *angle_out = SW_FT_Atan2( d1.x, d1.y ); + } + else + { + *angle_in = SW_FT_Atan2( d1.x, d1.y ); + *angle_out = SW_FT_Atan2( d2.x, d2.y ); + } + } + + theta = ft_pos_abs( SW_FT_Angle_Diff( *angle_in, *angle_out ) ); + + return SW_FT_BOOL( theta < SW_FT_SMALL_CONIC_THRESHOLD ); + } + + + static void + ft_cubic_split( SW_FT_Vector* base ) + { + SW_FT_Pos a, b, c, d; + + + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + + + /* Return the average of `angle1' and `angle2'. */ + /* This gives correct result even if `angle1' and `angle2' */ + /* have opposite signs. */ + static SW_FT_Angle + ft_angle_mean( SW_FT_Angle angle1, + SW_FT_Angle angle2 ) + { + return angle1 + SW_FT_Angle_Diff( angle1, angle2 ) / 2; + } + + + static SW_FT_Bool + ft_cubic_is_small_enough( SW_FT_Vector* base, + SW_FT_Angle *angle_in, + SW_FT_Angle *angle_mid, + SW_FT_Angle *angle_out ) + { + SW_FT_Vector d1, d2, d3; + SW_FT_Angle theta1, theta2; + SW_FT_Int close1, close2, close3; + + + d1.x = base[2].x - base[3].x; + d1.y = base[2].y - base[3].y; + d2.x = base[1].x - base[2].x; + d2.y = base[1].y - base[2].y; + d3.x = base[0].x - base[1].x; + d3.y = base[0].y - base[1].y; + + close1 = SW_FT_IS_SMALL( d1.x ) && SW_FT_IS_SMALL( d1.y ); + close2 = SW_FT_IS_SMALL( d2.x ) && SW_FT_IS_SMALL( d2.y ); + close3 = SW_FT_IS_SMALL( d3.x ) && SW_FT_IS_SMALL( d3.y ); + + if ( close1 ) + { + if ( close2 ) + { + if ( close3 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else /* !close3 */ + { + *angle_in = + *angle_mid = + *angle_out = SW_FT_Atan2( d3.x, d3.y ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = SW_FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = + *angle_mid = SW_FT_Atan2( d2.x, d2.y ); + *angle_out = SW_FT_Atan2( d3.x, d3.y ); + } + } + } + else /* !close1 */ + { + if ( close2 ) + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = SW_FT_Atan2( d1.x, d1.y ); + } + else /* !close3 */ + { + *angle_in = SW_FT_Atan2( d1.x, d1.y ); + *angle_out = SW_FT_Atan2( d3.x, d3.y ); + *angle_mid = ft_angle_mean( *angle_in, *angle_out ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = SW_FT_Atan2( d1.x, d1.y ); + *angle_mid = + *angle_out = SW_FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = SW_FT_Atan2( d1.x, d1.y ); + *angle_mid = SW_FT_Atan2( d2.x, d2.y ); + *angle_out = SW_FT_Atan2( d3.x, d3.y ); + } + } + } + + theta1 = ft_pos_abs( SW_FT_Angle_Diff( *angle_in, *angle_mid ) ); + theta2 = ft_pos_abs( SW_FT_Angle_Diff( *angle_mid, *angle_out ) ); + + return SW_FT_BOOL( theta1 < SW_FT_SMALL_CUBIC_THRESHOLD && + theta2 < SW_FT_SMALL_CUBIC_THRESHOLD ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKE BORDERS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum SW_FT_StrokeTags_ + { + SW_FT_STROKE_TAG_ON = 1, /* on-curve point */ + SW_FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ + SW_FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ + SW_FT_STROKE_TAG_END = 8 /* sub-path end */ + + } SW_FT_StrokeTags; + +#define SW_FT_STROKE_TAG_BEGIN_END ( SW_FT_STROKE_TAG_BEGIN | SW_FT_STROKE_TAG_END ) + + typedef struct SW_FT_StrokeBorderRec_ + { + SW_FT_UInt num_points; + SW_FT_UInt max_points; + SW_FT_Vector* points; + SW_FT_Byte* tags; + SW_FT_Bool movable; /* TRUE for ends of lineto borders */ + SW_FT_Int start; /* index of current sub-path start point */ + SW_FT_Bool valid; + + } SW_FT_StrokeBorderRec, *SW_FT_StrokeBorder; + + + + SW_FT_Error + SW_FT_Outline_Check( SW_FT_Outline* outline ) + { + if ( outline ) + { + SW_FT_Int n_points = outline->n_points; + SW_FT_Int n_contours = outline->n_contours; + SW_FT_Int end0, end; + SW_FT_Int n; + + + /* empty glyph? */ + if ( n_points == 0 && n_contours == 0 ) + return 0; + + /* check point and contour counts */ + if ( n_points <= 0 || n_contours <= 0 ) + goto Bad; + + end0 = end = -1; + for ( n = 0; n < n_contours; n++ ) + { + end = outline->contours[n]; + + /* note that we don't accept empty contours */ + if ( end <= end0 || end >= n_points ) + goto Bad; + + end0 = end; + } + + if ( end != n_points - 1 ) + goto Bad; + + /* XXX: check the tags array */ + return 0; + } + + Bad: + return -1;//SW_FT_THROW( Invalid_Argument ); + } + + + + void + SW_FT_Outline_Get_CBox( const SW_FT_Outline* outline, + SW_FT_BBox *acbox ) + { + SW_FT_Pos xMin, yMin, xMax, yMax; + + + if ( outline && acbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + SW_FT_Vector* vec = outline->points; + SW_FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + SW_FT_Pos x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } + + + + static SW_FT_Error + ft_stroke_border_grow( SW_FT_StrokeBorder border, + SW_FT_UInt new_points ) + { + SW_FT_UInt old_max = border->max_points; + SW_FT_UInt new_max = border->num_points + new_points; + SW_FT_Error error = 0; + + + if ( new_max > old_max ) + { + SW_FT_UInt cur_max = old_max; + + + while ( cur_max < new_max ) + cur_max += ( cur_max >> 1 ) + 16; + + border->points = (SW_FT_Vector *) realloc(border->points, cur_max * sizeof(SW_FT_Vector)); + border->tags = (SW_FT_Byte *) realloc(border->tags, cur_max * sizeof(SW_FT_Byte)); + + if ( !border->points || !border->tags) + goto Exit; + + border->max_points = cur_max; + } + + Exit: + return error; + } + + + static void + ft_stroke_border_close( SW_FT_StrokeBorder border, + SW_FT_Bool reverse ) + { + SW_FT_UInt start = border->start; + SW_FT_UInt count = border->num_points; + + + assert( border->start >= 0 ); + + /* don't record empty paths! */ + if ( count <= start + 1U ) + border->num_points = start; + else + { + /* copy the last point to the start of this sub-path, since */ + /* it contains the `adjusted' starting coordinates */ + border->num_points = --count; + border->points[start] = border->points[count]; + + if ( reverse ) + { + /* reverse the points */ + { + SW_FT_Vector* vec1 = border->points + start + 1; + SW_FT_Vector* vec2 = border->points + count - 1; + + + for ( ; vec1 < vec2; vec1++, vec2-- ) + { + SW_FT_Vector tmp; + + + tmp = *vec1; + *vec1 = *vec2; + *vec2 = tmp; + } + } + + /* then the tags */ + { + SW_FT_Byte* tag1 = border->tags + start + 1; + SW_FT_Byte* tag2 = border->tags + count - 1; + + + for ( ; tag1 < tag2; tag1++, tag2-- ) + { + SW_FT_Byte tmp; + + + tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + } + + border->tags[start ] |= SW_FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= SW_FT_STROKE_TAG_END; + } + + border->start = -1; + border->movable = FALSE; + } + + + static SW_FT_Error + ft_stroke_border_lineto( SW_FT_StrokeBorder border, + SW_FT_Vector* to, + SW_FT_Bool movable ) + { + SW_FT_Error error = 0; + + + assert( border->start >= 0 ); + + if ( border->movable ) + { + /* move last point */ + border->points[border->num_points - 1] = *to; + } + else + { + /* don't add zero-length lineto */ + if ( border->num_points > 0 && + SW_FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) && + SW_FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) ) + return error; + + /* add one point */ + error = ft_stroke_border_grow( border, 1 ); + if ( !error ) + { + SW_FT_Vector* vec = border->points + border->num_points; + SW_FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *to; + tag[0] = SW_FT_STROKE_TAG_ON; + + border->num_points += 1; + } + } + border->movable = movable; + return error; + } + + + static SW_FT_Error + ft_stroke_border_conicto( SW_FT_StrokeBorder border, + SW_FT_Vector* control, + SW_FT_Vector* to ) + { + SW_FT_Error error; + + + assert( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 2 ); + if ( !error ) + { + SW_FT_Vector* vec = border->points + border->num_points; + SW_FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control; + vec[1] = *to; + + tag[0] = 0; + tag[1] = SW_FT_STROKE_TAG_ON; + + border->num_points += 2; + } + + border->movable = FALSE; + + return error; + } + + + static SW_FT_Error + ft_stroke_border_cubicto( SW_FT_StrokeBorder border, + SW_FT_Vector* control1, + SW_FT_Vector* control2, + SW_FT_Vector* to ) + { + SW_FT_Error error; + + + assert( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 3 ); + if ( !error ) + { + SW_FT_Vector* vec = border->points + border->num_points; + SW_FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + + tag[0] = SW_FT_STROKE_TAG_CUBIC; + tag[1] = SW_FT_STROKE_TAG_CUBIC; + tag[2] = SW_FT_STROKE_TAG_ON; + + border->num_points += 3; + } + + border->movable = FALSE; + + return error; + } + + +#define SW_FT_ARC_CUBIC_ANGLE ( SW_FT_ANGLE_PI / 2 ) + + + static SW_FT_Error + ft_stroke_border_arcto( SW_FT_StrokeBorder border, + SW_FT_Vector* center, + SW_FT_Fixed radius, + SW_FT_Angle angle_start, + SW_FT_Angle angle_diff ) + { + SW_FT_Angle total, angle, step, rotate, next, theta; + SW_FT_Vector a, b, a2, b2; + SW_FT_Fixed length; + SW_FT_Error error = 0; + + + /* compute start point */ + SW_FT_Vector_From_Polar( &a, radius, angle_start ); + a.x += center->x; + a.y += center->y; + + total = angle_diff; + angle = angle_start; + rotate = ( angle_diff >= 0 ) ? SW_FT_ANGLE_PI2 : -SW_FT_ANGLE_PI2; + + while ( total != 0 ) + { + step = total; + if ( step > SW_FT_ARC_CUBIC_ANGLE ) + step = SW_FT_ARC_CUBIC_ANGLE; + + else if ( step < -SW_FT_ARC_CUBIC_ANGLE ) + step = -SW_FT_ARC_CUBIC_ANGLE; + + next = angle + step; + theta = step; + if ( theta < 0 ) + theta = -theta; + + theta >>= 1; + + /* compute end point */ + SW_FT_Vector_From_Polar( &b, radius, next ); + b.x += center->x; + b.y += center->y; + + /* compute first and second control points */ + length = SW_FT_MulDiv( radius, SW_FT_Sin( theta ) * 4, + ( 0x10000L + SW_FT_Cos( theta ) ) * 3 ); + + SW_FT_Vector_From_Polar( &a2, length, angle + rotate ); + a2.x += a.x; + a2.y += a.y; + + SW_FT_Vector_From_Polar( &b2, length, next - rotate ); + b2.x += b.x; + b2.y += b.y; + + /* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); + if ( error ) + break; + + /* process the rest of the arc ?? */ + a = b; + total -= step; + angle = next; + } + + return error; + } + + + static SW_FT_Error + ft_stroke_border_moveto( SW_FT_StrokeBorder border, + SW_FT_Vector* to ) + { + /* close current open path if any ? */ + if ( border->start >= 0 ) + ft_stroke_border_close( border, FALSE ); + + border->start = border->num_points; + border->movable = FALSE; + + return ft_stroke_border_lineto( border, to, FALSE ); + } + + + static void + ft_stroke_border_init( SW_FT_StrokeBorder border) + { + border->points = NULL; + border->tags = NULL; + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_reset( SW_FT_StrokeBorder border ) + { + border->num_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_done( SW_FT_StrokeBorder border ) + { + + free( border->points ); + free( border->tags ); + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static SW_FT_Error + ft_stroke_border_get_counts( SW_FT_StrokeBorder border, + SW_FT_UInt *anum_points, + SW_FT_UInt *anum_contours ) + { + SW_FT_Error error = 0; + SW_FT_UInt num_points = 0; + SW_FT_UInt num_contours = 0; + + SW_FT_UInt count = border->num_points; + SW_FT_Vector* point = border->points; + SW_FT_Byte* tags = border->tags; + SW_FT_Int in_contour = 0; + + + for ( ; count > 0; count--, num_points++, point++, tags++ ) + { + if ( tags[0] & SW_FT_STROKE_TAG_BEGIN ) + { + if ( in_contour != 0 ) + goto Fail; + + in_contour = 1; + } + else if ( in_contour == 0 ) + goto Fail; + + if ( tags[0] & SW_FT_STROKE_TAG_END ) + { + in_contour = 0; + num_contours++; + } + } + + if ( in_contour != 0 ) + goto Fail; + + border->valid = TRUE; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + + Fail: + num_points = 0; + num_contours = 0; + goto Exit; + } + + + static void + ft_stroke_border_export( SW_FT_StrokeBorder border, + SW_FT_Outline* outline ) + { + /* copy point locations */ + memcpy( outline->points + outline->n_points, + border->points, + border->num_points * sizeof(SW_FT_Vector)); + + /* copy tags */ + { + SW_FT_UInt count = border->num_points; + SW_FT_Byte* read = border->tags; + SW_FT_Byte* write = (SW_FT_Byte*)outline->tags + outline->n_points; + + + for ( ; count > 0; count--, read++, write++ ) + { + if ( *read & SW_FT_STROKE_TAG_ON ) + *write = SW_FT_CURVE_TAG_ON; + else if ( *read & SW_FT_STROKE_TAG_CUBIC ) + *write = SW_FT_CURVE_TAG_CUBIC; + else + *write = SW_FT_CURVE_TAG_CONIC; + } + } + + /* copy contours */ + { + SW_FT_UInt count = border->num_points; + SW_FT_Byte* tags = border->tags; + SW_FT_Short* write = outline->contours + outline->n_contours; + SW_FT_Short idx = (SW_FT_Short)outline->n_points; + + + for ( ; count > 0; count--, tags++, idx++ ) + { + if ( *tags & SW_FT_STROKE_TAG_END ) + { + *write++ = idx; + outline->n_contours++; + } + } + } + + outline->n_points = (short)( outline->n_points + border->num_points ); + + assert( SW_FT_Outline_Check( outline ) == 0 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define SW_FT_SIDE_TO_ROTATE( s ) ( SW_FT_ANGLE_PI2 - (s) * SW_FT_ANGLE_PI ) + + typedef struct SW_FT_StrokerRec_ + { + SW_FT_Angle angle_in; /* direction into curr join */ + SW_FT_Angle angle_out; /* direction out of join */ + SW_FT_Vector center; /* current position */ + SW_FT_Fixed line_length; /* length of last lineto */ + SW_FT_Bool first_point; /* is this the start? */ + SW_FT_Bool subpath_open; /* is the subpath open? */ + SW_FT_Angle subpath_angle; /* subpath start direction */ + SW_FT_Vector subpath_start; /* subpath start position */ + SW_FT_Fixed subpath_line_length; /* subpath start lineto len */ + SW_FT_Bool handle_wide_strokes; /* use wide strokes logic? */ + + SW_FT_Stroker_LineCap line_cap; + SW_FT_Stroker_LineJoin line_join; + SW_FT_Stroker_LineJoin line_join_saved; + SW_FT_Fixed miter_limit; + SW_FT_Fixed radius; + + SW_FT_StrokeBorderRec borders[2]; + } SW_FT_StrokerRec; + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_New( SW_FT_Stroker *astroker ) + { + SW_FT_Error error = 0; /* assigned in SW_FT_NEW */ + SW_FT_Stroker stroker = NULL; + + + stroker = (SW_FT_StrokerRec *) calloc(1, sizeof(SW_FT_StrokerRec)); + if ( stroker ) + { + + ft_stroke_border_init( &stroker->borders[0]); + ft_stroke_border_init( &stroker->borders[1]); + } + + *astroker = stroker; + + return error; + } + + void + SW_FT_Stroker_Rewind( SW_FT_Stroker stroker ) + { + if ( stroker ) + { + ft_stroke_border_reset( &stroker->borders[0] ); + ft_stroke_border_reset( &stroker->borders[1] ); + } + } + + + /* documentation is in ftstroke.h */ + + void + SW_FT_Stroker_Set( SW_FT_Stroker stroker, + SW_FT_Fixed radius, + SW_FT_Stroker_LineCap line_cap, + SW_FT_Stroker_LineJoin line_join, + SW_FT_Fixed miter_limit ) + { + stroker->radius = radius; + stroker->line_cap = line_cap; + stroker->line_join = line_join; + stroker->miter_limit = miter_limit; + + /* ensure miter limit has sensible value */ + if ( stroker->miter_limit < 0x10000 ) + stroker->miter_limit = 0x10000; + + /* save line join style: */ + /* line join style can be temporarily changed when stroking curves */ + stroker->line_join_saved = line_join; + + SW_FT_Stroker_Rewind( stroker ); + } + + /* documentation is in ftstroke.h */ + + void + SW_FT_Stroker_Done( SW_FT_Stroker stroker ) + { + if ( stroker ) + { + + ft_stroke_border_done( &stroker->borders[0] ); + ft_stroke_border_done( &stroker->borders[1] ); + + free( stroker ); + } + } + + + /* create a circular arc at a corner or cap */ + static SW_FT_Error + ft_stroker_arcto( SW_FT_Stroker stroker, + SW_FT_Int side ) + { + SW_FT_Angle total, rotate; + SW_FT_Fixed radius = stroker->radius; + SW_FT_Error error = 0; + SW_FT_StrokeBorder border = stroker->borders + side; + + + rotate = SW_FT_SIDE_TO_ROTATE( side ); + + total = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( total == SW_FT_ANGLE_PI ) + total = -rotate * 2; + + error = ft_stroke_border_arcto( border, + &stroker->center, + radius, + stroker->angle_in + rotate, + total ); + border->movable = FALSE; + return error; + } + + + /* add a cap at the end of an opened path */ + static SW_FT_Error + ft_stroker_cap( SW_FT_Stroker stroker, + SW_FT_Angle angle, + SW_FT_Int side ) + { + SW_FT_Error error = 0; + + + if ( stroker->line_cap == SW_FT_STROKER_LINECAP_ROUND ) + { + /* add a round cap */ + stroker->angle_in = angle; + stroker->angle_out = angle + SW_FT_ANGLE_PI; + + error = ft_stroker_arcto( stroker, side ); + } + else if ( stroker->line_cap == SW_FT_STROKER_LINECAP_SQUARE ) + { + /* add a square cap */ + SW_FT_Vector delta, delta2; + SW_FT_Angle rotate = SW_FT_SIDE_TO_ROTATE( side ); + SW_FT_Fixed radius = stroker->radius; + SW_FT_StrokeBorder border = stroker->borders + side; + + + SW_FT_Vector_From_Polar( &delta2, radius, angle + rotate ); + SW_FT_Vector_From_Polar( &delta, radius, angle ); + + delta.x += stroker->center.x + delta2.x; + delta.y += stroker->center.y + delta2.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + SW_FT_Vector_From_Polar( &delta2, radius, angle - rotate ); + SW_FT_Vector_From_Polar( &delta, radius, angle ); + + delta.x += delta2.x + stroker->center.x; + delta.y += delta2.y + stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else if ( stroker->line_cap == SW_FT_STROKER_LINECAP_BUTT ) + { + /* add a butt ending */ + SW_FT_Vector delta; + SW_FT_Angle rotate = SW_FT_SIDE_TO_ROTATE( side ); + SW_FT_Fixed radius = stroker->radius; + SW_FT_StrokeBorder border = stroker->borders + side; + + + SW_FT_Vector_From_Polar( &delta, radius, angle + rotate ); + + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + SW_FT_Vector_From_Polar( &delta, radius, angle - rotate ); + + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + + Exit: + return error; + } + + + /* process an inside corner, i.e. compute intersection */ + static SW_FT_Error + ft_stroker_inside( SW_FT_Stroker stroker, + SW_FT_Int side, + SW_FT_Fixed line_length ) + { + SW_FT_StrokeBorder border = stroker->borders + side; + SW_FT_Angle phi, theta, rotate; + SW_FT_Fixed length, thcos; + SW_FT_Vector delta; + SW_FT_Error error = 0; + SW_FT_Bool intersect; /* use intersection of lines? */ + + + rotate = SW_FT_SIDE_TO_ROTATE( side ); + + theta = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + + /* Only intersect borders if between two lineto's and both */ + /* lines are long enough (line_length is zero for curves). */ + if ( !border->movable || line_length == 0 ) + intersect = FALSE; + else + { + /* compute minimum required length of lines */ + SW_FT_Fixed min_length = ft_pos_abs( SW_FT_MulFix( stroker->radius, + SW_FT_Tan( theta ) ) ); + + + intersect = SW_FT_BOOL( stroker->line_length >= min_length && + line_length >= min_length ); + } + + if ( !intersect ) + { + SW_FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + } + else + { + /* compute median angle */ + phi = stroker->angle_in + theta; + + thcos = SW_FT_Cos( theta ); + + length = SW_FT_DivFix( stroker->radius, thcos ); + + SW_FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + } + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + + return error; + } + + + /* process an outside corner, i.e. compute bevel/miter/round */ + static SW_FT_Error + ft_stroker_outside( SW_FT_Stroker stroker, + SW_FT_Int side, + SW_FT_Fixed line_length ) + { + SW_FT_StrokeBorder border = stroker->borders + side; + SW_FT_Error error; + SW_FT_Angle rotate; + + + if ( stroker->line_join == SW_FT_STROKER_LINEJOIN_ROUND ) + error = ft_stroker_arcto( stroker, side ); + else + { + /* this is a mitered (pointed) or beveled (truncated) corner */ + SW_FT_Fixed sigma = 0, radius = stroker->radius; + SW_FT_Angle theta = 0, phi = 0; + SW_FT_Fixed thcos = 0; + SW_FT_Bool bevel, fixed_bevel; + + + rotate = SW_FT_SIDE_TO_ROTATE( side ); + + bevel = + SW_FT_BOOL( stroker->line_join == SW_FT_STROKER_LINEJOIN_BEVEL ); + + fixed_bevel = + SW_FT_BOOL( stroker->line_join != SW_FT_STROKER_LINEJOIN_MITER_VARIABLE ); + + if ( !bevel ) + { + theta = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + + if ( theta == SW_FT_ANGLE_PI ) + { + theta = rotate; + phi = stroker->angle_in; + } + else + { + theta /= 2; + phi = stroker->angle_in + theta + rotate; + } + + thcos = SW_FT_Cos( theta ); + sigma = SW_FT_MulFix( stroker->miter_limit, thcos ); + + /* is miter limit exceeded? */ + if ( sigma < 0x10000L ) + { + /* don't create variable bevels for very small deviations; */ + /* SW_FT_Sin(x) = 0 for x <= 57 */ + if ( fixed_bevel || ft_pos_abs( theta ) > 57 ) + bevel = TRUE; + } + } + + if ( bevel ) /* this is a bevel (broken angle) */ + { + if ( fixed_bevel ) + { + /* the outer corners are simply joined together */ + SW_FT_Vector delta; + + + /* add bevel */ + SW_FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else /* variable bevel */ + { + /* the miter is truncated */ + SW_FT_Vector middle, delta; + SW_FT_Fixed length; + + + /* compute middle point */ + SW_FT_Vector_From_Polar( &middle, + SW_FT_MulFix( radius, stroker->miter_limit ), + phi ); + middle.x += stroker->center.x; + middle.y += stroker->center.y; + + /* compute first angle point */ + length = SW_FT_MulDiv( radius, 0x10000L - sigma, + ft_pos_abs( SW_FT_Sin( theta ) ) ); + + SW_FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* compute second angle point */ + SW_FT_Vector_From_Polar( &delta, length, phi - rotate ); + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* finally, add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + SW_FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + else /* this is a miter (intersection) */ + { + SW_FT_Fixed length; + SW_FT_Vector delta; + + + length = SW_FT_DivFix( stroker->radius, thcos ); + + SW_FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* now add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + SW_FT_Vector_From_Polar( &delta, + stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + + Exit: + return error; + } + + + static SW_FT_Error + ft_stroker_process_corner( SW_FT_Stroker stroker, + SW_FT_Fixed line_length ) + { + SW_FT_Error error = 0; + SW_FT_Angle turn; + SW_FT_Int inside_side; + + + turn = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn == 0 ) + goto Exit; + + /* when we turn to the right, the inside side is 0 */ + inside_side = 0; + + /* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; + + /* process the inside side */ + error = ft_stroker_inside( stroker, inside_side, line_length ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, 1 - inside_side, line_length ); + + Exit: + return error; + } + + + /* add two points to the left and right borders corresponding to the */ + /* start of the subpath */ + static SW_FT_Error + ft_stroker_subpath_start( SW_FT_Stroker stroker, + SW_FT_Angle start_angle, + SW_FT_Fixed line_length ) + { + SW_FT_Vector delta; + SW_FT_Vector point; + SW_FT_Error error; + SW_FT_StrokeBorder border; + + + SW_FT_Vector_From_Polar( &delta, stroker->radius, + start_angle + SW_FT_ANGLE_PI2 ); + + point.x = stroker->center.x + delta.x; + point.y = stroker->center.y + delta.y; + + border = stroker->borders; + error = ft_stroke_border_moveto( border, &point ); + if ( error ) + goto Exit; + + point.x = stroker->center.x - delta.x; + point.y = stroker->center.y - delta.y; + + border++; + error = ft_stroke_border_moveto( border, &point ); + + /* save angle, position, and line length for last join */ + /* (line_length is zero for curves) */ + stroker->subpath_angle = start_angle; + stroker->first_point = FALSE; + stroker->subpath_line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_LineTo( SW_FT_Stroker stroker, + SW_FT_Vector* to ) + { + SW_FT_Error error = 0; + SW_FT_StrokeBorder border; + SW_FT_Vector delta; + SW_FT_Angle angle; + SW_FT_Int side; + SW_FT_Fixed line_length; + + + delta.x = to->x - stroker->center.x; + delta.y = to->y - stroker->center.y; + + /* a zero-length lineto is a no-op; avoid creating a spurious corner */ + if ( delta.x == 0 && delta.y == 0 ) + goto Exit; + + /* compute length of line */ + line_length = SW_FT_Vector_Length( &delta ); + + angle = SW_FT_Atan2( delta.x, delta.y ); + SW_FT_Vector_From_Polar( &delta, stroker->radius, angle + SW_FT_ANGLE_PI2 ); + + /* process corner if necessary */ + if ( stroker->first_point ) + { + /* This is the first segment of a subpath. We need to */ + /* add a point to each border at their respective starting */ + /* point locations. */ + error = ft_stroker_subpath_start( stroker, angle, line_length ); + if ( error ) + goto Exit; + } + else + { + /* process the current corner */ + stroker->angle_out = angle; + error = ft_stroker_process_corner( stroker, line_length ); + if ( error ) + goto Exit; + } + + /* now add a line segment to both the `inside' and `outside' paths */ + for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) + { + SW_FT_Vector point; + + + point.x = to->x + delta.x; + point.y = to->y + delta.y; + + /* the ends of lineto borders are movable */ + error = ft_stroke_border_lineto( border, &point, TRUE ); + if ( error ) + goto Exit; + + delta.x = -delta.x; + delta.y = -delta.y; + } + + stroker->angle_in = angle; + stroker->center = *to; + stroker->line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_ConicTo( SW_FT_Stroker stroker, + SW_FT_Vector* control, + SW_FT_Vector* to ) + { + SW_FT_Error error = 0; + SW_FT_Vector bez_stack[34]; + SW_FT_Vector* arc; + SW_FT_Vector* limit = bez_stack + 30; + SW_FT_Bool first_arc = TRUE; + + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( SW_FT_IS_SMALL( stroker->center.x - control->x ) && + SW_FT_IS_SMALL( stroker->center.y - control->y ) && + SW_FT_IS_SMALL( control->x - to->x ) && + SW_FT_IS_SMALL( control->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control; + arc[2] = stroker->center; + + while ( arc >= bez_stack ) + { + SW_FT_Angle angle_in, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = stroker->angle_in; + + if ( arc < limit && + !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_conic_split( arc ); + arc += 2; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( SW_FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + SW_FT_SMALL_CONIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[2]; + stroker->angle_out = angle_in; + stroker->line_join = SW_FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + SW_FT_Vector ctrl, end; + SW_FT_Angle theta, phi, rotate, alpha0 = 0; + SW_FT_Fixed length; + SW_FT_StrokeBorder border; + SW_FT_Int side; + + + theta = SW_FT_Angle_Diff( angle_in, angle_out ) / 2; + phi = angle_in + theta; + length = SW_FT_DivFix( stroker->radius, SW_FT_Cos( theta ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = SW_FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = SW_FT_SIDE_TO_ROTATE( side ); + + /* compute control point */ + SW_FT_Vector_From_Polar( &ctrl, length, phi + rotate ); + ctrl.x += arc[1].x; + ctrl.y += arc[1].y; + + /* compute end point */ + SW_FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + SW_FT_Vector start; + SW_FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = SW_FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( SW_FT_Angle_Diff( alpha0, alpha1 ) ) > + SW_FT_ANGLE_PI / 2 ) + { + SW_FT_Angle beta, gamma; + SW_FT_Vector bvec, delta; + SW_FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = SW_FT_Atan2( arc[2].x - start.x, arc[2].y - start.y ); + gamma = SW_FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = SW_FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( SW_FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( SW_FT_Sin( beta - gamma ) ); + + alen = SW_FT_MulDiv( blen, sinA, sinB ); + + SW_FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_conicto( border, &ctrl, &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_conicto( border, &ctrl, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 2; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_CubicTo( SW_FT_Stroker stroker, + SW_FT_Vector* control1, + SW_FT_Vector* control2, + SW_FT_Vector* to ) + { + SW_FT_Error error = 0; + SW_FT_Vector bez_stack[37]; + SW_FT_Vector* arc; + SW_FT_Vector* limit = bez_stack + 32; + SW_FT_Bool first_arc = TRUE; + + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( SW_FT_IS_SMALL( stroker->center.x - control1->x ) && + SW_FT_IS_SMALL( stroker->center.y - control1->y ) && + SW_FT_IS_SMALL( control1->x - control2->x ) && + SW_FT_IS_SMALL( control1->y - control2->y ) && + SW_FT_IS_SMALL( control2->x - to->x ) && + SW_FT_IS_SMALL( control2->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control2; + arc[2] = *control1; + arc[3] = stroker->center; + + while ( arc >= bez_stack ) + { + SW_FT_Angle angle_in, angle_mid, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = angle_mid = stroker->angle_in; + + if ( arc < limit && + !ft_cubic_is_small_enough( arc, &angle_in, + &angle_mid, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_cubic_split( arc ); + arc += 3; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( SW_FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + SW_FT_SMALL_CUBIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[3]; + stroker->angle_out = angle_in; + stroker->line_join = SW_FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + SW_FT_Vector ctrl1, ctrl2, end; + SW_FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; + SW_FT_Fixed length1, length2; + SW_FT_StrokeBorder border; + SW_FT_Int side; + + + theta1 = SW_FT_Angle_Diff( angle_in, angle_mid ) / 2; + theta2 = SW_FT_Angle_Diff( angle_mid, angle_out ) / 2; + phi1 = ft_angle_mean( angle_in, angle_mid ); + phi2 = ft_angle_mean( angle_mid, angle_out ); + length1 = SW_FT_DivFix( stroker->radius, SW_FT_Cos( theta1 ) ); + length2 = SW_FT_DivFix( stroker->radius, SW_FT_Cos( theta2 ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = SW_FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = SW_FT_SIDE_TO_ROTATE( side ); + + /* compute control points */ + SW_FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); + ctrl1.x += arc[2].x; + ctrl1.y += arc[2].y; + + SW_FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); + ctrl2.x += arc[1].x; + ctrl2.y += arc[1].y; + + /* compute end point */ + SW_FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + SW_FT_Vector start; + SW_FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = SW_FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( SW_FT_Angle_Diff( alpha0, alpha1 ) ) > + SW_FT_ANGLE_PI / 2 ) + { + SW_FT_Angle beta, gamma; + SW_FT_Vector bvec, delta; + SW_FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = SW_FT_Atan2( arc[3].x - start.x, arc[3].y - start.y ); + gamma = SW_FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = SW_FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( SW_FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( SW_FT_Sin( beta - gamma ) ); + + alen = SW_FT_MulDiv( blen, sinA, sinB ); + + SW_FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_cubicto( border, + &ctrl2, + &ctrl1, + &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 3; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_BeginSubPath( SW_FT_Stroker stroker, + SW_FT_Vector* to, + SW_FT_Bool open ) + { + /* We cannot process the first point, because there is not enough */ + /* information regarding its corner/cap. The latter will be processed */ + /* in the `SW_FT_Stroker_EndSubPath' routine. */ + /* */ + stroker->first_point = TRUE; + stroker->center = *to; + stroker->subpath_open = open; + + /* Determine if we need to check whether the border radius is greater */ + /* than the radius of curvature of a curve, to handle this case */ + /* specially. This is only required if bevel joins or butt caps may */ + /* be created, because round & miter joins and round & square caps */ + /* cover the negative sector created with wide strokes. */ + stroker->handle_wide_strokes = + SW_FT_BOOL( stroker->line_join != SW_FT_STROKER_LINEJOIN_ROUND || + ( stroker->subpath_open && + stroker->line_cap == SW_FT_STROKER_LINECAP_BUTT ) ); + + /* record the subpath start point for each border */ + stroker->subpath_start = *to; + + stroker->angle_in = 0; + + return 0; + } + + + static SW_FT_Error + ft_stroker_add_reverse_left( SW_FT_Stroker stroker, + SW_FT_Bool open ) + { + SW_FT_StrokeBorder right = stroker->borders + 0; + SW_FT_StrokeBorder left = stroker->borders + 1; + SW_FT_Int new_points; + SW_FT_Error error = 0; + + + assert( left->start >= 0 ); + + new_points = left->num_points - left->start; + if ( new_points > 0 ) + { + error = ft_stroke_border_grow( right, (SW_FT_UInt)new_points ); + if ( error ) + goto Exit; + + { + SW_FT_Vector* dst_point = right->points + right->num_points; + SW_FT_Byte* dst_tag = right->tags + right->num_points; + SW_FT_Vector* src_point = left->points + left->num_points - 1; + SW_FT_Byte* src_tag = left->tags + left->num_points - 1; + + + while ( src_point >= left->points + left->start ) + { + *dst_point = *src_point; + *dst_tag = *src_tag; + + if ( open ) + dst_tag[0] &= ~SW_FT_STROKE_TAG_BEGIN_END; + else + { + SW_FT_Byte ttag = + (SW_FT_Byte)( dst_tag[0] & SW_FT_STROKE_TAG_BEGIN_END ); + + + /* switch begin/end tags if necessary */ + if ( ttag == SW_FT_STROKE_TAG_BEGIN || + ttag == SW_FT_STROKE_TAG_END ) + dst_tag[0] ^= SW_FT_STROKE_TAG_BEGIN_END; + } + + src_point--; + src_tag--; + dst_point++; + dst_tag++; + } + } + + left->num_points = left->start; + right->num_points += new_points; + + right->movable = FALSE; + left->movable = FALSE; + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + /* there's a lot of magic in this function! */ + SW_FT_Error + SW_FT_Stroker_EndSubPath( SW_FT_Stroker stroker ) + { + SW_FT_Error error = 0; + + + if ( stroker->subpath_open ) + { + SW_FT_StrokeBorder right = stroker->borders; + + + /* All right, this is an opened path, we need to add a cap between */ + /* right & left, add the reverse of left, then add a final cap */ + /* between left & right. */ + error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); + if ( error ) + goto Exit; + + /* add reversed points from `left' to `right' */ + error = ft_stroker_add_reverse_left( stroker, TRUE ); + if ( error ) + goto Exit; + + /* now add the final cap */ + stroker->center = stroker->subpath_start; + error = ft_stroker_cap( stroker, + stroker->subpath_angle + SW_FT_ANGLE_PI, 0 ); + if ( error ) + goto Exit; + + /* Now end the right subpath accordingly. The left one is */ + /* rewind and doesn't need further processing. */ + ft_stroke_border_close( right, FALSE ); + } + else + { + SW_FT_Angle turn; + SW_FT_Int inside_side; + + + /* close the path if needed */ + if ( stroker->center.x != stroker->subpath_start.x || + stroker->center.y != stroker->subpath_start.y ) + { + error = SW_FT_Stroker_LineTo( stroker, &stroker->subpath_start ); + if ( error ) + goto Exit; + } + + /* process the corner */ + stroker->angle_out = stroker->subpath_angle; + turn = SW_FT_Angle_Diff( stroker->angle_in, + stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn != 0 ) + { + /* when we turn to the right, the inside side is 0 */ + inside_side = 0; + + /* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; + + error = ft_stroker_inside( stroker, + inside_side, + stroker->subpath_line_length ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, + 1 - inside_side, + stroker->subpath_line_length ); + if ( error ) + goto Exit; + } + + /* then end our two subpaths */ + ft_stroke_border_close( stroker->borders + 0, FALSE ); + ft_stroke_border_close( stroker->borders + 1, TRUE ); + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_GetBorderCounts( SW_FT_Stroker stroker, + SW_FT_StrokerBorder border, + SW_FT_UInt *anum_points, + SW_FT_UInt *anum_contours ) + { + SW_FT_UInt num_points = 0, num_contours = 0; + SW_FT_Error error; + + + if ( !stroker || border > 1 ) + { + error = -1;//SW_FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + SW_FT_Error + SW_FT_Stroker_GetCounts( SW_FT_Stroker stroker, + SW_FT_UInt *anum_points, + SW_FT_UInt *anum_contours ) + { + SW_FT_UInt count1, count2, num_points = 0; + SW_FT_UInt count3, count4, num_contours = 0; + SW_FT_Error error; + + + error = ft_stroke_border_get_counts( stroker->borders + 0, + &count1, &count2 ); + if ( error ) + goto Exit; + + error = ft_stroke_border_get_counts( stroker->borders + 1, + &count3, &count4 ); + if ( error ) + goto Exit; + + num_points = count1 + count3; + num_contours = count2 + count4; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + } + + + /* documentation is in ftstroke.h */ + + void + SW_FT_Stroker_ExportBorder( SW_FT_Stroker stroker, + SW_FT_StrokerBorder border, + SW_FT_Outline* outline ) + { + if ( border == SW_FT_STROKER_BORDER_LEFT || + border == SW_FT_STROKER_BORDER_RIGHT ) + { + SW_FT_StrokeBorder sborder = & stroker->borders[border]; + + + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); + } + } + + + /* documentation is in ftstroke.h */ + + void + SW_FT_Stroker_Export( SW_FT_Stroker stroker, + SW_FT_Outline* outline ) + { + SW_FT_Stroker_ExportBorder( stroker, SW_FT_STROKER_BORDER_LEFT, outline ); + SW_FT_Stroker_ExportBorder( stroker, SW_FT_STROKER_BORDER_RIGHT, outline ); + } + + + /* documentation is in ftstroke.h */ + + /* + * The following is very similar to SW_FT_Outline_Decompose, except + * that we do support opened paths, and do not scale the outline. + */ + SW_FT_Error + SW_FT_Stroker_ParseOutline( SW_FT_Stroker stroker, + SW_FT_Outline* outline, + SW_FT_Bool opened ) + { + SW_FT_Vector v_last; + SW_FT_Vector v_control; + SW_FT_Vector v_start; + + SW_FT_Vector* point; + SW_FT_Vector* limit; + char* tags; + + SW_FT_Error error; + + SW_FT_Int n; /* index of contour in outline */ + SW_FT_UInt first; /* index of first point in contour */ + SW_FT_Int tag; /* current point's state */ + + + if ( !outline || !stroker ) + return -1;//SW_FT_THROW( Invalid_Argument ); + + SW_FT_Stroker_Rewind( stroker ); + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + SW_FT_UInt last; /* index of last point in contour */ + + + last = outline->contours[n]; + limit = outline->points + last; + + /* skip empty points; we don't stroke these */ + if ( last <= first ) + { + first = last + 1; + continue; + } + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = SW_FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == SW_FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == SW_FT_CURVE_TAG_CONIC ) + { + /* First point is conic control. Yes, this happens. */ + if ( SW_FT_CURVE_TAG( outline->tags[last] ) == SW_FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + } + point--; + tags--; + } + + error = SW_FT_Stroker_BeginSubPath( stroker, &v_start, opened ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = SW_FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ + { + SW_FT_Vector vec; + + + vec.x = point->x; + vec.y = point->y; + + error = SW_FT_Stroker_LineTo( stroker, &vec ); + if ( error ) + goto Exit; + continue; + } + + case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = point->x; + v_control.y = point->y; + + Do_Conic: + if ( point < limit ) + { + SW_FT_Vector vec; + SW_FT_Vector v_middle; + + + point++; + tags++; + tag = SW_FT_CURVE_TAG( tags[0] ); + + vec = point[0]; + + if ( tag == SW_FT_CURVE_TAG_ON ) + { + error = SW_FT_Stroker_ConicTo( stroker, &v_control, &vec ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != SW_FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = SW_FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = SW_FT_Stroker_ConicTo( stroker, &v_control, &v_start ); + goto Close; + + default: /* SW_FT_CURVE_TAG_CUBIC */ + { + SW_FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + SW_FT_CURVE_TAG( tags[1] ) != SW_FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1 = point[-2]; + vec2 = point[-1]; + + if ( point <= limit ) + { + SW_FT_Vector vec; + + + vec = point[0]; + + error = SW_FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); + if ( error ) + goto Exit; + continue; + } + + error = SW_FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); + goto Close; + } + } + } + + Close: + if ( error ) + goto Exit; + + /* don't try to end the path if no segments have been generated */ + if ( !stroker->first_point ) + { + error = SW_FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; + } + + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return -2;//SW_FT_THROW( Invalid_Outline ); + } + + +/* END */ diff --git a/src/lib/ector/software/sw_ft_stroker.h b/src/lib/ector/software/sw_ft_stroker.h new file mode 100755 index 0000000000..75830fb25c --- /dev/null +++ b/src/lib/ector/software/sw_ft_stroker.h @@ -0,0 +1,325 @@ +#ifndef SW_FT_STROKER_H +#define SW_FT_STROKER_H +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include "sw_ft_raster.h" + + /************************************************************** + * + * @type: + * SW_FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ + typedef struct SW_FT_StrokerRec_* SW_FT_Stroker; + + + /************************************************************** + * + * @enum: + * SW_FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * SW_FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * SW_FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins. The outer corner of + * the joined lines is filled by enclosing the triangular + * region of the corner with a straight line between the + * outer corners of each stroke. + * + * SW_FT_STROKER_LINEJOIN_MITER_FIXED :: + * Used to render mitered line joins, with fixed bevels if the + * miter limit is exceeded. The outer edges of the strokes + * for the two segments are extended until they meet at an + * angle. If the segments meet at too sharp an angle (such + * that the miter would extend from the intersection of the + * segments a distance greater than the product of the miter + * limit value and the border radius), then a bevel join (see + * above) is used instead. This prevents long spikes being + * created. SW_FT_STROKER_LINEJOIN_MITER_FIXED generates a miter + * line join as used in PostScript and PDF. + * + * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE :: + * SW_FT_STROKER_LINEJOIN_MITER :: + * Used to render mitered line joins, with variable bevels if + * the miter limit is exceeded. The intersection of the + * strokes is clipped at a line perpendicular to the bisector + * of the angle between the strokes, at the distance from the + * intersection of the segments equal to the product of the + * miter limit value and the border radius. This prevents + * long spikes being created. + * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line + * join as used in XPS. SW_FT_STROKER_LINEJOIN_MITER is an alias + * for SW_FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for + * backwards compatibility. + */ + typedef enum SW_FT_Stroker_LineJoin_ + { + SW_FT_STROKER_LINEJOIN_ROUND = 0, + SW_FT_STROKER_LINEJOIN_BEVEL = 1, + SW_FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, + SW_FT_STROKER_LINEJOIN_MITER = SW_FT_STROKER_LINEJOIN_MITER_VARIABLE, + SW_FT_STROKER_LINEJOIN_MITER_FIXED = 3 + + } SW_FT_Stroker_LineJoin; + + + /************************************************************** + * + * @enum: + * SW_FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * SW_FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * SW_FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * SW_FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ + typedef enum SW_FT_Stroker_LineCap_ + { + SW_FT_STROKER_LINECAP_BUTT = 0, + SW_FT_STROKER_LINECAP_ROUND, + SW_FT_STROKER_LINECAP_SQUARE + + } SW_FT_Stroker_LineCap; + + + /************************************************************** + * + * @enum: + * SW_FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @SW_FT_Stroker_GetBorderCounts and @SW_FT_Stroker_ExportBorder. + * + * @values: + * SW_FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * SW_FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @SW_FT_Outline_GetInsideBorder and + * @SW_FT_Outline_GetOutsideBorder to get these. + */ + typedef enum SW_FT_StrokerBorder_ + { + SW_FT_STROKER_BORDER_LEFT = 0, + SW_FT_STROKER_BORDER_RIGHT + + } SW_FT_StrokerBorder; + + + /************************************************************** + * + * @function: + * SW_FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + SW_FT_Error + SW_FT_Stroker_New( SW_FT_Stroker *astroker ); + + + /************************************************************** + * + * @function: + * SW_FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the SW_FT_STROKER_LINEJOIN_MITER_FIXED and + * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles, + * expressed as 16.16 fixed-point value. + * + * @note: + * The radius is expressed in the same units as the outline + * coordinates. + */ + void + SW_FT_Stroker_Set( SW_FT_Stroker stroker, + SW_FT_Fixed radius, + SW_FT_Stroker_LineCap line_cap, + SW_FT_Stroker_LineJoin line_join, + SW_FT_Fixed miter_limit ); + + /************************************************************** + * + * @function: + * SW_FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @SW_FT_Stroker_GetCounts and @SW_FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If~1, the outline is treated as an open path instead + * of a closed one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened' is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct `border' outlines. + * + * If `opened' is~1, the outline is processed as an open path, and the + * stroker generates a single `stroke' outline. + * + * This function calls @SW_FT_Stroker_Rewind automatically. + */ + SW_FT_Error + SW_FT_Stroker_ParseOutline( SW_FT_Stroker stroker, + SW_FT_Outline* outline, + SW_FT_Bool opened ); + + + /************************************************************** + * + * @function: + * SW_FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ + SW_FT_Error + SW_FT_Stroker_GetCounts( SW_FT_Stroker stroker, + SW_FT_UInt *anum_points, + SW_FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * SW_FT_Stroker_Export + * + * @description: + * Call this function after @SW_FT_Stroker_GetBorderCounts to + * export all borders to your own @SW_FT_Outline structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + void + SW_FT_Stroker_Export( SW_FT_Stroker stroker, + SW_FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * SW_FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ + void + SW_FT_Stroker_Done( SW_FT_Stroker stroker ); + + +#endif // SW_FT_STROKER_H diff --git a/src/lib/ector/software/sw_ft_types.h b/src/lib/ector/software/sw_ft_types.h new file mode 100755 index 0000000000..1e8b865233 --- /dev/null +++ b/src/lib/ector/software/sw_ft_types.h @@ -0,0 +1,160 @@ +#ifndef SW_FT_TYPES_H +#define SW_FT_TYPES_H + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Fixed */ +/* */ +/* */ +/* This type is used to store 16.16 fixed-point values, like scaling */ +/* values or matrix coefficients. */ +/* */ +typedef signed long SW_FT_Fixed; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Int */ +/* */ +/* */ +/* A typedef for the int type. */ +/* */ +typedef signed int SW_FT_Int; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_UInt */ +/* */ +/* */ +/* A typedef for the unsigned int type. */ +/* */ +typedef unsigned int SW_FT_UInt; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Long */ +/* */ +/* */ +/* A typedef for signed long. */ +/* */ +typedef signed long SW_FT_Long; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_ULong */ +/* */ +/* */ +/* A typedef for unsigned long. */ +/* */ +typedef unsigned long SW_FT_ULong; + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Short */ +/* */ +/* */ +/* A typedef for signed short. */ +/* */ +typedef signed short SW_FT_Short; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Byte */ +/* */ +/* */ +/* A simple typedef for the _unsigned_ char type. */ +/* */ +typedef unsigned char SW_FT_Byte; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Bool */ +/* */ +/* */ +/* A typedef of unsigned char, used for simple booleans. As usual, */ +/* values 1 and~0 represent true and false, respectively. */ +/* */ +typedef unsigned char SW_FT_Bool; + + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Error */ +/* */ +/* */ +/* The FreeType error code type. A value of~0 is always interpreted */ +/* as a successful operation. */ +/* */ +typedef int SW_FT_Error; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Pos */ +/* */ +/* */ +/* The type SW_FT_Pos is used to store vectorial coordinates. Depending */ +/* on the context, these can represent distances in integer font */ +/* units, or 16.16, or 26.6 fixed-point pixel coordinates. */ +/* */ +typedef signed long SW_FT_Pos; + + +/*************************************************************************/ +/* */ +/* */ +/* SW_FT_Vector */ +/* */ +/* */ +/* A simple structure used to store a 2D vector; coordinates are of */ +/* the SW_FT_Pos type. */ +/* */ +/* */ +/* x :: The horizontal coordinate. */ +/* y :: The vertical coordinate. */ +/* */ +typedef struct SW_FT_Vector_ +{ + SW_FT_Pos x; + SW_FT_Pos y; + +} SW_FT_Vector; + + +typedef long long int SW_FT_Int64; +typedef unsigned long long int SW_FT_UInt64; + +typedef signed int SW_FT_Int32; +typedef unsigned int SW_FT_UInt32; + + +#define SW_FT_BOOL( x ) ( (SW_FT_Bool)( x ) ) + +#define SW_FT_SIZEOF_LONG 4 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +#endif // SW_FT_TYPES_H diff --git a/src/lib/edje/Edje_Legacy.h b/src/lib/edje/Edje_Legacy.h index 0525120763..e5e980045a 100644 --- a/src/lib/edje/Edje_Legacy.h +++ b/src/lib/edje/Edje_Legacy.h @@ -212,5 +212,42 @@ Edje object */ EAPI void edje_object_file_get(const Eo *obj, const char **file, const char **group); + +/** + * + * @brief Sets the @b EDJ file (and group within it) to load an Edje + * object's contents from + * + * @return @c EINA_TRUE, on success or @c EINA_FALSE, on errors (check + * edje_object_load_error_get() after this call to get errors causes) + * + * Edje expects EDJ files, which are theming objects' descriptions and + * resources packed together in an EET file, to read Edje object + * definitions from. They usually are created with the @c .edj + * extension. EDJ files, in turn, are assembled from @b textual object + * description files, where one describes Edje objects declaratively + * -- the EDC files (see @ref edcref "the syntax" for those files). + * + * Those description files were designed so that many Edje object + * definitions -- also called @b groups (or collections) -- could be + * packed together in the same EDJ file, so that a whole + * application's theme could be packed in one file only. This is the + * reason for the @p group argument. + * + * Use this function after you instantiate a new Edje object, so that + * you can "give him life", telling where to get its contents from. + * + * @see edje_object_add() + * @see edje_object_file_get() + * @see edje_object_mmap_set() + * @since 1.8 + * + * @param[in] file The Eina.File pointing to the EDJ file to load @p from + * @param[in] group The name of the group, in @p file, which implements an +Edje object + */ +EAPI Eina_Bool edje_object_mmap_set(Eo *obj, const Eina_File *file, const char *group); + + #include "edje_object.eo.legacy.h" #include "edje_edit.eo.legacy.h" diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index e9329d52ad..58f7633a99 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -1422,7 +1422,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc, if (!chosen_desc->text.min_x) { eo_do(ep->object, - evas_obj_size_set(TO_INT(params->eval.w), TO_INT(params->eval.h)), + efl_gfx_size_set(TO_INT(params->eval.w), TO_INT(params->eval.h)), evas_obj_textblock_size_formatted_get(&tw, &th)); } else @@ -1450,7 +1450,7 @@ _edje_part_recalc_single_textblock(FLOAT_T sc, if (!chosen_desc->text.max_x) { eo_do(ep->object, - evas_obj_size_set(TO_INT(params->eval.w), TO_INT(params->eval.h)), + efl_gfx_size_set(TO_INT(params->eval.w), TO_INT(params->eval.h)), evas_obj_textblock_size_formatted_get(&tw, &th)); } else @@ -1538,7 +1538,7 @@ _edje_part_recalc_single_text(FLOAT_T sc EINA_UNUSED, return; // Note: No need to add padding to that, it's already in the geometry - eo_do(ep->object, evas_obj_size_get(&mw, &mh)); + eo_do(ep->object, efl_gfx_size_get(&mw, &mh)); if (chosen_desc->text.max_x) { @@ -1698,7 +1698,7 @@ _edje_part_recalc_single_text(FLOAT_T sc EINA_UNUSED, eo_do(ep->object, evas_obj_text_style_set(style), evas_obj_text_set(text), - evas_obj_size_get(&tw, &th)); + efl_gfx_size_get(&tw, &th)); if (chosen_desc->text.max_x) { int l, r; @@ -2686,10 +2686,10 @@ _edje_proxy_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edj } eo_do(ep->object, - evas_obj_image_fill_set(p3->type.common.fill.x, - p3->type.common.fill.y, - p3->type.common.fill.w, - p3->type.common.fill.h), + efl_gfx_fill_set(p3->type.common.fill.x, + p3->type.common.fill.y, + p3->type.common.fill.w, + p3->type.common.fill.h), efl_image_smooth_scale_set(p3->smooth), evas_obj_image_source_visible_set(chosen_desc->proxy.source_visible), evas_obj_image_source_clip_set(chosen_desc->proxy.source_clip)); @@ -2727,9 +2727,9 @@ _edje_image_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edj } eo_do(ep->object, - evas_obj_image_fill_set(p3->type.common.fill.x, p3->type.common.fill.y, - p3->type.common.fill.w, p3->type.common.fill.h), - efl_image_smooth_scale_set(p3->smooth)); + efl_gfx_fill_set(p3->type.common.fill.x, p3->type.common.fill.y, + p3->type.common.fill.w, p3->type.common.fill.h), + efl_image_smooth_scale_set(p3->smooth)); if (chosen_desc->image.border.scale) { if (p3->type.common.spec.image.border_scale_by > FROM_DOUBLE(0.0)) @@ -3918,7 +3918,7 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta /* visibility and color have no meaning on SWALLOW and GROUP part. */ #ifdef HAVE_EPHYSICS eo_do(ep->object, - evas_obj_size_set(pf->final.w, pf->final.h)); + efl_gfx_size_set(pf->final.w, pf->final.h)); if ((ep->part->physics_body) && (!ep->body)) { if (_edje_physics_world_geometry_check(ed->world)) @@ -3936,19 +3936,19 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta } else eo_do(ep->object, - evas_obj_position_set(ed->x + pf->final.x, ed->y + pf->final.y)); + efl_gfx_position_set(ed->x + pf->final.x, ed->y + pf->final.y)); #else eo_do(ep->object, - evas_obj_position_set(ed->x + pf->final.x, ed->y + pf->final.y), - evas_obj_size_set(pf->final.w, pf->final.h)); + efl_gfx_position_set(ed->x + pf->final.x, ed->y + pf->final.y), + efl_gfx_size_set(pf->final.w, pf->final.h)); #endif if (ep->nested_smart) { /* Move, Resize all nested parts */ /* Not really needed but will improve the bounding box evaluation done by Evas */ eo_do(ep->nested_smart, - evas_obj_position_set(ed->x + pf->final.x, ed->y + pf->final.y), - evas_obj_size_set(pf->final.w, pf->final.h)); + efl_gfx_position_set(ed->x + pf->final.x, ed->y + pf->final.y), + efl_gfx_size_set(pf->final.w, pf->final.h)); } if (ep->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) _edje_entry_real_part_configure(ed, ep); @@ -4012,9 +4012,9 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta if (ep->part->type == EDJE_PART_TYPE_GROUP) vis = evas_object_visible_get(ed->obj); eo_do(ep->typedata.swallow->swallowed_object, - evas_obj_position_set(ed->x + pf->final.x, ed->y + pf->final.y), - evas_obj_size_set(pf->final.w, pf->final.h), - evas_obj_visibility_set(vis)); + efl_gfx_position_set(ed->x + pf->final.x, ed->y + pf->final.y), + efl_gfx_size_set(pf->final.w, pf->final.h), + efl_gfx_visible_set(vis)); } else evas_object_hide(ep->typedata.swallow->swallowed_object); mo = ep->typedata.swallow->swallowed_object; diff --git a/src/lib/edje/edje_object.eo b/src/lib/edje/edje_object.eo index ba8d9764a5..2653d72f65 100644 --- a/src/lib/edje/edje_object.eo +++ b/src/lib/edje/edje_object.eo @@ -182,43 +182,6 @@ class Edje.Object (Evas.Smart_Clipped, Efl.File) that means the edc file is made based on scale 1.0. */ } } - mmap { - set { - /*@ - @brief Sets the @b EDJ file (and group within it) to load an Edje - object's contents from - - @return @c EINA_TRUE, on success or @c EINA_FALSE, on errors (check - edje_object_load_error_get() after this call to get errors causes) - - Edje expects EDJ files, which are theming objects' descriptions and - resources packed together in an EET file, to read Edje object - definitions from. They usually are created with the @c .edj - extension. EDJ files, in turn, are assembled from @b textual object - description files, where one describes Edje objects declaratively - -- the EDC files (see @ref edcref "the syntax" for those files). - - Those description files were designed so that many Edje object - definitions -- also called @b groups (or collections) -- could be - packed together in the same EDJ file, so that a whole - application's theme could be packed in one file only. This is the - reason for the @p group argument. - - Use this function after you instantiate a new Edje object, so that - you can "give him life", telling where to get its contents from. - - @see edje_object_add() - @see edje_object_file_get() - @see edje_object_mmap_set() - @since 1.8 */ - return: bool; - } - values { - const(Eina.File)* file; /*@ The Eina.File pointing to the EDJ file to load @p from */ - const(char)* group; /*@ The name of the group, in @p file, which implements an - Edje object */ - } - } text_change_cb { set { /*@ @@ -2414,5 +2377,7 @@ class Edje.Object (Evas.Smart_Clipped, Efl.File) Evas.Object_Smart.resize; Efl.File.file.set; Efl.File.file.get; + Efl.File.mmap.set; + Efl.File.mmap.get; } } diff --git a/src/lib/edje/edje_smart.c b/src/lib/edje/edje_smart.c index 332b9586c9..0bf8399598 100644 --- a/src/lib/edje/edje_smart.c +++ b/src/lib/edje/edje_smart.c @@ -337,7 +337,8 @@ _edje_object_efl_file_file_set(Eo *obj, Edje *_pd EINA_UNUSED, const char *file, } EOLIAN static Eina_Bool -_edje_object_mmap_set(Eo *obj, Edje *_pd EINA_UNUSED, const Eina_File *f, const char *group) +_edje_object_efl_file_mmap_set(Eo *obj, Edje *pd EINA_UNUSED, + const Eina_File *f, const char *key) { Eina_Bool ret; Eina_Array *nested; @@ -346,7 +347,7 @@ _edje_object_mmap_set(Eo *obj, Edje *_pd EINA_UNUSED, const Eina_File *f, const nested = eina_array_new(8); - if (_edje_object_file_set_internal(obj, f, group, NULL, NULL, nested)) + if (_edje_object_file_set_internal(obj, f, key, NULL, NULL, nested)) ret = EINA_TRUE; eina_array_free(nested); @@ -355,6 +356,22 @@ _edje_object_mmap_set(Eo *obj, Edje *_pd EINA_UNUSED, const Eina_File *f, const return ret; } +EOLIAN static void +_edje_object_efl_file_mmap_get(Eo *obj EINA_UNUSED, Edje *pd, + const Eina_File **f, const char **key) +{ + if (f) *f = pd->file->f; + if (key) *key = pd->group; +} + +EAPI Eina_Bool +edje_object_mmap_set(Edje_Object *obj, const Eina_File *file, const char *group) +{ + Eina_Bool ret; + + return eo_do_ret((Edje_Object *)obj, ret, efl_file_mmap_set(file, group)); +} + EAPI Eina_Bool edje_object_file_set(Eo *obj, const char *file, const char *group) { @@ -370,4 +387,3 @@ edje_object_file_get(const Eo *obj, const char **file, const char **group) } #include "edje_object.eo.c" - diff --git a/src/lib/edje/edje_text.c b/src/lib/edje/edje_text.c index e95feb580d..057d6d0a6e 100644 --- a/src/lib/edje/edje_text.c +++ b/src/lib/edje/edje_text.c @@ -18,7 +18,7 @@ static inline void part_get_geometry(Edje_Real_Part *rp, Evas_Coord *w, Evas_Coord *h) { if (!rp->part->use_alternate_font_metrics) - eo_do(rp->object, evas_obj_size_get(w, h)); + eo_do(rp->object, efl_gfx_size_get(w, h)); else { if (w) *w = evas_object_text_horiz_advance_get(rp->object); @@ -100,7 +100,7 @@ _edje_text_fit_x(Edje *ed, Edje_Real_Part *ep, evas_obj_text_ellipsis_set(chosen_desc->text.min_x ? -1 : params->type.text.ellipsis), efl_text_properties_font_set(font, size), efl_text_set(text), - evas_obj_size_set(sw, sh)); + efl_gfx_size_set(sw, sh)); return text; } @@ -519,10 +519,10 @@ arrange_text: if (!calc_only) { eo_do(ep->object, - evas_obj_position_set(ed->x + TO_INT(params->eval.x) + ep->typedata.text->offset.x, - ed->y + TO_INT(params->eval.y) + ep->typedata.text->offset.y); + efl_gfx_position_set(ed->x + TO_INT(params->eval.x) + ep->typedata.text->offset.x, + ed->y + TO_INT(params->eval.y) + ep->typedata.text->offset.y); - evas_obj_visibility_set(params->visible)); + efl_gfx_visible_set(params->visible)); } diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h index f4cdedcf99..5a0b3eb949 100644 --- a/src/lib/efl/Efl.h +++ b/src/lib/efl/Efl.h @@ -34,6 +34,109 @@ extern "C" # endif #endif /* ! _WIN32 */ +/** + * These values determine how the points are interpreted in a stream of points. + * + * @since 1.14 + */ +typedef enum _Efl_Gfx_Path_Command +{ + EFL_GFX_PATH_COMMAND_TYPE_END = 0, /**< The end of stream , no more points to process. */ + EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO, /**< The next point is the start point of a sub path */ + EFL_GFX_PATH_COMMAND_TYPE_LINE_TO, /**< The next point is used to draw a line from current point */ + EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO, /**< The next three point is used to draw a cubic bezier curve from current point */ + EFL_GFX_PATH_COMMAND_TYPE_CLOSE, /**< Close the curent subpath by drawing a line between current point and the first point of current subpath */ + EFL_GFX_PATH_COMMAND_TYPE_LAST, /**< Not a valid command, but last one according to this version header */ +} Efl_Gfx_Path_Command; + +/** + * Type describing dash + * + * @see efl_gfx_shape_stroke_dash_set() + * + * @since 1.14 + */ +typedef struct _Efl_Gfx_Dash Efl_Gfx_Dash; +struct _Efl_Gfx_Dash +{ + double length; /**< dash drawing length */ + double gap; /**< distance bettwen two dashes */ +}; + +/** + * These values determine how the end of opened sub-paths are rendered in a + * stroke. + * + * @see efl_gfx_shape_stroke_cap_set() + * + * @since 1.14 + */ +typedef enum _Efl_Gfx_Cap +{ + EFL_GFX_CAP_BUTT = 0, /**< The end of lines is rendered as a full stop on the last point itself */ + EFL_GFX_CAP_ROUND, /**< The end of lines is rendered as a half-circle around the last point */ + EFL_GFX_CAP_SQUARE, /**< The end of lines is rendered as a square around the last point */ + EFL_GFX_CAP_LAST /**< End of enum value */ +} Efl_Gfx_Cap; + +/** + * These values determine how two joining lines are rendered in a stroker. + * + * @see efl_gfx_shape_stroke_join_set() + * + * @since 1.14 + */ +typedef enum _Efl_Gfx_Join +{ + EFL_GFX_JOIN_MITER = 0, /**< Used to render rounded line joins. Circular arcs are used to join two lines smoothly. */ + EFL_GFX_JOIN_ROUND, /**< Used to render beveled line joins. The outer corner of the joined lines is filled by enclosing the triangular region of the corner with a straight line between the outer corners of each stroke. */ + EFL_GFX_JOIN_BEVEL, /**< Used to render mitered line joins. The intersection of the strokes is clipped at a line perpendicular to the bisector of the angle between the strokes, at the distance from the intersection of the segments equal to the product of the miter limit value and the border radius. This prevents long spikes being created. */ + EFL_GFX_JOIN_LAST /**< End of enum value */ +} Efl_Gfx_Join; + +/** + * Type defining gradient stop. + * @since 1.14 + */ +typedef struct _Efl_Gfx_Gradient_Stop Efl_Gfx_Gradient_Stop; +struct _Efl_Gfx_Gradient_Stop +{ + double offset; /**< The location of the gradient stop within the gradient vector*/ + int r; /**< The component R color of the gradient stop */ + int g; /**< The component G color of the gradient stop */ + int b; /**< The component B color of the graident stop */ + int a; /**< The component A color of the graident stop */ +}; + +/** + * Specifies how the area outside the gradient area should be filled. + * + * @see efl_gfx_gradient_spread_set() + * + * @since 1.14 + */ +typedef enum _Efl_Gfx_Gradient_Spread +{ + EFL_GFX_GRADIENT_SPREAD_PAD, /**< The area is filled with the closest stop color. This is the default. */ + EFL_GFX_GRADIENT_SPREAD_REFLECT, /**< The gradient is reflected outside the gradient area. */ + EFL_GFX_GRADIENT_SPREAD_REPEAT, /**< The gradient is repeated outside the gradient area. */ + EFL_GFX_GRADIENT_SPREAD_LAST /**< End of enum value */ +} Efl_Gfx_Gradient_Spread; + +/** + * Type defining how an image content get filled. + * @since 1.14 + */ +typedef enum _Efl_Gfx_Fill_Spread +{ + EFL_GFX_FILL_REFLECT = 0, /**< image fill tiling mode - tiling reflects */ + EFL_GFX_FILL_REPEAT = 1, /**< tiling repeats */ + EFL_GFX_FILL_RESTRICT = 2, /**< tiling clamps - range offset ignored */ + EFL_GFX_FILL_RESTRICT_REFLECT = 3, /**< tiling clamps and any range offset reflects */ + EFL_GFX_FILL_RESTRICT_REPEAT = 4, /**< tiling clamps and any range offset repeats */ + EFL_GFX_FILL_PAD = 5 /**< tiling extends with end values */ +} Efl_Gfx_Fill_Spread; + #ifdef EFL_BETA_API_SUPPORT /* Interfaces */ @@ -44,6 +147,21 @@ extern "C" #include "interfaces/efl_text.eo.h" #include "interfaces/efl_text_properties.eo.h" +EAPI extern const Eo_Event_Description _EFL_GFX_CHANGED; +EAPI extern const Eo_Event_Description _EFL_GFX_PATH_CHANGED; + +#define EFL_GFX_CHANGED (&(_EFL_GFX_CHANGED)) +#define EFL_GFX_PATH_CHANGED (&(_EFL_GFX_PATH_CHANGED)) + +#include "interfaces/efl_gfx_base.eo.h" +#include "interfaces/efl_gfx_stack.eo.h" +#include "interfaces/efl_gfx_fill.eo.h" +#include "interfaces/efl_gfx_view.eo.h" +#include "interfaces/efl_gfx_shape.eo.h" +#include "interfaces/efl_gfx_gradient_base.eo.h" +#include "interfaces/efl_gfx_gradient_linear.eo.h" +#include "interfaces/efl_gfx_gradient_radial.eo.h" + #endif #if defined ( __cplusplus ) diff --git a/src/lib/efl/interfaces/efl_file.eo b/src/lib/efl/interfaces/efl_file.eo index 0265344c8d..887d96f408 100644 --- a/src/lib/efl/interfaces/efl_file.eo +++ b/src/lib/efl/interfaces/efl_file.eo @@ -1,6 +1,37 @@ interface Efl.File { legacy_prefix: null; properties { + mmap { + set { + /*@ + Set the source mmaped file from where an image object must fetch the real + image data (it must be an Eina_File). + + If the file supports multiple data stored in it (as Eet files do), + you can specify the key to be used as the index of the image in + this file. + + @since 1.8 */ + + return: bool; + } + get { + /*@ + Get the source mmaped file from where an image object must fetch the real + image data (it must be an Eina_File). + + If the file supports multiple data stored in it (as Eet files do), + you can get the key to be used as the index of the image in + this file. + + @since 1.10 */ + } + values { + const(Eina.File)* f; /*@ The mmaped file */ + const(char)* key; /*@ The image key in @p file (if its an Eet one), or @c + NULL, otherwise. */ + } + } file { set { /*@ diff --git a/src/lib/efl/interfaces/efl_gfx_base.eo b/src/lib/efl/interfaces/efl_gfx_base.eo new file mode 100644 index 0000000000..df9369c620 --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_base.eo @@ -0,0 +1,134 @@ +interface Efl.Gfx.Base { + legacy_prefix: null; + eo_prefix: efl_gfx; + properties { + position { + set { + /*@ Move the given Evas object to the given location inside its canvas' viewport. */ + } + get { + /*@ Retrieves the position of the given Evas object. */ + } + values { + int x; /*@ in */ + int y; /*@ in */ + } + } + size { + set { + /*@ Changes the size of the given Evas object. */ + } + get { + /*@ Retrieves the (rectangular) size of the given Evas object. */ + } + values { + int w; /*@ in */ + int h; /*@ in */ + } + } + color { + set { + /*@ + Sets the general/main color of the given Evas object to the given + one. + + @see evas_object_color_get() (for an example) + @note These color values are expected to be premultiplied by @p a. + + @ingroup Evas_Object_Group_Basic */ + } + get { + /*@ + Retrieves the general/main color of the given Evas object. + + Retrieves the “main” color's RGB component (and alpha channel) + values, which range from 0 to 255. For the alpha channel, + which defines the object's transparency level, 0 means totally + transparent, while 255 means opaque. These color values are + premultiplied by the alpha value. + + Usually you’ll use this attribute for text and rectangle objects, + where the “main” color is their unique one. If set for objects + which themselves have colors, like the images one, those colors get + modulated by this one. + + @note All newly created Evas rectangles get the default color + values of 255 255 255 255 (opaque white). + + @note Use @c NULL pointers on the components you're not interested + in: they'll be ignored by the function. + + Example: + @dontinclude evas-object-manipulation.c + @skip int alpha, r, g, b; + @until return + + See the full @ref Example_Evas_Object_Manipulation "example". + + @ingroup Evas_Object_Group_Basic */ + } + values { + int r; /*@ The red component of the given color. */ + int g; /*@ The green component of the given color. */ + int b; /*@ The blue component of the given color. */ + int a; /*@ The alpha component of the given color. */ + } + } + color_part { + set { + /*@ + Sets a specifc color of the given Efl.Gfx.Base object to the given + one. + + @see evas_object_color_get() (for an example) + @note These color values are expected to be premultiplied by @p a. + + */ + return: bool; + } + get { + /*@ + Retrieves a specific color of the given Evas object. + + Retrieves a specific color's RGB component (and alpha channel) + values, which range from 0 to 255. For the alpha channel, + which defines the object's transparency level, 0 means totally + transparent, while 255 means opaque. These color values are + premultiplied by the alpha value. + + The “main“ color being mapped to @c NULL. + + Usually you’ll use this attribute for text and rectangle objects, + where the “main” color is their unique one. If set for objects + which themselves have colors, like the images one, those colors get + modulated by this one. + + @note Use @c NULL pointers on the components you're not interested + in: they'll be ignored by the function. + + */ + return: bool; + } + keys { + const (char)* part; /*@ The part you are interested in. */ + } + values { + int r; /*@ The red component of the given color. */ + int g; /*@ The green component of the given color. */ + int b; /*@ The blue component of the given color. */ + int a; /*@ The alpha component of the given color. */ + } + } + visible { + set { + /*@ Makes the given Evas object visible or invisible. */ + } + get { + /*@ Retrieves whether or not the given Evas object is visible. */ + } + values { + bool v; /*@ @c EINA_TRUE if to make the object visible, @c EINA_FALSE otherwise */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_fill.eo b/src/lib/efl/interfaces/efl_gfx_fill.eo new file mode 100644 index 0000000000..1ce4dd8b57 --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_fill.eo @@ -0,0 +1,72 @@ +interface Efl.Gfx.Fill { + legacy_prefix: null; + properties { + fill_spread { + set { + /*@ + Sets the tiling mode for the given evas image object's fill. + EFL_GFX_FILL_RESTRICT, or EFL_GFX_FILL_PAD. */ + } + get { + /*@ + Retrieves the spread (tiling mode) for the given image object's + fill. + + @return The current spread mode of the image object. */ + } + values { + Efl_Gfx_Fill_Spread spread; /*@ One of EVAS_TEXTURE_REFLECT, EVAS_TEXTURE_REPEAT, */ + } + } + fill { + set { + /*@ + Set how to fill an image object's drawing rectangle given the + (real) image bound to it. + + Note that if @p w or @p h are smaller than the dimensions of + @p obj, the displayed image will be @b tiled around the object's + area. To have only one copy of the bound image drawn, @p x and @p y + must be 0 and @p w and @p h need to be the exact width and height + of the image object itself, respectively. + + See the following image to better understand the effects of this + call. On this diagram, both image object and original image source + have @c a x @c a dimensions and the image itself is a circle, with + empty space around it: + + @image html image-fill.png + @image rtf image-fill.png + @image latex image-fill.eps + + @warning The default values for the fill parameters are @p x = 0, + @p y = 0, @p w = 0 and @p h = 0. Thus, if you're not using the + evas_object_image_filled_add() helper and want your image + displayed, you'll have to set valid values with this function on + your object. + + @note evas_object_image_filled_set() is a helper function which + will @b override the values set here automatically, for you, in a + given way. */ + } + get { + /*@ + Retrieve how an image object is to fill its drawing rectangle, + given the (real) image bound to it. + + @note Use @c NULL pointers on the fill components you're not + interested in: they'll be ignored by the function. + + See @ref evas_object_image_fill_set() for more details. */ + } + values { + int x; /*@ The x coordinate (from the top left corner of the bound + image) to start drawing from. */ + int y; /*@ The y coordinate (from the top left corner of the bound + image) to start drawing from. */ + int w; /*@ The width the bound image will be displayed at. */ + int h; /*@ The height the bound image will be displayed at. */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_gradient_base.eo b/src/lib/efl/interfaces/efl_gfx_gradient_base.eo new file mode 100644 index 0000000000..b50d7bca1b --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_gradient_base.eo @@ -0,0 +1,38 @@ +interface Efl.Gfx.Gradient.Base +{ + eo_prefix: efl_gfx_gradient; + legacy_prefix: null; + properties { + stop { + set { + /*@ + Set the list of color stops for the gradient + */ + } + get { + /*@ + get the list of color stops. + */ + } + values { + const(Efl_Gfx_Gradient_Stop) *colors; /*@ color stops list*/ + uint length; /*@ length of the list */ + } + } + spread { + set { + /*@ + Specifies the spread method that should be used for this gradient. + */ + } + get { + /*@ + Returns the spread method use by this gradient. The default is EFL_GFX_GRADIENT_SPREAD_PAD. + */ + } + values { + Efl_Gfx_Gradient_Spread s; /*@ spread type to be used */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_gradient_linear.eo b/src/lib/efl/interfaces/efl_gfx_gradient_linear.eo new file mode 100644 index 0000000000..0d9299fe63 --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_gradient_linear.eo @@ -0,0 +1,38 @@ +interface Efl.Gfx.Gradient.Linear (Efl.Gfx.Gradient.Base) +{ + legacy_prefix: null; + properties { + start { + set { + /*@ + Sets the start point of this linear gradient. + */ + } + get { + /*@ + Gets the start point of this linear gradient. + */ + } + values { + double x; /*@ x co-ordinate of start point */ + double y; /*@ y co-ordinate of start point */ + } + } + end { + set { + /*@ + Sets the end point of this linear gradient. + */ + } + get { + /*@ + Gets the end point of this linear gradient. + */ + } + values { + double x; /*@ x co-ordinate of end point */ + double y; /*@ y co-ordinate of end point */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_gradient_radial.eo b/src/lib/efl/interfaces/efl_gfx_gradient_radial.eo new file mode 100644 index 0000000000..b9eeb72830 --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_gradient_radial.eo @@ -0,0 +1,53 @@ +interface Efl.Gfx.Gradient.Radial (Efl.Gfx.Gradient.Base) +{ + legacy_prefix: null; + properties { + center { + set { + /*@ + Sets the center of this radial gradient. + */ + } + get { + /*@ + Gets the center of this radial gradient. + */ + } + values { + double x; /*@ x co-ordinate of center point */ + double y; /*@ y co-ordinate of center point */ + } + } + radius { + set { + /*@ + Sets the center radius of this radial gradient. + */ + } + get { + /*@ + Gets the center radius of this radial gradient. + */ + } + values { + double r; /*@ center radius */ + } + } + focal { + set { + /*@ + Sets the focal point of this radial gradient. + */ + } + get { + /*@ + Gets the focal point of this radial gradient. + */ + } + values { + double x; /*@ x co-ordinate of focal point */ + double y; /*@ y co-ordinate of focal point */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_shape.c b/src/lib/efl/interfaces/efl_gfx_shape.c new file mode 100644 index 0000000000..efbc9d5ea9 --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_shape.c @@ -0,0 +1,1371 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include + +typedef struct _Efl_Gfx_Shape_Data Efl_Gfx_Shape_Data; +struct _Efl_Gfx_Shape_Data +{ + struct { + double x; + double y; + } current, current_ctrl; + + Efl_Gfx_Path_Command *commands; + double *points; + + unsigned int commands_count; + unsigned int points_count; +}; + +static inline unsigned int +_efl_gfx_path_command_length(Efl_Gfx_Path_Command command) +{ + switch (command) + { + case EFL_GFX_PATH_COMMAND_TYPE_END: return 0; + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: return 2; + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: return 2; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: return 6; + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: return 0; + case EFL_GFX_PATH_COMMAND_TYPE_LAST: return 0; + } + return 0; +} + +static inline void +_efl_gfx_path_length(const Efl_Gfx_Path_Command *commands, + unsigned int *cmd_length, + unsigned int *pts_length) +{ + if (commands) + while (commands[*cmd_length] != EFL_GFX_PATH_COMMAND_TYPE_END) + { + *pts_length += _efl_gfx_path_command_length(commands[*cmd_length]); + (*cmd_length)++; + } + + // Accounting for END command and handle gracefully the NULL case at the same time + (*cmd_length)++; +} + +static inline Eina_Bool +efl_gfx_path_grow(Efl_Gfx_Path_Command command, + Efl_Gfx_Shape_Data *pd, + double **offset_point) +{ + Efl_Gfx_Path_Command *cmd_tmp; + double *pts_tmp; + unsigned int cmd_length = 0, pts_length = 0; + + cmd_length = pd->commands_count ? pd->commands_count : 1; + pts_length = pd->points_count; + + if (_efl_gfx_path_command_length(command)) + { + pts_length += _efl_gfx_path_command_length(command); + pts_tmp = realloc(pd->points, pts_length * sizeof (double)); + if (!pts_tmp) return EINA_FALSE; + + pd->points = pts_tmp; + *offset_point = pd->points + + pts_length - _efl_gfx_path_command_length(command); + } + + cmd_tmp = realloc(pd->commands, + (cmd_length + 1) * sizeof (Efl_Gfx_Path_Command)); + if (!cmd_tmp) return EINA_FALSE; + pd->commands = cmd_tmp; + + pd->commands_count = cmd_length + 1; + pd->points_count = pts_length; + + // Append the command + cmd_tmp[cmd_length - 1] = command; + // NULL terminate the stream + cmd_tmp[cmd_length] = EFL_GFX_PATH_COMMAND_TYPE_END; + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_current_search(const Efl_Gfx_Path_Command *cmd, + const double *points, + double *current_x, double *current_y, + double *current_ctrl_x, double *current_ctrl_y) +{ + unsigned int i; + + if (current_x) *current_x = 0; + if (current_y) *current_y = 0; + if (current_ctrl_x) *current_ctrl_x = 0; + if (current_ctrl_y) *current_ctrl_y = 0; + if (!cmd || !points) return EINA_FALSE; + + for (i = 0; cmd[i] != EFL_GFX_PATH_COMMAND_TYPE_END; i++) + { + switch (cmd[i]) + { + case EFL_GFX_PATH_COMMAND_TYPE_END: + break; + case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO: + case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO: + if (current_x) *current_x = points[0]; + if (current_y) *current_y = points[1]; + + points += 2; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO: + if (current_x) *current_x = points[0]; + if (current_y) *current_y = points[1]; + if (current_ctrl_x) *current_ctrl_x = points[4]; + if (current_ctrl_y) *current_ctrl_y = points[5]; + + points += 6; + break; + case EFL_GFX_PATH_COMMAND_TYPE_CLOSE: + break; + case EFL_GFX_PATH_COMMAND_TYPE_LAST: + default: + return EINA_FALSE; + } + } + + return EINA_TRUE; +} + +static void +_efl_gfx_shape_path_set(Eo *obj, Efl_Gfx_Shape_Data *pd, + const Efl_Gfx_Path_Command *commands, + const double *points) +{ + Efl_Gfx_Path_Command *cmds; + double *pts; + unsigned int cmds_length = 0, pts_length = 0; + + if (!commands) + { + free(pd->commands); pd->commands = NULL; + free(pd->points); pd->points = NULL; + pd->current.x = pd->current.y = 0; + pd->current_ctrl.x = pd->current_ctrl.y = 0; + goto end; + } + + _efl_gfx_path_length(commands, &cmds_length, &pts_length); + + cmds = realloc(pd->commands, + sizeof (Efl_Gfx_Path_Command) * cmds_length); + if (!cmds) return ; + pd->commands = cmds; + + pts = realloc(pd->points, + sizeof (double) * pts_length); + if (!pts) return ; + pd->points = pts; + + pd->commands_count = cmds_length; + pd->points_count = pts_length; + + memcpy(pd->commands, commands, sizeof (Efl_Gfx_Path_Command) * cmds_length); + memcpy(pd->points, points, sizeof (double) * pts_length); + + _efl_gfx_path_current_search(pd->commands, pd->points, + &pd->current.x, &pd->current.y, + &pd->current_ctrl.x, &pd->current_ctrl.y); + + end: + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_path_get(Eo *obj EINA_UNUSED, Efl_Gfx_Shape_Data *pd, + const Efl_Gfx_Path_Command **commands, + const double **points) +{ + if (commands) *commands = pd->commands; + if (points) *points = pd->points; +} + +static void +_efl_gfx_shape_path_length_get(Eo *obj EINA_UNUSED, Efl_Gfx_Shape_Data *pd, + unsigned int *commands, unsigned int *points) +{ + if (commands) *commands = pd->commands_count; + if (points) *points = pd->points_count; +} + +static void +_efl_gfx_shape_bounds_get(Eo *obj EINA_UNUSED, + Efl_Gfx_Shape_Data *pd, + Eina_Rectangle *r) +{ + double minx, miny, maxx, maxy; + unsigned int i; + + EINA_RECTANGLE_SET(r, 0, 0, 0, 0); + + if (pd->points_count <= 0) return ; + + minx = pd->points[0]; + miny = pd->points[1]; + maxx = pd->points[0]; + maxy = pd->points[1]; + + for (i = 1; i < pd->points_count; i += 2) + { + minx = minx < pd->points[i] ? minx : pd->points[i]; + miny = miny < pd->points[i + 1] ? miny : pd->points[i + 1]; + maxx = maxx > pd->points[i] ? maxx : pd->points[i]; + maxy = maxy > pd->points[i + 1] ? maxy : pd->points[i + 1]; + } + + EINA_RECTANGLE_SET(r, + minx, miny, + maxx - minx, maxy - miny); +} + +static void +_efl_gfx_shape_current_get(Eo *obj EINA_UNUSED, Efl_Gfx_Shape_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->current.x; + if (y) *y = pd->current.y; +} + +static void +_efl_gfx_shape_current_ctrl_get(Eo *obj EINA_UNUSED, Efl_Gfx_Shape_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->current_ctrl.x; + if (y) *y = pd->current_ctrl.y; +} + +static Eina_Bool +_efl_gfx_shape_equal_commands_internal(Efl_Gfx_Shape_Data *a, + Efl_Gfx_Shape_Data *b) +{ + unsigned int i; + + if (a->commands_count != b->commands_count) return EINA_FALSE; + + for (i = 0; a->commands[i] == b->commands[i] && + a->commands[i] != EFL_GFX_PATH_COMMAND_TYPE_END; i++) + ; + + return (a->commands[i] == b->commands[i]); +} + +static inline double +interpolate(double from, double to, double pos_map) +{ + return (from * pos_map) + (to * (1.0 - pos_map)); +} + +static inline int +interpolatei(int from, int to, double pos_map) +{ + return (from * pos_map) + (to * (1.0 - pos_map)); +} + +typedef struct _Efl_Gfx_Property Efl_Gfx_Property; +struct _Efl_Gfx_Property +{ + double scale; + int r, g, b, a; + int fr, fg, fb, fa; + double w; + double centered; + const Efl_Gfx_Dash *dash; + unsigned int dash_length; + Efl_Gfx_Cap c; + Efl_Gfx_Join j; +}; + +static inline void +gfx_property_get(const Eo *obj, Efl_Gfx_Property *property) +{ + eo_do(obj, + property->scale = efl_gfx_shape_stroke_scale_get(), + efl_gfx_shape_stroke_color_get(&property->r, &property->g, &property->b, &property->a), + efl_gfx_color_get(&property->fr, &property->fg, &property->fb, &property->fa), + property->w = efl_gfx_shape_stroke_width_get(), + property->centered = efl_gfx_shape_stroke_location_get(), + efl_gfx_shape_stroke_dash_get(&property->dash, &property->dash_length), + property->c = efl_gfx_shape_stroke_cap_get(), + property->j = efl_gfx_shape_stroke_join_get()); +} + +static Eina_Bool +_efl_gfx_shape_interpolate(Eo *obj, Efl_Gfx_Shape_Data *pd, + const Eo *from, const Eo *to, double pos_map) +{ + Efl_Gfx_Shape_Data *from_pd, *to_pd; + Efl_Gfx_Path_Command *cmds; + double *pts, *from_pts, *to_pts; + unsigned int i, j; + Efl_Gfx_Property property_from, property_to; + Efl_Gfx_Dash *dash = NULL; + + from_pd = eo_data_scope_get(from, EFL_GFX_SHAPE_MIXIN); + to_pd = eo_data_scope_get(to, EFL_GFX_SHAPE_MIXIN); + if (!eo_isa(from, EFL_GFX_SHAPE_MIXIN) || + !eo_isa(to, EFL_GFX_SHAPE_MIXIN)) return EINA_FALSE; + if (pd == from_pd || pd == to_pd) return EINA_FALSE; + if (!_efl_gfx_shape_equal_commands_internal(from_pd, to_pd)) + return EINA_FALSE; + + gfx_property_get(from, &property_from); + gfx_property_get(to, &property_to); + + if (property_from.dash_length != property_to.dash_length) return EINA_FALSE; + + cmds = realloc(pd->commands, + sizeof (Efl_Gfx_Path_Command) * from_pd->commands_count); + if (!cmds && from_pd->commands_count) return EINA_FALSE; + pd->commands = cmds; + + pts = realloc(pd->points, + sizeof (double) * from_pd->points_count); + if (!pts && from_pd->points_count) return EINA_FALSE; + pd->points = pts; + + memcpy(cmds, from_pd->commands, + sizeof (Efl_Gfx_Path_Command) * from_pd->commands_count); + + to_pts = to_pd->points; + from_pts = from_pd->points; + + for (i = 0; cmds[i] != EFL_GFX_PATH_COMMAND_TYPE_END; i++) + for (j = 0; j < _efl_gfx_path_command_length(cmds[i]); j++) + { + *pts = interpolate(*from_pts, *to_pts, pos_map); + + pts++; + from_pts++; + to_pts++; + } + + pd->points_count = from_pd->points_count; + pd->commands_count = from_pd->commands_count; + + pd->current.x = interpolate(from_pd->current.x, + to_pd->current.x, + pos_map); + pd->current.y = interpolate(from_pd->current.y, + to_pd->current.y, + pos_map); + pd->current_ctrl.x = interpolate(from_pd->current_ctrl.x, + to_pd->current_ctrl.x, + pos_map); + pd->current_ctrl.y = interpolate(from_pd->current_ctrl.y, + to_pd->current_ctrl.y, + pos_map); + + if (property_to.dash_length) + { + dash = malloc(sizeof (Efl_Gfx_Dash) * property_to.dash_length); + if (!dash) return EINA_FALSE; + + for (i = 0; i < property_to.dash_length; i++) + { + dash[i].length = interpolate(property_from.dash[i].length, + property_to.dash[i].length, pos_map); + dash[i].gap = interpolate(property_from.dash[i].gap, + property_to.dash[i].gap, pos_map); + } + } + + + eo_do(obj, + efl_gfx_shape_stroke_scale_set(interpolate(property_to.scale, property_from.scale, pos_map)), + efl_gfx_shape_stroke_color_set(interpolatei(property_to.r, property_from.r, pos_map), + interpolatei(property_to.g, property_from.g, pos_map), + interpolatei(property_to.b, property_from.b, pos_map), + interpolatei(property_to.a, property_from.a, pos_map)), + efl_gfx_color_set(interpolatei(property_to.fr, property_from.fr, pos_map), + interpolatei(property_to.fg, property_from.fg, pos_map), + interpolatei(property_to.fb, property_from.fb, pos_map), + interpolatei(property_to.fa, property_from.fa, pos_map)), + efl_gfx_shape_stroke_width_set(interpolate(property_to.w, property_from.w, pos_map)), + efl_gfx_shape_stroke_location_set(interpolate(property_to.centered, property_from.centered, pos_map)), + efl_gfx_shape_stroke_dash_set(dash, property_to.dash_length), + efl_gfx_shape_stroke_cap_set(pos_map < 0.5 ? property_from.c : property_to.c), + efl_gfx_shape_stroke_join_set(pos_map < 0.5 ? property_from.j : property_to.j), + + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_shape_equal_commands(Eo *obj EINA_UNUSED, + Efl_Gfx_Shape_Data *pd, + const Eo *with) +{ + Efl_Gfx_Shape_Data *with_pd; + + with_pd = eo_data_scope_get(with, EFL_GFX_SHAPE_MIXIN); + if (!with_pd) return EINA_FALSE; + + return _efl_gfx_shape_equal_commands_internal(with_pd, pd); +} + +static void +_efl_gfx_shape_dup(Eo *obj, Efl_Gfx_Shape_Data *pd, Eo *dup_from) +{ + const Efl_Gfx_Dash *dash = NULL; + Efl_Gfx_Shape_Data *from; + unsigned int dash_length = 0; + Efl_Gfx_Cap cap; + Efl_Gfx_Join j; + int sr, sg, sb, sa; + double scale, location; + double sw; + + if (obj == dup_from) return ; + from = eo_data_scope_get(dup_from, EFL_GFX_SHAPE_MIXIN); + if (!from) return ; + + eo_do(dup_from, + scale = efl_gfx_shape_stroke_scale_get(), + efl_gfx_shape_stroke_color_get(&sr, &sg, &sb, &sa), + sw = efl_gfx_shape_stroke_width_get(), + location = efl_gfx_shape_stroke_location_get(), + efl_gfx_shape_stroke_dash_get(&dash, &dash_length), + cap = efl_gfx_shape_stroke_cap_get(), + j = efl_gfx_shape_stroke_join_get()); + eo_do(obj, + efl_gfx_shape_stroke_scale_set(scale), + efl_gfx_shape_stroke_color_set(sr, sg, sb, sa), + efl_gfx_shape_stroke_width_set(sw), + efl_gfx_shape_stroke_location_set(location), + efl_gfx_shape_stroke_dash_set(dash, dash_length), + efl_gfx_shape_stroke_cap_set(cap), + efl_gfx_shape_stroke_join_set(j)); + + _efl_gfx_shape_path_set(obj, pd, from->commands, from->points); + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_reset(Eo *obj, Efl_Gfx_Shape_Data *pd) +{ + free(pd->commands); + pd->commands = NULL; + pd->commands_count = 0; + + free(pd->points); + pd->points = NULL; + pd->points_count = 0; + + pd->current.x = 0; + pd->current.y = 0; + pd->current_ctrl.x = 0; + pd->current_ctrl.y = 0; + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_append_move_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y) +{ + double *offset_point; + + if (!efl_gfx_path_grow(EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO, + pd, &offset_point)) + return ; + + offset_point[0] = x; + offset_point[1] = y; + + pd->current.x = x; + pd->current.y = y; + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_append_line_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y) +{ + double *offset_point; + + if (!efl_gfx_path_grow(EFL_GFX_PATH_COMMAND_TYPE_LINE_TO, + pd, &offset_point)) + return ; + + offset_point[0] = x; + offset_point[1] = y; + + pd->current.x = x; + pd->current.y = y; + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_append_cubic_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, + double ctrl_x0, double ctrl_y0, + double ctrl_x1, double ctrl_y1) +{ + double *offset_point; + + if (!efl_gfx_path_grow(EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO, + pd, &offset_point)) + return ; + + offset_point[0] = x; + offset_point[1] = y; + offset_point[2] = ctrl_x0; + offset_point[3] = ctrl_y0; + offset_point[4] = ctrl_x1; + offset_point[5] = ctrl_y1; + + pd->current.x = x; + pd->current.y = y; + pd->current_ctrl.x = ctrl_x1; + pd->current_ctrl.y = ctrl_y1; + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_append_scubic_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, + double ctrl_x, double ctrl_y) +{ + double ctrl_x0, ctrl_y0; + double current_x = 0, current_y = 0; + double current_ctrl_x = 0, current_ctrl_y = 0; + + current_x = pd->current.x; + current_y = pd->current.x; + current_ctrl_x = pd->current_ctrl.x; + current_ctrl_y = pd->current_ctrl.y; + + ctrl_x0 = 2 * current_x - current_ctrl_x; + ctrl_y0 = 2 * current_y - current_ctrl_y; + + _efl_gfx_shape_append_cubic_to(obj, pd, x, y, + ctrl_x0, ctrl_y0, ctrl_x, ctrl_y); +} + +static void +_efl_gfx_shape_append_quadratic_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, + double ctrl_x, double ctrl_y) +{ + double current_x = 0, current_y = 0; + double ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1; + + current_x = pd->current.x; + current_y = pd->current.y; + + // Convert quadratic bezier to cubic + ctrl_x0 = (current_x + 2 * ctrl_x) * (1.0 / 3.0); + ctrl_y0 = (current_y + 2 * ctrl_y) * (1.0 / 3.0); + ctrl_x1 = (x + 2 * ctrl_x) * (1.0 / 3.0); + ctrl_y1 = (y + 2 * ctrl_y) * (1.0 / 3.0); + + _efl_gfx_shape_append_cubic_to(obj, pd, x, y, + ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1); +} + +static void +_efl_gfx_shape_append_squadratic_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y) +{ + double xc, yc; /* quadratic control point */ + double ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1; + double current_x = 0, current_y = 0; + double current_ctrl_x = 0, current_ctrl_y = 0; + + current_x = pd->current.x; + current_y = pd->current.x; + current_ctrl_x = pd->current_ctrl.x; + current_ctrl_y = pd->current_ctrl.y; + + xc = 2 * current_x - current_ctrl_x; + yc = 2 * current_y - current_ctrl_y; + /* generate a quadratic bezier with control point = xc, yc */ + ctrl_x0 = (current_x + 2 * xc) * (1.0 / 3.0); + ctrl_y0 = (current_y + 2 * yc) * (1.0 / 3.0); + ctrl_x1 = (x + 2 * xc) * (1.0 / 3.0); + ctrl_y1 = (y + 2 * yc) * (1.0 / 3.0); + + _efl_gfx_shape_append_cubic_to(obj, pd, x, y, + ctrl_x0, ctrl_y0, + ctrl_x1, ctrl_y1); +} + +/* + * code adapted from enesim which was adapted from moonlight sources + */ +static void +_efl_gfx_shape_append_arc_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, + double rx, double ry, + double angle, + Eina_Bool large_arc, Eina_Bool sweep) +{ + double cxp, cyp, cx, cy; + double sx, sy; + double cos_phi, sin_phi; + double dx2, dy2; + double x1p, y1p; + double x1p2, y1p2; + double rx2, ry2; + double lambda; + double c; + double at; + double theta1, delta_theta; + double nat; + double delta, bcp; + double cos_phi_rx, cos_phi_ry; + double sin_phi_rx, sin_phi_ry; + double cos_theta1, sin_theta1; + int segments, i; + + // some helpful stuff is available here: + // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + sx = pd->current.x; + sy = pd->current.y; + + // if start and end points are identical, then no arc is drawn + if ((fabs(x - sx) < (1 / 256.0)) && (fabs(y - sy) < (1 / 256.0))) + return; + + // Correction of out-of-range radii, see F6.6.1 (step 2) + rx = fabs(rx); + ry = fabs(ry); + if ((rx < 0.5) || (ry < 0.5)) + { + _efl_gfx_shape_append_line_to(obj, pd, x, y); + return; + } + + angle = angle * M_PI / 180.0; + cos_phi = cos(angle); + sin_phi = sin(angle); + dx2 = (sx - x) / 2.0; + dy2 = (sy - y) / 2.0; + x1p = cos_phi * dx2 + sin_phi * dy2; + y1p = cos_phi * dy2 - sin_phi * dx2; + x1p2 = x1p * x1p; + y1p2 = y1p * y1p; + rx2 = rx * rx; + ry2 = ry * ry; + lambda = (x1p2 / rx2) + (y1p2 / ry2); + + // Correction of out-of-range radii, see F6.6.2 (step 4) + if (lambda > 1.0) + { + // see F6.6.3 + double lambda_root = sqrt(lambda); + + rx *= lambda_root; + ry *= lambda_root; + // update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + } + + c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2); + + // check if there is no possible solution + // (i.e. we can't do a square root of a negative value) + if (c < 0.0) + { + // scale uniformly until we have a single solution + // (see F6.2) i.e. when c == 0.0 + double scale = sqrt(1.0 - c / (rx2 * ry2)); + rx *= scale; + ry *= scale; + // update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + + // step 2 (F6.5.2) - simplified since c == 0.0 + cxp = 0.0; + cyp = 0.0; + // step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0 + cx = 0.0; + cy = 0.0; + } + else + { + // complete c calculation + c = sqrt(c / ((rx2 * y1p2) + (ry2 * x1p2))); + // inverse sign if Fa == Fs + if (large_arc == sweep) + c = -c; + + // step 2 (F6.5.2) + cxp = c * ( rx * y1p / ry); + cyp = c * (-ry * x1p / rx); + + // step 3 (F6.5.3 first part) + cx = cos_phi * cxp - sin_phi * cyp; + cy = sin_phi * cxp + cos_phi * cyp; + } + + // step 3 (F6.5.3 second part) we now have the center point of the ellipse + cx += (sx + x) / 2.0; + cy += (sy + y) / 2.0; + + // step 4 (F6.5.4) + // we dont' use arccos (as per w3c doc), + // see http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm + // note: atan2 (0.0, 1.0) == 0.0 + at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx)); + theta1 = (at < 0.0) ? 2.0 * M_PI + at : at; + + nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx)); + delta_theta = (nat < at) ? 2.0 * M_PI - at + nat : nat - at; + + if (sweep) + { + // ensure delta theta < 0 or else add 360 degrees + if (delta_theta < 0.0) + delta_theta += 2.0 * M_PI; + } + else + { + // ensure delta theta > 0 or else substract 360 degrees + if (delta_theta > 0.0) + delta_theta -= 2.0 * M_PI; + } + + // add several cubic bezier to approximate the arc + // (smaller than 90 degrees) + // we add one extra segment because we want something + // smaller than 90deg (i.e. not 90 itself) + segments = (int) (fabs(delta_theta / M_PI_2)) + 1; + delta = delta_theta / segments; + + // http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13) + bcp = 4.0 / 3 * (1 - cos(delta / 2)) / sin(delta / 2); + + cos_phi_rx = cos_phi * rx; + cos_phi_ry = cos_phi * ry; + sin_phi_rx = sin_phi * rx; + sin_phi_ry = sin_phi * ry; + + cos_theta1 = cos(theta1); + sin_theta1 = sin(theta1); + + for (i = 0; i < segments; ++i) + { + // end angle (for this segment) = current + delta + double c1x, c1y, ex, ey, c2x, c2y; + double theta2 = theta1 + delta; + double cos_theta2 = cos(theta2); + double sin_theta2 = sin(theta2); + + // first control point (based on start point sx,sy) + c1x = sx - bcp * (cos_phi_rx * sin_theta1 + sin_phi_ry * cos_theta1); + c1y = sy + bcp * (cos_phi_ry * cos_theta1 - sin_phi_rx * sin_theta1); + + // end point (for this segment) + ex = cx + (cos_phi_rx * cos_theta2 - sin_phi_ry * sin_theta2); + ey = cy + (sin_phi_rx * cos_theta2 + cos_phi_ry * sin_theta2); + + // second control point (based on end point ex,ey) + c2x = ex + bcp * (cos_phi_rx * sin_theta2 + sin_phi_ry * cos_theta2); + c2y = ey + bcp * (sin_phi_rx * sin_theta2 - cos_phi_ry * cos_theta2); + + _efl_gfx_shape_append_cubic_to(obj, pd, ex, ey, c1x, c1y, c2x, c2y); + + // next start point is the current end point (same for angle) + sx = ex; + sy = ey; + theta1 = theta2; + // avoid recomputations + cos_theta1 = cos_theta2; + sin_theta1 = sin_theta2; + } +} + +static void +_efl_gfx_shape_append_close(Eo *obj, Efl_Gfx_Shape_Data *pd) +{ + double *offset_point; + + efl_gfx_path_grow(EFL_GFX_PATH_COMMAND_TYPE_CLOSE, + pd, &offset_point); + + eo_do(obj, + eo_event_callback_call(EFL_GFX_PATH_CHANGED, NULL), + eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +static void +_efl_gfx_shape_append_circle(Eo *obj, Efl_Gfx_Shape_Data *pd, + double xc, double yc, double radius) +{ + _efl_gfx_shape_append_move_to(obj, pd, xc - radius, yc); + _efl_gfx_shape_append_arc_to(obj, pd, xc + radius, yc, radius, radius, 0, EINA_TRUE, EINA_TRUE); + _efl_gfx_shape_append_arc_to(obj, pd, xc - radius, yc, radius, radius, 0, EINA_TRUE, EINA_TRUE); +} + +static void +_efl_gfx_shape_append_rect(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, double w, double h, + double rx, double ry) +{ + // clamp the x and y radius value. + if (rx > w/2) rx = w/2; + if (ry > h/2) ry = h/2; + + _efl_gfx_shape_append_move_to(obj, pd, x, y + ry); + // Top left corner + _efl_gfx_shape_append_arc_to(obj, pd, x + rx, y, rx, ry, 0, EINA_FALSE, EINA_TRUE); + _efl_gfx_shape_append_line_to(obj, pd, x + w - rx, y); + // Top right corner + _efl_gfx_shape_append_arc_to(obj, pd, x + w, y + ry, rx, ry, 0, EINA_FALSE, EINA_TRUE); + _efl_gfx_shape_append_line_to(obj, pd, x + w, y + h - ry); + // Bottom right corner + _efl_gfx_shape_append_arc_to(obj, pd, x + w - rx, y + h, rx, ry, 0, EINA_FALSE, EINA_TRUE); + _efl_gfx_shape_append_line_to(obj, pd, x + rx, y + h); + // Bottom left corner + _efl_gfx_shape_append_arc_to(obj, pd, x, y + h - ry, rx, ry, 0, EINA_FALSE, EINA_TRUE); + _efl_gfx_shape_append_close(obj, pd); +} + +static void +_efl_gfx_path_append_horizontal_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double d, double current_x EINA_UNUSED, double current_y) +{ + _efl_gfx_shape_append_line_to(obj, pd, d, current_y); +} + +static void +_efl_gfx_path_append_vertical_to(Eo *obj, Efl_Gfx_Shape_Data *pd, + double d, double current_x, double current_y EINA_UNUSED) +{ + _efl_gfx_shape_append_line_to(obj, pd, current_x, d); +} + +static char * +_strcomma(const char *content) +{ + while (*content && isspace(*content)) content++; + if (*content != ',') return NULL; + return (char*) content + 1; +} + +static inline Eina_Bool +_next_isnumber(const char *content) +{ + char *tmp = NULL; + + (void) strtod(content, &tmp); + return content != tmp; +} + +static Eina_Bool +_efl_gfx_path_parse_pair(const char *content, char **end, double *x, double *y) +{ + /* "x,y" */ + char *end1 = NULL; + char *end2 = NULL; + + *x = strtod(content, &end1); + end1 = _strcomma(end1); + if (!end1) return EINA_FALSE; + *y = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *end = end2; + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_pair_to(const char *content, char **end, + Eo *obj, Efl_Gfx_Shape_Data *pd, + double *current_x, double *current_y, + void (*func)(Eo *obj, Efl_Gfx_Shape_Data *pd, double x, double y), + Eina_Bool rel) +{ + double x, y; + + *end = (char*) content; + do + { + Eina_Bool r; + + r = _efl_gfx_path_parse_pair(content, end, &x, &y); + if (!r) return EINA_FALSE; + + if (rel) + { + x += *current_x; + y += *current_y; + } + + func(obj, pd, x, y); + content = *end; + + *current_x = x; + *current_y = y; + } + while (_next_isnumber(content)); + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_double_to(const char *content, char **end, + Eo *obj, Efl_Gfx_Shape_Data *pd, + double *current, double current_x, double current_y, + void (*func)(Eo *obj, Efl_Gfx_Shape_Data *pd, double d, double current_x, double current_y), + Eina_Bool rel) +{ + double d; + Eina_Bool first = EINA_FALSE; + + *end = (char*) content; + do + { + d = strtod(content, end); + if (content == *end) + return first; + first = EINA_TRUE; + + if (rel) + { + d += *current; + } + + func(obj, pd, d, current_x, current_y); + content = *end; + + *current = d; + } + while (1); // This is an optimisation as we have only one parameter. + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_six(const char *content, char **end, + double *x, double *y, + double *ctrl_x0, double *ctrl_y0, + double *ctrl_x1, double *ctrl_y1) +{ + /* "x,y ctrl_x0,ctrl_y0 ctrl_x1,ctrl_y1" */ + char *end1 = NULL; + char *end2 = NULL; + + *ctrl_x0 = strtod(content, &end1); + end1 = _strcomma(end1); + if (!end1) return EINA_FALSE; + *ctrl_y0 = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *ctrl_x1 = strtod(end2, &end2); + end2 = _strcomma(end2); + if (!end2) return EINA_FALSE; + *ctrl_y1 = strtod(end2, &end1); + if (end1 == end2) return EINA_FALSE; + + *x = strtod(end1, &end2); + end2 = _strcomma(end2); + if (!end2) return EINA_FALSE; + *y = strtod(end2, &end1); + if (end1 == end2) return EINA_FALSE; + + *end = end1; + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_six_to(const char *content, char **end, + Eo *obj, Efl_Gfx_Shape_Data *pd, + double *current_x, double *current_y, + void (*func)(Eo *obj, Efl_Gfx_Shape_Data *pd, double x, double y, double ctrl_x0, double ctrl_y0, double ctrl_x1, double ctrl_y1), + Eina_Bool rel) +{ + double x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1; + + *end = (char*) content; + do + { + Eina_Bool r; + + r = _efl_gfx_path_parse_six(content, end, + &x, &y, + &ctrl_x0, &ctrl_y0, + &ctrl_x1, &ctrl_y1); + if (!r) return EINA_FALSE; + + if (rel) + { + x += *current_x; + y += *current_y; + } + + func(obj, pd, x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1); + content = *end; + + *current_x = x; + *current_y = y; + } + while (_next_isnumber(content)); + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_quad(const char *content, char **end, + double *x, double *y, + double *ctrl_x0, double *ctrl_y0) +{ + /* "x,y ctrl_x0,ctrl_y0" */ + char *end1 = NULL; + char *end2 = NULL; + + *ctrl_x0 = strtod(content, &end1); + end1 = _strcomma(end1); + if (!end1) return EINA_FALSE; + *ctrl_y0 = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *x = strtod(end2, &end1); + end1 = _strcomma(end2); + if (!end1) return EINA_FALSE; + *y = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *end = end2; + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_quad_to(const char *content, char **end, + Eo *obj, Efl_Gfx_Shape_Data *pd, + double *current_x, double *current_y, + void (*func)(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, double ctrl_x0, double ctrl_y0), + Eina_Bool rel) +{ + double x, y, ctrl_x0, ctrl_y0; + + *end = (char*) content; + do + { + Eina_Bool r; + + r = _efl_gfx_path_parse_quad(content, end, + &x, &y, + &ctrl_x0, &ctrl_y0); + if (!r) return EINA_FALSE; + + if (rel) + { + x += *current_x; + y += *current_y; + } + + func(obj, pd, x, y, ctrl_x0, ctrl_y0); + content = *end; + + *current_x = x; + *current_y = y; + } + while (_next_isnumber(content)); + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_arc(const char *content, char **end, + double *x, double *y, + double *rx, double *ry, + double *radius, + Eina_Bool *large_arc, Eina_Bool *sweep) +{ + /* "rx,ry r large-arc-flag,sweep-flag x,y" */ + char *end1 = NULL; + char *end2 = NULL; + + *rx = strtod(content, &end1); + end1 = _strcomma(end1); + if (!end1) return EINA_FALSE; + *ry = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *radius = strtod(end2, &end1); + if (end1 == end2) return EINA_FALSE; + + *large_arc = strtol(end1, &end2, 10) ? EINA_TRUE : EINA_FALSE; + end1 = _strcomma(end2); + if (!end1) return EINA_FALSE; + *sweep = strtol(end1, &end2, 10) ? EINA_TRUE : EINA_FALSE; + if (end1 == end2) return EINA_FALSE; + + *x = strtod(end2, &end1); + end1 = _strcomma(end2); + if (!end1) return EINA_FALSE; + *y = strtod(end1, &end2); + if (end1 == end2) return EINA_FALSE; + + *end = end2; + + return EINA_TRUE; +} + +static Eina_Bool +_efl_gfx_path_parse_arc_to(const char *content, char **end, + Eo *obj, Efl_Gfx_Shape_Data *pd, + double *current_x, double *current_y, + void (*func)(Eo *obj, Efl_Gfx_Shape_Data *pd, + double x, double y, double rx, double ry, double angle, + Eina_Bool large_arc, Eina_Bool sweep), + Eina_Bool rel) +{ + double x, y, rx, ry, angle; + Eina_Bool large_arc, sweep; // FIXME: handle those flag + + *end = (char*) content; + do + { + Eina_Bool r; + + r = _efl_gfx_path_parse_arc(content, end, + &x, &y, + &rx, &ry, + &angle, + &large_arc, &sweep); + if (!r) return EINA_FALSE; + + if (rel) + { + x += *current_x; + y += *current_y; + } + + func(obj, pd, x, y, rx, ry, angle, large_arc, sweep); + content = *end; + + *current_x = x; + *current_y = y; + } + while (_next_isnumber(content)); + + return EINA_TRUE; +} + +static void +_efl_gfx_shape_append_svg_path(Eo *obj, Efl_Gfx_Shape_Data *pd, + const char *svg_path_data) +{ + double current_x = 0, current_y = 0; + char *content = (char*) svg_path_data; + + if (!content) return ; + + while (content[0] != '\0') + { + while (isspace(content[0])) content++; + + switch (content[0]) + { + case 'M': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_move_to, + EINA_FALSE)) + return ; + break; + case 'm': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_move_to, + EINA_TRUE)) + return ; + break; + case 'z': + case 'Z': + _efl_gfx_shape_append_close(obj, pd); + content++; + break; + case 'L': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_line_to, + EINA_FALSE)) + return ; + break; + case 'l': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_line_to, + EINA_TRUE)) + return ; + break; + case 'H': + if (!_efl_gfx_path_parse_double_to(&content[1], + &content, + obj, pd, + ¤t_x, current_x, current_y, + _efl_gfx_path_append_horizontal_to, + EINA_FALSE)) + return ; + break; + case 'h': + if (!_efl_gfx_path_parse_double_to(&content[1], + &content, + obj, pd, + ¤t_x, current_x, current_y, + _efl_gfx_path_append_horizontal_to, + EINA_TRUE)) + return ; + break; + case 'V': + if (!_efl_gfx_path_parse_double_to(&content[1], + &content, + obj, pd, + ¤t_y, current_x, current_y, + _efl_gfx_path_append_vertical_to, + EINA_FALSE)) + return ; + break; + case 'v': + if (!_efl_gfx_path_parse_double_to(&content[1], + &content, + obj, pd, + ¤t_y, current_x, current_y, + _efl_gfx_path_append_vertical_to, + EINA_TRUE)) + return ; + break; + case 'C': + if (!_efl_gfx_path_parse_six_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_cubic_to, + EINA_FALSE)) + return ; + break; + case 'c': + if (!_efl_gfx_path_parse_six_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_cubic_to, + EINA_TRUE)) + return ; + break; + case 'S': + if (!_efl_gfx_path_parse_quad_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_scubic_to, + EINA_FALSE)) + return ; + break; + case 's': + if (!_efl_gfx_path_parse_quad_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_scubic_to, + EINA_TRUE)) + return ; + break; + case 'Q': + if (!_efl_gfx_path_parse_quad_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_quadratic_to, + EINA_FALSE)) + return ; + break; + case 'q': + if (!_efl_gfx_path_parse_quad_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_quadratic_to, + EINA_TRUE)) + return ; + break; + case 'T': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_squadratic_to, + EINA_FALSE)) + return ; + break; + case 't': + if (!_efl_gfx_path_parse_pair_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_squadratic_to, + EINA_TRUE)) + return ; + break; + case 'A': + if (!_efl_gfx_path_parse_arc_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_arc_to, + EINA_FALSE)) + return ; + break; + case 'a': + if (!_efl_gfx_path_parse_arc_to(&content[1], + &content, + obj, pd, + ¤t_x, ¤t_y, + _efl_gfx_shape_append_arc_to, + EINA_TRUE)) + return ; + break; + default: + return ; + } + } +} + +#include "interfaces/efl_gfx_shape.eo.c" diff --git a/src/lib/efl/interfaces/efl_gfx_shape.eo b/src/lib/efl/interfaces/efl_gfx_shape.eo new file mode 100644 index 0000000000..37d0abd3ec --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_shape.eo @@ -0,0 +1,405 @@ +mixin Efl.Gfx.Shape +{ + legacy_prefix: null; + properties { + stroke_scale { + set { + /*@ + Sets the stroke scale to be used for stroking the path. + the scale property will be used along with stroke width property. + @since 1.14 + */ + } + get { + /*@ + Get the stroke scaling factor used for stroking this path. + @since 1.14 + */ + } + values { + double s; /*@ stroke scale value */ + } + } + stroke_color { + set { + /*@ + Sets the color to be used for stroking the path. + @since 1.14 + */ + } + get { + /*@ + Gets the color used for stroking the path. + @since 1.14 + */ + } + values { + int r; /*@ The red component of the given color. */ + int g; /*@ The green component of the given color. */ + int b; /*@ The blue component of the given color. */ + int a; /*@ The alpha component of the given color. */ + } + } + stroke_width { + set { + /*@ + Sets the stroke width to be used for stroking the path. + @since 1.14 + */ + } + get { + /*@ + Gets the stroke width to be used for stroking the path. + @since 1.14 + */ + } + values { + double w; /*@ stroke width to be used */ + } + } + stroke_location { + set { + /*@ + Not Implemented + */ + } + get { + /*@ + Not Implemented + */ + } + values { + double centered; /*@ */ + } + } + stroke_dash { + set { + /*@ + Not Implemented + */ + } + get { + /*@ + Not Implemented + */ + } + values { + const(Efl_Gfx_Dash) *dash; /*@ */ + uint length; /*@ */ + } + } + stroke_cap { + set { + /*@ + Sets the cap style to be used for stroking the path. + The cap will be used for capping the end point of a + open subpath. + + @see Efl_Gfx_Cap + @since 1.14 + */ + } + get { + /*@ + Gets the cap style used for stroking path. + @since 1.14 + */ + } + values { + Efl_Gfx_Cap c; /*@ cap style to use , default is EFL_GFX_CAP_BUTT */ + } + } + stroke_join { + set { + /*@ + Sets the join style to be used for stroking the path. + The join style will be used for joining the two line segment + while stroking teh path. + + @see Efl_Gfx_Join + @since 1.14 + */ + } + get { + /*@ + Gets the join style used for stroking path. + @since 1.14 + */ + } + values { + Efl_Gfx_Join j; /*@ join style to use , default is + EFL_GFX_JOIN_MITER */ + } + } + path { + set { + /*@ + Set the list of commands and points to be used to create the + content of shape. + + @note see efl_gfx_path interface for how to create a command list. + @see Efl_Gfx_Path_Command + @since 1.14 + */ + } + get { + /*@ + Gets the command and points list + @since 1.14 + */ + } + values { + const(Efl_Gfx_Path_Command) *op; /*@ command list */ + const(double) *points; /*@ point list */ + } + } + path_length { + get { + } + values { + uint commands; + uint points; + } + } + current { + get { + } + values { + double x; + double y; + } + } + current_ctrl { + get { + } + values { + double x; + double y; + } + } + } + methods { + dup { + /*@ + Copy the shape data from the object specified . + + @since 1.14 + */ + params { + @in Eo *dup_from; /*@ Shape object from where data will be copied.*/ + } + } + bounds_get { + /*@ + Compute and return the bounding box of the currently set path + + @since 1.14 + */ + params { + @out Eina_Rectangle r; /*@ Contain the bounding box of the currently set path */ + } + } + reset { + /*@ + Reset the shape data of the shape object. + + @since 1.14 + */ + } + append_move_to { + /*@ + Moves the current point to the given point, + implicitly starting a new subpath and closing the previous one. + + @see efl_gfx_path_append_close() + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of the current point.*/ + @in double y; /*@ Y co-ordinate of the current point.*/ + } + } + append_line_to { + /*@ + Adds a straight line from the current position to the given endPoint. + After the line is drawn, the current position is updated to be at the end + point of the line. + + @note if no current position present, it draws a line to itself, basically + a point. + + @see efl_gfx_path_append_move_to() + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the line.*/ + @in double y; /*@ Y co-ordinate of end point of the line.*/ + } + } + append_quadratic_to { + /*@ + Adds a quadratic Bezier curve between the current position and the + given end point (x,y) using the control points specified by (ctrl_x, ctrl_y). + After the path is drawn, the current position is updated to be at the end + point of the path. + + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the line.*/ + @in double y; /*@ Y co-ordinate of end point of the line.*/ + @in double ctrl_x; /*@ X co-ordinate of control point.*/ + @in double ctrl_y; /*@ Y co-ordinate of control point.*/ + } + } + append_squadratic_to { + /*@ + Same as efl_gfx_path_append_quadratic_to() api only difference is that it + uses the current control point to draw the bezier. + + @see efl_gfx_path_append_quadratic_to() + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the line.*/ + @in double y; /*@ Y co-ordinate of end point of the line.*/ + } + } + append_cubic_to { + /*@ + Adds a cubic Bezier curve between the current position and the + given end point (x,y) using the control points specified by + (ctrl_x0, ctrl_y0), and (ctrl_x1, ctrl_y1). After the path is drawn, + the current position is updated to be at the end point of the path. + + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the line.*/ + @in double y; /*@ Y co-ordinate of end point of the line.*/ + @in double ctrl_x0; /*@ X co-ordinate of 1st control point.*/ + @in double ctrl_y0; /*@ Y co-ordinate of 1st control point.*/ + @in double ctrl_x1; /*@ X co-ordinate of 2nd control point.*/ + @in double ctrl_y1; /*@ Y co-ordinate of 2nd control point.*/ + } + } + append_scubic_to { + /*@ + Same as efl_gfx_path_append_cubic_to() api only difference is that it uses + the current control point to draw the bezier. + + @see efl_gfx_path_append_cubic_to() + + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the line.*/ + @in double y; /*@ Y co-ordinate of end point of the line.*/ + @in double ctrl_x; /*@ X co-ordinate of 2nd control point.*/ + @in double ctrl_y; /*@ Y co-ordinate of 2nd control point.*/ + } + } + append_arc_to { + /*@ + Append an arc that connects from the current point int the point list + to the given point (x,y). The arc is defined by the given radius in + x-direction (rx) and radius in y direction (ry) . + + @note Use this api if you know the end point's of the arc otherwise + use more convenient function efl_gfx_path_append_arc_to() + + @see efl_gfx_path_append_arc_to() + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of end point of the arc.*/ + @in double y; /*@ Y co-ordinate of end point of the arc.*/ + @in double rx; /*@ radius of arc in x direction.*/ + @in double ry; /*@ radius of arc in y direction.*/ + @in double angle; /*@ x-axis rotation , normally 0.*/ + @in bool large_arc; /*@ Defines whether to draw the larger arc or smaller arc joining two point.*/ + @in bool sweep; /*@ Defines whether the arc will be drawn counter-clockwise or clockwise from current point to the end point taking into account the large_arc property.*/ + } + } + append_close { + /*@ + Closes the current subpath by drawing a line to the beginning of the subpath, + automatically starting a new path. The current point of the new path is + (0, 0). + + @note If the subpath does not contain any points, this function does nothing. + + @since 1.14 + */ + } + append_circle { + /*@ + Append a circle with given center and radius. + + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of the center of the circle.*/ + @in double y; /*@ Y co-ordinate of the center of the circle.*/ + @in double radius; /*@ radius of the circle.*/ + } + } + append_rect { + /*@ + Append the given rectangle with rounded corner to the path. + + The xr and yr arguments specify the radii of the ellipses defining the + corners of the rounded rectangle. + + @note xr and yr are specified in terms of width and height respectively. + + @note if xr and yr are 0, then it will draw a rectangle without rounded corner. + + @since 1.14 + */ + params { + @in double x; /*@ X co-ordinate of the rectangle.*/ + @in double y; /*@ Y co-ordinate of the rectangle.*/ + @in double w; /*@ Width of the rectangle.*/ + @in double h; /*@ Height of the rectangle.*/ + @in double rx; /*@ The x radius of the rounded corner and should be in range [ 0 to w/2 ]*/ + @in double ry; /*@ The y radius of the rounded corner and should be in range [ 0 to h/2 ]*/ + } + } + append_svg_path { + params { + @in const(char)* svg_path_data; + } + } + interpolate { + return: bool; + params { + @in const(Eo)* from; + @in const(Eo)* to; + @in double pos_map; + } + } + equal_commands { + return: bool; + params { + @in const(Eo)* with; + } + } + } + implements { + @virtual .stroke_scale.get; + @virtual .stroke_scale.set; + @virtual .stroke_color.get; + @virtual .stroke_color.set; + @virtual .stroke_width.get; + @virtual .stroke_width.set; + @virtual .stroke_location.get; + @virtual .stroke_location.set; + @virtual .stroke_dash.get; + @virtual .stroke_dash.set; + @virtual .stroke_cap.get; + @virtual .stroke_cap.set; + @virtual .stroke_join.get; + @virtual .stroke_join.set; + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_stack.eo b/src/lib/efl/interfaces/efl_gfx_stack.eo new file mode 100644 index 0000000000..a104d0d4ed --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_stack.eo @@ -0,0 +1,154 @@ +interface Efl.Gfx.Stack { + legacy_prefix: null; + properties { + layer { + set { + /*@ + Sets the layer of its canvas that the given object will be part of. + + If you don't use this function, you'll be dealing with an @b unique + layer of objects, the default one. Additional layers are handy when + you don't want a set of objects to interfere with another set with + regard to @b stacking. Two layers are completely disjoint in that + matter. + + This is a low-level function, which you'd be using when something + should be always on top, for example. + + @warning Be careful, it doesn't make sense to change the layer of + smart objects' children. Smart objects have a layer of their own, + which should contain all their children objects. + + @see evas_object_layer_get() */ + } + get { + /*@ + Retrieves the layer of its canvas that the given object is part of. + + @return Number of its layer + + @see evas_object_layer_set() */ + } + values { + short l; /*@ The number of the layer to place the object on. + Must be between #EVAS_LAYER_MIN and #EVAS_LAYER_MAX. */ + } + } + below { + get { + /*@ + Get the Evas object stacked right below @p obj + + @return the #Efl_Gfx_Stack directly below @p obj, if any, or @c NULL, + if none + + This function will traverse layers in its search, if there are + objects on layers below the one @p obj is placed at. + + @see evas_object_layer_get() + @see evas_object_layer_set() + @see evas_object_below_get() */ + return: Efl_Gfx_Stack * @warn_unused; + } + } + above { + get { + /*@ + Get the Evas object stacked right above @p obj + + @return the #Efl_Gfx_Stack directly above @p obj, if any, or @c NULL, + if none + + This function will traverse layers in its search, if there are + objects on layers above the one @p obj is placed at. + + @see evas_object_layer_get() + @see evas_object_layer_set() + @see evas_object_below_get() */ + return: Efl_Gfx_Stack * @warn_unused; + } + } + } + methods { + stack_below { + /*@ + Stack @p obj immediately below @p below + + Objects, in a given canvas, are stacked in the order they get added + to it. This means that, if they overlap, the highest ones will + cover the lowest ones, in that order. This function is a way to + change the stacking order for the objects. + + This function is intended to be used with objects belonging to + the same layer in a given canvas, otherwise it will fail (and + accomplish nothing). + + If you have smart objects on your canvas and @p obj is a member of + one of them, then @p below must also be a member of the same + smart object. + + Similarly, if @p obj is not a member of a smart object, @p below + must not be either. + + @see evas_object_layer_get() + @see evas_object_layer_set() + @see evas_object_stack_below() */ + + params { + @in Efl_Gfx_Stack *below @nonull; /*@ the object below which to stack */ + } + } + raise { + /*@ + Raise @p obj to the top of its layer. + + @p obj will, then, be the highest one in the layer it belongs + to. Object on other layers won't get touched. + + @see evas_object_stack_above() + @see evas_object_stack_below() + @see evas_object_lower() */ + + } + stack_above { + /*@ + Stack @p obj immediately above @p above + + Objects, in a given canvas, are stacked in the order they get added + to it. This means that, if they overlap, the highest ones will + cover the lowest ones, in that order. This function is a way to + change the stacking order for the objects. + + This function is intended to be used with objects belonging to + the same layer in a given canvas, otherwise it will fail (and + accomplish nothing). + + If you have smart objects on your canvas and @p obj is a member of + one of them, then @p above must also be a member of the same + smart object. + + Similarly, if @p obj is not a member of a smart object, @p above + must not be either. + + @see evas_object_layer_get() + @see evas_object_layer_set() + @see evas_object_stack_below() */ + + params { + @in Efl_Gfx_Stack *above @nonull; /*@ the object above which to stack */ + } + } + lower { + /*@ + Lower @p obj to the bottom of its layer. + + @p obj will, then, be the lowest one in the layer it belongs + to. Objects on other layers won't get touched. + + @see evas_object_stack_above() + @see evas_object_stack_below() + @see evas_object_raise() */ + + } + } +} diff --git a/src/lib/efl/interfaces/efl_gfx_view.eo b/src/lib/efl/interfaces/efl_gfx_view.eo new file mode 100644 index 0000000000..9d609d5cdb --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_view.eo @@ -0,0 +1,27 @@ +interface Efl.Gfx.View { + legacy_prefix: null; + properties { + size { + set { + /*@ + Sets the size of the given image object. + + This function will scale down or crop the image so that it is + treated as if it were at the given size. If the size given is + smaller than the image, it will be cropped. If the size given is + larger, then the image will be treated as if it were in the upper + left hand corner of a larger image that is otherwise transparent. */ + } + get { + /*@ + Retrieves the size of the given image object. + + See @ref evas_object_image_size_set() for more details. */ + } + values { + int w; /*@ The new width of the image. */ + int h; /*@ The new height of the image. */ + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c index c490636a3d..6ae1cb3ea4 100644 --- a/src/lib/efl/interfaces/efl_interfaces_main.c +++ b/src/lib/efl/interfaces/efl_interfaces_main.c @@ -10,3 +10,18 @@ #include "interfaces/efl_player.eo.c" #include "interfaces/efl_text.eo.c" #include "interfaces/efl_text_properties.eo.c" + +#include "interfaces/efl_gfx_base.eo.c" +#include "interfaces/efl_gfx_stack.eo.c" +#include "interfaces/efl_gfx_fill.eo.c" +#include "interfaces/efl_gfx_view.eo.c" + +#include "interfaces/efl_gfx_gradient_base.eo.c" +#include "interfaces/efl_gfx_gradient_linear.eo.c" +#include "interfaces/efl_gfx_gradient_radial.eo.c" + +EAPI const Eo_Event_Description _EFL_GFX_CHANGED = + EO_EVENT_DESCRIPTION("Graphics changed", "The visual representation of the object changed"); + +EAPI const Eo_Event_Description _EFL_GFX_PATH_CHANGED = + EO_EVENT_DESCRIPTION("Graphics path changed", "The path of a shape object changed"); diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index f7283f7a9c..0f6851a5e4 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -262,6 +262,7 @@ extern "C" { #include #include #include +#include #ifdef __cplusplus } diff --git a/src/lib/eina/eina_matrix.c b/src/lib/eina/eina_matrix.c new file mode 100644 index 0000000000..dc2e65cc21 --- /dev/null +++ b/src/lib/eina/eina_matrix.c @@ -0,0 +1,586 @@ +/* EINA - Drawing Library + * Copyright (C) 2007-2014 Jorge Luis Zapata + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "eina_private.h" + +#include + +#include "eina_fp.h" +#include "eina_rectangle.h" +#include "eina_quad.h" +#include "eina_matrix.h" + +#define MATRIX_XX(m) (m)->xx +#define MATRIX_XY(m) (m)->xy +#define MATRIX_XZ(m) (m)->xz +#define MATRIX_YX(m) (m)->yx +#define MATRIX_YY(m) (m)->yy +#define MATRIX_YZ(m) (m)->yz +#define MATRIX_ZX(m) (m)->zx +#define MATRIX_ZY(m) (m)->zy +#define MATRIX_ZZ(m) (m)->zz +#define MATRIX_SIZE 9 + +#define QUAD_X0(q) q->x0 +#define QUAD_Y0(q) q->y0 +#define QUAD_X1(q) q->x1 +#define QUAD_Y1(q) q->y1 +#define QUAD_X2(q) q->x2 +#define QUAD_Y2(q) q->y2 +#define QUAD_X3(q) q->x3 +#define QUAD_Y3(q) q->y3 + +/*============================================================================* + * Local * + *============================================================================*/ +/** @cond internal */ +/* + * In the range [-pi pi] + * (4/pi)*x - ((4/(pi*pi))*x*abs(x)) + * http://www.devmaster.net/forums/showthread.php?t=5784 + */ +#define EXTRA_PRECISION +static inline double + _sin(double x) +{ + const double B = 4/M_PI; + const double C = -4/(M_PI*M_PI); + + double y = (B * x) + (C * x * fabsf(x)); + +#ifdef EXTRA_PRECISION + // const float Q = 0.775; + const double P = 0.225; + + y = P * (y * fabsf(y) - y) + y; // Q * y + P * y * abs(y) +#endif + return y; +} + +static inline double +_cos(double x) +{ + x += M_PI_2; + + if (x > M_PI) // Original x > pi/2 + { + x -= 2 * M_PI; // Wrap: cos(x) = cos(x - 2 pi) + } + + return _sin(x); +} +/** @endcond */ + +/*============================================================================* + * API * + *============================================================================*/ +EAPI Eina_Matrix_Type +eina_matrix3_type_get(const Eina_Matrix3 *m) +{ + if ((MATRIX_ZX(m) != 0) || (MATRIX_ZY(m) != 0) || (MATRIX_ZZ(m) != 1)) + return EINA_MATRIX_TYPE_PROJECTIVE; + else + { + if ((MATRIX_XX(m) == 1) && (MATRIX_XY(m) == 0) && (MATRIX_XZ(m) == 0) && + (MATRIX_YX(m) == 0) && (MATRIX_YY(m) == 1) && (MATRIX_YZ(m) == 0)) + return EINA_MATRIX_TYPE_IDENTITY; + else + return EINA_MATRIX_TYPE_AFFINE; + } +} + +EAPI Eina_Matrix_Type +eina_matrix3_f16p16_type_get(const Eina_Matrix3_F16p16 *m) +{ + if ((MATRIX_ZX(m) != 0) || (MATRIX_ZY(m) != 0) || (MATRIX_ZZ(m) != 65536)) + return EINA_MATRIX_TYPE_PROJECTIVE; + else + { + if ((MATRIX_XX(m) == 65536) && (MATRIX_XY(m) == 0) && (MATRIX_XZ(m) == 0) && + (MATRIX_YX(m) == 0) && (MATRIX_YY(m) == 65536) && (MATRIX_YZ(m) == 0)) + return EINA_MATRIX_TYPE_IDENTITY; + else + return EINA_MATRIX_TYPE_AFFINE; + } +} + +EAPI void +eina_matrix3_values_set(Eina_Matrix3 *m, + double xx, double xy, double xz, + double yx, double yy, double yz, + double zx, double zy, double zz) +{ + MATRIX_XX(m) = xx; + MATRIX_XY(m) = xy; + MATRIX_XZ(m) = xz; + MATRIX_YX(m) = yx; + MATRIX_YY(m) = yy; + MATRIX_YZ(m) = yz; + MATRIX_ZX(m) = zx; + MATRIX_ZY(m) = zy; + MATRIX_ZZ(m) = zz; +} + +EAPI void +eina_matrix3_values_get(const Eina_Matrix3 *m, + double *xx, double *xy, double *xz, + double *yx, double *yy, double *yz, + double *zx, double *zy, double *zz) +{ + if (xx) *xx = MATRIX_XX(m); + if (xy) *xy = MATRIX_XY(m); + if (xz) *xz = MATRIX_XZ(m); + if (yx) *yx = MATRIX_YX(m); + if (yy) *yy = MATRIX_YY(m); + if (yz) *yz = MATRIX_YZ(m); + if (zx) *zx = MATRIX_ZX(m); + if (zy) *zy = MATRIX_ZY(m); + if (zz) *zz = MATRIX_ZZ(m); +} + +EAPI void +eina_matrix3_fixed_values_get(const Eina_Matrix3 *m, + Eina_F16p16 *xx, Eina_F16p16 *xy, Eina_F16p16 *xz, + Eina_F16p16 *yx, Eina_F16p16 *yy, Eina_F16p16 *yz, + Eina_F16p16 *zx, Eina_F16p16 *zy, Eina_F16p16 *zz) +{ + if (xx) *xx = eina_f16p16_double_from(MATRIX_XX(m)); + if (xy) *xy = eina_f16p16_double_from(MATRIX_XY(m)); + if (xz) *xz = eina_f16p16_double_from(MATRIX_XZ(m)); + if (yx) *yx = eina_f16p16_double_from(MATRIX_YX(m)); + if (yy) *yy = eina_f16p16_double_from(MATRIX_YY(m)); + if (yz) *yz = eina_f16p16_double_from(MATRIX_YZ(m)); + if (zx) *zx = eina_f16p16_double_from(MATRIX_ZX(m)); + if (zy) *zy = eina_f16p16_double_from(MATRIX_ZY(m)); + if (zz) *zz = eina_f16p16_double_from(MATRIX_ZZ(m)); +} + +EAPI void +eina_matrix3_matrix3_f16p16_to(const Eina_Matrix3 *m, + Eina_Matrix3_F16p16 *fm) +{ + eina_matrix3_fixed_values_get(m, + &fm->xx, &fm->xy, &fm->xz, + &fm->yx, &fm->yy, &fm->yz, + &fm->zx, &fm->zy, &fm->zz); +} + +EAPI void +eina_matrix3_point_transform(const Eina_Matrix3 *m, + double x, double y, + double *xr, double *yr) +{ + double xrr, yrr; + + if (!MATRIX_ZX(m) && !MATRIX_ZY(m)) + { + xrr = (x * MATRIX_XX(m) + y * MATRIX_XY(m) + MATRIX_XZ(m)); + yrr = (x * MATRIX_YX(m) + y * MATRIX_YY(m) + MATRIX_YZ(m)); + } + else + { + xrr = (x * MATRIX_XX(m) + y * MATRIX_XY(m) + MATRIX_XZ(m)) / + (x * MATRIX_ZX(m) + y * MATRIX_ZY(m) + MATRIX_ZZ(m)); + yrr = (x * MATRIX_YX(m) + y * MATRIX_YY(m) + MATRIX_YZ(m)) / + (x * MATRIX_ZX(m) + y * MATRIX_ZY(m) + MATRIX_ZZ(m)); + } + + if (xr) *xr = xrr; + if (yr) *yr = yrr; +} + +EAPI void +eina_matrix3_rectangle_transform(const Eina_Matrix3 *m, + const Eina_Rectangle *r, + const Eina_Quad *q) +{ + eina_matrix3_point_transform(m, r->x, r->y, &((Eina_Quad *)q)->x0, &((Eina_Quad *)q)->y0); + eina_matrix3_point_transform(m, r->x + r->w, r->y, &((Eina_Quad *)q)->x1, &((Eina_Quad *)q)->y1); + eina_matrix3_point_transform(m, r->x + r->w, r->y + r->h, &((Eina_Quad *)q)->x2, &((Eina_Quad *)q)->y2); + eina_matrix3_point_transform(m, r->x, r->y + r->h, &((Eina_Quad *)q)->x3, &((Eina_Quad *)q)->y3); +} + +EAPI void +eina_matrix3_cofactor(const Eina_Matrix3 *m, Eina_Matrix3 *a) +{ + double a11, a12, a13, a21, a22, a23, a31, a32, a33; + + a11 = (MATRIX_YY(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZY(m)); + a12 = -1 * ((MATRIX_YX(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZX(m))); + a13 = (MATRIX_YX(m) * MATRIX_ZY(m)) - (MATRIX_YY(m) * MATRIX_ZX(m)); + + a21 = -1 * ((MATRIX_XY(m) * MATRIX_ZZ(m)) - (MATRIX_XZ(m) * MATRIX_ZY(m))); + a22 = (MATRIX_XX(m) * MATRIX_ZZ(m)) - (MATRIX_XZ(m) * MATRIX_ZX(m)); + a23 = -1 * ((MATRIX_XX(m) * MATRIX_ZY(m)) - (MATRIX_XY(m) * MATRIX_ZX(m))); + + a31 = (MATRIX_XY(m) * MATRIX_YZ(m)) - (MATRIX_XZ(m) * MATRIX_YY(m)); + a32 = -1 * ((MATRIX_XX(m) * MATRIX_YZ(m)) - (MATRIX_XZ(m) * MATRIX_YX(m))); + a33 = (MATRIX_XX(m) * MATRIX_YY(m)) - (MATRIX_XY(m) * MATRIX_YX(m)); + + MATRIX_XX(a) = a11; + MATRIX_XY(a) = a12; + MATRIX_XZ(a) = a13; + + MATRIX_YX(a) = a21; + MATRIX_YY(a) = a22; + MATRIX_YZ(a) = a23; + + MATRIX_ZX(a) = a31; + MATRIX_ZY(a) = a32; + MATRIX_ZZ(a) = a33; +} + +EAPI void +eina_matrix3_transpose(const Eina_Matrix3 *m, Eina_Matrix3 *a) +{ + MATRIX_XX(a) = MATRIX_XX(m); + MATRIX_XY(a) = MATRIX_YX(m); + MATRIX_XZ(a) = MATRIX_ZX(m); + + MATRIX_YX(a) = MATRIX_XY(m); + MATRIX_YY(a) = MATRIX_YY(m); + MATRIX_YZ(a) = MATRIX_ZY(m); + + MATRIX_ZX(a) = MATRIX_XZ(m); + MATRIX_ZY(a) = MATRIX_YZ(m); + MATRIX_ZZ(a) = MATRIX_ZZ(m); +} + +EAPI void +eina_matrix3_adjoint(const Eina_Matrix3 *m, Eina_Matrix3 *a) +{ + Eina_Matrix3 cofactor; + + /* cofactor */ + eina_matrix3_cofactor(m, &cofactor); + /* transpose */ + eina_matrix3_transpose(&cofactor, a); +} + +EAPI double +eina_matrix3_determinant(const Eina_Matrix3 *m) +{ + double det; + + det = MATRIX_XX(m) * ((MATRIX_YY(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZY(m))); + det -= MATRIX_XY(m) * ((MATRIX_YX(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZX(m))); + det += MATRIX_XZ(m) * ((MATRIX_YX(m) * MATRIX_ZY(m)) - (MATRIX_YY(m) * MATRIX_ZX(m))); + + return det; +} + +EAPI void +eina_matrix3_divide(Eina_Matrix3 *m, double scalar) +{ + MATRIX_XX(m) /= scalar; + MATRIX_XY(m) /= scalar; + MATRIX_XZ(m) /= scalar; + + MATRIX_YX(m) /= scalar; + MATRIX_YY(m) /= scalar; + MATRIX_YZ(m) /= scalar; + + MATRIX_ZX(m) /= scalar; + MATRIX_ZY(m) /= scalar; + MATRIX_ZZ(m) /= scalar; +} + +EAPI void +eina_matrix3_inverse(const Eina_Matrix3 *m, Eina_Matrix3 *m2) +{ + double scalar; + + /* determinant */ + scalar = eina_matrix3_determinant(m); + if (!scalar) + { + eina_matrix3_identity(m2); + return; + } + /* do its adjoint */ + eina_matrix3_adjoint(m, m2); + /* divide */ + eina_matrix3_divide(m2, scalar); +} + +EAPI void +eina_matrix3_compose(const Eina_Matrix3 *m1, + const Eina_Matrix3 *m2, + Eina_Matrix3 *dst) +{ + double a11, a12, a13, a21, a22, a23, a31, a32, a33; + + a11 = (MATRIX_XX(m1) * MATRIX_XX(m2)) + (MATRIX_XY(m1) * MATRIX_YX(m2)) + (MATRIX_XZ(m1) * MATRIX_ZX(m2)); + a12 = (MATRIX_XX(m1) * MATRIX_XY(m2)) + (MATRIX_XY(m1) * MATRIX_YY(m2)) + (MATRIX_XZ(m1) * MATRIX_ZY(m2)); + a13 = (MATRIX_XX(m1) * MATRIX_XZ(m2)) + (MATRIX_XY(m1) * MATRIX_YZ(m2)) + (MATRIX_XZ(m1) * MATRIX_ZZ(m2)); + + a21 = (MATRIX_YX(m1) * MATRIX_XX(m2)) + (MATRIX_YY(m1) * MATRIX_YX(m2)) + (MATRIX_YZ(m1) * MATRIX_ZX(m2)); + a22 = (MATRIX_YX(m1) * MATRIX_XY(m2)) + (MATRIX_YY(m1) * MATRIX_YY(m2)) + (MATRIX_YZ(m1) * MATRIX_ZY(m2)); + a23 = (MATRIX_YX(m1) * MATRIX_XZ(m2)) + (MATRIX_YY(m1) * MATRIX_YZ(m2)) + (MATRIX_YZ(m1) * MATRIX_ZZ(m2)); + + a31 = (MATRIX_ZX(m1) * MATRIX_XX(m2)) + (MATRIX_ZY(m1) * MATRIX_YX(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZX(m2)); + a32 = (MATRIX_ZX(m1) * MATRIX_XY(m2)) + (MATRIX_ZY(m1) * MATRIX_YY(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZY(m2)); + a33 = (MATRIX_ZX(m1) * MATRIX_XZ(m2)) + (MATRIX_ZY(m1) * MATRIX_YZ(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZZ(m2)); + + MATRIX_XX(dst) = a11; + MATRIX_XY(dst) = a12; + MATRIX_XZ(dst) = a13; + MATRIX_YX(dst) = a21; + MATRIX_YY(dst) = a22; + MATRIX_YZ(dst) = a23; + MATRIX_ZX(dst) = a31; + MATRIX_ZY(dst) = a32; + MATRIX_ZZ(dst) = a33; +} + +EAPI Eina_Bool +eina_matrix3_equal(const Eina_Matrix3 *m1, const Eina_Matrix3 *m2) +{ + if (m1->xx != m2->xx || + m1->xy != m2->xy || + m1->xz != m2->xz || + m1->yx != m2->yx || + m1->yy != m2->yy || + m1->yz != m2->yz || + m1->zx != m2->zx || + m1->zy != m2->zy || + m1->zz != m2->zz) + return EINA_FALSE; + return EINA_TRUE; +} + +EAPI void +eina_matrix3_f16p16_compose(const Eina_Matrix3_F16p16 *m1, + const Eina_Matrix3_F16p16 *m2, + Eina_Matrix3_F16p16 *dst) +{ + Eina_F16p16 a11, a12, a13, a21, a22, a23, a31, a32, a33; + + a11 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XX(m2)) + + eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YX(m2)) + + eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZX(m2)); + a12 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XY(m2)) + + eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YY(m2)) + + eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZY(m2)); + a13 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XZ(m2)) + + eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YZ(m2)) + + eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZZ(m2)); + + a21 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XX(m2)) + + eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YX(m2)) + + eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZX(m2)); + a22 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XY(m2)) + + eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YY(m2)) + + eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZY(m2)); + a23 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XZ(m2)) + + eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YZ(m2)) + + eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZZ(m2)); + + a31 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XX(m2)) + + eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YX(m2)) + + eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZX(m2)); + a32 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XY(m2)) + + eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YY(m2)) + + eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZY(m2)); + a33 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XZ(m2)) + + eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YZ(m2)) + + eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZZ(m2)); + + MATRIX_XX(dst) = a11; + MATRIX_XY(dst) = a12; + MATRIX_XZ(dst) = a13; + MATRIX_YX(dst) = a21; + MATRIX_YY(dst) = a22; + MATRIX_YZ(dst) = a23; + MATRIX_ZX(dst) = a31; + MATRIX_ZY(dst) = a32; + MATRIX_ZZ(dst) = a33; +} + +EAPI void +eina_matrix3_translate(Eina_Matrix3 *m, double tx, double ty) +{ + MATRIX_XX(m) = 1; + MATRIX_XY(m) = 0; + MATRIX_XZ(m) = tx; + MATRIX_YX(m) = 0; + MATRIX_YY(m) = 1; + MATRIX_YZ(m) = ty; + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 1; +} + +EAPI void +eina_matrix3_scale(Eina_Matrix3 *m, double sx, double sy) +{ + MATRIX_XX(m) = sx; + MATRIX_XY(m) = 0; + MATRIX_XZ(m) = 0; + MATRIX_YX(m) = 0; + MATRIX_YY(m) = sy; + MATRIX_YZ(m) = 0; + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 1; +} + +EAPI void +eina_matrix3_rotate(Eina_Matrix3 *m, double rad) +{ + double c, s; +#if 0 + c = cosf(rad); + s = sinf(rad); +#else + /* normalize the angle between -pi,pi */ + rad = fmod(rad + M_PI, 2 * M_PI) - M_PI; + c = _cos(rad); + s = _sin(rad); +#endif + + MATRIX_XX(m) = c; + MATRIX_XY(m) = -s; + MATRIX_XZ(m) = 0; + MATRIX_YX(m) = s; + MATRIX_YY(m) = c; + MATRIX_YZ(m) = 0; + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 1; +} + +EAPI void +eina_matrix3_identity(Eina_Matrix3 *m) +{ + MATRIX_XX(m) = 1; + MATRIX_XY(m) = 0; + MATRIX_XZ(m) = 0; + MATRIX_YX(m) = 0; + MATRIX_YY(m) = 1; + MATRIX_YZ(m) = 0; + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 1; +} + +EAPI void +eina_matrix3_f16p16_identity(Eina_Matrix3_F16p16 *m) +{ + MATRIX_XX(m) = 65536; + MATRIX_XY(m) = 0; + MATRIX_XZ(m) = 0; + MATRIX_YX(m) = 0; + MATRIX_YY(m) = 65536; + MATRIX_YZ(m) = 0; + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 65536; +} + +EAPI Eina_Bool +eina_matrix3_square_quad_map(Eina_Matrix3 *m, const Eina_Quad *q) +{ + // x0 - x1 + x2 - x3 + double ex = QUAD_X0(q) - QUAD_X1(q) + QUAD_X2(q) - QUAD_X3(q); + // y0 - y1 + y2 - y3 + double ey = QUAD_Y0(q) - QUAD_Y1(q) + QUAD_Y2(q) - QUAD_Y3(q); + + /* paralellogram */ + if (!ex && !ey) + { + /* create the affine matrix */ + MATRIX_XX(m) = QUAD_X1(q) - QUAD_X0(q); + MATRIX_XY(m) = QUAD_X2(q) - QUAD_X1(q); + MATRIX_XZ(m) = QUAD_X0(q); + + MATRIX_YX(m) = QUAD_Y1(q) - QUAD_Y0(q); + MATRIX_YY(m) = QUAD_Y2(q) - QUAD_Y1(q); + MATRIX_YZ(m) = QUAD_Y0(q); + + MATRIX_ZX(m) = 0; + MATRIX_ZY(m) = 0; + MATRIX_ZZ(m) = 1; + + return EINA_TRUE; + } + else + { + double dx1 = QUAD_X1(q) - QUAD_X2(q); // x1 - x2 + double dx2 = QUAD_X3(q) - QUAD_X2(q); // x3 - x2 + double dy1 = QUAD_Y1(q) - QUAD_Y2(q); // y1 - y2 + double dy2 = QUAD_Y3(q) - QUAD_Y2(q); // y3 - y2 + double den = (dx1 * dy2) - (dx2 * dy1); + + if (!den) + return EINA_FALSE; + + MATRIX_ZX(m) = ((ex * dy2) - (dx2 * ey)) / den; + MATRIX_ZY(m) = ((dx1 * ey) - (ex * dy1)) / den; + MATRIX_ZZ(m) = 1; + MATRIX_XX(m) = QUAD_X1(q) - QUAD_X0(q) + (MATRIX_ZX(m) * QUAD_X1(q)); + MATRIX_XY(m) = QUAD_X3(q) - QUAD_X0(q) + (MATRIX_ZY(m) * QUAD_X3(q)); + MATRIX_XZ(m) = QUAD_X0(q); + MATRIX_YX(m) = QUAD_Y1(q) - QUAD_Y0(q) + (MATRIX_ZX(m) * QUAD_Y1(q)); + MATRIX_YY(m) = QUAD_Y3(q) - QUAD_Y0(q) + (MATRIX_ZY(m) * QUAD_Y3(q)); + MATRIX_YZ(m) = QUAD_Y0(q); + + return EINA_TRUE; + } +} + +EAPI Eina_Bool +eina_matrix3_quad_square_map(Eina_Matrix3 *m, + const Eina_Quad *q) +{ + Eina_Matrix3 tmp; + + /* compute square to quad */ + if (!eina_matrix3_square_quad_map(&tmp, q)) + return EINA_FALSE; + + eina_matrix3_inverse(&tmp, m); + /* make the projective matrix3 always have 1 on zz */ + if (MATRIX_ZZ(m) != 1) + { + eina_matrix3_divide(m, MATRIX_ZZ(m)); + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +eina_matrix3_quad_quad_map(Eina_Matrix3 *m, + const Eina_Quad *src, + const Eina_Quad *dst) +{ + Eina_Matrix3 tmp; + + /* TODO check that both are actually quadrangles */ + if (!eina_matrix3_quad_square_map(m, src)) + return EINA_FALSE; + if (!eina_matrix3_square_quad_map(&tmp, dst)) + return EINA_FALSE; + eina_matrix3_compose(&tmp, m, m); + + return EINA_TRUE; +} diff --git a/src/lib/eina/eina_matrix.h b/src/lib/eina/eina_matrix.h new file mode 100644 index 0000000000..57b5baba82 --- /dev/null +++ b/src/lib/eina/eina_matrix.h @@ -0,0 +1,339 @@ +/* EINA - EFL data type library + * Copyright (C) 2007-2014 Jorge Luis Zapata + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ +#ifndef EINA_MATRIX3_H_ +#define EINA_MATRIX3_H_ + +#include "eina_quad.h" + +/** + * @file + * @ender_group{Eina_Matrix_Type} + * @ender_group{Eina_Matrix3_F16p16} + * @ender_group{Eina_Matrix3} + */ + +/** + * @defgroup Eina_Matrix_Type Matrices type + * @ingroup Eina_Basic + * @brief Matrix3 types + * @{ + */ +typedef enum _Eina_Matrix_Type + { + EINA_MATRIX_TYPE_IDENTITY, /**< Identity matrix3 type */ + EINA_MATRIX_TYPE_AFFINE, /**< Affine matrix3 type */ + EINA_MATRIX_TYPE_PROJECTIVE, /**< Projective matrix3 type */ + EINA_MATRIX_TYPE_LAST /**< The total number of matrix3 types */ + } Eina_Matrix_Type; + +/** + * @} + * @defgroup Eina_Matrix3_F16p16 Matrices in fixed point + * @ingroup Eina_Basic + * @brief Fixed point matrices operations + * @{ + */ + +/** + * Fixed point matrix3 handler + */ +typedef struct _Eina_Matrix3_F16p16 Eina_Matrix3_F16p16; + +struct _Eina_Matrix3_F16p16 +{ + Eina_F16p16 xx; /**< xx in x' = (x * xx) + (y * xy) + xz */ + Eina_F16p16 xy; /**< xy in x' = (x * xx) + (y * xy) + xz */ + Eina_F16p16 xz; /**< xz in x' = (x * xx) + (y * xy) + xz */ + + Eina_F16p16 yx; /**< yx in y' = (x * yx) + (y * yy) + yz */ + Eina_F16p16 yy; /**< yy in y' = (x * yx) + (y * yy) + yz */ + Eina_F16p16 yz; /**< yz in y' = (x * yx) + (y * yy) + yz */ + + Eina_F16p16 zx; /**< zx in z' = (x * zx) + (y * zy) + zz */ + Eina_F16p16 zy; /**< zy in z' = (x * zx) + (y * zy) + zz */ + Eina_F16p16 zz; /**< zz in z' = (x * zx) + (y * zy) + zz */ +}; + +/** + * @brief Set the given fixed point matrix to the identity matrix. + * + * @param m The fixed point matrix to set + * + * This function sets @p m to the identity matrix. No check is done on + * @p m. + */ +EAPI void eina_matrix3_f16p16_identity(Eina_Matrix3_F16p16 *m); + +EAPI void eina_matrix3_f16p16_compose(const Eina_Matrix3_F16p16 *m1, + const Eina_Matrix3_F16p16 *m2, + Eina_Matrix3_F16p16 *dst); + +/** + * @brief Return the type of the given fixed point matrix. + * + * @param m The fixed point matrix. + * @return The type of the matrix. + * + * This function returns the type of the matrix @p m. No check is done + * on @p m. + */ +EAPI Eina_Matrix_Type eina_matrix3_f16p16_type_get(const Eina_Matrix3_F16p16 *m); + +/** + * @} + * @defgroup Eina_Matrix3 Matrices in floating point + * @ingroup Eina_Basic + * @brief Matrix definition and operations + * @{ + */ + +/** Helper macro for printf formatting */ +#define EINA_MATRIX3_FORMAT "g %g %g | %g %g %g | %g %g %g" +/** Helper macro for printf formatting arg */ +#define EINA_MATRIX3_ARGS(m) (m)->xx, (m)->xy, (m)->xz, \ + (m)->yx, (m)->yy, (m)->yz, \ + (m)->zx, (m)->zy, (m)->zz + + +/** + * Floating point matrix3 handler + */ +typedef struct _Eina_Matrix3 Eina_Matrix3; + +struct _Eina_Matrix3 +{ + double xx; /**< xx in x' = (x * xx) + (y * xy) + xz */ + double xy; /**< xy in x' = (x * xx) + (y * xy) + xz */ + double xz; /**< xz in x' = (x * xx) + (y * xy) + xz */ + + double yx; /**< yx in y' = (x * yx) + (y * yy) + yz */ + double yy; /**< yy in y' = (x * yx) + (y * yy) + yz */ + double yz; /**< yz in y' = (x * yx) + (y * yy) + yz */ + + double zx; /**< zx in z' = (x * zx) + (y * zy) + zz */ + double zy; /**< zy in z' = (x * zx) + (y * zy) + zz */ + double zz; /**< zz in z' = (x * zx) + (y * zy) + zz */ +}; + +/** + * @brief Return the type of the given floating point matrix. + * + * @param m The floating point matrix. + * @return The type of the matrix. + * + * This function returns the type of the matrix @p m. No check is done + * on @p m. + */ +EAPI Eina_Matrix_Type eina_matrix3_type_get(const Eina_Matrix3 *m); + +/** + * @brief Set the values of the coefficients of the given floating + * point matrix. + * + * @param m The floating point matrix. + * @param xx The first coefficient value. + * @param xy The second coefficient value. + * @param xz The third coefficient value. + * @param yx The fourth coefficient value. + * @param yy The fifth coefficient value. + * @param yz The sixth coefficient value. + * @param zx The seventh coefficient value. + * @param zy The heighth coefficient value. + * @param zz The nineth coefficient value. + * + * This function sets the values of the coefficients of the matrix + * @p m. No check is done on @p m. + * + * @see eina_matrix3_values_get() + */ +EAPI void eina_matrix3_values_set(Eina_Matrix3 *m, + double xx, double xy, double xz, + double yx, double yy, double yz, + double zx, double zy, double zz); + +/** + * @brief Get the values of the coefficients of the given floating + * point matrix. + * + * @param m The floating point matrix. + * @param xx The first coefficient value. + * @param xy The second coefficient value. + * @param xz The third coefficient value. + * @param yx The fourth coefficient value. + * @param yy The fifth coefficient value. + * @param yz The sixth coefficient value. + * @param zx The seventh coefficient value. + * @param zy The heighth coefficient value. + * @param zz The nineth coefficient value. + * + * This function gets the values of the coefficients of the matrix + * @p m. No check is done on @p m. + * + * @see eina_matrix3_values_set() + */ +EAPI void eina_matrix3_values_get(const Eina_Matrix3 *m, + double *xx, double *xy, double *xz, + double *yx, double *yy, double *yz, + double *zx, double *zy, double *zz); + +/** + * @brief Get the values of the coefficients of the given fixed + * point matrix. + * + * @param m The fixed point matrix. + * @param xx The first coefficient value. + * @param xy The second coefficient value. + * @param xz The third coefficient value. + * @param yx The fourth coefficient value. + * @param yy The fifth coefficient value. + * @param yz The sixth coefficient value. + * @param zx The seventh coefficient value. + * @param zy The heighth coefficient value. + * @param zz The nineth coefficient value. + * + * This function gets the values of the coefficients of the matrix + * @p m. No check is done on @p m. + * + * @see eina_matrix3_values_set() + */ +EAPI void eina_matrix3_fixed_values_get(const Eina_Matrix3 *m, + Eina_F16p16 *xx, Eina_F16p16 *xy, Eina_F16p16 *xz, + Eina_F16p16 *yx, Eina_F16p16 *yy, Eina_F16p16 *yz, + Eina_F16p16 *zx, Eina_F16p16 *zy, Eina_F16p16 *zz); + +/** + * @brief Transform the given floating point matrix to the given fixed + * point matrix. + * + * @param m The floating point matrix. + * @param fm The fixed point matrix. + * + * This function transforms the floating point matrix @p m to a fixed + * point matrix and store the coefficients into the fixed point matrix + * @p fm. + */ +EAPI void eina_matrix3_matrix3_f16p16_to(const Eina_Matrix3 *m, + Eina_Matrix3_F16p16 *fm); + +/** + * @brief Check whether the two given matrices are equal or not. + * + * @param m1 The first matrix. + * @param m2 The second matrix. + * @return EINA_TRUE if the two matrices are equal, 0 otherwise. + * + * This function return EINA_TRUE if thematrices @p m1 and @p m2 are + * equal, EINA_FALSE otherwise. No check is done on the matrices. + */ +EAPI Eina_Bool eina_matrix3_equal(const Eina_Matrix3 *m1, const Eina_Matrix3 *m2); +EAPI void eina_matrix3_compose(const Eina_Matrix3 *m1, + const Eina_Matrix3 *m2, + Eina_Matrix3 *dst); + +/** + * Set the matrix values for a translation + * @param[in] m The matrix to set the translation values + * @param[in] tx The X coordinate translate + * @param[in] ty The Y coordinate translate + */ +EAPI void eina_matrix3_translate(Eina_Matrix3 *t, double tx, double ty); + +/** + * Set the matrix values for a scale + * @param[in] m The matrix to set the scale values + * @param[in] sx The X coordinate scale + * @param[in] sy The Y coordinate scale + */ +EAPI void eina_matrix3_scale(Eina_Matrix3 *t, double sx, double sy); + +/** + * Set the matrix values for a rotation + * @param[in] m The matrix to set the rotation values + * @param[in] rad The radius to rotate the matrix + */ +EAPI void eina_matrix3_rotate(Eina_Matrix3 *t, double rad); + +/** + * @brief Set the given floating point matrix to the identity matrix. + * + * @param m The floating point matrix to set + * + * This function sets @p m to the identity matrix. No check is done on + * @p m. + */ +EAPI void eina_matrix3_identity(Eina_Matrix3 *t); + +/** + * @brief Return the determinant of the given matrix. + * + * @param m The matrix. + * @return The determinant. + * + * This function returns the determinant of the matrix @p m. No check + * is done on @p m. + */ +EAPI double eina_matrix3_determinant(const Eina_Matrix3 *m); + +/** + * @brief Divide the given matrix by the given scalar. + * + * @param m The matrix. + * @param scalar The scalar number. + * + * This function divides the matrix @p m by @p scalar. No check + * is done on @p m. + */ +EAPI void eina_matrix3_divide(Eina_Matrix3 *m, double scalar); + +/** + * @brief Compute the inverse of the given matrix. + * + * @param m The matrix to inverse. + * @param m2 The inverse matrix. + * + * This function inverse the matrix @p m and stores the result in + * @p m2. No check is done on @p m or @p m2. If @p m can not be + * invertible, then @p m2 is set to the identity matrix. + */ +EAPI void eina_matrix3_inverse(const Eina_Matrix3 *m, Eina_Matrix3 *m2); +EAPI void eina_matrix3_transpose(const Eina_Matrix3 *m, Eina_Matrix3 *a); +EAPI void eina_matrix3_cofactor(const Eina_Matrix3 *m, Eina_Matrix3 *a); +EAPI void eina_matrix3_adjoint(const Eina_Matrix3 *m, Eina_Matrix3 *a); + +EAPI void eina_matrix3_point_transform(const Eina_Matrix3 *m, + double x, double y, + double *xr, double *yr); +EAPI void eina_matrix3_rectangle_transform(const Eina_Matrix3 *m, + const Eina_Rectangle *r, + const Eina_Quad *q); + +/** + * @brief Creates a projective matrix that maps a quadrangle to a quadrangle + */ +EAPI Eina_Bool eina_matrix3_quad_quad_map(Eina_Matrix3 *m, + const Eina_Quad *src, + const Eina_Quad *dst); +EAPI Eina_Bool eina_matrix3_square_quad_map(Eina_Matrix3 *m, + const Eina_Quad *q); +EAPI Eina_Bool eina_matrix3_quad_square_map(Eina_Matrix3 *m, + const Eina_Quad *q); + +/** + * @} + */ +#endif /*EINA_MATRIX3_H_*/ diff --git a/src/lib/eina/eina_quad.c b/src/lib/eina/eina_quad.c new file mode 100644 index 0000000000..d2874c004d --- /dev/null +++ b/src/lib/eina/eina_quad.c @@ -0,0 +1,127 @@ +/* EINA - EFL data type library + * Copyright (C) 2007-2014 Jorge Luis Zapata + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "eina_private.h" + +#include +#include + +#include "eina_rectangle.h" +#include "eina_quad.h" + +#define QUAD_X0(q) q->x0 +#define QUAD_Y0(q) q->y0 +#define QUAD_X1(q) q->x1 +#define QUAD_Y1(q) q->y1 +#define QUAD_X2(q) q->x2 +#define QUAD_Y2(q) q->y2 +#define QUAD_X3(q) q->x3 +#define QUAD_Y3(q) q->y3 + +/*============================================================================* + * Local * + *============================================================================*/ +/** @cond internal */ +/* FIXME make this function on API */ +static inline void _quad_dump(Eina_Quad *q) +{ + printf("Q = %f %f, %f %f, %f %f, %f %f\n", QUAD_X0(q), QUAD_Y0(q), QUAD_X1(q), QUAD_Y1(q), QUAD_X2(q), QUAD_Y2(q), QUAD_X3(q), QUAD_Y3(q)); +} +/** @endcond */ + +/*============================================================================* + * API * + *============================================================================*/ +EAPI void +eina_quad_rectangle_to(const Eina_Quad *q, + Eina_Rectangle *r) +{ + double xmin, ymin, xmax, ymax; + /* FIXME this code is very ugly, for sure there must be a better + * implementation */ + xmin = QUAD_X0(q) < QUAD_X1(q) ? QUAD_X0(q) : QUAD_X1(q); + xmin = xmin < QUAD_X2(q) ? xmin : QUAD_X2(q); + xmin = xmin < QUAD_X3(q) ? xmin : QUAD_X3(q); + + ymin = QUAD_Y0(q) < QUAD_Y1(q) ? QUAD_Y0(q) : QUAD_Y1(q); + ymin = ymin < QUAD_Y2(q) ? ymin : QUAD_Y2(q); + ymin = ymin < QUAD_Y3(q) ? ymin : QUAD_Y3(q); + + xmax = QUAD_X0(q) > QUAD_X1(q) ? QUAD_X0(q) : QUAD_X1(q); + xmax = xmax > QUAD_X2(q) ? xmax : QUAD_X2(q); + xmax = xmax > QUAD_X3(q) ? xmax : QUAD_X3(q); + + ymax = QUAD_Y0(q) > QUAD_Y1(q) ? QUAD_Y0(q) : QUAD_Y1(q); + ymax = ymax > QUAD_Y2(q) ? ymax : QUAD_Y2(q); + ymax = ymax > QUAD_Y3(q) ? ymax : QUAD_Y3(q); + + r->x = lround(xmin); + r->w = lround(xmax) - r->x; + r->y = lround(ymin); + r->h = lround(ymax) - r->y; +} + +EAPI void +eina_quad_rectangle_from(Eina_Quad *q, + const Eina_Rectangle *r) +{ + QUAD_X0(q) = r->x; + QUAD_Y0(q) = r->y; + QUAD_X1(q) = r->x + r->w; + QUAD_Y1(q) = r->y; + QUAD_X2(q) = r->x + r->w; + QUAD_Y2(q) = r->y + r->h; + QUAD_X3(q) = r->x; + QUAD_Y3(q) = r->y + r->h; +} + +EAPI void eina_quad_coords_get(const Eina_Quad *q, + double *qx0, double *qy0, + double *qx1, double *qy1, + double *qx2, double *qy2, + double *qx3, double *qy3) +{ + if (qx0) *qx0 = q->x0; + if (qy0) *qy0 = q->y0; + if (qx1) *qx1 = q->x1; + if (qy1) *qy1 = q->y1; + if (qx2) *qx2 = q->x2; + if (qy2) *qy2 = q->y2; + if (qx3) *qx3 = q->x3; + if (qy3) *qy3 = q->y3; +} + +EAPI void eina_quad_coords_set(Eina_Quad *q, + double qx0, double qy0, + double qx1, double qy1, + double qx2, double qy2, + double qx3, double qy3) +{ + QUAD_X0(q) = qx0; + QUAD_Y0(q) = qy0; + QUAD_X1(q) = qx1; + QUAD_Y1(q) = qy1; + QUAD_X2(q) = qx2; + QUAD_Y2(q) = qy2; + QUAD_X3(q) = qx3; + QUAD_Y3(q) = qy3; +} diff --git a/src/lib/eina/eina_quad.h b/src/lib/eina/eina_quad.h new file mode 100644 index 0000000000..2abbc34bd0 --- /dev/null +++ b/src/lib/eina/eina_quad.h @@ -0,0 +1,67 @@ +/* EINA - EFL data type library + * Copyright (C) 2007-2014 Jorge Luis Zapata + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see . + */ +#ifndef EINA_QUAD_H_ +#define EINA_QUAD_H_ + +/** + * @file + * @ender_group{Eina_Quad} + */ + +/** + * @defgroup Eina_Quad Quadrangles + * @ingroup Eina_Basic + * @brief Quadrangles operations + * @{ + */ + +/** + * Quadrangle definition + */ +typedef struct _Eina_Quad +{ + double x0; /**< Top left x coordinate */ + double y0; /**< Top left y coordinate */ + double x1; /**< Top right x coordinate */ + double y1; /**< Top right y coordinate */ + double x2; /**< Bottom right x coordinate */ + double y2; /**< Bottom right y coordinate */ + double x3; /**< Bottom left x coordinate */ + double y3; /**< Bottom left y coordinate */ +} Eina_Quad; + +EAPI void eina_quad_rectangle_to(const Eina_Quad *q, + Eina_Rectangle *r); +EAPI void eina_quad_rectangle_from(Eina_Quad *q, + const Eina_Rectangle *r); +EAPI void eina_quad_coords_set(Eina_Quad *q, + double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4); +EAPI void eina_quad_coords_get(const Eina_Quad *q, + double *x1, double *y1, + double *x2, double *y2, + double *x3, double *y3, + double *x4, double *y4); + +/** + * @} + */ + +#endif diff --git a/src/lib/eina/eina_simple_xml_parser.c b/src/lib/eina/eina_simple_xml_parser.c index 2ead2e2683..13dd5ee7b1 100644 --- a/src/lib/eina/eina_simple_xml_parser.c +++ b/src/lib/eina/eina_simple_xml_parser.c @@ -556,6 +556,63 @@ eina_simple_xml_attributes_parse(const char *buf, unsigned buflen, Eina_Simple_X return EINA_TRUE; } +EAPI Eina_Bool +eina_simple_xml_attribute_w3c_parse(const char *buf, Eina_Simple_XML_Attribute_Cb func, const void *data) +{ + const char *end; + char *key; + char *val; + char *next; + + if (!buf) return EINA_FALSE; + + end = buf + strlen(buf); + key = alloca(end - buf + 1); + val = alloca(end - buf + 1); + + if (buf == end) return EINA_TRUE; + + do + { + char *sep = strchr(buf, ':'); + next = strchr(buf, ';'); + + key[0] = '\0'; + val[0] = '\0'; + + if (next == NULL && sep != NULL) + { + memcpy(key, buf, sep - buf); + key[sep - buf] = '\0'; + + memcpy(val, sep + 1, end - sep - 1); + val[end - sep - 1] = '\0'; + } + else if (sep < next && sep != NULL) + { + memcpy(key, buf, sep - buf); + key[sep - buf] = '\0'; + + memcpy(val, sep + 1, next - sep - 1); + val[next - sep - 1] = '\0'; + } + else if (next) + { + memcpy(key, buf, next - buf); + key[next - buf] = '\0'; + } + + if (key[0]) + if (!func((void*) data, key, val)) + return EINA_FALSE; + + buf = next + 1; + } + while (next != NULL); + + return EINA_TRUE; +} + /* Node loader *************************************************************/ EAPI Eina_Simple_XML_Attribute * diff --git a/src/lib/eina/eina_simple_xml_parser.h b/src/lib/eina/eina_simple_xml_parser.h index 8f83c1e01a..365b2d0360 100644 --- a/src/lib/eina/eina_simple_xml_parser.h +++ b/src/lib/eina/eina_simple_xml_parser.h @@ -277,6 +277,23 @@ EAPI const char * eina_simple_xml_tag_attributes_find(const char *buf, unsigned EAPI Eina_Bool eina_simple_xml_attributes_parse(const char *buf, unsigned buflen, Eina_Simple_XML_Attribute_Cb func, const void *data); +/** + * Given a buffer with the xml value of an attributes, parse them to key:value pairs. + * + * @param buf the input string. Need to contain \0 terminator. + * @param func what to call back while parse to do some action. The + * first parameter is the given user @a data, the second is the + * key (null-terminated) and the last is the value (null + * terminated). These strings should not be modified and + * reference is just valid until the function return. + * @param data data to pass to the callback function. + * + * @return #EINA_TRUE on success or #EINA_FALSE if it was aborted by user or + * parsing error. + */ +EAPI Eina_Bool +eina_simple_xml_attribute_w3c_parse(const char *buf, Eina_Simple_XML_Attribute_Cb func, const void *data); + /** * Create (and append) new attribute to tag. * diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index af787957d8..46e9d73ef8 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -486,32 +486,32 @@ EAPI extern Eo_Hook_Call eo_hook_call_post; #define EO_HOOK_CALL_PREPARE(Hook, FuncName) \ if (Hook) \ - Hook(call.klass, call.obj, FuncName, call.func); + Hook(___call.klass, ___call.obj, FuncName, ___call.func); #define EO_HOOK_CALL_PREPAREV(Hook, FuncName, ...) \ if (Hook) \ - Hook(call.klass, call.obj, FuncName, call.func, __VA_ARGS__); + Hook(___call.klass, ___call.obj, FuncName, ___call.func, __VA_ARGS__); // cache OP id, get real fct and object data then do the call #define EO_FUNC_COMMON_OP(Name, DefRet) \ - Eo_Op_Call_Data call; \ - Eina_Bool is_main_loop = eina_main_loop_is(); \ - static Eo_Op op = EO_NOOP; \ - if (op == EO_NOOP) \ - op = _eo_api_op_id_get((void*) Name, is_main_loop, __FILE__, __LINE__); \ - if (!_eo_call_resolve(#Name, op, &call, is_main_loop, __FILE__, __LINE__)) return DefRet; \ - _Eo_##Name##_func _func_ = (_Eo_##Name##_func) call.func; \ + Eo_Op_Call_Data ___call; \ + Eina_Bool ___is_main_loop = eina_main_loop_is(); \ + static Eo_Op ___op = EO_NOOP; \ + if (___op == EO_NOOP) \ + ___op = _eo_api_op_id_get((void*) Name, ___is_main_loop, __FILE__, __LINE__); \ + if (!_eo_call_resolve(#Name, ___op, &___call, ___is_main_loop, __FILE__, __LINE__)) return DefRet; \ + _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \ // to define an EAPI function -#define EO_FUNC_BODY(Name, Ret, DefRet) \ +#define EO_FUNC_BODY(Name, Ret, DefRet) \ Ret \ Name(void) \ { \ - typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \ + typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \ Ret _r; \ - EO_FUNC_COMMON_OP(Name, DefRet); \ - EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \ - _r = _func_(call.obj, call.data); \ + EO_FUNC_COMMON_OP(Name, DefRet); \ + EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \ + _r = _func_(___call.obj, ___call.data); \ EO_HOOK_CALL_PREPARE(eo_hook_call_post, #Name); \ return _r; \ } @@ -520,35 +520,35 @@ EAPI extern Eo_Hook_Call eo_hook_call_post; void \ Name(void) \ { \ - typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \ - EO_FUNC_COMMON_OP(Name, ); \ - EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \ - _func_(call.obj, call.data); \ - EO_HOOK_CALL_PREPARE(eo_hook_call_post, #Name); \ + typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \ + EO_FUNC_COMMON_OP(Name, ); \ + EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \ + _func_(___call.obj, ___call.data); \ + EO_HOOK_CALL_PREPARE(eo_hook_call_post, #Name); \ } -#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) \ +#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) \ Ret \ Name(__VA_ARGS__) \ { \ typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ Ret _r; \ - EO_FUNC_COMMON_OP(Name, DefRet); \ - EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \ - _r = _func_(call.obj, call.data, Arguments); \ - EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \ + EO_FUNC_COMMON_OP(Name, DefRet); \ + EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \ + _r = _func_(___call.obj, ___call.data, Arguments); \ + EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \ return _r; \ } -#define EO_VOID_FUNC_BODYV(Name, Arguments, ...) \ +#define EO_VOID_FUNC_BODYV(Name, Arguments, ...) \ void \ Name(__VA_ARGS__) \ { \ typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ - EO_FUNC_COMMON_OP(Name, ); \ - EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \ - _func_(call.obj, call.data, Arguments); \ - EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \ + EO_FUNC_COMMON_OP(Name, ); \ + EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \ + _func_(___call.obj, ___call.data, Arguments); \ + EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \ } // OP ID of an overriding function diff --git a/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh b/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh index 82678496ee..38382d5092 100644 --- a/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh +++ b/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh @@ -21,7 +21,7 @@ _ns_as_prefix(eo_class const& cls) std::string::size_type found = s.find("::"); while (found != std::string::npos) { - s.replace(found, 1, "_"); + s.replace(found, 2, "_"); found = s.find("::"); } return s; diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h index 0a93f745d3..5055561515 100644 --- a/src/lib/evas/Evas_Common.h +++ b/src/lib/evas/Evas_Common.h @@ -312,6 +312,11 @@ typedef Eo Evas_Object; /* This define is used in H files generated by Eolian */ #define _EVAS_OBJECT_EO_CLASS_TYPE +/** + * Type of abstract VG node + */ +typedef Eo Efl_VG; + typedef void Evas_Performance; /**< An Evas Performance handle */ typedef struct _Evas_Modifier Evas_Modifier; /**< An opaque type containing information on which modifier keys are registered in an Evas canvas */ typedef struct _Evas_Lock Evas_Lock; /**< An opaque type containing information on which lock keys are registered in an Evas canvas */ @@ -432,15 +437,13 @@ typedef enum _Evas_Alloc_Error EVAS_ALLOC_ERROR_RECOVERED = 2 /**< Allocation succeeded, but extra memory had to be found by freeing up speculative resources */ } Evas_Alloc_Error; /**< Possible allocation errors returned by evas_alloc_error() */ -typedef enum _Evas_Fill_Spread -{ - EVAS_TEXTURE_REFLECT = 0, /**< image fill tiling mode - tiling reflects */ - EVAS_TEXTURE_REPEAT = 1, /**< tiling repeats */ - EVAS_TEXTURE_RESTRICT = 2, /**< tiling clamps - range offset ignored */ - EVAS_TEXTURE_RESTRICT_REFLECT = 3, /**< tiling clamps and any range offset reflects */ - EVAS_TEXTURE_RESTRICT_REPEAT = 4, /**< tiling clamps and any range offset repeats */ - EVAS_TEXTURE_PAD = 5 /**< tiling extends with end values */ -} Evas_Fill_Spread; /**< Fill types used for evas_object_image_fill_spread_set() */ +typedef Efl_Gfx_Fill_Spread Evas_Fill_Spread; +#define EVAS_TEXTURE_REFLECT EFL_GFX_FILL_REFLECT +#define EVAS_TEXTURE_REPEAT EFL_GFX_FILL_REPEAT +#define EVAS_TEXTURE_RESTRICT EFL_GFX_FILL_RESTRICT +#define EVAS_TEXTURE_RESTRICT_REFLECT EFL_GFX_FILL_RESTRICT_REFLECT +#define EVAS_TEXTURE_RESTRICT_REPEAT EFL_GFX_FILL_RESTRICT_REPEAT +#define EVAS_TEXTURE_PAD EFL_GFX_FILL_PAD typedef enum _Evas_Pixel_Import_Pixel_Format { diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index 34ab6a486b..1e1c639bb0 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -845,3 +845,19 @@ typedef enum _Evas_3D_Material_Attrib #include "canvas/evas_3d_object.eo.h" +/** + * @ingroup Evas_Object_VG + * + * @{ + */ +#include "canvas/evas_vg.eo.h" +/** + * @} + */ + +#include "canvas/efl_vg_base.eo.h" +#include "canvas/efl_vg_container.eo.h" +#include "canvas/efl_vg_shape.eo.h" +#include "canvas/efl_vg_gradient.eo.h" +#include "canvas/efl_vg_gradient_linear.eo.h" +#include "canvas/efl_vg_gradient_radial.eo.h" diff --git a/src/lib/evas/Evas_Legacy.h b/src/lib/evas/Evas_Legacy.h index ca746f8209..a3ee6e0f2f 100644 --- a/src/lib/evas/Evas_Legacy.h +++ b/src/lib/evas/Evas_Legacy.h @@ -567,6 +567,241 @@ EAPI void evas_object_show(Evas_Object *obj) EINA_ARG_NONNULL(1); */ EAPI void evas_object_hide(Evas_Object *obj) EINA_ARG_NONNULL(1); +/** + * + * Sets the general/main color of the given Evas object to the given + * one. + * + * @see evas_object_color_get() (for an example) + * @note These color values are expected to be premultiplied by @p a. + * + * @ingroup Evas_Object_Group_Basic + * + * @param[in] r The red component of the given color. + * @param[in] g The green component of the given color. + * @param[in] b The blue component of the given color. + * @param[in] a The alpha component of the given color. + */ +EAPI void evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a); + +/** + * + * Retrieves the general/main color of the given Evas object. + * + * Retrieves the “main” color's RGB component (and alpha channel) + * values, which range from 0 to 255. For the alpha channel, + * which defines the object's transparency level, 0 means totally + * transparent, while 255 means opaque. These color values are + * premultiplied by the alpha value. + * + * Usually you’ll use this attribute for text and rectangle objects, + * where the “main” color is their unique one. If set for objects + * which themselves have colors, like the images one, those colors get + * modulated by this one. + * + * @note All newly created Evas rectangles get the default color + * values of 255 255 255 255 (opaque white). + * + * @note Use @c NULL pointers on the components you're not interested + * in: they'll be ignored by the function. + * + * Example: + * @dontinclude evas-object-manipulation.c + * @skip int alpha, r, g, b; + * @until return + * + * See the full @ref Example_Evas_Object_Manipulation "example". + * + * @ingroup Evas_Object_Group_Basic + * + * @param[out] r The red component of the given color. + * @param[out] g The green component of the given color. + * @param[out] b The blue component of the given color. + * @param[out] a The alpha component of the given color. + */ +EAPI void evas_object_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a); + +/** + * + * Move the given Evas object to the given location inside its canvas' viewport. + * + * @param[in] x in + * @param[in] y in + */ +EAPI void evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y); + +/** + * + * Changes the size of the given Evas object. + * + * @param[in] w in + * @param[in] h in + */ +EAPI void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h); + +/** + * + * Retrieves whether or not the given Evas object is visible. + * + */ +EAPI Eina_Bool evas_object_visible_get(const Evas_Object *obj); + +/** + * + * Sets the layer of its canvas that the given object will be part of. + * + * If you don't use this function, you'll be dealing with an @b unique + * layer of objects, the default one. Additional layers are handy when + * you don't want a set of objects to interfere with another set with + * regard to @b stacking. Two layers are completely disjoint in that + * matter. + * + * This is a low-level function, which you'd be using when something + * should be always on top, for example. + * + * @warning Be careful, it doesn't make sense to change the layer of + * smart objects' children. Smart objects have a layer of their own, + * which should contain all their children objects. + * + * @see evas_object_layer_get() + * + * @param[in] l The number of the layer to place the object on. +Must be between #EVAS_LAYER_MIN and #EVAS_LAYER_MAX. + */ +EAPI void evas_object_layer_set(Evas_Object *obj, short l); + +/** + * + * Retrieves the layer of its canvas that the given object is part of. + * + * @return Number of its layer + * + * @see evas_object_layer_set() + * + */ +EAPI short evas_object_layer_get(const Evas_Object *obj); + +/** + * + * Get the Evas object stacked right below @p obj + * + * @return the #Evas_Object directly below @p obj, if any, or @c NULL, + * if none + * + * This function will traverse layers in its search, if there are + * objects on layers below the one @p obj is placed at. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_below_get() + * + */ +EAPI Evas_Object *evas_object_below_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT; + +/** + * + * Get the Evas object stacked right above @p obj + * + * @return the #Evas_Object directly above @p obj, if any, or @c NULL, + * if none + * + * This function will traverse layers in its search, if there are + * objects on layers above the one @p obj is placed at. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_below_get() + * + */ +EAPI Evas_Object *evas_object_above_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT; + +/** + * + * Stack @p obj immediately below @p below + * + * Objects, in a given canvas, are stacked in the order they get added + * to it. This means that, if they overlap, the highest ones will + * cover the lowest ones, in that order. This function is a way to + * change the stacking order for the objects. + * + * This function is intended to be used with objects belonging to + * the same layer in a given canvas, otherwise it will fail (and + * accomplish nothing). + * + * If you have smart objects on your canvas and @p obj is a member of + * one of them, then @p below must also be a member of the same + * smart object. + * + * Similarly, if @p obj is not a member of a smart object, @p below + * must not be either. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_stack_below() + * + * + * @param[in] below the object below which to stack + */ +EAPI void evas_object_stack_below(Evas_Object *obj, Evas_Object *below) EINA_ARG_NONNULL(2); + +/** + * + * Raise @p obj to the top of its layer. + * + * @p obj will, then, be the highest one in the layer it belongs + * to. Object on other layers won't get touched. + * + * @see evas_object_stack_above() + * @see evas_object_stack_below() + * @see evas_object_lower() + * + * + */ +EAPI void evas_object_raise(Evas_Object *obj); + +/** + * + * Stack @p obj immediately above @p above + * + * Objects, in a given canvas, are stacked in the order they get added + * to it. This means that, if they overlap, the highest ones will + * cover the lowest ones, in that order. This function is a way to + * change the stacking order for the objects. + * + * This function is intended to be used with objects belonging to + * the same layer in a given canvas, otherwise it will fail (and + * accomplish nothing). + * + * If you have smart objects on your canvas and @p obj is a member of + * one of them, then @p above must also be a member of the same + * smart object. + * + * Similarly, if @p obj is not a member of a smart object, @p above + * must not be either. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_stack_below() + * + * + * @param[in] above the object above which to stack + */ +EAPI void evas_object_stack_above(Evas_Object *obj, Evas_Object *above) EINA_ARG_NONNULL(2); + +/** + * + * Lower @p obj to the bottom of its layer. + * + * @p obj will, then, be the lowest one in the layer it belongs + * to. Objects on other layers won't get touched. + * + * @see evas_object_stack_above() + * @see evas_object_stack_below() + * @see evas_object_raise() + * + * + */ +EAPI void evas_object_lower(Evas_Object *obj); #include "canvas/evas_common_interface.eo.legacy.h" #include "canvas/evas_object.eo.legacy.h" @@ -1386,6 +1621,831 @@ EAPI void *evas_object_intercept_focus_set_callback_del(Evas_Object *obj, Evas_O EAPI Evas_Object *evas_object_rectangle_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; #include "canvas/evas_rectangle.eo.legacy.h" + +/** + * @} + */ + +/** + * @defgroup Evas_Object_Vg + * @ingroup Evas + * + * Evas_Object_Vg is the scene graph for managing vector graphics objects. + * User can create shape objects as well as fill objects and give it to the + * Evas_Object_Vg for drawing on the screen as well as managing the lifecycle + * of the objects. enabling reuse of shape objects. + * + * As Evas_Object_Vg is a Evas_Object all the operation that applicable to + * a Evas_Object can be performed on it(clipping , map, etc). + * + * To create any complex vector graphics you can create a hirarchy of shape + * and fill objects and give the hirarchy to Evas_Object which will be + * responsible for drawing and showing on the screen. + * + * As the shape object and fill object (linear and radial gradient) have + * retain mode API, you only have to create it once and set the properties + * and give it to evas_object_vg. + * + * Any change in the property of shape/fill object will automaticaly notified + * to the evas_object_vg which will trigger a redrawing to reflect the change. + * + * To create a vector path, you can give list of path commands to the shape + * object using efl_gfx_shape_path_set() API. + * + * Enabling graphical shapes to be constructed and reused. + * + * Below are the list of feature currently supported by Vector object. + * + * @li Drawing SVG Path. + * You can construct a path by using api in efl_gfx_utils.h + * + * @li Gradient filling and stroking. + * You can fill or stroke the path using linear or radial gradient. + * @see Evas_Vg_Gradient_Linear and Evas_Vg_Gradient_Radial + * + * @li Transformation support for path and gradient fill. You can apply + affin transformation on path object. + * @see Eina_Matrix. + * + * @note Below are the list of interface, classes can be used to draw vector + * graphics using vector object. + * + * @li Efl.Gfx.Shape + * @li Evas.VG_Shape + * @li Evas.VG_Node + * @li Efl.Gfx.Gradient + * @li Efl.Gfx.Gradient_Radial + * @li Efl.Gfx.Gradient_Linear + * + * Example: + * @code + * vector = evas_object_vg_add(canvas); + * root = evas_obj_vg_root_node_get(vector); + * shape = eo_add(EVAS_VG_SHAPE_CLASS, root); + * Efl_Gfx_Path_Command *path_cmd = NULL; + * double *points = NULL; + * efl_gfx_path_append_circle(&path_cmd, &points); + * eo_do(shape, + * evas_vg_node_origin_set(10, 10), + * efl_gfx_shape_stroke_width_set(1.0), + * evas_vg_node_color_set(128, 128, 128, 80), + * efl_gfx_shape_path_set(path_cmd, points)); + * @endcode + * + * @since 1.14 + */ + +/** + * Creates a new vector object on the given Evas @p e canvas. + * + * @param e The given canvas. + * @return The created vector object handle. + * + * The shape object hirarchy can be added to the evas_object_vg by accessing + * the rootnode of the vg canvas and adding the hirarchy as child to the root + * node. + * + * @see evas_obj_vg_root_node_get() + * @since 1.14 + */ +EAPI Evas_Object *evas_object_vg_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; + +#include "canvas/evas_vg.eo.legacy.h" + +#ifdef EFL_BETA_API_SUPPORT + +/** + * Creates a new vector shape object \. + * + * @param parent The given vector container object. + * @return The created vector shape object handle. + * + * @since 1.14 + */ +EAPI Efl_VG* evas_vg_shape_add(Efl_VG *parent); + +/** + * Creates a new vector container object \. + * + * @param parent The given vector container object. + * @return The created vector container object handle. + * + * @since 1.14 + */ + +EAPI Efl_VG* evas_vg_container_add(Efl_VG *parent); + +/** + * + * Retrieves whether or not the given Efl_Vg object is visible. + * + * + */ +EAPI Eina_Bool evas_vg_node_visible_get(Eo *obj); + +/** + * + * Makes the given Efl_Vg object visible or invisible. + * + * @param[in] v @c EINA_TRUE if to make the object visible, @c EINA_FALSE otherwise + * + */ +EAPI void evas_vg_node_visible_set(Eo *obj, Eina_Bool v); + +/** + * + * Retrieves the general/main color of the given Efl_Vg object. + * + * Retrieves the “main” color's RGB component (and alpha channel) + * values, which range from 0 to 255. For the alpha channel, + * which defines the object's transparency level, 0 means totally + * transparent, while 255 means opaque. These color values are + * premultiplied by the alpha value. + * + * + * @note Use @c NULL pointers on the components you're not interested + * in: they'll be ignored by the function. + * + * @param[out] r The red component of the given color. + * @param[out] g The green component of the given color. + * @param[out] b The blue component of the given color. + * @param[out] a The alpha component of the given color. + * + */ +EAPI void evas_vg_node_color_get(Eo *obj, int *r, int *g, int *b, int *a); + +/** + * + * Sets the general/main color of the given Efl_Vg object to the given + * one. + * + * @see evas_vg_node_color_get() (for an example) + * @note These color values are expected to be premultiplied by @p a. + * + * @ingroup Evas_Object_Group_Basic + * + * @param[in] r The red component of the given color. + * @param[in] g The green component of the given color. + * @param[in] b The blue component of the given color. + * @param[in] a The alpha component of the given color. + * + */ +EAPI void evas_vg_node_color_set(Eo *obj, int r, int g, int b, int a); + +/** + * + * Retrieves the geometry of the given Efl_Vg object. + * + * @param[out] x in + * @param[out] y in + * @param[out] w in + * @param[out] h in + * + */ +EAPI void evas_vg_node_geometry_get(Eo *obj, int *x, int *y, int *w, int *h); + +/** + * + * Changes the geometry of the given Efl_Vg object. + * + * @param[in] x in + * @param[in] y in + * @param[in] w in + * @param[in] h in + * + */ +EAPI void evas_vg_node_geometry_set(Eo *obj, int x, int y, int w, int h); + +/** + * + * Stack @p obj immediately below @p below + * + * Objects, in a given canvas, are stacked in the order they get added + * to it. This means that, if they overlap, the highest ones will + * cover the lowest ones, in that order. This function is a way to + * change the stacking order for the objects. + * + * This function is intended to be used with objects belonging to + * the same layer in a given canvas, otherwise it will fail (and + * accomplish nothing). + * + * If you have smart objects on your canvas and @p obj is a member of + * one of them, then @p below must also be a member of the same + * smart object. + * + * Similarly, if @p obj is not a member of a smart object, @p below + * must not be either. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_stack_below() + * + * + * @param[in] below the object below which to stack + * + */ +EAPI void evas_vg_node_stack_below(Eo *obj, Eo *below); + +/** + * + * Stack @p obj immediately above @p above + * + * Objects, in a given canvas, are stacked in the order they get added + * to it. This means that, if they overlap, the highest ones will + * cover the lowest ones, in that order. This function is a way to + * change the stacking order for the objects. + * + * This function is intended to be used with objects belonging to + * the same layer in a given canvas, otherwise it will fail (and + * accomplish nothing). + * + * If you have smart objects on your canvas and @p obj is a member of + * one of them, then @p above must also be a member of the same + * smart object. + * + * Similarly, if @p obj is not a member of a smart object, @p above + * must not be either. + * + * @see evas_object_layer_get() + * @see evas_object_layer_set() + * @see evas_object_stack_below() + * + * + * @param[in] above the object above which to stack + * + */ +EAPI void evas_vg_node_stack_above(Eo *obj, Eo *above); + +/** + * + * Raise @p obj to the top of its layer. + * + * @p obj will, then, be the highest one in the layer it belongs + * to. Object on other layers won't get touched. + * + * @see evas_object_stack_above() + * @see evas_object_stack_below() + * @see evas_object_lower() + * + */ +EAPI void evas_vg_node_raise(Eo *obj); + +/** + * + * Lower @p obj to the bottom of its layer. + * + * @p obj will, then, be the lowest one in the layer it belongs + * to. Objects on other layers won't get touched. + * + * @see evas_object_stack_above() + * @see evas_object_stack_below() + * @see evas_object_raise() + * + * + * + */ +EAPI void evas_vg_node_lower(Eo *obj); + +#include "canvas/efl_vg_base.eo.legacy.h" + +/** + * + * Get the stroke scaling factor used for stroking this path. + * @since 1.14 + * + * + */ +EAPI double evas_vg_shape_stroke_scale_get(Eo *obj); + +/** + * + * Sets the stroke scale to be used for stroking the path. + * the scale property will be used along with stroke width property. + * @since 1.14 + * + * @param[in] s stroke scale value + * + */ +EAPI void evas_vg_shape_stroke_scale_set(Eo *obj, double s); + +/** + * + * Gets the color used for stroking the path. + * @since 1.14 + * + * @param[out] r The red component of the given color. + * @param[out] g The green component of the given color. + * @param[out] b The blue component of the given color. + * @param[out] a The alpha component of the given color. + * + */ +EAPI void evas_vg_shape_stroke_color_get(Eo *obj, int *r, int *g, int *b, int *a); + +/** + * + * Sets the color to be used for stroking the path. + * @since 1.14 + * + * @param[in] r The red component of the given color. + * @param[in] g The green component of the given color. + * @param[in] b The blue component of the given color. + * @param[in] a The alpha component of the given color. + * + */ +EAPI void evas_vg_shape_stroke_color_set(Eo *obj, int r, int g, int b, int a); + +/** + * + * Gets the stroke width to be used for stroking the path. + * @since 1.14 + * + * + */ +EAPI double evas_vg_shape_stroke_width_get(Eo *obj); + +/** + * + * Sets the stroke width to be used for stroking the path. + * @since 1.14 + * + * @param[in] w stroke width to be used + * + */ +EAPI void evas_vg_shape_stroke_width_set(Eo *obj, double w); + +/** + * + * Not Implemented + * + * + */ +EAPI double evas_vg_shape_stroke_location_get(Eo *obj); + +/** + * + * Not Implemented + * + * @param[in] centered + * + */ +EAPI void evas_vg_shape_stroke_location_set(Eo *obj, double centered); + +/** + * + * Not Implemented + * + * @param[out] dash + * @param[out] length + * + */ +EAPI void evas_vg_shape_stroke_dash_get(Eo *obj, const Efl_Gfx_Dash **dash, unsigned int *length); + +/** + * + * Not Implemented + * + * @param[in] dash + * @param[in] length + * + */ +EAPI void evas_vg_shape_stroke_dash_set(Eo *obj, const Efl_Gfx_Dash *dash, unsigned int length); + +/** + * + * Gets the cap style used for stroking path. + * @since 1.14 + * + * + */ +EAPI Efl_Gfx_Cap evas_vg_shape_stroke_cap_get(Eo *obj); + +/** + * + * Sets the cap style to be used for stroking the path. + * The cap will be used for capping the end point of a + * open subpath. + * + * @see Efl_Gfx_Cap + * @since 1.14 + * + * @param[in] c cap style to use , default is EFL_GFX_CAP_BUTT + * + */ +EAPI void evas_vg_shape_stroke_cap_set(Eo *obj, Efl_Gfx_Cap c); + +/** + * + * Gets the join style used for stroking path. + * @since 1.14 + * + * + */ +EAPI Efl_Gfx_Join evas_vg_shape_stroke_join_get(Eo *obj); + +/** + * + * Sets the join style to be used for stroking the path. + * The join style will be used for joining the two line segment + * while stroking teh path. + * + * @see Efl_Gfx_Join + * @since 1.14 + * + * @param[in] j join style to use , default is +EFL_GFX_JOIN_MITER + * + */ +EAPI void evas_vg_shape_stroke_join_set(Eo *obj, Efl_Gfx_Join j); + +/** + * + * Set the list of commands and points to be used to create the + * content of shape. + * + * @note see efl_gfx_path interface for how to create a command list. + * @see Efl_Gfx_Path_Command + * @since 1.14 + * + * @param[in] op command list + * @param[in] points point list + * + */ +EAPI void evas_vg_shape_shape_path_set(Eo *obj, const Efl_Gfx_Path_Command *op, const double *points); + +/** + * + * Gets the command and points list + * @since 1.14 + * + * @param[out] op command list + * @param[out] points point list + * + */ + +EAPI void evas_vg_shape_shape_path_get(Eo *obj, const Efl_Gfx_Path_Command **op, const double **points); +EAPI void evas_vg_shape_shape_path_length_get(Eo *obj, unsigned int *commands, unsigned int *points); +EAPI void evas_vg_shape_shape_current_get(Eo *obj, double *x, double *y); +EAPI void evas_vg_shape_shape_current_ctrl_get(Eo *obj, double *x, double *y); + +/** + * + * Copy the shape data from the object specified . + * + * @since 1.14 + * + * + * @param[in] dup_from Shape object from where data will be copied. + * + */ +EAPI void evas_vg_shape_shape_dup(Eo *obj, Eo *dup_from); + +/** + * + * Reset the shape data of the shape object. + * + * @since 1.14 + * + * + * + */ +EAPI void evas_vg_shape_shape_reset(Eo *obj); + +/** + * + * Moves the current point to the given point, + * implicitly starting a new subpath and closing the previous one. + * + * @see efl_gfx_path_append_close() + * @since 1.14 + * + * + * @param[in] x X co-ordinate of the current point. + * @param[in] y Y co-ordinate of the current point. + * + */ +EAPI void evas_vg_shape_shape_append_move_to(Eo *obj, double x, double y); + +/** + * + * Adds a straight line from the current position to the given endPoint. + * After the line is drawn, the current position is updated to be at the end + * point of the line. + * + * @note if no current position present, it draws a line to itself, basically + * a point. + * + * @see efl_gfx_path_append_move_to() + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the line. + * @param[in] y Y co-ordinate of end point of the line. + * + */ +EAPI void evas_vg_shape_shape_append_line_to(Eo *obj, double x, double y); + +/** + * + * Adds a quadratic Bezier curve between the current position and the + * given end point (x,y) using the control points specified by (ctrl_x, ctrl_y). + * After the path is drawn, the current position is updated to be at the end + * point of the path. + * + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the line. + * @param[in] y Y co-ordinate of end point of the line. + * @param[in] ctrl_x X co-ordinate of control point. + * @param[in] ctrl_y Y co-ordinate of control point. + * + */ +EAPI void evas_vg_shape_shape_append_quadratic_to(Eo *obj, double x, double y, double ctrl_x, double ctrl_y); + +/** + * + * Same as efl_gfx_path_append_quadratic_to() api only difference is that it + * uses the current control point to draw the bezier. + * + * @see efl_gfx_path_append_quadratic_to() + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the line. + * @param[in] y Y co-ordinate of end point of the line. + * + */ +EAPI void evas_vg_shape_shape_append_squadratic_to(Eo *obj, double x, double y); + +/** + * + * Adds a cubic Bezier curve between the current position and the + * given end point (x,y) using the control points specified by + * (ctrl_x0, ctrl_y0), and (ctrl_x1, ctrl_y1). After the path is drawn, + * the current position is updated to be at the end point of the path. + * + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the line. + * @param[in] y Y co-ordinate of end point of the line. + * @param[in] ctrl_x0 X co-ordinate of 1st control point. + * @param[in] ctrl_y0 Y co-ordinate of 1st control point. + * @param[in] ctrl_x1 X co-ordinate of 2nd control point. + * @param[in] ctrl_y1 Y co-ordinate of 2nd control point. + * + */ +EAPI void evas_vg_shape_shape_append_cubic_to(Eo *obj, double x, double y, double ctrl_x0, double ctrl_y0, double ctrl_x1, double ctrl_y1); + +/** + * + * Same as efl_gfx_path_append_cubic_to() api only difference is that it uses + * the current control point to draw the bezier. + * + * @see efl_gfx_path_append_cubic_to() + * + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the line. + * @param[in] y Y co-ordinate of end point of the line. + * @param[in] ctrl_x X co-ordinate of 2nd control point. + * @param[in] ctrl_y Y co-ordinate of 2nd control point. + * + */ +EAPI void evas_vg_shape_shape_append_scubic_to(Eo *obj, double x, double y, double ctrl_x, double ctrl_y); + +/** + * + * Append an arc that connects from the current point int the point list + * to the given point (x,y). The arc is defined by the given radius in + * x-direction (rx) and radius in y direction (ry) . + * + * @note Use this api if you know the end point's of the arc otherwise + * use more convenient function efl_gfx_path_append_arc_to() + * + * @see efl_gfx_path_append_arc_to() + * @since 1.14 + * + * + * @param[in] x X co-ordinate of end point of the arc. + * @param[in] y Y co-ordinate of end point of the arc. + * @param[in] rx radius of arc in x direction. + * @param[in] ry radius of arc in y direction. + * @param[in] angle x-axis rotation , normally 0. + * @param[in] large_arc Defines whether to draw the larger arc or smaller arc joining two point. + * @param[in] sweep Defines whether the arc will be drawn counter-clockwise or clockwise from current point to the end point taking into account the large_arc property. + * + */ +EAPI void evas_vg_shape_shape_append_arc_to(Eo *obj, double x, double y, double rx, double ry, double angle, Eina_Bool large_arc, Eina_Bool sweep); + +/** + * + * Closes the current subpath by drawing a line to the beginning of the subpath, + * automatically starting a new path. The current point of the new path is + * (0, 0). + * + * @note If the subpath does not contain any points, this function does nothing. + * + * @since 1.14 + * + * + * + */ +EAPI void evas_vg_shape_shape_append_close(Eo *obj); + +/** + * + * Append a circle with given center and radius. + * + * @see efl_gfx_path_append_arc() + * @since 1.14 + * + * + * @param[in] x X co-ordinate of the center of the circle. + * @param[in] y Y co-ordinate of the center of the circle. + * @param[in] radius radius of the circle. + * + */ +EAPI void evas_vg_shape_shape_append_circle(Eo *obj, double x, double y, double radius); + +/** + * + * Append the given rectangle with rounded corner to the path. + * + * The xr and yr arguments specify the radii of the ellipses defining the + * corners of the rounded rectangle. + * + * @note xr and yr are specified in terms of width and height respectively. + * + * @note if xr and yr are 0, then it will draw a rectangle without rounded corner. + * + * @since 1.14 + * + * + * @param[in] x X co-ordinate of the rectangle. + * @param[in] y Y co-ordinate of the rectangle. + * @param[in] w Width of the rectangle. + * @param[in] h Height of the rectangle. + * @param[in] rx The x radius of the rounded corner and should be in range [ 0 to w/2 ] + * @param[in] ry The y radius of the rounded corner and should be in range [ 0 to h/2 ] + * + */ +EAPI void evas_vg_shape_shape_append_rect(Eo *obj, double x, double y, double w, double h, double rx, double ry); + +EAPI void evas_vg_shape_shape_append_svg_path(Eo *obj, const char *svg_path_data); +EAPI Eina_Bool evas_vg_shape_shape_interpolate(Eo *obj, const Eo *from, const Eo *to, double pos_map); +EAPI Eina_Bool evas_vg_shape_shape_equal_commands(Eo *obj, const Eo *with); + +#include "canvas/efl_vg_shape.eo.legacy.h" + +/** + * + * Set the list of color stops for the gradient + * @since 1.14 + * + * @param[in] colors color stops list + * @param[in] length length of the list + * + */ +EAPI void evas_vg_gradient_stop_set(Eo *obj, const Efl_Gfx_Gradient_Stop *colors, unsigned int length); + +/** + * + * get the list of color stops. + * @since 1.14 + * + * @param[out] colors color stops list + * @param[out] length length of the list + * + */ +EAPI void evas_vg_gradient_stop_get(Eo *obj, const Efl_Gfx_Gradient_Stop **colors, unsigned int *length); + +/** + * + * Specifies the spread method that should be used for this gradient. + * @since 1.14 + * + * @param[in] s spread type to be used + * + */ +EAPI void evas_vg_gradient_spread_set(Eo *obj, Efl_Gfx_Gradient_Spread s); + +/** + * + * Returns the spread method use by this gradient. The default is + * EFL_GFX_GRADIENT_SPREAD_PAD. + * @since 1.14 + * + * + */ +EAPI Efl_Gfx_Gradient_Spread evas_vg_gradient_spread_get(Eo *obj); + +#include "canvas/efl_vg_gradient.eo.legacy.h" + +/** + * + * Sets the start point of this linear gradient. + * + * @param[in] x x co-ordinate of start point + * @param[in] y y co-ordinate of start point + * + */ +EAPI void evas_vg_gradient_linear_start_set(Eo *obj, double x, double y); + +/** + * + * Gets the start point of this linear gradient. + * + * @param[out] x x co-ordinate of start point + * @param[out] y y co-ordinate of start point + * + */ +EAPI void evas_vg_gradient_linear_start_get(Eo *obj, double *x, double *y); + +/** + * + * Sets the end point of this linear gradient. + * + * @param[in] x x co-ordinate of end point + * @param[in] y y co-ordinate of end point + * + */ +EAPI void evas_vg_gradient_linear_end_set(Eo *obj, double x, double y); + +/** + * + * Gets the end point of this linear gradient. + * + * @param[out] x x co-ordinate of end point + * @param[out] y y co-ordinate of end point + * + */ +EAPI void evas_vg_gradient_linear_end_get(Eo *obj, double *x, double *y); + +#include "canvas/efl_vg_gradient_linear.eo.legacy.h" + +/** + * + * Sets the center of this radial gradient. + * + * @param[in] x x co-ordinate of center point + * @param[in] y y co-ordinate of center point + * + */ +EAPI void evas_vg_gradient_radial_center_set(Eo *obj, double x, double y); + +/** + * + * Gets the center of this radial gradient. + * + * @param[out] x x co-ordinate of center point + * @param[out] y y co-ordinate of center point + * + */ +EAPI void evas_vg_gradient_radial_center_get(Eo *obj, double *x, double *y); + +/** + * + * Sets the center radius of this radial gradient. + * + * @param[in] r center radius + * + */ +EAPI void evas_vg_gradient_radial_radius_set(Eo *obj, double r); + +/** + * + * Gets the center radius of this radial gradient. + * + * + */ +EAPI double evas_vg_gradient_radial_radius_get(Eo *obj); + +/** + * + * Sets the focal point of this radial gradient. + * + * @param[in] x x co-ordinate of focal point + * @param[in] y y co-ordinate of focal point + * + */ +EAPI void evas_vg_gradient_radial_focal_set(Eo *obj, double x, double y); + +/** + * + * Gets the focal point of this radial gradient. + * + * @param[out] x x co-ordinate of focal point + * @param[out] y y co-ordinate of focal point + * + */ +EAPI void evas_vg_gradient_radial_focal_get(Eo *obj, double *x, double *y); + +#include "canvas/efl_vg_gradient_radial.eo.legacy.h" + +#endif + /** * @} */ @@ -1576,6 +2636,40 @@ NULL, otherwise. */ EAPI void evas_object_image_file_get(const Eo *obj, const char **file, const char **key); +/** + * + * Set the source mmaped file from where an image object must fetch the real + * image data (it must be an Eina_File). + * + * If the file supports multiple data stored in it (as Eet files do), + * you can specify the key to be used as the index of the image in + * this file. + * + * @since 1.8 + * + * @param[in] f The mmaped file + * @param[in] key The image key in @p file (if its an Eet one), or @c +NULL, otherwise. + */ +EAPI void evas_object_image_mmap_set(Eo *obj, const Eina_File *f, const char *key); + +/** + * + * Get the source mmaped file from where an image object must fetch the real + * image data (it must be an Eina_File). + * + * If the file supports multiple data stored in it (as Eet files do), + * you can get the key to be used as the index of the image in + * this file. + * + * @since 1.10 + * + * @param[out] f The mmaped file + * @param[out] key The image key in @p file (if its an Eet one), or @c +NULL, otherwise. + */ +EAPI void evas_object_image_mmap_get(const Eo *obj, const Eina_File **f, const char **key); + /** * * Save the given image object's contents to an (image) file. @@ -1720,6 +2814,109 @@ EAPI void evas_object_image_smooth_scale_set(Eo *obj, Eina_Bool smooth_scale); */ EAPI Eina_Bool evas_object_image_smooth_scale_get(const Eo *obj); +/** + * + * Sets the tiling mode for the given evas image object's fill. + * EVAS_TEXTURE_RESTRICT, or EVAS_TEXTURE_PAD. + * + * @param[in] spread One of EVAS_TEXTURE_REFLECT, EVAS_TEXTURE_REPEAT, + */ +EAPI void evas_object_image_fill_spread_set(Evas_Object *obj, Evas_Fill_Spread spread); + +/** + * + * Retrieves the spread (tiling mode) for the given image object's + * fill. + * + * @return The current spread mode of the image object. + * + */ +EAPI Evas_Fill_Spread evas_object_image_fill_spread_get(const Evas_Object *obj); + +/** + * + * Set how to fill an image object's drawing rectangle given the + * (real) image bound to it. + * + * Note that if @p w or @p h are smaller than the dimensions of + * @p obj, the displayed image will be @b tiled around the object's + * area. To have only one copy of the bound image drawn, @p x and @p y + * must be 0 and @p w and @p h need to be the exact width and height + * of the image object itself, respectively. + * + * See the following image to better understand the effects of this + * call. On this diagram, both image object and original image source + * have @c a x @c a dimensions and the image itself is a circle, with + * empty space around it: + * + * @image html image-fill.png + * @image rtf image-fill.png + * @image latex image-fill.eps + * + * @warning The default values for the fill parameters are @p x = 0, + * @p y = 0, @p w = 0 and @p h = 0. Thus, if you're not using the + * evas_object_image_filled_add() helper and want your image + * displayed, you'll have to set valid values with this function on + * your object. + * + * @note evas_object_image_filled_set() is a helper function which + * will @b override the values set here automatically, for you, in a + * given way. + * + * @param[in] x The x coordinate (from the top left corner of the bound +image) to start drawing from. + * @param[in] y The y coordinate (from the top left corner of the bound +image) to start drawing from. + * @param[in] w The width the bound image will be displayed at. + * @param[in] h The height the bound image will be displayed at. + */ +EAPI void evas_object_image_fill_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h); + +/** + * + * Retrieve how an image object is to fill its drawing rectangle, + * given the (real) image bound to it. + * + * @note Use @c NULL pointers on the fill components you're not + * interested in: they'll be ignored by the function. + * + * See @ref evas_object_image_fill_set() for more details. + * + * @param[out] x The x coordinate (from the top left corner of the bound +image) to start drawing from. + * @param[out] y The y coordinate (from the top left corner of the bound +image) to start drawing from. + * @param[out] w The width the bound image will be displayed at. + * @param[out] h The height the bound image will be displayed at. + */ +EAPI void evas_object_image_fill_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); + +/** + * + * Sets the size of the given image object. + * + * This function will scale down or crop the image so that it is + * treated as if it were at the given size. If the size given is + * smaller than the image, it will be cropped. If the size given is + * larger, then the image will be treated as if it were in the upper + * left hand corner of a larger image that is otherwise transparent. + * + * @param[in] w The new width of the image. + * @param[in] h The new height of the image. + */ +EAPI void evas_object_image_size_set(Evas_Object *obj, int w, int h); + +/** + * + * Retrieves the size of the given image object. + * + * See @ref evas_object_image_size_set() for more details. + * + * @param[out] w The new width of the image. + * @param[out] h The new height of the image. + */ +EAPI void evas_object_image_size_get(const Evas_Object *obj, int *w, int *h); + #include "canvas/evas_image.eo.legacy.h" /** diff --git a/src/lib/evas/canvas/efl_vg_base.eo b/src/lib/evas/canvas/efl_vg_base.eo new file mode 100644 index 0000000000..ebd0dce3c9 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_base.eo @@ -0,0 +1,95 @@ +abstract Efl.VG.Base (Eo.Base, Efl.Gfx.Base, Efl.Gfx.Stack) +{ + eo_prefix: efl_vg; + legacy_prefix: evas_vg_node; + properties { + transformation { + set { + /*@ + Sets the transformation matrix to be used for this node object. + @since 1.14 + */ + } + get { + /*@ + Gets the transformation matrix used for this node object. + @since 1.14 + */ + } + values { + const(Eina_Matrix3) *m; /*@ transformation matrix */ + } + } + origin { + set { + /*@ + Sets the origin position of this node object. This origin position + affects to node transformation + @since 1.14 + */ + } + get { + /*@ + Gets the origin position of this node object. + @since 1.14 + */ + } + values { + double x; /* @origin x position */ + double y; /* @origin y position */ + } + } + mask { + set { + } + get { + } + values { + Efl_VG *m; + } + } +/* quality { + set { + } + get { + } + values { + Evas_VG_Quality q; + } + } */ + } + methods { + bounds_get { + /*@ + Give the bounding box in screen coordinate as being drawn. + It will start as the control box until it is refined once the shape + is computed. + @since 1.14 + */ + params { + @out Eina_Rectangle r; /*@ bounding box to be returned */ + } + } + } + implements { + Eo.Base.parent.set; + Eo.Base.constructor; + Eo.Base.destructor; + Efl.Gfx.Base.visible.set; + Efl.Gfx.Base.visible.get; + Efl.Gfx.Base.color.set; + Efl.Gfx.Base.color.get; + Efl.Gfx.Base.color_part.set; + Efl.Gfx.Base.color_part.get; + Efl.Gfx.Base.size.get; + Efl.Gfx.Base.position.set; + Efl.Gfx.Base.position.get; + Efl.Gfx.Stack.below.get; + Efl.Gfx.Stack.above.get; + Efl.Gfx.Stack.stack_below; + Efl.Gfx.Stack.stack_above; + Efl.Gfx.Stack.raise; + Efl.Gfx.Stack.lower; + @virtual .bounds_get; + } +} \ No newline at end of file diff --git a/src/lib/evas/canvas/efl_vg_container.eo b/src/lib/evas/canvas/efl_vg_container.eo new file mode 100644 index 0000000000..0c954e2696 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_container.eo @@ -0,0 +1,9 @@ +class Efl.VG.Container (Efl.VG.Base) +{ + legacy_prefix: evas_vg_container; + implements { + Eo.Base.constructor; + Eo.Base.destructor; + Efl.VG.Base.bounds_get; + } +} diff --git a/src/lib/evas/canvas/efl_vg_gradient.eo b/src/lib/evas/canvas/efl_vg_gradient.eo new file mode 100644 index 0000000000..de78039adf --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_gradient.eo @@ -0,0 +1,10 @@ +abstract Efl.VG.Gradient (Efl.VG.Base, Efl.Gfx.Gradient.Base) +{ + legacy_prefix: evas_vg_gradient; + implements { + Efl.Gfx.Gradient.Base.stop.set; + Efl.Gfx.Gradient.Base.stop.get; + Efl.Gfx.Gradient.Base.spread.set; + Efl.Gfx.Gradient.Base.spread.get; + } +} diff --git a/src/lib/evas/canvas/efl_vg_gradient_linear.eo b/src/lib/evas/canvas/efl_vg_gradient_linear.eo new file mode 100644 index 0000000000..4aaddd4fd7 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_gradient_linear.eo @@ -0,0 +1,13 @@ +class Efl.VG.Gradient_Linear (Efl.VG.Gradient, Efl.Gfx.Gradient.Linear) +{ + legacy_prefix: evas_vg_gradient_linear; + implements { + Efl.Gfx.Gradient.Linear.start.set; + Efl.Gfx.Gradient.Linear.start.get; + Efl.Gfx.Gradient.Linear.end.set; + Efl.Gfx.Gradient.Linear.end.get; + Efl.VG.Base.bounds_get; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/evas/canvas/efl_vg_gradient_radial.eo b/src/lib/evas/canvas/efl_vg_gradient_radial.eo new file mode 100644 index 0000000000..62eb0868d2 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_gradient_radial.eo @@ -0,0 +1,15 @@ +class Efl.VG.Gradient_Radial (Efl.VG.Gradient, Efl.Gfx.Gradient.Radial) +{ + legacy_prefix: evas_vg_gradient_radial; + implements { + Efl.Gfx.Gradient.Radial.center.set; + Efl.Gfx.Gradient.Radial.center.get; + Efl.Gfx.Gradient.Radial.radius.set; + Efl.Gfx.Gradient.Radial.radius.get; + Efl.Gfx.Gradient.Radial.focal.set; + Efl.Gfx.Gradient.Radial.focal.get; + Efl.VG.Base.bounds_get; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/evas/canvas/efl_vg_root_node.eo b/src/lib/evas/canvas/efl_vg_root_node.eo new file mode 100644 index 0000000000..685bf7e134 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_root_node.eo @@ -0,0 +1,8 @@ +class Efl.VG.Root_Node (Efl.VG.Container) +{ + legacy_prefix: evas_vg_root_node; + implements { + Eo.Base.parent.set; + Eo.Base.constructor; + } +} diff --git a/src/lib/evas/canvas/efl_vg_shape.eo b/src/lib/evas/canvas/efl_vg_shape.eo new file mode 100644 index 0000000000..ee43e83d04 --- /dev/null +++ b/src/lib/evas/canvas/efl_vg_shape.eo @@ -0,0 +1,47 @@ +class Efl.VG.Shape (Efl.VG.Base, Efl.Gfx.Shape) +{ + legacy_prefix: evas_vg_shape; + properties { + fill { + set { + } + get { + } + values { + Efl_VG *f; + } + } + stroke_fill { + set { + } + get { + } + values { + Efl_VG *f; + } + } + stroke_marker { + set { + } + get { + } + values { + Efl_VG *m; + } + } + } + implements { + Efl.Gfx.Shape.stroke_scale; + Efl.Gfx.Shape.stroke_color; + Efl.Gfx.Shape.stroke_width; + Efl.Gfx.Shape.stroke_location; + Efl.Gfx.Shape.stroke_dash; + Efl.Gfx.Shape.stroke_cap; + Efl.Gfx.Shape.stroke_join; + Efl.Gfx.Base.color_part.set; + Efl.Gfx.Base.color_part.get; + Efl.VG.Base.bounds_get; + Eo.Base.constructor; + Eo.Base.destructor; + } +} diff --git a/src/lib/evas/canvas/evas_3d_mesh.c b/src/lib/evas/canvas/evas_3d_mesh.c index 52a71f2d66..f055da1317 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.c +++ b/src/lib/evas/canvas/evas_3d_mesh.c @@ -840,16 +840,39 @@ _evas_3d_mesh_alpha_test_enable_get(Eo *obj EINA_UNUSED, Evas_3D_Mesh_Data *pd) return pd->alpha_test_enabled; } -EOLIAN static void -_evas_3d_mesh_mmap_set(Eo *obj, Evas_3D_Mesh_Data *pd, - Eina_File *file, const char *key EINA_UNUSED) +EOLIAN static Eina_Bool +_evas_3d_mesh_efl_file_mmap_set(Eo *obj, + Evas_3D_Mesh_Data *pd, + const Eina_File *f, const char *key EINA_UNUSED) { _mesh_fini(pd); _mesh_init(pd); - if (file == NULL) return; + if (f == NULL) return EINA_FALSE; - evas_common_load_model_from_eina_file(obj, file); + evas_common_load_model_from_eina_file(obj, f); + + return EINA_TRUE; +} + +EOLIAN static void +_evas_3d_mesh_efl_file_mmap_get(Eo *obj EINA_UNUSED, + Evas_3D_Mesh_Data *pd EINA_UNUSED, + const Eina_File **f EINA_UNUSED, + const char **key EINA_UNUSED) +{ + #warning "mmap get is not implemented on Evas_3D_Mesh." + ERR("mmap get is not implemented !"); +} + +EOLIAN static void +_evas_3d_mesh_efl_file_file_get(Eo *obj EINA_UNUSED, + Evas_3D_Mesh_Data *pd EINA_UNUSED, + const char **file EINA_UNUSED, + const char **key EINA_UNUSED) +{ + #warning "file get is not implemented on Evas_3D_Mesh." + ERR("file get is not implemented !"); } EOLIAN static Eina_Bool diff --git a/src/lib/evas/canvas/evas_3d_mesh.eo b/src/lib/evas/canvas/evas_3d_mesh.eo index 784f91a257..28022ee07f 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.eo +++ b/src/lib/evas/canvas/evas_3d_mesh.eo @@ -4,21 +4,6 @@ class Evas_3D_Mesh (Evas_3D_Object, Evas.Common_Interface, Efl.File) data: Evas_3D_Mesh_Data; methods { - mmap_set { - /** - * Load mesh data from Eina_File. - * - * Loading a mesh from existing Eina_File is supported. Currently, only MD2, OBJ, - * PLY and EET file formats are supported. - * - * @ingroup Evas_3D_Mesh - */ - params { - @in Eina_File* file; /*@ Eina_File with mesh data. */ - @in const(char)* key; /*@ Key in the mesh file. */ - } - } - frame_vertex_data_set { /*@ Set the vertex data of the key frame of the given mesh. @@ -540,6 +525,9 @@ class Evas_3D_Mesh (Evas_3D_Object, Evas.Common_Interface, Efl.File) Evas_3D_Object.update_notify; Evas_3D_Object.change_notify; Efl.File.file.set; + Efl.File.file.get; + Efl.File.mmap.set; + Efl.File.mmap.get; Efl.File.save; } diff --git a/src/lib/evas/canvas/evas_image.eo b/src/lib/evas/canvas/evas_image.eo index df97e32525..e6783b1400 100644 --- a/src/lib/evas/canvas/evas_image.eo +++ b/src/lib/evas/canvas/evas_image.eo @@ -1,4 +1,4 @@ -class Evas.Image (Evas.Object, Efl.File, Efl.Image) +class Evas.Image (Evas.Object, Efl.File, Efl.Image, Efl.Gfx.Fill, Efl.Gfx.View) { legacy_prefix: evas_object_image; eo_prefix: evas_obj_image; @@ -362,23 +362,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image) bool enable; /*@ @c EINA_TRUE means that it should honor the orientation information */ } } - fill_spread { - set { - /*@ - Sets the tiling mode for the given evas image object's fill. - EVAS_TEXTURE_RESTRICT, or EVAS_TEXTURE_PAD. */ - } - get { - /*@ - Retrieves the spread (tiling mode) for the given image object's - fill. - - @return The current spread mode of the image object. */ - } - values { - Evas_Fill_Spread spread; /*@ One of EVAS_TEXTURE_REFLECT, EVAS_TEXTURE_REPEAT, */ - } - } border_center_fill { set { /*@ @@ -410,28 +393,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image) #Evas_Border_Fill_Mode). */ } } - size { - set { - /*@ - Sets the size of the given image object. - - This function will scale down or crop the image so that it is - treated as if it were at the given size. If the size given is - smaller than the image, it will be cropped. If the size given is - larger, then the image will be treated as if it were in the upper - left hand corner of a larger image that is otherwise transparent. */ - } - get { - /*@ - Retrieves the size of the given image object. - - See @ref evas_object_image_size_set() for more details. */ - } - values { - int w; /*@ The new width of the image. */ - int h; /*@ The new height of the image. */ - } - } source_visible { set { /*@ @@ -474,56 +435,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image) otherwise. */ } } - fill { - set { - /*@ - Set how to fill an image object's drawing rectangle given the - (real) image bound to it. - - Note that if @p w or @p h are smaller than the dimensions of - @p obj, the displayed image will be @b tiled around the object's - area. To have only one copy of the bound image drawn, @p x and @p y - must be 0 and @p w and @p h need to be the exact width and height - of the image object itself, respectively. - - See the following image to better understand the effects of this - call. On this diagram, both image object and original image source - have @c a x @c a dimensions and the image itself is a circle, with - empty space around it: - - @image html image-fill.png - @image rtf image-fill.png - @image latex image-fill.eps - - @warning The default values for the fill parameters are @p x = 0, - @p y = 0, @p w = 0 and @p h = 0. Thus, if you're not using the - evas_object_image_filled_add() helper and want your image - displayed, you'll have to set valid values with this function on - your object. - - @note evas_object_image_filled_set() is a helper function which - will @b override the values set here automatically, for you, in a - given way. */ - } - get { - /*@ - Retrieve how an image object is to fill its drawing rectangle, - given the (real) image bound to it. - - @note Use @c NULL pointers on the fill components you're not - interested in: they'll be ignored by the function. - - See @ref evas_object_image_fill_set() for more details. */ - } - values { - Evas_Coord x; /*@ The x coordinate (from the top left corner of the bound - image) to start drawing from. */ - Evas_Coord y; /*@ The y coordinate (from the top left corner of the bound - image) to start drawing from. */ - Evas_Coord w; /*@ The width the bound image will be displayed at. */ - Evas_Coord h; /*@ The height the bound image will be displayed at. */ - } - } native_surface { set { /*@ @@ -663,35 +574,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image) void *data; /*@ The data pointer to be passed to @a func. */ } } - mmap { - set { - /*@ - Set the source mmaped file from where an image object must fetch the real - image data (it must be an Eina_File). - - If the file supports multiple data stored in it (as Eet files do), - you can specify the key to be used as the index of the image in - this file. - - @since 1.8 */ - } - get { - /*@ - Get the source mmaped file from where an image object must fetch the real - image data (it must be an Eina_File). - - If the file supports multiple data stored in it (as Eet files do), - you can get the key to be used as the index of the image in - this file. - - @since 1.10 */ - } - values { - const(Eina.File)* f; /*@ The mmaped file */ - const(char)* key; /*@ The image key in @p file (if its an Eet one), or @c - NULL, otherwise. */ - } - } data_copy { set { /*@ @@ -1094,11 +976,19 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image) Eo.Base.dbg_info_get; Efl.File.file.set; Efl.File.file.get; + Efl.File.mmap.set; + Efl.File.mmap.get; Efl.File.save; Efl.Image.animated.get; Efl.Image.load_size.set; Efl.Image.load_size.get; Efl.Image.smooth_scale.set; Efl.Image.smooth_scale.get; + Efl.Gfx.Fill.fill_spread.set; + Efl.Gfx.Fill.fill_spread.get; + Efl.Gfx.Fill.fill.set; + Efl.Gfx.Fill.fill.get; + Efl.Gfx.View.size.set; + Efl.Gfx.View.size.get; } } diff --git a/src/lib/evas/canvas/evas_layer.c b/src/lib/evas/canvas/evas_layer.c index e1baf63d7b..3731078a04 100644 --- a/src/lib/evas/canvas/evas_layer.c +++ b/src/lib/evas/canvas/evas_layer.c @@ -178,8 +178,16 @@ _evas_object_layer_set_child(Evas_Object *eo_obj, Evas_Object *par, short l) /* public functions */ +EAPI void +evas_object_layer_set(Evas_Object *obj, short l) +{ + eo_do((Evas_Object *)obj, efl_gfx_stack_layer_set(l)); +} + EOLIAN void -_evas_object_layer_set(Eo *eo_obj, Evas_Object_Protected_Data *obj EINA_UNUSED, short l) +_evas_object_efl_gfx_stack_layer_set(Eo *eo_obj, + Evas_Object_Protected_Data *obj, + short l) { Evas *eo_e; @@ -236,8 +244,17 @@ _evas_object_layer_set(Eo *eo_obj, Evas_Object_Protected_Data *obj EINA_UNUSED, evas_object_inform_call_restack(eo_obj); } +EAPI short +evas_object_layer_get(const Evas_Object *obj) +{ + short ret; + + return eo_do_ret((Evas_Object *)obj, ret, efl_gfx_stack_layer_get()); +} + EOLIAN short -_evas_object_layer_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) +_evas_object_efl_gfx_stack_layer_get(Eo *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj) { if (obj->smart.parent) { diff --git a/src/lib/evas/canvas/evas_object.eo b/src/lib/evas/canvas/evas_object.eo index afbaa27d5e..51b936933a 100644 --- a/src/lib/evas/canvas/evas_object.eo +++ b/src/lib/evas/canvas/evas_object.eo @@ -1,4 +1,4 @@ -abstract Evas.Object (Eo.Base, Evas.Common_Interface) +abstract Evas.Object (Eo.Base, Evas.Common_Interface, Efl.Gfx.Base, Efl.Gfx.Stack) { eo_prefix: evas_obj; data: Evas_Object_Protected_Data; @@ -80,19 +80,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) Evas_Coord h; /*@ Integer to use as the preferred height hint. */ } } - visibility { - set { - /*@ Makes the given Evas object visible or invisible. */ - legacy: null; - } - get { - /*@ Retrieves whether or not the given Evas object is visible. */ - legacy: evas_object_visible_get; - } - values { - bool v; /*@ @c EINA_TRUE if to make the object visible, @c EINA_FALSE otherwise */ - } - } type { set { /*@ Sets the type of the given Evas object. */ @@ -394,39 +381,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) Evas_Coord h; /*@ Integer to use as aspect height ratio term. */ } } - layer { - set { - /*@ - Sets the layer of its canvas that the given object will be part of. - - If you don't use this function, you'll be dealing with an @b unique - layer of objects, the default one. Additional layers are handy when - you don't want a set of objects to interfere with another set with - regard to @b stacking. Two layers are completely disjoint in that - matter. - - This is a low-level function, which you'd be using when something - should be always on top, for example. - - @warning Be careful, it doesn't make sense to change the layer of - smart objects' children. Smart objects have a layer of their own, - which should contain all their children objects. - - @see evas_object_layer_get() */ - } - get { - /*@ - Retrieves the layer of its canvas that the given object is part of. - - @return Number of its layer - - @see evas_object_layer_set() */ - } - values { - short l; /*@ The number of the layer to place the object on. - Must be between #EVAS_LAYER_MIN and #EVAS_LAYER_MAX. */ - } - } clip { set { /*@ @@ -745,20 +699,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) clipper, @c EINA_FALSE otherwise. */ } } - size { - set { - /*@ Changes the size of the given Evas object. */ - legacy: evas_object_resize; - } - get { - /*@ Retrieves the (rectangular) size of the given Evas object. */ - legacy: null; - } - values { - Evas_Coord w; /*@ in */ - Evas_Coord h; /*@ in */ - } - } focus { set { /*@ @@ -1031,20 +971,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) (@c EINA_FALSE) */ } } - position { - set { - /*@ Move the given Evas object to the given location inside its canvas' viewport. */ - legacy: evas_object_move; - } - get { - /*@ Retrieves the position of the given Evas object. */ - legacy: null; - } - values { - Evas_Coord x; /*@ in */ - Evas_Coord y; /*@ in */ - } - } anti_alias { set { /*@ @@ -1062,54 +988,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) bool anti_alias; /*@ (@c EINA_TRUE) if the object is to be anti_aliased, (@c EINA_FALSE) otherwise. */ } } - color { - set { - /*@ - Sets the general/main color of the given Evas object to the given - one. - - @see evas_object_color_get() (for an example) - @note These color values are expected to be premultiplied by @p a. - - @ingroup Evas_Object_Group_Basic */ - } - get { - /*@ - Retrieves the general/main color of the given Evas object. - - Retrieves the “main” color's RGB component (and alpha channel) - values, which range from 0 to 255. For the alpha channel, - which defines the object's transparency level, 0 means totally - transparent, while 255 means opaque. These color values are - premultiplied by the alpha value. - - Usually you’ll use this attribute for text and rectangle objects, - where the “main” color is their unique one. If set for objects - which themselves have colors, like the images one, those colors get - modulated by this one. - - @note All newly created Evas rectangles get the default color - values of 255 255 255 255 (opaque white). - - @note Use @c NULL pointers on the components you're not interested - in: they'll be ignored by the function. - - Example: - @dontinclude evas-object-manipulation.c - @skip int alpha, r, g, b; - @until return - - See the full @ref Example_Evas_Object_Manipulation "example". - - @ingroup Evas_Object_Group_Basic */ - } - values { - int r; /*@ The red component of the given color. */ - int g; /*@ The green component of the given color. */ - int b; /*@ The blue component of the given color. */ - int a; /*@ The alpha component of the given color. */ - } - } smart_data { get { /*@ @@ -1139,23 +1017,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) return: Evas_Object * @warn_unused; } } - below { - get { - /*@ - Get the Evas object stacked right below @p obj - - @return the #Evas_Object directly below @p obj, if any, or @c NULL, - if none - - This function will traverse layers in its search, if there are - objects on layers below the one @p obj is placed at. - - @see evas_object_layer_get() - @see evas_object_layer_set() - @see evas_object_below_get() */ - return: Evas_Object * @warn_unused; - } - } clipees { get { /*@ @@ -1210,23 +1071,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) return: Evas_Object * @warn_unused; } } - above { - get { - /*@ - Get the Evas object stacked right above @p obj - - @return the #Evas_Object directly above @p obj, if any, or @c NULL, - if none - - This function will traverse layers in its search, if there are - objects on layers above the one @p obj is placed at. - - @see evas_object_layer_get() - @see evas_object_layer_set() - @see evas_object_below_get() */ - return: Evas_Object * @warn_unused; - } - } size_hint_display_mode { get { /*@ @@ -1310,74 +1154,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) receiving the @p keyname events. */ } } - stack_below { - /*@ - Stack @p obj immediately below @p below - - Objects, in a given canvas, are stacked in the order they get added - to it. This means that, if they overlap, the highest ones will - cover the lowest ones, in that order. This function is a way to - change the stacking order for the objects. - - This function is intended to be used with objects belonging to - the same layer in a given canvas, otherwise it will fail (and - accomplish nothing). - - If you have smart objects on your canvas and @p obj is a member of - one of them, then @p below must also be a member of the same - smart object. - - Similarly, if @p obj is not a member of a smart object, @p below - must not be either. - - @see evas_object_layer_get() - @see evas_object_layer_set() - @see evas_object_stack_below() */ - - params { - @in Evas_Object *below @nonull; /*@ the object below which to stack */ - } - } - raise { - /*@ - Raise @p obj to the top of its layer. - - @p obj will, then, be the highest one in the layer it belongs - to. Object on other layers won't get touched. - - @see evas_object_stack_above() - @see evas_object_stack_below() - @see evas_object_lower() */ - - } - stack_above { - /*@ - Stack @p obj immediately above @p above - - Objects, in a given canvas, are stacked in the order they get added - to it. This means that, if they overlap, the highest ones will - cover the lowest ones, in that order. This function is a way to - change the stacking order for the objects. - - This function is intended to be used with objects belonging to - the same layer in a given canvas, otherwise it will fail (and - accomplish nothing). - - If you have smart objects on your canvas and @p obj is a member of - one of them, then @p above must also be a member of the same - smart object. - - Similarly, if @p obj is not a member of a smart object, @p above - must not be either. - - @see evas_object_layer_get() - @see evas_object_layer_set() - @see evas_object_stack_below() */ - - params { - @in Evas_Object *above @nonull; /*@ the object above which to stack */ - } - } smart_type_check @const { /*@ Checks whether a given smart object or any of its smart object @@ -1456,18 +1232,6 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) present to trigger the event. */ } } - lower { - /*@ - Lower @p obj to the bottom of its layer. - - @p obj will, then, be the lowest one in the layer it belongs - to. Objects on other layers won't get touched. - - @see evas_object_stack_above() - @see evas_object_stack_below() - @see evas_object_raise() */ - - } clip_unset { /*@ Disable/cease clipping on a clipped @p obj object. @@ -1522,6 +1286,24 @@ abstract Evas.Object (Eo.Base, Evas.Common_Interface) Eo.Base.destructor; Eo.Base.dbg_info_get; Evas.Common_Interface.evas.get; + Efl.Gfx.Base.visible.set; + Efl.Gfx.Base.visible.get; + Efl.Gfx.Base.position.set; + Efl.Gfx.Base.position.get; + Efl.Gfx.Base.color.set; + Efl.Gfx.Base.color.get; + Efl.Gfx.Base.color_part.set; + Efl.Gfx.Base.color_part.get; + Efl.Gfx.Base.size.set; + Efl.Gfx.Base.size.get; + Efl.Gfx.Stack.layer.set; + Efl.Gfx.Stack.layer.get; + Efl.Gfx.Stack.below.get; + Efl.Gfx.Stack.above.get; + Efl.Gfx.Stack.stack_below; + Efl.Gfx.Stack.stack_above; + Efl.Gfx.Stack.raise; + Efl.Gfx.Stack.lower; } events { mouse,in; /*@ Mouse In Event */ diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index 90b3c49aa2..ebd3292c99 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -412,7 +412,7 @@ evas_object_image_memfile_set(Evas_Object *eo_obj, void *data, int size, char *f f = eina_file_virtualize(NULL, data, size, EINA_TRUE); if (!f) return ; - eo_do(eo_obj, evas_obj_image_mmap_set(f, key)); + eo_do(eo_obj, efl_file_mmap_set(f, key)); eina_file_close(f); } @@ -544,8 +544,10 @@ _image_done_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o) evas_object_change(eo_obj, obj); } -EOLIAN static void -_evas_image_mmap_set(Eo *eo_obj, Evas_Image_Data *o, const Eina_File *f, const char *key) +EOLIAN static Eina_Bool +_evas_image_efl_file_mmap_set(Eo *eo_obj, + Evas_Image_Data *o, + const Eina_File *f, const char *key) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); Evas_Image_Load_Opts lo; @@ -553,18 +555,22 @@ _evas_image_mmap_set(Eo *eo_obj, Evas_Image_Data *o, const Eina_File *f, const c if (o->cur->u.f == f) { if ((!o->cur->key) && (!key)) - return; + return EINA_FALSE; if ((o->cur->key) && (key) && (!strcmp(o->cur->key, key))) - return; + return EINA_FALSE; } evas_object_async_block(obj); _image_init_set(f, NULL, key, eo_obj, obj, o, &lo); o->engine_data = ENFN->image_mmap(ENDT, o->cur->u.f, o->cur->key, &o->load_error, &lo); _image_done_set(eo_obj, obj, o); + + return EINA_TRUE; } EOLIAN static void -_evas_image_mmap_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, const Eina_File **f, const char **key) +_evas_image_efl_file_mmap_get(Eo *eo_obj EINA_UNUSED, + Evas_Image_Data *o, + const Eina_File **f, const char **key) { if (f) *f = o->cur->mmaped_source ? o->cur->u.f : NULL; @@ -972,8 +978,17 @@ _evas_image_border_scale_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o) return o->cur->border.scale; } +EAPI void +evas_object_image_fill_set(Evas_Image *obj, + Evas_Coord x, Evas_Coord y, + Evas_Coord w, Evas_Coord h) +{ + eo_do((Evas_Image *)obj, efl_gfx_fill_set(x, y, w, h)); +} + EOLIAN static void -_evas_image_fill_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) +_evas_image_efl_gfx_fill_fill_set(Eo *eo_obj, Evas_Image_Data *o, + int x, int y, int w, int h) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); @@ -1002,8 +1017,17 @@ _evas_image_fill_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Coord x, Evas_Coord y, evas_object_change(eo_obj, obj); } +EAPI void +evas_object_image_fill_get(const Evas_Image *obj, + Evas_Coord *x, Evas_Coord *y, + Evas_Coord *w, Evas_Coord *h) +{ + eo_do((Evas_Image *)obj, efl_gfx_fill_get(x, y, w, h)); +} + EOLIAN static void -_evas_image_fill_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) +_evas_image_efl_gfx_fill_fill_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, + int *x, int *y, int *w, int *h) { if (x) *x = o->cur->fill.x; if (y) *y = o->cur->fill.y; @@ -1011,8 +1035,15 @@ _evas_image_fill_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, Evas_Coord *x, if (h) *h = o->cur->fill.h; } +EAPI void +evas_object_image_fill_spread_set(Evas_Image *obj, Evas_Fill_Spread spread) +{ + eo_do((Evas_Image *)obj, efl_gfx_fill_spread_set(spread)); +} + EOLIAN static void -_evas_image_fill_spread_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Fill_Spread spread) +_evas_image_efl_gfx_fill_fill_spread_set(Eo *eo_obj, Evas_Image_Data *o, + Efl_Gfx_Fill_Spread spread) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); @@ -1027,14 +1058,29 @@ _evas_image_fill_spread_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Fill_Spread spr evas_object_change(eo_obj, obj); } -EOLIAN static Evas_Fill_Spread -_evas_image_fill_spread_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o) +EAPI Evas_Fill_Spread +evas_object_image_fill_spread_get(const Evas_Image *obj) +{ + Evas_Fill_Spread ret; + + return eo_do_ret((Evas_Image *)obj, ret, efl_gfx_fill_spread_get()); +} + +EOLIAN static Efl_Gfx_Fill_Spread +_evas_image_efl_gfx_fill_fill_spread_get(Eo *eo_obj EINA_UNUSED, + Evas_Image_Data *o) { return (Evas_Fill_Spread)o->cur->spread;; } +EAPI void +evas_object_image_size_set(Evas_Image *obj, int w, int h) +{ + eo_do((Evas_Image *)obj, efl_gfx_view_size_set(w, h)); +} + EOLIAN static void -_evas_image_size_set(Eo *eo_obj, Evas_Image_Data *o, int w, int h) +_evas_image_efl_gfx_view_size_set(Eo *eo_obj, Evas_Image_Data *o, int w, int h) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); @@ -1097,8 +1143,16 @@ _evas_image_size_set(Eo *eo_obj, Evas_Image_Data *o, int w, int h) evas_object_change(eo_obj, obj); } +EAPI void +evas_object_image_size_get(const Evas_Image *obj, int *w, int *h) +{ + eo_do((Evas_Image *)obj, efl_gfx_view_size_get(w, h)); +} + EOLIAN static void -_evas_image_size_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, int *w, int *h) +_evas_image_efl_gfx_view_size_get(Eo *eo_obj EINA_UNUSED, + Evas_Image_Data *o, + int *w, int *h) { if (w) *w = o->cur->image.w; if (h) *h = o->cur->image.h; @@ -4915,6 +4969,17 @@ evas_object_image_file_get(const Eo *obj, const char **file, const char **key) eo_do((Eo *) obj, efl_file_get(file, key)); } +EAPI void +evas_object_image_mmap_set(Evas_Image *obj, const Eina_File *f, const char *key) +{ + eo_do((Evas_Image *)obj, efl_file_mmap_set(f, key)); +} + +EAPI void +evas_object_image_mmap_get(const Evas_Image *obj, const Eina_File **f, const char **key) +{ + eo_do((Evas_Image *)obj, efl_file_mmap_get(f, key)); +} EAPI Eina_Bool evas_object_image_save(const Eo *obj, const char *file, const char *key, const char *flags) diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index d5a8a478bf..3c0c8d51f9 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -750,12 +750,19 @@ evas_object_geometry_set(Evas_Object *eo_obj, Evas_Coord x, Evas_Coord y, Evas_C return; MAGIC_CHECK_END(); eo_do(eo_obj, - evas_obj_position_set(x, y), - evas_obj_size_set(w, h)); + efl_gfx_position_set(x, y), + efl_gfx_size_set(w, h)); +} + +EAPI void +evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + eo_do((Evas_Object *)obj, efl_gfx_position_set(x, y)); } EOLIAN static void -_evas_object_position_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord x, Evas_Coord y) +_evas_object_efl_gfx_base_position_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, + Evas_Coord x, Evas_Coord y) { Eina_Bool is, was = EINA_FALSE; @@ -838,8 +845,15 @@ _evas_object_position_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coor evas_object_inform_call_move(eo_obj, obj); } +EAPI void +evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + eo_do((Evas_Object *)obj, efl_gfx_size_set(w, h)); +} + EOLIAN static void -_evas_object_size_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord w, Evas_Coord h) +_evas_object_efl_gfx_base_size_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, + Evas_Coord w, Evas_Coord h) { Eina_Bool is, was = EINA_FALSE; Eina_Bool pass = EINA_FALSE, freeze = EINA_FALSE; @@ -923,33 +937,37 @@ evas_object_geometry_get(const Evas_Object *eo_obj, Evas_Coord *x, Evas_Coord *y if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0; return; MAGIC_CHECK_END(); - eo_do((Eo *)eo_obj, evas_obj_position_get(x, y), evas_obj_size_get(w, h)); + eo_do((Eo *)eo_obj, efl_gfx_position_get(x, y), efl_gfx_size_get(w, h)); } EOLIAN static void -_evas_object_position_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord *x, Evas_Coord *y) +_evas_object_efl_gfx_base_position_get(Eo *obj EINA_UNUSED, + Evas_Object_Protected_Data *pd, + Evas_Coord *x, Evas_Coord *y) { - if ((obj->delete_me) || (!obj->layer)) + if ((pd->delete_me) || (!pd->layer)) { if (x) *x = 0; if (y) *y = 0; return; } - if (x) *x = obj->cur->geometry.x; - if (y) *y = obj->cur->geometry.y; + if (x) *x = pd->cur->geometry.x; + if (y) *y = pd->cur->geometry.y; } EOLIAN static void -_evas_object_size_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord *w, Evas_Coord *h) +_evas_object_efl_gfx_base_size_get(Eo *obj EINA_UNUSED, + Evas_Object_Protected_Data *pd, + Evas_Coord *w, Evas_Coord *h) { - if (obj->delete_me) + if (pd->delete_me) { if (w) *w = 0; if (h) *h = 0; return; } - if (w) *w = obj->cur->geometry.w; - if (h) *h = obj->cur->geometry.h; + if (w) *w = pd->cur->geometry.w; + if (h) *h = pd->cur->geometry.h; } static void @@ -1186,18 +1204,28 @@ evas_object_show(Evas_Object *eo_obj) MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); return; MAGIC_CHECK_END(); - eo_do(eo_obj, evas_obj_visibility_set(EINA_TRUE)); + eo_do(eo_obj, efl_gfx_visible_set(EINA_TRUE)); } EAPI void evas_object_hide(Evas_Object *eo_obj) { if (!eo_obj) return; - eo_do(eo_obj, evas_obj_visibility_set(EINA_FALSE)); + eo_do(eo_obj, efl_gfx_visible_set(EINA_FALSE)); +} + +EAPI Eina_Bool +evas_object_visible_get(const Evas_Object *obj) +{ + Eina_Bool ret; + + return eo_do_ret((Evas_Object *)obj, ret, efl_gfx_visible_get()); } static void -_evas_object_visibility_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool visible) +_evas_object_efl_gfx_base_visible_set(Eo *eo_obj, + Evas_Object_Protected_Data *obj, + Eina_Bool visible) { evas_object_async_block(obj); if (visible) _show(eo_obj, obj); @@ -1373,14 +1401,22 @@ _hide(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj) } static Eina_Bool -_evas_object_visibility_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) +_evas_object_efl_gfx_base_visible_get(Eo *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj) { if (obj->delete_me) return EINA_FALSE; return obj->cur->visible; } +EAPI void +evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a) +{ + eo_do((Evas_Object *)obj, efl_gfx_color_set(r, g, b, a)); +} + EOLIAN static void -_evas_object_color_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, int r, int g, int b, int a) +_evas_object_efl_gfx_base_color_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, + int r, int g, int b, int a) { if (obj->delete_me) return; if (r > 255) r = 255; if (r < 0) r = 0; @@ -1435,8 +1471,27 @@ _evas_object_color_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, int r, int g evas_object_change(eo_obj, obj); } +EOLIAN static Eina_Bool +_evas_object_efl_gfx_base_color_part_set(Eo *obj, Evas_Object_Protected_Data *pd, + const char *part, + int r, int g, int b, int a) +{ + if (part) return EINA_FALSE; + + _evas_object_efl_gfx_base_color_set(obj, pd, r, g, b, a); + return EINA_TRUE; +} + +EAPI void +evas_object_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) +{ + eo_do((Evas_Object *)obj, efl_gfx_color_get(r, g, b, a)); +} + EOLIAN static void -_evas_object_color_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, int *r, int *g, int *b, int *a) +_evas_object_efl_gfx_base_color_get(Eo *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj, + int *r, int *g, int *b, int *a) { if (obj->delete_me) { @@ -1449,6 +1504,18 @@ _evas_object_color_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, if (a) *a = obj->cur->color.a; } +EOLIAN static Eina_Bool +_evas_object_efl_gfx_base_color_part_get(Eo *obj, + Evas_Object_Protected_Data *pd, + const char *part, + int *r, int *g, int *b, int *a) +{ + if (part) return EINA_FALSE; + + _evas_object_efl_gfx_base_color_get(obj, pd, r, g, b, a); + return EINA_TRUE; +} + EOLIAN static void _evas_object_anti_alias_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool anti_alias) { @@ -1546,18 +1613,18 @@ _evas_object_eo_base_dbg_info_get(Eo *eo_obj, Evas_Object_Protected_Data *obj EI Eina_Bool clipees_has; eo_do(eo_obj, - visible = evas_obj_visibility_get(), - layer = evas_obj_layer_get(), + visible = efl_gfx_visible_get(), + layer = efl_gfx_stack_layer_get(), name = evas_obj_name_get(), - evas_obj_position_get(&x, &y), - evas_obj_size_get(&w, &h), + efl_gfx_position_get(&x, &y), + efl_gfx_size_get(&w, &h), scale = evas_obj_scale_get(), evas_obj_size_hint_min_get(&minw, &minh), evas_obj_size_hint_max_get(&maxw, &maxh), evas_obj_size_hint_request_get(&requestw, &requesth), evas_obj_size_hint_align_get(&dblx, &dbly), evas_obj_size_hint_weight_get(&dblw, &dblh), - evas_obj_color_get(&r, &g, &b, &a), + efl_gfx_color_get(&r, &g, &b, &a), focus = evas_obj_focus_get(), m = evas_obj_pointer_mode_get(), pass_event = evas_obj_pass_events_get(), diff --git a/src/lib/evas/canvas/evas_object_text.c b/src/lib/evas/canvas/evas_object_text.c index e17bd63384..c053515e6d 100644 --- a/src/lib/evas/canvas/evas_object_text.c +++ b/src/lib/evas/canvas/evas_object_text.c @@ -926,7 +926,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t } EOLIAN static void -_evas_text_evas_object_size_set(Eo *eo_obj, Evas_Text_Data *o, Evas_Coord w, Evas_Coord h) +_evas_text_efl_gfx_base_size_set(Eo *eo_obj, Evas_Text_Data *o, int w, int h) { Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); @@ -1235,7 +1235,7 @@ _evas_text_style_set(Eo *eo_obj, Evas_Text_Data *o, Evas_Text_Style_Type style) h = obj->cur->geometry.h + (t - pt) + (b - pb); eo_do_super(eo_obj, MY_CLASS, - evas_obj_size_set(w, h)); + efl_gfx_size_set(w, h)); evas_object_change(eo_obj, obj); } @@ -2350,12 +2350,12 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text) min = w + l + r < obj->cur->geometry.w || obj->cur->geometry.w == 0 ? w + l + r : obj->cur->geometry.w; eo_do_super(eo_obj, MY_CLASS, - evas_obj_size_set(min, h + t + b)); + efl_gfx_size_set(min, h + t + b)); } else { eo_do_super(eo_obj, MY_CLASS, - evas_obj_size_set(w + l + r, h + t + b)); + efl_gfx_size_set(w + l + r, h + t + b)); } //// obj->cur->cache.geometry.validity = 0; } @@ -2369,7 +2369,7 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text) evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, &t, &b); eo_do_super(eo_obj, MY_CLASS, - evas_obj_size_set(0, o->max_ascent + o->max_descent + t + b)); + efl_gfx_size_set(0, o->max_ascent + o->max_descent + t + b)); //// obj->cur->cache.geometry.validity = 0; } o->last_computed.w = obj->cur->geometry.w; diff --git a/src/lib/evas/canvas/evas_object_vg.c b/src/lib/evas/canvas/evas_object_vg.c new file mode 100644 index 0000000000..57d4090d68 --- /dev/null +++ b/src/lib/evas/canvas/evas_object_vg.c @@ -0,0 +1,410 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" +#include "efl_vg_root_node.eo.h" + +#define MY_CLASS EVAS_VG_CLASS + +/* private magic number for rectangle objects */ +static const char o_type[] = "vectors"; + +const char *o_vg_type = o_type; + +/* private struct for rectangle object internal data */ +typedef struct _Evas_VG_Data Evas_VG_Data; + +struct _Evas_VG_Data +{ + void *engine_data; + Efl_VG *root; + + Eina_Rectangle fill; + + unsigned int width, height; +}; + +static void evas_object_vg_render(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data, + void *output, void *context, void *surface, + int x, int y, Eina_Bool do_async); +static void evas_object_vg_render_pre(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data); +static void evas_object_vg_render_post(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data); +static unsigned int evas_object_vg_id_get(Evas_Object *eo_obj); +static unsigned int evas_object_vg_visual_id_get(Evas_Object *eo_obj); +static void *evas_object_vg_engine_data_get(Evas_Object *eo_obj); +static int evas_object_vg_is_opaque(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data); +static int evas_object_vg_was_opaque(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data); + +static const Evas_Object_Func object_func = +{ + /* methods (compulsory) */ + NULL, + evas_object_vg_render, + evas_object_vg_render_pre, + evas_object_vg_render_post, + evas_object_vg_id_get, + evas_object_vg_visual_id_get, + evas_object_vg_engine_data_get, + /* these are optional. NULL = nothing */ + NULL, + NULL, + NULL, + NULL, + evas_object_vg_is_opaque, + evas_object_vg_was_opaque, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/* the actual api call to add a vector graphic object */ +EAPI Evas_Object * +evas_object_vg_add(Evas *e) +{ + MAGIC_CHECK(e, Evas, MAGIC_EVAS); + return NULL; + MAGIC_CHECK_END(); + Evas_Object *eo_obj = eo_add(MY_CLASS, e); + + // Ask backend to return the main Ector_Surface + + return eo_obj; +} + +Efl_VG * +_evas_vg_root_node_get(Eo *obj EINA_UNUSED, Evas_VG_Data *pd) +{ + return pd->root; +} + +void +_evas_vg_eo_base_destructor(Eo *eo_obj, Evas_VG_Data *pd) +{ + eo_unref(pd->root); + eo_do_super(eo_obj, MY_CLASS, eo_destructor()); +} + +void +_evas_vg_eo_base_constructor(Eo *eo_obj, Evas_VG_Data *pd) +{ + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); + Eo *parent = NULL; + + eo_do_super(eo_obj, MY_CLASS, eo_constructor()); + + /* set up methods (compulsory) */ + obj->func = &object_func; + obj->private_data = eo_data_ref(eo_obj, MY_CLASS); + obj->type = o_type; + + /* root node */ + pd->root = eo_add(EFL_VG_ROOT_NODE_CLASS, eo_obj); + eo_ref(pd->root); + + eo_do(eo_obj, parent = eo_parent_get()); + evas_object_inject(eo_obj, obj, evas_object_evas_get(parent)); +} + +static void +_evas_vg_render(Evas_Object_Protected_Data *obj, + void *output, void *context, void *surface, Efl_VG *n, + Eina_Array *clips, Eina_Bool do_async) +{ + Efl_VG_Container_Data *vd = eo_data_scope_get(n, EFL_VG_CONTAINER_CLASS); + + if (eo_isa(n, EFL_VG_CONTAINER_CLASS)) + { + Efl_VG *child; + Eina_List *l; + + EINA_LIST_FOREACH(vd->children, l, child) + _evas_vg_render(obj, + output, context, surface, child, + clips, do_async); + } + else + { + Efl_VG_Base_Data *nd; + + nd = eo_data_scope_get(n, EFL_VG_BASE_CLASS); + + obj->layer->evas->engine.func->ector_renderer_draw(output, context, surface, nd->renderer, clips, do_async); + } +} + +static void +evas_object_vg_render(Evas_Object *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj, + void *type_private_data, + void *output, void *context, void *surface, + int x, int y, Eina_Bool do_async) +{ + Evas_VG_Data *vd = type_private_data; + + // FIXME: Set context (that should affect Ector_Surface) and + // then call Ector_Renderer render from bottom to top. Get the + // Ector_Surface that match the output from Evas engine API. + // It is a requirement that you can reparent an Ector_Renderer + // to another Ector_Surface as long as that Ector_Surface is a + // child of the main Ector_Surface (necessary for Evas_Map). + + /* render object to surface with context, and offxet by x,y */ + obj->layer->evas->engine.func->context_color_set(output, + context, + obj->cur->cache.clip.r, + obj->cur->cache.clip.g, + obj->cur->cache.clip.b, + obj->cur->cache.clip.a); + obj->layer->evas->engine.func->context_anti_alias_set(output, context, + obj->cur->anti_alias); + obj->layer->evas->engine.func->context_multiplier_unset(output, + context); + obj->layer->evas->engine.func->context_render_op_set(output, context, + obj->cur->render_op); + obj->layer->evas->engine.func->ector_begin(output, context, surface, + obj->cur->geometry.x + x, obj->cur->geometry.y + y, + do_async); + _evas_vg_render(obj, output, context, surface, vd->root, NULL, + do_async); + obj->layer->evas->engine.func->ector_end(output, context, surface, do_async); +} + +static void +evas_object_vg_render_pre(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj, + void *type_private_data) +{ + Evas_VG_Data *vd = type_private_data; + Efl_VG_Base_Data *rnd; + Evas_Public_Data *e = obj->layer->evas; + int is_v, was_v; + Ector_Surface *s; + + /* dont pre-render the obj twice! */ + if (obj->pre_render_done) return; + obj->pre_render_done = EINA_TRUE; + + /* pre-render phase. this does anything an object needs to do just before */ + /* rendering. this could mean loading the image data, retrieving it from */ + /* elsewhere, decoding video etc. */ + /* then when this is done the object needs to figure if it changed and */ + /* if so what and where and add the appropriate redraw rectangles */ + /* if someone is clipping this obj - go calculate the clipper */ + if (obj->cur->clipper) + { + if (obj->cur->cache.clip.dirty) + evas_object_clip_recalc(obj->cur->clipper); + obj->cur->clipper->func->render_pre(obj->cur->clipper->object, + obj->cur->clipper, + obj->cur->clipper->private_data); + } + /* now figure what changed and add draw rects */ + /* if it just became visible or invisible */ + is_v = evas_object_is_visible(eo_obj, obj); + was_v = evas_object_was_visible(eo_obj,obj); + if (!(is_v | was_v)) goto done; + + // FIXME: handle damage only on changed renderer. + s = e->engine.func->ector_get(e->engine.data.output); + if (vd->root && s) + _evas_vg_render_pre(vd->root, s, NULL); + + // FIXME: for now the walking Evas_VG_Node tree doesn't trigger any damage + // So just forcing it here if necessary + rnd = eo_data_scope_get(vd->root, EFL_VG_BASE_CLASS); + if (rnd->changed) + { + rnd->changed = EINA_FALSE; + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); + goto done; + } + + if (is_v != was_v) + { + evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v); + goto done; + } + if (obj->changed_map || obj->changed_src_visible) + { + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); + goto done; + } + /* it's not visible - we accounted for it appearing or not so just abort */ + if (!is_v) goto done; + /* clipper changed this is in addition to anything else for obj */ + evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, eo_obj); + /* if we restacked (layer or just within a layer) and don't clip anyone */ + if ((obj->restack) && (!obj->clip.clipees)) + { + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); + goto done; + } + /* if it changed render op */ + if (obj->cur->render_op != obj->prev->render_op) + { + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); + goto done; + } + /* if it changed color */ + if ((obj->cur->color.r != obj->prev->color.r) || + (obj->cur->color.g != obj->prev->color.g) || + (obj->cur->color.b != obj->prev->color.b) || + (obj->cur->color.a != obj->prev->color.a)) + { + evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, eo_obj, obj); + goto done; + } + /* if it changed geometry - and obviously not visibility or color */ + /* calculate differences since we have a constant color fill */ + /* we really only need to update the differences */ + if ((obj->cur->geometry.x != obj->prev->geometry.x) || + (obj->cur->geometry.y != obj->prev->geometry.y) || + (obj->cur->geometry.w != obj->prev->geometry.w) || + (obj->cur->geometry.h != obj->prev->geometry.h)) + { + evas_rects_return_difference_rects(&obj->layer->evas->clip_changes, + obj->cur->geometry.x, + obj->cur->geometry.y, + obj->cur->geometry.w, + obj->cur->geometry.h, + obj->prev->geometry.x, + obj->prev->geometry.y, + obj->prev->geometry.w, + obj->prev->geometry.h); + goto done; + } + /* it obviously didn't change - add a NO obscure - this "unupdates" this */ + /* area so if there were updates for it they get wiped. don't do it if we */ + /* arent fully opaque and we are visible */ + if (evas_object_is_visible(eo_obj, obj) && + evas_object_is_opaque(eo_obj, obj) && + (!obj->clip.clipees)) + { + Evas_Coord x, y, w, h; + + x = obj->cur->cache.clip.x; + y = obj->cur->cache.clip.y; + w = obj->cur->cache.clip.w; + h = obj->cur->cache.clip.h; + if (obj->cur->clipper) + { + RECTS_CLIP_TO_RECT(x, y, w, h, + obj->cur->clipper->cur->cache.clip.x, + obj->cur->clipper->cur->cache.clip.y, + obj->cur->clipper->cur->cache.clip.w, + obj->cur->clipper->cur->cache.clip.h); + } + obj->layer->evas->engine.func->output_redraws_rect_del + (obj->layer->evas->engine.data.output, + x + obj->layer->evas->framespace.x, + y + obj->layer->evas->framespace.y, + w, h); + } + done: + evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v); +} + +static void +evas_object_vg_render_post(Evas_Object *eo_obj, + Evas_Object_Protected_Data *obj EINA_UNUSED, + void *type_private_data EINA_UNUSED) +{ + /* this moves the current data to the previous state parts of the object */ + /* in whatever way is safest for the object. also if we don't need object */ + /* data anymore we can free it if the object deems this is a good idea */ + /* remove those pesky changes */ + evas_object_clip_changes_clean(eo_obj); + /* move cur to prev safely for object data */ + evas_object_cur_prev(eo_obj); +} + +static unsigned int +evas_object_vg_id_get(Evas_Object *eo_obj) +{ + Evas_VG_Data *o = eo_data_scope_get(eo_obj, MY_CLASS); + if (!o) return 0; + return MAGIC_OBJ_VG; +} + +static unsigned int +evas_object_vg_visual_id_get(Evas_Object *eo_obj) +{ + Evas_VG_Data *o = eo_data_scope_get(eo_obj, MY_CLASS); + if (!o) return 0; + return MAGIC_OBJ_SHAPE; +} + +static void * +evas_object_vg_engine_data_get(Evas_Object *eo_obj) +{ + Evas_VG_Data *o = eo_data_scope_get(eo_obj, MY_CLASS); + return o->engine_data; +} + +static int +evas_object_vg_is_opaque(Evas_Object *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj EINA_UNUSED, + void *type_private_data EINA_UNUSED) +{ + return 0; +} + +static int +evas_object_vg_was_opaque(Evas_Object *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj EINA_UNUSED, + void *type_private_data EINA_UNUSED) +{ + return 0; +} + +void +_evas_vg_efl_gfx_view_size_get(Eo *obj EINA_UNUSED, Evas_VG_Data *pd, + int *w, int *h) +{ + if (w) *w = pd->width; + if (h) *h = pd->height; +} + +void +_evas_vg_efl_gfx_view_size_set(Eo *obj EINA_UNUSED, Evas_VG_Data *pd, + int w, int h) +{ + pd->width = w; + pd->height = h; +} + +void +_evas_vg_efl_gfx_fill_fill_set(Eo *obj EINA_UNUSED, Evas_VG_Data *pd, + int x, int y, int w, int h) +{ + pd->fill.x = x; + pd->fill.y = y; + pd->fill.w = w; + pd->fill.h = h; +} + +void +_evas_vg_efl_gfx_fill_fill_get(Eo *obj EINA_UNUSED, Evas_VG_Data *pd, + int *x, int *y, int *w, int *h) +{ + if (x) *x = pd->fill.x; + if (y) *y = pd->fill.y; + if (w) *w = pd->fill.w; + if (h) *h = pd->fill.h; +} + +#include "evas_vg.eo.c" diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index b761bbe00d..5032b49541 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -107,7 +107,7 @@ _time_get() } struct accumulator { - double total, min, max; + double total, min, max, draw_start_time; int samples; const char *what; }; @@ -128,8 +128,27 @@ static struct accumulator sync_accumulator = { }; static void -_accumulate_time(double before, struct accumulator *acc) +_accumulate_time(double before, Eina_Bool async) { + static Eina_Bool async_start = EINA_TRUE; + static double cache_before; + struct accumulator *acc = &sync_accumulator; + if (async) + { + acc = &async_accumulator; + if (async_start) + { + async_start = EINA_FALSE; + cache_before = before; + return; + } + else + { + async_start = EINA_TRUE; + before = cache_before; + } + } + double diff = _time_get() - before; acc->total += diff; @@ -2084,9 +2103,7 @@ evas_render_updates_internal(Evas *eo_e, int redraw_all = 0; Eina_Bool haveup = 0; Evas_Render_Mode render_mode = EVAS_RENDER_MODE_UNDEF; -#ifdef EVAS_RENDER_DEBUG_TIMING - double start_time = _time_get(); -#endif + Eina_Rectangle clip_rect; MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS); @@ -2109,6 +2126,10 @@ evas_render_updates_internal(Evas *eo_e, } } +#ifdef EVAS_RENDER_DEBUG_TIMING + double start_time = _time_get(); +#endif + #ifdef EVAS_CSERVE2 if (evas_cserve2_use_get()) evas_cserve2_dispatch(); @@ -2639,7 +2660,7 @@ evas_render_updates_internal(Evas *eo_e, RD(0, "---]\n"); #ifdef EVAS_RENDER_DEBUG_TIMING - _accumulate_time(start_time, do_async ? &async_accumulator : &sync_accumulator); + _accumulate_time(start_time, do_async); #endif return EINA_TRUE; @@ -2725,6 +2746,10 @@ evas_render_wakeup(Evas *eo_e) evas_render_updates_free(ret_updates); eo_unref(eo_e); + +#ifdef EVAS_RENDER_DEBUG_TIMING + _accumulate_time(0, EINA_TRUE); +#endif } static void diff --git a/src/lib/evas/canvas/evas_stack.c b/src/lib/evas/canvas/evas_stack.c index 44508da022..84fa6d8a51 100644 --- a/src/lib/evas/canvas/evas_stack.c +++ b/src/lib/evas/canvas/evas_stack.c @@ -37,8 +37,14 @@ evas_object_below_get_internal(const Evas_Object_Protected_Data *obj) return NULL; } +EAPI void +evas_object_raise(Evas_Object *obj) +{ + eo_do((Evas_Object *)obj, efl_gfx_stack_raise()); +} + EOLIAN void -_evas_object_raise(Eo *eo_obj, Evas_Object_Protected_Data *obj) +_evas_object_efl_gfx_stack_raise(Eo *eo_obj, Evas_Object_Protected_Data *obj) { evas_object_async_block(obj); if (evas_object_intercept_call_raise(eo_obj, obj)) return; @@ -84,8 +90,14 @@ _evas_object_raise(Eo *eo_obj, Evas_Object_Protected_Data *obj) } } +EAPI void +evas_object_lower(Evas_Object *obj) +{ + eo_do((Evas_Object *)obj, efl_gfx_stack_lower()); +} + EOLIAN void -_evas_object_lower(Eo *eo_obj, Evas_Object_Protected_Data *obj) +_evas_object_efl_gfx_stack_lower(Eo *eo_obj, Evas_Object_Protected_Data *obj) { evas_object_async_block(obj); if (evas_object_intercept_call_lower(eo_obj, obj)) return; @@ -132,8 +144,14 @@ _evas_object_lower(Eo *eo_obj, Evas_Object_Protected_Data *obj) } } +EAPI void +evas_object_stack_above(Evas_Object *obj, Evas_Object *above) +{ + eo_do((Evas_Object *)obj, efl_gfx_stack_above(above)); +} + EOLIAN void -_evas_object_stack_above(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *eo_above) +_evas_object_efl_gfx_stack_stack_above(Eo *eo_obj, Evas_Object_Protected_Data *obj, Efl_Gfx_Stack *eo_above) { evas_object_async_block(obj); if (!eo_above) @@ -208,8 +226,14 @@ _evas_object_stack_above(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Objec } } +EAPI void +evas_object_stack_below(Evas_Object *obj, Evas_Object *below) +{ + eo_do((Evas_Object *)obj, efl_gfx_stack_below(below)); +} + EOLIAN void -_evas_object_stack_below(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object *eo_below) +_evas_object_efl_gfx_stack_stack_below(Eo *eo_obj, Evas_Object_Protected_Data *obj, Efl_Gfx_Stack *eo_below) { evas_object_async_block(obj); if (!eo_below) @@ -284,8 +308,17 @@ _evas_object_stack_below(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Objec } } -EOLIAN Evas_Object * -_evas_object_above_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) +EAPI Evas_Object * +evas_object_above_get(const Evas_Object *obj) +{ + Evas_Object *ret; + + return eo_do_ret((Evas_Object *)obj, ret, efl_gfx_stack_above_get()); +} + +EOLIAN Efl_Gfx_Stack * +_evas_object_efl_gfx_stack_above_get(Eo *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj) { if (obj->smart.parent) { @@ -306,8 +339,17 @@ _evas_object_above_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) return NULL; } -EOLIAN Evas_Object * -_evas_object_below_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj) +EAPI Evas_Object * +evas_object_below_get(const Evas_Object *obj) +{ + Evas_Object *ret; + + return eo_do_ret((Evas_Object *)obj, ret, efl_gfx_stack_below_get()); +} + +EOLIAN Efl_Gfx_Stack * +_evas_object_efl_gfx_stack_below_get(Eo *eo_obj EINA_UNUSED, + Evas_Object_Protected_Data *obj) { if (obj->smart.parent) { diff --git a/src/lib/evas/canvas/evas_text.eo b/src/lib/evas/canvas/evas_text.eo index c6ddfe29a5..1d423335e8 100644 --- a/src/lib/evas/canvas/evas_text.eo +++ b/src/lib/evas/canvas/evas_text.eo @@ -362,7 +362,7 @@ class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties) Eo.Base.constructor; Eo.Base.destructor; Eo.Base.dbg_info_get; - Evas.Object.size.set; + Efl.Gfx.Base.size.set; Efl.Text.text.set; Efl.Text.text.get; Efl.Text_Properties.font.get; diff --git a/src/lib/evas/canvas/evas_vg.eo b/src/lib/evas/canvas/evas_vg.eo new file mode 100644 index 0000000000..8c6d3526e1 --- /dev/null +++ b/src/lib/evas/canvas/evas_vg.eo @@ -0,0 +1,30 @@ +class Evas.VG (Evas.Object, Efl.Gfx.Fill, Efl.Gfx.View) +{ + legacy_prefix: evas_object_vg; + eo_prefix: evas_obj_vg; + properties { + root_node { + get { + /*@ + Get the root node of the evas_object_vg. + + @note To manually create the shape object and show in the Vg + object canvas you must create the hirarchy and set the + parent as root node. + @since 1.14 + */ + } + values { + Efl_VG *container; /*@ Root node of the VG canvas */ + } + } + } + implements { + Eo.Base.constructor; + Eo.Base.destructor; + Efl.Gfx.Fill.fill.set; + Efl.Gfx.Fill.fill.get; + Efl.Gfx.View.size.set; + Efl.Gfx.View.size.get; + } +} diff --git a/src/lib/evas/canvas/evas_vg_container.c b/src/lib/evas/canvas/evas_vg_container.c new file mode 100644 index 0000000000..ba0eeec8ca --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_container.c @@ -0,0 +1,81 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" + +#define MY_CLASS EFL_VG_CONTAINER_CLASS + +static void +_efl_vg_container_render_pre(Eo *obj EINA_UNUSED, + Eina_Matrix3 *parent, + Ector_Surface *s, + void *data, + Efl_VG_Base_Data *nd) +{ + Efl_VG_Container_Data *pd = data; + Eina_List *l; + Eo *child; + + if (!nd->changed) return ; + nd->changed = EINA_FALSE; + + EFL_VG_COMPUTE_MATRIX(current, parent, nd); + + EINA_LIST_FOREACH(pd->children, l, child) + _evas_vg_render_pre(child, s, current); +} + +static void +_efl_vg_container_eo_base_constructor(Eo *obj, + Efl_VG_Container_Data *pd) +{ + Efl_VG_Base_Data *nd; + + eo_do_super(obj, MY_CLASS, eo_constructor()); + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + nd->render_pre = _efl_vg_container_render_pre; + nd->data = pd; +} + +static void +_efl_vg_container_eo_base_destructor(Eo *obj, + Efl_VG_Container_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +static void +_efl_vg_container_efl_vg_base_bounds_get(Eo *obj EINA_UNUSED, + Efl_VG_Container_Data *pd, + Eina_Rectangle *r) +{ + Eina_Rectangle s; + Eina_Bool first = EINA_TRUE; + Eina_List *l; + Eo *child; + + EINA_RECTANGLE_SET(&s, -1, -1, 0, 0); + + EINA_LIST_FOREACH(pd->children, l, child) + { + if (first) + { + eo_do(child, efl_vg_bounds_get(r)); + first = EINA_FALSE; + } + else + { + eo_do(child, efl_vg_bounds_get(&s)); + eina_rectangle_union(r, &s); + } + } +} + +EAPI Efl_VG* +evas_vg_container_add(Efl_VG *parent) +{ + return eo_add(EFL_VG_CONTAINER_CLASS, parent); +} + +#include "efl_vg_container.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_gradient.c b/src/lib/evas/canvas/evas_vg_gradient.c new file mode 100644 index 0000000000..245b6fe334 --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_gradient.c @@ -0,0 +1,80 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" + +#include + +static void +_efl_vg_gradient_efl_gfx_gradient_base_stop_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Data *pd, + const Efl_Gfx_Gradient_Stop *colors, + unsigned int length) +{ + pd->colors = realloc(pd->colors, length * sizeof(Efl_Gfx_Gradient_Stop)); + if (!pd->colors) + { + pd->colors_count = 0; + return ; + } + + memcpy(pd->colors, colors, length * sizeof(Efl_Gfx_Gradient_Stop)); + pd->colors_count = length; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_gradient_efl_gfx_gradient_base_stop_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Data *pd, + const Efl_Gfx_Gradient_Stop **colors, + unsigned int *length) +{ + if (colors) *colors = pd->colors; + if (length) *length = pd->colors_count; +} + +static void +_efl_vg_gradient_efl_gfx_gradient_base_spread_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Data *pd, + Efl_Gfx_Gradient_Spread s) +{ + pd->s = s; + + _efl_vg_base_changed(obj); +} + +static Efl_Gfx_Gradient_Spread +_efl_vg_gradient_efl_gfx_gradient_base_spread_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Data *pd) +{ + return pd->s; +} + +EAPI void +evas_vg_gradient_stop_set(Eo *obj, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) +{ + eo_do(obj, efl_gfx_gradient_stop_set(colors, length)); +} + +EAPI void +evas_vg_gradient_stop_get(Eo *obj, const Efl_Gfx_Gradient_Stop **colors, unsigned int *length) +{ + eo_do(obj, efl_gfx_gradient_stop_get(colors, length)); +} + +EAPI void +evas_vg_gradient_spread_set(Eo *obj, Efl_Gfx_Gradient_Spread s) +{ + eo_do(obj, efl_gfx_gradient_spread_set(s)); +} + +EAPI Efl_Gfx_Gradient_Spread +evas_vg_gradient_spread_get(Eo *obj) +{ + Efl_Gfx_Gradient_Spread ret; + + return eo_do_ret(obj, ret, efl_gfx_gradient_spread_get()); +} + +#include "efl_vg_gradient.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_gradient_linear.c b/src/lib/evas/canvas/evas_vg_gradient_linear.c new file mode 100644 index 0000000000..9f05fac4ad --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_gradient_linear.c @@ -0,0 +1,145 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" + +#include + +#define MY_CLASS EFL_VG_GRADIENT_LINEAR_CLASS + +typedef struct _Efl_VG_Gradient_Linear_Data Efl_VG_Gradient_Linear_Data; +struct _Efl_VG_Gradient_Linear_Data +{ + struct { + double x, y; + } start, end; +}; + +static void +_efl_vg_gradient_linear_efl_gfx_gradient_linear_start_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Linear_Data *pd, + double x, double y) +{ + pd->start.x = x; + pd->start.y = y; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_gradient_linear_efl_gfx_gradient_linear_start_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Linear_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->start.x; + if (y) *y = pd->start.y; +} + +static void +_efl_vg_gradient_linear_efl_gfx_gradient_linear_end_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Linear_Data *pd, + double x, double y) +{ + pd->end.x = x; + pd->end.y = y; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_gradient_linear_efl_gfx_gradient_linear_end_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Linear_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->end.x; + if (y) *y = pd->end.y; +} + +static void +_efl_vg_gradient_linear_render_pre(Eo *obj, + Eina_Matrix3 *parent, + Ector_Surface *s, + void *data, + Efl_VG_Base_Data *nd) +{ + Efl_VG_Gradient_Linear_Data *pd = data; + Efl_VG_Gradient_Data *gd; + + if (!nd->changed) return ; + nd->changed = EINA_FALSE; + + gd = eo_data_scope_get(obj, EFL_VG_GRADIENT_CLASS); + EFL_VG_COMPUTE_MATRIX(current, parent, nd); + + if (!nd->renderer) + { + eo_do(s, nd->renderer = ector_surface_renderer_factory_new(ECTOR_RENDERER_GENERIC_GRADIENT_LINEAR_MIXIN)); + } + + eo_do(nd->renderer, + ector_renderer_transformation_set(current), + ector_renderer_origin_set(nd->x, nd->y), + ector_renderer_color_set(nd->r, nd->g, nd->b, nd->a), + ector_renderer_visibility_set(nd->visibility), + efl_gfx_gradient_stop_set(gd->colors, gd->colors_count), + efl_gfx_gradient_spread_set(gd->s), + efl_gfx_gradient_linear_start_set(pd->start.x, pd->start.y), + efl_gfx_gradient_linear_end_set(pd->end.x, pd->end.y), + ector_renderer_prepare()); +} + +static void +_efl_vg_gradient_linear_eo_base_constructor(Eo *obj, + Efl_VG_Gradient_Linear_Data *pd) +{ + Efl_VG_Base_Data *nd; + + eo_do_super(obj, MY_CLASS, eo_constructor()); + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + nd->render_pre = _efl_vg_gradient_linear_render_pre; + nd->data = pd; +} + +static void +_efl_vg_gradient_linear_eo_base_destructor(Eo *obj, Efl_VG_Gradient_Linear_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +static void +_efl_vg_gradient_linear_efl_vg_base_bounds_get(Eo *obj, Efl_VG_Gradient_Linear_Data *pd, Eina_Rectangle *r) +{ + Efl_VG_Base_Data *nd; + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + EINA_RECTANGLE_SET(r, + nd->x + pd->start.x, nd->y + pd->start.y, + pd->end.x - pd->start.x, pd->end.y - pd->start.x); +} + +EAPI void +evas_vg_gradient_linear_start_set(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_gradient_linear_start_set(x, y)); +} + +EAPI void +evas_vg_gradient_linear_start_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_gradient_linear_start_get(x, y)); +} + +EAPI void +evas_vg_gradient_linear_end_set(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_gradient_linear_end_set(x, y)); +} + +EAPI void +evas_vg_gradient_linear_end_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_gradient_linear_end_get(x, y)); +} + +#include "efl_vg_gradient_linear.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_gradient_radial.c b/src/lib/evas/canvas/evas_vg_gradient_radial.c new file mode 100644 index 0000000000..e79f4fde2d --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_gradient_radial.c @@ -0,0 +1,177 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" + +#define MY_CLASS EFL_VG_GRADIENT_RADIAL_CLASS + +typedef struct _Efl_VG_Gradient_Radial_Data Efl_VG_Gradient_Radial_Data; +struct _Efl_VG_Gradient_Radial_Data +{ + struct { + double x, y; + } center, focal; + double radius; +}; + +static void +_efl_vg_gradient_radial_efl_gfx_gradient_radial_center_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd, + double x, double y) +{ + pd->center.x = x; + pd->center.y = y; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_gradient_radial_efl_gfx_gradient_radial_center_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->center.x; + if (y) *y = pd->center.y; +} + +static void +_efl_vg_gradient_radial_efl_gfx_gradient_radial_radius_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd, + double r) +{ + pd->radius = r; + + _efl_vg_base_changed(obj); +} + +static double +_efl_vg_gradient_radial_efl_gfx_gradient_radial_radius_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd) +{ + return pd->radius; +} + +static void +_efl_vg_gradient_radial_efl_gfx_gradient_radial_focal_set(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd, + double x, double y) +{ + pd->focal.x = x; + pd->focal.y = y; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_gradient_radial_efl_gfx_gradient_radial_focal_get(Eo *obj EINA_UNUSED, + Efl_VG_Gradient_Radial_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->focal.x; + if (y) *y = pd->focal.y; +} + +static void +_efl_vg_gradient_radial_render_pre(Eo *obj, + Eina_Matrix3 *parent, + Ector_Surface *s, + void *data, + Efl_VG_Base_Data *nd) +{ + Efl_VG_Gradient_Radial_Data *pd = data; + Efl_VG_Gradient_Data *gd; + + if (!nd->changed) return ; + nd->changed = EINA_FALSE; + + gd = eo_data_scope_get(obj, EFL_VG_GRADIENT_CLASS); + EFL_VG_COMPUTE_MATRIX(current, parent, nd); + + if (!nd->renderer) + { + eo_do(s, nd->renderer = ector_surface_renderer_factory_new(ECTOR_RENDERER_GENERIC_GRADIENT_RADIAL_MIXIN)); + } + + eo_do(nd->renderer, + ector_renderer_transformation_set(current), + ector_renderer_origin_set(nd->x, nd->y), + ector_renderer_color_set(nd->r, nd->g, nd->b, nd->a), + ector_renderer_visibility_set(nd->visibility), + efl_gfx_gradient_stop_set(gd->colors, gd->colors_count), + efl_gfx_gradient_spread_set(gd->s), + efl_gfx_gradient_radial_center_set(pd->center.x, pd->center.y), + efl_gfx_gradient_radial_focal_set(pd->focal.x, pd->focal.y), + efl_gfx_gradient_radial_radius_set(pd->radius), + ector_renderer_prepare()); +} + +static void +_efl_vg_gradient_radial_eo_base_constructor(Eo *obj, Efl_VG_Gradient_Radial_Data *pd) +{ + Efl_VG_Base_Data *nd; + + eo_do_super(obj, MY_CLASS, eo_constructor()); + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + nd->render_pre = _efl_vg_gradient_radial_render_pre; + nd->data = pd; +} + +static void +_efl_vg_gradient_radial_eo_base_destructor(Eo *obj, + Efl_VG_Gradient_Radial_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +static void +_efl_vg_gradient_radial_efl_vg_base_bounds_get(Eo *obj, Efl_VG_Gradient_Radial_Data *pd, Eina_Rectangle *r) +{ + Efl_VG_Base_Data *nd; + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + EINA_RECTANGLE_SET(r, + nd->x + pd->center.x - pd->radius, + nd->y + pd->center.y - pd->radius, + pd->radius * 2, pd->radius * 2); +} + +EAPI void +evas_vg_gradient_radial_center_set(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_gradient_radial_center_set(x, y)); +} + +EAPI void +evas_vg_gradient_radial_center_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_gradient_radial_center_get(x, y)); +} + +EAPI void +evas_vg_gradient_radial_radius_set(Eo *obj, double r) +{ + eo_do(obj, efl_gfx_gradient_radial_radius_set(r)); +} + +EAPI double +evas_vg_gradient_radial_radius_get(Eo *obj) +{ + double ret; + + return eo_do_ret(obj, ret, efl_gfx_gradient_radial_radius_get()); +} + +EAPI void +evas_vg_gradient_radial_focal_set(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_gradient_radial_focal_set(x, y)); +} + +EAPI void +evas_vg_gradient_radial_focal_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_gradient_radial_focal_get(x, y)); +} + +#include "efl_vg_gradient_radial.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_node.c b/src/lib/evas/canvas/evas_vg_node.c new file mode 100644 index 0000000000..6757771262 --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_node.c @@ -0,0 +1,598 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" +#include "efl_vg_root_node.eo.h" + +#include +#include + +#define MY_CLASS EFL_VG_BASE_CLASS + +static Eina_Bool +_efl_vg_base_property_changed(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info) +{ + Efl_VG_Base_Data *pd = data; + Eo *parent; + + if (pd->changed) return EINA_TRUE; + pd->changed = EINA_TRUE; + + eo_do(obj, parent = eo_parent_get()); + eo_do(parent, eo_event_callback_call(desc, event_info)); + return EINA_TRUE; +} + +static void +_efl_vg_base_transformation_set(Eo *obj, + Efl_VG_Base_Data *pd, + const Eina_Matrix3 *m) +{ + if (!pd->m) + { + pd->m = malloc(sizeof (Eina_Matrix3)); + if (!pd->m) return ; + } + memcpy(pd->m, m, sizeof (Eina_Matrix3)); + + _efl_vg_base_changed(obj); +} + +const Eina_Matrix3 * +_efl_vg_base_transformation_get(Eo *obj EINA_UNUSED, Efl_VG_Base_Data *pd) +{ + return pd->m; +} + +static void +_efl_vg_base_origin_set(Eo *obj, + Efl_VG_Base_Data *pd, + double x, double y) +{ + pd->x = x; + pd->y = y; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_base_origin_get(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + double *x, double *y) +{ + if (x) *x = pd->x; + if (y) *y = pd->y; +} + +static void +_efl_vg_base_efl_gfx_base_position_set(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + int x, int y) +{ + pd->x = lrint(x); + pd->y = lrint(y); + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_base_efl_gfx_base_position_get(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + int *x, int *y) +{ + if (x) *x = pd->x; + if (y) *y = pd->y; +} + +static void +_efl_vg_base_efl_gfx_base_visible_set(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, Eina_Bool v) +{ + pd->visibility = v; + + _efl_vg_base_changed(obj); +} + + +static Eina_Bool +_efl_vg_base_efl_gfx_base_visible_get(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd) +{ + return pd->visibility; +} + +static void +_efl_vg_base_efl_gfx_base_color_set(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + int r, int g, int b, int a) +{ + if (r > 255) r = 255; if (r < 0) r = 0; + if (g > 255) g = 255; if (g < 0) g = 0; + if (b > 255) b = 255; if (b < 0) b = 0; + if (a > 255) a = 255; if (a < 0) a = 0; + if (r > a) + { + r = a; + ERR("Evas only handles pre multiplied colors!"); + } + if (g > a) + { + g = a; + ERR("Evas only handles pre multiplied colors!"); + } + if (b > a) + { + b = a; + ERR("Evas only handles pre multiplied colors!"); + } + + pd->r = r; + pd->g = g; + pd->b = b; + pd->a = a; + + _efl_vg_base_changed(obj); +} + +static Eina_Bool +_efl_vg_base_efl_gfx_base_color_part_set(Eo *obj, Efl_VG_Base_Data *pd, + const char *part, + int r, int g, int b, int a) +{ + if (part) return EINA_FALSE; + + _efl_vg_base_efl_gfx_base_color_set(obj, pd, r, g, b, a); + return EINA_TRUE; +} + +static void +_efl_vg_base_efl_gfx_base_color_get(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + int *r, int *g, int *b, int *a) +{ + if (r) *r = pd->r; + if (g) *g = pd->g; + if (b) *b = pd->b; + if (a) *a = pd->a; +} + +static Eina_Bool +_efl_vg_base_efl_gfx_base_color_part_get(Eo *obj, Efl_VG_Base_Data *pd, + const char *part, + int *r, int *g, int *b, int *a) +{ + if (part) return EINA_FALSE; + + _efl_vg_base_efl_gfx_base_color_get(obj, pd, r, g, b, a); + return EINA_TRUE; +} + +static void +_efl_vg_base_mask_set(Eo *obj EINA_UNUSED, + Efl_VG_Base_Data *pd, + Efl_VG_Base *r) +{ + Efl_VG_Base *tmp = pd->mask; + + pd->mask = eo_ref(r); + eo_unref(tmp); + + _efl_vg_base_changed(obj); +} + +static Efl_VG_Base* +_efl_vg_base_mask_get(Eo *obj EINA_UNUSED, Efl_VG_Base_Data *pd) +{ + return pd->mask; +} + +static void +_efl_vg_base_efl_gfx_base_size_get(Eo *obj, + Efl_VG_Base_Data *pd EINA_UNUSED, + int *w, int *h) +{ + Eina_Rectangle r = { 0, 0, 0, 0 }; + + eo_do(obj, efl_vg_bounds_get(&r)); + if (w) *w = r.w; + if (h) *h = r.h; +} + +// Parent should be a container otherwise dismissing the stacking operation +static Eina_Bool +_efl_vg_base_parent_checked_get(Eo *obj, + Eo **parent, + Efl_VG_Container_Data **cd) +{ + *cd = NULL; + eo_do(obj, *parent = eo_parent_get()); + + if (eo_isa(*parent, EFL_VG_CONTAINER_CLASS)) + { + *cd = eo_data_scope_get(*parent, EFL_VG_CONTAINER_CLASS); + if (!*cd) + { + ERR("Can't get EFL_VG_CONTAINER_CLASS data."); + goto on_error; + } + } + else if (*parent != NULL) + { + ERR("Parent of unauthorized class."); + goto on_error; + } + + return EINA_TRUE; + + on_error: + *parent = NULL; + *cd = NULL; + return EINA_FALSE; +} + +static void +_efl_vg_base_eo_base_constructor(Eo *obj, + Efl_VG_Base_Data *pd) +{ + Efl_VG_Container_Data *cd = NULL; + Eo *parent; + + eo_do_super(obj, MY_CLASS, eo_constructor()); + + if (!_efl_vg_base_parent_checked_get(obj, &parent, &cd)) + eo_error_set(obj); + + eo_do(obj, eo_event_callback_add(EFL_GFX_CHANGED, _efl_vg_base_property_changed, pd)); + pd->changed = EINA_TRUE; +} + +static void +_efl_vg_base_eo_base_destructor(Eo *obj, Efl_VG_Base_Data *pd) +{ + if (pd->m) + { + free(pd->m); + pd->m = NULL; + } + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +static void +_efl_vg_base_eo_base_parent_set(Eo *obj, + Efl_VG_Base_Data *pd EINA_UNUSED, + Eo *parent) +{ + Efl_VG_Container_Data *cd = NULL; + Efl_VG_Container_Data *old_cd = NULL; + Eo *old_parent; + + if (eo_isa(parent, EFL_VG_CONTAINER_CLASS)) + { + cd = eo_data_scope_get(parent, EFL_VG_CONTAINER_CLASS); + if (!cd) + { + ERR("Can't get EFL_VG_CONTAINER_CLASS data from %p.", parent); + goto on_error; + } + } + else if (parent != NULL) + { + ERR("%p not even an EVAS_VG_CLASS.", parent); + goto on_error; + } + + if (!_efl_vg_base_parent_checked_get(obj, &old_parent, &old_cd)) + goto on_error; + + // FIXME: this may become slow with to much object + if (old_cd) + old_cd->children = eina_list_remove(old_cd->children, obj); + + eo_do_super(obj, MY_CLASS, eo_parent_set(parent)); + if (cd) + cd->children = eina_list_append(cd->children, obj); + + _efl_vg_base_changed(old_parent); + _efl_vg_base_changed(obj); + _efl_vg_base_changed(parent); + + return ; + + on_error: + eo_error_set(obj); + return ; +} + +static void +_efl_vg_base_efl_gfx_stack_raise(Eo *obj, Efl_VG_Base_Data *pd EINA_UNUSED) +{ + Efl_VG_Container_Data *cd; + Eina_List *lookup, *next; + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!eo_isa(parent, EFL_VG_CONTAINER_CLASS)) goto on_error; + cd = eo_data_scope_get(parent, EFL_VG_CONTAINER_CLASS); + + // FIXME: this could become slow with to much object + lookup = eina_list_data_find_list(cd->children, obj); + if (!lookup) goto on_error; + + next = eina_list_next(lookup); + if (!next) return ; + + cd->children = eina_list_remove_list(cd->children, lookup); + cd->children = eina_list_append_relative_list(cd->children, obj, next); + + _efl_vg_base_changed(parent); + return ; + + on_error: + eo_error_set(obj); +} + +static void +_efl_vg_base_efl_gfx_stack_stack_above(Eo *obj, + Efl_VG_Base_Data *pd EINA_UNUSED, + Efl_Gfx_Stack *above) +{ + Efl_VG_Container_Data *cd; + Eina_List *lookup, *ref; + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!eo_isa(parent, EFL_VG_CONTAINER_CLASS)) goto on_error; + cd = eo_data_scope_get(parent, EFL_VG_CONTAINER_CLASS); + + // FIXME: this could become slow with to much object + lookup = eina_list_data_find_list(cd->children, obj); + if (!lookup) goto on_error; + + ref = eina_list_data_find_list(cd->children, above); + if (!ref) goto on_error; + + cd->children = eina_list_remove_list(cd->children, lookup); + cd->children = eina_list_append_relative_list(cd->children, obj, ref); + + _efl_vg_base_changed(parent); + return ; + + on_error: + eo_error_set(obj); +} + +static void +_efl_vg_base_efl_gfx_stack_stack_below(Eo *obj, + Efl_VG_Base_Data *pd EINA_UNUSED, + Efl_Gfx_Stack *below) +{ + Efl_VG_Container_Data *cd; + Eina_List *lookup, *ref; + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!eo_isa(parent, EFL_VG_CONTAINER_CLASS)) goto on_error; + cd = eo_data_scope_get(parent, EFL_VG_CONTAINER_CLASS); + + // FIXME: this could become slow with to much object + lookup = eina_list_data_find_list(cd->children, obj); + if (!lookup) goto on_error; + + ref = eina_list_data_find_list(cd->children, below); + if (!ref) goto on_error; + + cd->children = eina_list_remove_list(cd->children, lookup); + cd->children = eina_list_prepend_relative_list(cd->children, obj, ref); + + _efl_vg_base_changed(parent); + return ; + + on_error: + eo_error_set(obj); +} + +static void +_efl_vg_base_efl_gfx_stack_lower(Eo *obj, Efl_VG_Base_Data *pd EINA_UNUSED) +{ + Efl_VG_Container_Data *cd; + Eina_List *lookup, *prev; + Eo *parent; + + eo_do(obj, parent = eo_parent_get()); + if (!eo_isa(parent, EFL_VG_CONTAINER_CLASS)) goto on_error; + cd = eo_data_scope_get(parent, EFL_VG_CONTAINER_CLASS); + + // FIXME: this could become slow with to much object + lookup = eina_list_data_find_list(cd->children, obj); + if (!lookup) goto on_error; + + prev = eina_list_prev(lookup); + if (!prev) return ; + + cd->children = eina_list_remove_list(cd->children, lookup); + cd->children = eina_list_prepend_relative_list(cd->children, obj, prev); + + _efl_vg_base_changed(parent); + return ; + + on_error: + eo_error_set(obj); +} + +static Eo * +_efl_vg_base_root_parent_get(Eo *obj) +{ + Eo *parent; + + if (eo_isa(obj, EFL_VG_ROOT_NODE_CLASS)) + return obj; + + eo_do(obj, parent = eo_parent_get()); + + if (!parent) return NULL; + return _efl_vg_base_root_parent_get(parent); +} + +static void +_efl_vg_base_walk_down_at(Eo *root, Eina_Array *a, Eina_Rectangle *r) +{ + Eina_Rectangle bounds; + + eo_do(root, efl_vg_bounds_get(&bounds)); + if (!eina_rectangles_intersect(&bounds, r)) return ; + + eina_array_push(a, root); + + if (eo_isa(root, EFL_VG_CONTAINER_CLASS)) + { + Efl_VG_Container_Data *cd; + Eina_List *l; + Eo *child; + + cd = eo_data_scope_get(root, EFL_VG_CONTAINER_CLASS); + EINA_LIST_FOREACH(cd->children, l, child) + _efl_vg_base_walk_down_at(child, a, r); + } +} + +static void +_efl_vg_base_object_at(Eo *obj, Eina_Array *a, Eina_Rectangle *r) +{ + Eo *root; + + root = _efl_vg_base_root_parent_get(obj); + if (!root) return ; + + _efl_vg_base_walk_down_at(root, a, r); +} + +static Efl_Gfx_Stack * +_efl_vg_base_efl_gfx_stack_below_get(Eo *obj, Efl_VG_Base_Data *pd EINA_UNUSED) +{ + Eina_Rectangle r; + Eina_Array a; + Eo *current; + Eo *below = NULL; + Eina_Array_Iterator iterator; + unsigned int i; + + eo_do(obj, efl_vg_bounds_get(&r)); + + eina_array_step_set(&a, sizeof (Eina_Array), 8); + + _efl_vg_base_object_at(obj, &a, &r); + + EINA_ARRAY_ITER_NEXT(&a, i, current, iterator) + if (current == obj) + break; + + if (current == obj) + { + i++; + if (i < eina_array_count(&a)) + below = eina_array_data_get(&a, i); + } + + eina_array_flush(&a); + + return below; +} + +static Efl_Gfx_Stack * +_efl_vg_base_efl_gfx_stack_above_get(Eo *obj, Efl_VG_Base_Data *pd EINA_UNUSED) +{ + Eina_Rectangle r; + Eina_Array a; + Eo *current; + Eo *above = NULL; + Eina_Array_Iterator iterator; + unsigned int i; + + eo_do(obj, efl_vg_bounds_get(&r)); + + eina_array_step_set(&a, sizeof (Eina_Array), 8); + + _efl_vg_base_object_at(obj, &a, &r); + + EINA_ARRAY_ITER_NEXT(&a, i, current, iterator) + if (current == obj) + break; + + if (current == obj) + { + if (i > 0) + above = eina_array_data_get(&a, i - 1); + } + + eina_array_flush(&a); + + return above; +} + +EAPI Eina_Bool +evas_vg_node_visible_get(Eo *obj) +{ + Eina_Bool ret; + + return eo_do_ret(obj, ret, efl_gfx_visible_get()); +} + +EAPI void +evas_vg_node_visible_set(Eo *obj, Eina_Bool v) +{ + eo_do(obj, efl_gfx_visible_set(v)); +} + +EAPI void +evas_vg_node_color_get(Eo *obj, int *r, int *g, int *b, int *a) +{ + eo_do(obj, efl_gfx_color_get(r, g, b, a)); +} + +EAPI void +evas_vg_node_color_set(Eo *obj, int r, int g, int b, int a) +{ + eo_do(obj, efl_gfx_color_set(r, g, b, a)); +} + +EAPI void +evas_vg_node_geometry_get(Eo *obj, int *x, int *y, int *w, int *h) +{ + eo_do(obj, + efl_gfx_position_get(x, y), + efl_gfx_size_get(w, h)); +} + +EAPI void +evas_vg_node_geometry_set(Eo *obj, int x, int y, int w, int h) +{ + eo_do(obj, + efl_gfx_position_set(x, y), + efl_gfx_size_set(w, h)); +} + +EAPI void +evas_vg_node_stack_below(Eo *obj, Eo *below) +{ + eo_do(obj, efl_gfx_stack_below(below)); +} + +EAPI void +evas_vg_node_stack_above(Eo *obj, Eo *above) +{ + eo_do(obj, efl_gfx_stack_above(above)); +} + +EAPI void +evas_vg_node_raise(Eo *obj) +{ + eo_do(obj, efl_gfx_stack_raise()); +} + +EAPI void +evas_vg_node_lower(Eo *obj) +{ + eo_do(obj, efl_gfx_stack_lower()); +} + +#include "efl_vg_base.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h new file mode 100644 index 0000000000..8f5bf4f98b --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_private.h @@ -0,0 +1,82 @@ +#ifndef EVAS_VG_PRIVATE_H_ +# define EVAS_VG_PRIVATE_H_ + +#include + +typedef struct _Efl_VG_Base_Data Efl_VG_Base_Data; +typedef struct _Efl_VG_Container_Data Efl_VG_Container_Data; +typedef struct _Efl_VG_Gradient_Data Efl_VG_Gradient_Data; + +struct _Efl_VG_Base_Data +{ + Eina_Matrix3 *m; + Efl_VG *mask; + Ector_Renderer *renderer; + + void (*render_pre)(Eo *obj, Eina_Matrix3 *parent, Ector_Surface *s, void *data, Efl_VG_Base_Data *nd); + void *data; + + double x, y; + int r, g, b, a; + + Eina_Bool visibility : 1; + Eina_Bool changed : 1; +}; + +struct _Efl_VG_Container_Data +{ + Eina_List *children; +}; + +struct _Efl_VG_Gradient_Data +{ + // FIXME: Later on we should deduplicate it somehow (Using Ector ?). + Efl_Gfx_Gradient_Stop *colors; + unsigned int colors_count; + + Efl_Gfx_Gradient_Spread s; +}; + +static inline Efl_VG_Base_Data * +_evas_vg_render_pre(Efl_VG *child, Ector_Surface *s, Eina_Matrix3 *m) +{ + Efl_VG_Base_Data *child_nd = NULL; + + // FIXME: Prevent infinite loop + if (child) + child_nd = eo_data_scope_get(child, EFL_VG_BASE_CLASS); + if (child_nd) + child_nd->render_pre(child, m, s, child_nd->data, child_nd); + + return child_nd; +} + +static inline void +_efl_vg_base_changed(Eo *obj) +{ + eo_do(obj, eo_event_callback_call(EFL_GFX_CHANGED, NULL)); +} + +#define EFL_VG_COMPUTE_MATRIX(Current, Parent, Nd) \ + Eina_Matrix3 *Current = Nd->m; \ + Eina_Matrix3 _matrix_tmp, translate; \ + \ + if (Parent) \ + { \ + if (Current) \ + { \ + eina_matrix3_compose(Parent, Current, &_matrix_tmp); \ + Current = &_matrix_tmp; \ + } \ + else \ + { \ + eina_matrix3_translate(&translate, -(Nd->x), -(Nd->y)); \ + eina_matrix3_compose(Parent, &translate, &_matrix_tmp); \ + eina_matrix3_translate(&translate, (Nd->x), (Nd->y)); \ + eina_matrix3_compose(&_matrix_tmp, &translate, &_matrix_tmp); \ + Current = &_matrix_tmp; \ + } \ + } + + +#endif diff --git a/src/lib/evas/canvas/evas_vg_root_node.c b/src/lib/evas/canvas/evas_vg_root_node.c new file mode 100644 index 0000000000..65dbb0220f --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_root_node.c @@ -0,0 +1,92 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" +#include "efl_vg_root_node.eo.h" + +#include + +#define MY_CLASS EFL_VG_ROOT_NODE_CLASS + +typedef struct _Efl_VG_Root_Node_Data Efl_VG_Root_Node_Data; +struct _Efl_VG_Root_Node_Data +{ + Evas_Object *parent; + Evas_Object_Protected_Data *data; +}; + +static void +_evas_vg_root_node_render_pre(Eo *obj EINA_UNUSED, + Eina_Matrix3 *parent, + Ector_Surface *s, + void *data, + Efl_VG_Base_Data *nd) +{ + Efl_VG_Container_Data *pd = data; + Eina_List *l; + Eo *child; + + EFL_VG_COMPUTE_MATRIX(current, parent, nd); + + EINA_LIST_FOREACH(pd->children, l, child) + _evas_vg_render_pre(child, s, current); +} + +static Eina_Bool +_evas_vg_root_node_changed(void *data, Eo *obj, + const Eo_Event_Description *desc EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Efl_VG_Root_Node_Data *pd = data; + Efl_VG_Base_Data *bd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + + if (bd->changed) return EINA_TRUE; + bd->changed = EINA_TRUE; + + if (pd->parent) evas_object_change(pd->parent, pd->data); + return EINA_TRUE; +} + +static void +_efl_vg_root_node_eo_base_parent_set(Eo *obj, + Efl_VG_Root_Node_Data *pd, + Eo *parent) +{ + // Nice little hack, jump over parent parent_set in Efl_VG_Root + eo_do_super(obj, EFL_VG_BASE_CLASS, eo_parent_set(parent)); + if (parent && !eo_isa(parent, EVAS_VG_CLASS)) + { + eo_error_set(obj); + } + else + { + pd->parent = parent; + pd->data = parent ? eo_data_scope_get(parent, EVAS_OBJECT_CLASS) : NULL; + } +} + +static void +_efl_vg_root_node_eo_base_constructor(Eo *obj, + Efl_VG_Root_Node_Data *pd) +{ + Efl_VG_Container_Data *cd; + Efl_VG_Base_Data *nd; + Eo *parent; + + // Nice little hack, jump over parent constructor in Efl_VG_Root + eo_do_super(obj, EFL_VG_BASE_CLASS, eo_constructor()); + eo_do(obj, parent = eo_parent_get()); + if (!eo_isa(parent, EVAS_VG_CLASS)) + eo_error_set(obj); + + cd = eo_data_scope_get(obj, EFL_VG_CONTAINER_CLASS); + cd->children = NULL; + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + nd->render_pre = _evas_vg_root_node_render_pre; + nd->data = cd; + + eo_do(obj, eo_event_callback_add(EFL_GFX_CHANGED, _evas_vg_root_node_changed, pd)); +} + +#include "efl_vg_root_node.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_shape.c b/src/lib/evas/canvas/evas_vg_shape.c new file mode 100644 index 0000000000..e67c3b5675 --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_shape.c @@ -0,0 +1,566 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" + +#define MY_CLASS EFL_VG_SHAPE_CLASS + +typedef struct _Efl_VG_Shape_Data Efl_VG_Shape_Data; +struct _Efl_VG_Shape_Data +{ + Efl_VG *fill; + + struct { + Efl_Gfx_Dash *dash; + Efl_VG *fill; + Efl_VG *marker; + + double scale; + double width; + double centered; // from 0 to 1 + + int r, g, b, a; + + unsigned int dash_count; + + Efl_Gfx_Cap cap; + Efl_Gfx_Join join; + } stroke; +}; + +static void +_efl_vg_shape_efl_vg_base_bounds_get(Eo *obj, + Efl_VG_Shape_Data *pd EINA_UNUSED, + Eina_Rectangle *r) +{ + // FIXME: Use the renderer bounding box when it has been created instead of an estimation + eo_do(obj, efl_gfx_shape_bounds_get(r)); +} + +static void +_efl_vg_shape_fill_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + Efl_VG *f) +{ + Efl_VG *tmp = pd->fill; + + pd->fill = eo_ref(f); + eo_unref(tmp); + + _efl_vg_base_changed(obj); +} + +static Efl_VG * +_efl_vg_shape_fill_get(Eo *obj EINA_UNUSED, Efl_VG_Shape_Data *pd) +{ + return pd->fill; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_scale_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + double s) +{ + pd->stroke.scale = s; + + _efl_vg_base_changed(obj); +} + +static double +_efl_vg_shape_efl_gfx_shape_stroke_scale_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.scale; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_color_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + int r, int g, int b, int a) +{ + pd->stroke.r = r; + pd->stroke.g = g; + pd->stroke.b = b; + pd->stroke.a = a; + + _efl_vg_base_changed(obj); +} + +static Eina_Bool +_efl_vg_shape_efl_gfx_base_color_part_set(Eo *obj, Efl_VG_Shape_Data *pd, + const char * part, + int r, int g, int b, int a) +{ + Eina_Bool ret; + + if (part && !strcmp(part, "stroke")) + { + _efl_vg_shape_efl_gfx_shape_stroke_color_set(obj, pd, r, g, b, a); + return EINA_TRUE; + } + + eo_do_super(obj, EFL_VG_SHAPE_CLASS, + ret = efl_gfx_color_part_set(part, r, g, b, a)); + + return ret; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_color_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + int *r, int *g, int *b, int *a) +{ + if (r) *r = pd->stroke.r; + if (g) *g = pd->stroke.g; + if (b) *b = pd->stroke.b; + if (a) *a = pd->stroke.a; +} + +static Eina_Bool +_efl_vg_shape_efl_gfx_base_color_part_get(Eo *obj, Efl_VG_Shape_Data *pd, + const char * part, + int *r, int *g, int *b, int *a) +{ + Eina_Bool ret; + + if (part && !strcmp(part, "stroke")) + { + _efl_vg_shape_efl_gfx_shape_stroke_color_get(obj, pd, r, g, b, a); + return EINA_TRUE; + } + + eo_do_super(obj, EFL_VG_SHAPE_CLASS, + ret = efl_gfx_color_part_get(part, r, g, b, a)); + + return ret; +} + +static void +_efl_vg_shape_stroke_fill_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + Efl_VG *f) +{ + Efl_VG *tmp = pd->fill; + + pd->stroke.fill = eo_ref(f); + eo_unref(tmp); + + _efl_vg_base_changed(obj); +} + +static Efl_VG * +_efl_vg_shape_stroke_fill_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.fill; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_width_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + double w) +{ + pd->stroke.width = w; + + _efl_vg_base_changed(obj); +} + +static double +_efl_vg_shape_efl_gfx_shape_stroke_width_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.width; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_location_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + double centered) +{ + pd->stroke.centered = centered; + + _efl_vg_base_changed(obj); +} + +static double +_efl_vg_shape_efl_gfx_shape_stroke_location_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.centered; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_dash_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + const Efl_Gfx_Dash *dash, + unsigned int length) +{ + free(pd->stroke.dash); + pd->stroke.dash = NULL; + pd->stroke.dash_count = 0; + + // check for null or empty dash + if (!dash || !length) return; + + pd->stroke.dash = malloc(sizeof (Efl_Gfx_Dash) * length); + if (!pd->stroke.dash) return ; + + memcpy(pd->stroke.dash, dash, sizeof (Efl_Gfx_Dash) * length); + pd->stroke.dash_count = length; + + _efl_vg_base_changed(obj); +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_dash_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + const Efl_Gfx_Dash **dash, + unsigned int *length) +{ + if (dash) *dash = pd->stroke.dash; + if (length) *length = pd->stroke.dash_count; +} + +static void +_efl_vg_shape_stroke_marker_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + Efl_VG_Shape *m) +{ + Efl_VG *tmp = pd->stroke.marker; + + pd->stroke.marker = eo_ref(m); + eo_unref(tmp); + + _efl_vg_base_changed(obj); +} + +static Efl_VG_Shape * +_efl_vg_shape_stroke_marker_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.marker; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_cap_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + Efl_Gfx_Cap c) +{ + pd->stroke.cap = c; + + _efl_vg_base_changed(obj); +} + +static Efl_Gfx_Cap +_efl_vg_shape_efl_gfx_shape_stroke_cap_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.cap; +} + +static void +_efl_vg_shape_efl_gfx_shape_stroke_join_set(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd, + Efl_Gfx_Join j) +{ + pd->stroke.join = j; + + _efl_vg_base_changed(obj); +} + +static Efl_Gfx_Join +_efl_vg_shape_efl_gfx_shape_stroke_join_get(Eo *obj EINA_UNUSED, + Efl_VG_Shape_Data *pd) +{ + return pd->stroke.join; +} + +static void +_efl_vg_shape_render_pre(Eo *obj EINA_UNUSED, + Eina_Matrix3 *parent, + Ector_Surface *s, + void *data, + Efl_VG_Base_Data *nd) +{ + Efl_VG_Shape_Data *pd = data; + Efl_VG_Base_Data *fill, *stroke_fill, *stroke_marker, *mask; + double xn = nd->x, yn = nd->y ; + + if (!nd->changed) return ; + nd->changed = EINA_FALSE; + + if(parent) eina_matrix3_point_transform(parent, nd->x, nd->y, &xn, &yn); + + EFL_VG_COMPUTE_MATRIX(current, parent, nd); + + fill = _evas_vg_render_pre(pd->fill, s, current); + stroke_fill = _evas_vg_render_pre(pd->stroke.fill, s, current); + stroke_marker = _evas_vg_render_pre(pd->stroke.marker, s, current); + mask = _evas_vg_render_pre(nd->mask, s, current); + + if (!nd->renderer) + { + eo_do(s, nd->renderer = ector_surface_renderer_factory_new(ECTOR_RENDERER_GENERIC_SHAPE_MIXIN)); + } + + eo_do(nd->renderer, + ector_renderer_transformation_set(current), + ector_renderer_origin_set(xn, yn), + ector_renderer_color_set(nd->r, nd->g, nd->b, nd->a), + ector_renderer_visibility_set(nd->visibility), + ector_renderer_mask_set(mask ? mask->renderer : NULL), + ector_renderer_shape_fill_set(fill ? fill->renderer : NULL), + ector_renderer_shape_stroke_fill_set(stroke_fill ? stroke_fill->renderer : NULL), + ector_renderer_shape_stroke_marker_set(stroke_marker ? stroke_marker->renderer : NULL), + efl_gfx_shape_dup(obj), + ector_renderer_prepare()); +} + +static void +_efl_vg_shape_eo_base_constructor(Eo *obj, Efl_VG_Shape_Data *pd) +{ + Efl_VG_Base_Data *nd; + + eo_do_super(obj, MY_CLASS, eo_constructor()); + + pd->stroke.cap = EFL_GFX_CAP_BUTT; + pd->stroke.join = EFL_GFX_JOIN_MITER; + pd->stroke.scale = 1; + pd->stroke.centered = 0.5; + + nd = eo_data_scope_get(obj, EFL_VG_BASE_CLASS); + nd->render_pre = _efl_vg_shape_render_pre; + nd->data = pd; +} + +static void +_efl_vg_shape_eo_base_destructor(Eo *obj, Efl_VG_Shape_Data *pd EINA_UNUSED) +{ + eo_do_super(obj, MY_CLASS, eo_destructor()); +} + +EAPI double +evas_vg_shape_stroke_scale_get(Eo *obj) +{ + double ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_stroke_scale_get()); +} + +EAPI void +evas_vg_shape_stroke_scale_set(Eo *obj, double s) +{ + eo_do(obj, efl_gfx_shape_stroke_scale_set(s)); +} + +EAPI void +evas_vg_shape_stroke_color_get(Eo *obj, int *r, int *g, int *b, int *a) +{ + eo_do(obj, efl_gfx_shape_stroke_color_get(r, g, b, a)); +} + +EAPI void +evas_vg_shape_stroke_color_set(Eo *obj, int r, int g, int b, int a) +{ + eo_do(obj, efl_gfx_shape_stroke_color_set(r, g, b, a)); +} + +EAPI double +evas_vg_shape_stroke_width_get(Eo *obj) +{ + double ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_stroke_width_get()); +} + +EAPI void +evas_vg_shape_stroke_width_set(Eo *obj, double w) +{ + eo_do(obj, efl_gfx_shape_stroke_width_set(w)); +} + +EAPI double +evas_vg_shape_stroke_location_get(Eo *obj) +{ + double ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_stroke_location_get()); +} + +EAPI void +evas_vg_shape_stroke_location_set(Eo *obj, double centered) +{ + eo_do(obj, efl_gfx_shape_stroke_location_set(centered)); +} + +EAPI void +evas_vg_shape_stroke_dash_get(Eo *obj, const Efl_Gfx_Dash **dash, unsigned int *length) +{ + eo_do(obj, efl_gfx_shape_stroke_dash_get(dash, length)); +} + +EAPI void +evas_vg_shape_stroke_dash_set(Eo *obj, const Efl_Gfx_Dash *dash, unsigned int length) +{ + eo_do(obj, efl_gfx_shape_stroke_dash_set(dash, length)); +} + +EAPI Efl_Gfx_Cap +evas_vg_shape_stroke_cap_get(Eo *obj) +{ + Efl_Gfx_Cap ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_stroke_cap_get()); +} + +EAPI void +evas_vg_shape_stroke_cap_set(Eo *obj, Efl_Gfx_Cap c) +{ + eo_do(obj, efl_gfx_shape_stroke_cap_set(c)); +} + +EAPI Efl_Gfx_Join +evas_vg_shape_stroke_join_get(Eo *obj) +{ + Efl_Gfx_Join ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_stroke_join_get()); +} + +EAPI void +evas_vg_shape_stroke_join_set(Eo *obj, Efl_Gfx_Join j) +{ + eo_do(obj, efl_gfx_shape_stroke_join_set(j)); +} + +EAPI void +evas_vg_shape_shape_path_set(Eo *obj, const Efl_Gfx_Path_Command *op, const double *points) +{ + eo_do(obj, efl_gfx_shape_path_set(op, points)); +} + +EAPI void +evas_vg_shape_shape_path_get(Eo *obj, const Efl_Gfx_Path_Command **op, const double **points) +{ + eo_do(obj, efl_gfx_shape_path_get(op, points)); +} + +EAPI void +evas_vg_shape_shape_path_length_get(Eo *obj, unsigned int *commands, unsigned int *points) +{ + eo_do(obj, efl_gfx_shape_path_length_get(commands, points)); +} + +EAPI void +evas_vg_shape_shape_current_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_shape_current_get(x, y)); +} + +EAPI void +evas_vg_shape_shape_current_ctrl_get(Eo *obj, double *x, double *y) +{ + eo_do(obj, efl_gfx_shape_current_ctrl_get(x, y)); +} + +EAPI void +evas_vg_shape_shape_dup(Eo *obj, Eo *dup_from) +{ + eo_do(obj, efl_gfx_shape_dup(dup_from)); +} + +EAPI void +evas_vg_shape_shape_reset(Eo *obj) +{ + eo_do(obj, efl_gfx_shape_reset()); +} + +EAPI void +evas_vg_shape_shape_append_move_to(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_shape_append_move_to(x, y)); +} + +EAPI void +evas_vg_shape_shape_append_line_to(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_shape_append_line_to(x, y)); +} + +EAPI void +evas_vg_shape_shape_append_quadratic_to(Eo *obj, double x, double y, double ctrl_x, double ctrl_y) +{ + eo_do(obj, efl_gfx_shape_append_quadratic_to(x, y, ctrl_x, ctrl_y)); +} + +EAPI void +evas_vg_shape_shape_append_squadratic_to(Eo *obj, double x, double y) +{ + eo_do(obj, efl_gfx_shape_append_squadratic_to(x, y)); +} + +EAPI void +evas_vg_shape_shape_append_cubic_to(Eo *obj, double x, double y, double ctrl_x0, double ctrl_y0, double ctrl_x1, double ctrl_y1) +{ + eo_do(obj, efl_gfx_shape_append_cubic_to(x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1)); +} + +EAPI void +evas_vg_shape_shape_append_scubic_to(Eo *obj, double x, double y, double ctrl_x, double ctrl_y) +{ + eo_do(obj, efl_gfx_shape_append_scubic_to(x, y, ctrl_x, ctrl_y)); +} + +EAPI void +evas_vg_shape_shape_append_arc_to(Eo *obj, double x, double y, double rx, double ry, double angle, Eina_Bool large_arc, Eina_Bool sweep) +{ + eo_do(obj, efl_gfx_shape_append_arc_to(x, y, rx, ry, angle, large_arc, sweep)); +} + +EAPI void +evas_vg_shape_shape_append_close(Eo *obj) +{ + eo_do(obj, efl_gfx_shape_append_close()); +} + +EAPI void +evas_vg_shape_shape_append_circle(Eo *obj, double x, double y, double radius) +{ + eo_do(obj, efl_gfx_shape_append_circle(x, y, radius)); +} + +EAPI void +evas_vg_shape_shape_append_rect(Eo *obj, double x, double y, double w, double h, double rx, double ry) +{ + eo_do(obj, efl_gfx_shape_append_rect(x, y, w, h, rx, ry)); +} + +EAPI void +evas_vg_shape_shape_append_svg_path(Eo *obj, const char *svg_path_data) +{ + eo_do(obj, efl_gfx_shape_append_svg_path(svg_path_data)); +} + +EAPI Eina_Bool +evas_vg_shape_shape_interpolate(Eo *obj, const Eo *from, const Eo *to, double pos_map) +{ + Eina_Bool ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_interpolate(from, to, pos_map)); +} + +EAPI Eina_Bool +evas_vg_shape_shape_equal_commands(Eo *obj, const Eo *with) +{ + Eina_Bool ret; + + return eo_do_ret(obj, ret, efl_gfx_shape_equal_commands(with)); +} + +EAPI Efl_VG* +evas_vg_shape_add(Efl_VG *parent) +{ + return eo_add(EFL_VG_SHAPE_CLASS, parent); +} + +#include "efl_vg_shape.eo.c" diff --git a/src/lib/evas/canvas/evas_vg_utils.c b/src/lib/evas/canvas/evas_vg_utils.c new file mode 100644 index 0000000000..f61c339781 --- /dev/null +++ b/src/lib/evas/canvas/evas_vg_utils.c @@ -0,0 +1,4 @@ +#include "evas_common_private.h" +#include "evas_private.h" + +#include "evas_vg_private.h" diff --git a/src/lib/evas/common/evas_model_load.c b/src/lib/evas/common/evas_model_load.c index bef10ba28c..959cd71bc8 100644 --- a/src/lib/evas/common/evas_model_load.c +++ b/src/lib/evas/common/evas_model_load.c @@ -65,7 +65,7 @@ evas_common_load_model_from_file(Evas_3D_Mesh *model, const char *file) } void -evas_common_load_model_from_eina_file(Evas_3D_Mesh *model, Eina_File *file) +evas_common_load_model_from_eina_file(Evas_3D_Mesh *model, const Eina_File *file) { Eina_File *e_file = eina_file_dup(file); diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index e3d6b07956..6b4cf5e623 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -49,6 +49,7 @@ #include #include +#include #ifdef BUILD_LOADER_EET # include diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index b1c82e59ca..c44a240e5e 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -5,9 +5,6 @@ # include #endif -#include -#include - #include "Evas.h" #include "../file/evas_module.h" @@ -488,6 +485,7 @@ OPAQUE_TYPE(Evas_Font_Instance); /* General type for RGBA_Font_Int */ #define MAGIC_SMART 0x7c6977c5 #define MAGIC_OBJ_SHAPE 0x747297f7 #define MAGIC_OBJ_CONTAINER 0x71877776 +#define MAGIC_OBJ_VG 0x77817EE7 #define MAGIC_OBJ_CUSTOM 0x7b7857ab #define MAGIC_EVAS_GL 0x77976718 #define MAGIC_MAP 0x7575177d @@ -736,6 +734,7 @@ struct _Evas_Public_Data struct { Evas_Module *module; Evas_Func *func; + Ector_Surface *surface; struct { void *output; @@ -1364,6 +1363,11 @@ struct _Evas_Func void (*texture_filter_set) (void *data, void *texture, Evas_3D_Texture_Filter min, Evas_3D_Texture_Filter mag); void (*texture_filter_get) (void *data, void *texture, Evas_3D_Texture_Filter *min, Evas_3D_Texture_Filter *mag); void (*texture_image_set) (void *data, void *texture, void *image); + + Ector_Surface *(*ector_get) (void *data); + void (*ector_begin) (void *data, void *context, void *surface, int x, int y, Eina_Bool do_async); + void (*ector_renderer_draw) (void *data, void *context, void *surface, Ector_Renderer *r, Eina_Array *clips, Eina_Bool do_async); + void (*ector_end) (void *data, void *context, void *surface, Eina_Bool do_async); }; struct _Evas_Image_Save_Func @@ -1698,7 +1702,7 @@ void _evas_3d_eet_file_free(void); /* Temporary save/load functions */ void evas_common_load_model_from_file(Evas_3D_Mesh *model, const char *file); -void evas_common_load_model_from_eina_file(Evas_3D_Mesh *model, Eina_File *file); +void evas_common_load_model_from_eina_file(Evas_3D_Mesh *model, const Eina_File *file); void evas_common_save_model_to_file(Evas_3D_Mesh *model, const char *file, Evas_3D_Mesh_Frame *f); void evas_model_load_file_eet(Evas_3D_Mesh *mesh, Eina_File *file); void evas_model_load_file_md2(Evas_3D_Mesh *mesh, Eina_File *file); @@ -1780,6 +1784,8 @@ Evas_Device *_evas_device_top_get(const Evas *e); void _evas_device_ref(Evas_Device *dev); void _evas_device_unref(Evas_Device *dev); +Eina_Bool evas_vg_loader_svg(Evas_Object *vg, const Eina_File *f, const char *key EINA_UNUSED); + extern Eina_Cow *evas_object_proxy_cow; extern Eina_Cow *evas_object_map_cow; extern Eina_Cow *evas_object_state_cow; diff --git a/src/modules/evas/engines/gl_generic/ector_cairo_software_surface.eo b/src/modules/evas/engines/gl_generic/ector_cairo_software_surface.eo new file mode 100644 index 0000000000..d5070abccf --- /dev/null +++ b/src/modules/evas/engines/gl_generic/ector_cairo_software_surface.eo @@ -0,0 +1,18 @@ +class Ector.Cairo_Software.Surface (Ector.Cairo.Surface) +{ + eo_prefix: ector_cairo_software_surface; + legacy_prefix: null; + properties { + surface { + set { + } + get { + } + values { + void *pixels; + uint width; + uint height; + } + } + } +} diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index dac9232c5f..45e8ded8f1 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -21,6 +21,11 @@ #include "evas_cs2_private.h" #endif +#include "cairo/Ector_Cairo.h" +#include "software/Ector_Software.h" + +#include "ector_cairo_software_surface.eo.h" + #define EVAS_GL_NO_GL_H_CHECK 1 #include "Evas_GL.h" @@ -2087,6 +2092,186 @@ eng_texture_image_set(void *data EINA_UNUSED, void *texture, void *image) e3d_texture_import((E3D_Texture *)texture, im->tex->pt->texture); } +static Ector_Surface *_software_ector = NULL; +static Eina_Bool use_cairo; + +static Ector_Surface * +eng_ector_get(void *data EINA_UNUSED) +{ + if (!_software_ector) + { + const char *ector_backend; + + ector_backend = getenv("ECTOR_BACKEND"); + if (ector_backend && !strcasecmp(ector_backend, "freetype")) + { + _software_ector = eo_add(ECTOR_SOFTWARE_SURFACE_CLASS, NULL); + use_cairo = EINA_FALSE; + } + else + { + _software_ector = eo_add(ECTOR_CAIRO_SOFTWARE_SURFACE_CLASS, NULL); + use_cairo = EINA_TRUE; + } + } + return _software_ector; +} + +static Ector_Rop +_evas_render_op_to_ector_rop(Evas_Render_Op op) +{ + switch (op) + { + case EVAS_RENDER_BLEND: + return ECTOR_ROP_BLEND; + case EVAS_RENDER_COPY: + return ECTOR_ROP_COPY; + default: + return ECTOR_ROP_BLEND; + } +} + +static void +eng_ector_renderer_draw(void *data, void *context EINA_UNUSED, void *surface, Ector_Renderer *renderer, Eina_Array *clips, Eina_Bool do_async EINA_UNUSED) +{ + Evas_GL_Image *dst = surface; + Evas_Engine_GL_Context *gc; + Render_Engine_GL_Generic *re = data; + Eina_Rectangle *r; + Eina_Array *c; + Eina_Rectangle clip; + Eina_Array_Iterator it; + unsigned int i; + + gc = re->window_gl_context_get(re->software.ob); + if (gc->dc->clip.use) + { + clip.x = gc->dc->clip.x; + clip.y = gc->dc->clip.y; + clip.w = gc->dc->clip.w; + clip.h = gc->dc->clip.h; + } + else + { + clip.x = 0; + clip.y = 0; + clip.w = dst->w; + clip.h = dst->h; + } + + c = eina_array_new(8); + if (clips) + { + EINA_ARRAY_ITER_NEXT(clips, i, r, it) + { + Eina_Rectangle *rc; + + rc = eina_rectangle_new(r->x, r->y, r->w, r->h); + if (!rc) continue; + + if (eina_rectangle_intersection(rc, &clip)) + eina_array_push(c, rc); + else + eina_rectangle_free(rc); + } + + if (eina_array_count(c) == 0 && + eina_array_count(clips) > 0) + return ; + } + + if (eina_array_count(c) == 0) + eina_array_push(c, eina_rectangle_new(clip.x, clip.y, clip.w, clip.h)); + + eo_do(renderer, + ector_renderer_draw(_evas_render_op_to_ector_rop(gc->dc->render_op), + c, + // mul_col will be applied by GL during ector_end + 0xffffffff)); + + while ((r = eina_array_pop(c))) + eina_rectangle_free(r); + eina_array_free(c); +} + +static void *software_buffer = NULL; + +static void +eng_ector_begin(void *data EINA_UNUSED, void *context EINA_UNUSED, void *surface, int x, int y, Eina_Bool do_async EINA_UNUSED) +{ + Evas_Engine_GL_Context *gl_context; + Render_Engine_GL_Generic *re = data; + int w, h; + + re->window_use(re->software.ob); + gl_context = re->window_gl_context_get(re->software.ob); + evas_gl_common_context_target_surface_set(gl_context, surface); + gl_context->dc = context; + + w = gl_context->w; h = gl_context->h; + + software_buffer = realloc(software_buffer, sizeof (unsigned int) * w * h); + if (use_cairo) + { + eo_do(_software_ector, + ector_cairo_software_surface_set(software_buffer, w, h), + ector_surface_reference_point_set(x, y)); + } + else + { + eo_do(_software_ector, + ector_software_surface_set(software_buffer, w, h), + ector_surface_reference_point_set(x, y)); + } +} + +static void +eng_ector_end(void *data, void *context EINA_UNUSED, void *surface EINA_UNUSED, Eina_Bool do_async EINA_UNUSED) +{ + Evas_Engine_GL_Context *gl_context; + Render_Engine_GL_Generic *re = data; + Evas_GL_Image *im; + int w, h; + Eina_Bool mul_use; + + gl_context = re->window_gl_context_get(re->software.ob); + w = gl_context->w; h = gl_context->h; + mul_use = gl_context->dc->mul.use; + + if (use_cairo) + { + eo_do(_software_ector, + ector_cairo_software_surface_set(NULL, 0, 0)); + } + else + { + eo_do(_software_ector, + ector_software_surface_set(NULL, 0, 0)); + } + + im = evas_gl_common_image_new_from_copied_data(gl_context, w, h, software_buffer, 1, EVAS_COLORSPACE_ARGB8888); + + if (!mul_use) + { + // @hack as image_draw uses below fields to do colour multiplication. + gl_context->dc->mul.col = ector_color_multiply(0xffffffff,gl_context->dc->col.col); + gl_context->dc->mul.use = EINA_TRUE; + } + + // We actually just bluntly push the pixel all over the + // destination surface. We don't have the actual information + // of the widget size. This is not a problem. + // Later on, we don't want that information and today when + // using GL backend, you just need to turn on Evas_Map on + // the Evas_Object_VG. + evas_gl_common_image_draw(gl_context, im, 0, 0, w, h, 0, 0, w, h, 0); + + evas_gl_common_image_free(im); + + // restore gl state + gl_context->dc->mul.use = mul_use; +} + static Evas_Func func, pfunc; static int @@ -2229,6 +2414,11 @@ module_open(Evas_Module *em) ORD(texture_filter_get); ORD(texture_image_set); + ORD(ector_get); + ORD(ector_begin); + ORD(ector_renderer_draw); + ORD(ector_end); + /* now advertise out own api */ em->functions = (void *)(&func); return 1; @@ -2257,3 +2447,94 @@ EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, gl_generic); #ifndef EVAS_STATIC_BUILD_GL_COMMON EVAS_EINA_MODULE_DEFINE(engine, gl_generic); #endif + +#define USE(Obj, Sym, Error) \ + if (!Sym) Sym = _ector_cairo_symbol_get(Obj, #Sym); \ + if (!Sym) return Error; + +static inline void * +_ector_cairo_symbol_get(Eo *ector_surface, const char *name) +{ + void *sym; + + eo_do(ector_surface, + sym = ector_cairo_surface_symbol_get(name)); + return sym; +} + +typedef struct _cairo_surface_t cairo_surface_t; +typedef enum { + CAIRO_FORMAT_INVALID = -1, + CAIRO_FORMAT_ARGB32 = 0, + CAIRO_FORMAT_RGB24 = 1, + CAIRO_FORMAT_A8 = 2, + CAIRO_FORMAT_A1 = 3, + CAIRO_FORMAT_RGB16_565 = 4, + CAIRO_FORMAT_RGB30 = 5 +} cairo_format_t; + +static cairo_surface_t *(*cairo_image_surface_create_for_data)(unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride) = NULL; +static void (*cairo_surface_destroy)(cairo_surface_t *surface) = NULL; +static cairo_t *(*cairo_create)(cairo_surface_t *target) = NULL; +static void (*cairo_destroy)(cairo_t *cr) = NULL; + +typedef struct _Ector_Cairo_Software_Surface_Data Ector_Cairo_Software_Surface_Data; +struct _Ector_Cairo_Software_Surface_Data +{ + cairo_surface_t *surface; + cairo_t *ctx; + + void *pixels; + + unsigned int width; + unsigned int height; +}; + +static void +_ector_cairo_software_surface_surface_set(Eo *obj, Ector_Cairo_Software_Surface_Data *pd, void *pixels, unsigned int width, unsigned int height) +{ + USE(obj, cairo_image_surface_create_for_data, ); + USE(obj, cairo_surface_destroy, ); + USE(obj, cairo_create, ); + USE(obj, cairo_destroy, ); + + if (pd->surface) cairo_surface_destroy(pd->surface); pd->surface = NULL; + if (pd->ctx) cairo_destroy(pd->ctx); pd->ctx = NULL; + + pd->pixels = NULL; + pd->width = 0; + pd->height = 0; + + if (pixels) + { + pd->surface = cairo_image_surface_create_for_data(pixels, + CAIRO_FORMAT_ARGB32, + width, height, width); + if (!pd->surface) goto end; + + pd->ctx = cairo_create(pd->surface); + if (!pd->ctx) goto end; + } + pd->pixels = pixels; + pd->width = width; + pd->height = height; + + end: + eo_do(obj, + ector_cairo_surface_context_set(pd->ctx), + ector_surface_size_set(pd->width, pd->height)); +} + +static void +_ector_cairo_software_surface_surface_get(Eo *obj EINA_UNUSED, Ector_Cairo_Software_Surface_Data *pd, void **pixels, unsigned int *width, unsigned int *height) +{ + if (pixels) *pixels = pd->pixels; + if (width) *width = pd->width; + if (height) *height = pd->height; +} + +#include "ector_cairo_software_surface.eo.c" diff --git a/src/modules/evas/engines/software_generic/ector_cairo_software_surface.eo b/src/modules/evas/engines/software_generic/ector_cairo_software_surface.eo new file mode 100644 index 0000000000..d5070abccf --- /dev/null +++ b/src/modules/evas/engines/software_generic/ector_cairo_software_surface.eo @@ -0,0 +1,18 @@ +class Ector.Cairo_Software.Surface (Ector.Cairo.Surface) +{ + eo_prefix: ector_cairo_software_surface; + legacy_prefix: null; + properties { + surface { + set { + } + get { + } + values { + void *pixels; + uint width; + uint height; + } + } + } +} diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index a679d5c767..fb276b9c9d 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -18,6 +18,11 @@ #include "Evas_Engine_Software_Generic.h" +#include "cairo/Ector_Cairo.h" +#include "software/Ector_Software.h" + +#include "ector_cairo_software_surface.eo.h" + #ifdef EVAS_GL //----------------------------------// // OSMesa... @@ -292,6 +297,8 @@ typedef struct _Evas_Thread_Command_Image Evas_Thread_Command_Image; typedef struct _Evas_Thread_Command_Font Evas_Thread_Command_Font; typedef struct _Evas_Thread_Command_Map Evas_Thread_Command_Map; typedef struct _Evas_Thread_Command_Multi_Font Evas_Thread_Command_Multi_Font; +typedef struct _Evas_Thread_Command_Ector Evas_Thread_Command_Ector; +typedef struct _Evas_Thread_Command_Ector_Surface Evas_Thread_Command_Ector_Surface; struct _Evas_Thread_Command_Rect { @@ -383,6 +390,23 @@ struct _Evas_Thread_Command_Multi_Font Evas_Font_Array *texts; }; +struct _Evas_Thread_Command_Ector +{ + Ector_Renderer *r; + Eina_Array *clips; + + DATA32 mul_col; + Ector_Rop render_op; + + Eina_Bool free_it; +}; + +struct _Evas_Thread_Command_Ector_Surface +{ + void *surface; + int x, y; +}; + Eina_Mempool *_mp_command_rect = NULL; Eina_Mempool *_mp_command_line = NULL; Eina_Mempool *_mp_command_polygon = NULL; @@ -390,7 +414,8 @@ Eina_Mempool *_mp_command_image = NULL; Eina_Mempool *_mp_command_font = NULL; Eina_Mempool *_mp_command_map = NULL; Eina_Mempool *_mp_command_multi_font = NULL; - +Eina_Mempool *_mp_command_ector = NULL; +Eina_Mempool *_mp_command_ector_surface = NULL; /* ***** ** @@ -3427,6 +3452,254 @@ eng_output_idle_flush(void *data) if (re->outbuf_idle_flush) re->outbuf_idle_flush(re->ob); } +static Ector_Surface *_software_ector = NULL; +static Eina_Bool use_cairo; + +static Ector_Surface * +eng_ector_get(void *data EINA_UNUSED) +{ + if (!_software_ector) + { + const char *ector_backend; + + ector_backend = getenv("ECTOR_BACKEND"); + if (ector_backend && !strcasecmp(ector_backend, "freetype")) + { + _software_ector = eo_add(ECTOR_SOFTWARE_SURFACE_CLASS, NULL); + use_cairo = EINA_FALSE; + } + else + { + _software_ector = eo_add(ECTOR_CAIRO_SOFTWARE_SURFACE_CLASS, NULL); + use_cairo = EINA_TRUE; + } + } + return _software_ector; +} + +static Ector_Rop +_evas_render_op_to_ector_rop(Evas_Render_Op op) +{ + switch (op) + { + case EVAS_RENDER_BLEND: + return ECTOR_ROP_BLEND; + case EVAS_RENDER_COPY: + return ECTOR_ROP_COPY; + default: + return ECTOR_ROP_BLEND; + } +} + +static void +_draw_thread_ector_cleanup(Evas_Thread_Command_Ector *ector) +{ + Eina_Rectangle *r; + + while ((r = eina_array_pop(ector->clips))) + eina_rectangle_free(r); + eina_array_free(ector->clips); + eo_unref(ector->r); + + if (ector->free_it) + eina_mempool_free(_mp_command_ector, ector); +} + +static void +_draw_thread_ector_draw(void *data) +{ + Evas_Thread_Command_Ector *ector = data; + + eo_do(ector->r, + ector_renderer_draw(ector->render_op, + ector->clips, + ector->mul_col)); + + _draw_thread_ector_cleanup(ector); +} + +static void +eng_ector_renderer_draw(void *data EINA_UNUSED, void *context, void *surface, Ector_Renderer *renderer, Eina_Array *clips, Eina_Bool do_async) +{ + RGBA_Image *dst = surface; + RGBA_Draw_Context *dc = context; + Evas_Thread_Command_Ector ector; + Eina_Array *c; + Eina_Rectangle *r; + Eina_Rectangle clip; + Eina_Array_Iterator it; + unsigned int i; + + if (dc->clip.use) + { + clip.x = dc->clip.x; + clip.y = dc->clip.y; + clip.w = dc->clip.w; + clip.h = dc->clip.h; + } + else + { + clip.x = 0; + clip.y = 0; + clip.w = dst->cache_entry.w; + clip.h = dst->cache_entry.h; + } + + c = eina_array_new(8); + if (clips) + { + EINA_ARRAY_ITER_NEXT(clips, i, r, it) + { + Eina_Rectangle *rc; + + rc = eina_rectangle_new(r->x, r->y, r->w, r->h); + if (!rc) continue; + + if (eina_rectangle_intersection(rc, &clip)) + eina_array_push(c, rc); + else + eina_rectangle_free(rc); + } + + if (eina_array_count(c) == 0 && + eina_array_count(clips) > 0) + return ; + } + + if (eina_array_count(c) == 0) + eina_array_push(c, eina_rectangle_new(clip.x, clip.y, clip.w, clip.h)); + + ector.r = eo_ref(renderer); + ector.clips = c; + ector.render_op = _evas_render_op_to_ector_rop(dc->render_op); + ector.mul_col = ector_color_multiply(dc->mul.use ? dc->mul.col : 0xffffffff, + dc->col.col);; + ector.free_it = EINA_FALSE; + + if (do_async) + { + Evas_Thread_Command_Ector *ne; + + ne = eina_mempool_malloc(_mp_command_ector, sizeof (Evas_Thread_Command_Ector)); + if (!ne) + { + _draw_thread_ector_cleanup(&ector); + return ; + } + + memcpy(ne, &ector, sizeof (Evas_Thread_Command_Ector)); + ne->free_it = EINA_TRUE; + + evas_thread_cmd_enqueue(_draw_thread_ector_draw, ne); + } + else + { + _draw_thread_ector_draw(&ector); + } +} + +static void +_draw_thread_ector_surface_set(void *data) +{ + Evas_Thread_Command_Ector_Surface *ector_surface = data; + RGBA_Image *surface = ector_surface->surface; + void *pixels = NULL; + unsigned int w = 0; + unsigned int h = 0; + unsigned int x = 0; + unsigned int y = 0; + + // flush the cpu pipeline before ector drawing. + evas_common_cpu_end_opt(); + + if (surface) + { + pixels = evas_cache_image_pixels(&surface->cache_entry); + w = surface->cache_entry.w; + h = surface->cache_entry.h; + x = ector_surface->x; + y = ector_surface->y; + } + + if (use_cairo) + { + eo_do(_software_ector, + ector_cairo_software_surface_set(pixels, w, h), + ector_surface_reference_point_set(x, y)); + } + else + { + eo_do(_software_ector, + ector_software_surface_set(pixels, w, h), + ector_surface_reference_point_set(x, y)); + } + + eina_mempool_free(_mp_command_ector_surface, ector_surface); +} + +static void +eng_ector_begin(void *data EINA_UNUSED, void *context EINA_UNUSED, void *surface, int x, int y, Eina_Bool do_async) +{ + if (do_async) + { + Evas_Thread_Command_Ector_Surface *nes; + + nes = eina_mempool_malloc(_mp_command_ector_surface, sizeof (Evas_Thread_Command_Ector_Surface)); + if (!nes) return ; + + nes->surface = surface; + nes->x = x; + nes->y = y; + + evas_thread_cmd_enqueue(_draw_thread_ector_surface_set, nes); + } + else + { + RGBA_Image *sf = surface; + void *pixels = NULL; + unsigned int w = 0; + unsigned int h = 0; + + pixels = evas_cache_image_pixels(&sf->cache_entry); + w = sf->cache_entry.w; + h = sf->cache_entry.h; + + if (use_cairo) + { + eo_do(_software_ector, + ector_cairo_software_surface_set(pixels, w, h), + ector_surface_reference_point_set(x, y)); + } + else + { + eo_do(_software_ector, + ector_software_surface_set(pixels, w, h), + ector_surface_reference_point_set(x, y)); + } + } +} + +static void +eng_ector_end(void *data EINA_UNUSED, void *context EINA_UNUSED, void *surface EINA_UNUSED, Eina_Bool do_async) +{ + if (do_async) + { + Evas_Thread_Command_Ector_Surface *nes; + + nes = eina_mempool_malloc(_mp_command_ector_surface, sizeof (Evas_Thread_Command_Ector_Surface)); + if (!nes) return ; + + nes->surface = NULL; + + evas_thread_cmd_enqueue(_draw_thread_ector_surface_set, nes); + } + else + { + eo_do(_software_ector, ector_cairo_software_surface_set(NULL, 0, 0)); + + evas_common_cpu_end_opt(); + } +} //------------------------------------------------// @@ -3597,7 +3870,10 @@ static Evas_Func func = NULL, // eng_drawable_free NULL, // eng_drawable_size_get NULL, // eng_image_drawable_set - NULL, // eng_drawable_render_scene + NULL, // eng_drawable_scene_render + NULL, // eng_drawable_scene_render_to_texture + NULL, // eng_drawable_texture_color_pick_id_get + NULL, // eng_drawable_texture_pixel_color_get NULL, // eng_texture_new NULL, // eng_texture_free NULL, // eng_texture_data_set @@ -3609,6 +3885,10 @@ static Evas_Func func = NULL, // eng_texture_filter_set NULL, // eng_texture_filter_get NULL, // eng_texture_image_set + eng_ector_get, + eng_ector_begin, + eng_ector_renderer_draw, + eng_ector_end /* FUTURE software generic calls go here */ }; @@ -4657,6 +4937,12 @@ module_open(Evas_Module *em) _mp_command_multi_font = eina_mempool_add("chained_mempool", "Evas_Thread_Command_Multi_Font", NULL, sizeof(Evas_Thread_Command_Multi_Font), 128); + _mp_command_ector = + eina_mempool_add("chained_mempool", "Evas_Thread_Command_Ector", + NULL, sizeof(Evas_Thread_Command_Ector), 128); + _mp_command_ector_surface = + eina_mempool_add("chained_mempool", "Evas_Thread_Command_Ector_Surface", + NULL, sizeof(Evas_Thread_Command_Ector_Surface), 128); init_gl(); evas_common_pipe_init(); @@ -4675,6 +4961,7 @@ module_close(Evas_Module *em EINA_UNUSED) eina_mempool_del(_mp_command_image); eina_mempool_del(_mp_command_font); eina_mempool_del(_mp_command_map); + eina_mempool_del(_mp_command_ector); eina_log_domain_unregister(_evas_soft_gen_log_dom); } @@ -4689,8 +4976,114 @@ static Evas_Module_Api evas_modapi = } }; -EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, software_generic); +Eina_Bool evas_engine_software_generic_init(void) +{ + return evas_module_register(&evas_modapi, EVAS_MODULE_TYPE_ENGINE); +} + +// Time to destroy the ector context +void evas_engine_software_generic_shutdown(void) +{ + if (_software_ector) eo_del(_software_ector); + _software_ector = NULL; + + evas_module_unregister(&evas_modapi, EVAS_MODULE_TYPE_ENGINE); +} #ifndef EVAS_STATIC_BUILD_SOFTWARE_GENERIC EVAS_EINA_MODULE_DEFINE(engine, software_generic); #endif + +#define USE(Obj, Sym, Error) \ + if (!Sym) Sym = _ector_cairo_symbol_get(Obj, #Sym); \ + if (!Sym) return Error; + +static inline void * +_ector_cairo_symbol_get(Eo *ector_surface, const char *name) +{ + void *sym; + + eo_do(ector_surface, + sym = ector_cairo_surface_symbol_get(name)); + return sym; +} + +typedef struct _cairo_surface_t cairo_surface_t; +typedef enum { + CAIRO_FORMAT_INVALID = -1, + CAIRO_FORMAT_ARGB32 = 0, + CAIRO_FORMAT_RGB24 = 1, + CAIRO_FORMAT_A8 = 2, + CAIRO_FORMAT_A1 = 3, + CAIRO_FORMAT_RGB16_565 = 4, + CAIRO_FORMAT_RGB30 = 5 +} cairo_format_t; + +static cairo_surface_t *(*cairo_image_surface_create_for_data)(unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride) = NULL; +static void (*cairo_surface_destroy)(cairo_surface_t *surface) = NULL; +static cairo_t *(*cairo_create)(cairo_surface_t *target) = NULL; +static void (*cairo_destroy)(cairo_t *cr) = NULL; + +typedef struct _Ector_Cairo_Software_Surface_Data Ector_Cairo_Software_Surface_Data; +struct _Ector_Cairo_Software_Surface_Data +{ + cairo_surface_t *surface; + cairo_t *ctx; + + void *pixels; + + unsigned int width; + unsigned int height; +}; + +void +_ector_cairo_software_surface_surface_set(Eo *obj, Ector_Cairo_Software_Surface_Data *pd, void *pixels, unsigned int width, unsigned int height) +{ + USE(obj, cairo_image_surface_create_for_data, ); + USE(obj, cairo_surface_destroy, ); + USE(obj, cairo_create, ); + USE(obj, cairo_destroy, ); + + if (pd->surface) cairo_surface_destroy(pd->surface); pd->surface = NULL; + if (pd->ctx) cairo_destroy(pd->ctx); pd->ctx = NULL; + + pd->pixels = NULL; + pd->width = 0; + pd->height = 0; + + if (pixels) + { + pd->surface = cairo_image_surface_create_for_data(pixels, + CAIRO_FORMAT_ARGB32, + width, height, width * sizeof (int)); + if (!pd->surface) goto end; + + pd->ctx = cairo_create(pd->surface); + if (!pd->ctx) goto end; + } + + pd->pixels = pixels; + pd->width = width; + pd->height = height; + + end: + evas_common_cpu_end_opt(); + + eo_do(obj, + ector_cairo_surface_context_set(pd->ctx), + ector_surface_size_set(pd->width, pd->height)); +} + +void +_ector_cairo_software_surface_surface_get(Eo *obj EINA_UNUSED, Ector_Cairo_Software_Surface_Data *pd, void **pixels, unsigned int *width, unsigned int *height) +{ + if (pixels) *pixels = pd->pixels; + if (width) *width = pd->width; + if (height) *height = pd->height; +} + +#include "ector_cairo_software_surface.eo.c" diff --git a/src/tests/ector/cxx_compile_test.cxx b/src/tests/ector/cxx_compile_test.cxx new file mode 100644 index 0000000000..091757aa37 --- /dev/null +++ b/src/tests/ector/cxx_compile_test.cxx @@ -0,0 +1,34 @@ +/* EINA - EFL data type library + * Copyright (C) 2012 ProFUSION embedded systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "Ector.h" + +#include +using namespace std; + +int main() +{ + ector_init(); + cout << "Ector compiles with C++!"; + ector_shutdown(); + return 0; +} diff --git a/src/tests/ector/ector_suite.c b/src/tests/ector/ector_suite.c new file mode 100644 index 0000000000..fbae22c4a0 --- /dev/null +++ b/src/tests/ector/ector_suite.c @@ -0,0 +1,113 @@ +/* ECTOR - EFL retained mode drawing library + * Copyright (C) 2014 Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include + +#include "Eina.h" + +#include "ector_suite.h" + +typedef struct _Ector_Test_Case Ector_Test_Case; +struct _Ector_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Ector_Test_Case etc[] = { + { "init", ector_test_init }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Ector_Test_Case *itr = etc; + fputs("Available Test Cases:\n", stderr); + for (; itr->test_case; itr++) + fprintf(stderr, "\t%s\n", itr->test_case); +} + +static Eina_Bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return 1; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return 1; + + return 0; +} + +int +main(int argc, char *argv[]) +{ + TCase *tc; + Suite *s; + SRunner *sr; + int failed_count, i; + + for (i = 1; i < argc; i++) + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", + argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + + putenv("EFL_RUN_IN_TREE=1"); + + s = suite_create("Ector"); + + for (i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc - 1, (const char **) argv + 1, etc[i].test_case)) + continue; + + tc = tcase_create(etc[i].test_case); + tcase_set_timeout(tc, 0); + + etc[i].build(tc); + suite_add_tcase(s, tc); + } + + sr = srunner_create(s); + srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml"); + srunner_run_all(sr, CK_ENV); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + return (failed_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/tests/ector/ector_suite.h b/src/tests/ector/ector_suite.h new file mode 100644 index 0000000000..176a838818 --- /dev/null +++ b/src/tests/ector/ector_suite.h @@ -0,0 +1,8 @@ +#ifndef ECTOR_SUITE_H +#define ECTOR_SUITE_H + +#include + +void ector_test_init(TCase *tc); + +#endif diff --git a/src/tests/ector/ector_test_init.c b/src/tests/ector/ector_test_init.c new file mode 100644 index 0000000000..1c36e4012d --- /dev/null +++ b/src/tests/ector/ector_test_init.c @@ -0,0 +1,38 @@ +/* ECTOR - EFL retained mode drawing library + * Copyright (C) 2014 Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ector_suite.h" + +#include "Ector.h" + +START_TEST(ector_init_simple) +{ + fail_if(ector_init() != 1); + fail_if(ector_shutdown() != 0); +} +END_TEST + +void +ector_test_init(TCase *tc) +{ + tcase_add_test(tc, ector_init_simple); +} diff --git a/src/tests/evas/evas_test_filters.c b/src/tests/evas/evas_test_filters.c index cb219056c0..b81edc3f7c 100644 --- a/src/tests/evas/evas_test_filters.c +++ b/src/tests/evas/evas_test_filters.c @@ -387,14 +387,14 @@ START_TEST(evas_filter_text_render_test) evas_object_resize(o, 10, 10); evas_object_show(o); eo_do(to, - evas_obj_color_set(255, 255, 255, 255), + efl_gfx_color_set(255, 255, 255, 255), evas_obj_text_filter_source_set(tc->source, o), evas_obj_text_filter_program_set(tc->code)); } else { eo_do(to, - evas_obj_color_set(255, 255, 255, 255), + efl_gfx_color_set(255, 255, 255, 255), evas_obj_text_filter_program_set(tc->code)); } diff --git a/src/tests/evas/evas_test_mesh.c b/src/tests/evas/evas_test_mesh.c index 558dcfad20..440c31b28a 100644 --- a/src/tests/evas/evas_test_mesh.c +++ b/src/tests/evas/evas_test_mesh.c @@ -34,29 +34,29 @@ src2 += f2->vertices[a].element_count; \ } -#define CHECK_MESHES_IN_FOLDER(folder, ext) \ - it = eina_file_direct_ls(folder); \ - EINA_ITERATOR_FOREACH(it, file) \ - { \ - mesh = eo_add(EVAS_3D_MESH_CLASS, e); \ - mesh2 = eo_add(EVAS_3D_MESH_CLASS, e); \ - fail_if(mesh == NULL); \ - fail_if(mesh2 == NULL); \ - snprintf(buffer, PATH_MAX, "%s", ext); \ - eo_do(mesh, efl_file_set(file->path, NULL), \ - efl_file_save(buffer, NULL, NULL)); \ - eo_do(mesh2, efl_file_set(buffer, NULL)); \ - res = _compare_meshes(mesh, mesh2); \ - fail_if(res == 1); \ - eo_do(mesh, evas_3d_mesh_mmap_set(eina_file_open(file->path, 0), NULL), \ - efl_file_save(buffer, NULL, NULL)); \ - eo_do(mesh2, evas_3d_mesh_mmap_set(eina_file_open(buffer, 0), NULL)); \ - res = _compare_meshes(mesh, mesh2); \ - fail_if(res == 1); \ - eo_del(mesh2); \ - eo_del(mesh); \ - unlink(buffer); \ - } +#define CHECK_MESHES_IN_FOLDER(folder, ext) \ + it = eina_file_direct_ls(folder); \ + EINA_ITERATOR_FOREACH(it, file) \ + { \ + mesh = eo_add(EVAS_3D_MESH_CLASS, e); \ + mesh2 = eo_add(EVAS_3D_MESH_CLASS, e); \ + fail_if(mesh == NULL); \ + fail_if(mesh2 == NULL); \ + snprintf(buffer, PATH_MAX, "%s", ext); \ + eo_do(mesh, efl_file_set(file->path, NULL), \ + efl_file_save(buffer, NULL, NULL)); \ + eo_do(mesh2, efl_file_set(buffer, NULL)); \ + res = _compare_meshes(mesh, mesh2); \ + fail_if(res == 1); \ + eo_do(mesh, efl_file_mmap_set(eina_file_open(file->path, 0), NULL), \ + efl_file_save(buffer, NULL, NULL)); \ + eo_do(mesh2, efl_file_mmap_set(eina_file_open(buffer, 0), NULL)); \ + res = _compare_meshes(mesh, mesh2); \ + fail_if(res == 1); \ + eo_del(mesh2); \ + eo_del(mesh); \ + unlink(buffer); \ + } static Evas_3D_Mesh_Frame * return_zero_frame(Evas_3D_Mesh_Data *pd)