aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas
diff options
context:
space:
mode:
authorDavid Walter Seikel2012-01-04 18:41:13 +1000
committerDavid Walter Seikel2012-01-04 18:41:13 +1000
commitdd7595a3475407a7fa96a97393bae8c5220e8762 (patch)
treee341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/evas/src/lib/canvas
parentAdd the skeleton. (diff)
downloadSledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
Diffstat (limited to 'libraries/evas/src/lib/canvas')
-rw-r--r--libraries/evas/src/lib/canvas/Makefile.am68
-rw-r--r--libraries/evas/src/lib/canvas/Makefile.in760
-rw-r--r--libraries/evas/src/lib/canvas/evas_async_events.c173
-rw-r--r--libraries/evas/src/lib/canvas/evas_callbacks.c534
-rw-r--r--libraries/evas/src/lib/canvas/evas_clip.c321
-rw-r--r--libraries/evas/src/lib/canvas/evas_data.c72
-rw-r--r--libraries/evas/src/lib/canvas/evas_events.c1602
-rw-r--r--libraries/evas/src/lib/canvas/evas_filter.c1427
-rw-r--r--libraries/evas/src/lib/canvas/evas_focus.c59
-rw-r--r--libraries/evas/src/lib/canvas/evas_font_dir.c1349
-rw-r--r--libraries/evas/src/lib/canvas/evas_gl.c245
-rw-r--r--libraries/evas/src/lib/canvas/evas_key.c245
-rw-r--r--libraries/evas/src/lib/canvas/evas_key_grab.c179
-rw-r--r--libraries/evas/src/lib/canvas/evas_layer.c193
-rw-r--r--libraries/evas/src/lib/canvas/evas_main.c671
-rw-r--r--libraries/evas/src/lib/canvas/evas_map.c1031
-rw-r--r--libraries/evas/src/lib/canvas/evas_name.c40
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_box.c2128
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_grid.c465
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_image.c3895
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_inform.c79
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_intercept.c625
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_line.c461
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_main.c1319
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_polygon.c554
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_rectangle.c387
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_smart.c920
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_smart_clipped.c183
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_table.c1373
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_text.c1943
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_textblock.c9569
-rw-r--r--libraries/evas/src/lib/canvas/evas_rectangle.c98
-rw-r--r--libraries/evas/src/lib/canvas/evas_render.c1866
-rw-r--r--libraries/evas/src/lib/canvas/evas_smart.c266
-rw-r--r--libraries/evas/src/lib/canvas/evas_stack.c391
-rw-r--r--libraries/evas/src/lib/canvas/evas_stats.c185
-rw-r--r--libraries/evas/src/lib/canvas/evas_touch_point.c110
37 files changed, 35786 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/Makefile.am b/libraries/evas/src/lib/canvas/Makefile.am
new file mode 100644
index 0000000..79544aa
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/Makefile.am
@@ -0,0 +1,68 @@
1MAINTAINERCLEANFILES = Makefile.in
2
3AM_CPPFLAGS = \
4-I. \
5-I$(top_srcdir)/src/lib \
6-I$(top_srcdir)/src/lib/include \
7-I$(top_srcdir)/src/lib/cserve \
8-DPACKAGE_BIN_DIR=\"$(bindir)\" \
9-DPACKAGE_LIB_DIR=\"$(libdir)\" \
10-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
11@WIN32_CPPFLAGS@ \
12@FREETYPE_CFLAGS@ \
13@EET_CFLAGS@ \
14@FONTCONFIG_CFLAGS@ \
15@EVAS_CFLAGS@ \
16@EINA_CFLAGS@ \
17@EVIL_CFLAGS@ \
18@PIXMAN_CFLAGS@
19
20noinst_LTLIBRARIES = libevas_canvas.la
21libevas_canvas_la_SOURCES = \
22evas_callbacks.c \
23evas_clip.c \
24evas_data.c \
25evas_events.c \
26evas_filter.c \
27evas_focus.c \
28evas_key.c \
29evas_key_grab.c \
30evas_layer.c \
31evas_main.c \
32evas_name.c \
33evas_object_image.c \
34evas_object_main.c \
35evas_object_inform.c \
36evas_object_intercept.c \
37evas_object_line.c \
38evas_object_polygon.c \
39evas_object_rectangle.c \
40evas_object_smart.c \
41evas_object_smart_clipped.c \
42evas_object_box.c \
43evas_object_table.c \
44evas_object_text.c \
45evas_object_textblock.c \
46evas_object_grid.c \
47evas_font_dir.c \
48evas_rectangle.c \
49evas_render.c \
50evas_smart.c \
51evas_stack.c \
52evas_async_events.c \
53evas_stats.c \
54evas_touch_point.c \
55evas_map.c \
56evas_gl.c
57
58#evas_object_textgrid.c
59
60libevas_canvas_la_LIBADD = @EVAS_LIBS@ @EVIL_LIBS@
61
62if EVAS_USE_LINEBREAK
63AM_CPPFLAGS += @LINEBREAK_CFLAGS@
64libevas_canvas_la_LIBADD += @LINEBREAK_LIBS@
65endif
66
67clean-local:
68 rm -rf *.gcno
diff --git a/libraries/evas/src/lib/canvas/Makefile.in b/libraries/evas/src/lib/canvas/Makefile.in
new file mode 100644
index 0000000..0b4e15d
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/Makefile.in
@@ -0,0 +1,760 @@
1# Makefile.in generated by automake 1.11.1 from Makefile.am.
2# @configure_input@
3
4# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
6# Inc.
7# This Makefile.in is free software; the Free Software Foundation
8# gives unlimited permission to copy and/or distribute it,
9# with or without modifications, as long as this notice is preserved.
10
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
13# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14# PARTICULAR PURPOSE.
15
16@SET_MAKE@
17
18VPATH = @srcdir@
19pkgdatadir = $(datadir)/@PACKAGE@
20pkgincludedir = $(includedir)/@PACKAGE@
21pkglibdir = $(libdir)/@PACKAGE@
22pkglibexecdir = $(libexecdir)/@PACKAGE@
23am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
24install_sh_DATA = $(install_sh) -c -m 644
25install_sh_PROGRAM = $(install_sh) -c
26install_sh_SCRIPT = $(install_sh) -c
27INSTALL_HEADER = $(INSTALL_DATA)
28transform = $(program_transform_name)
29NORMAL_INSTALL = :
30PRE_INSTALL = :
31POST_INSTALL = :
32NORMAL_UNINSTALL = :
33PRE_UNINSTALL = :
34POST_UNINSTALL = :
35build_triplet = @build@
36host_triplet = @host@
37@EVAS_USE_LINEBREAK_TRUE@am__append_1 = @LINEBREAK_CFLAGS@
38@EVAS_USE_LINEBREAK_TRUE@am__append_2 = @LINEBREAK_LIBS@
39subdir = src/lib/canvas
40DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
41ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
42am__aclocal_m4_deps = $(top_srcdir)/m4/efl_attribute.m4 \
43 $(top_srcdir)/m4/efl_coverage.m4 \
44 $(top_srcdir)/m4/efl_doxygen.m4 \
45 $(top_srcdir)/m4/efl_fnmatch.m4 \
46 $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \
47 $(top_srcdir)/m4/evas_check_engine.m4 \
48 $(top_srcdir)/m4/evas_check_loader.m4 \
49 $(top_srcdir)/m4/evas_converter.m4 \
50 $(top_srcdir)/m4/evas_dither.m4 \
51 $(top_srcdir)/m4/evas_scaler.m4 $(top_srcdir)/m4/libtool.m4 \
52 $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
53 $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
54 $(top_srcdir)/configure.ac
55am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
56 $(ACLOCAL_M4)
57mkinstalldirs = $(install_sh) -d
58CONFIG_HEADER = $(top_builddir)/config.h
59CONFIG_CLEAN_FILES =
60CONFIG_CLEAN_VPATH_FILES =
61LTLIBRARIES = $(noinst_LTLIBRARIES)
62am__DEPENDENCIES_1 =
63libevas_canvas_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
64am_libevas_canvas_la_OBJECTS = evas_callbacks.lo evas_clip.lo \
65 evas_data.lo evas_events.lo evas_filter.lo evas_focus.lo \
66 evas_key.lo evas_key_grab.lo evas_layer.lo evas_main.lo \
67 evas_name.lo evas_object_image.lo evas_object_main.lo \
68 evas_object_inform.lo evas_object_intercept.lo \
69 evas_object_line.lo evas_object_polygon.lo \
70 evas_object_rectangle.lo evas_object_smart.lo \
71 evas_object_smart_clipped.lo evas_object_box.lo \
72 evas_object_table.lo evas_object_text.lo \
73 evas_object_textblock.lo evas_object_grid.lo evas_font_dir.lo \
74 evas_rectangle.lo evas_render.lo evas_smart.lo evas_stack.lo \
75 evas_async_events.lo evas_stats.lo evas_touch_point.lo \
76 evas_map.lo evas_gl.lo
77libevas_canvas_la_OBJECTS = $(am_libevas_canvas_la_OBJECTS)
78AM_V_lt = $(am__v_lt_$(V))
79am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
80am__v_lt_0 = --silent
81DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
82depcomp = $(SHELL) $(top_srcdir)/depcomp
83am__depfiles_maybe = depfiles
84am__mv = mv -f
85COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
86 $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
87LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
88 $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
89 $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
90 $(AM_CFLAGS) $(CFLAGS)
91AM_V_CC = $(am__v_CC_$(V))
92am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
93am__v_CC_0 = @echo " CC " $@;
94AM_V_at = $(am__v_at_$(V))
95am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
96am__v_at_0 = @
97CCLD = $(CC)
98LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
99 $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
100 $(AM_LDFLAGS) $(LDFLAGS) -o $@
101AM_V_CCLD = $(am__v_CCLD_$(V))
102am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
103am__v_CCLD_0 = @echo " CCLD " $@;
104AM_V_GEN = $(am__v_GEN_$(V))
105am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
106am__v_GEN_0 = @echo " GEN " $@;
107SOURCES = $(libevas_canvas_la_SOURCES)
108DIST_SOURCES = $(libevas_canvas_la_SOURCES)
109ETAGS = etags
110CTAGS = ctags
111DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
112ACLOCAL = @ACLOCAL@
113ALLOCA = @ALLOCA@
114AMTAR = @AMTAR@
115AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
116AR = @AR@
117AS = @AS@
118AUTOCONF = @AUTOCONF@
119AUTOHEADER = @AUTOHEADER@
120AUTOMAKE = @AUTOMAKE@
121AWK = @AWK@
122CC = @CC@
123CCDEPMODE = @CCDEPMODE@
124CFLAGS = @CFLAGS@
125CHECK_CFLAGS = @CHECK_CFLAGS@
126CHECK_LIBS = @CHECK_LIBS@
127CPP = @CPP@
128CPPFLAGS = @CPPFLAGS@
129CXX = @CXX@
130CXXCPP = @CXXCPP@
131CXXDEPMODE = @CXXDEPMODE@
132CXXFLAGS = @CXXFLAGS@
133CYGPATH_W = @CYGPATH_W@
134DEFS = @DEFS@
135DEPDIR = @DEPDIR@
136DIRECTFB_CFLAGS = @DIRECTFB_CFLAGS@
137DIRECTFB_LIBS = @DIRECTFB_LIBS@
138DLLTOOL = @DLLTOOL@
139DSYMUTIL = @DSYMUTIL@
140DUMPBIN = @DUMPBIN@
141ECHO_C = @ECHO_C@
142ECHO_N = @ECHO_N@
143ECHO_T = @ECHO_T@
144ECORE_EVAS_CFLAGS = @ECORE_EVAS_CFLAGS@
145ECORE_EVAS_LIBS = @ECORE_EVAS_LIBS@
146EDB_CFLAGS = @EDB_CFLAGS@
147EDB_LIBS = @EDB_LIBS@
148EDJE_CFLAGS = @EDJE_CFLAGS@
149EDJE_LIBS = @EDJE_LIBS@
150EET_CFLAGS = @EET_CFLAGS@
151EET_LIBS = @EET_LIBS@
152EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@
153EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@
154EFL_FNMATCH_LIBS = @EFL_FNMATCH_LIBS@
155EGREP = @EGREP@
156EINA_CFLAGS = @EINA_CFLAGS@
157EINA_LIBS = @EINA_LIBS@
158EVAS_CFLAGS = @EVAS_CFLAGS@
159EVAS_LIBS = @EVAS_LIBS@
160EVAS_SSE3_CFLAGS = @EVAS_SSE3_CFLAGS@
161EVIL_CFLAGS = @EVIL_CFLAGS@
162EVIL_LIBS = @EVIL_LIBS@
163EXEEXT = @EXEEXT@
164FGREP = @FGREP@
165FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
166FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
167FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
168FREETYPE_LIBS = @FREETYPE_LIBS@
169FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@
170FRIBIDI_LIBS = @FRIBIDI_LIBS@
171GL_EET_CFLAGS = @GL_EET_CFLAGS@
172GL_EET_LIBS = @GL_EET_LIBS@
173GREP = @GREP@
174HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
175HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
176INSTALL = @INSTALL@
177INSTALL_DATA = @INSTALL_DATA@
178INSTALL_PROGRAM = @INSTALL_PROGRAM@
179INSTALL_SCRIPT = @INSTALL_SCRIPT@
180INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
181LD = @LD@
182LDFLAGS = @LDFLAGS@
183LIBOBJS = @LIBOBJS@
184LIBS = @LIBS@
185LIBTOOL = @LIBTOOL@
186LINEBREAK_CFLAGS = @LINEBREAK_CFLAGS@
187LINEBREAK_LIBS = @LINEBREAK_LIBS@
188LIPO = @LIPO@
189LN_S = @LN_S@
190LTLIBOBJS = @LTLIBOBJS@
191MAKEINFO = @MAKEINFO@
192MKDIR_P = @MKDIR_P@
193MODULE_ARCH = @MODULE_ARCH@
194NM = @NM@
195NMEDIT = @NMEDIT@
196OBJC = @OBJC@
197OBJCDEPMODE = @OBJCDEPMODE@
198OBJCFLAGS = @OBJCFLAGS@
199OBJDUMP = @OBJDUMP@
200OBJEXT = @OBJEXT@
201OTOOL = @OTOOL@
202OTOOL64 = @OTOOL64@
203PACKAGE = @PACKAGE@
204PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
205PACKAGE_NAME = @PACKAGE_NAME@
206PACKAGE_STRING = @PACKAGE_STRING@
207PACKAGE_TARNAME = @PACKAGE_TARNAME@
208PACKAGE_URL = @PACKAGE_URL@
209PACKAGE_VERSION = @PACKAGE_VERSION@
210PATH_SEPARATOR = @PATH_SEPARATOR@
211PIXMAN_CFLAGS = @PIXMAN_CFLAGS@
212PIXMAN_LIBS = @PIXMAN_LIBS@
213PKG_CONFIG = @PKG_CONFIG@
214PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
215PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
216PNG_CFLAGS = @PNG_CFLAGS@
217PNG_LIBS = @PNG_LIBS@
218RANLIB = @RANLIB@
219SDL_CFLAGS = @SDL_CFLAGS@
220SDL_LIBS = @SDL_LIBS@
221SED = @SED@
222SET_MAKE = @SET_MAKE@
223SHELL = @SHELL@
224SHM_OPEN_LINK = @SHM_OPEN_LINK@
225STRIP = @STRIP@
226SVG_CFLAGS = @SVG_CFLAGS@
227SVG_LIBS = @SVG_LIBS@
228VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
229VALGRIND_LIBS = @VALGRIND_LIBS@
230VERSION = @VERSION@
231VMAJ = @VMAJ@
232WIN32_CFLAGS = @WIN32_CFLAGS@
233WIN32_CPPFLAGS = @WIN32_CPPFLAGS@
234XCB_CFLAGS = @XCB_CFLAGS@
235XCB_GL_CFLAGS = @XCB_GL_CFLAGS@
236XCB_GL_LIBS = @XCB_GL_LIBS@
237XCB_LIBS = @XCB_LIBS@
238XEXT_CFLAGS = @XEXT_CFLAGS@
239XEXT_LIBS = @XEXT_LIBS@
240XMKMF = @XMKMF@
241X_CFLAGS = @X_CFLAGS@
242X_EXTRA_LIBS = @X_EXTRA_LIBS@
243X_LIBS = @X_LIBS@
244X_PRE_LIBS = @X_PRE_LIBS@
245abs_builddir = @abs_builddir@
246abs_srcdir = @abs_srcdir@
247abs_top_builddir = @abs_top_builddir@
248abs_top_srcdir = @abs_top_srcdir@
249ac_ct_CC = @ac_ct_CC@
250ac_ct_CXX = @ac_ct_CXX@
251ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
252ac_ct_OBJC = @ac_ct_OBJC@
253altivec_cflags = @altivec_cflags@
254am__include = @am__include@
255am__leading_dot = @am__leading_dot@
256am__quote = @am__quote@
257am__tar = @am__tar@
258am__untar = @am__untar@
259bindir = @bindir@
260build = @build@
261build_alias = @build_alias@
262build_cpu = @build_cpu@
263build_os = @build_os@
264build_vendor = @build_vendor@
265builddir = @builddir@
266datadir = @datadir@
267datarootdir = @datarootdir@
268dlopen_libs = @dlopen_libs@
269docdir = @docdir@
270dvidir = @dvidir@
271edje_cc = @edje_cc@
272efl_doxygen = @efl_doxygen@
273efl_have_doxygen = @efl_have_doxygen@
274evas_engine_buffer_cflags = @evas_engine_buffer_cflags@
275evas_engine_buffer_libs = @evas_engine_buffer_libs@
276evas_engine_direct3d_cflags = @evas_engine_direct3d_cflags@
277evas_engine_direct3d_libs = @evas_engine_direct3d_libs@
278evas_engine_directfb_cflags = @evas_engine_directfb_cflags@
279evas_engine_directfb_libs = @evas_engine_directfb_libs@
280evas_engine_fb_cflags = @evas_engine_fb_cflags@
281evas_engine_fb_libs = @evas_engine_fb_libs@
282evas_engine_gl_cocoa_cflags = @evas_engine_gl_cocoa_cflags@
283evas_engine_gl_cocoa_libs = @evas_engine_gl_cocoa_libs@
284evas_engine_gl_common_libs = @evas_engine_gl_common_libs@
285evas_engine_gl_sdl_cflags = @evas_engine_gl_sdl_cflags@
286evas_engine_gl_sdl_libs = @evas_engine_gl_sdl_libs@
287evas_engine_gl_xcb_cflags = @evas_engine_gl_xcb_cflags@
288evas_engine_gl_xcb_libs = @evas_engine_gl_xcb_libs@
289evas_engine_gl_xlib_cflags = @evas_engine_gl_xlib_cflags@
290evas_engine_gl_xlib_libs = @evas_engine_gl_xlib_libs@
291evas_engine_psl1ght_cflags = @evas_engine_psl1ght_cflags@
292evas_engine_psl1ght_libs = @evas_engine_psl1ght_libs@
293evas_engine_software_16_ddraw_cflags = @evas_engine_software_16_ddraw_cflags@
294evas_engine_software_16_ddraw_libs = @evas_engine_software_16_ddraw_libs@
295evas_engine_software_16_sdl_cflags = @evas_engine_software_16_sdl_cflags@
296evas_engine_software_16_sdl_libs = @evas_engine_software_16_sdl_libs@
297evas_engine_software_16_wince_cflags = @evas_engine_software_16_wince_cflags@
298evas_engine_software_16_wince_libs = @evas_engine_software_16_wince_libs@
299evas_engine_software_16_x11_cflags = @evas_engine_software_16_x11_cflags@
300evas_engine_software_16_x11_libs = @evas_engine_software_16_x11_libs@
301evas_engine_software_8_x11_cflags = @evas_engine_software_8_x11_cflags@
302evas_engine_software_8_x11_libs = @evas_engine_software_8_x11_libs@
303evas_engine_software_ddraw_cflags = @evas_engine_software_ddraw_cflags@
304evas_engine_software_ddraw_libs = @evas_engine_software_ddraw_libs@
305evas_engine_software_gdi_cflags = @evas_engine_software_gdi_cflags@
306evas_engine_software_gdi_libs = @evas_engine_software_gdi_libs@
307evas_engine_software_sdl_cflags = @evas_engine_software_sdl_cflags@
308evas_engine_software_sdl_libs = @evas_engine_software_sdl_libs@
309evas_engine_software_xcb_cflags = @evas_engine_software_xcb_cflags@
310evas_engine_software_xcb_libs = @evas_engine_software_xcb_libs@
311evas_engine_software_xlib_cflags = @evas_engine_software_xlib_cflags@
312evas_engine_software_xlib_libs = @evas_engine_software_xlib_libs@
313evas_image_loader_bmp_cflags = @evas_image_loader_bmp_cflags@
314evas_image_loader_bmp_libs = @evas_image_loader_bmp_libs@
315evas_image_loader_edb_cflags = @evas_image_loader_edb_cflags@
316evas_image_loader_edb_libs = @evas_image_loader_edb_libs@
317evas_image_loader_eet_cflags = @evas_image_loader_eet_cflags@
318evas_image_loader_eet_libs = @evas_image_loader_eet_libs@
319evas_image_loader_generic_cflags = @evas_image_loader_generic_cflags@
320evas_image_loader_generic_libs = @evas_image_loader_generic_libs@
321evas_image_loader_gif_cflags = @evas_image_loader_gif_cflags@
322evas_image_loader_gif_libs = @evas_image_loader_gif_libs@
323evas_image_loader_ico_cflags = @evas_image_loader_ico_cflags@
324evas_image_loader_ico_libs = @evas_image_loader_ico_libs@
325evas_image_loader_jpeg_cflags = @evas_image_loader_jpeg_cflags@
326evas_image_loader_jpeg_libs = @evas_image_loader_jpeg_libs@
327evas_image_loader_pmaps_cflags = @evas_image_loader_pmaps_cflags@
328evas_image_loader_pmaps_libs = @evas_image_loader_pmaps_libs@
329evas_image_loader_png_cflags = @evas_image_loader_png_cflags@
330evas_image_loader_png_libs = @evas_image_loader_png_libs@
331evas_image_loader_psd_cflags = @evas_image_loader_psd_cflags@
332evas_image_loader_psd_libs = @evas_image_loader_psd_libs@
333evas_image_loader_svg_cflags = @evas_image_loader_svg_cflags@
334evas_image_loader_svg_libs = @evas_image_loader_svg_libs@
335evas_image_loader_tga_cflags = @evas_image_loader_tga_cflags@
336evas_image_loader_tga_libs = @evas_image_loader_tga_libs@
337evas_image_loader_tiff_cflags = @evas_image_loader_tiff_cflags@
338evas_image_loader_tiff_libs = @evas_image_loader_tiff_libs@
339evas_image_loader_wbmp_cflags = @evas_image_loader_wbmp_cflags@
340evas_image_loader_wbmp_libs = @evas_image_loader_wbmp_libs@
341evas_image_loader_xpm_cflags = @evas_image_loader_xpm_cflags@
342evas_image_loader_xpm_libs = @evas_image_loader_xpm_libs@
343exec_prefix = @exec_prefix@
344have_evas_engine_gl_x11 = @have_evas_engine_gl_x11@
345have_evas_engine_gl_xcb = @have_evas_engine_gl_xcb@
346have_evas_engine_gl_xlib = @have_evas_engine_gl_xlib@
347have_evas_engine_software_x11 = @have_evas_engine_software_x11@
348have_evas_engine_software_xcb = @have_evas_engine_software_xcb@
349have_evas_engine_software_xlib = @have_evas_engine_software_xlib@
350have_lcov = @have_lcov@
351host = @host@
352host_alias = @host_alias@
353host_cpu = @host_cpu@
354host_os = @host_os@
355host_vendor = @host_vendor@
356htmldir = @htmldir@
357includedir = @includedir@
358infodir = @infodir@
359install_sh = @install_sh@
360libdir = @libdir@
361libexecdir = @libexecdir@
362localedir = @localedir@
363localstatedir = @localstatedir@
364lt_ECHO = @lt_ECHO@
365lt_enable_auto_import = @lt_enable_auto_import@
366mandir = @mandir@
367mkdir_p = @mkdir_p@
368oldincludedir = @oldincludedir@
369pdfdir = @pdfdir@
370pkgconfig_requires_private = @pkgconfig_requires_private@
371prefix = @prefix@
372program_transform_name = @program_transform_name@
373psdir = @psdir@
374pthread_cflags = @pthread_cflags@
375pthread_libs = @pthread_libs@
376release_info = @release_info@
377requirement_evas = @requirement_evas@
378sbindir = @sbindir@
379sharedstatedir = @sharedstatedir@
380srcdir = @srcdir@
381sysconfdir = @sysconfdir@
382target_alias = @target_alias@
383top_build_prefix = @top_build_prefix@
384top_builddir = @top_builddir@
385top_srcdir = @top_srcdir@
386version_info = @version_info@
387MAINTAINERCLEANFILES = Makefile.in
388AM_CPPFLAGS = -I. -I$(top_srcdir)/src/lib \
389 -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/lib/cserve \
390 -DPACKAGE_BIN_DIR=\"$(bindir)\" \
391 -DPACKAGE_LIB_DIR=\"$(libdir)\" \
392 -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" @WIN32_CPPFLAGS@ \
393 @FREETYPE_CFLAGS@ @EET_CFLAGS@ @FONTCONFIG_CFLAGS@ \
394 @EVAS_CFLAGS@ @EINA_CFLAGS@ @EVIL_CFLAGS@ @PIXMAN_CFLAGS@ \
395 $(am__append_1)
396noinst_LTLIBRARIES = libevas_canvas.la
397libevas_canvas_la_SOURCES = \
398evas_callbacks.c \
399evas_clip.c \
400evas_data.c \
401evas_events.c \
402evas_filter.c \
403evas_focus.c \
404evas_key.c \
405evas_key_grab.c \
406evas_layer.c \
407evas_main.c \
408evas_name.c \
409evas_object_image.c \
410evas_object_main.c \
411evas_object_inform.c \
412evas_object_intercept.c \
413evas_object_line.c \
414evas_object_polygon.c \
415evas_object_rectangle.c \
416evas_object_smart.c \
417evas_object_smart_clipped.c \
418evas_object_box.c \
419evas_object_table.c \
420evas_object_text.c \
421evas_object_textblock.c \
422evas_object_grid.c \
423evas_font_dir.c \
424evas_rectangle.c \
425evas_render.c \
426evas_smart.c \
427evas_stack.c \
428evas_async_events.c \
429evas_stats.c \
430evas_touch_point.c \
431evas_map.c \
432evas_gl.c
433
434
435#evas_object_textgrid.c
436libevas_canvas_la_LIBADD = @EVAS_LIBS@ @EVIL_LIBS@ $(am__append_2)
437all: all-am
438
439.SUFFIXES:
440.SUFFIXES: .c .lo .o .obj
441$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
442 @for dep in $?; do \
443 case '$(am__configure_deps)' in \
444 *$$dep*) \
445 ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
446 && { if test -f $@; then exit 0; else break; fi; }; \
447 exit 1;; \
448 esac; \
449 done; \
450 echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/canvas/Makefile'; \
451 $(am__cd) $(top_srcdir) && \
452 $(AUTOMAKE) --gnu src/lib/canvas/Makefile
453.PRECIOUS: Makefile
454Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
455 @case '$?' in \
456 *config.status*) \
457 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
458 *) \
459 echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
460 cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
461 esac;
462
463$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
464 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
465
466$(top_srcdir)/configure: $(am__configure_deps)
467 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
468$(ACLOCAL_M4): $(am__aclocal_m4_deps)
469 cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
470$(am__aclocal_m4_deps):
471
472clean-noinstLTLIBRARIES:
473 -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
474 @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
475 dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
476 test "$$dir" != "$$p" || dir=.; \
477 echo "rm -f \"$${dir}/so_locations\""; \
478 rm -f "$${dir}/so_locations"; \
479 done
480libevas_canvas.la: $(libevas_canvas_la_OBJECTS) $(libevas_canvas_la_DEPENDENCIES)
481 $(AM_V_CCLD)$(LINK) $(libevas_canvas_la_OBJECTS) $(libevas_canvas_la_LIBADD) $(LIBS)
482
483mostlyclean-compile:
484 -rm -f *.$(OBJEXT)
485
486distclean-compile:
487 -rm -f *.tab.c
488
489@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_async_events.Plo@am__quote@
490@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_callbacks.Plo@am__quote@
491@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_clip.Plo@am__quote@
492@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_data.Plo@am__quote@
493@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_events.Plo@am__quote@
494@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_filter.Plo@am__quote@
495@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_focus.Plo@am__quote@
496@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_font_dir.Plo@am__quote@
497@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_gl.Plo@am__quote@
498@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_key.Plo@am__quote@
499@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_key_grab.Plo@am__quote@
500@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_layer.Plo@am__quote@
501@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_main.Plo@am__quote@
502@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_map.Plo@am__quote@
503@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_name.Plo@am__quote@
504@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_box.Plo@am__quote@
505@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_grid.Plo@am__quote@
506@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_image.Plo@am__quote@
507@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_inform.Plo@am__quote@
508@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_intercept.Plo@am__quote@
509@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_line.Plo@am__quote@
510@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_main.Plo@am__quote@
511@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_polygon.Plo@am__quote@
512@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_rectangle.Plo@am__quote@
513@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_smart.Plo@am__quote@
514@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_smart_clipped.Plo@am__quote@
515@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_table.Plo@am__quote@
516@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_text.Plo@am__quote@
517@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_textblock.Plo@am__quote@
518@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_rectangle.Plo@am__quote@
519@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_render.Plo@am__quote@
520@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_smart.Plo@am__quote@
521@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_stack.Plo@am__quote@
522@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_stats.Plo@am__quote@
523@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_touch_point.Plo@am__quote@
524
525.c.o:
526@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
527@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
528@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
529@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
530@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
531@am__fastdepCC_FALSE@ $(COMPILE) -c $<
532
533.c.obj:
534@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
535@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
536@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
537@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
538@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
539@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
540
541.c.lo:
542@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
543@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
544@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
545@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
546@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
547@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
548
549mostlyclean-libtool:
550 -rm -f *.lo
551
552clean-libtool:
553 -rm -rf .libs _libs
554
555ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
556 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
557 unique=`for i in $$list; do \
558 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
559 done | \
560 $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
561 END { if (nonempty) { for (i in files) print i; }; }'`; \
562 mkid -fID $$unique
563tags: TAGS
564
565TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
566 $(TAGS_FILES) $(LISP)
567 set x; \
568 here=`pwd`; \
569 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
570 unique=`for i in $$list; do \
571 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
572 done | \
573 $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
574 END { if (nonempty) { for (i in files) print i; }; }'`; \
575 shift; \
576 if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
577 test -n "$$unique" || unique=$$empty_fix; \
578 if test $$# -gt 0; then \
579 $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
580 "$$@" $$unique; \
581 else \
582 $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
583 $$unique; \
584 fi; \
585 fi
586ctags: CTAGS
587CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
588 $(TAGS_FILES) $(LISP)
589 list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
590 unique=`for i in $$list; do \
591 if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
592 done | \
593 $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
594 END { if (nonempty) { for (i in files) print i; }; }'`; \
595 test -z "$(CTAGS_ARGS)$$unique" \
596 || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
597 $$unique
598
599GTAGS:
600 here=`$(am__cd) $(top_builddir) && pwd` \
601 && $(am__cd) $(top_srcdir) \
602 && gtags -i $(GTAGS_ARGS) "$$here"
603
604distclean-tags:
605 -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
606
607distdir: $(DISTFILES)
608 @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
609 topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
610 list='$(DISTFILES)'; \
611 dist_files=`for file in $$list; do echo $$file; done | \
612 sed -e "s|^$$srcdirstrip/||;t" \
613 -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
614 case $$dist_files in \
615 */*) $(MKDIR_P) `echo "$$dist_files" | \
616 sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
617 sort -u` ;; \
618 esac; \
619 for file in $$dist_files; do \
620 if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
621 if test -d $$d/$$file; then \
622 dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
623 if test -d "$(distdir)/$$file"; then \
624 find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
625 fi; \
626 if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
627 cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
628 find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
629 fi; \
630 cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
631 else \
632 test -f "$(distdir)/$$file" \
633 || cp -p $$d/$$file "$(distdir)/$$file" \
634 || exit 1; \
635 fi; \
636 done
637check-am: all-am
638check: check-am
639all-am: Makefile $(LTLIBRARIES)
640installdirs:
641install: install-am
642install-exec: install-exec-am
643install-data: install-data-am
644uninstall: uninstall-am
645
646install-am: all-am
647 @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
648
649installcheck: installcheck-am
650install-strip:
651 $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
652 install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
653 `test -z '$(STRIP)' || \
654 echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
655mostlyclean-generic:
656
657clean-generic:
658
659distclean-generic:
660 -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
661 -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
662
663maintainer-clean-generic:
664 @echo "This command is intended for maintainers to use"
665 @echo "it deletes files that may require special tools to rebuild."
666 -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
667clean: clean-am
668
669clean-am: clean-generic clean-libtool clean-local \
670 clean-noinstLTLIBRARIES mostlyclean-am
671
672distclean: distclean-am
673 -rm -rf ./$(DEPDIR)
674 -rm -f Makefile
675distclean-am: clean-am distclean-compile distclean-generic \
676 distclean-tags
677
678dvi: dvi-am
679
680dvi-am:
681
682html: html-am
683
684html-am:
685
686info: info-am
687
688info-am:
689
690install-data-am:
691
692install-dvi: install-dvi-am
693
694install-dvi-am:
695
696install-exec-am:
697
698install-html: install-html-am
699
700install-html-am:
701
702install-info: install-info-am
703
704install-info-am:
705
706install-man:
707
708install-pdf: install-pdf-am
709
710install-pdf-am:
711
712install-ps: install-ps-am
713
714install-ps-am:
715
716installcheck-am:
717
718maintainer-clean: maintainer-clean-am
719 -rm -rf ./$(DEPDIR)
720 -rm -f Makefile
721maintainer-clean-am: distclean-am maintainer-clean-generic
722
723mostlyclean: mostlyclean-am
724
725mostlyclean-am: mostlyclean-compile mostlyclean-generic \
726 mostlyclean-libtool
727
728pdf: pdf-am
729
730pdf-am:
731
732ps: ps-am
733
734ps-am:
735
736uninstall-am:
737
738.MAKE: install-am install-strip
739
740.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
741 clean-libtool clean-local clean-noinstLTLIBRARIES ctags \
742 distclean distclean-compile distclean-generic \
743 distclean-libtool distclean-tags distdir dvi dvi-am html \
744 html-am info info-am install install-am install-data \
745 install-data-am install-dvi install-dvi-am install-exec \
746 install-exec-am install-html install-html-am install-info \
747 install-info-am install-man install-pdf install-pdf-am \
748 install-ps install-ps-am install-strip installcheck \
749 installcheck-am installdirs maintainer-clean \
750 maintainer-clean-generic mostlyclean mostlyclean-compile \
751 mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
752 tags uninstall uninstall-am
753
754
755clean-local:
756 rm -rf *.gcno
757
758# Tell versions [3.59,3.63) of GNU make to not export all variables.
759# Otherwise a system limit (for SysV at least) may be exceeded.
760.NOEXPORT:
diff --git a/libraries/evas/src/lib/canvas/evas_async_events.c b/libraries/evas/src/lib/canvas/evas_async_events.c
new file mode 100644
index 0000000..bd2e3a8
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_async_events.c
@@ -0,0 +1,173 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#ifdef BUILD_ASYNC_EVENTS
6
7# ifndef _MSC_VER
8# include <unistd.h>
9# endif
10# include <fcntl.h>
11# include <errno.h>
12
13#endif
14
15#include "evas_common.h"
16#include "evas_private.h"
17
18#ifdef BUILD_ASYNC_EVENTS
19
20static int _fd_write = -1;
21static int _fd_read = -1;
22
23static int _init_evas_event = 0;
24
25typedef struct _Evas_Event_Async Evas_Event_Async;
26
27struct _Evas_Event_Async
28{
29 const void *target;
30 void *event_info;
31 Evas_Async_Events_Put_Cb func;
32 Evas_Callback_Type type;
33};
34
35int
36evas_async_events_init(void)
37{
38 int filedes[2];
39
40 _init_evas_event++;
41 if (_init_evas_event > 1) return _init_evas_event;
42
43 if (pipe(filedes) == -1)
44 {
45 _init_evas_event = 0;
46 return 0;
47 }
48
49 _fd_read = filedes[0];
50 _fd_write = filedes[1];
51
52 fcntl(_fd_read, F_SETFL, O_NONBLOCK);
53
54 return _init_evas_event;
55}
56
57int
58evas_async_events_shutdown(void)
59{
60 _init_evas_event--;
61 if (_init_evas_event > 0) return _init_evas_event;
62
63 close(_fd_read);
64 close(_fd_write);
65 _fd_read = -1;
66 _fd_write = -1;
67
68 return _init_evas_event;
69}
70
71#endif
72
73EAPI int
74evas_async_events_fd_get(void)
75{
76#ifdef BUILD_ASYNC_EVENTS
77 return _fd_read;
78#else
79 return -1;
80#endif
81}
82
83EAPI int
84evas_async_events_process(void)
85{
86#ifdef BUILD_ASYNC_EVENTS
87 Evas_Event_Async *ev;
88 int check;
89 int count = 0;
90
91 if (_fd_read == -1) return 0;
92
93 do
94 {
95 check = read(_fd_read, &ev, sizeof (Evas_Event_Async *));
96
97 if (check == sizeof (Evas_Event_Async *))
98 {
99 if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
100 free(ev);
101 count++;
102 }
103 }
104 while (check > 0);
105
106 evas_cache_image_wakeup();
107
108 if (check < 0)
109 {
110 switch (errno)
111 {
112 case EBADF:
113 case EINVAL:
114 case EIO:
115 case EISDIR:
116 _fd_read = -1;
117 }
118 }
119
120 return count;
121#else
122 return 0;
123#endif
124}
125
126EAPI Eina_Bool
127evas_async_events_put(const void *target, Evas_Callback_Type type, void *event_info, Evas_Async_Events_Put_Cb func)
128{
129#ifdef BUILD_ASYNC_EVENTS
130 Evas_Event_Async *ev;
131 ssize_t check;
132 Eina_Bool result = EINA_FALSE;
133
134 if (!func) return 0;
135 if (_fd_write == -1) return 0;
136
137 ev = calloc(1, sizeof (Evas_Event_Async));
138 if (!ev) return 0;
139
140 ev->func = func;
141 ev->target = target;
142 ev->type = type;
143 ev->event_info = event_info;
144
145 do
146 {
147 check = write(_fd_write, &ev, sizeof (Evas_Event_Async*));
148 }
149 while ((check != sizeof (Evas_Event_Async*)) &&
150 ((errno == EINTR) || (errno == EAGAIN)));
151
152 evas_cache_image_wakeup();
153
154 if (check == sizeof (Evas_Event_Async*))
155 result = EINA_TRUE;
156 else
157 {
158 switch (errno)
159 {
160 case EBADF:
161 case EINVAL:
162 case EIO:
163 case EPIPE:
164 _fd_write = -1;
165 }
166 }
167
168 return result;
169#else
170 func((void*) target, type, event_info);
171 return EINA_TRUE;
172#endif
173}
diff --git a/libraries/evas/src/lib/canvas/evas_callbacks.c b/libraries/evas/src/lib/canvas/evas_callbacks.c
new file mode 100644
index 0000000..33b93bc
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_callbacks.c
@@ -0,0 +1,534 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4static void evas_object_event_callback_clear(Evas_Object *obj);
5static void evas_event_callback_clear(Evas *e);
6int _evas_event_counter = 0;
7
8EVAS_MEMPOOL(_mp_fn);
9EVAS_MEMPOOL(_mp_cb);
10EVAS_MEMPOOL(_mp_pc);
11
12void
13_evas_post_event_callback_call(Evas *e)
14{
15 Evas_Post_Callback *pc;
16 int skip = 0;
17
18 if (e->delete_me) return;
19 _evas_walk(e);
20 EINA_LIST_FREE(e->post_events, pc)
21 {
22 if ((!skip) && (!e->delete_me) && (!pc->delete_me))
23 {
24 if (!pc->func((void*)pc->data, e)) skip = 1;
25 }
26 EVAS_MEMPOOL_FREE(_mp_pc, pc);
27 }
28 _evas_unwalk(e);
29}
30
31void
32_evas_post_event_callback_free(Evas *e)
33{
34 Evas_Post_Callback *pc;
35
36 EINA_LIST_FREE(e->post_events, pc)
37 {
38 EVAS_MEMPOOL_FREE(_mp_pc, pc);
39 }
40 _evas_unwalk(e);
41}
42
43void
44evas_event_callback_list_post_free(Eina_Inlist **list)
45{
46 Eina_Inlist *l;
47
48 /* MEM OK */
49 for (l = *list; l;)
50 {
51 Evas_Func_Node *fn;
52
53 fn = (Evas_Func_Node *)l;
54 l = l->next;
55 if (fn->delete_me)
56 {
57 *list = eina_inlist_remove(*list, EINA_INLIST_GET(fn));
58 EVAS_MEMPOOL_FREE(_mp_fn, fn);
59 }
60 }
61}
62
63static void
64evas_object_event_callback_clear(Evas_Object *obj)
65{
66 if (!obj->callbacks) return;
67 if (!obj->callbacks->deletions_waiting) return;
68 obj->callbacks->deletions_waiting = 0;
69 evas_event_callback_list_post_free(&obj->callbacks->callbacks);
70 if (!obj->callbacks->callbacks)
71 {
72 EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks);
73 obj->callbacks = NULL;
74 }
75}
76
77static void
78evas_event_callback_clear(Evas *e)
79{
80 if (!e->callbacks) return;
81 if (!e->callbacks->deletions_waiting) return;
82 e->callbacks->deletions_waiting = 0;
83 evas_event_callback_list_post_free(&e->callbacks->callbacks);
84 if (!e->callbacks->callbacks)
85 {
86 EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks);
87 e->callbacks = NULL;
88 }
89}
90
91void
92evas_object_event_callback_all_del(Evas_Object *obj)
93{
94 Evas_Func_Node *fn;
95
96 if (!obj->callbacks) return;
97 EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
98 fn->delete_me = 1;
99}
100
101void
102evas_object_event_callback_cleanup(Evas_Object *obj)
103{
104 /* MEM OK */
105 if (!obj->callbacks) return;
106 evas_event_callback_list_post_free(&obj->callbacks->callbacks);
107 EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks);
108 obj->callbacks = NULL;
109}
110
111void
112evas_event_callback_all_del(Evas *e)
113{
114 Evas_Func_Node *fn;
115
116 if (!e->callbacks) return;
117 EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
118 fn->delete_me = 1;
119}
120
121void
122evas_event_callback_cleanup(Evas *e)
123{
124 /* MEM OK */
125 if (!e->callbacks) return;
126 evas_event_callback_list_post_free(&e->callbacks->callbacks);
127 EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks);
128 e->callbacks = NULL;
129}
130
131void
132evas_event_callback_call(Evas *e, Evas_Callback_Type type, void *event_info)
133{
134 Eina_Inlist **l_mod = NULL, *l;
135
136 _evas_walk(e);
137 if (e->callbacks)
138 {
139 l_mod = &e->callbacks->callbacks;
140 e->callbacks->walking_list++;
141 for (l = *l_mod; l; l = l->next)
142 {
143 Evas_Func_Node *fn;
144
145 fn = (Evas_Func_Node *)l;
146 if ((fn->type == type) && (!fn->delete_me))
147 {
148 Evas_Event_Cb func = fn->func;
149 if (func)
150 func(fn->data, e, event_info);
151 }
152 if (e->delete_me) break;
153 }
154 e->callbacks->walking_list--;
155 if (!e->callbacks->walking_list)
156 {
157 evas_event_callback_clear(e);
158 l_mod = NULL;
159 }
160 }
161 _evas_unwalk(e);
162}
163
164void
165evas_object_event_callback_call(Evas_Object *obj, Evas_Callback_Type type, void *event_info)
166{
167 /* MEM OK */
168 Eina_Inlist **l_mod = NULL, *l;
169 Evas_Button_Flags flags = EVAS_BUTTON_NONE;
170 Evas *e;
171
172 if ((obj->delete_me) || (!obj->layer)) return;
173 if ((obj->last_event == _evas_event_counter) &&
174 (obj->last_event_type == type)) return;
175 obj->last_event = _evas_event_counter;
176 obj->last_event_type = type;
177 if (!(e = obj->layer->evas)) return;
178
179 _evas_walk(e);
180 if (obj->callbacks)
181 {
182 l_mod = &obj->callbacks->callbacks;
183 switch (type)
184 {
185 case EVAS_CALLBACK_MOUSE_DOWN:
186 {
187 Evas_Event_Mouse_Down *ev = event_info;
188
189 flags = ev->flags;
190 if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK))
191 {
192 if (obj->last_mouse_down_counter < (e->last_mouse_down_counter - 1))
193 ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK);
194 }
195 obj->last_mouse_down_counter = e->last_mouse_down_counter;
196 break;
197 }
198 case EVAS_CALLBACK_MOUSE_UP:
199 {
200 Evas_Event_Mouse_Up *ev = event_info;
201
202 flags = ev->flags;
203 if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK))
204 {
205 if (obj->last_mouse_up_counter < (e->last_mouse_up_counter - 1))
206 ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK);
207 }
208 obj->last_mouse_up_counter = e->last_mouse_up_counter;
209 break;
210 }
211 default:
212 break;
213 }
214 obj->callbacks->walking_list++;
215 for (l = *l_mod; l; l = l->next)
216 {
217 Evas_Func_Node *fn;
218
219 fn = (Evas_Func_Node *)l;
220 if ((fn->type == type) && (!fn->delete_me))
221 {
222 Evas_Object_Event_Cb func = fn->func;
223 if (func)
224 func(fn->data, obj->layer->evas, obj, event_info);
225 }
226 if (obj->delete_me) break;
227 }
228 obj->callbacks->walking_list--;
229 if (!obj->callbacks->walking_list)
230 {
231 evas_object_event_callback_clear(obj);
232 l_mod = NULL;
233 }
234
235 if (type == EVAS_CALLBACK_MOUSE_DOWN)
236 {
237 Evas_Event_Mouse_Down *ev = event_info;
238 ev->flags = flags;
239 }
240 else if (type == EVAS_CALLBACK_MOUSE_UP)
241 {
242 Evas_Event_Mouse_Up *ev = event_info;
243 ev->flags = flags;
244 }
245 }
246
247 if (!((obj->no_propagate) && (l_mod) && (*l_mod)))
248 {
249 if (!obj->no_propagate)
250 {
251 if ((obj->smart.parent) && (type != EVAS_CALLBACK_FREE) &&
252 (type <= EVAS_CALLBACK_KEY_UP))
253 evas_object_event_callback_call(obj->smart.parent, type, event_info);
254 }
255 }
256 _evas_unwalk(e);
257}
258
259static int
260_callback_priority_cmp(const void *_a, const void *_b)
261{
262 const Evas_Func_Node *a, *b;
263 a = EINA_INLIST_CONTAINER_GET(_a, Evas_Func_Node);
264 b = EINA_INLIST_CONTAINER_GET(_b, Evas_Func_Node);
265 if (a->priority < b->priority)
266 return -1;
267 else
268 return 1;
269}
270
271EAPI void
272evas_object_event_callback_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
273{
274 evas_object_event_callback_priority_add(obj, type,
275 EVAS_CALLBACK_PRIORITY_DEFAULT, func, data);
276}
277
278EAPI void
279evas_object_event_callback_priority_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Object_Event_Cb func, const void *data)
280{
281 /* MEM OK */
282 Evas_Func_Node *fn;
283
284 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
285 return;
286 MAGIC_CHECK_END();
287
288 if (!func) return;
289
290 if (!obj->callbacks)
291 {
292 EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 512, );
293 obj->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks);
294 if (!obj->callbacks) return;
295 EVAS_MEMPOOL_PREP(_mp_cb, obj->callbacks, Evas_Callbacks);
296 }
297
298 EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 2048, );
299 fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node);
300 if (!fn) return;
301 EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node);
302 fn->func = func;
303 fn->data = (void *)data;
304 fn->type = type;
305 fn->priority = priority;
306
307 obj->callbacks->callbacks =
308 eina_inlist_sorted_insert(obj->callbacks->callbacks, EINA_INLIST_GET(fn),
309 _callback_priority_cmp);
310}
311
312EAPI void *
313evas_object_event_callback_del(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func)
314{
315 /* MEM OK */
316 Evas_Func_Node *fn;
317
318 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
319 return NULL;
320 MAGIC_CHECK_END();
321
322 if (!func) return NULL;
323
324 if (!obj->callbacks) return NULL;
325
326 EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
327 {
328 if ((fn->func == func) && (fn->type == type) && (!fn->delete_me))
329 {
330 void *tmp;
331
332 tmp = fn->data;
333 fn->delete_me = 1;
334 obj->callbacks->deletions_waiting = 1;
335 if (!obj->callbacks->walking_list)
336 evas_object_event_callback_clear(obj);
337 return tmp;
338 }
339 }
340 return NULL;
341}
342
343EAPI void *
344evas_object_event_callback_del_full(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
345{
346 /* MEM OK */
347 Evas_Func_Node *fn;
348
349 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
350 return NULL;
351 MAGIC_CHECK_END();
352
353 if (!func) return NULL;
354
355 if (!obj->callbacks) return NULL;
356
357 EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn)
358 {
359 if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me))
360 {
361 void *tmp;
362
363 tmp = fn->data;
364 fn->delete_me = 1;
365 obj->callbacks->deletions_waiting = 1;
366 if (!obj->callbacks->walking_list)
367 evas_object_event_callback_clear(obj);
368 return tmp;
369 }
370 }
371 return NULL;
372}
373
374EAPI void
375evas_event_callback_add(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
376{
377 evas_event_callback_priority_add(e, type, EVAS_CALLBACK_PRIORITY_DEFAULT,
378 func, data);
379}
380
381EAPI void
382evas_event_callback_priority_add(Evas *e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data)
383{
384 /* MEM OK */
385 Evas_Func_Node *fn;
386
387 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
388 return;
389 MAGIC_CHECK_END();
390
391 if (!func) return;
392
393 if (!e->callbacks)
394 {
395 EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 512, );
396 e->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks);
397 if (!e->callbacks) return;
398 EVAS_MEMPOOL_PREP(_mp_cb, e->callbacks, Evas_Callbacks);
399 }
400
401 EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 2048, );
402 fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node);
403 if (!fn) return;
404 EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node);
405 fn->func = func;
406 fn->data = (void *)data;
407 fn->type = type;
408 fn->priority = priority;
409
410 e->callbacks->callbacks = eina_inlist_sorted_insert(e->callbacks->callbacks,
411 EINA_INLIST_GET(fn), _callback_priority_cmp);
412}
413
414EAPI void *
415evas_event_callback_del(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func)
416{
417 /* MEM OK */
418 Evas_Func_Node *fn;
419
420 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
421 return NULL;
422 MAGIC_CHECK_END();
423
424 if (!func) return NULL;
425
426 if (!e->callbacks) return NULL;
427
428 EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
429 {
430 if ((fn->func == func) && (fn->type == type) && (!fn->delete_me))
431 {
432 void *data;
433
434 data = fn->data;
435 fn->delete_me = 1;
436 e->callbacks->deletions_waiting = 1;
437 if (!e->callbacks->walking_list)
438 evas_event_callback_clear(e);
439 return data;
440 }
441 }
442 return NULL;
443}
444
445EAPI void *
446evas_event_callback_del_full(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data)
447{
448 /* MEM OK */
449 Evas_Func_Node *fn;
450
451 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
452 return NULL;
453 MAGIC_CHECK_END();
454
455 if (!func) return NULL;
456
457 if (!e->callbacks) return NULL;
458
459 EINA_INLIST_FOREACH(e->callbacks->callbacks, fn)
460 {
461 if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me))
462 {
463 void *tmp;
464
465 tmp = fn->data;
466 fn->delete_me = 1;
467 e->callbacks->deletions_waiting = 1;
468 if (!e->callbacks->walking_list)
469 evas_event_callback_clear(e);
470 return tmp;
471 }
472 }
473 return NULL;
474}
475
476EAPI void
477evas_post_event_callback_push(Evas *e, Evas_Object_Event_Post_Cb func, const void *data)
478{
479 Evas_Post_Callback *pc;
480
481 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
482 return;
483 MAGIC_CHECK_END();
484
485 EVAS_MEMPOOL_INIT(_mp_pc, "evas_post_callback", Evas_Post_Callback, 64, );
486 pc = EVAS_MEMPOOL_ALLOC(_mp_pc, Evas_Post_Callback);
487 if (!pc) return;
488 EVAS_MEMPOOL_PREP(_mp_pc, pc, Evas_Post_Callback);
489 if (e->delete_me) return;
490
491 pc->func = func;
492 pc->data = data;
493 e->post_events = eina_list_prepend(e->post_events, pc);
494}
495
496EAPI void
497evas_post_event_callback_remove(Evas *e, Evas_Object_Event_Post_Cb func)
498{
499 Evas_Post_Callback *pc;
500 Eina_List *l;
501
502 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
503 return;
504 MAGIC_CHECK_END();
505
506 EINA_LIST_FOREACH(e->post_events, l, pc)
507 {
508 if (pc->func == func)
509 {
510 pc->delete_me = 1;
511 return;
512 }
513 }
514}
515
516EAPI void
517evas_post_event_callback_remove_full(Evas *e, Evas_Object_Event_Post_Cb func, const void *data)
518{
519 Evas_Post_Callback *pc;
520 Eina_List *l;
521
522 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
523 return;
524 MAGIC_CHECK_END();
525
526 EINA_LIST_FOREACH(e->post_events, l, pc)
527 {
528 if ((pc->func == func) && (pc->data == data))
529 {
530 pc->delete_me = 1;
531 return;
532 }
533 }
534}
diff --git a/libraries/evas/src/lib/canvas/evas_clip.c b/libraries/evas/src/lib/canvas/evas_clip.c
new file mode 100644
index 0000000..1ae2f73
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_clip.c
@@ -0,0 +1,321 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4void
5evas_object_clip_dirty(Evas_Object *obj)
6{
7 Eina_List *l;
8 Evas_Object *data;
9
10 if (obj->cur.cache.clip.dirty) return ;
11
12 obj->cur.cache.clip.dirty = 1;
13 EINA_LIST_FOREACH(obj->clip.clipees, l, data)
14 evas_object_clip_dirty(data);
15}
16
17void
18evas_object_recalc_clippees(Evas_Object *obj)
19{
20 Eina_List *l;
21 Evas_Object *data;
22
23 if (obj->cur.cache.clip.dirty)
24 {
25 evas_object_clip_recalc(obj);
26 EINA_LIST_FOREACH(obj->clip.clipees, l, data)
27 evas_object_recalc_clippees(data);
28 }
29}
30
31int
32evas_object_clippers_was_visible(Evas_Object *obj)
33{
34 if (obj->prev.visible)
35 {
36 if (obj->prev.clipper)
37 return evas_object_clippers_is_visible(obj->prev.clipper);
38 return 1;
39 }
40 return 0;
41}
42
43/* aaaaargh (pirate voice) ... notes!
44 *
45 * we have a big problem until now that's gone undetected... until yesterday.
46 * that problem involves clips and maps and smart objects. hooray! 3 of the
47 * more complex bits of evas - and maps and smart objects being one of the
48 * nastiest ones.
49 *
50 * what is the problem? when a clip crosses a map boundary. that is to say
51 * that when the clipper and clippee are not within the child tree of the
52 * mapped object. in this case "bad stuff" happens. basically as clips are
53 * then used to render objects, but they no longer apply as you'd expect as
54 * the map transfomr the objects to-be-clipped separately from the objects
55 * that clip them and this whole relationship is broken by maps. it somehow
56 * managed to not break with the advent of smart objects. lucky me... but
57 * maps killed it. now... what do we do? that is a good question. detect
58 * such a broken link and "turn off clipping" in that event - sure. but this
59 * isn't going to be cheap as ANY addition or deletion of a map to an object
60 * or any change in clipper of an object or any change in smart object
61 * membership needs to walk the obj tree both up and down from the changed
62 * object and probably walk entire object trees to find these and mark them.
63 * thats silly-expensive and i was about to fix it that way but it has since
64 * dawned on me that that is just going to kill performance in some critical
65 * areas like during object setup and manipulation, as well as teardown.
66 *
67 * aaaaagh! best for now is to document this as a "don't do it damnit!" thing
68 * and have the apps avoid it. but even then - how to do this? this is not
69 * easy. everywhere i turn so far i come up to either expensive operations,
70 * breaks in logic, or nasty re-work of apps or4 the whole concept of clipping,
71 * smart objects and maps... and that will have to wait for evas 2.0
72 *
73 * the below does clip fixups etc. in the even a clip spans a map boundary.
74 * not pretty, but necessary.
75 */
76
77#define MAP_ACROSS 1
78static void
79evas_object_child_map_across_mark(Evas_Object *obj, Evas_Object *map_obj, Eina_Bool force)
80{
81#ifdef MAP_ACROSS
82 if ((obj->cur.map_parent != map_obj) || force)
83 {
84 obj->cur.map_parent = map_obj;
85 obj->cur.cache.clip.dirty = 1;
86 evas_object_clip_recalc(obj);
87 if (obj->smart.smart)
88 {
89 Evas_Object *obj2;
90
91 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
92 {
93 // if obj has its own map - skip it. already done
94 if ((obj2->cur.map) && (obj2->cur.usemap)) continue;
95 evas_object_child_map_across_mark(obj2, map_obj, force);
96 }
97 }
98 else if (obj->clip.clipees)
99 {
100 Eina_List *l;
101 Evas_Object *obj2;
102
103 EINA_LIST_FOREACH(obj->clip.clipees, l, obj2)
104 evas_object_child_map_across_mark(obj2, map_obj, force);
105 }
106 }
107#endif
108}
109
110void
111evas_object_clip_across_check(Evas_Object *obj)
112{
113#ifdef MAP_ACROSS
114 if (!obj->cur.clipper) return;
115 if (obj->cur.clipper->cur.map_parent != obj->cur.map_parent)
116 evas_object_child_map_across_mark(obj, obj->cur.map_parent, 1);
117#endif
118}
119
120void
121evas_object_clip_across_clippees_check(Evas_Object *obj)
122{
123#ifdef MAP_ACROSS
124 Eina_List *l;
125 Evas_Object *obj2;
126
127 if (!obj->clip.clipees) return;
128// schloooooooooooow:
129// evas_object_child_map_across_mark(obj, obj->cur.map_parent, 1);
130// buggy:
131 evas_object_child_map_across_mark(obj, obj->cur.map_parent, 0);
132 if (obj->cur.cache.clip.dirty)
133 {
134 EINA_LIST_FOREACH(obj->clip.clipees, l, obj2)
135 evas_object_clip_across_clippees_check(obj2);
136 }
137#endif
138}
139
140// this function is called on an object when map is enabled or disabled on it
141// thus creating a "map boundary" at that point.
142//
143// FIXME: flip2 test broken in elm - might be show/hide of clips
144void
145evas_object_mapped_clip_across_mark(Evas_Object *obj)
146{
147#ifdef MAP_ACROSS
148 if ((obj->cur.map) && (obj->cur.usemap))
149 evas_object_child_map_across_mark(obj, obj, 0);
150 else
151 {
152 if (obj->smart.parent)
153 evas_object_child_map_across_mark
154 (obj, obj->smart.parent->cur.map_parent, 0);
155 else
156 evas_object_child_map_across_mark(obj, NULL, 0);
157 }
158#endif
159}
160
161/* public functions */
162extern const char *o_rect_type;
163
164EAPI void
165evas_object_clip_set(Evas_Object *obj, Evas_Object *clip)
166{
167 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
168 return;
169 MAGIC_CHECK_END();
170 if (!clip)
171 {
172 evas_object_clip_unset(obj);
173 return;
174 }
175 MAGIC_CHECK(clip, Evas_Object, MAGIC_OBJ);
176 return;
177 MAGIC_CHECK_END();
178 if (obj->cur.clipper == clip) return;
179 if (obj == clip) return;
180 if (evas_object_intercept_call_clip_set(obj, clip)) return;
181 // illegal to set anything but a rect as a clip
182 if (clip->type != o_rect_type)
183 {
184 ERR("For now a clip on other object than a rectangle is disabled");
185 return;
186 }
187 if (obj->smart.smart)
188 {
189 if (obj->smart.smart->smart_class->clip_set)
190 obj->smart.smart->smart_class->clip_set(obj, clip);
191 }
192 if (obj->cur.clipper)
193 {
194 /* unclip */
195 obj->cur.clipper->clip.clipees = eina_list_remove(obj->cur.clipper->clip.clipees, obj);
196 if (!obj->cur.clipper->clip.clipees)
197 {
198 obj->cur.clipper->cur.have_clipees = 0;
199 if (obj->cur.clipper->cur.visible)
200 evas_damage_rectangle_add(obj->cur.clipper->layer->evas,
201 obj->cur.clipper->cur.geometry.x,
202 obj->cur.clipper->cur.geometry.y,
203 obj->cur.clipper->cur.geometry.w,
204 obj->cur.clipper->cur.geometry.h);
205 }
206 evas_object_change(obj->cur.clipper);
207 evas_object_change(obj);
208 obj->cur.clipper = NULL;
209 }
210 /* clip me */
211 if ((!clip->clip.clipees) && (clip->cur.visible))
212 {
213 /* Basically it just went invisible */
214 clip->changed = 1;
215 clip->layer->evas->changed = 1;
216 evas_damage_rectangle_add(clip->layer->evas,
217 clip->cur.geometry.x, clip->cur.geometry.y,
218 clip->cur.geometry.w, clip->cur.geometry.h);
219 }
220 obj->cur.clipper = clip;
221 clip->clip.clipees = eina_list_append(clip->clip.clipees, obj);
222 if (clip->clip.clipees) clip->cur.have_clipees = 1;
223
224 /* If it's NOT a rectangle set the mask bits too */
225 /* FIXME: Optmz ths chck */
226 if (strcmp(evas_object_type_get(clip),"rectangle") == 0)
227 obj->cur.mask = NULL;
228 else
229 {
230 void *engdata;
231 obj->cur.mask = clip;
232 engdata = clip->func->engine_data_get(clip);
233 /* FIXME: Images only */
234 clip->layer->evas->engine.func->image_mask_create(
235 clip->layer->evas->engine.data.output,
236 engdata);
237 }
238 evas_object_change(clip);
239 evas_object_change(obj);
240 evas_object_clip_dirty(obj);
241 evas_object_recalc_clippees(obj);
242 if ((!obj->smart.smart) &&
243 (!((obj->cur.map) && (obj->cur.usemap))))
244 {
245 if (evas_object_is_in_output_rect(obj,
246 obj->layer->evas->pointer.x,
247 obj->layer->evas->pointer.y, 1, 1))
248 evas_event_feed_mouse_move(obj->layer->evas,
249 obj->layer->evas->pointer.x,
250 obj->layer->evas->pointer.y,
251 obj->layer->evas->last_timestamp,
252 NULL);
253 }
254 evas_object_clip_across_check(obj);
255}
256
257EAPI Evas_Object *
258evas_object_clip_get(const Evas_Object *obj)
259{
260 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
261 return NULL;
262 MAGIC_CHECK_END();
263 return obj->cur.clipper;
264}
265
266EAPI void
267evas_object_clip_unset(Evas_Object *obj)
268{
269 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
270 return;
271 MAGIC_CHECK_END();
272 if (!obj->cur.clipper) return;
273 /* unclip */
274 if (evas_object_intercept_call_clip_unset(obj)) return;
275 if (obj->smart.smart)
276 {
277 if (obj->smart.smart->smart_class->clip_unset)
278 obj->smart.smart->smart_class->clip_unset(obj);
279 }
280 if (obj->cur.clipper)
281 {
282 obj->cur.clipper->clip.clipees = eina_list_remove(obj->cur.clipper->clip.clipees, obj);
283 if (!obj->cur.clipper->clip.clipees)
284 {
285 obj->cur.clipper->cur.have_clipees = 0;
286 if (obj->cur.clipper->cur.visible)
287 evas_damage_rectangle_add(obj->cur.clipper->layer->evas,
288 obj->cur.clipper->cur.geometry.x,
289 obj->cur.clipper->cur.geometry.y,
290 obj->cur.clipper->cur.geometry.w,
291 obj->cur.clipper->cur.geometry.h);
292 }
293 evas_object_change(obj->cur.clipper);
294 }
295 obj->cur.clipper = NULL;
296 evas_object_change(obj);
297 evas_object_clip_dirty(obj);
298 evas_object_recalc_clippees(obj);
299 if ((!obj->smart.smart) &&
300 (!((obj->cur.map) && (obj->cur.usemap))))
301 {
302 if (evas_object_is_in_output_rect(obj,
303 obj->layer->evas->pointer.x,
304 obj->layer->evas->pointer.y, 1, 1))
305 evas_event_feed_mouse_move(obj->layer->evas,
306 obj->layer->evas->pointer.x,
307 obj->layer->evas->pointer.y,
308 obj->layer->evas->last_timestamp,
309 NULL);
310 }
311 evas_object_clip_across_check(obj);
312}
313
314EAPI const Eina_List *
315evas_object_clipees_get(const Evas_Object *obj)
316{
317 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
318 return NULL;
319 MAGIC_CHECK_END();
320 return obj->clip.clipees;
321}
diff --git a/libraries/evas/src/lib/canvas/evas_data.c b/libraries/evas/src/lib/canvas/evas_data.c
new file mode 100644
index 0000000..3ac9d63
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_data.c
@@ -0,0 +1,72 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4
5EAPI void
6evas_object_data_set(Evas_Object *obj, const char *key, const void *data)
7{
8 Evas_Data_Node *node;
9
10 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
11 return;
12 MAGIC_CHECK_END();
13 if (!key) return;
14
15 evas_object_data_del(obj, key);
16 if (!data) return;
17 node = malloc(sizeof(Evas_Data_Node) + strlen(key) + 1);
18 node->key = (char *)node + sizeof(Evas_Data_Node);
19 strcpy(node->key, key);
20 node->data = (void *)data;
21 obj->data.elements = eina_list_prepend(obj->data.elements, node);
22}
23
24EAPI void *
25evas_object_data_get(const Evas_Object *obj, const char *key)
26{
27 Eina_List *l;
28 Evas_Data_Node *node;
29
30 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
31 return NULL;
32 MAGIC_CHECK_END();
33 if (!key) return NULL;
34
35 EINA_LIST_FOREACH(obj->data.elements, l, node)
36 {
37 if (!strcmp(node->key, key))
38 {
39 Eina_List *lst;
40 lst = obj->data.elements;
41 lst = eina_list_promote_list(lst, l);
42 ((Evas_Object *)obj)->data.elements = lst;
43 return node->data;
44 }
45 }
46 return NULL;
47}
48
49EAPI void *
50evas_object_data_del(Evas_Object *obj, const char *key)
51{
52 Eina_List *l;
53 Evas_Data_Node *node;
54
55 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
56 return NULL;
57 MAGIC_CHECK_END();
58 if (!key) return NULL;
59 EINA_LIST_FOREACH(obj->data.elements, l, node)
60 {
61 if (!strcmp(node->key, key))
62 {
63 void *data;
64
65 data = node->data;
66 obj->data.elements = eina_list_remove_list(obj->data.elements, l);
67 free(node);
68 return data;
69 }
70 }
71 return NULL;
72}
diff --git a/libraries/evas/src/lib/canvas/evas_events.c b/libraries/evas/src/lib/canvas/evas_events.c
new file mode 100644
index 0000000..99ecf8c
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_events.c
@@ -0,0 +1,1602 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4static void
5_evas_event_havemap_adjust(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Eina_Bool mouse_grabbed)
6{
7 if (obj->smart.parent)
8 _evas_event_havemap_adjust(obj->smart.parent, x, y, mouse_grabbed);
9
10 if ((!obj->cur.usemap) || (!obj->cur.map) || (!obj->cur.map->count == 4))
11 return;
12
13 evas_map_coords_get(obj->cur.map, *x, *y, x, y, mouse_grabbed);
14 *x += obj->cur.geometry.x;
15 *y += obj->cur.geometry.y;
16}
17
18static Eina_List *
19_evas_event_object_list_in_get(Evas *e, Eina_List *in,
20 const Eina_Inlist *list, Evas_Object *stop,
21 int x, int y, int *no_rep)
22{
23 Evas_Object *obj;
24 if (!list) return in;
25 EINA_INLIST_REVERSE_FOREACH(list, obj)
26 {
27 if (obj == stop)
28 {
29 *no_rep = 1;
30 return in;
31 }
32 if (evas_event_passes_through(obj)) continue;
33 if ((obj->cur.visible) && (obj->delete_me == 0) &&
34 (!obj->clip.clipees) &&
35 (evas_object_clippers_is_visible(obj)))
36 {
37 if (obj->smart.smart)
38 {
39 int norep = 0;
40 int inside;
41
42 if (((obj->cur.usemap) && (obj->cur.map) && (obj->cur.map->count == 4)))
43 {
44 inside = evas_object_is_in_output_rect(obj, x, y, 1, 1);
45 if (inside)
46 {
47 if (!evas_map_coords_get(obj->cur.map, x, y,
48 &(obj->cur.map->mx),
49 &(obj->cur.map->my), 0))
50 {
51 inside = 0;
52 }
53 else
54 {
55 in = _evas_event_object_list_in_get
56 (e, in,
57 evas_object_smart_members_get_direct(obj),
58 stop,
59 obj->cur.geometry.x + obj->cur.map->mx,
60 obj->cur.geometry.y + obj->cur.map->my, &norep);
61 }
62 }
63 }
64 else
65 {
66 in = _evas_event_object_list_in_get
67 (e, in, evas_object_smart_members_get_direct(obj),
68 stop, x, y, &norep);
69 }
70 if (norep)
71 {
72 if (!obj->repeat_events) *no_rep = 1;
73 return in;
74 }
75 }
76 else
77 {
78 int inside = evas_object_is_in_output_rect(obj, x, y, 1, 1);
79
80 if (((obj->cur.usemap) && (obj->cur.map) && (obj->cur.map->count == 4)))
81 {
82 if ((inside) && (!evas_map_coords_get(obj->cur.map, x, y,
83 &(obj->cur.map->mx),
84 &(obj->cur.map->my), 0)))
85 {
86 inside = 0;
87 }
88 }
89
90 if (inside && ((!obj->precise_is_inside) ||
91 (evas_object_is_inside(obj, x, y))))
92 {
93 if (!evas_event_freezes_through(obj))
94 in = eina_list_append(in, obj);
95 if (!obj->repeat_events)
96 {
97 *no_rep = 1;
98 return in;
99 }
100 }
101 }
102 }
103 }
104 *no_rep = 0;
105 return in;
106}
107
108Eina_List *
109evas_event_objects_event_list(Evas *e, Evas_Object *stop, int x, int y)
110{
111 Evas_Layer *lay;
112 Eina_List *in = NULL;
113
114 if ((!e->layers) || (e->events_frozen > 0)) return NULL;
115 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay)
116 {
117 int norep = 0;
118 in = _evas_event_object_list_in_get(e, in,
119 EINA_INLIST_GET(lay->objects),
120 stop, x, y, &norep);
121 if (norep) return in;
122 }
123 return in;
124}
125
126static Eina_List *
127evas_event_list_copy(Eina_List *list)
128{
129 Eina_List *l, *new_l = NULL;
130 const void *data;
131
132 EINA_LIST_FOREACH(list, l, data)
133 new_l = eina_list_append(new_l, data);
134 return new_l;
135}
136/* public functions */
137
138EAPI void
139evas_event_freeze(Evas *e)
140{
141 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
142 return;
143 MAGIC_CHECK_END();
144 e->events_frozen++;
145}
146
147EAPI void
148evas_event_thaw(Evas *e)
149{
150 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
151 return;
152 MAGIC_CHECK_END();
153 e->events_frozen--;
154 if (e->events_frozen == 0)
155 {
156 Evas_Layer *lay;
157
158 EINA_INLIST_FOREACH((EINA_INLIST_GET(e->layers)), lay)
159 {
160 Evas_Object *obj;
161
162 EINA_INLIST_FOREACH(lay->objects, obj)
163 {
164 evas_object_clip_recalc(obj);
165 evas_object_recalc_clippees(obj);
166 }
167 }
168 }
169 if (e->events_frozen < 0)
170 evas_debug_generic(" Thaw of events when already thawed!!!\n");
171}
172
173EAPI int
174evas_event_freeze_get(const Evas *e)
175{
176 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
177 return 0;
178 MAGIC_CHECK_END();
179 return e->events_frozen;
180}
181
182EAPI void
183evas_event_thaw_eval(Evas *e)
184{
185 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
186 return;
187 MAGIC_CHECK_END();
188 if (e->events_frozen != 0) return;
189
190 evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y,
191 e->last_timestamp, NULL);
192}
193
194EAPI void
195evas_event_feed_mouse_down(Evas *e, int b, Evas_Button_Flags flags, unsigned int timestamp, const void *data)
196{
197 Eina_List *l, *copy;
198 Evas_Event_Mouse_Down ev;
199 Evas_Object *obj;
200
201 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
202 return;
203 MAGIC_CHECK_END();
204
205 if ((b < 1) || (b > 32)) return;
206
207 e->pointer.button |= (1 << (b - 1));
208
209 if (e->events_frozen > 0) return;
210 e->last_timestamp = timestamp;
211
212 _evas_object_event_new();
213
214 ev.button = b;
215 ev.output.x = e->pointer.x;
216 ev.output.y = e->pointer.y;
217 ev.canvas.x = e->pointer.x;
218 ev.canvas.y = e->pointer.y;
219 ev.data = (void *)data;
220 ev.modifiers = &(e->modifiers);
221 ev.locks = &(e->locks);
222 ev.flags = flags;
223 ev.timestamp = timestamp;
224 ev.event_flags = EVAS_EVENT_FLAG_NONE;
225
226 _evas_walk(e);
227 /* append new touch point to the touch point list */
228 _evas_touch_point_append(e, 0, e->pointer.x, e->pointer.y);
229 /* If this is the first finger down, i.e no other fingers pressed,
230 * get a new event list, otherwise, keep the current grabbed list. */
231 if (e->pointer.mouse_grabbed == 0)
232 {
233 Eina_List *ins = evas_event_objects_event_list(e,
234 NULL,
235 e->pointer.x,
236 e->pointer.y);
237 /* free our old list of ins */
238 e->pointer.object.in = eina_list_free(e->pointer.object.in);
239 /* and set up the new one */
240 e->pointer.object.in = ins;
241 }
242 copy = evas_event_list_copy(e->pointer.object.in);
243 EINA_LIST_FOREACH(copy, l, obj)
244 {
245 if (obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB)
246 {
247 obj->mouse_grabbed++;
248 e->pointer.mouse_grabbed++;
249 }
250 }
251 EINA_LIST_FOREACH(copy, l, obj)
252 {
253 if (obj->delete_me) continue;
254 ev.canvas.x = e->pointer.x;
255 ev.canvas.y = e->pointer.y;
256 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
257
258 if (e->events_frozen <= 0)
259 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_DOWN, &ev);
260 if (e->delete_me) break;
261 }
262 if (copy) eina_list_free(copy);
263 e->last_mouse_down_counter++;
264 _evas_post_event_callback_call(e);
265 /* update touch point's state to EVAS_TOUCH_POINT_STILL */
266 _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_STILL);
267 _evas_unwalk(e);
268}
269
270static int
271_post_up_handle(Evas *e, unsigned int timestamp, const void *data)
272{
273 Eina_List *l, *copy, *ins, *ll;
274 Evas_Event_Mouse_Out ev;
275 Evas_Object *obj;
276 int post_called = 0;
277
278 _evas_object_event_new();
279
280 ev.buttons = e->pointer.button;
281 ev.output.x = e->pointer.x;
282 ev.output.y = e->pointer.y;
283 ev.canvas.x = e->pointer.x;
284 ev.canvas.y = e->pointer.y;
285 ev.data = (void *)data;
286 ev.modifiers = &(e->modifiers);
287 ev.locks = &(e->locks);
288 ev.timestamp = timestamp;
289 ev.event_flags = EVAS_EVENT_FLAG_NONE;
290
291 /* get new list of ins */
292 ins = evas_event_objects_event_list(e, NULL, e->pointer.x, e->pointer.y);
293 /* go thru old list of in objects */
294 copy = evas_event_list_copy(e->pointer.object.in);
295 EINA_LIST_FOREACH(copy, ll, obj)
296 {
297 ev.canvas.x = e->pointer.x;
298 ev.canvas.y = e->pointer.y;
299 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
300 if ((!eina_list_data_find(ins, obj)) ||
301 (!e->pointer.inside))
302 {
303 if (obj->mouse_in)
304 {
305 obj->mouse_in = 0;
306 if (e->events_frozen <= 0)
307 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev);
308 }
309 }
310 if (e->delete_me) break;
311 }
312 _evas_post_event_callback_call(e);
313
314 if (copy) copy = eina_list_free(copy);
315 if (e->pointer.inside)
316 {
317 Evas_Event_Mouse_In ev_in;
318 Evas_Object *obj_itr;
319
320 _evas_object_event_new();
321
322 ev_in.buttons = e->pointer.button;
323 ev_in.output.x = e->pointer.x;
324 ev_in.output.y = e->pointer.y;
325 ev_in.canvas.x = e->pointer.x;
326 ev_in.canvas.y = e->pointer.y;
327 ev_in.data = (void *)data;
328 ev_in.modifiers = &(e->modifiers);
329 ev_in.locks = &(e->locks);
330 ev_in.timestamp = timestamp;
331 ev_in.event_flags = EVAS_EVENT_FLAG_NONE;
332
333 EINA_LIST_FOREACH(ins, l, obj_itr)
334 {
335 ev_in.canvas.x = e->pointer.x;
336 ev_in.canvas.y = e->pointer.y;
337 _evas_event_havemap_adjust(obj_itr, &ev_in.canvas.x, &ev_in.canvas.y, obj_itr->mouse_grabbed);
338 if (!eina_list_data_find(e->pointer.object.in, obj_itr))
339 {
340 if (!obj_itr->mouse_in)
341 {
342 obj_itr->mouse_in = 1;
343 if (e->events_frozen <= 0)
344 evas_object_event_callback_call(obj_itr, EVAS_CALLBACK_MOUSE_IN, &ev_in);
345 }
346 }
347 if (e->delete_me) break;
348 }
349 post_called = 1;
350 _evas_post_event_callback_call(e);
351 }
352 else
353 {
354 ins = eina_list_free(ins);
355 }
356
357 if (e->pointer.mouse_grabbed == 0)
358 {
359 /* free our old list of ins */
360 eina_list_free(e->pointer.object.in);
361 /* and set up the new one */
362 e->pointer.object.in = ins;
363 }
364 else
365 {
366 /* free our cur ins */
367 eina_list_free(ins);
368 }
369 if (e->pointer.inside)
370 evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y, timestamp, data);
371 return post_called;
372}
373
374EAPI void
375evas_event_feed_mouse_up(Evas *e, int b, Evas_Button_Flags flags, unsigned int timestamp, const void *data)
376{
377 Eina_List *l, *copy;
378
379 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
380 return;
381 MAGIC_CHECK_END();
382
383 if ((b < 1) || (b > 32)) return;
384
385 e->pointer.button &= ~(1 << (b - 1));
386
387 if (e->events_frozen > 0) return;
388 e->last_timestamp = timestamp;
389
390 {
391 Evas_Event_Mouse_Up ev;
392 Evas_Object *obj;
393
394 _evas_object_event_new();
395
396 ev.button = b;
397 ev.output.x = e->pointer.x;
398 ev.output.y = e->pointer.y;
399 ev.canvas.x = e->pointer.x;
400 ev.canvas.y = e->pointer.y;
401 ev.data = (void *)data;
402 ev.modifiers = &(e->modifiers);
403 ev.locks = &(e->locks);
404 ev.flags = flags;
405 ev.timestamp = timestamp;
406 ev.event_flags = EVAS_EVENT_FLAG_NONE;
407
408 _evas_walk(e);
409 /* update released touch point */
410 _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_UP);
411 copy = evas_event_list_copy(e->pointer.object.in);
412 EINA_LIST_FOREACH(copy, l, obj)
413 {
414 ev.canvas.x = e->pointer.x;
415 ev.canvas.y = e->pointer.y;
416 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
417 if ((obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) &&
418 (obj->mouse_grabbed > 0))
419 {
420 obj->mouse_grabbed--;
421 e->pointer.mouse_grabbed--;
422 }
423 if (!obj->delete_me)
424 {
425 if (e->events_frozen <= 0)
426 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_UP, &ev);
427 }
428 if (e->delete_me) break;
429 }
430 if (copy) copy = eina_list_free(copy);
431 e->last_mouse_up_counter++;
432 _evas_post_event_callback_call(e);
433 }
434
435 if (e->pointer.mouse_grabbed == 0)
436 {
437 _post_up_handle(e, timestamp, data);
438 }
439
440 if (e->pointer.mouse_grabbed < 0)
441 {
442 ERR("BUG? e->pointer.mouse_grabbed (=%d) < 0!",
443 e->pointer.mouse_grabbed);
444 }
445 /* remove released touch point from the touch point list */
446 _evas_touch_point_remove(e, 0);
447
448 _evas_unwalk(e);
449}
450
451EAPI void
452evas_event_feed_mouse_cancel(Evas *e, unsigned int timestamp, const void *data)
453{
454 int i;
455
456 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
457 return;
458 MAGIC_CHECK_END();
459
460 if (e->events_frozen > 0) return;
461
462 _evas_walk(e);
463 for (i = 0; i < 32; i++)
464 {
465 if ((e->pointer.button & (1 << i)))
466 evas_event_feed_mouse_up(e, i + 1, 0, timestamp, data);
467 }
468 _evas_unwalk(e);
469}
470
471EAPI void
472evas_event_feed_mouse_wheel(Evas *e, int direction, int z, unsigned int timestamp, const void *data)
473{
474 Eina_List *l, *copy;
475 Evas_Event_Mouse_Wheel ev;
476 Evas_Object *obj;
477
478 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
479 return;
480 MAGIC_CHECK_END();
481
482 if (e->events_frozen > 0) return;
483 e->last_timestamp = timestamp;
484
485 _evas_object_event_new();
486
487 ev.direction = direction;
488 ev.z = z;
489 ev.output.x = e->pointer.x;
490 ev.output.y = e->pointer.y;
491 ev.canvas.x = e->pointer.x;
492 ev.canvas.y = e->pointer.y;
493 ev.data = (void *) data;
494 ev.modifiers = &(e->modifiers);
495 ev.locks = &(e->locks);
496 ev.timestamp = timestamp;
497 ev.event_flags = EVAS_EVENT_FLAG_NONE;
498
499 _evas_walk(e);
500 copy = evas_event_list_copy(e->pointer.object.in);
501
502 EINA_LIST_FOREACH(copy, l, obj)
503 {
504 ev.canvas.x = e->pointer.x;
505 ev.canvas.y = e->pointer.y;
506 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
507 if ((e->events_frozen <= 0) && !evas_event_freezes_through(obj))
508 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_WHEEL, &ev);
509 if (e->delete_me) break;
510 }
511 if (copy) copy = eina_list_free(copy);
512 _evas_post_event_callback_call(e);
513
514 _evas_unwalk(e);
515}
516
517EAPI void
518evas_event_feed_mouse_move(Evas *e, int x, int y, unsigned int timestamp, const void *data)
519{
520 int px, py;
521//// Evas_Coord pcx, pcy;
522
523 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
524 return;
525 MAGIC_CHECK_END();
526
527 px = e->pointer.x;
528 py = e->pointer.y;
529//// pcx = e->pointer.canvas_x;
530//// pcy = e->pointer.canvas_y;
531
532 if (e->events_frozen > 0) return;
533 e->last_timestamp = timestamp;
534
535 e->pointer.x = x;
536 e->pointer.y = y;
537//// e->pointer.canvas_x = x;
538//// e->pointer.canvas_y = y;
539//// e->pointer.canvas_x = evas_coord_screen_x_to_world(e, x);
540//// e->pointer.canvas_y = evas_coord_screen_y_to_world(e, y);
541 if ((!e->pointer.inside) && (e->pointer.mouse_grabbed == 0)) return;
542 _evas_walk(e);
543 /* update moved touch point */
544 if ((px != x) || (py != y))
545 _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_MOVE);
546 /* if our mouse button is grabbed to any objects */
547 if (e->pointer.mouse_grabbed > 0)
548 {
549 /* go thru old list of in objects */
550 Eina_List *outs = NULL;
551 Eina_List *l, *copy;
552
553 {
554 Evas_Event_Mouse_Move ev;
555 Evas_Object *obj;
556
557 _evas_object_event_new();
558
559 ev.buttons = e->pointer.button;
560 ev.cur.output.x = e->pointer.x;
561 ev.cur.output.y = e->pointer.y;
562 ev.cur.canvas.x = e->pointer.x;
563 ev.cur.canvas.y = e->pointer.y;
564 ev.prev.output.x = px;
565 ev.prev.output.y = py;
566 ev.prev.canvas.x = px;
567 ev.prev.canvas.y = py;
568 ev.data = (void *)data;
569 ev.modifiers = &(e->modifiers);
570 ev.locks = &(e->locks);
571 ev.timestamp = timestamp;
572 ev.event_flags = EVAS_EVENT_FLAG_NONE;
573 copy = evas_event_list_copy(e->pointer.object.in);
574 EINA_LIST_FOREACH(copy, l, obj)
575 {
576 ev.cur.canvas.x = e->pointer.x;
577 ev.cur.canvas.y = e->pointer.y;
578 _evas_event_havemap_adjust(obj, &ev.cur.canvas.x,
579 &ev.cur.canvas.y,
580 obj->mouse_grabbed);
581 if ((e->events_frozen <= 0) &&
582 (evas_object_clippers_is_visible(obj) ||
583 obj->mouse_grabbed) &&
584 (!evas_event_passes_through(obj)) &&
585 (!evas_event_freezes_through(obj)) &&
586 (!obj->clip.clipees))
587 {
588 if ((px != x) || (py != y))
589 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_MOVE, &ev);
590 }
591 else
592 outs = eina_list_append(outs, obj);
593 if (e->delete_me) break;
594 }
595 _evas_post_event_callback_call(e);
596 }
597 {
598 Evas_Event_Mouse_Out ev;
599
600 _evas_object_event_new();
601
602 ev.buttons = e->pointer.button;
603 ev.output.x = e->pointer.x;
604 ev.output.y = e->pointer.y;
605 ev.canvas.x = e->pointer.x;
606 ev.canvas.y = e->pointer.y;
607 ev.data = (void *)data;
608 ev.modifiers = &(e->modifiers);
609 ev.locks = &(e->locks);
610 ev.timestamp = timestamp;
611 ev.event_flags = EVAS_EVENT_FLAG_NONE;
612
613 if (copy) eina_list_free(copy);
614 while (outs)
615 {
616 Evas_Object *obj;
617
618 obj = outs->data;
619 outs = eina_list_remove(outs, obj);
620 if ((obj->mouse_grabbed == 0) && (!e->delete_me))
621 {
622 ev.canvas.x = e->pointer.x;
623 ev.canvas.y = e->pointer.y;
624 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
625 e->pointer.object.in = eina_list_remove(e->pointer.object.in, obj);
626 if (obj->mouse_in)
627 {
628 obj->mouse_in = 0;
629 if (!obj->delete_me)
630 {
631 if (e->events_frozen <= 0)
632 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev);
633 }
634 }
635 }
636 }
637 _evas_post_event_callback_call(e);
638 }
639 }
640 else
641 {
642 Eina_List *ins;
643 Eina_List *l, *copy;
644 Evas_Event_Mouse_Move ev;
645 Evas_Event_Mouse_Out ev2;
646 Evas_Event_Mouse_In ev3;
647 Evas_Object *obj;
648
649 _evas_object_event_new();
650
651 ev.buttons = e->pointer.button;
652 ev.cur.output.x = e->pointer.x;
653 ev.cur.output.y = e->pointer.y;
654 ev.cur.canvas.x = e->pointer.x;
655 ev.cur.canvas.y = e->pointer.y;
656 ev.prev.output.x = px;
657 ev.prev.output.y = py;
658 ev.prev.canvas.x = px;
659 ev.prev.canvas.y = py;
660 ev.data = (void *)data;
661 ev.modifiers = &(e->modifiers);
662 ev.locks = &(e->locks);
663 ev.timestamp = timestamp;
664 ev.event_flags = EVAS_EVENT_FLAG_NONE;
665
666 ev2.buttons = e->pointer.button;
667 ev2.output.x = e->pointer.x;
668 ev2.output.y = e->pointer.y;
669 ev2.canvas.x = e->pointer.x;
670 ev2.canvas.y = e->pointer.y;
671 ev2.data = (void *)data;
672 ev2.modifiers = &(e->modifiers);
673 ev2.locks = &(e->locks);
674 ev2.timestamp = timestamp;
675 ev2.event_flags = EVAS_EVENT_FLAG_NONE;
676
677 ev3.buttons = e->pointer.button;
678 ev3.output.x = e->pointer.x;
679 ev3.output.y = e->pointer.y;
680 ev3.canvas.x = e->pointer.x;
681 ev3.canvas.y = e->pointer.y;
682 ev3.data = (void *)data;
683 ev3.modifiers = &(e->modifiers);
684 ev3.locks = &(e->locks);
685 ev3.timestamp = timestamp;
686 ev3.event_flags = EVAS_EVENT_FLAG_NONE;
687
688 /* get all new in objects */
689 ins = evas_event_objects_event_list(e, NULL, x, y);
690 /* go thru old list of in objects */
691 copy = evas_event_list_copy(e->pointer.object.in);
692 EINA_LIST_FOREACH(copy, l, obj)
693 {
694 /* if its under the pointer and its visible and its in the new */
695 /* in list */
696 // FIXME: i don't think we need this
697 // evas_object_clip_recalc(obj);
698 if ((e->events_frozen <= 0) &&
699 evas_object_is_in_output_rect(obj, x, y, 1, 1) &&
700 (evas_object_clippers_is_visible(obj) ||
701 obj->mouse_grabbed) &&
702 eina_list_data_find(ins, obj) &&
703 (!evas_event_passes_through(obj)) &&
704 (!evas_event_freezes_through(obj)) &&
705 (!obj->clip.clipees) &&
706 ((!obj->precise_is_inside) || evas_object_is_inside(obj, x, y))
707 )
708 {
709 if ((px != x) || (py != y))
710 {
711 ev.cur.canvas.x = e->pointer.x;
712 ev.cur.canvas.y = e->pointer.y;
713 _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed);
714 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_MOVE, &ev);
715 }
716 }
717 /* otherwise it has left the object */
718 else
719 {
720 if (obj->mouse_in)
721 {
722 obj->mouse_in = 0;
723 ev2.canvas.x = e->pointer.x;
724 ev2.canvas.y = e->pointer.y;
725 _evas_event_havemap_adjust(obj, &ev2.canvas.x, &ev2.canvas.y, obj->mouse_grabbed);
726 if (e->events_frozen <= 0)
727 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev2);
728 }
729 }
730 if (e->delete_me) break;
731 }
732 _evas_post_event_callback_call(e);
733
734 _evas_object_event_new();
735
736 if (copy) copy = eina_list_free(copy);
737 /* go thru our current list of ins */
738 EINA_LIST_FOREACH(ins, l, obj)
739 {
740 ev3.canvas.x = e->pointer.x;
741 ev3.canvas.y = e->pointer.y;
742 _evas_event_havemap_adjust(obj, &ev3.canvas.x, &ev3.canvas.y, obj->mouse_grabbed);
743 /* if its not in the old list of ins send an enter event */
744 if (!eina_list_data_find(e->pointer.object.in, obj))
745 {
746 if (!obj->mouse_in)
747 {
748 obj->mouse_in = 1;
749 if (e->events_frozen <= 0)
750 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_IN, &ev3);
751 }
752 }
753 if (e->delete_me) break;
754 }
755 if (e->pointer.mouse_grabbed == 0)
756 {
757 /* free our old list of ins */
758 eina_list_free(e->pointer.object.in);
759 /* and set up the new one */
760 e->pointer.object.in = ins;
761 }
762 else
763 {
764 /* free our cur ins */
765 eina_list_free(ins);
766 }
767 _evas_post_event_callback_call(e);
768 }
769 _evas_unwalk(e);
770}
771
772EAPI void
773evas_event_feed_mouse_in(Evas *e, unsigned int timestamp, const void *data)
774{
775 Eina_List *ins;
776 Eina_List *l;
777 Evas_Event_Mouse_In ev;
778 Evas_Object *obj;
779
780 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
781 return;
782 MAGIC_CHECK_END();
783 e->pointer.inside = 1;
784
785 if (e->events_frozen > 0) return;
786 e->last_timestamp = timestamp;
787
788 if (e->pointer.mouse_grabbed != 0) return;
789
790 _evas_object_event_new();
791
792 ev.buttons = e->pointer.button;
793 ev.output.x = e->pointer.x;
794 ev.output.y = e->pointer.y;
795 ev.canvas.x = e->pointer.x;
796 ev.canvas.y = e->pointer.y;
797 ev.data = (void *)data;
798 ev.modifiers = &(e->modifiers);
799 ev.locks = &(e->locks);
800 ev.timestamp = timestamp;
801 ev.event_flags = EVAS_EVENT_FLAG_NONE;
802
803 _evas_walk(e);
804 /* get new list of ins */
805 ins = evas_event_objects_event_list(e, NULL, e->pointer.x, e->pointer.y);
806 EINA_LIST_FOREACH(ins, l, obj)
807 {
808 ev.canvas.x = e->pointer.x;
809 ev.canvas.y = e->pointer.y;
810 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
811 if (!eina_list_data_find(e->pointer.object.in, obj))
812 {
813 if (!obj->mouse_in)
814 {
815 obj->mouse_in = 1;
816 if (e->events_frozen <= 0)
817 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_IN, &ev);
818 }
819 }
820 if (e->delete_me) break;
821 }
822 /* free our old list of ins */
823 e->pointer.object.in = eina_list_free(e->pointer.object.in);
824 /* and set up the new one */
825 e->pointer.object.in = ins;
826 _evas_post_event_callback_call(e);
827 evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y, timestamp, data);
828 _evas_unwalk(e);
829}
830
831EAPI void
832evas_event_feed_mouse_out(Evas *e, unsigned int timestamp, const void *data)
833{
834 Evas_Event_Mouse_Out ev;
835
836 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
837 return;
838 MAGIC_CHECK_END();
839 e->pointer.inside = 0;
840
841 if (e->events_frozen > 0) return;
842 e->last_timestamp = timestamp;
843
844 _evas_object_event_new();
845
846 ev.buttons = e->pointer.button;
847 ev.output.x = e->pointer.x;
848 ev.output.y = e->pointer.y;
849 ev.canvas.x = e->pointer.x;
850 ev.canvas.y = e->pointer.y;
851 ev.data = (void *)data;
852 ev.modifiers = &(e->modifiers);
853 ev.locks = &(e->locks);
854 ev.timestamp = timestamp;
855 ev.event_flags = EVAS_EVENT_FLAG_NONE;
856
857 _evas_walk(e);
858 /* if our mouse button is grabbed to any objects */
859 if (e->pointer.mouse_grabbed == 0)
860 {
861 /* go thru old list of in objects */
862 Eina_List *l, *copy;
863 Evas_Object *obj;
864
865 copy = evas_event_list_copy(e->pointer.object.in);
866 EINA_LIST_FOREACH(copy, l, obj)
867 {
868 ev.canvas.x = e->pointer.x;
869 ev.canvas.y = e->pointer.y;
870 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
871 if (obj->mouse_in)
872 {
873 obj->mouse_in = 0;
874 if (!obj->delete_me)
875 {
876 if (e->events_frozen <= 0)
877 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev);
878 }
879 }
880 if (e->delete_me) break;
881 }
882 if (copy) copy = eina_list_free(copy);
883 /* free our old list of ins */
884 e->pointer.object.in = eina_list_free(e->pointer.object.in);
885 _evas_post_event_callback_call(e);
886 }
887 _evas_unwalk(e);
888}
889
890EAPI void
891evas_event_feed_multi_down(Evas *e,
892 int d, int x, int y,
893 double rad, double radx, double rady,
894 double pres, double ang,
895 double fx, double fy,
896 Evas_Button_Flags flags, unsigned int timestamp,
897 const void *data)
898{
899 Eina_List *l, *copy;
900 Evas_Event_Multi_Down ev;
901 Evas_Object *obj;
902
903 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
904 return;
905 MAGIC_CHECK_END();
906
907 if (e->events_frozen > 0) return;
908 e->last_timestamp = timestamp;
909
910 _evas_object_event_new();
911
912 ev.device = d;
913 ev.output.x = x;
914 ev.output.y = y;
915 ev.canvas.x = x;
916 ev.canvas.y = y;
917 ev.radius = rad;
918 ev.radius_x = radx;
919 ev.radius_y = rady;
920 ev.pressure = pres;
921 ev.angle = ang;
922 ev.canvas.xsub = fx;
923 ev.canvas.ysub = fy;
924 ev.data = (void *)data;
925 ev.modifiers = &(e->modifiers);
926 ev.locks = &(e->locks);
927 ev.flags = flags;
928 ev.timestamp = timestamp;
929 ev.event_flags = EVAS_EVENT_FLAG_NONE;
930
931 _evas_walk(e);
932 /* append new touch point to the touch point list */
933 _evas_touch_point_append(e, d, x, y);
934 copy = evas_event_list_copy(e->pointer.object.in);
935 EINA_LIST_FOREACH(copy, l, obj)
936 {
937 if (obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB)
938 {
939 obj->mouse_grabbed++;
940 e->pointer.mouse_grabbed++;
941 }
942 }
943 EINA_LIST_FOREACH(copy, l, obj)
944 {
945 ev.canvas.x = x;
946 ev.canvas.y = y;
947 ev.canvas.xsub = fx;
948 ev.canvas.ysub = fy;
949 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
950 if (x != ev.canvas.x)
951 ev.canvas.xsub = ev.canvas.x; // fixme - lost precision
952 if (y != ev.canvas.y)
953 ev.canvas.ysub = ev.canvas.y; // fixme - lost precision
954 if (e->events_frozen <= 0)
955 evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_DOWN, &ev);
956 if (e->delete_me) break;
957 }
958 if (copy) eina_list_free(copy);
959 _evas_post_event_callback_call(e);
960 /* update touch point's state to EVAS_TOUCH_POINT_STILL */
961 _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_STILL);
962 _evas_unwalk(e);
963}
964
965EAPI void
966evas_event_feed_multi_up(Evas *e,
967 int d, int x, int y,
968 double rad, double radx, double rady,
969 double pres, double ang,
970 double fx, double fy,
971 Evas_Button_Flags flags, unsigned int timestamp,
972 const void *data)
973{
974 Eina_List *l, *copy;
975 Evas_Event_Multi_Up ev;
976 Evas_Object *obj;
977
978 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
979 return;
980 MAGIC_CHECK_END();
981
982 if (e->events_frozen > 0) return;
983 e->last_timestamp = timestamp;
984
985 _evas_object_event_new();
986
987 ev.device = d;
988 ev.output.x = x;
989 ev.output.y = y;
990 ev.canvas.x = x;
991 ev.canvas.y = y;
992 ev.radius = rad;
993 ev.radius_x = radx;
994 ev.radius_y = rady;
995 ev.pressure = pres;
996 ev.angle = ang;
997 ev.canvas.xsub = fx;
998 ev.canvas.ysub = fy;
999 ev.data = (void *)data;
1000 ev.modifiers = &(e->modifiers);
1001 ev.locks = &(e->locks);
1002 ev.flags = flags;
1003 ev.timestamp = timestamp;
1004 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1005
1006 _evas_walk(e);
1007 /* update released touch point */
1008 _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_UP);
1009 copy = evas_event_list_copy(e->pointer.object.in);
1010 EINA_LIST_FOREACH(copy, l, obj)
1011 {
1012 ev.canvas.x = x;
1013 ev.canvas.y = y;
1014 ev.canvas.xsub = fx;
1015 ev.canvas.ysub = fy;
1016 _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed);
1017 if (x != ev.canvas.x)
1018 ev.canvas.xsub = ev.canvas.x; // fixme - lost precision
1019 if (y != ev.canvas.y)
1020 ev.canvas.ysub = ev.canvas.y; // fixme - lost precision
1021 if ((obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) &&
1022 (obj->mouse_grabbed > 0))
1023 {
1024 obj->mouse_grabbed--;
1025 e->pointer.mouse_grabbed--;
1026 }
1027 if (e->events_frozen <= 0)
1028 evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_UP, &ev);
1029 if (e->delete_me) break;
1030 }
1031 if (copy) copy = eina_list_free(copy);
1032 if ((e->pointer.mouse_grabbed == 0) && !_post_up_handle(e, timestamp, data))
1033 _evas_post_event_callback_call(e);
1034 /* remove released touch point from the touch point list */
1035 _evas_touch_point_remove(e, d);
1036 _evas_unwalk(e);
1037}
1038
1039EAPI void
1040evas_event_feed_multi_move(Evas *e,
1041 int d, int x, int y,
1042 double rad, double radx, double rady,
1043 double pres, double ang,
1044 double fx, double fy,
1045 unsigned int timestamp, const void *data)
1046{
1047 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1048 return;
1049 MAGIC_CHECK_END();
1050
1051 if (e->events_frozen > 0) return;
1052 e->last_timestamp = timestamp;
1053
1054 if (!e->pointer.inside) return;
1055
1056 _evas_walk(e);
1057 /* update moved touch point */
1058 _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_MOVE);
1059 /* if our mouse button is grabbed to any objects */
1060 if (e->pointer.mouse_grabbed > 0)
1061 {
1062 /* go thru old list of in objects */
1063 Eina_List *l, *copy;
1064 Evas_Event_Multi_Move ev;
1065 Evas_Object *obj;
1066
1067 _evas_object_event_new();
1068
1069 ev.device = d;
1070 ev.cur.output.x = x;
1071 ev.cur.output.y = y;
1072 ev.cur.canvas.x = x;
1073 ev.cur.canvas.y = y;
1074 ev.radius = rad;
1075 ev.radius_x = radx;
1076 ev.radius_y = rady;
1077 ev.pressure = pres;
1078 ev.angle = ang;
1079 ev.cur.canvas.xsub = fx;
1080 ev.cur.canvas.ysub = fy;
1081 ev.data = (void *)data;
1082 ev.modifiers = &(e->modifiers);
1083 ev.locks = &(e->locks);
1084 ev.timestamp = timestamp;
1085 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1086
1087 copy = evas_event_list_copy(e->pointer.object.in);
1088 EINA_LIST_FOREACH(copy, l, obj)
1089 {
1090 if ((e->events_frozen <= 0) &&
1091 (evas_object_clippers_is_visible(obj) || obj->mouse_grabbed) &&
1092 (!evas_event_passes_through(obj)) &&
1093 (!evas_event_freezes_through(obj)) &&
1094 (!obj->clip.clipees))
1095 {
1096 ev.cur.canvas.x = x;
1097 ev.cur.canvas.y = y;
1098 ev.cur.canvas.xsub = fx;
1099 ev.cur.canvas.ysub = fy;
1100 _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed);
1101 if (x != ev.cur.canvas.x)
1102 ev.cur.canvas.xsub = ev.cur.canvas.x; // fixme - lost precision
1103 if (y != ev.cur.canvas.y)
1104 ev.cur.canvas.ysub = ev.cur.canvas.y; // fixme - lost precision
1105 evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_MOVE, &ev);
1106 }
1107 if (e->delete_me) break;
1108 }
1109 _evas_post_event_callback_call(e);
1110 }
1111 else
1112 {
1113 Eina_List *ins;
1114 Eina_List *l, *copy;
1115 Evas_Event_Multi_Move ev;
1116 Evas_Object *obj;
1117
1118 _evas_object_event_new();
1119
1120 ev.device = d;
1121 ev.cur.output.x = x;
1122 ev.cur.output.y = y;
1123 ev.cur.canvas.x = x;
1124 ev.cur.canvas.y = y;
1125 ev.radius = rad;
1126 ev.radius_x = radx;
1127 ev.radius_y = rady;
1128 ev.pressure = pres;
1129 ev.angle = ang;
1130 ev.cur.canvas.xsub = fx;
1131 ev.cur.canvas.ysub = fy;
1132 ev.data = (void *)data;
1133 ev.modifiers = &(e->modifiers);
1134 ev.locks = &(e->locks);
1135 ev.timestamp = timestamp;
1136 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1137
1138 /* get all new in objects */
1139 ins = evas_event_objects_event_list(e, NULL, x, y);
1140 /* go thru old list of in objects */
1141 copy = evas_event_list_copy(e->pointer.object.in);
1142 EINA_LIST_FOREACH(copy, l, obj)
1143 {
1144 /* if its under the pointer and its visible and its in the new */
1145 /* in list */
1146 // FIXME: i don't think we need this
1147 // evas_object_clip_recalc(obj);
1148 if ((e->events_frozen <= 0) &&
1149 evas_object_is_in_output_rect(obj, x, y, 1, 1) &&
1150 (evas_object_clippers_is_visible(obj) ||
1151 obj->mouse_grabbed) &&
1152 eina_list_data_find(ins, obj) &&
1153 (!evas_event_passes_through(obj)) &&
1154 (!evas_event_freezes_through(obj)) &&
1155 (!obj->clip.clipees) &&
1156 ((!obj->precise_is_inside) || evas_object_is_inside(obj, x, y))
1157 )
1158 {
1159 ev.cur.canvas.x = x;
1160 ev.cur.canvas.y = y;
1161 ev.cur.canvas.xsub = fx;
1162 ev.cur.canvas.ysub = fy;
1163 _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed);
1164 if (x != ev.cur.canvas.x)
1165 ev.cur.canvas.xsub = ev.cur.canvas.x; // fixme - lost precision
1166 if (y != ev.cur.canvas.y)
1167 ev.cur.canvas.ysub = ev.cur.canvas.y; // fixme - lost precision
1168 evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_MOVE, &ev);
1169 }
1170 if (e->delete_me) break;
1171 }
1172 if (copy) copy = eina_list_free(copy);
1173 if (e->pointer.mouse_grabbed == 0)
1174 {
1175 /* free our old list of ins */
1176 eina_list_free(e->pointer.object.in);
1177 /* and set up the new one */
1178 e->pointer.object.in = ins;
1179 }
1180 else
1181 {
1182 /* free our cur ins */
1183 eina_list_free(ins);
1184 }
1185 _evas_post_event_callback_call(e);
1186 }
1187 _evas_unwalk(e);
1188}
1189
1190EAPI void
1191evas_event_feed_key_down(Evas *e, const char *keyname, const char *key, const char *string, const char *compose, unsigned int timestamp, const void *data)
1192{
1193 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1194 return;
1195 MAGIC_CHECK_END();
1196
1197 if (!keyname) return;
1198 if (e->events_frozen > 0) return;
1199 e->last_timestamp = timestamp;
1200 _evas_walk(e);
1201
1202 Evas_Event_Key_Down ev;
1203 Eina_Bool exclusive;
1204
1205 _evas_object_event_new();
1206
1207 exclusive = EINA_FALSE;
1208 ev.keyname = (char *)keyname;
1209 ev.data = (void *)data;
1210 ev.modifiers = &(e->modifiers);
1211 ev.locks = &(e->locks);
1212 ev.key = key;
1213 ev.string = string;
1214 ev.compose = compose;
1215 ev.timestamp = timestamp;
1216 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1217
1218 if (e->grabs)
1219 {
1220 Eina_List *l;
1221 Evas_Key_Grab *g;
1222
1223 e->walking_grabs++;
1224 EINA_LIST_FOREACH(e->grabs, l, g)
1225 {
1226 if (g->just_added)
1227 {
1228 g->just_added = EINA_FALSE;
1229 continue;
1230 }
1231 if (g->delete_me) continue;
1232 if (((e->modifiers.mask & g->modifiers) ||
1233 (g->modifiers == e->modifiers.mask)) &&
1234 (!strcmp(keyname, g->keyname)))
1235 {
1236 if (!(e->modifiers.mask & g->not_modifiers))
1237 {
1238 if (e->events_frozen <= 0 &&
1239 !evas_event_freezes_through(g->object))
1240 evas_object_event_callback_call(g->object,
1241 EVAS_CALLBACK_KEY_DOWN,
1242 &ev);
1243 if (g->exclusive) exclusive = EINA_TRUE;
1244 }
1245 }
1246 if (e->delete_me) break;
1247 }
1248 e->walking_grabs--;
1249 if (e->walking_grabs <= 0)
1250 {
1251 while (e->delete_grabs > 0)
1252 {
1253 e->delete_grabs--;
1254 for (l = e->grabs; l;)
1255 {
1256 g = eina_list_data_get(l);
1257 l = eina_list_next(l);
1258 if (g->delete_me)
1259 evas_key_grab_free(g->object, g->keyname, g->modifiers,
1260 g->not_modifiers);
1261 }
1262 }
1263 }
1264 }
1265 if ((e->focused) && (!exclusive))
1266 {
1267 if (e->events_frozen <= 0 && !evas_event_freezes_through(e->focused))
1268 evas_object_event_callback_call(e->focused, EVAS_CALLBACK_KEY_DOWN,
1269 &ev);
1270 }
1271 _evas_post_event_callback_call(e);
1272 _evas_unwalk(e);
1273}
1274
1275EAPI void
1276evas_event_feed_key_up(Evas *e, const char *keyname, const char *key, const char *string, const char *compose, unsigned int timestamp, const void *data)
1277{
1278 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1279 return;
1280 MAGIC_CHECK_END();
1281 if (!keyname) return;
1282 if (e->events_frozen > 0) return;
1283 e->last_timestamp = timestamp;
1284 _evas_walk(e);
1285
1286 Evas_Event_Key_Up ev;
1287 Eina_Bool exclusive;
1288
1289 _evas_object_event_new();
1290
1291 exclusive = EINA_FALSE;
1292 ev.keyname = (char *)keyname;
1293 ev.data = (void *)data;
1294 ev.modifiers = &(e->modifiers);
1295 ev.locks = &(e->locks);
1296 ev.key = key;
1297 ev.string = string;
1298 ev.compose = compose;
1299 ev.timestamp = timestamp;
1300 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1301
1302 if (e->grabs)
1303 {
1304 Eina_List *l;
1305 Evas_Key_Grab *g;
1306
1307 e->walking_grabs++;
1308 EINA_LIST_FOREACH(e->grabs, l, g)
1309 {
1310 if (g->just_added)
1311 {
1312 g->just_added = EINA_FALSE;
1313 continue;
1314 }
1315 if (g->delete_me) continue;
1316 if (((e->modifiers.mask & g->modifiers) ||
1317 (g->modifiers == e->modifiers.mask)) &&
1318 (!((e->modifiers.mask & g->not_modifiers) ||
1319 (g->not_modifiers == ~e->modifiers.mask))) &&
1320 (!strcmp(keyname, g->keyname)))
1321 {
1322 if (e->events_frozen <= 0 &&
1323 !evas_event_freezes_through(g->object))
1324 evas_object_event_callback_call(g->object,
1325 EVAS_CALLBACK_KEY_UP, &ev);
1326 if (g->exclusive) exclusive = EINA_TRUE;
1327 }
1328 if (e->delete_me) break;
1329 }
1330 e->walking_grabs--;
1331 if (e->walking_grabs <= 0)
1332 {
1333 while (e->delete_grabs > 0)
1334 {
1335 Eina_List *ll, *l_next;
1336 Evas_Key_Grab *gr;
1337
1338 e->delete_grabs--;
1339 EINA_LIST_FOREACH_SAFE(e->grabs, ll, l_next, gr)
1340 {
1341 if (gr->delete_me)
1342 evas_key_grab_free(gr->object, gr->keyname,
1343 gr->modifiers, gr->not_modifiers);
1344 }
1345 }
1346 }
1347 }
1348 if ((e->focused) && (!exclusive))
1349 {
1350 if (e->events_frozen <= 0 && !evas_event_freezes_through(e->focused))
1351 evas_object_event_callback_call(e->focused, EVAS_CALLBACK_KEY_UP,
1352 &ev);
1353 }
1354 _evas_post_event_callback_call(e);
1355 _evas_unwalk(e);
1356}
1357
1358EAPI void
1359evas_event_feed_hold(Evas *e, int hold, unsigned int timestamp, const void *data)
1360{
1361 Eina_List *l, *copy;
1362 Evas_Event_Hold ev;
1363 Evas_Object *obj;
1364
1365 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1366 return;
1367 MAGIC_CHECK_END();
1368
1369 if (e->events_frozen > 0) return;
1370 e->last_timestamp = timestamp;
1371
1372 _evas_object_event_new();
1373
1374 ev.hold = hold;
1375 ev.data = (void *)data;
1376 ev.timestamp = timestamp;
1377 ev.event_flags = EVAS_EVENT_FLAG_NONE;
1378
1379 _evas_walk(e);
1380 copy = evas_event_list_copy(e->pointer.object.in);
1381 EINA_LIST_FOREACH(copy, l, obj)
1382 {
1383 if ((e->events_frozen <= 0) && !evas_event_freezes_through(obj))
1384 evas_object_event_callback_call(obj, EVAS_CALLBACK_HOLD, &ev);
1385 if (e->delete_me) break;
1386 }
1387 if (copy) copy = eina_list_free(copy);
1388 _evas_post_event_callback_call(e);
1389 _evas_unwalk(e);
1390 _evas_object_event_new();
1391}
1392
1393EAPI void
1394evas_object_freeze_events_set(Evas_Object *obj, Eina_Bool freeze)
1395{
1396 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1397 return;
1398 MAGIC_CHECK_END();
1399
1400 freeze = !!freeze;
1401 if (obj->freeze_events == freeze) return;
1402 obj->freeze_events = freeze;
1403 evas_object_smart_member_cache_invalidate(obj, EINA_FALSE, EINA_TRUE);
1404 if (evas_object_is_in_output_rect(obj,
1405 obj->layer->evas->pointer.x,
1406 obj->layer->evas->pointer.y, 1, 1) &&
1407 ((!obj->precise_is_inside) ||
1408 (evas_object_is_inside(obj,
1409 obj->layer->evas->pointer.x,
1410 obj->layer->evas->pointer.y))))
1411 evas_event_feed_mouse_move(obj->layer->evas,
1412 obj->layer->evas->pointer.x,
1413 obj->layer->evas->pointer.y,
1414 obj->layer->evas->last_timestamp,
1415 NULL);
1416}
1417
1418EAPI Eina_Bool
1419evas_object_freeze_events_get(const Evas_Object *obj)
1420{
1421 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1422 return EINA_FALSE;
1423 MAGIC_CHECK_END();
1424 return obj->freeze_events;
1425}
1426
1427EAPI void
1428evas_object_pass_events_set(Evas_Object *obj, Eina_Bool pass)
1429{
1430 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1431 return;
1432 MAGIC_CHECK_END();
1433 pass = !!pass;
1434 if (obj->pass_events == pass) return;
1435 obj->pass_events = pass;
1436 evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_FALSE);
1437 if (evas_object_is_in_output_rect(obj,
1438 obj->layer->evas->pointer.x,
1439 obj->layer->evas->pointer.y, 1, 1) &&
1440 ((!obj->precise_is_inside) ||
1441 (evas_object_is_inside(obj,
1442 obj->layer->evas->pointer.x,
1443 obj->layer->evas->pointer.y))))
1444 evas_event_feed_mouse_move(obj->layer->evas,
1445 obj->layer->evas->pointer.x,
1446 obj->layer->evas->pointer.y,
1447 obj->layer->evas->last_timestamp,
1448 NULL);
1449}
1450
1451EAPI Eina_Bool
1452evas_object_pass_events_get(const Evas_Object *obj)
1453{
1454 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1455 return EINA_FALSE;
1456 MAGIC_CHECK_END();
1457 return obj->pass_events;
1458}
1459
1460EAPI void
1461evas_object_repeat_events_set(Evas_Object *obj, Eina_Bool repeat)
1462{
1463 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1464 return;
1465 MAGIC_CHECK_END();
1466 repeat = !!repeat;
1467 if (obj->repeat_events == repeat) return;
1468 obj->repeat_events = repeat;
1469 if (evas_object_is_in_output_rect(obj,
1470 obj->layer->evas->pointer.x,
1471 obj->layer->evas->pointer.y, 1, 1) &&
1472 ((!obj->precise_is_inside) ||
1473 (evas_object_is_inside(obj,
1474 obj->layer->evas->pointer.x,
1475 obj->layer->evas->pointer.y))))
1476 evas_event_feed_mouse_move(obj->layer->evas,
1477 obj->layer->evas->pointer.x,
1478 obj->layer->evas->pointer.y,
1479 obj->layer->evas->last_timestamp,
1480 NULL);
1481}
1482
1483EAPI Eina_Bool
1484evas_object_repeat_events_get(const Evas_Object *obj)
1485{
1486 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1487 return EINA_FALSE;
1488 MAGIC_CHECK_END();
1489 return obj->repeat_events;
1490}
1491
1492EAPI void
1493evas_object_propagate_events_set(Evas_Object *obj, Eina_Bool prop)
1494{
1495 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1496 return;
1497 MAGIC_CHECK_END();
1498 obj->no_propagate = !prop;
1499}
1500
1501EAPI Eina_Bool
1502evas_object_propagate_events_get(const Evas_Object *obj)
1503{
1504 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1505 return EINA_FALSE;
1506 MAGIC_CHECK_END();
1507 return !(obj->no_propagate);
1508}
1509
1510EAPI void
1511evas_object_pointer_mode_set(Evas_Object *obj, Evas_Object_Pointer_Mode setting)
1512{
1513 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1514 return;
1515 MAGIC_CHECK_END();
1516 obj->pointer_mode = setting;
1517}
1518
1519EAPI Evas_Object_Pointer_Mode
1520evas_object_pointer_mode_get(const Evas_Object *obj)
1521{
1522 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1523 return EVAS_OBJECT_POINTER_MODE_AUTOGRAB;
1524 MAGIC_CHECK_END();
1525 return obj->pointer_mode;
1526}
1527
1528EAPI void
1529evas_event_refeed_event(Evas *e, void *event_copy, Evas_Callback_Type event_type)
1530{
1531 switch(event_type)
1532 {
1533 case EVAS_CALLBACK_MOUSE_IN:
1534 {
1535 Evas_Event_Mouse_In *ev = event_copy;
1536 evas_event_feed_mouse_in(e, ev->timestamp, ev->data);
1537 break;
1538 }
1539 case EVAS_CALLBACK_MOUSE_OUT:
1540 {
1541 Evas_Event_Mouse_Out *ev = event_copy;
1542 evas_event_feed_mouse_out(e, ev->timestamp, ev->data);
1543 break;
1544 }
1545 case EVAS_CALLBACK_MOUSE_DOWN:
1546 {
1547 Evas_Event_Mouse_Down *ev = event_copy;
1548 evas_event_feed_mouse_down(e, ev->button, ev->flags, ev-> timestamp, ev->data);
1549 break;
1550 }
1551 case EVAS_CALLBACK_MOUSE_UP:
1552 {
1553 Evas_Event_Mouse_Up *ev = event_copy;
1554 evas_event_feed_mouse_up(e, ev->button, ev->flags, ev-> timestamp, ev->data);
1555 break;
1556 }
1557 case EVAS_CALLBACK_MOUSE_MOVE:
1558 {
1559 Evas_Event_Mouse_Move *ev = event_copy;
1560 evas_event_feed_mouse_move(e, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp, ev->data);
1561 break;
1562 }
1563 case EVAS_CALLBACK_MOUSE_WHEEL:
1564 {
1565 Evas_Event_Mouse_Wheel *ev = event_copy;
1566 evas_event_feed_mouse_wheel(e, ev->direction, ev-> z, ev->timestamp, ev->data);
1567 break;
1568 }
1569 case EVAS_CALLBACK_MULTI_DOWN:
1570 {
1571 Evas_Event_Multi_Down *ev = event_copy;
1572 evas_event_feed_multi_down(e, ev->device, ev->canvas.x, ev->canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->canvas.xsub, ev->canvas.ysub, ev->flags, ev->timestamp, ev->data);
1573 break;
1574 }
1575 case EVAS_CALLBACK_MULTI_UP:
1576 {
1577 Evas_Event_Multi_Up *ev = event_copy;
1578 evas_event_feed_multi_up(e, ev->device, ev->canvas.x, ev->canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->canvas.xsub, ev->canvas.ysub, ev->flags, ev->timestamp, ev->data);
1579 break;
1580 }
1581 case EVAS_CALLBACK_MULTI_MOVE:
1582 {
1583 Evas_Event_Multi_Move *ev = event_copy;
1584 evas_event_feed_multi_move(e, ev->device, ev->cur.canvas.x, ev->cur.canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->cur.canvas.xsub, ev->cur.canvas.ysub, ev->timestamp, ev->data);
1585 break;
1586 }
1587 case EVAS_CALLBACK_KEY_DOWN:
1588 {
1589 Evas_Event_Key_Down *ev = event_copy;
1590 evas_event_feed_key_down(e, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, ev->data);
1591 break;
1592 }
1593 case EVAS_CALLBACK_KEY_UP:
1594 {
1595 Evas_Event_Key_Up *ev = event_copy;
1596 evas_event_feed_key_up(e, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, ev->data);
1597 break;
1598 }
1599 default: /* All non-input events are not handeled */
1600 break;
1601 }
1602}
diff --git a/libraries/evas/src/lib/canvas/evas_filter.c b/libraries/evas/src/lib/canvas/evas_filter.c
new file mode 100644
index 0000000..6194ec2
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_filter.c
@@ -0,0 +1,1427 @@
1/*
2 * Filter implementation for evas
3 */
4
5#if 0 // filtering disabled
6typedef enum
7{
8 /** Apply any filter effects to this object (Default) */
9 EVAS_FILTER_MODE_OBJECT,
10 /** Filter all objects beneath this object on the canvas */
11 EVAS_FILTER_MODE_BELOW,
12} Evas_Filter_Mode;
13typedef enum
14{
15 /** No filter: Default */
16 EVAS_FILTER_NONE,
17 /** A blur filter. Params are quality (float), and radius (int). */
18 EVAS_FILTER_BLUR,
19 /** Negates the colors of an image. Also called solarize */
20 EVAS_FILTER_INVERT,
21 EVAS_FILTER_SOLARIZE = EVAS_FILTER_INVERT,
22 /** Makes a sepia version of the image. */
23 EVAS_FILTER_SEPIA,
24 /** Makes a greyscale version of the image. Params are 'red',
25 * 'green', 'blue' (all floats) which must add to 1. The defaults are
26 * 0.3, 0.59 and 0.11 which approximates human vision. Setting 'all'
27 * sets rgb to the same value. */
28 EVAS_FILTER_GREYSCALE,
29 EVAS_FILTER_GRAYSCALE = EVAS_FILTER_GREYSCALE,
30 /** Brighten (or darken) image. Param 'adjust' float (-1.0 to 1.0)
31 * amount to adjust. */
32 EVAS_FILTER_BRIGHTNESS,
33 /** Enhance contrast on image. Param 'adjust' float (-1.0 to 1.0)
34 * amount to adjust. */
35 EVAS_FILTER_CONTRAST,
36
37 EVAS_FILTER_LAST = EVAS_FILTER_CONTRAST
38} Evas_Filter;
39
40/**
41 * Set the filter mode for an object.
42 *
43 * There are two valid filtering modes currently:
44 * - EVAS_FILTER_MODE_OBJECT: which applies the filter to the object itself
45 * - EVAS_FILTER_MODE_BELOW: which makes the object invisible and filters
46 * what is below the object.
47 *
48 * The default filter mode is EVAS_FILTER_MODE_OBJECT.
49 *
50 * @param o Object to set filter mode on.
51 * @param mode Mode to set.
52 * @return EINA_TRUE on success, EINA_FALSE otherwise.
53 */
54 EAPI Eina_Bool evas_object_filter_mode_set (Evas_Object *o, Evas_Filter_Mode mode);
55
56/**
57 * Get the current filtering mode for an object.
58 *
59 * By default all objects are in object filtering mode, even if no filter is
60 * set.
61 *
62 * @param o Object to get filter mode of.
63 * @return Filter mode (default EVAS_FILTER_MODE_OBJECT)
64 */
65 EAPI Evas_Filter_Mode evas_object_filter_mode_get (Evas_Object *o);
66
67/**
68 * Set the current filter type.
69 *
70 * This sets the filter type, whether a blur, color filter or some other type
71 * of filter. This is normally the only filter call necessary, although some
72 * filters require additional parameters.
73 *
74 * If the object has a filter already, and existing parameters will be
75 * cleared.
76 *
77 * Setting the blur to EVAS_FILTER_NONE removes any filter.
78 *
79 * @param o Object to set the filter on.
80 * @param filter Filter to set.
81 * @return EINA_TRUE On success
82 */
83 EAPI Eina_Bool evas_object_filter_set (Evas_Object *o, Evas_Filter filter);
84
85/**
86 * Get the current filter.
87 *
88 * @param o Object to get filter of.
89 * @return The filter if set, or EVAS_FILTER_NONE.
90 */
91 EAPI Evas_Filter evas_object_filter_get (Evas_Object *o);
92
93/**
94 * Set an integer parameter of a filter.
95 *
96 * This sets an integer parameter of a filter, if such parameter is known to
97 * the filter. Note that some parameters may actually set multiple fields.
98 * The individual filters define the specific parameters available.
99 *
100 * It should be noted that filter parameters are lost after the filter type
101 * changes, so set the filter type, then the parameters.
102 *
103 * @param o Object to set parameter on.
104 * @param param Name of parameter to set.
105 * @param val Value to set.
106 * @return EINA_TRUE if at least one parameter was set, EINA_FALSE
107 * otherwise.
108 */
109 EAPI Eina_Bool evas_object_filter_param_int_set (Evas_Object *o, const char *param, int val);
110
111/**
112 * Get an integer value parameter from a filter.
113 *
114 * Gets the first matching parameter for a filter. Note there is no way to
115 * later fields if they do not have their own accessor name.
116 *
117 * Also note that there is no way to tell the difference between a -1 as a
118 * value, and the error code. Ask your filter writer to use a different
119 * range.
120 *
121 * @param o The object.
122 * @Param param Name of the parameter to get.
123 * @return The value, or -1 on error.
124 */
125 EAPI int evas_object_filter_param_int_get (Evas_Object *o, const char *param);
126
127/**
128 * Set a string parameter on a filter
129 *
130 * Currently unimplemented as no filters use this yet
131 */
132 EAPI Eina_Bool evas_object_filter_param_str_set (Evas_Object *o, const char *param, const char *val);
133
134/**
135 * Get a string parameter from a filter
136 *
137 * Currently unimplemented as no filters use this yet
138 */
139 EAPI const char *evas_object_filter_param_str_get (Evas_Object *o, const char *param);
140
141/**
142 * Set an object parameter on a filter
143 *
144 * Currently unimplemented as no filters use this yet
145 */
146 EAPI Eina_Bool evas_object_filter_param_obj_set (Evas_Object *o, const char *param, Evas_Object *val);
147
148/**
149 * get an object parameter from a filter
150 *
151 * Currently unimplemented as no filters use this yet
152 */
153 EAPI Evas_Object *evas_object_filter_param_obj_get (Evas_Object *o, const char *param);
154
155/**
156 * Set a float parameter of a filter.
157 *
158 * This is the same as evas_object_filter_param_int_set(), but for floating
159 * point values.
160 *
161 * @param o Object to set value on.
162 * @param param Name of the parameter to set.
163 * @param EINA_TRUE if at least one parameter was set, EINA_FALSE otherwise.
164 */
165 EAPI Eina_Bool evas_object_filter_param_float_set(Evas_Object *o, const char *param, double val);
166
167/**
168 * Get a float parameter of a filter.
169 *
170 * This is the same as evas_object_filter_param_int_get(), but for floating
171 * point values.
172 *
173 * @param o Object to set value on.
174 * @param param Name of the parameter to set.
175 * @return The value, or -1 on error.
176 */
177 EAPI double evas_object_filter_param_float_get(Evas_Object *o, const char *param);
178
179#include <stddef.h> // offsetof
180
181#include "evas_common.h"
182#include "evas_private.h"
183
184#include <assert.h>
185/* disable neon - even after fixes:
186 * Error: ARM register expected -- vdup.u32 q14,$0xff000000'
187 * not going to fix now
188#ifdef BUILD_NEON
189# define BUILD_NEON0 1
190#else
191# define BUILD_NEON0 0
192#endif
193*/
194
195#define BUILD_NEON0 0
196
197typedef struct Evas_Filter_Info_Blur
198{
199 double quality;
200 int radius;
201} Evas_Filter_Info_Blur;
202
203typedef struct Evas_Filter_Info_GreyScale
204{
205 double r,g,b;
206} Evas_Filter_Info_GreyScale;
207
208typedef struct Evas_Filter_Info_Brightness
209{
210 double adjust;
211} Evas_Filter_Info_Brightness;
212
213typedef struct Evas_Filter_Info_Contrast
214{
215 double adjust;
216} Evas_Filter_Info_Contrast;
217
218typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool);
219typedef uint8_t *(*Key_FN)(const Evas_Filter_Info *, uint32_t *);
220
221struct fieldinfo
222{
223 const char *field;
224 int type;
225 size_t offset;
226};
227
228struct filterinfo
229{
230 Evas_Software_Filter_Fn filter;
231 const size_t datasize;
232 Filter_Size_FN sizefn;
233 Key_FN keyfn;
234 Eina_Bool alwaysalpha;
235};
236
237enum
238{
239 TYPE_INT,
240 TYPE_FLOAT
241};
242
243static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool);
244static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *);
245
246static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
247static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
248static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
249static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
250static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
251static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
252
253struct filterinfo filterinfo[] =
254{
255 /* None */
256 { NULL, 0, NULL, NULL, EINA_FALSE},
257 /* Blur */
258 { gaussian_filter, sizeof(Evas_Filter_Info_Blur), blur_size_get, gaussian_key_get, EINA_TRUE },
259 /* Negation */
260 { negation_filter, 0, NULL, NULL, EINA_FALSE },
261 /* Sepia */
262 { sepia_filter, 0, NULL, NULL, EINA_FALSE },
263 /* Greyscale */
264 { greyscale_filter, sizeof(Evas_Filter_Info_GreyScale), NULL, NULL, EINA_FALSE },
265 /* Brightness */
266 { brightness_filter, sizeof(Evas_Filter_Info_Brightness), NULL, NULL, EINA_FALSE },
267 /* Contrast */
268 { contrast_filter, sizeof(Evas_Filter_Info_Contrast), NULL, NULL, EINA_FALSE},
269};
270
271
272static struct fieldinfo blurfields[] =
273{
274 { "quality", TYPE_FLOAT, offsetof(Evas_Filter_Info_Blur, quality) },
275 { "radius", TYPE_INT, offsetof(Evas_Filter_Info_Blur, radius) },
276 { NULL, 0, 0 },
277};
278
279static struct fieldinfo greyfields[] =
280{
281 { "red", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
282 { "green", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
283 { "blue", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
284
285 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
286 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
287 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
288 { NULL, 0, 0 },
289};
290
291static struct fieldinfo brightnessfields[] =
292{
293 { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) },
294 { NULL, 0, 0 },
295};
296
297static struct fieldinfo contrastfields[] =
298{
299 { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) },
300 { NULL, 0, 0 },
301};
302
303static struct fieldinfo *filterfields[] =
304{
305 NULL,
306 blurfields,
307 NULL,
308 NULL,
309 greyfields,
310 brightnessfields,
311 contrastfields,
312};
313
314static Evas_Filter_Info *filter_alloc(Evas_Object *o);
315
316EAPI Eina_Bool
317evas_object_filter_mode_set(Evas_Object *o, Evas_Filter_Mode mode)
318{
319 Evas_Filter_Info *info;
320
321 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
322 return EINA_FALSE;
323 MAGIC_CHECK_END();
324
325 if ((mode != EVAS_FILTER_MODE_OBJECT) && (mode != EVAS_FILTER_MODE_BELOW))
326 return EINA_FALSE;
327
328 if (!o->filter)
329 {
330 filter_alloc(o);
331 }
332 if (!o->filter) return EINA_FALSE;
333 info = o->filter;
334
335 if (info->mode == mode) return EINA_TRUE; /* easy case */
336 info->mode = mode;
337 info->dirty = 1;
338 return EINA_TRUE;
339}
340
341EAPI Evas_Filter_Mode
342evas_object_filter_mode_get(Evas_Object *o)
343{
344 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
345 return EVAS_FILTER_MODE_OBJECT;
346 MAGIC_CHECK_END();
347
348 if (!o->filter) return EVAS_FILTER_MODE_OBJECT;
349 return o->filter->mode;
350}
351
352EAPI Eina_Bool
353evas_object_filter_set(Evas_Object *o, Evas_Filter filter)
354{
355 Evas_Filter_Info *info;
356 struct filterinfo *finfo;
357
358 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
359 return EINA_FALSE;
360 MAGIC_CHECK_END();
361
362 /* force filter to be signed: else gcc complains, but enums may always be
363 * signed */
364 if (((int)filter < (int)EVAS_FILTER_NONE) || (filter > EVAS_FILTER_LAST))
365 return EINA_FALSE;
366
367 /* Don't alloc on no-op */
368 if (!o-filter && filter == EVAS_FILTER_NONE) return EINA_TRUE;
369
370 if (!o->filter) filter_alloc(o);
371 if (!o->filter) return EINA_FALSE;
372
373 info = o->filter;
374
375 if (info->filter == filter) return EINA_TRUE;
376
377 finfo = filterinfo + filter;
378 info->filter = filter;
379 info->dirty = 1;
380 if (info->data)
381 {
382 if (info->data_free)
383 info->data_free(info->data);
384 else
385 free(info->data);
386 }
387 info->datalen = finfo->datasize;
388 if (finfo->datasize)
389 {
390 info->data = calloc(1, finfo->datasize);
391 if (!info->data)
392 {
393 o->filter = EVAS_FILTER_NONE;
394 return EINA_FALSE;
395 }
396 }
397 else
398 info->data = NULL;
399 info->data_free = NULL;
400
401 return EINA_TRUE;
402}
403
404EAPI Evas_Filter
405evas_object_filter_get(Evas_Object *o)
406{
407 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
408 return EVAS_FILTER_NONE;
409 MAGIC_CHECK_END();
410
411 if (!o->filter) return EVAS_FILTER_NONE;
412 return o->filter->filter;
413}
414
415EAPI Eina_Bool
416evas_object_filter_param_int_set(Evas_Object *o, const char *param, int val)
417{
418 char *data;
419 const struct fieldinfo *fields;
420 Eina_Bool found;
421 int i;
422
423 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
424 return EINA_FALSE;
425 MAGIC_CHECK_END();
426
427 if ((!o->filter) || (!o->filter->data)) return EINA_FALSE;
428
429 fields = filterfields[o->filter->filter];
430 data = o->filter->data;
431 found = EINA_FALSE;
432 for (i = 0; fields[i].field; i++)
433 {
434 if (!strcmp(fields[i].field, param))
435 {
436 if (fields[i].type != TYPE_INT) continue;
437 *(int *)(data + fields[i].offset) = val;
438 o->filter->dirty = 1;
439 evas_object_change(o);
440 found = EINA_TRUE;
441 }
442 }
443 return found;
444}
445
446EAPI int
447evas_object_filter_param_int_get(Evas_Object *o, const char *param)
448{
449 char *data;
450 const struct fieldinfo *fields;
451 int val;
452 int i;
453
454 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
455 return -1;
456 MAGIC_CHECK_END();
457
458 if ((!o->filter) || (!o->filter->data)) return -1;
459
460 fields = filterfields[o->filter->filter];
461 if (!fields) return -1;
462 data = o->filter->data;
463
464 for (i = 0; fields[i].field; i++)
465 {
466 if (!strcmp(fields[i].field, param))
467 {
468 if (fields[i].type != TYPE_INT) continue;
469 val = *(int *)(data + fields[i].offset);
470 return val;
471 }
472 }
473 return -1;
474}
475
476EAPI Eina_Bool
477evas_object_filter_param_str_set(Evas_Object *o __UNUSED__,
478 const char *param __UNUSED__,
479 const char *val __UNUSED__)
480{
481 return EINA_FALSE;
482}
483
484EAPI const char *
485evas_object_filter_param_str_get(Evas_Object *o __UNUSED__,
486 const char *param __UNUSED__)
487{
488 return NULL;
489}
490
491EAPI Eina_Bool
492evas_object_filter_param_obj_set(Evas_Object *o __UNUSED__,
493 const char *param __UNUSED__,
494 Evas_Object *val __UNUSED__)
495{
496 return EINA_FALSE;
497}
498
499EAPI Evas_Object *
500evas_object_filter_param_obj_get(Evas_Object *o __UNUSED__,
501 const char *param __UNUSED__)
502{
503 return NULL;
504}
505
506EAPI Eina_Bool
507evas_object_filter_param_float_set(Evas_Object *o, const char *param,
508 double val)
509{
510 char *data;
511 const struct fieldinfo *fields;
512 int i;
513 Eina_Bool rv;
514
515 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
516 return EINA_FALSE;
517 MAGIC_CHECK_END();
518
519 if ((!o->filter) || (!o->filter->data)) return EINA_FALSE;
520
521 rv = EINA_FALSE;
522 fields = filterfields[o->filter->filter];
523 if (!fields) return EINA_FALSE;
524
525 data = o->filter->data;
526
527 for (i = 0; fields[i].field; i++)
528 {
529 if (!strcmp(fields[i].field, param))
530 {
531 if (fields[i].type != TYPE_FLOAT) continue;
532 *(double *)(data + fields[i].offset) = val;
533 o->filter->dirty = 1;
534 o->changed = 1;
535 evas_object_change(o);
536 rv = EINA_TRUE;
537 }
538 }
539 return rv;
540}
541
542EAPI double
543evas_object_filter_param_float_get(Evas_Object *o, const char *param)
544{
545 char *data;
546 const struct fieldinfo *fields;
547 double val;
548 int i;
549
550 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
551 return -1;
552 MAGIC_CHECK_END();
553
554 if ((!o->filter) || (!o->filter->data)) return -1;
555
556 fields = filterfields[o->filter->filter];
557 if (!fields) return -1;
558 data = o->filter->data;
559
560 for (i = 0; fields[i].field; i++)
561 {
562 if (!strcmp(fields[i].field, param))
563 {
564 if (fields[i].type != TYPE_FLOAT) continue;
565 val = *(double *)(data + fields[i].offset);
566 return val;
567 }
568 }
569 return -1;
570}
571
572
573
574
575
576/*
577 * Internal call
578 */
579int
580evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
581 int *outw, int *outh, Eina_Bool inv)
582{
583 if (!info) return -1;
584 if ((!outw) && (!outh)) return 0;
585
586 if (filterinfo[info->filter].sizefn)
587 return filterinfo[info->filter].sizefn(info, inw, inh, outw, outh, inv);
588
589 if (outw) *outw = inw;
590 if (outh) *outh = inh;
591 return 0;
592}
593
594Eina_Bool
595evas_filter_always_alpha(Evas_Filter_Info *info)
596{
597 if (!info) return EINA_FALSE;
598 return filterinfo[info->filter].alwaysalpha;
599}
600
601/*
602 * Another internal call:
603 * Given a filterinfo, generate a unique key for it
604 *
605 * For simple filters, it's just the filter type.
606 * for more complex filters, it's the type, with it's params.
607 *
608 * Note management of the key data is up to the caller, that is it should
609 * probably be freed after use.
610 *
611 * Note the automatic fallback generation places the single byte at the end so
612 * the memcpy will be aligned. Micro-optimisations FTW!
613 *
614 * @param info Filter info to generate from
615 * @param len Length of the buffer returned.
616 * @return key Key buffer
617 */
618uint8_t *
619evas_filter_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
620{
621 struct filterinfo *finfo;
622 uint8_t *key;
623 int len;
624
625 if (!info) return NULL;
626
627 finfo = filterinfo + info->filter;
628 if (finfo->keyfn) return finfo->keyfn(info, lenp);
629
630 len = 1 + finfo->datasize;
631 key = malloc(len);
632 if (!key) return NULL;
633 if (finfo->datasize) memcpy(key, info->data, finfo->datasize);
634 key[finfo->datasize] = info->filter;
635 if (lenp) *lenp = len;
636 return key;
637}
638
639Evas_Software_Filter_Fn
640evas_filter_software_get(Evas_Filter_Info *info)
641{
642 return filterinfo[info->filter].filter;
643}
644
645void
646evas_filter_free(Evas_Object *o)
647{
648 if (!o->filter) return;
649 if (o->filter->key) free(o->filter->key);
650 free(o->filter);
651 o->filter = NULL;
652}
653
654
655
656
657/*
658 * Private calls
659 */
660static Evas_Filter_Info *
661filter_alloc(Evas_Object *o)
662{
663 Evas_Filter_Info *info;
664
665 if (!o) return NULL;
666 info = calloc(1,sizeof(struct Evas_Filter_Info));
667 if (!info) return NULL;
668 info->dirty = 1;
669 info->filter = EVAS_FILTER_NONE;
670 info->mode = EVAS_FILTER_MODE_OBJECT;
671 info->datalen = 0;
672
673 o->filter = info;
674
675 return info;
676}
677
678static int
679blur_size_get(Evas_Filter_Info *info, int inw, int inh, int *outw, int *outh,
680 Eina_Bool inv)
681{
682 Evas_Filter_Info_Blur *blur = info->data;
683
684 if (inv)
685 {
686 if (outw) *outw = MAX(inw - (blur->radius * 2), 0);
687 if (outh) *outh = MAX(inh - (blur->radius * 2), 0);
688 }
689 else
690 {
691 if (outw) *outw = inw + (blur->radius * 2);
692 if (outh) *outh = inh + (blur->radius * 2);
693 }
694 return 0;
695}
696
697/*
698 * Generate a key for the Gaussian generator.
699 *
700 * The size is:
701 * - 1 byte for the type (blur)
702 * - 1 byte for the quality (0-1 -> 0-255)
703 * - 2 bytes for radius (max is 508 anyway)
704 *
705 * @param info Filter info
706 * @param len Length of the returned buffer
707 * @return new buffer
708 */
709static uint8_t *
710gaussian_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
711{
712 struct Evas_Filter_Info_Blur *blur;
713 uint8_t *key;
714
715 if ((!info) || (!info->data)) return NULL;
716 blur = info->data;
717
718 if (lenp) *lenp = 4;
719 key = malloc(4);
720 if (!key) return NULL;
721 key[0] = EVAS_FILTER_BLUR;
722 key[1] = blur->quality * 255;
723 key[2] = blur->radius >> 8;
724 key[3] = blur->radius;
725
726 return key;
727}
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747/**
748 * Software implementations
749 */
750#define all(OP, A, R, G, B, W, I) \
751 do { \
752 A OP A_VAL(I) * W; \
753 R OP R_VAL(I) * W; \
754 G OP G_VAL(I) * W; \
755 B OP B_VAL(I) * W; \
756 } while (0)
757#define wavg(x,n) (((x) / (n)) & 0xff)
758#define wavgd(x,n) ((uint32_t)((x) / (n)) & 0xff)
759
760typedef int (*FilterH)(int, uint32_t *, int, uint32_t *);
761typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *);
762
763static int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out);
764static int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out);
765static int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out);
766static int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out);
767static int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out);
768static int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out);
769static const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight);
770static const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight);
771static const double *gaussian_row_getd(int row, int *npoints, double *weight);
772
773static Eina_Bool
774gaussian_filter(Evas_Filter_Info *filter, RGBA_Image *src, RGBA_Image *dst)
775{
776 int i;
777 uint32_t nw, nh;
778 uint32_t *in, *tmp, *out;
779 FilterV filter_v = gaussian_filter_v;
780 FilterH filter_h = gaussian_filter_h;
781 Evas_Filter_Info_Blur *blur;
782 int w, h;
783
784 blur = filter->data;
785
786 /* Use 64 bit version if we are going to overflow */
787 if (blur->radius > 508) /** too big for doubles: Bail out */
788 return EINA_FALSE;
789 else if (blur->radius > 28)
790 {
791 filter_v = gaussian_filter_vd;
792 filter_h = gaussian_filter_hd;
793 }
794 else if (blur->radius > 12)
795 {
796 filter_v = gaussian_filter_v64;
797 filter_h = gaussian_filter_h64;
798 }
799
800 w = src->cache_entry.w;
801 h = src->cache_entry.h;
802 in = src->image.data;
803
804 if (!in) return EINA_FALSE;
805
806 nw = w + (2 * blur->radius);
807 nh = h + (2 * blur->radius);
808
809 out = dst->image.data;
810 if (!out) return EINA_FALSE;
811 tmp = malloc(nw * h * sizeof(uint32_t));
812
813 for (i = 0; i < h; i++)
814 filter_h(blur->radius,in + (i * w), w, tmp + (i * nw));
815
816 for (i = 0; i < (int)nw; i++)
817 filter_v(blur->radius,tmp + i, h, nw, out + i);
818
819 free(tmp);
820 return EINA_TRUE;
821}
822
823/* Blur only horizontally */
824static int
825gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out)
826{
827 const uint32_t *points;
828 int npoints = 0;
829 uint32_t weight = 0;
830 int i = 0, k = 0;
831 uint32_t r, g, b, a;
832
833 /* Get twice the radius: even rows have 1 element */
834 points = gaussian_row_get(rad * 2, &npoints, &weight);
835 for (i = -rad; i < (w + rad); i++)
836 {
837 r = g = b = a = 0;
838 for (k = -rad; k <= rad; k++)
839 {
840 if ((k + i) < 0) continue;
841 if ((k + i) >= w) continue;
842 all(+=, a, r, g, b, points[k + rad], in + k + i);
843 }
844 *(out) = ARGB_JOIN(wavg(a, weight),
845 wavg(r, weight),
846 wavg(g, weight),
847 wavg(b, weight));
848 out++;
849 }
850 return 0;
851}
852
853/* Blur only horizontally */
854static int
855gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out)
856{
857 const double *points;
858 int npoints = 0;
859 double weight = 0.0;
860 int i = 0, k = 0;
861 double r, g, b, a;
862
863 /* Get twice the radius: even rows have 1 element */
864 points = gaussian_row_getd(rad * 2, &npoints, &weight);
865 for (i = -rad; i < (w + rad); i++)
866 {
867 r = g = b = a = 0;
868 for (k = -rad; k <= rad; k++)
869 {
870 if ((k + i) < 0) continue;
871 if ((k + i) >= w) continue;
872 all(+=, a, r, g, b, points[k + rad], in + k + i);
873 }
874 *(out) = ARGB_JOIN(wavgd(a, weight),
875 wavgd(r, weight),
876 wavgd(g, weight),
877 wavgd(b, weight));
878 out++;
879 }
880 return 0;
881}
882
883
884/* Blur only horizontally */
885static int
886gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out)
887{
888 const uint64_t *points;
889 int npoints = 0;
890 uint64_t weight = 0;
891 int i = 0, k = 0;
892 uint64_t r, g, b, a;
893
894 /* Get twice the radius: even rows have 1 element */
895 points = gaussian_row_get64(rad * 2, &npoints, &weight);
896 for (i = -rad ; i < w + rad; i ++){
897 r = g = b = a = 0;
898 for (k = -rad ; k <= rad ; k ++){
899 if ((k + i) < 0) continue;
900 if ((k + i) >= w) continue;
901 all(+=, a, r, g, b, points[k + rad], in + k + i);
902 }
903 *(out) = ARGB_JOIN(wavg(a, weight),
904 wavg(r, weight),
905 wavg(g, weight),
906 wavg(b, weight));
907 out++;
908 }
909 return 0;
910}
911
912static int
913gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out)
914{
915 const uint32_t *points;
916 int npoints = 0;
917 uint32_t weight = 0;
918 int i = 0, k = 0;
919 uint32_t r, g, b, a;
920
921 /* Get twice the radius: even rows have 1 element */
922 points = gaussian_row_get(rad * 2, &npoints, &weight);
923 weight = 0;
924 for (i = 0; i < npoints; i++) weight += points[i];
925
926 for (i = -rad; i < (h + rad); i++)
927 {
928 r = g = b = a = 0;
929 for (k = -rad; k <= rad; k++)
930 {
931 if ((k + i) < 0) continue;
932 if ((k + i) >= h) continue;
933 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
934 }
935 *(out) = ARGB_JOIN(wavg(a, weight),
936 wavg(r, weight),
937 wavg(g, weight),
938 wavg(b, weight));
939 out += skip;
940 }
941 return 0;
942}
943
944static int
945gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out)
946{
947 const uint64_t *points;
948 int npoints = 0;
949 uint64_t weight;
950 int i = 0, k = 0;
951 uint64_t r, g, b, a;
952
953 /* Get twice the radius: even rows have 1 element */
954 points = gaussian_row_get64(rad * 2, &npoints, &weight);
955 weight = 0;
956 for (i = 0; i < npoints; i++) weight += points[i];
957
958 for (i = -rad; i < (h + rad); i++)
959 {
960 r = g = b = a = 0;
961 for (k = -rad ; k <= rad ; k++)
962 {
963 if ((k + i) < 0) continue;
964 if ((k + i) >= h) continue;
965 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
966 }
967 *(out) = ARGB_JOIN(wavg(a, weight),
968 wavg(r, weight),
969 wavg(g, weight),
970 wavg(b, weight));
971 out += skip;
972 }
973 return 0;
974}
975
976static int
977gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out)
978{
979 const double *points;
980 int npoints = 0;
981 double weight = 0.0;
982 int i = 0, k = 0;
983 double r, g, b, a;
984
985 /* Get twice the radius: even rows have 1 element */
986 points = gaussian_row_getd(rad * 2, &npoints, &weight);
987 weight = 0;
988 for (i = 0 ; i < npoints ; i ++) weight += points[i];
989
990 for (i = -rad ; i < h + rad; i ++)
991 {
992 r = g = b = a = 0;
993 for (k = -rad ; k <= rad ; k ++)
994 {
995 if ((k + i) < 0) continue;
996 if ((k + i) >= h) continue;
997 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
998 }
999 *(out) = ARGB_JOIN(wavgd(a, weight),
1000 wavgd(r, weight),
1001 wavgd(g, weight),
1002 wavgd(b, weight));
1003 out += skip;
1004 }
1005 return 0;
1006}
1007
1008static const uint32_t *
1009gaussian_row_get(int row, int *npoints, uint32_t *weight)
1010{
1011 static uint32_t *points = NULL;
1012 static int last = -1;
1013 static uint32_t lastweight = -1;
1014 int c, k;
1015
1016 if (row < 0) return NULL;
1017
1018 if (npoints) *npoints = row + 1;
1019
1020 if (last == row)
1021 {
1022 if (weight) *weight = lastweight;
1023 return points;
1024 }
1025 if (points) free(points);
1026
1027 points = malloc((row + 1) * sizeof(uint32_t));
1028 if (!points)
1029 {
1030 last = -1;
1031 return NULL;
1032 }
1033 last = row;
1034
1035 c = 1;
1036 for (k = 0; k <= row; k++)
1037 {
1038 points[k] = c;
1039 c = c * (row - k) / (k + 1);
1040 }
1041
1042 for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k];
1043 if (weight) *weight = lastweight;
1044 return points;
1045}
1046
1047static const uint64_t *
1048gaussian_row_get64(int row, int *npoints, uint64_t *weight)
1049{
1050 static uint64_t *points = NULL;
1051 static int last = -1;
1052 static uint64_t lastweight = -1;
1053 uint64_t c;
1054 int k;
1055
1056 if (row < 0) return NULL;
1057
1058 if (npoints) *npoints = row + 1;
1059 if (last == row)
1060 {
1061 if (weight) *weight = lastweight;
1062 return points;
1063 }
1064 if (points) free(points);
1065
1066 points = malloc((row + 1) * sizeof(uint64_t));
1067 if (!points)
1068 {
1069 last = -1;
1070 return NULL;
1071 }
1072 last = row;
1073
1074 c = 1;
1075 for (k = 0; k <= row; k++)
1076 {
1077 points[k] = c;
1078 c = c * (row - k) / (k + 1);
1079 }
1080
1081 for (k = 0, lastweight = 0; k <= row; k ++) lastweight += points[k];
1082 if (weight) *weight = lastweight;
1083
1084 return points;
1085}
1086
1087static const double *
1088gaussian_row_getd(int row, int *npoints, double *weight)
1089{
1090 static double *points = NULL;
1091 static int last = -1;
1092 static double lastweight = -1;
1093 double c;
1094 int k;
1095
1096 if (row < 0) return NULL;
1097
1098 if (last == row)
1099 {
1100 if (weight) *weight = lastweight;
1101 return points;
1102 }
1103
1104 if (points) free(points);
1105 points = malloc((row + 1) * sizeof(double));
1106 if (!points)
1107 {
1108 last = -1;
1109 return NULL;
1110 }
1111 last = row;
1112
1113 if (npoints) *npoints = row + 1;
1114
1115 c = 1;
1116 for (k = 0; k <= row; k++)
1117 {
1118 points[k] = c;
1119 c = c * (row - k) / (k + 1);
1120 }
1121
1122 for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k];
1123 if (weight) *weight = lastweight;
1124
1125 return points;
1126}
1127
1128#if BUILD_NEON0
1129static Eina_Bool
1130negation_filter_neon(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1131{
1132 uint32_t tmp;
1133
1134 if (src->cache_entry.flags.alpha)
1135 {
1136 // FIXME: not implemented
1137 }
1138 else
1139 {
1140 /* No alpha */
1141#define AP "NEG_FILTER_NA"
1142 asm volatile (
1143
1144 ".fpu neon \n\t"
1145 "vdup.u32 q14, $0xff000000 \n\t"
1146 "vmvn.u32 q15, q1 \n\t"
1147
1148 // fixme: do check for small loops
1149 AP"loopinit: \n\t"
1150 "sub %[tmp], %[e], #31 \n\t"
1151
1152 AP"loop: \n\t"
1153 "vldm %[s]!, {d0,d1,d2,d3} \n\t"
1154 "vand q2, q0, q15 \n\t"
1155 "vand q3, q1, q15 \n\t"
1156 "vand q4, q0, q14 \n\t"
1157 "vand q5, q1, q14 \n\t"
1158 // fixme: can i do this with xor
1159 "cmp %[tmp], %[s] \n\t"
1160
1161 "vmvn q6, q2 \n\t"
1162 "vmvn q7, q3 \n\t"
1163
1164 "vorr q0, q6,q4 \n\t"
1165 "vorr q1, q7,q5 \n\t"
1166
1167 "vstm %[d]!, {d0,d1,d2,d3} \n\t"
1168
1169 "bhi "AP"loop \n\t"
1170
1171 : // no out
1172 : // input
1173 [e] "r" (src->image.data+ src->cache_entry.w*src->cache_entry.h),
1174 [s] "r" (src->image.data),
1175 [tmp] "r" (tmp),
1176 [d] "r" (dst->image.data)
1177 : "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q14", "q15",
1178 "memory"
1179 );
1180#undef AP
1181 }
1182 return EINA_TRUE;
1183}
1184#endif
1185
1186static Eina_Bool
1187negation_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1188{
1189 uint32_t *in, *out;
1190 int i,j;
1191 int w,h;
1192 uint32_t a;
1193 uint8_t r,g,b;
1194
1195#if BUILD_NEON0
1196 if (evas_common_cpu_has_feature(CPU_FEATURE_NEON) &&
1197 (!src->cache_entry.flags.alpha))
1198 return negation_filter_neon(info, src, dst);
1199#endif
1200
1201 in = src->image.data;
1202 out = dst->image.data;
1203 w = src->cache_entry.w;
1204 h = src->cache_entry.h;
1205
1206 if (src->cache_entry.flags.alpha)
1207 {
1208 for (i = 0; i < h; i++)
1209 {
1210 for (j = 0; j < w; j++)
1211 {
1212 a = A_VAL(in);
1213 r = R_VAL(in);
1214 g = G_VAL(in);
1215 b = B_VAL(in);
1216 *out = ARGB_JOIN(a, a - r, a - g, a - b);
1217 out++;
1218 in++;
1219 }
1220 }
1221 }
1222 else
1223 {
1224 for (i = 0; i < h; i++)
1225 {
1226 for (j = 0; j < w; j++)
1227 {
1228 a = A_VAL(in);
1229 r = R_VAL(in);
1230 g = G_VAL(in);
1231 b = B_VAL(in);
1232 *out = ARGB_JOIN(a, ~r, ~g, ~b);
1233 out++;
1234 in++;
1235 }
1236 }
1237 }
1238 return EINA_TRUE;
1239 info = NULL;
1240}
1241
1242static Eina_Bool
1243sepia_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1244{
1245 uint32_t *in, *out;
1246 int i, j;
1247 int w, h;
1248 uint32_t a, r, g, b, nr, ng, nb;
1249
1250 in = src->image.data;
1251 out = dst->image.data;
1252 w = src->cache_entry.w;
1253 h = src->cache_entry.h;
1254
1255 for (i = 0; i < h; i++)
1256 {
1257 for (j = 0; j < w; j++)
1258 {
1259 a = A_VAL(in);
1260 r = R_VAL(in);
1261 g = G_VAL(in);
1262 b = B_VAL(in);
1263 nr = ((uint32_t)((r * 0.393) + (g * 0.769) + (b * 0.189)));
1264 ng = ((uint32_t)((r * 0.349) + (g * 0.686) + (b * 0.168)));
1265 nb = ((uint32_t)((r * 0.272) + (g * 0.534) + (b * 0.131)));
1266 if (nr > 255) nr = 255;
1267 if (ng > 255) ng = 255;
1268 if (nb > 255) nb = 255;
1269 *out = ARGB_JOIN(a, nr, ng, nb);
1270 out++;
1271 in++;
1272 }
1273 }
1274
1275 return EINA_TRUE;
1276
1277}
1278
1279static Eina_Bool
1280greyscale_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1281{
1282 uint32_t *in, *out;
1283 int i, j;
1284 int w, h;
1285 uint32_t cur;
1286 uint32_t a, r, g, b;
1287
1288 in = src->image.data;
1289 out = dst->image.data;
1290 w = src->cache_entry.w;
1291 h = src->cache_entry.h;
1292
1293 if (src->cache_entry.flags.alpha)
1294 {
1295 for (i = 0; i < h; i++)
1296 {
1297 for (j = 0; j < w; j++)
1298 {
1299 a = A_VAL(in);
1300 r = R_VAL(in);
1301 g = G_VAL(in);
1302 b = B_VAL(in);
1303 cur = (r * 0.3) + (g * 0.59) + (b * 0.11);
1304 *out = ARGB_JOIN(a, r, g, b);
1305 out++;
1306 in++;
1307 }
1308 }
1309 }
1310 else
1311 {
1312 for (i = 0 ; i < h ; i ++)
1313 {
1314 for (j = 0; j < w ; j ++)
1315 {
1316 r = R_VAL(in);
1317 g = G_VAL(in);
1318 b = B_VAL(in);
1319 cur = r * 0.3 + g * 0.59 + b * 0.11;
1320 *out = ARGB_JOIN(255, r, g, b);
1321 out++;
1322 in++;
1323 }
1324 }
1325 }
1326 return EINA_TRUE;
1327}
1328
1329static Eina_Bool
1330brightness_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1331{
1332 uint32_t *in, *out;
1333 int i, j;
1334 int w, h;
1335 int a,r,g,b;
1336 int delta;
1337 int adjdelta;
1338 Evas_Filter_Info_Brightness *bness;
1339
1340 in = src->image.data;
1341 out = dst->image.data;
1342 w = src->cache_entry.w;
1343 h = src->cache_entry.h;
1344 bness = info->data;
1345
1346 delta = bness->adjust * 255;
1347 if (delta > 255)
1348 delta = 255;
1349 else if (delta < -255)
1350 delta = -255;
1351
1352 /* Note we could optimise the -255, 0 and 255 cases, but why would people
1353 * be doing that */
1354 if (delta >= 0)
1355 {
1356 for (i = 0; i < h; i++)
1357 {
1358 for (j = 0; j < w; j++)
1359 {
1360 a = A_VAL(in);
1361 r = R_VAL(in);
1362 g = G_VAL(in);
1363 b = B_VAL(in);
1364 adjdelta = (a * delta) >> 8;
1365 r = MIN(r + adjdelta, a);
1366 g = MIN(g + adjdelta, a);
1367 b = MIN(b + adjdelta, a);
1368 *out = ARGB_JOIN(a, r ,g, b);
1369 out++;
1370 in++;
1371 }
1372 }
1373 }
1374 else
1375 {
1376 /* Delta negative */
1377 for (i = 0; i < h; i++)
1378 {
1379 for (j = 0; j < w; j++)
1380 {
1381 a = A_VAL(in);
1382 r = R_VAL(in);
1383 g = G_VAL(in);
1384 b = B_VAL(in);
1385 adjdelta = (a * delta) >> 8;
1386 r = MAX(r + adjdelta, 0);
1387 g = MAX(g + adjdelta, 0);
1388 b = MAX(b + adjdelta, 0);
1389 *out = ARGB_JOIN(a, r ,g, b);
1390 out++;
1391 in++;
1392 }
1393 }
1394 }
1395
1396 return EINA_TRUE;
1397
1398}
1399
1400static Eina_Bool
1401contrast_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1402{
1403 uint32_t *in, *out;
1404 int i, j;
1405 int w, h;
1406
1407 in = src->image.data;
1408 out = dst->image.data;
1409 w = src->cache_entry.w;
1410 h = src->cache_entry.h;
1411
1412 for (i = 0; i < h; i++)
1413 {
1414 for (j = 0; j < w; j++)
1415 {
1416 // FIXME: not even implemented
1417 out++;
1418 in++;
1419 }
1420 }
1421
1422 return EINA_TRUE;
1423
1424}
1425#endif
1426
1427/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
diff --git a/libraries/evas/src/lib/canvas/evas_focus.c b/libraries/evas/src/lib/canvas/evas_focus.c
new file mode 100644
index 0000000..a1a3bca
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_focus.c
@@ -0,0 +1,59 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private calls */
5
6/* local calls */
7
8/* public calls */
9
10EAPI void
11evas_object_focus_set(Evas_Object *obj, Eina_Bool focus)
12{
13 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
14 return;
15 MAGIC_CHECK_END();
16
17 _evas_object_event_new();
18
19 if (focus)
20 {
21 if (obj->focused) goto end;
22 if (obj->layer->evas->focused)
23 evas_object_focus_set(obj->layer->evas->focused, 0);
24 obj->focused = 1;
25 obj->layer->evas->focused = obj;
26 evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_IN, NULL);
27 evas_event_callback_call(obj->layer->evas,
28 EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, obj);
29 }
30 else
31 {
32 if (!obj->focused) goto end;
33 obj->focused = 0;
34 obj->layer->evas->focused = NULL;
35 evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_OUT, NULL);
36 evas_event_callback_call(obj->layer->evas,
37 EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, obj);
38 }
39 end:
40 _evas_post_event_callback_call(obj->layer->evas);
41}
42
43EAPI Eina_Bool
44evas_object_focus_get(const Evas_Object *obj)
45{
46 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
47 return 0;
48 MAGIC_CHECK_END();
49 return obj->focused;
50}
51
52EAPI Evas_Object *
53evas_focus_get(const Evas *e)
54{
55 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
56 return NULL;
57 MAGIC_CHECK_END();
58 return e->focused;
59}
diff --git a/libraries/evas/src/lib/canvas/evas_font_dir.c b/libraries/evas/src/lib/canvas/evas_font_dir.c
new file mode 100644
index 0000000..e97f7f7
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_font_dir.c
@@ -0,0 +1,1349 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#ifdef HAVE_EVIL
6# include <Evil.h>
7#endif
8
9#ifdef BUILD_FONT_LOADER_EET
10#include <Eet.h>
11#endif
12
13#ifdef HAVE_FONTCONFIG
14#include <fontconfig/fontconfig.h>
15#endif
16
17#include "evas_common.h"
18#include "evas_private.h"
19
20/* font dir cache */
21static Eina_Hash *font_dirs = NULL;
22static Eina_List *fonts_cache = NULL;
23static Eina_List *fonts_zero = NULL;
24
25typedef struct _Fndat Fndat;
26
27struct _Fndat
28{
29 Evas_Font_Description *fdesc;
30 const char *source;
31 Evas_Font_Size size;
32 Evas_Font_Set *font;
33 int ref;
34 Font_Rend_Flags wanted_rend;
35
36#ifdef HAVE_FONTCONFIG
37 FcFontSet *set;
38 FcPattern *p_nm;
39#endif
40};
41
42/* private methods for font dir cache */
43static Eina_Bool font_cache_dir_free(const Eina_Hash *hash, const void *key, void *data, void *fdata);
44static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd);
45static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font);
46static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font);
47static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font);
48static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font);
49static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir);
50static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd);
51static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]);
52
53#ifdef HAVE_FONTCONFIG
54static int fc_init = 0;
55#endif
56
57void
58evas_font_dir_cache_free(void)
59{
60 if (!font_dirs) return;
61
62 eina_hash_foreach(font_dirs, font_cache_dir_free, NULL);
63 eina_hash_free(font_dirs);
64 font_dirs = NULL;
65
66#ifdef HAVE_FONTCONFIG
67/* this is bad i got a:
68 * fccache.c:512: FcCacheFini: Assertion fcCacheChains[i] == ((void *)0)' failed.
69 *
70 * all i can do for now is shut this puppy down. butthat breaks, so disable
71 * it as in reality - there is little reason to care about the memory not
72 * being freed etc.
73 *
74 * fc_init--;
75 * if (fc_init == 0) FcFini();
76 */
77#endif
78}
79
80const char *
81evas_font_dir_cache_find(char *dir, char *font)
82{
83 Evas_Font_Dir *fd = NULL;
84
85 if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
86 else fd = eina_hash_find(font_dirs, dir);
87 fd = object_text_font_cache_dir_update(dir, fd);
88 if (fd)
89 {
90 Evas_Font *fn;
91
92 fn = object_text_font_cache_font_find(fd, font);
93 if (fn)
94 {
95 return fn->path;
96 }
97 }
98 return NULL;
99}
100
101static Eina_List *
102evas_font_set_get(const char *name)
103{
104 Eina_List *fonts = NULL;
105 char *p;
106
107 p = strchr(name, ',');
108 if (!p)
109 {
110 fonts = eina_list_append(fonts, eina_stringshare_add(name));
111 }
112 else
113 {
114 const char *pp;
115 char *nm;
116
117 pp = name;
118 while (p)
119 {
120 nm = alloca(p - pp + 1);
121 strncpy(nm, pp, p - pp);
122 nm[p - pp] = 0;
123 fonts = eina_list_append(fonts, eina_stringshare_add(nm));
124 pp = p + 1;
125 p = strchr(pp, ',');
126 if (!p) fonts = eina_list_append(fonts, eina_stringshare_add(pp));
127 }
128 }
129 return fonts;
130}
131
132void
133evas_fonts_zero_free(Evas *evas)
134{
135 Fndat *fd;
136
137 EINA_LIST_FREE(fonts_zero, fd)
138 {
139 if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
140 if (fd->source) eina_stringshare_del(fd->source);
141 evas->engine.func->font_free(evas->engine.data.output, fd->font);
142#ifdef HAVE_FONTCONFIG
143 if (fd->set) FcFontSetDestroy(fd->set);
144 if (fd->p_nm) FcPatternDestroy(fd->p_nm);
145#endif
146 free(fd);
147 }
148}
149
150void
151evas_fonts_zero_presure(Evas *evas)
152{
153 Fndat *fd;
154
155 while (fonts_zero
156 && eina_list_count(fonts_zero) > 4) /* 4 is arbitrary */
157 {
158 fd = eina_list_data_get(fonts_zero);
159
160 if (fd->ref != 0) break;
161 fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
162
163 if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
164 if (fd->source) eina_stringshare_del(fd->source);
165 evas->engine.func->font_free(evas->engine.data.output, fd->font);
166#ifdef HAVE_FONTCONFIG
167 if (fd->set) FcFontSetDestroy(fd->set);
168 if (fd->p_nm) FcPatternDestroy(fd->p_nm);
169#endif
170 free(fd);
171
172 if (eina_list_count(fonts_zero) < 5) break;
173 }
174}
175
176void
177evas_font_free(Evas *evas, void *font)
178{
179 Eina_List *l;
180 Fndat *fd;
181
182 EINA_LIST_FOREACH(fonts_cache, l, fd)
183 {
184 if (fd->font == font)
185 {
186 fd->ref--;
187 if (fd->ref == 0)
188 {
189 fonts_cache = eina_list_remove_list(fonts_cache, l);
190 fonts_zero = eina_list_append(fonts_zero, fd);
191 }
192 break;
193 }
194 }
195 while (fonts_zero
196 && eina_list_count(fonts_zero) > 42) /* 42 is arbitrary */
197 {
198 fd = eina_list_data_get(fonts_zero);
199
200 if (fd->ref != 0) break;
201 fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
202
203 if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
204 if (fd->source) eina_stringshare_del(fd->source);
205 evas->engine.func->font_free(evas->engine.data.output, fd->font);
206#ifdef HAVE_FONTCONFIG
207 if (fd->set) FcFontSetDestroy(fd->set);
208 if (fd->p_nm) FcPatternDestroy(fd->p_nm);
209#endif
210 free(fd);
211
212 if (eina_list_count(fonts_zero) < 43) break;
213 }
214}
215
216static void
217evas_font_init(void)
218{
219 static int done = 0;
220 if (done) return;
221 done = 1;
222#ifdef HAVE_FONTCONFIG
223 fc_init++;
224 if (fc_init == 1)
225 {
226 FcInit();
227 FcConfigEnableHome(1);
228 }
229#endif
230}
231
232#ifdef HAVE_FONTCONFIG
233static Evas_Font_Set *
234evas_load_fontconfig(Evas *evas, FcFontSet *set, int size,
235 Font_Rend_Flags wanted_rend)
236{
237 Evas_Font_Set *font = NULL;
238 int i;
239
240 /* Do loading for all in family */
241 for (i = 0; i < set->nfont; i++)
242 {
243 FcValue filename;
244
245 FcPatternGet(set->fonts[i], FC_FILE, 0, &filename);
246
247 if (font)
248 evas->engine.func->font_add(evas->engine.data.output, font, (char *)filename.u.s, size, wanted_rend);
249 else
250 font = evas->engine.func->font_load(evas->engine.data.output, (char *)filename.u.s, size, wanted_rend);
251 }
252
253 return font;
254}
255#endif
256
257#ifdef HAVE_FONTCONFIG
258/* In sync with Evas_Font_Style, Evas_Font_Weight and Evas_Font_Width */
259static int _fc_slant_map[] =
260{
261 FC_SLANT_ROMAN,
262 FC_SLANT_OBLIQUE,
263 FC_SLANT_ITALIC
264};
265
266static int _fc_weight_map[] =
267{
268 FC_WEIGHT_NORMAL,
269 FC_WEIGHT_THIN,
270 FC_WEIGHT_ULTRALIGHT,
271 FC_WEIGHT_LIGHT,
272 FC_WEIGHT_BOOK,
273 FC_WEIGHT_MEDIUM,
274 FC_WEIGHT_SEMIBOLD,
275 FC_WEIGHT_BOLD,
276 FC_WEIGHT_ULTRABOLD,
277 FC_WEIGHT_BLACK,
278 FC_WEIGHT_EXTRABLACK
279};
280
281# ifdef FC_WIDTH
282static int _fc_width_map[] =
283{
284 FC_WIDTH_NORMAL,
285 FC_WIDTH_ULTRACONDENSED,
286 FC_WIDTH_EXTRACONDENSED,
287 FC_WIDTH_CONDENSED,
288 FC_WIDTH_SEMICONDENSED,
289 FC_WIDTH_SEMIEXPANDED,
290 FC_WIDTH_EXPANDED,
291 FC_WIDTH_EXTRAEXPANDED,
292 FC_WIDTH_ULTRAEXPANDED
293};
294# endif
295
296#endif
297
298struct _Style_Map
299{
300 const char *name;
301 int type;
302};
303typedef struct _Style_Map Style_Map;
304
305static Style_Map _style_width_map[] =
306{
307 {"normal", EVAS_FONT_WIDTH_NORMAL},
308 {"ultracondensed", EVAS_FONT_WIDTH_ULTRACONDENSED},
309 {"extracondensed", EVAS_FONT_WIDTH_EXTRACONDENSED},
310 {"condensed", EVAS_FONT_WIDTH_CONDENSED},
311 {"semicondensed", EVAS_FONT_WIDTH_SEMICONDENSED},
312 {"semiexpanded", EVAS_FONT_WIDTH_SEMIEXPANDED},
313 {"expanded", EVAS_FONT_WIDTH_EXPANDED},
314 {"extraexpanded", EVAS_FONT_WIDTH_EXTRAEXPANDED},
315 {"ultraexpanded", EVAS_FONT_WIDTH_ULTRAEXPANDED},
316};
317
318static Style_Map _style_weight_map[] =
319{
320 {"normal", EVAS_FONT_WEIGHT_NORMAL},
321 {"thin", EVAS_FONT_WEIGHT_THIN},
322 {"ultralight", EVAS_FONT_WEIGHT_ULTRALIGHT},
323 {"light", EVAS_FONT_WEIGHT_LIGHT},
324 {"book", EVAS_FONT_WEIGHT_BOOK},
325 {"medium", EVAS_FONT_WEIGHT_MEDIUM},
326 {"semibold", EVAS_FONT_WEIGHT_SEMIBOLD},
327 {"bold", EVAS_FONT_WEIGHT_BOLD},
328 {"ultrabold", EVAS_FONT_WEIGHT_ULTRABOLD},
329 {"black", EVAS_FONT_WEIGHT_BLACK},
330 {"extrablack", EVAS_FONT_WEIGHT_EXTRABLACK}
331};
332
333static Style_Map _style_slant_map[] =
334{
335 {"normal", EVAS_FONT_SLANT_NORMAL},
336 {"oblique", EVAS_FONT_SLANT_OBLIQUE},
337 {"italic", EVAS_FONT_SLANT_ITALIC}
338};
339
340#define _STYLE_MAP_LEN(x) (sizeof(x) / sizeof(*(x)))
341/**
342 * @internal
343 * Find a certain attribute from the map in the style.
344 * @return the index of the found one.
345 */
346static int
347_evas_font_style_find_internal(const char *style, const char *style_end,
348 Style_Map _map[], size_t map_len)
349{
350 size_t i;
351 while (style < style_end)
352 {
353 for (i = 0 ; i < map_len ; i++)
354 {
355 size_t len;
356 const char *cur = _map[i].name;
357 len = strlen(cur);
358 if (!strncasecmp(style, cur, len) &&
359 (!cur[len] || (cur[len] == ' ')))
360 {
361 return _map[i].type;
362 }
363 }
364 style = strchr(style, ' ');
365 if (!style)
366 break;
367
368 while (*style && (*style == ' '))
369 style++;
370 }
371 return 0;
372}
373
374int
375evas_font_style_find(const char *start, const char *end,
376 Evas_Font_Style style)
377{
378#define _RET_STYLE(x) \
379 return _evas_font_style_find_internal(start, end, \
380 _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
381 switch (style)
382 {
383 case EVAS_FONT_STYLE_SLANT:
384 _RET_STYLE(slant);
385 case EVAS_FONT_STYLE_WEIGHT:
386 _RET_STYLE(weight);
387 case EVAS_FONT_STYLE_WIDTH:
388 _RET_STYLE(width);
389 default:
390 return 0;
391 }
392#undef _RET_STYLE
393}
394
395void
396evas_font_desc_unref(Evas_Font_Description *fdesc)
397{
398 if (--(fdesc->ref) == 0)
399 {
400 eina_stringshare_del(fdesc->name);
401 eina_stringshare_del(fdesc->fallbacks);
402 eina_stringshare_del(fdesc->lang);
403 free(fdesc);
404 }
405}
406
407Evas_Font_Description *
408evas_font_desc_ref(Evas_Font_Description *fdesc)
409{
410 fdesc->ref++;
411 return fdesc;
412}
413
414Evas_Font_Description *
415evas_font_desc_new(void)
416{
417 Evas_Font_Description *fdesc;
418 fdesc = calloc(1, sizeof(*fdesc));
419 fdesc->ref = 1;
420 fdesc->is_new = EINA_TRUE;
421
422 return fdesc;
423}
424
425Evas_Font_Description *
426evas_font_desc_dup(const Evas_Font_Description *fdesc)
427{
428 Evas_Font_Description *new;
429 new = evas_font_desc_new();
430 memcpy(new, fdesc, sizeof(*new));
431 new->ref = 1;
432 new->is_new = EINA_TRUE;
433 new->name = eina_stringshare_ref(new->name);
434
435 return new;
436}
437
438int
439evas_font_desc_cmp(const Evas_Font_Description *a,
440 const Evas_Font_Description *b)
441{
442 /* FIXME: Do actual comparison, i.e less than and bigger than. */
443 return !((a->name == b->name) && (a->weight == b->weight) &&
444 (a->slant == b->slant) && (a->width == b->width) &&
445 (a->lang == b->lang));
446}
447
448void
449evas_font_name_parse(Evas_Font_Description *fdesc, const char *name)
450{
451 const char *end;
452
453 end = strchr(name, ':');
454 if (!end)
455 eina_stringshare_replace(&(fdesc->name), name);
456 else
457 eina_stringshare_replace_length(&(fdesc->name), name, end - name);
458
459 while (end)
460 {
461 const char *tend;
462 name = end;
463 end = strchr(end + 1, ':');
464 if (!end)
465 tend = name + strlen(name);
466 else
467 tend = end;
468
469 if (!strncmp(name, ":style=", 7))
470 {
471#define _SET_STYLE(x) \
472 fdesc->x = _evas_font_style_find_internal(name + 7, tend, \
473 _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
474 _SET_STYLE(slant);
475 _SET_STYLE(weight);
476 _SET_STYLE(width);
477#undef _SET_STYLE
478 }
479 else if (!strncmp(name, ":lang=", 6))
480 {
481 const char *tmp = name + 6;
482 eina_stringshare_replace_length(&(fdesc->lang), tmp, tend - tmp);
483 }
484 }
485}
486
487void *
488evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Evas_Font_Size size)
489{
490#ifdef HAVE_FONTCONFIG
491 FcPattern *p_nm = NULL;
492 FcFontSet *set = NULL;
493#endif
494
495 Evas_Font_Set *font = NULL;
496 Eina_List *fonts, *l;
497 Fndat *fd;
498 char *nm;
499 Font_Rend_Flags wanted_rend = 0;
500
501 if (!fdesc) return NULL;
502 fdesc->is_new = EINA_FALSE;
503
504 if (fdesc->slant != EVAS_FONT_SLANT_NORMAL)
505 wanted_rend |= FONT_REND_SLANT;
506 if (fdesc->weight == EVAS_FONT_WEIGHT_BOLD)
507 wanted_rend |= FONT_REND_WEIGHT;
508
509 evas_font_init();
510
511 EINA_LIST_FOREACH(fonts_cache, l, fd)
512 {
513 if (!evas_font_desc_cmp(fdesc, fd->fdesc))
514 {
515 if (((!source) && (!fd->source)) ||
516 ((source) && (fd->source) && (!strcmp(source, fd->source))))
517 {
518 if ((size == fd->size) &&
519 (wanted_rend == fd->wanted_rend))
520 {
521 fonts_cache = eina_list_promote_list(fonts_cache, l);
522 fd->ref++;
523 return fd->font;
524 }
525#ifdef HAVE_FONTCONFIG
526 else if (fd->set && fd->p_nm)
527 {
528 font = evas_load_fontconfig(evas, fd->set, size,
529 wanted_rend);
530 goto on_find;
531 }
532#endif
533 }
534 }
535 }
536
537 EINA_LIST_FOREACH(fonts_zero, l, fd)
538 {
539 if (!evas_font_desc_cmp(fdesc, fd->fdesc))
540 {
541 if (((!source) && (!fd->source)) ||
542 ((source) && (fd->source) && (!strcmp(source, fd->source))))
543 {
544 if ((size == fd->size) &&
545 (wanted_rend == fd->wanted_rend))
546 {
547 fonts_zero = eina_list_remove_list(fonts_zero, l);
548 fonts_cache = eina_list_prepend(fonts_cache, fd);
549 fd->ref++;
550 return fd->font;
551 }
552#ifdef HAVE_FONTCONFIG
553 else if (fd->set && fd->p_nm)
554 {
555 font = evas_load_fontconfig(evas, fd->set, size,
556 wanted_rend);
557 goto on_find;
558 }
559#endif
560 }
561 }
562 }
563
564 fonts = evas_font_set_get(fdesc->name);
565 EINA_LIST_FOREACH(fonts, l, nm) /* Load each font in append */
566 {
567 if (l == fonts || !font) /* First iteration OR no font */
568 {
569#ifdef BUILD_FONT_LOADER_EET
570 if (source) /* Load Font from "eet" source */
571 {
572 Eet_File *ef;
573 char *fake_name;
574
575 fake_name = evas_file_path_join(source, nm);
576 if (fake_name)
577 {
578 font = evas->engine.func->font_load(evas->engine.data.output, fake_name, size, wanted_rend);
579 if (!font) /* Load from fake name failed, probably not cached */
580 {
581 /* read original!!! */
582 ef = eet_open(source, EET_FILE_MODE_READ);
583 if (ef)
584 {
585 void *fdata;
586 int fsize = 0;
587
588 fdata = eet_read(ef, nm, &fsize);
589 if ((fdata) && (fsize > 0))
590 {
591 font = evas->engine.func->font_memory_load(evas->engine.data.output, fake_name, size, fdata, fsize, wanted_rend);
592 free(fdata);
593 }
594 eet_close(ef);
595 }
596 }
597 free(fake_name);
598 }
599 }
600 if (!font) /* Source load failed */
601 {
602#endif
603 if (evas_file_path_is_full_path((char *)nm)) /* Try filename */
604 font = evas->engine.func->font_load(evas->engine.data.output, (char *)nm, size, wanted_rend);
605 else /* search font path */
606 {
607 Eina_List *ll;
608 char *dir;
609
610 EINA_LIST_FOREACH(evas->font_path, ll, dir)
611 {
612 const char *f_file;
613
614 f_file = evas_font_dir_cache_find(dir, (char *)nm);
615 if (f_file)
616 {
617 font = evas->engine.func->font_load(evas->engine.data.output, f_file, size, wanted_rend);
618 if (font) break;
619 }
620 }
621 }
622#ifdef BUILD_FONT_LOADER_EET
623 }
624#endif
625 }
626 else /* Base font loaded, append others */
627 {
628#ifdef BUILD_FONT_LOADER_EET
629 void *ok = NULL;
630
631 if (source)
632 {
633 Eet_File *ef;
634 char *fake_name;
635
636 fake_name = evas_file_path_join(source, nm);
637 if (fake_name)
638 {
639 /* FIXME: make an engine func */
640 if (!evas->engine.func->font_add(evas->engine.data.output, font, fake_name, size, wanted_rend))
641 {
642 /* read original!!! */
643 ef = eet_open(source, EET_FILE_MODE_READ);
644 if (ef)
645 {
646 void *fdata;
647 int fsize = 0;
648
649 fdata = eet_read(ef, nm, &fsize);
650 if ((fdata) && (fsize > 0))
651 {
652 ok = evas->engine.func->font_memory_add(evas->engine.data.output, font, fake_name, size, fdata, fsize, wanted_rend);
653 free(fdata);
654 }
655 eet_close(ef);
656 }
657 }
658 else
659 ok = (void *)1;
660 free(fake_name);
661 }
662 }
663 if (!ok)
664 {
665#endif
666 if (evas_file_path_is_full_path((char *)nm))
667 evas->engine.func->font_add(evas->engine.data.output, font, (char *)nm, size, wanted_rend);
668 else
669 {
670 Eina_List *ll;
671 char *dir;
672
673 EINA_LIST_FOREACH(evas->font_path, ll, dir)
674 {
675 const char *f_file;
676
677 f_file = evas_font_dir_cache_find(dir, (char *)nm);
678 if (f_file)
679 {
680 if (evas->engine.func->font_add(evas->engine.data.output, font, f_file, size, wanted_rend))
681 break;
682 }
683 }
684 }
685#ifdef BUILD_FONT_LOADER_EET
686 }
687#endif
688 }
689 eina_stringshare_del(nm);
690 }
691 fonts = eina_list_free(fonts);
692
693#ifdef HAVE_FONTCONFIG
694 if (!font) /* Search using fontconfig */
695 {
696 FcResult res;
697
698 p_nm = FcPatternBuild (NULL,
699 FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight],
700 FC_SLANT, FcTypeInteger, _fc_slant_map[fdesc->slant],
701#ifdef FC_WIDTH
702 FC_WIDTH, FcTypeInteger, _fc_width_map[fdesc->width],
703#endif
704 NULL);
705 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name);
706
707 /* Handle font fallbacks */
708 if (fdesc->fallbacks)
709 {
710 while (1)
711 {
712 const char *start, *end;
713 start = fdesc->fallbacks;
714 end = strchr(start, ',');
715 if (end)
716 {
717 char *tmp = alloca((end - start) + 1);
718 strncpy(tmp, start, end - start);
719 tmp[end - start] = 0;
720 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) tmp);
721 }
722 else
723 {
724 FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) start);
725 break;
726 }
727 }
728 }
729
730 if (fdesc->lang)
731 FcPatternAddString (p_nm, FC_LANG, (FcChar8 *) fdesc->lang);
732
733 FcConfigSubstitute(NULL, p_nm, FcMatchPattern);
734 FcDefaultSubstitute(p_nm);
735
736 /* do matching */
737 set = FcFontSort(NULL, p_nm, FcTrue, NULL, &res);
738 if (!set)
739 {
740 ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name);
741 FcPatternDestroy(p_nm);
742 p_nm = NULL;
743 }
744 else
745 {
746 font = evas_load_fontconfig(evas, set, size, wanted_rend);
747 }
748 }
749#endif
750
751#ifdef HAVE_FONTCONFIG
752 on_find:
753#endif
754 fd = calloc(1, sizeof(Fndat));
755 if (fd)
756 {
757 fd->fdesc = evas_font_desc_ref(fdesc);
758 if (source) fd->source = eina_stringshare_add(source);
759 fd->font = font;
760 fd->wanted_rend = wanted_rend;
761 fd->size = size;
762 fd->ref = 1;
763 fonts_cache = eina_list_prepend(fonts_cache, fd);
764#ifdef HAVE_FONTCONFIG
765 fd->set = set;
766 fd->p_nm = p_nm;
767#endif
768 }
769
770 if (font)
771 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
772 evas->hinting);
773 return font;
774}
775
776void
777evas_font_load_hinting_set(Evas *evas, void *font, int hinting)
778{
779 evas->engine.func->font_hinting_set(evas->engine.data.output, font,
780 hinting);
781}
782
783Eina_List *
784evas_font_dir_available_list(const Evas *evas)
785{
786 Eina_List *l;
787 Eina_List *ll;
788 Eina_List *available = NULL;
789 char *dir;
790
791#ifdef HAVE_FONTCONFIG
792 /* Add font config fonts */
793 FcPattern *p;
794 FcFontSet *set = NULL;
795 FcObjectSet *os;
796 int i;
797
798 evas_font_init();
799
800 p = FcPatternCreate();
801 os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
802
803 if (p && os) set = FcFontList(NULL, p, os);
804
805 if (p) FcPatternDestroy(p);
806 if (os) FcObjectSetDestroy(os);
807
808 if (set)
809 {
810 for (i = 0; i < set->nfont; i++)
811 {
812 char *font;
813
814 font = (char *)FcNameUnparse(set->fonts[i]);
815 available = eina_list_append(available, eina_stringshare_add(font));
816 free(font);
817 }
818
819 FcFontSetDestroy(set);
820 }
821#endif
822
823 /* Add fonts in evas font_path*/
824 if (!evas->font_path)
825 return available;
826
827 if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL);
828
829 EINA_LIST_FOREACH(evas->font_path, l, dir)
830 {
831 Evas_Font_Dir *fd;
832
833 fd = eina_hash_find(font_dirs, dir);
834 fd = object_text_font_cache_dir_update(dir, fd);
835 if (fd && fd->aliases)
836 {
837 Evas_Font_Alias *fa;
838
839 EINA_LIST_FOREACH(fd->aliases, ll, fa)
840 available = eina_list_append(available, eina_stringshare_add((char *)fa->alias));
841 }
842 }
843
844 return available;
845}
846
847void
848evas_font_dir_available_list_free(Eina_List *available)
849{
850 while (available)
851 {
852 eina_stringshare_del(available->data);
853 available = eina_list_remove(available, available->data);
854 }
855}
856
857/* private stuff */
858static Eina_Bool
859font_cache_dir_free(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata __UNUSED__)
860{
861 object_text_font_cache_dir_del((char *) key, data);
862 return 1;
863}
864
865static Evas_Font_Dir *
866object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd)
867{
868 DATA64 mt;
869 char *tmp;
870
871 if (fd)
872 {
873 mt = evas_file_modified_time(dir);
874 if (mt != fd->dir_mod_time)
875 {
876 object_text_font_cache_dir_del(dir, fd);
877 eina_hash_del(font_dirs, dir, fd);
878 }
879 else
880 {
881 tmp = evas_file_path_join(dir, "fonts.dir");
882 if (tmp)
883 {
884 mt = evas_file_modified_time(tmp);
885 free(tmp);
886 if (mt != fd->fonts_dir_mod_time)
887 {
888 object_text_font_cache_dir_del(dir, fd);
889 eina_hash_del(font_dirs, dir, fd);
890 }
891 else
892 {
893 tmp = evas_file_path_join(dir, "fonts.alias");
894 if (tmp)
895 {
896 mt = evas_file_modified_time(tmp);
897 free(tmp);
898 }
899 if (mt != fd->fonts_alias_mod_time)
900 {
901 object_text_font_cache_dir_del(dir, fd);
902 eina_hash_del(font_dirs, dir, fd);
903 }
904 else
905 return fd;
906 }
907 }
908 }
909 }
910 return object_text_font_cache_dir_add(dir);
911}
912
913static Evas_Font *
914object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font)
915{
916 Eina_List *l;
917 char font_prop[14][256];
918 int num;
919 Evas_Font *fn;
920
921 num = evas_object_text_font_string_parse(font, font_prop);
922 if (num != 14) return NULL;
923 EINA_LIST_FOREACH(fd->fonts, l, fn)
924 {
925 if (fn->type == 1)
926 {
927 int i;
928 int match = 0;
929
930 for (i = 0; i < 14; i++)
931 {
932 if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0))
933 match++;
934 else
935 {
936 if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++;
937 else break;
938 }
939 }
940 if (match == 14) return fn;
941 }
942 }
943 return NULL;
944}
945
946static Evas_Font *
947object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font)
948{
949 Eina_List *l;
950 Evas_Font *fn;
951
952 EINA_LIST_FOREACH(fd->fonts, l, fn)
953 {
954 if (fn->type == 0)
955 {
956 if (!strcasecmp(font, fn->simple.name)) return fn;
957 }
958 }
959 return NULL;
960}
961
962static Evas_Font *
963object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font)
964{
965 Eina_List *l;
966 Evas_Font_Alias *fa;
967
968 EINA_LIST_FOREACH(fd->aliases, l, fa)
969 if (!strcasecmp(fa->alias, font)) return fa->fn;
970 return NULL;
971}
972
973static Evas_Font *
974object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font)
975{
976 Evas_Font *fn;
977
978 fn = eina_hash_find(fd->lookup, font);
979 if (fn) return fn;
980 fn = object_text_font_cache_font_find_alias(fd, font);
981 if (!fn) fn = object_text_font_cache_font_find_x(fd, font);
982 if (!fn) fn = object_text_font_cache_font_find_file(fd, font);
983 if (!fn) return NULL;
984 eina_hash_add(fd->lookup, font, fn);
985 return fn;
986}
987
988static Evas_Font_Dir *
989object_text_font_cache_dir_add(char *dir)
990{
991 Evas_Font_Dir *fd;
992 char *tmp, *tmp2;
993 Eina_List *fdir;
994 Evas_Font *fn;
995
996 fd = calloc(1, sizeof(Evas_Font_Dir));
997 if (!fd) return NULL;
998 fd->lookup = eina_hash_string_superfast_new(NULL);
999
1000 eina_hash_add(font_dirs, dir, fd);
1001
1002 /* READ fonts.alias, fonts.dir and directory listing */
1003
1004 /* fonts.dir */
1005 tmp = evas_file_path_join(dir, "fonts.dir");
1006 if (tmp)
1007 {
1008 FILE *f;
1009
1010 f = fopen(tmp, "rb");
1011 if (f)
1012 {
1013 int num;
1014 char fname[4096], fdef[4096];
1015
1016 if (fscanf(f, "%i\n", &num) != 1) goto cant_read;
1017 /* read font lines */
1018 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
1019 {
1020 char font_prop[14][256];
1021 int i;
1022
1023 /* skip comments */
1024 if ((fdef[0] == '!') || (fdef[0] == '#')) continue;
1025 /* parse font def */
1026 num = evas_object_text_font_string_parse((char *)fdef, font_prop);
1027 if (num == 14)
1028 {
1029 fn = calloc(1, sizeof(Evas_Font));
1030 if (fn)
1031 {
1032 fn->type = 1;
1033 for (i = 0; i < 14; i++)
1034 fn->x.prop[i] = eina_stringshare_add(font_prop[i]);
1035 tmp2 = evas_file_path_join(dir, fname);
1036 if (tmp2)
1037 {
1038 fn->path = eina_stringshare_add(tmp2);
1039 free(tmp2);
1040 }
1041 fd->fonts = eina_list_append(fd->fonts, fn);
1042 }
1043 }
1044 }
1045 cant_read: ;
1046 fclose(f);
1047 }
1048 free(tmp);
1049 }
1050
1051 /* directoy listing */
1052 fdir = evas_file_path_list(dir, "*.ttf", 0);
1053 while (fdir)
1054 {
1055 tmp = evas_file_path_join(dir, fdir->data);
1056 if (tmp)
1057 {
1058 fn = calloc(1, sizeof(Evas_Font));
1059 if (fn)
1060 {
1061 char *p;
1062
1063 fn->type = 0;
1064 tmp2 = alloca(strlen(fdir->data) + 1);
1065 strcpy(tmp2, fdir->data);
1066 p = strrchr(tmp2, '.');
1067 if (p) *p = 0;
1068 fn->simple.name = eina_stringshare_add(tmp2);
1069 tmp2 = evas_file_path_join(dir, fdir->data);
1070 if (tmp2)
1071 {
1072 fn->path = eina_stringshare_add(tmp2);
1073 free(tmp2);
1074 }
1075 fd->fonts = eina_list_append(fd->fonts, fn);
1076 }
1077 free(tmp);
1078 }
1079 free(fdir->data);
1080 fdir = eina_list_remove(fdir, fdir->data);
1081 }
1082
1083 /* fonts.alias */
1084 tmp = evas_file_path_join(dir, "fonts.alias");
1085 if (tmp)
1086 {
1087 FILE *f;
1088
1089 f = fopen(tmp, "rb");
1090 if (f)
1091 {
1092 char fname[4096], fdef[4096];
1093
1094 /* read font alias lines */
1095 while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2)
1096 {
1097 Evas_Font_Alias *fa;
1098
1099 /* skip comments */
1100 if ((fname[0] == '!') || (fname[0] == '#')) continue;
1101 fa = calloc(1, sizeof(Evas_Font_Alias));
1102 if (fa)
1103 {
1104 fa->alias = eina_stringshare_add(fname);
1105 fa->fn = object_text_font_cache_font_find_x(fd, fdef);
1106 if ((!fa->alias) || (!fa->fn))
1107 {
1108 if (fa->alias) eina_stringshare_del(fa->alias);
1109 free(fa);
1110 }
1111 else
1112 fd->aliases = eina_list_append(fd->aliases, fa);
1113 }
1114 }
1115 fclose(f);
1116 }
1117 free(tmp);
1118 }
1119
1120 fd->dir_mod_time = evas_file_modified_time(dir);
1121 tmp = evas_file_path_join(dir, "fonts.dir");
1122 if (tmp)
1123 {
1124 fd->fonts_dir_mod_time = evas_file_modified_time(tmp);
1125 free(tmp);
1126 }
1127 tmp = evas_file_path_join(dir, "fonts.alias");
1128 if (tmp)
1129 {
1130 fd->fonts_alias_mod_time = evas_file_modified_time(tmp);
1131 free(tmp);
1132 }
1133
1134 return fd;
1135}
1136
1137static void
1138object_text_font_cache_dir_del(char *dir __UNUSED__, Evas_Font_Dir *fd)
1139{
1140 if (fd->lookup) eina_hash_free(fd->lookup);
1141 while (fd->fonts)
1142 {
1143 Evas_Font *fn;
1144 int i;
1145
1146 fn = fd->fonts->data;
1147 fd->fonts = eina_list_remove(fd->fonts, fn);
1148 for (i = 0; i < 14; i++)
1149 {
1150 if (fn->x.prop[i]) eina_stringshare_del(fn->x.prop[i]);
1151 }
1152 if (fn->simple.name) eina_stringshare_del(fn->simple.name);
1153 if (fn->path) eina_stringshare_del(fn->path);
1154 free(fn);
1155 }
1156 while (fd->aliases)
1157 {
1158 Evas_Font_Alias *fa;
1159
1160 fa = fd->aliases->data;
1161 fd->aliases = eina_list_remove(fd->aliases, fa);
1162 if (fa->alias) eina_stringshare_del(fa->alias);
1163 free(fa);
1164 }
1165 free(fd);
1166}
1167
1168static int
1169evas_object_text_font_string_parse(char *buffer, char dest[14][256])
1170{
1171 char *p;
1172 int n, m, i;
1173
1174 n = 0;
1175 m = 0;
1176 p = buffer;
1177 if (p[0] != '-') return 0;
1178 i = 1;
1179 while (p[i])
1180 {
1181 dest[n][m] = p[i];
1182 if ((p[i] == '-') || (m == 255))
1183 {
1184 dest[n][m] = 0;
1185 n++;
1186 m = -1;
1187 }
1188 i++;
1189 m++;
1190 if (n == 14) return n;
1191 }
1192 dest[n][m] = 0;
1193 n++;
1194 return n;
1195}
1196
1197EAPI void
1198evas_font_path_clear(Evas *e)
1199{
1200 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1201 return;
1202 MAGIC_CHECK_END();
1203 while (e->font_path)
1204 {
1205 eina_stringshare_del(e->font_path->data);
1206 e->font_path = eina_list_remove(e->font_path, e->font_path->data);
1207 }
1208}
1209
1210EAPI void
1211evas_font_path_append(Evas *e, const char *path)
1212{
1213 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1214 return;
1215 MAGIC_CHECK_END();
1216
1217 if (!path) return;
1218 e->font_path = eina_list_append(e->font_path, eina_stringshare_add(path));
1219}
1220
1221EAPI void
1222evas_font_path_prepend(Evas *e, const char *path)
1223{
1224 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1225 return;
1226 MAGIC_CHECK_END();
1227
1228 if (!path) return;
1229 e->font_path = eina_list_prepend(e->font_path, eina_stringshare_add(path));
1230}
1231
1232EAPI const Eina_List *
1233evas_font_path_list(const Evas *e)
1234{
1235 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1236 return NULL;
1237 MAGIC_CHECK_END();
1238 return e->font_path;
1239}
1240
1241static void
1242evas_font_object_rehint(Evas_Object *obj)
1243{
1244 if (obj->smart.smart)
1245 {
1246 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj)
1247 evas_font_object_rehint(obj);
1248 }
1249 else
1250 {
1251 if (!strcmp(obj->type, "text"))
1252 _evas_object_text_rehint(obj);
1253 if (!strcmp(obj->type, "textblock"))
1254 _evas_object_textblock_rehint(obj);
1255 }
1256}
1257
1258EAPI void
1259evas_font_hinting_set(Evas *e, Evas_Font_Hinting_Flags hinting)
1260{
1261 Evas_Layer *lay;
1262
1263 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1264 return;
1265 MAGIC_CHECK_END();
1266 if (e->hinting == hinting) return;
1267 e->hinting = hinting;
1268
1269 EINA_INLIST_FOREACH(e->layers, lay)
1270 {
1271 Evas_Object *obj;
1272
1273 EINA_INLIST_FOREACH(lay->objects, obj)
1274 evas_font_object_rehint(obj);
1275 }
1276}
1277
1278EAPI Evas_Font_Hinting_Flags
1279evas_font_hinting_get(const Evas *e)
1280{
1281 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1282 return EVAS_FONT_HINTING_BYTECODE;
1283 MAGIC_CHECK_END();
1284 return e->hinting;
1285}
1286
1287EAPI Eina_Bool
1288evas_font_hinting_can_hint(const Evas *e, Evas_Font_Hinting_Flags hinting)
1289{
1290 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1291 return 0;
1292 MAGIC_CHECK_END();
1293 if (e->engine.func->font_hinting_can_hint)
1294 return e->engine.func->font_hinting_can_hint(e->engine.data.output,
1295 hinting);
1296 return EINA_FALSE;
1297}
1298
1299EAPI void
1300evas_font_cache_flush(Evas *e)
1301{
1302 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1303 return;
1304 MAGIC_CHECK_END();
1305
1306 e->engine.func->font_cache_flush(e->engine.data.output);
1307}
1308
1309EAPI void
1310evas_font_cache_set(Evas *e, int size)
1311{
1312 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1313 return;
1314 MAGIC_CHECK_END();
1315
1316 if (size < 0) size = 0;
1317 e->engine.func->font_cache_set(e->engine.data.output, size);
1318}
1319
1320EAPI int
1321evas_font_cache_get(const Evas *e)
1322{
1323 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1324 return 0;
1325 MAGIC_CHECK_END();
1326
1327 return e->engine.func->font_cache_get(e->engine.data.output);
1328}
1329
1330EAPI Eina_List *
1331evas_font_available_list(const Evas *e)
1332{
1333 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1334 return NULL;
1335 MAGIC_CHECK_END();
1336
1337 return evas_font_dir_available_list(e);
1338}
1339
1340EAPI void
1341evas_font_available_list_free(Evas *e, Eina_List *available)
1342{
1343 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1344 return;
1345 MAGIC_CHECK_END();
1346
1347 evas_font_dir_available_list_free(available);
1348}
1349
diff --git a/libraries/evas/src/lib/canvas/evas_gl.c b/libraries/evas/src/lib/canvas/evas_gl.c
new file mode 100644
index 0000000..47bb583
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_gl.c
@@ -0,0 +1,245 @@
1/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
2#include "evas_common.h"
3#include "evas_private.h"
4#include "Evas_GL.h"
5
6struct _Evas_GL
7{
8 DATA32 magic;
9 Evas *evas;
10
11 Eina_List *contexts;
12 Eina_List *surfaces;
13};
14
15struct _Evas_GL_Context
16{
17 void *data;
18};
19
20struct _Evas_GL_Surface
21{
22 void *data;
23};
24
25EAPI Evas_GL *
26evas_gl_new(Evas *e)
27{
28 Evas_GL *evas_gl;
29
30 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
31 return NULL;
32 MAGIC_CHECK_END();
33
34 evas_gl = calloc(1, sizeof(Evas_GL));
35 if (!evas_gl) return NULL;
36
37 evas_gl->magic = MAGIC_EVAS_GL;
38 evas_gl->evas = e;
39
40 return evas_gl;
41}
42
43EAPI void
44evas_gl_free(Evas_GL *evas_gl)
45{
46 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
47 return;
48 MAGIC_CHECK_END();
49
50
51 // Delete undeleted surfaces
52 while (evas_gl->surfaces)
53 evas_gl_surface_destroy(evas_gl, evas_gl->surfaces->data);
54
55 // Delete undeleted contexts
56 while (evas_gl->contexts)
57 evas_gl_context_destroy(evas_gl, evas_gl->contexts->data);
58
59 evas_gl->magic = 0;
60 free(evas_gl);
61}
62
63EAPI Evas_GL_Surface *
64evas_gl_surface_create(Evas_GL *evas_gl, Evas_GL_Config *config, int width, int height)
65{
66 Evas_GL_Surface *surf;
67
68 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
69 return NULL;
70 MAGIC_CHECK_END();
71
72 if (!config)
73 {
74 ERR("Invalid Config\n");
75 return NULL;
76 }
77
78 surf = calloc(1, sizeof(Evas_GL_Surface));
79
80 surf->data = evas_gl->evas->engine.func->gl_surface_create(evas_gl->evas->engine.data.output, config, width, height);
81
82 if (!surf->data)
83 {
84 ERR("Failed creating a surface from the engine\n");
85 free(surf);
86 return NULL;
87 }
88
89 // Keep track of the surface creations
90 evas_gl->surfaces = eina_list_prepend(evas_gl->surfaces, surf);
91
92 return surf;
93}
94
95EAPI void
96evas_gl_surface_destroy(Evas_GL *evas_gl, Evas_GL_Surface *surf)
97{
98 // Magic
99 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
100 return;
101 MAGIC_CHECK_END();
102
103 if (!surf)
104 {
105 ERR("Trying to destroy a NULL surface pointer!\n");
106 return;
107 }
108
109 // Call Engine's Surface Destroy
110 evas_gl->evas->engine.func->gl_surface_destroy(evas_gl->evas->engine.data.output, surf->data);
111
112 // Remove it from the list
113 evas_gl->surfaces = eina_list_remove(evas_gl->surfaces, surf);
114
115 // Delete the object
116 free(surf);
117 surf = NULL;
118}
119
120EAPI Evas_GL_Context *
121evas_gl_context_create(Evas_GL *evas_gl, Evas_GL_Context *share_ctx)
122{
123 Evas_GL_Context *ctx;
124
125 // Magic
126 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
127 return NULL;
128 MAGIC_CHECK_END();
129
130 // Allocate a context object
131 ctx = calloc(1, sizeof(Evas_GL_Context));
132 if (!ctx)
133 {
134 ERR("Unable to create a Evas_GL_Context object\n");
135 return NULL;
136 }
137
138 // Call engine->gl_create_context
139 if (share_ctx)
140 {
141 ctx->data = evas_gl->evas->engine.func->gl_context_create(evas_gl->evas->engine.data.output, share_ctx->data);
142 }
143 else
144 {
145 ctx->data = evas_gl->evas->engine.func->gl_context_create(evas_gl->evas->engine.data.output, NULL);
146 }
147
148 // Set a few variables
149 if (!ctx->data)
150 {
151 ERR("Failed creating a context from the engine\n");
152 free(ctx);
153 return NULL;
154 }
155
156 // Keep track of the context creations
157 evas_gl->contexts = eina_list_prepend(evas_gl->contexts, ctx);
158
159 return ctx;
160
161}
162
163EAPI void
164evas_gl_context_destroy(Evas_GL *evas_gl, Evas_GL_Context *ctx)
165{
166
167 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
168 return;
169 MAGIC_CHECK_END();
170
171 if (!ctx)
172 {
173 ERR("Trying to destroy a NULL context pointer!\n");
174 return;
175 }
176
177 // Call Engine's destroy
178 evas_gl->evas->engine.func->gl_context_destroy(evas_gl->evas->engine.data.output, ctx->data);
179
180 // Remove it from the list
181 evas_gl->contexts = eina_list_remove(evas_gl->contexts, ctx);
182
183 // Delete the object
184 free(ctx);
185 ctx = NULL;
186}
187
188EAPI Eina_Bool
189evas_gl_make_current(Evas_GL *evas_gl, Evas_GL_Surface *surf, Evas_GL_Context *ctx)
190{
191 Eina_Bool ret;
192
193 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
194 return EINA_FALSE;
195 MAGIC_CHECK_END();
196
197 if ((!surf) || (!ctx))
198 ret = (Eina_Bool)evas_gl->evas->engine.func->gl_make_current(evas_gl->evas->engine.data.output, NULL, NULL);
199 else
200 ret = (Eina_Bool)evas_gl->evas->engine.func->gl_make_current(evas_gl->evas->engine.data.output, surf->data, ctx->data);
201
202 return ret;
203}
204
205EAPI const char *
206evas_gl_string_query(Evas_GL *evas_gl, int name)
207{
208 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
209 return EINA_FALSE;
210 MAGIC_CHECK_END();
211
212 return (const char *)evas_gl->evas->engine.func->gl_string_query(evas_gl->evas->engine.data.output, name);
213}
214
215EAPI Evas_GL_Func
216evas_gl_proc_address_get(Evas_GL *evas_gl, const char *name)
217{
218 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
219 return EINA_FALSE;
220 MAGIC_CHECK_END();
221
222 return (Evas_GL_Func)evas_gl->evas->engine.func->gl_proc_address_get(evas_gl->evas->engine.data.output, name);
223}
224
225EAPI Eina_Bool
226evas_gl_native_surface_get(Evas_GL *evas_gl, Evas_GL_Surface *surf, Evas_Native_Surface *ns)
227{
228 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
229 return EINA_FALSE;
230 MAGIC_CHECK_END();
231
232 return (Eina_Bool)evas_gl->evas->engine.func->gl_native_surface_get(evas_gl->evas->engine.data.output, surf->data, ns);
233}
234
235
236EAPI Evas_GL_API *
237evas_gl_api_get(Evas_GL *evas_gl)
238{
239 MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL);
240 return NULL;
241 MAGIC_CHECK_END();
242
243 return (Evas_GL_API*)evas_gl->evas->engine.func->gl_api_get(evas_gl->evas->engine.data.output);
244
245}
diff --git a/libraries/evas/src/lib/canvas/evas_key.c b/libraries/evas/src/lib/canvas/evas_key.c
new file mode 100644
index 0000000..f74ef34
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_key.c
@@ -0,0 +1,245 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private calls */
5
6static int
7evas_key_modifier_number(const Evas_Modifier *m, const char *keyname)
8{
9 int i;
10
11 for (i = 0; i < m->mod.count; i++)
12 {
13 if (!strcmp(m->mod.list[i], keyname)) return i;
14 }
15 return -1;
16}
17
18static int
19evas_key_lock_number(const Evas_Lock *l, const char *keyname)
20{
21 int i;
22
23 for (i = 0; i < l->lock.count; i++)
24 {
25 if (!strcmp(l->lock.list[i], keyname)) return i;
26 }
27 return -1;
28}
29
30/* local calls */
31
32/* public calls */
33
34EAPI const Evas_Modifier *
35evas_key_modifier_get(const Evas *e)
36{
37 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
38 return NULL;
39 MAGIC_CHECK_END();
40 return &(e->modifiers);
41}
42
43EAPI const Evas_Lock *
44evas_key_lock_get(const Evas *e)
45{
46 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
47 return NULL;
48 MAGIC_CHECK_END();
49 return &(e->locks);
50}
51
52EAPI Eina_Bool
53evas_key_modifier_is_set(const Evas_Modifier *m, const char *keyname)
54{
55 Evas_Modifier_Mask num;
56 int n;
57
58 if (!m) return 0;
59 if (!keyname) return 0;
60 n = evas_key_modifier_number(m, keyname);
61 if (n < 0) return 0;
62 num = (Evas_Modifier_Mask)n;
63 num = 1 << num;
64 if (m->mask & num) return 1;
65 return 0;
66}
67
68EAPI Eina_Bool
69evas_key_lock_is_set(const Evas_Lock *l, const char *keyname)
70{
71 Evas_Modifier_Mask num;
72 int n;
73
74 if (!l) return 0;
75 if (!keyname) return 0;
76 n = evas_key_lock_number(l, keyname);
77 if (n < 0) return 0;
78 num = (Evas_Modifier_Mask)n;
79 num = 1 << num;
80 if (l->mask & num) return 1;
81 return 0;
82}
83
84EAPI void
85evas_key_modifier_add(Evas *e, const char *keyname)
86{
87 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
88 return;
89 MAGIC_CHECK_END();
90 if (!keyname) return;
91 if (e->modifiers.mod.count >= 64) return;
92 evas_key_modifier_del(e, keyname);
93 e->modifiers.mod.count++;
94 e->modifiers.mod.list = realloc(e->modifiers.mod.list, e->modifiers.mod.count * sizeof(char *));
95 e->modifiers.mod.list[e->modifiers.mod.count - 1] = strdup(keyname);
96 e->modifiers.mask = 0;
97}
98
99EAPI void
100evas_key_modifier_del(Evas *e, const char *keyname)
101{
102 int i;
103
104 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
105 return;
106 MAGIC_CHECK_END();
107 if (!keyname) return;
108 for (i = 0; i < e->modifiers.mod.count; i++)
109 {
110 if (!strcmp(e->modifiers.mod.list[i], keyname))
111 {
112 int j;
113
114 free(e->modifiers.mod.list[i]);
115 e->modifiers.mod.count--;
116 for (j = i; j < e->modifiers.mod.count; j++)
117 e->modifiers.mod.list[j] = e->modifiers.mod.list[j + 1];
118 e->modifiers.mask = 0;
119 return;
120 }
121 }
122}
123
124EAPI void
125evas_key_lock_add(Evas *e, const char *keyname)
126{
127 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
128 return;
129 MAGIC_CHECK_END();
130 if (!keyname) return;
131 if (e->locks.lock.count >= 64) return;
132 evas_key_lock_del(e, keyname);
133 e->locks.lock.count++;
134 e->locks.lock.list = realloc(e->locks.lock.list, e->locks.lock.count * sizeof(char *));
135 e->locks.lock.list[e->locks.lock.count - 1] = strdup(keyname);
136 e->locks.mask = 0;
137}
138
139EAPI void
140evas_key_lock_del(Evas *e, const char *keyname)
141{
142 int i;
143
144 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
145 return;
146 MAGIC_CHECK_END();
147 if (!keyname) return;
148 e->locks.mask = 0;
149 for (i = 0; i < e->locks.lock.count; i++)
150 {
151 if (!strcmp(e->locks.lock.list[i], keyname))
152 {
153 int j;
154
155 free(e->locks.lock.list[i]);
156 e->locks.lock.count--;
157 for (j = i; j < e->locks.lock.count; j++)
158 e->locks.lock.list[j] = e->locks.lock.list[j + 1];
159 e->locks.mask = 0;
160 return;
161 }
162 }
163}
164
165EAPI void
166evas_key_modifier_on(Evas *e, const char *keyname)
167{
168 Evas_Modifier_Mask num;
169 int n;
170
171 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
172 return;
173 MAGIC_CHECK_END();
174 n = (Evas_Modifier_Mask)evas_key_modifier_number(&(e->modifiers), keyname);
175 if (n < 0) return;
176 num = (Evas_Modifier_Mask)n;
177 num = 1 << num;
178 e->modifiers.mask |= num;
179}
180
181EAPI void
182evas_key_modifier_off(Evas *e, const char *keyname)
183{
184 Evas_Modifier_Mask num;
185 int n;
186
187 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
188 return;
189 MAGIC_CHECK_END();
190 n = evas_key_modifier_number(&(e->modifiers), keyname);
191 if (n < 0) return;
192 num = (Evas_Modifier_Mask)n;
193 num = 1 << num;
194 e->modifiers.mask &= ~num;
195}
196
197EAPI void
198evas_key_lock_on(Evas *e, const char *keyname)
199{
200 Evas_Modifier_Mask num;
201 int n;
202
203 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
204 return;
205 MAGIC_CHECK_END();
206 n = evas_key_lock_number(&(e->locks), keyname);
207 if (n < 0) return;
208 num = (Evas_Modifier_Mask)n;
209 num = 1 << num;
210 e->locks.mask |= num;
211}
212
213EAPI void
214evas_key_lock_off(Evas *e, const char *keyname)
215{
216 Evas_Modifier_Mask num;
217 int n;
218
219 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
220 return;
221 MAGIC_CHECK_END();
222 n = evas_key_lock_number(&(e->locks), keyname);
223 if (n < 0) return;
224 num = (Evas_Modifier_Mask)n;
225 num = 1 << num;
226 e->locks.mask &= ~num;
227}
228
229/* errr need to add key grabbing/ungrabbing calls - missing modifier stuff. */
230
231EAPI Evas_Modifier_Mask
232evas_key_modifier_mask_get(const Evas *e, const char *keyname)
233{
234 Evas_Modifier_Mask num;
235 int n;
236
237 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
238 return 0;
239 MAGIC_CHECK_END();
240 if (!keyname) return 0;
241 n = evas_key_modifier_number(&(e->modifiers), keyname);
242 if (n < 0) return 0;
243 num = (Evas_Modifier_Mask)n;
244 return 1 << num;
245}
diff --git a/libraries/evas/src/lib/canvas/evas_key_grab.c b/libraries/evas/src/lib/canvas/evas_key_grab.c
new file mode 100644
index 0000000..3fc2172
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_key_grab.c
@@ -0,0 +1,179 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private calls */
5
6/* FIXME: this is not optimal, but works. i should have a hash of keys per */
7/* Evas and then a linked lists of grabs for that key and what */
8/* modifiers/not_modifers they use */
9
10static Evas_Key_Grab *evas_key_grab_new (Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive);
11static Evas_Key_Grab *evas_key_grab_find (Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive);
12
13static Evas_Key_Grab *
14evas_key_grab_new(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive)
15{
16 /* MEM OK */
17 Evas_Key_Grab *g;
18
19 g = evas_mem_calloc(sizeof(Evas_Key_Grab));
20 if (!g) return NULL;
21 g->object = obj;
22 g->modifiers = modifiers;
23 g->not_modifiers = not_modifiers;
24 g->exclusive = exclusive;
25 g->keyname = strdup(keyname);
26 if (obj->layer->evas->walking_grabs)
27 g->just_added = EINA_TRUE;
28 if (!g->keyname)
29 {
30 if (!evas_mem_free(strlen(keyname) + 1))
31 {
32 free(g);
33 return NULL;
34 }
35 g->keyname = strdup(keyname);
36 if (!g->keyname)
37 {
38 free(g);
39 return NULL;
40 }
41 }
42 g->object->grabs = eina_list_append(g->object->grabs, g);
43 if (eina_error_get())
44 {
45 MERR_BAD();
46 evas_mem_free(sizeof(Eina_List));
47 g->object->grabs = eina_list_append(g->object->grabs, g);
48 if (eina_error_get())
49 {
50 MERR_FATAL();
51 free(g->keyname);
52 free(g);
53 return NULL;
54 }
55 }
56 obj->layer->evas->grabs = eina_list_append(obj->layer->evas->grabs, g);
57 if (eina_error_get())
58 {
59 MERR_BAD();
60 evas_mem_free(sizeof(Eina_List));
61 obj->layer->evas->grabs = eina_list_append(obj->layer->evas->grabs, g);
62 if (eina_error_get())
63 {
64 MERR_FATAL();
65 g->object->grabs = eina_list_remove(g->object->grabs, g);
66 free(g->keyname);
67 free(g);
68 return NULL;
69 }
70 }
71 return g;
72}
73
74static Evas_Key_Grab *
75evas_key_grab_find(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive)
76{
77 /* MEM OK */
78 Eina_List *l;
79 Evas_Key_Grab *g;
80
81 EINA_LIST_FOREACH(obj->layer->evas->grabs, l, g)
82 {
83 if ((g->modifiers == modifiers) &&
84 (g->not_modifiers == not_modifiers) &&
85 (!strcmp(g->keyname, keyname)))
86 {
87 if ((exclusive) || (obj == g->object)) return g;
88 }
89 }
90 return NULL;
91}
92
93/* local calls */
94
95void
96evas_object_grabs_cleanup(Evas_Object *obj)
97{
98 if (obj->layer->evas->walking_grabs)
99 {
100 Eina_List *l;
101 Evas_Key_Grab *g;
102
103 EINA_LIST_FOREACH(obj->grabs, l, g)
104 g->delete_me = EINA_TRUE;
105 }
106 else
107 {
108 while (obj->grabs)
109 {
110 Evas_Key_Grab *g = obj->grabs->data;
111 if (g->keyname) free(g->keyname);
112 free(g);
113 obj->layer->evas->grabs = eina_list_remove(obj->layer->evas->grabs,
114 g);
115 obj->grabs = eina_list_remove(obj->grabs, g);
116 }
117 }
118}
119
120void
121evas_key_grab_free(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
122{
123 /* MEM OK */
124 Evas_Key_Grab *g;
125
126 g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers, 0);
127 if (!g) return;
128 g->object->grabs = eina_list_remove(g->object->grabs, g);
129 obj->layer->evas->grabs = eina_list_remove(obj->layer->evas->grabs, g);
130 if (g->keyname) free(g->keyname);
131 free(g);
132}
133
134/* public calls */
135
136EAPI Eina_Bool
137evas_object_key_grab(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive)
138{
139 /* MEM OK */
140 Evas_Key_Grab *g;
141
142 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
143 return EINA_FALSE;
144 MAGIC_CHECK_END();
145 if (!keyname) return EINA_FALSE;
146 if (exclusive)
147 {
148 g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers,
149 exclusive);
150 if (g) return EINA_FALSE;
151 }
152 g = evas_key_grab_new(obj, keyname, modifiers, not_modifiers, exclusive);
153 if (!g) return EINA_FALSE;
154 return EINA_TRUE;
155}
156
157EAPI void
158evas_object_key_ungrab(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers)
159{
160 /* MEM OK */
161 Evas_Key_Grab *g;
162
163 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
164 return;
165 MAGIC_CHECK_END();
166 if (!keyname) return;
167 g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers, 0);
168 if (!g) return;
169 if (g->object->layer->evas->walking_grabs)
170 {
171 if (!g->delete_me)
172 {
173 g->object->layer->evas->delete_grabs++;
174 g->delete_me = EINA_TRUE;
175 }
176 }
177 else
178 evas_key_grab_free(g->object, keyname, modifiers, not_modifiers);
179}
diff --git a/libraries/evas/src/lib/canvas/evas_layer.c b/libraries/evas/src/lib/canvas/evas_layer.c
new file mode 100644
index 0000000..54e9907
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_layer.c
@@ -0,0 +1,193 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4static void _evas_layer_free(Evas_Layer *lay);
5
6void
7evas_object_inject(Evas_Object *obj, Evas *e)
8{
9 Evas_Layer *lay;
10
11 if (obj->in_layer) return;
12 lay = evas_layer_find(e, obj->cur.layer);
13 if (!lay)
14 {
15 lay = evas_layer_new(e);
16 lay->layer = obj->cur.layer;
17 evas_layer_add(lay);
18 }
19 lay->objects = (Evas_Object *)eina_inlist_append(EINA_INLIST_GET(lay->objects), EINA_INLIST_GET(obj));
20 lay->usage++;
21 obj->layer = lay;
22 obj->in_layer = 1;
23}
24
25void
26evas_object_release(Evas_Object *obj, int clean_layer)
27{
28 if (!obj->in_layer) return;
29 obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects), EINA_INLIST_GET(obj));
30 obj->layer->usage--;
31 if (clean_layer)
32 {
33 if (obj->layer->usage <= 0)
34 {
35 evas_layer_del(obj->layer);
36 _evas_layer_free(obj->layer);
37 }
38 }
39 obj->layer = NULL;
40 obj->in_layer = 0;
41}
42
43Evas_Layer *
44evas_layer_new(Evas *e)
45{
46 Evas_Layer *lay;
47
48 lay = calloc(1, sizeof(Evas_Layer));
49 if (!lay) return NULL;
50 lay->evas = e;
51 return lay;
52}
53
54static void
55_evas_layer_free(Evas_Layer *lay)
56{
57 free(lay);
58}
59
60void
61evas_layer_pre_free(Evas_Layer *lay)
62{
63 Evas_Object *obj;
64
65 EINA_INLIST_FOREACH(lay->objects, obj)
66 {
67 if ((!obj->smart.parent) && (!obj->delete_me))
68 evas_object_del(obj);
69 }
70}
71
72void
73evas_layer_free_objects(Evas_Layer *lay)
74{
75 while (lay->objects)
76 {
77 Evas_Object *obj;
78
79 obj = (Evas_Object *)lay->objects;
80 evas_object_free(obj, 0);
81 }
82}
83
84void
85evas_layer_clean(Evas *e)
86{
87 Evas_Layer *tmp;
88
89 while (e->layers)
90 {
91 tmp = e->layers;
92 evas_layer_del(tmp);
93 _evas_layer_free(tmp);
94 }
95}
96
97Evas_Layer *
98evas_layer_find(Evas *e, short layer_num)
99{
100 Evas_Layer *layer;
101
102 EINA_INLIST_FOREACH(e->layers, layer)
103 {
104 if (layer->layer == layer_num) return layer;
105 }
106 return NULL;
107}
108
109void
110evas_layer_add(Evas_Layer *lay)
111{
112 Evas_Layer *layer;
113
114 EINA_INLIST_FOREACH(lay->evas->layers, layer)
115 {
116 if (layer->layer > lay->layer)
117 {
118 lay->evas->layers = (Evas_Layer *)eina_inlist_prepend_relative(EINA_INLIST_GET(lay->evas->layers),
119 EINA_INLIST_GET(lay),
120 EINA_INLIST_GET(layer));
121 return;
122 }
123 }
124 lay->evas->layers = (Evas_Layer *)eina_inlist_append(EINA_INLIST_GET(lay->evas->layers), EINA_INLIST_GET(lay));
125}
126
127void
128evas_layer_del(Evas_Layer *lay)
129{
130 Evas *e;
131
132 e = lay->evas;
133 e->layers = (Evas_Layer *)eina_inlist_remove(EINA_INLIST_GET(e->layers), EINA_INLIST_GET(lay));
134}
135
136/* public functions */
137
138EAPI void
139evas_object_layer_set(Evas_Object *obj, short l)
140{
141 Evas *e;
142
143 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
144 return;
145 MAGIC_CHECK_END();
146 if (obj->delete_me) return;
147 if (evas_object_intercept_call_layer_set(obj, l)) return;
148 if (obj->smart.parent) return;
149 if (obj->cur.layer == l)
150 {
151 evas_object_raise(obj);
152 return;
153 }
154 e = obj->layer->evas;
155 evas_object_release(obj, 1);
156 obj->cur.layer = l;
157 evas_object_inject(obj, e);
158 obj->restack = 1;
159 evas_object_change(obj);
160 if (obj->clip.clipees)
161 {
162 evas_object_inform_call_restack(obj);
163 return;
164 }
165 evas_object_change(obj);
166 if (!obj->smart.smart)
167 {
168 if (evas_object_is_in_output_rect(obj,
169 obj->layer->evas->pointer.x,
170 obj->layer->evas->pointer.y, 1, 1) &&
171 obj->cur.visible)
172 if (eina_list_data_find(obj->layer->evas->pointer.object.in, obj))
173 evas_event_feed_mouse_move(obj->layer->evas,
174 obj->layer->evas->pointer.x,
175 obj->layer->evas->pointer.y,
176 obj->layer->evas->last_timestamp,
177 NULL);
178 }
179 evas_object_inform_call_restack(obj);
180}
181
182EAPI short
183evas_object_layer_get(const Evas_Object *obj)
184{
185 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
186 return 0;
187 MAGIC_CHECK_END();
188 if (obj->smart.parent)
189 {
190 return obj->smart.parent->cur.layer;
191 }
192 return obj->cur.layer;
193}
diff --git a/libraries/evas/src/lib/canvas/evas_main.c b/libraries/evas/src/lib/canvas/evas_main.c
new file mode 100644
index 0000000..0a37b2c
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_main.c
@@ -0,0 +1,671 @@
1#include "evas_common.h"
2#include "evas_private.h"
3#include "evas_cs.h"
4
5#ifdef LKDEBUG
6EAPI Eina_Bool lockdebug = EINA_FALSE;
7EAPI int lockmax = 0;
8#endif
9
10static int _evas_init_count = 0;
11int _evas_log_dom_global = -1;
12EAPI int
13evas_init(void)
14{
15 if (++_evas_init_count != 1)
16 return _evas_init_count;
17
18#ifdef LKDEBUG
19 if (getenv("EVAS_LOCK_DEBUG"))
20 {
21 lockdebug = EINA_TRUE;
22 lockmax = atoi(getenv("EVAS_LOCK_DEBUG"));
23 }
24#endif
25
26#ifdef HAVE_EVIL
27 if (!evil_init())
28 return --_evas_init_count;
29#endif
30
31 if (!eina_init())
32 goto shutdown_evil;
33
34 _evas_log_dom_global = eina_log_domain_register
35 ("evas_main", EVAS_DEFAULT_LOG_COLOR);
36 if (_evas_log_dom_global < 0)
37 {
38 EINA_LOG_ERR("Can not create a module log domain.");
39 goto shutdown_eina;
40 }
41
42 evas_module_init();
43#ifdef BUILD_ASYNC_EVENTS
44 if (!evas_async_events_init())
45 goto shutdown_module;
46#endif
47#ifdef EVAS_CSERVE
48 if (getenv("EVAS_CSERVE")) evas_cserve_init();
49#endif
50#ifdef BUILD_ASYNC_PRELOAD
51 _evas_preload_thread_init();
52#endif
53#ifdef EVAS_FRAME_QUEUING
54 evas_common_frameq_init();
55#endif
56
57 return _evas_init_count;
58
59#ifdef BUILD_ASYNC_EVENTS
60 shutdown_module:
61 evas_module_shutdown();
62 eina_log_domain_unregister(_evas_log_dom_global);
63#endif
64 shutdown_eina:
65 eina_shutdown();
66 shutdown_evil:
67#ifdef HAVE_EVIL
68 evil_shutdown();
69#endif
70
71 return --_evas_init_count;
72}
73
74EAPI int
75evas_shutdown(void)
76{
77 if (--_evas_init_count != 0)
78 return _evas_init_count;
79
80#ifdef EVAS_FRAME_QUEUING
81 if (evas_common_frameq_enabled())
82 {
83 evas_common_frameq_finish();
84 evas_common_frameq_destroy();
85 }
86#endif
87#ifdef BUILD_ASYNC_EVENTS
88 _evas_preload_thread_shutdown();
89#endif
90#ifdef EVAS_CSERVE
91 if (getenv("EVAS_CSERVE")) evas_cserve_shutdown();
92#endif
93#ifdef BUILD_ASYNC_EVENTS
94 evas_async_events_shutdown();
95#endif
96 evas_font_dir_cache_free();
97 evas_common_shutdown();
98 evas_module_shutdown();
99 eina_log_domain_unregister(_evas_log_dom_global);
100 eina_shutdown();
101#ifdef HAVE_EVIL
102 evil_shutdown();
103#endif
104
105 return _evas_init_count;
106}
107
108
109EAPI Evas *
110evas_new(void)
111{
112 Evas *e;
113
114 e = calloc(1, sizeof(Evas));
115 if (!e) return NULL;
116
117 e->magic = MAGIC_EVAS;
118 e->output.render_method = RENDER_METHOD_INVALID;
119 e->viewport.w = 1;
120 e->viewport.h = 1;
121 e->hinting = EVAS_FONT_HINTING_BYTECODE;
122 e->name_hash = eina_hash_string_superfast_new(NULL);
123 eina_clist_init(&e->calc_list);
124 eina_clist_init(&e->calc_done);
125
126#define EVAS_ARRAY_SET(E, Array) \
127 eina_array_step_set(&E->Array, sizeof (E->Array), 4096);
128
129 EVAS_ARRAY_SET(e, delete_objects);
130 EVAS_ARRAY_SET(e, active_objects);
131 EVAS_ARRAY_SET(e, restack_objects);
132 EVAS_ARRAY_SET(e, render_objects);
133 EVAS_ARRAY_SET(e, pending_objects);
134 EVAS_ARRAY_SET(e, obscuring_objects);
135 EVAS_ARRAY_SET(e, temporary_objects);
136 EVAS_ARRAY_SET(e, calculate_objects);
137 EVAS_ARRAY_SET(e, clip_changes);
138
139#undef EVAS_ARRAY_SET
140
141 return e;
142}
143
144EAPI void
145evas_free(Evas *e)
146{
147 Eina_Rectangle *r;
148 Evas_Coord_Touch_Point *touch_point;
149 Evas_Layer *lay;
150 int i;
151 int del;
152
153 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
154 return;
155 MAGIC_CHECK_END();
156
157#ifdef EVAS_FRAME_QUEUING
158 evas_common_frameq_flush();
159#endif
160
161 if (e->walking_list == 0) evas_render_idle_flush(e);
162
163 if (e->walking_list > 0) return;
164
165 if (e->callbacks)
166 {
167 if (e->callbacks->deletions_waiting) return;
168
169 e->callbacks->deletions_waiting = 0;
170 evas_event_callback_list_post_free(&e->callbacks->callbacks);
171 if (!e->callbacks->callbacks)
172 {
173 free(e->callbacks);
174 e->callbacks = NULL;
175 }
176
177 _evas_post_event_callback_free(e);
178 }
179
180 del = 1;
181 e->walking_list++;
182 e->cleanup = 1;
183 while (del)
184 {
185 del = 0;
186 EINA_INLIST_FOREACH(e->layers, lay)
187 {
188 Evas_Object *o;
189
190 evas_layer_pre_free(lay);
191
192 EINA_INLIST_FOREACH(lay->objects, o)
193 {
194 if ((o->callbacks) && (o->callbacks->walking_list))
195 {
196 /* Defer free */
197 e->delete_me = 1;
198 e->walking_list--;
199 return;
200 }
201 if (!o->delete_me)
202 del = 1;
203 }
204 }
205 }
206 EINA_INLIST_FOREACH(e->layers, lay)
207 evas_layer_free_objects(lay);
208 evas_layer_clean(e);
209
210 e->walking_list--;
211
212 evas_font_path_clear(e);
213 e->pointer.object.in = eina_list_free(e->pointer.object.in);
214
215 if (e->name_hash) eina_hash_free(e->name_hash);
216 e->name_hash = NULL;
217
218 EINA_LIST_FREE(e->damages, r)
219 eina_rectangle_free(r);
220 EINA_LIST_FREE(e->obscures, r)
221 eina_rectangle_free(r);
222
223 evas_fonts_zero_free(e);
224
225 evas_event_callback_all_del(e);
226 evas_event_callback_cleanup(e);
227
228 if (e->engine.func)
229 {
230 e->engine.func->context_free(e->engine.data.output, e->engine.data.context);
231 e->engine.func->output_free(e->engine.data.output);
232 e->engine.func->info_free(e, e->engine.info);
233 }
234
235 for (i = 0; i < e->modifiers.mod.count; i++)
236 free(e->modifiers.mod.list[i]);
237 if (e->modifiers.mod.list) free(e->modifiers.mod.list);
238
239 for (i = 0; i < e->locks.lock.count; i++)
240 free(e->locks.lock.list[i]);
241 if (e->locks.lock.list) free(e->locks.lock.list);
242
243 if (e->engine.module) evas_module_unref(e->engine.module);
244
245 eina_array_flush(&e->delete_objects);
246 eina_array_flush(&e->active_objects);
247 eina_array_flush(&e->restack_objects);
248 eina_array_flush(&e->render_objects);
249 eina_array_flush(&e->pending_objects);
250 eina_array_flush(&e->obscuring_objects);
251 eina_array_flush(&e->temporary_objects);
252 eina_array_flush(&e->calculate_objects);
253 eina_array_flush(&e->clip_changes);
254
255 EINA_LIST_FREE(e->touch_points, touch_point)
256 free(touch_point);
257
258 e->magic = 0;
259 free(e);
260}
261
262EAPI void
263evas_output_method_set(Evas *e, int render_method)
264{
265 Evas_Module *em;
266
267 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
268 return;
269 MAGIC_CHECK_END();
270
271 /* if our engine to set it to is invalid - abort */
272 if (render_method == RENDER_METHOD_INVALID) return;
273 /* if the engine is already set up - abort */
274 if (e->output.render_method != RENDER_METHOD_INVALID) return;
275 /* Request the right engine. */
276 em = evas_module_engine_get(render_method);
277 if (!em) return ;
278 if (em->id_engine != render_method) return;
279 if (!evas_module_load(em)) return;
280
281 /* set the correct render */
282 e->output.render_method = render_method;
283 e->engine.func = (em->functions);
284 evas_module_use(em);
285 if (e->engine.module) evas_module_unref(e->engine.module);
286 e->engine.module = em;
287 evas_module_ref(em);
288 /* get the engine info struct */
289 if (e->engine.func->info) e->engine.info = e->engine.func->info(e);
290 return;
291}
292
293EAPI int
294evas_output_method_get(const Evas *e)
295{
296 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
297 return RENDER_METHOD_INVALID;
298 MAGIC_CHECK_END();
299
300 return e->output.render_method;
301}
302
303EAPI Evas_Engine_Info *
304evas_engine_info_get(const Evas *e)
305{
306 Evas_Engine_Info *info;
307
308 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
309 return NULL;
310 MAGIC_CHECK_END();
311
312 if (!e->engine.info) return NULL;
313
314 info = e->engine.info;
315 ((Evas *)e)->engine.info_magic = info->magic;
316
317 return info;
318}
319
320EAPI Eina_Bool
321evas_engine_info_set(Evas *e, Evas_Engine_Info *info)
322{
323 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
324 return EINA_FALSE;
325 MAGIC_CHECK_END();
326 if (!info) return EINA_FALSE;
327 if (info != e->engine.info) return EINA_FALSE;
328 if (info->magic != e->engine.info_magic) return EINA_FALSE;
329 return (Eina_Bool)e->engine.func->setup(e, info);
330}
331
332EAPI void
333evas_output_size_set(Evas *e, int w, int h)
334{
335 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
336 return;
337 MAGIC_CHECK_END();
338
339 if ((w == e->output.w) && (h == e->output.h)) return;
340 if (w < 1) w = 1;
341 if (h < 1) h = 1;
342
343#ifdef EVAS_FRAME_QUEUING
344 evas_common_frameq_flush();
345#endif
346
347 e->output.w = w;
348 e->output.h = h;
349 e->output.changed = 1;
350 e->output_validity++;
351 e->changed = 1;
352 evas_render_invalidate(e);
353}
354
355EAPI void
356evas_output_size_get(const Evas *e, int *w, int *h)
357{
358 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
359 if (w) *w = 0;
360 if (h) *h = 0;
361 return;
362 MAGIC_CHECK_END();
363
364 if (w) *w = e->output.w;
365 if (h) *h = e->output.h;
366}
367
368EAPI void
369evas_output_viewport_set(Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
370{
371 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
372 return;
373 MAGIC_CHECK_END();
374
375 if ((x == e->viewport.x) && (y == e->viewport.y) &&
376 (w == e->viewport.w) && (h == e->viewport.h)) return;
377 if (w <= 0) return;
378 if (h <= 0) return;
379 if ((x != 0) || (y != 0))
380 {
381 ERR("Compat error. viewport x,y != 0,0 not supported");
382 x = 0;
383 y = 0;
384 }
385 e->viewport.x = x;
386 e->viewport.y = y;
387 e->viewport.w = w;
388 e->viewport.h = h;
389 e->viewport.changed = 1;
390 e->output_validity++;
391 e->changed = 1;
392}
393
394EAPI void
395evas_output_viewport_get(const Evas *e, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
396{
397 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
398 if (x) *x = 0;
399 if (y) *y = 0;
400 if (w) *w = 0;
401 if (h) *h = 0;
402 return;
403 MAGIC_CHECK_END();
404
405 if (x) *x = e->viewport.x;
406 if (y) *y = e->viewport.y;
407 if (w) *w = e->viewport.w;
408 if (h) *h = e->viewport.h;
409}
410
411EAPI Evas_Coord
412evas_coord_screen_x_to_world(const Evas *e, int x)
413{
414 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
415 return 0;
416 MAGIC_CHECK_END();
417 if (e->output.w == e->viewport.w) return e->viewport.x + x;
418 return (long long)e->viewport.x + (((long long)x * (long long)e->viewport.w) / (long long)e->output.w);
419}
420
421EAPI Evas_Coord
422evas_coord_screen_y_to_world(const Evas *e, int y)
423{
424 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
425 return 0;
426 MAGIC_CHECK_END();
427 if (e->output.h == e->viewport.h) return e->viewport.y + y;
428 return (long long)e->viewport.y + (((long long)y * (long long)e->viewport.h) / (long long)e->output.h);
429}
430
431EAPI int
432evas_coord_world_x_to_screen(const Evas *e, Evas_Coord x)
433{
434 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
435 return 0;
436 MAGIC_CHECK_END();
437 if (e->output.w == e->viewport.w) return x - e->viewport.x;
438 return (int)((((long long)x - (long long)e->viewport.x) * (long long)e->output.w) / (long long)e->viewport.w);
439}
440
441EAPI int
442evas_coord_world_y_to_screen(const Evas *e, Evas_Coord y)
443{
444 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
445 return 0;
446 MAGIC_CHECK_END();
447 if (e->output.h == e->viewport.h) return y - e->viewport.y;
448 return (int)((((long long)y - (long long)e->viewport.y) * (long long)e->output.h) / (long long)e->viewport.h);
449}
450
451EAPI int
452evas_render_method_lookup(const char *name)
453{
454 Evas_Module *em;
455
456 if (!name) return RENDER_METHOD_INVALID;
457 /* search on the engines list for the name */
458 em = evas_module_find_type(EVAS_MODULE_TYPE_ENGINE, name);
459 if (!em) return RENDER_METHOD_INVALID;
460
461 return em->id_engine;
462}
463
464EAPI Eina_List *
465evas_render_method_list(void)
466{
467 return evas_module_engine_list();
468}
469
470EAPI void
471evas_render_method_list_free(Eina_List *list)
472{
473 eina_list_free(list);
474}
475
476EAPI Eina_Bool
477evas_object_image_extension_can_load_get(const char *file)
478{
479 const char *tmp;
480 Eina_Bool result;
481
482 tmp = eina_stringshare_add(file);
483 result = evas_common_extension_can_load_get(tmp);
484 eina_stringshare_del(tmp);
485
486 return result;
487}
488
489EAPI Eina_Bool
490evas_object_image_extension_can_load_fast_get(const char *file)
491{
492 return evas_common_extension_can_load_get(file);
493}
494
495EAPI void
496evas_pointer_output_xy_get(const Evas *e, int *x, int *y)
497{
498 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
499 if (x) *x = 0;
500 if (y) *y = 0;
501 return;
502 MAGIC_CHECK_END();
503 if (x) *x = e->pointer.x;
504 if (y) *y = e->pointer.y;
505}
506
507EAPI void
508evas_pointer_canvas_xy_get(const Evas *e, Evas_Coord *x, Evas_Coord *y)
509{
510 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
511 if (x) *x = 0;
512 if (y) *y = 0;
513 return;
514 MAGIC_CHECK_END();
515 if (x) *x = e->pointer.x;
516 if (y) *y = e->pointer.y;
517}
518
519EAPI int
520evas_pointer_button_down_mask_get(const Evas *e)
521{
522 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
523 return 0;
524 MAGIC_CHECK_END();
525 return (int)e->pointer.button;
526}
527
528EAPI Eina_Bool
529evas_pointer_inside_get(const Evas *e)
530{
531 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
532 return 0;
533 MAGIC_CHECK_END();
534 return (int)e->pointer.inside;
535}
536
537EAPI void
538evas_data_attach_set(Evas *e, void *data)
539{
540 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
541 return;
542 MAGIC_CHECK_END();
543 e->attach_data = data;
544}
545
546EAPI void *
547evas_data_attach_get(const Evas *e)
548{
549 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
550 return NULL;
551 MAGIC_CHECK_END();
552 return e->attach_data;
553}
554
555EAPI void
556evas_focus_in(Evas *e)
557{
558 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
559 return;
560 MAGIC_CHECK_END();
561 if (e->focus) return;
562 e->focus = 1;
563 evas_event_callback_call(e, EVAS_CALLBACK_CANVAS_FOCUS_IN, NULL);
564}
565
566EAPI void
567evas_focus_out(Evas *e)
568{
569 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
570 return;
571 MAGIC_CHECK_END();
572 if (!e->focus) return;
573 e->focus = 0;
574 evas_event_callback_call(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT, NULL);
575}
576
577EAPI Eina_Bool
578evas_focus_state_get(const Evas *e)
579{
580 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
581 return 0;
582 MAGIC_CHECK_END();
583 return e->focus;
584}
585
586EAPI void
587evas_nochange_push(Evas *e)
588{
589 e->nochange++;
590}
591
592EAPI void
593evas_nochange_pop(Evas *e)
594{
595 e->nochange--;
596}
597
598void
599_evas_walk(Evas *e)
600{
601 e->walking_list++;
602}
603
604void
605_evas_unwalk(Evas *e)
606{
607 e->walking_list--;
608 if ((e->walking_list == 0) && (e->delete_me)) evas_free(e);
609}
610
611EAPI const char *
612evas_load_error_str(Evas_Load_Error error)
613{
614 switch (error)
615 {
616 case EVAS_LOAD_ERROR_NONE:
617 return "No error on load";
618 case EVAS_LOAD_ERROR_GENERIC:
619 return "A non-specific error occurred";
620 case EVAS_LOAD_ERROR_DOES_NOT_EXIST:
621 return "File (or file path) does not exist";
622 case EVAS_LOAD_ERROR_PERMISSION_DENIED:
623 return "Permission deinied to an existing file (or path)";
624 case EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED:
625 return "Allocation of resources failure prevented load";
626 case EVAS_LOAD_ERROR_CORRUPT_FILE:
627 return "File corrupt (but was detected as a known format)";
628 case EVAS_LOAD_ERROR_UNKNOWN_FORMAT:
629 return "File is not a known format";
630 default:
631 return "Unknown error";
632 }
633}
634
635EAPI void
636evas_color_hsv_to_rgb(float h, float s, float v, int *r, int *g, int *b)
637{
638 evas_common_convert_color_hsv_to_rgb(h, s, v, r, g, b);
639}
640
641EAPI void
642evas_color_rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v)
643{
644 evas_common_convert_color_rgb_to_hsv(r, g, b, h, s, v);
645}
646
647EAPI void
648evas_color_argb_premul(int a, int *r, int *g, int *b)
649{
650 evas_common_convert_color_argb_premul(a, r, g, b);
651}
652
653EAPI void
654evas_color_argb_unpremul(int a, int *r, int *g, int *b)
655{
656 evas_common_convert_color_argb_unpremul(a, r, g, b);
657}
658
659EAPI void
660evas_data_argb_premul(unsigned int *data, unsigned int len)
661{
662 if (!data || (len < 1)) return;
663 evas_common_convert_argb_premul(data, len);
664}
665
666EAPI void
667evas_data_argb_unpremul(unsigned int *data, unsigned int len)
668{
669 if (!data || (len < 1)) return;
670 evas_common_convert_argb_unpremul(data, len);
671}
diff --git a/libraries/evas/src/lib/canvas/evas_map.c b/libraries/evas/src/lib/canvas/evas_map.c
new file mode 100644
index 0000000..fca8b3a
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_map.c
@@ -0,0 +1,1031 @@
1#include "evas_common.h"
2#include "evas_private.h"
3#include <math.h>
4
5static void
6_evas_map_calc_geom_change(Evas_Object *obj)
7{
8 int is, was = 0, pass = 0;
9
10 evas_object_change(obj);
11 evas_object_clip_dirty(obj);
12 if (obj->layer->evas->events_frozen <= 0)
13 {
14 evas_object_recalc_clippees(obj);
15 if (!pass)
16 {
17 if (!obj->smart.smart)
18 {
19 is = evas_object_is_in_output_rect(obj,
20 obj->layer->evas->pointer.x,
21 obj->layer->evas->pointer.y, 1, 1);
22 if ((is ^ was) && obj->cur.visible)
23 evas_event_feed_mouse_move(obj->layer->evas,
24 obj->layer->evas->pointer.x,
25 obj->layer->evas->pointer.y,
26 obj->layer->evas->last_timestamp,
27 NULL);
28 }
29 }
30 }
31 evas_object_inform_call_move(obj);
32 evas_object_inform_call_resize(obj);
33}
34
35static void
36_evas_map_calc_map_geometry(Evas_Object *obj)
37{
38 Evas_Coord x1, x2, y1, y2;
39 const Evas_Map_Point *p, *p_end;
40 Eina_Bool ch = EINA_FALSE;
41
42 if (!obj->cur.map) return;
43
44 // WARN: Do not merge below code to SLP until it is fixed.
45 // It has an infinite loop bug.
46 if (obj->prev.map)
47 {
48 // FIXME: this causes an infinite loop somewhere... hard to debug
49 if (obj->prev.map->count == obj->cur.map->count)
50 {
51 const Evas_Map_Point *p2;
52
53 p = obj->cur.map->points;
54 p_end = p + obj->cur.map->count;
55 p2 = obj->prev.map->points;
56
57 for (; p < p_end; p++, p2++)
58 {
59 if ((p->a != p2->a) ||
60 (p->r != p2->r) ||
61 (p->g != p2->g) ||
62 (p->b != p2->b))
63 {
64 ch = 1;
65 break;
66 }
67 if ((p->x != p2->x) ||
68 (p->y != p2->y) ||
69 (p->z != p2->z))
70 {
71 ch = 1;
72 break;
73 }
74 }
75 }
76 else
77 ch = 1;
78 }
79 else
80 ch = 1;
81
82 p = obj->cur.map->points;
83 p_end = p + obj->cur.map->count;
84 x1 = lround(p->x);
85 x2 = lround(p->x);
86 y1 = lround(p->y);
87 y2 = lround(p->y);
88 p++;
89 for (; p < p_end; p++)
90 {
91 if (p->x < x1) x1 = p->x;
92 if (p->x > x2) x2 = p->x;
93 if (p->y < y1) y1 = p->y;
94 if (p->y > y2) y2 = p->y;
95 }
96// this causes clip-out bugs now mapped objs canbe opaque!!!
97// // add 1 pixel of fuzz around the map region to ensure updates are correct
98// x1 -= 1; y1 -= 1;
99// x2 += 1; y2 += 1;
100 if (obj->cur.map->normal_geometry.x != x1) ch = 1;
101 if (obj->cur.map->normal_geometry.y != y1) ch = 1;
102 if (obj->cur.map->normal_geometry.w != (x2 - x1)) ch = 1;
103 if (obj->cur.map->normal_geometry.h != (y2 - y1)) ch = 1;
104 obj->cur.map->normal_geometry.x = x1;
105 obj->cur.map->normal_geometry.y = y1;
106 obj->cur.map->normal_geometry.w = (x2 - x1);
107 obj->cur.map->normal_geometry.h = (y2 - y1);
108 if (ch) _evas_map_calc_geom_change(obj);
109}
110
111static inline Evas_Map *
112_evas_map_new(int count)
113{
114 int i;
115 int alloc;
116 Evas_Map *m;
117
118 /* Adjust allocation such that: at least 4 points, and always an even
119 * number: this allows the software engine to work efficiently */
120 alloc = (count < 4) ? 4 : count;
121 if (alloc & 0x1) alloc ++;
122
123 m = calloc(1, sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point)));
124 if (!m) return NULL;
125 m->count = count;
126 m->persp.foc = 0;
127 m->alpha = 1;
128 m->smooth = 1;
129 m->magic = MAGIC_MAP;
130 for (i = 0; i < count; i++)
131 {
132 m->points[i].r = 255;
133 m->points[i].g = 255;
134 m->points[i].b = 255;
135 m->points[i].a = 255;
136 }
137 return m;
138}
139
140static inline Eina_Bool
141_evas_map_copy(Evas_Map *dst, const Evas_Map *src)
142{
143 if (dst->count != src->count)
144 {
145 ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count);
146 return EINA_FALSE;
147 }
148 memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point));
149 dst->smooth = src->smooth;
150 dst->alpha = src->alpha;
151 dst->persp = src->persp;
152 return EINA_TRUE;
153}
154
155static inline Evas_Map *
156_evas_map_dup(const Evas_Map *orig)
157{
158 Evas_Map *copy = _evas_map_new(orig->count);
159 if (!copy) return NULL;
160 memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point));
161 copy->smooth = orig->smooth;
162 copy->alpha = orig->alpha;
163 copy->persp = orig->persp;
164 return copy;
165}
166
167static inline void
168_evas_map_free(Evas_Object *obj, Evas_Map *m)
169{
170 if (obj)
171 {
172 if (m->surface)
173 obj->layer->evas->engine.func->image_map_surface_free
174 (obj->layer->evas->engine.data.output, m->surface);
175 }
176 m->magic = 0;
177 free(m);
178}
179
180/****************************************************************************/
181/* util functions for manipulating maps, so you don't need to know the math */
182/****************************************************************************/
183static inline void
184_evas_map_util_points_populate(Evas_Map *m, const Evas_Coord x, const Evas_Coord y, const Evas_Coord w, const Evas_Coord h, const Evas_Coord z)
185{
186 Evas_Map_Point *p = m->points;
187 int i;
188
189 p[0].x = x;
190 p[0].y = y;
191 p[0].z = z;
192 p[0].u = 0.0;
193 p[0].v = 0.0;
194
195 p[1].x = x + w;
196 p[1].y = y;
197 p[1].z = z;
198 p[1].u = w;
199 p[1].v = 0.0;
200
201 p[2].x = x + w;
202 p[2].y = y + h;
203 p[2].z = z;
204 p[2].u = w;
205 p[2].v = h;
206
207 p[3].x = x;
208 p[3].y = y + h;
209 p[3].z = z;
210 p[3].u = 0.0;
211 p[3].v = h;
212
213 for (i = 0; i < 4; i++)
214 {
215 p[i].px = p[i].x;
216 p[i].py = p[i].y;
217 }
218}
219
220Eina_Bool
221evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y,
222 Evas_Coord *mx, Evas_Coord *my, int grab)
223{
224 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
225 return EINA_FALSE;
226 MAGIC_CHECK_END();
227
228 int i, j, edges, edge[m->count][2], douv;
229 Evas_Coord xe[2];
230 double u[2] = { 0.0, 0.0 };
231 double v[2] = { 0.0, 0.0 };
232
233 if (m->count < 4) return 0;
234 // FIXME need to handle grab mode and extrapolte coords outside
235 // map
236 if (grab)
237 {
238 Evas_Coord ymin, ymax;
239
240 ymin = m->points[0].y;
241 ymax = m->points[0].y;
242 for (i = 1; i < m->count; i++)
243 {
244 if (m->points[i].y < ymin) ymin = m->points[i].y;
245 else if (m->points[i].y > ymax) ymax = m->points[i].y;
246 }
247 if (y <= ymin) y = ymin + 1;
248 if (y >= ymax) y = ymax - 1;
249 }
250 edges = 0;
251 for (i = 0; i < m->count; i++)
252 {
253 j = (i + 1) % m->count;
254 if ((m->points[i].y <= y) && (m->points[j].y > y))
255 {
256 edge[edges][0] = i;
257 edge[edges][1] = j;
258 edges++;
259 }
260 else if ((m->points[j].y <= y) && (m->points[i].y > y))
261 {
262 edge[edges][0] = j;
263 edge[edges][1] = i;
264 edges++;
265 }
266 }
267 douv = 0;
268 if ((mx) || (my)) douv = 1;
269 for (i = 0; i < (edges - 1); i+= 2)
270 {
271 Evas_Coord yp, yd;
272
273 j = i + 1;
274 yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y;
275 if (yd > 0)
276 {
277 yp = y - m->points[edge[i][0]].y;
278 xe[0] = m->points[edge[i][1]].x - m->points[edge[i][0]].x;
279 xe[0] = m->points[edge[i][0]].x + ((xe[0] * yp) / yd);
280 if (douv)
281 {
282 u[0] = m->points[edge[i][1]].u - m->points[edge[i][0]].u;
283 u[0] = m->points[edge[i][0]].u + ((u[0] * yp) / yd);
284 v[0] = m->points[edge[i][1]].v - m->points[edge[i][0]].v;
285 v[0] = m->points[edge[i][0]].v + ((v[0] * yp) / yd);
286 }
287 }
288 else
289 {
290 xe[0] = m->points[edge[i][0]].x;
291 if (douv)
292 {
293 u[0] = m->points[edge[i][0]].u;
294 v[0] = m->points[edge[i][0]].v;
295 }
296 }
297 yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y;
298 if (yd > 0)
299 {
300 yp = y - m->points[edge[j][0]].y;
301 xe[1] = m->points[edge[j][1]].x - m->points[edge[j][0]].x;
302 xe[1] = m->points[edge[j][0]].x + ((xe[1] * yp) / yd);
303 if (douv)
304 {
305 u[1] = m->points[edge[j][1]].u - m->points[edge[j][0]].u;
306 u[1] = m->points[edge[j][0]].u + ((u[1] * yp) / yd);
307 v[1] = m->points[edge[j][1]].v - m->points[edge[j][0]].v;
308 v[1] = m->points[edge[j][0]].v + ((v[1] * yp) / yd);
309 }
310 }
311 else
312 {
313 xe[1] = m->points[edge[j][0]].x;
314 if (douv)
315 {
316 u[1] = m->points[edge[j][0]].u;
317 v[1] = m->points[edge[j][0]].v;
318 }
319 }
320 if (xe[0] > xe[1])
321 {
322 int ti;
323
324 ti = xe[0]; xe[0] = xe[1]; xe[1] = ti;
325 if (douv)
326 {
327 double td;
328
329 td = u[0]; u[0] = u[1]; u[1] = td;
330 td = v[0]; v[0] = v[1]; v[1] = td;
331 }
332 }
333 if ((x >= xe[0]) && (x < xe[1]))
334 {
335 if (douv)
336 {
337 if (mx)
338 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
339 (xe[1] - xe[0]));
340 if (my)
341 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
342 (xe[1] - xe[0]));
343 }
344 return EINA_TRUE;
345 }
346 if (grab)
347 {
348 if (douv)
349 {
350 if (mx)
351 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
352 (xe[1] - xe[0]));
353 if (my)
354 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
355 (xe[1] - xe[0]));
356 }
357 return EINA_TRUE;
358 }
359 }
360 return EINA_FALSE;
361}
362
363Eina_Bool
364evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y)
365{
366 return evas_map_coords_get(m, x, y, NULL, NULL, 0);
367}
368
369EAPI void
370evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled)
371{
372 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
373 return;
374 MAGIC_CHECK_END();
375
376 enabled = !!enabled;
377 if (obj->cur.usemap == enabled) return;
378 obj->cur.usemap = enabled;
379 if (enabled)
380 {
381 if (!obj->cur.map)
382 obj->cur.map = _evas_map_new(4);
383 evas_object_mapped_clip_across_mark(obj);
384// obj->cur.map->normal_geometry = obj->cur.geometry;
385 }
386 else
387 {
388 if (obj->cur.map)
389 {
390 _evas_map_calc_geom_change(obj);
391 evas_object_mapped_clip_across_mark(obj);
392 //FIXME: Since the last frame is not updated when map is
393 //disabled, afterimage problem is happened in s/w rendering.
394 //Need to find out the fundamental reason then fix it.
395 evas_damage_rectangle_add(obj->layer->evas,
396 0,
397 0,
398 obj->layer->evas->output.w,
399 obj->layer->evas->output.h);
400 }
401 }
402 _evas_map_calc_map_geometry(obj);
403 /* This is a bit heavy handed, but it fixes the case of same geometry, but
404 * changed colour or UV settings. */
405 evas_object_change(obj);
406}
407
408EAPI Eina_Bool
409evas_object_map_enable_get(const Evas_Object *obj)
410{
411 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
412 return EINA_FALSE;
413 MAGIC_CHECK_END();
414 return obj->cur.usemap;
415}
416
417
418EAPI void
419evas_object_map_source_set(Evas_Object *obj, Evas_Object *src)
420{
421 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
422 return;
423 MAGIC_CHECK_END();
424 (void)src; /* method still needs to be implemented. */
425}
426
427EAPI Evas_Object *
428evas_object_map_source_get(const Evas_Object *obj)
429{
430 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
431 return NULL;
432 MAGIC_CHECK_END();
433 return NULL;
434}
435
436EAPI void
437evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
438{
439 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
440 return;
441 MAGIC_CHECK_END();
442
443 if (!map)
444 {
445 if (obj->cur.map)
446 {
447 if (obj->cur.map->surface)
448 {
449 obj->layer->evas->engine.func->image_map_surface_free
450 (obj->layer->evas->engine.data.output,
451 obj->cur.map->surface);
452 obj->cur.map->surface = NULL;
453 }
454 obj->prev.geometry = obj->cur.map->normal_geometry;
455 if (!obj->prev.map)
456 {
457 _evas_map_free(obj, obj->cur.map);
458 obj->cur.map = NULL;
459 evas_object_mapped_clip_across_mark(obj);
460 return;
461 }
462 _evas_map_free(obj, obj->cur.map);
463 obj->cur.map = NULL;
464 if (!obj->cur.usemap) _evas_map_calc_geom_change(obj);
465 else _evas_map_calc_map_geometry(obj);
466 if (obj->cur.usemap)
467 {
468 evas_object_mapped_clip_across_mark(obj);
469 //FIXME: Since the last frame is not updated when map is
470 //disabled, afterimage problem is happened in s/w
471 //rendering. Need to find out the fundamental reason
472 //then fix it.
473 evas_damage_rectangle_add(obj->layer->evas,
474 0,
475 0,
476 obj->layer->evas->output.w,
477 obj->layer->evas->output.h);
478 }
479 }
480 return;
481 }
482
483 if ((obj->cur.map) && (obj->cur.map->count == map->count))
484 {
485 Evas_Map *omap = obj->cur.map;
486 obj->cur.map = _evas_map_new(map->count);
487 memcpy(obj->cur.map, omap, sizeof(Evas_Map) + (map->count * sizeof(Evas_Map_Point)));
488 _evas_map_copy(obj->cur.map, map);
489 if (obj->prev.map == omap) obj->prev.map = NULL;
490 free(omap);
491 }
492 else
493 {
494 if (obj->cur.map) evas_map_free(obj->cur.map);
495 obj->cur.map = _evas_map_dup(map);
496 if (obj->cur.usemap)
497 evas_object_mapped_clip_across_mark(obj);
498 }
499 _evas_map_calc_map_geometry(obj);
500}
501
502EAPI const Evas_Map *
503evas_object_map_get(const Evas_Object *obj)
504{
505 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
506 return NULL;
507 MAGIC_CHECK_END();
508
509 return obj->cur.map;
510}
511
512EAPI Evas_Map *
513evas_map_new(int count)
514{
515 if (count != 4)
516 {
517 ERR("map point count (%i) != 4 is unsupported!", count);
518 return NULL;
519 }
520
521 return _evas_map_new(count);
522}
523
524EAPI void
525evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
526{
527 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
528 return;
529 MAGIC_CHECK_END();
530
531 m->smooth = enabled;
532}
533
534EAPI Eina_Bool
535evas_map_smooth_get(const Evas_Map *m)
536{
537 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
538 return EINA_FALSE;
539 MAGIC_CHECK_END();
540
541 return m->smooth;
542}
543
544EAPI void
545evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
546{
547 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
548 return;
549 MAGIC_CHECK_END();
550
551 m->alpha = enabled;
552}
553
554EAPI Eina_Bool
555evas_map_alpha_get(const Evas_Map *m)
556{
557 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
558 return EINA_FALSE;
559 MAGIC_CHECK_END();
560
561 return m->alpha;
562}
563
564EAPI Evas_Map *
565evas_map_dup(const Evas_Map *m)
566{
567 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
568 return NULL;
569 MAGIC_CHECK_END();
570
571 return _evas_map_dup(m);
572}
573
574EAPI void
575evas_map_free(Evas_Map *m)
576{
577 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
578 return;
579 MAGIC_CHECK_END();
580
581 _evas_map_free(NULL, m);
582}
583
584EAPI int
585evas_map_count_get(const Evas_Map *m)
586{
587 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
588 return -1;
589 MAGIC_CHECK_END();
590
591 return m->count;
592}
593
594EAPI void
595evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
596{
597 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
598 return;
599 MAGIC_CHECK_END();
600
601 Evas_Map_Point *p;
602
603 if (idx >= m->count) return;
604 p = m->points + idx;
605 p->x = p->px = x;
606 p->y = p->py = y;
607 p->z = z;
608}
609
610EAPI void
611evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
612{
613 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
614 goto error;
615 MAGIC_CHECK_END();
616
617 const Evas_Map_Point *p;
618
619 if (idx >= m->count) goto error;
620 p = m->points + idx;
621 if (x) *x = p->x;
622 if (y) *y = p->y;
623 if (z) *z = p->z;
624 return;
625
626 error:
627 if (x) *x = 0;
628 if (y) *y = 0;
629 if (z) *z = 0;
630}
631
632EAPI void
633evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
634{
635 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
636 return;
637 MAGIC_CHECK_END();
638
639 Evas_Map_Point *p;
640
641 if (idx >= m->count) return;
642 p = m->points + idx;
643 p->u = u;
644 p->v = v;
645}
646
647EAPI void
648evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v)
649{
650 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
651 goto error;
652 MAGIC_CHECK_END();
653
654 const Evas_Map_Point *p;
655
656 if (idx >= m->count) goto error;
657 p = m->points + idx;
658 if (u) *u = p->u;
659 if (v) *v = p->v;
660 return;
661
662 error:
663 if (u) *u = 0.0;
664 if (v) *v = 0.0;
665}
666
667EAPI void
668evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
669{
670 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
671 return;
672 MAGIC_CHECK_END();
673
674 Evas_Map_Point *p;
675
676 if (idx >= m->count) return;
677 p = m->points + idx;
678 p->r = r;
679 p->g = g;
680 p->b = b;
681 p->a = a;
682}
683
684EAPI void
685evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a)
686{
687 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
688 return;
689 MAGIC_CHECK_END();
690
691 const Evas_Map_Point *p;
692
693 if (idx >= m->count) return;
694 p = m->points + idx;
695 if (r) *r = p->r;
696 if (g) *g = p->g;
697 if (b) *b = p->b;
698 if (a) *a = p->a;
699}
700
701EAPI void
702evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
703{
704 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
705 return;
706 MAGIC_CHECK_END();
707
708 if (m->count != 4)
709 {
710 ERR("map has count=%d where 4 was expected.", m->count);
711 return;
712 }
713 _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
714 obj->cur.geometry.w, obj->cur.geometry.h, z);
715}
716
717EAPI void
718evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
719{
720 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
721 return;
722 MAGIC_CHECK_END();
723
724 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
725 return;
726 MAGIC_CHECK_END();
727
728 if (m->count != 4)
729 {
730 ERR("map has count=%d where 4 was expected.", m->count);
731 return;
732 }
733 _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
734 obj->cur.geometry.w, obj->cur.geometry.h, 0);
735}
736
737EAPI void
738evas_map_util_points_populate_from_geometry(Evas_Map *m, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Evas_Coord z)
739{
740 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
741 return;
742 MAGIC_CHECK_END();
743
744 if (m->count != 4)
745 {
746 ERR("map has count=%d where 4 was expected.", m->count);
747 return;
748 }
749 _evas_map_util_points_populate(m, x, y, w, h, z);
750}
751
752EAPI void
753evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
754{
755 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
756 return;
757 MAGIC_CHECK_END();
758
759 Evas_Map_Point *p, *p_end;
760
761 p = m->points;
762 p_end = p + m->count;
763 for (; p < p_end; p++)
764 {
765 p->r = r;
766 p->g = g;
767 p->b = b;
768 p->a = a;
769 }
770}
771
772EAPI void
773evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
774{
775 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
776 return;
777 MAGIC_CHECK_END();
778
779 double r = (degrees * M_PI) / 180.0;
780 Evas_Map_Point *p, *p_end;
781
782 p = m->points;
783 p_end = p + m->count;
784
785 for (; p < p_end; p++)
786 {
787 double x, y, xx, yy;
788
789 x = p->x - cx;
790 y = p->y - cy;
791
792 xx = x * cos(r);
793 yy = x * sin(r);
794 x = xx - (y * sin(r));
795 y = yy + (y * cos(r));
796
797 p->px = p->x = x + cx;
798 p->py = p->y = y + cy;
799 }
800}
801
802EAPI void
803evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
804{
805 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
806 return;
807 MAGIC_CHECK_END();
808
809 Evas_Map_Point *p, *p_end;
810
811 p = m->points;
812 p_end = p + m->count;
813
814 for (; p < p_end; p++)
815 {
816 double x, y;
817
818 x = p->x - cx;
819 y = p->y - cy;
820
821 x = (((double)x) * zoomx);
822 y = (((double)y) * zoomy);
823
824 p->px = p->x = x + cx;
825 p->py = p->y = y + cy;
826 }
827}
828
829EAPI void
830evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz,
831 Evas_Coord cx, Evas_Coord cy, Evas_Coord cz)
832{
833 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
834 return;
835 MAGIC_CHECK_END();
836
837 double rz = (dz * M_PI) / 180.0;
838 double rx = (dx * M_PI) / 180.0;
839 double ry = (dy * M_PI) / 180.0;
840 Evas_Map_Point *p, *p_end;
841
842 p = m->points;
843 p_end = p + m->count;
844
845 for (; p < p_end; p++)
846 {
847 double x, y, z, xx, yy, zz;
848
849 x = p->x - cx;
850 y = p->y - cy;
851 z = p->z - cz;
852
853 if (rz != 0.0)
854 {
855 xx = x * cos(rz);
856 yy = x * sin(rz);
857 x = xx - (y * sin(rz));
858 y = yy + (y * cos(rz));
859 }
860
861 if (ry != 0.0)
862 {
863 xx = x * cos(ry);
864 zz = x * sin(ry);
865 x = xx - (z * sin(ry));
866 z = zz + (z * cos(ry));
867 }
868
869 if (rx != 0.0)
870 {
871 zz = z * cos(rx);
872 yy = z * sin(rx);
873 z = zz - (y * sin(rx));
874 y = yy + (y * cos(rx));
875 }
876
877 p->px = p->x = x + cx;
878 p->py = p->y = y + cy;
879 p->z = z + cz;
880 }
881}
882
883EAPI void
884evas_map_util_3d_lighting(Evas_Map *m,
885 Evas_Coord lx, Evas_Coord ly, Evas_Coord lz,
886 int lr, int lg, int lb, int ar, int ag, int ab)
887{
888 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
889 return;
890 MAGIC_CHECK_END();
891
892 int i;
893
894 for (i = 0; i < m->count; i++)
895 {
896 double x, y, z;
897 double nx, ny, nz, x1, y1, z1, x2, y2, z2, ln, br;
898 int h, j, mr, mg, mb;
899
900 x = m->points[i].x;
901 y = m->points[i].y;
902 z = m->points[i].z;
903 // calc normal
904 h = (i - 1 + 4) % 4 + (i & ~0x3); // prev point
905 j = (i + 1) % 4 + (i & ~0x3); // next point
906
907 x1 = m->points[h].x - x;
908 y1 = m->points[h].y - y;
909 z1 = m->points[h].z - z;
910
911 x2 = m->points[j].x - x;
912 y2 = m->points[j].y - y;
913 z2 = m->points[j].z - z;
914 nx = (y1 * z2) - (z1 * y2);
915 ny = (z1 * x2) - (x1 * z2);
916 nz = (x1 * y2) - (y1 * x2);
917
918 ln = (nx * nx) + (ny * ny) + (nz * nz);
919 ln = sqrt(ln);
920
921 if (ln != 0.0)
922 {
923 nx /= ln;
924 ny /= ln;
925 nz /= ln;
926 }
927
928 // calc point -> light vector
929 x = lx - x;
930 y = ly - y;
931 z = lz - z;
932
933 ln = (x * x) + (y * y) + (z * z);
934 ln = sqrt(ln);
935
936 if (ln != 0.0)
937 {
938 x /= ln;
939 y /= ln;
940 z /= ln;
941 }
942
943 // brightness - tan (0.0 -> 1.0 brightness really)
944 br = (nx * x) + (ny * y) + (nz * z);
945 if (br < 0.0) br = 0.0;
946
947 mr = ar + ((lr - ar) * br);
948 mg = ag + ((lg - ag) * br);
949 mb = ab + ((lb - ab) * br);
950 if (m->points[i].a != 255)
951 {
952 mr = (mr * m->points[i].a) / 255;
953 mg = (mg * m->points[i].a) / 255;
954 mb = (mb * m->points[i].a) / 255;
955 }
956 m->points[i].r = (m->points[i].r * mr) / 255;
957 m->points[i].g = (m->points[i].g * mg) / 255;
958 m->points[i].b = (m->points[i].b * mb) / 255;
959 }
960}
961
962EAPI void
963evas_map_util_3d_perspective(Evas_Map *m,
964 Evas_Coord px, Evas_Coord py,
965 Evas_Coord z0, Evas_Coord foc)
966{
967 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
968 return;
969 MAGIC_CHECK_END();
970
971 Evas_Map_Point *p, *p_end;
972
973 p = m->points;
974 p_end = p + m->count;
975
976 m->persp.px = px;
977 m->persp.py = py;
978 m->persp.z0 = z0;
979 m->persp.foc = foc;
980
981 if (foc <= 0) return;
982
983 for (; p < p_end; p++)
984 {
985 double x, y, zz;
986
987 x = p->x - px;
988 y = p->y - py;
989
990 zz = ((p->z - z0) + foc);
991
992 if (zz > 0)
993 {
994 x = (x * foc) / zz;
995 y = (y * foc) / zz;
996 }
997
998 p->x = px + x;
999 p->y = py + y;
1000 }
1001}
1002
1003EAPI Eina_Bool
1004evas_map_util_clockwise_get(Evas_Map *m)
1005{
1006 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
1007 return EINA_FALSE;
1008 MAGIC_CHECK_END();
1009
1010 int i, j, k, count;
1011 long long c;
1012
1013 if (m->count < 3) return EINA_FALSE;
1014
1015 count = 0;
1016 for (i = 0; i < m->count; i++)
1017 {
1018 j = (i + 1) % m->count;
1019 k = (i + 2) % m->count;
1020 c =
1021 ((m->points[j].x - m->points[i].x) *
1022 (m->points[k].y - m->points[j].y))
1023 -
1024 ((m->points[j].y - m->points[i].y) *
1025 (m->points[k].x - m->points[j].x));
1026 if (c < 0) count--;
1027 else if (c > 0) count++;
1028 }
1029 if (count > 0) return EINA_TRUE;
1030 return EINA_FALSE;
1031}
diff --git a/libraries/evas/src/lib/canvas/evas_name.c b/libraries/evas/src/lib/canvas/evas_name.c
new file mode 100644
index 0000000..c42f941
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_name.c
@@ -0,0 +1,40 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4EAPI void
5evas_object_name_set(Evas_Object *obj, const char *name)
6{
7 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
8 return;
9 MAGIC_CHECK_END();
10 if (obj->name)
11 {
12 eina_hash_del(obj->layer->evas->name_hash, obj->name, obj);
13 free(obj->name);
14 }
15 if (!name) obj->name = NULL;
16 else
17 {
18 obj->name = strdup(name);
19 eina_hash_add(obj->layer->evas->name_hash, obj->name, obj);
20 }
21}
22
23EAPI const char *
24evas_object_name_get(const Evas_Object *obj)
25{
26 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
27 return NULL;
28 MAGIC_CHECK_END();
29 return obj->name;
30}
31
32EAPI Evas_Object *
33evas_object_name_find(const Evas *e, const char *name)
34{
35 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
36 return NULL;
37 MAGIC_CHECK_END();
38 if (!name) return NULL;
39 return (Evas_Object *)eina_hash_find(e->name_hash, name);
40}
diff --git a/libraries/evas/src/lib/canvas/evas_object_box.c b/libraries/evas/src/lib/canvas/evas_object_box.c
new file mode 100644
index 0000000..ab2f222
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_box.c
@@ -0,0 +1,2128 @@
1#include "evas_common.h"
2
3#ifdef _WIN32_WCE
4# undef remove
5#endif
6
7typedef struct _Evas_Object_Box_Iterator Evas_Object_Box_Iterator;
8typedef struct _Evas_Object_Box_Accessor Evas_Object_Box_Accessor;
9
10struct _Evas_Object_Box_Iterator
11{
12 Eina_Iterator iterator;
13
14 Eina_Iterator *real_iterator;
15 const Evas_Object *box;
16};
17
18struct _Evas_Object_Box_Accessor
19{
20 Eina_Accessor accessor;
21
22 Eina_Accessor *real_accessor;
23 const Evas_Object *box;
24};
25
26#define _evas_object_box_type "Evas_Object_Box"
27#define SIG_CHILD_ADDED "child,added"
28#define SIG_CHILD_REMOVED "child,removed"
29
30static const Evas_Smart_Cb_Description _signals[] =
31{
32 {SIG_CHILD_ADDED, ""},
33 {SIG_CHILD_REMOVED, ""},
34 {NULL, NULL}
35};
36
37
38static void _sizing_eval(Evas_Object *obj);
39
40#define EVAS_OBJECT_BOX_DATA_GET(o, ptr) \
41 Evas_Object_Box_Data *ptr = evas_object_smart_data_get(o)
42
43#define EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, ptr) \
44 EVAS_OBJECT_BOX_DATA_GET(o, ptr); \
45 if (!ptr) \
46 { \
47 CRIT("no widget data for object %p (%s)", \
48 o, evas_object_type_get(o)); \
49 fflush(stderr); \
50 abort(); \
51 return; \
52}
53
54#define EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
55 EVAS_OBJECT_BOX_DATA_GET(o, ptr); \
56 if (!ptr) \
57 { \
58 CRIT("no widget data for object %p (%s)", \
59 o, evas_object_type_get(o)); \
60 fflush(stderr); \
61 abort(); \
62 return val; \
63 }
64
65EVAS_SMART_SUBCLASS_NEW(_evas_object_box_type, _evas_object_box,
66 Evas_Object_Box_Api, Evas_Smart_Class,
67 evas_object_smart_clipped_class_get, NULL)
68
69static Eina_Bool
70_evas_object_box_iterator_next(Evas_Object_Box_Iterator *it, void **data)
71{
72 Evas_Object_Box_Option *opt;
73
74 if (!eina_iterator_next(it->real_iterator, (void **)&opt))
75 return EINA_FALSE;
76 if (data) *data = opt->obj;
77 return EINA_TRUE;
78}
79
80static Evas_Object *
81_evas_object_box_iterator_get_container(Evas_Object_Box_Iterator *it)
82{
83 return (Evas_Object *)it->box;
84}
85
86static void
87_evas_object_box_iterator_free(Evas_Object_Box_Iterator *it)
88{
89 eina_iterator_free(it->real_iterator);
90 free(it);
91}
92
93static Eina_Bool
94_evas_object_box_accessor_get_at(Evas_Object_Box_Accessor *it, unsigned int idx, void **data)
95{
96 Evas_Object_Box_Option *opt = NULL;
97
98 if (!eina_accessor_data_get(it->real_accessor, idx, (void *)&opt))
99 return EINA_FALSE;
100 if (data) *data = opt->obj;
101 return EINA_TRUE;
102}
103
104static Evas_Object *
105_evas_object_box_accessor_get_container(Evas_Object_Box_Accessor *it)
106{
107 return (Evas_Object *)it->box;
108}
109
110static void
111_evas_object_box_accessor_free(Evas_Object_Box_Accessor *it)
112{
113 eina_accessor_free(it->real_accessor);
114 free(it);
115}
116
117static void
118_on_child_resize(void *data, Evas *evas __UNUSED__, Evas_Object *o __UNUSED__, void *einfo __UNUSED__)
119{
120 Evas_Object *box = data;
121 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(box, priv);
122 if (!priv->layouting) evas_object_smart_changed(box);
123}
124
125static void
126_on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *o, void *einfo __UNUSED__)
127{
128 const Evas_Object_Box_Api *api;
129 Evas_Object *box = data;
130
131 EVAS_OBJECT_BOX_DATA_GET(box, priv);
132 api = priv->api;
133
134 if ((!api) || (!api->remove))
135 {
136 ERR("no api->remove");
137 return;
138 }
139
140 if (!api->remove(box, priv, o))
141 ERR("child removal failed");
142 evas_object_smart_changed(box);
143}
144
145static void
146_on_child_hints_changed(void *data, Evas *evas __UNUSED__, Evas_Object *o __UNUSED__, void *einfo __UNUSED__)
147{
148 Evas_Object *box = data;
149 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(box, priv);
150 if (!priv->layouting) evas_object_smart_changed(box);
151}
152
153static void
154_on_hints_changed(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *o , void *einfo __UNUSED__)
155{
156 _sizing_eval(o);
157}
158
159static Evas_Object_Box_Option *
160_evas_object_box_option_new(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child)
161{
162 Evas_Object_Box_Option *opt;
163 const Evas_Object_Box_Api *api;
164
165 api = priv->api;
166 if ((!api) || (!api->option_new))
167 {
168 ERR("no api->option_new");
169 return NULL;
170 }
171
172 opt = api->option_new(o, priv, child);
173 if (!opt)
174 {
175 ERR("option_new failed");
176 return NULL;
177 }
178
179 return opt;
180}
181
182static void
183_evas_object_box_child_callbacks_unregister(Evas_Object *obj)
184{
185 evas_object_event_callback_del
186 (obj, EVAS_CALLBACK_RESIZE, _on_child_resize);
187 evas_object_event_callback_del
188 (obj, EVAS_CALLBACK_FREE, _on_child_del);
189 evas_object_event_callback_del
190 (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed);
191}
192
193static Evas_Object_Box_Option *
194_evas_object_box_option_callbacks_register(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object_Box_Option *opt)
195{
196 const Evas_Object_Box_Api *api;
197 Evas_Object *obj = opt->obj;
198
199 api = priv->api;
200
201 if ((!api) || (!api->option_free))
202 {
203 WRN("api->option_free not set (may cause memory leaks, segfaults)");
204 return NULL;
205 }
206
207 evas_object_event_callback_add
208 (obj, EVAS_CALLBACK_RESIZE, _on_child_resize, o);
209 evas_object_event_callback_add
210 (obj, EVAS_CALLBACK_FREE, _on_child_del, o);
211 evas_object_event_callback_add
212 (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
213
214 return opt;
215}
216
217static Evas_Object_Box_Option *
218_evas_object_box_option_new_default(Evas_Object *o __UNUSED__, Evas_Object_Box_Data *priv __UNUSED__, Evas_Object *child)
219{
220 Evas_Object_Box_Option *opt;
221
222 opt = (Evas_Object_Box_Option *)malloc(sizeof(*opt));
223 if (!opt)
224 return NULL;
225
226 opt->obj = child;
227
228 return opt;
229}
230
231static void
232_evas_object_box_option_free_default(Evas_Object *o __UNUSED__, Evas_Object_Box_Data *priv __UNUSED__, Evas_Object_Box_Option *opt)
233{
234 free(opt);
235}
236
237static Evas_Object_Box_Option *
238_evas_object_box_append_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child)
239{
240 Evas_Object_Box_Option *opt;
241
242 opt = _evas_object_box_option_new(o, priv, child);
243 if (!opt)
244 return NULL;
245
246 priv->children = eina_list_append(priv->children, opt);
247 priv->children_changed = EINA_TRUE;
248 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt);
249
250 return opt;
251}
252
253static Evas_Object_Box_Option *
254_evas_object_box_prepend_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child)
255{
256 Evas_Object_Box_Option *opt;
257
258 opt = _evas_object_box_option_new(o, priv, child);
259 if (!opt)
260 return NULL;
261
262 priv->children = eina_list_prepend(priv->children, opt);
263 priv->children_changed = EINA_TRUE;
264 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt);
265
266 return opt;
267}
268
269static Evas_Object_Box_Option *
270_evas_object_box_insert_before_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, const Evas_Object *reference)
271{
272 Eina_List *l;
273 Evas_Object_Box_Option *opt;
274
275 EINA_LIST_FOREACH(priv->children, l, opt)
276 {
277 if (opt->obj == reference)
278 {
279 Evas_Object_Box_Option *new_opt;
280
281 new_opt = _evas_object_box_option_new(o, priv, child);
282 if (!new_opt)
283 return NULL;
284
285 priv->children = eina_list_prepend_relative
286 (priv->children, new_opt, opt);
287 priv->children_changed = EINA_TRUE;
288 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
289 return new_opt;
290 }
291 }
292
293 return NULL;
294}
295
296static Evas_Object_Box_Option *
297_evas_object_box_insert_after_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, const Evas_Object *reference)
298{
299 Eina_List *l;
300 Evas_Object_Box_Option *opt;
301
302 EINA_LIST_FOREACH(priv->children, l, opt)
303 {
304 if (opt->obj == reference)
305 {
306 Evas_Object_Box_Option *new_opt;
307
308 new_opt = _evas_object_box_option_new(o, priv, child);
309 if (!new_opt)
310 return NULL;
311
312 priv->children = eina_list_append_relative
313 (priv->children, new_opt, opt);
314 priv->children_changed = EINA_TRUE;
315 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
316 return new_opt;
317 }
318 }
319
320 return NULL;
321}
322
323static Evas_Object_Box_Option *
324_evas_object_box_insert_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, unsigned int pos)
325{
326 Eina_List *l;
327 unsigned int i;
328
329 if ((pos == 0) && (eina_list_count(priv->children) == 0))
330 {
331 Evas_Object_Box_Option *new_opt;
332
333 new_opt = _evas_object_box_option_new(o, priv, child);
334 if (!new_opt)
335 return NULL;
336
337 priv->children = eina_list_prepend(priv->children, new_opt);
338 priv->children_changed = EINA_TRUE;
339 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
340 return new_opt;
341 }
342
343 for (l = priv->children, i = 0; l; l = l->next, i++)
344 {
345 Evas_Object_Box_Option *opt = l->data;
346
347 if (i == pos)
348 {
349 Evas_Object_Box_Option *new_opt;
350
351 new_opt = _evas_object_box_option_new(o, priv, child);
352 if (!new_opt)
353 return NULL;
354
355 priv->children = eina_list_prepend_relative
356 (priv->children, new_opt, opt);
357 priv->children_changed = EINA_TRUE;
358 evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt);
359 return new_opt;
360 }
361 }
362
363 return NULL;
364}
365
366static Evas_Object *
367_evas_object_box_remove_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child)
368{
369 const Evas_Object_Box_Api *api;
370 Evas_Object_Box_Option *opt;
371 Eina_List *l;
372
373 api = priv->api;
374
375 if ((!api) || (!api->option_free))
376 {
377 ERR("api->option_free not set (may cause memory leaks, segfaults)");
378 return NULL;
379 }
380
381 EINA_LIST_FOREACH(priv->children, l, opt)
382 {
383 Evas_Object *obj = opt->obj;
384
385 if (obj == child)
386 {
387 priv->children = eina_list_remove(priv->children, opt);
388 api->option_free(o, priv, opt);
389 priv->children_changed = EINA_TRUE;
390 evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj);
391
392 return obj;
393 }
394 }
395
396 return NULL;
397}
398
399static Evas_Object *
400_evas_object_box_remove_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, unsigned int pos)
401{
402 const Evas_Object_Box_Api *api;
403 Eina_List *node;
404 Evas_Object_Box_Option *opt;
405 Evas_Object *obj;
406
407 api = priv->api;
408
409 if ((!api) || (!api->option_free))
410 {
411 WRN("api->option_free not set (may cause memory leaks, segfaults)");
412 return NULL;
413 }
414
415 node = eina_list_nth_list(priv->children, pos);
416 if (!node)
417 {
418 ERR("No item to be removed at position %d", pos);
419 return NULL;
420 }
421
422 opt = node->data;
423 obj = opt->obj;
424
425 priv->children = eina_list_remove_list(priv->children, node);
426 api->option_free(o, priv, opt);
427 priv->children_changed = EINA_TRUE;
428 evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj);
429 return obj;
430}
431
432static void
433_evas_object_box_smart_add(Evas_Object *o)
434{
435 Evas_Object_Box_Data *priv;
436
437 priv = evas_object_smart_data_get(o);
438 if (!priv)
439 {
440 const Evas_Smart *smart;
441 const Evas_Smart_Class *sc;
442
443 priv = (Evas_Object_Box_Data *)calloc(1, sizeof(*priv));
444 if (!priv)
445 {
446 ERR("Could not allocate object private data.");
447 return;
448 }
449
450 smart = evas_object_smart_smart_get(o);
451 sc = evas_smart_class_get(smart);
452 priv->api = (const Evas_Object_Box_Api *)sc;
453
454 evas_object_smart_data_set(o, priv);
455 }
456 _evas_object_box_parent_sc->add(o);
457
458
459 evas_object_event_callback_add
460 (o, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_hints_changed, o);
461 priv->children = NULL;
462 priv->align.h = 0.5;
463 priv->align.v = 0.5;
464 priv->pad.h = 0;
465 priv->pad.v = 0;
466 priv->layout.cb = evas_object_box_layout_horizontal;
467 priv->layout.data = NULL;
468 priv->layout.free_data = NULL;
469}
470
471static void
472_evas_object_box_smart_del(Evas_Object *o)
473{
474 const Evas_Object_Box_Api *api;
475 Eina_List *l;
476
477 EVAS_OBJECT_BOX_DATA_GET(o, priv);
478
479 api = priv->api;
480 if ((!api) || (!api->option_free))
481 {
482 WRN("api->option_free not set (may cause memory leaks, segfaults)");
483 return;
484 }
485
486 l = priv->children;
487 while (l)
488 {
489 Evas_Object_Box_Option *opt = l->data;
490
491 _evas_object_box_child_callbacks_unregister(opt->obj);
492 api->option_free(o, priv, opt);
493 l = eina_list_remove_list(l, l);
494 }
495
496 if (priv->layout.data && priv->layout.free_data)
497 priv->layout.free_data(priv->layout.data);
498
499 _evas_object_box_parent_sc->del(o);
500}
501
502static void
503_evas_object_box_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
504{
505 Evas_Coord ow, oh;
506 evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
507 if ((ow == w) && (oh == h)) return;
508 evas_object_smart_changed(o);
509}
510
511static void
512_evas_object_box_smart_calculate(Evas_Object *o)
513{
514 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
515 if (priv->layout.cb)
516 {
517 priv->layouting = 1;
518 priv->layout.cb(o, priv, priv->layout.data);
519 priv->layouting = 0;
520 priv->children_changed = EINA_FALSE;
521 }
522 else
523 ERR("No layout function set for %p box.", o);
524}
525
526static void
527_evas_object_box_smart_set_user(Evas_Object_Box_Api *api)
528{
529 api->base.add = _evas_object_box_smart_add;
530 api->base.del = _evas_object_box_smart_del;
531 api->base.resize = _evas_object_box_smart_resize;
532 api->base.calculate = _evas_object_box_smart_calculate;
533 api->base.callbacks = _signals;
534
535 api->append = _evas_object_box_append_default;
536 api->prepend = _evas_object_box_prepend_default;
537 api->insert_before = _evas_object_box_insert_before_default;
538 api->insert_after = _evas_object_box_insert_after_default;
539 api->insert_at = _evas_object_box_insert_at_default;
540 api->remove = _evas_object_box_remove_default;
541 api->remove_at = _evas_object_box_remove_at_default;
542 api->option_new = _evas_object_box_option_new_default;
543 api->option_free = _evas_object_box_option_free_default;
544}
545
546EAPI Evas_Object *
547evas_object_box_add(Evas *evas)
548{
549 return evas_object_smart_add(evas, _evas_object_box_smart_class_new());
550}
551
552EAPI Evas_Object *
553evas_object_box_add_to(Evas_Object *parent)
554{
555 Evas *evas;
556 Evas_Object *o;
557
558 evas = evas_object_evas_get(parent);
559 o = evas_object_box_add(evas);
560 evas_object_smart_member_add(o, parent);
561 return o;
562}
563
564EAPI void
565evas_object_box_smart_set(Evas_Object_Box_Api *api)
566{
567 if (!api)
568 return;
569 _evas_object_box_smart_set(api);
570}
571
572EAPI const Evas_Object_Box_Api *
573evas_object_box_smart_class_get(void)
574{
575 static Evas_Object_Box_Api _sc =
576 EVAS_OBJECT_BOX_API_INIT_NAME_VERSION(_evas_object_box_type);
577 static const Evas_Object_Box_Api *class = NULL;
578
579 if (class)
580 return class;
581
582 evas_object_box_smart_set(&_sc);
583 class = &_sc;
584
585 return class;
586}
587
588EAPI void
589evas_object_box_layout_set(Evas_Object *o, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data))
590{
591 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
592
593 if ((priv->layout.cb == cb) && (priv->layout.data == data) &&
594 (priv->layout.free_data == free_data))
595 return;
596
597 if (priv->layout.data && priv->layout.free_data)
598 priv->layout.free_data(priv->layout.data);
599
600 priv->layout.cb = cb;
601 priv->layout.data = (void *)data;
602 priv->layout.free_data = free_data;
603 evas_object_smart_changed(o);
604}
605
606static void
607_fixed_point_divide_and_decompose_integer(int dividend, int divisor, int *int_part, int *frac_part)
608{
609 int quotient = (long long)(dividend << 16) / divisor;
610 *frac_part = quotient & 0xffff;
611 *int_part = quotient >> 16;
612}
613
614static void
615_layout_dimension_change_min_max_cell_bound(int dim, int *new_dim, int min_d, int max_d, int cell_sz)
616{
617 if (dim > cell_sz)
618 {
619 if ((min_d != 0) && (cell_sz < min_d))
620 *new_dim = min_d;
621 else
622 *new_dim = cell_sz;
623 }
624 else
625 {
626 if ((max_d != -1) && (cell_sz > max_d))
627 *new_dim = max_d;
628 else
629 *new_dim = cell_sz;
630 }
631}
632
633static void
634_layout_set_offset_and_expand_dimension_space_max_bounded(int dim, int *new_dim, int space_sz, int max_dim, int *offset, double align, int pad_before, int pad_after)
635{
636 if (align >= 0.0)
637 {
638 *new_dim = dim;
639 *offset = (space_sz - (dim + pad_before + pad_after)) * align
640 + pad_before;
641 }
642 else
643 {
644 if ((max_dim != -1) && (space_sz > max_dim))
645 {
646 *new_dim = max_dim;
647 *offset = (space_sz - (max_dim + pad_before + pad_after)) * 0.5
648 + pad_before;
649 }
650 else
651 {
652 *new_dim = space_sz;
653 *offset = 0;
654 }
655 }
656}
657
658static void
659_layout_set_offset_and_change_dimension_min_max_cell_bounded(int dim, int *new_dim, int min_dim, int max_dim, int cell_sz, int *offset, double align, int pad_before, int pad_after)
660{
661 if (align >= 0.0)
662 {
663 *new_dim = dim;
664 *offset =
665 (cell_sz - (dim + pad_before + pad_after)) * align + pad_before;
666 }
667 else
668 {
669 *offset = pad_before;
670 _layout_dimension_change_min_max_cell_bound
671 (dim, new_dim, min_dim, max_dim, cell_sz - pad_before - pad_after);
672 }
673}
674
675static void
676_sizing_eval(Evas_Object *obj)
677{
678 Evas_Coord minw, minh, maxw, maxh;
679 Evas_Coord w, h;
680
681 evas_object_size_hint_min_get(obj, &minw, &minh);
682 evas_object_size_hint_max_get(obj, &maxw, &maxh);
683 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
684
685 if (w < minw) w = minw;
686 if (h < minh) h = minh;
687 if ((maxw >= 0) && (w > maxw)) w = maxw;
688 if ((maxh >= 0) && (h > maxh)) h = maxh;
689
690 evas_object_resize(obj, w, h);
691}
692
693static int
694_evas_object_box_layout_horizontal_weight_apply(Evas_Object_Box_Data *priv, Evas_Object_Box_Option **objects, int n_objects, int remaining, int weight_total)
695{
696 int rem_diff = 0;
697 int i;
698
699 for (i = 0; i < n_objects; i++)
700 {
701 Evas_Object_Box_Option *opt = objects[i];
702 Evas_Object *o = opt->obj;
703 int h;
704
705 evas_object_geometry_get(o, NULL, NULL, NULL, &h);
706
707 if (remaining <= 0)
708 {
709 int min_w;
710
711 evas_object_size_hint_min_get(o, &min_w, NULL);
712 evas_object_resize(o, min_w, h);
713 }
714 else
715 {
716 double normal_weight, weight_x;
717 int target_size;
718 int max_w;
719
720 evas_object_size_hint_weight_get(o, &weight_x, NULL);
721 normal_weight = weight_x / weight_total;
722 target_size = (int)((double)remaining * normal_weight);
723
724 evas_object_size_hint_max_get(o, &max_w, NULL);
725 if ((max_w != -1) && (target_size > max_w))
726 {
727 evas_object_resize(o, max_w, h);
728 rem_diff += max_w;
729 objects[i] = objects[n_objects - 1];
730 weight_total -= weight_x;
731 n_objects--;
732 return _evas_object_box_layout_horizontal_weight_apply
733 (priv, objects, n_objects, remaining - rem_diff,
734 weight_total);
735 }
736 else
737 {
738 evas_object_resize(o, target_size, h);
739 rem_diff += target_size;
740 }
741 }
742 }
743
744 return remaining - rem_diff;
745}
746
747EAPI void
748evas_object_box_layout_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
749{
750 int pad_inc = 0, sub_pixel = 0;
751 int req_w, global_pad, remaining, top_h = 0;
752 double weight_total = 0.0;
753 int weight_use = 0;
754 int x, y, w, h;
755 int n_children;
756 Evas_Object_Box_Option *opt;
757 Evas_Object_Box_Option **objects;
758 Eina_List *l;
759
760 n_children = eina_list_count(priv->children);
761 if (!n_children)
762 return;
763
764 objects = (Evas_Object_Box_Option **)alloca(sizeof(Evas_Object_Box_Option *) * n_children);
765 if (!objects)
766 return;
767
768 evas_object_geometry_get(o, &x, &y, &w, &h);
769 global_pad = priv->pad.h;
770 req_w = global_pad * (n_children - 1);
771
772 EINA_LIST_FOREACH(priv->children, l, opt)
773 {
774 int padding_l, padding_r;
775 double weight_x;
776
777 _sizing_eval(opt->obj);
778 evas_object_size_hint_weight_get(opt->obj, &weight_x, NULL);
779 evas_object_size_hint_padding_get
780 (opt->obj, &padding_l, &padding_r, NULL, NULL);
781 req_w += padding_l + padding_r;
782
783 if (!weight_x)
784 {
785 int child_w;
786
787 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, NULL);
788 req_w += child_w;
789 }
790 else
791 {
792 objects[weight_use] = opt;
793 weight_use++;
794 weight_total += weight_x;
795 }
796 }
797
798 remaining = w - req_w;
799
800 if (weight_use)
801 remaining = _evas_object_box_layout_horizontal_weight_apply
802 (priv, objects, weight_use, remaining, weight_total);
803
804 if (priv->align.h >= 0.0)
805 x += remaining * priv->align.h;
806 else if (n_children == 1)
807 x += remaining / 2;
808 else
809 { /* justified */
810 _fixed_point_divide_and_decompose_integer
811 (remaining, n_children - 1, &global_pad, &pad_inc);
812 global_pad += priv->pad.h;
813 }
814
815 EINA_LIST_FOREACH(priv->children, l, opt)
816 {
817 int child_w, child_h, max_h, new_h, off_x, off_y;
818 int padding_l, padding_r, padding_t, padding_b;
819 double align_y;
820
821 evas_object_size_hint_align_get(opt->obj, NULL, &align_y);
822 evas_object_size_hint_padding_get
823 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
824 evas_object_size_hint_max_get(opt->obj, NULL, &max_h);
825
826 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
827
828 off_x = padding_l;
829 new_h = child_h;
830 if (new_h > top_h) top_h = new_h;
831
832 _layout_set_offset_and_expand_dimension_space_max_bounded
833 (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b);
834
835 if (new_h != child_h)
836 evas_object_resize(opt->obj, child_w, new_h);
837 evas_object_move(opt->obj, x + off_x, y + off_y);
838
839 x += child_w + padding_l + padding_r + global_pad;
840 sub_pixel += pad_inc;
841 if (sub_pixel >= 1 << 16)
842 {
843 x++;
844 sub_pixel -= 1 << 16;
845 }
846 }
847
848 evas_object_size_hint_min_set(o, req_w, top_h);
849}
850
851static int
852_evas_object_box_layout_vertical_weight_apply(Evas_Object_Box_Data *priv, Evas_Object_Box_Option **objects, int n_objects, int remaining, int weight_total)
853{
854 int rem_diff = 0;
855 int i;
856
857 for (i = 0; i < n_objects; i++)
858 {
859 Evas_Object_Box_Option *opt = objects[i];
860 Evas_Object *o = opt->obj;
861 int w;
862
863 evas_object_geometry_get(o, NULL, NULL, &w, NULL);
864
865 if (remaining <= 0)
866 {
867 int min_h;
868
869 evas_object_size_hint_min_get(o, NULL, &min_h);
870 evas_object_resize(o, w, min_h);
871 }
872 else
873 {
874 double normal_weight, weight_y;
875 int target_size;
876 int max_h;
877
878 evas_object_size_hint_weight_get(o, NULL, &weight_y);
879 normal_weight = weight_y / weight_total;
880 target_size = (int)((double)remaining * normal_weight);
881
882 evas_object_size_hint_max_get(o, NULL, &max_h);
883 if ((max_h != -1) && (target_size > max_h))
884 {
885 evas_object_resize(o, w, max_h);
886 rem_diff += max_h;
887 objects[i] = objects[n_objects - 1];
888 weight_total -= weight_y;
889 n_objects--;
890 return _evas_object_box_layout_vertical_weight_apply
891 (priv, objects, n_objects, remaining - rem_diff,
892 weight_total);
893 }
894 else
895 {
896 evas_object_resize(o, w, target_size);
897 rem_diff += target_size;
898 }
899 }
900 }
901
902 return remaining - rem_diff;
903}
904
905EAPI void
906evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
907{
908 int pad_inc = 0, sub_pixel = 0;
909 int req_h, global_pad, remaining, top_w = 0;
910 double weight_total = 0.0;
911 int weight_use = 0;
912 int x, y, w, h;
913 int n_children;
914 Evas_Object_Box_Option *opt;
915 Evas_Object_Box_Option **objects;
916 Eina_List *l;
917
918 n_children = eina_list_count(priv->children);
919 if (!n_children)
920 return;
921
922 objects = (Evas_Object_Box_Option **)alloca(sizeof(Evas_Object_Box_Option *) * n_children);
923 if (!objects)
924 return;
925
926 evas_object_geometry_get(o, &x, &y, &w, &h);
927 global_pad = priv->pad.v;
928 req_h = global_pad * (n_children - 1);
929
930 EINA_LIST_FOREACH(priv->children, l, opt)
931 {
932 int padding_t, padding_b;
933 double weight_y;
934
935 _sizing_eval(opt->obj);
936 evas_object_size_hint_weight_get(opt->obj, NULL, &weight_y);
937 evas_object_size_hint_padding_get
938 (opt->obj, NULL, NULL, &padding_t, &padding_b);
939 req_h += padding_t + padding_b;
940
941 if (!weight_y)
942 {
943 int child_h;
944
945 evas_object_geometry_get(opt->obj, NULL, NULL, NULL, &child_h);
946 req_h += child_h;
947 }
948 else
949 {
950 objects[weight_use] = opt;
951 weight_use++;
952 weight_total += weight_y;
953 }
954 }
955
956 remaining = h - req_h;
957
958 if (weight_use)
959 remaining = _evas_object_box_layout_vertical_weight_apply
960 (priv, objects, weight_use, remaining, weight_total);
961
962 if (priv->align.v >= 0.0)
963 y += remaining * priv->align.v;
964 else if (n_children == 1)
965 y += remaining / 2;
966 else
967 { /* justified */
968 _fixed_point_divide_and_decompose_integer
969 (remaining, n_children - 1, &global_pad, &pad_inc);
970 global_pad += priv->pad.v;
971 }
972
973 EINA_LIST_FOREACH(priv->children, l, opt)
974 {
975 int child_w, child_h, max_w, new_w, off_x, off_y;
976 int padding_l, padding_r, padding_t, padding_b;
977 double align_x;
978
979 evas_object_size_hint_align_get(opt->obj, &align_x, NULL);
980 evas_object_size_hint_padding_get
981 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
982 evas_object_size_hint_max_get(opt->obj, &max_w, NULL);
983
984 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
985
986 off_y = padding_t;
987 new_w = child_w;
988
989 _layout_set_offset_and_expand_dimension_space_max_bounded
990 (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r);
991
992 if (new_w > top_w) top_w = new_w;
993
994 if (new_w != child_w)
995 evas_object_resize(opt->obj, new_w, child_h);
996 evas_object_move(opt->obj, x + off_x, y + off_y);
997
998 y += child_h + padding_t + padding_b + global_pad;
999 sub_pixel += pad_inc;
1000 if (sub_pixel >= 1 << 16)
1001 {
1002 y++;
1003 sub_pixel -= 1 << 16;
1004 }
1005 }
1006
1007 evas_object_size_hint_min_set(o, top_w, req_h);
1008}
1009
1010EAPI void
1011evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1012{
1013 int cell_sz, share, inc;
1014 int sub_pixel = 0;
1015 int x, y, w, h;
1016 int n_children;
1017 Evas_Object_Box_Option *opt;
1018 Eina_List *l;
1019
1020 n_children = eina_list_count(priv->children);
1021 if (!n_children)
1022 return;
1023
1024 evas_object_geometry_get(o, &x, &y, &w, &h);
1025
1026 share = w - priv->pad.h * (n_children - 1);
1027 _fixed_point_divide_and_decompose_integer
1028 (share, n_children, &cell_sz, &inc);
1029
1030 EINA_LIST_FOREACH(priv->children, l, opt)
1031 {
1032 int child_w, child_h, max_h, min_w, max_w, new_w, new_h, off_x, off_y;
1033 int padding_l, padding_r, padding_t, padding_b;
1034 double align_x, align_y;
1035
1036 evas_object_size_hint_align_get(opt->obj, &align_x, &align_y);
1037 evas_object_size_hint_padding_get
1038 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1039 evas_object_size_hint_max_get(opt->obj, &max_w, &max_h);
1040 evas_object_size_hint_min_get(opt->obj, &min_w, NULL);
1041
1042 _sizing_eval(opt->obj);
1043 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1044
1045 new_w = child_w;
1046 new_h = child_h;
1047
1048 _layout_set_offset_and_expand_dimension_space_max_bounded
1049 (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b);
1050
1051 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1052 (child_w, &new_w, min_w, max_w, cell_sz, &off_x, align_x,
1053 padding_l, padding_r);
1054
1055 if ((new_w != child_w) || (new_h != child_h))
1056 evas_object_resize(opt->obj, new_w, new_h);
1057 evas_object_move(opt->obj, x + off_x, y + off_y);
1058
1059 x += cell_sz + priv->pad.h;
1060 sub_pixel += inc;
1061 if (sub_pixel >= 1 << 16)
1062 {
1063 x++;
1064 sub_pixel -= 1 << 16;
1065 }
1066 }
1067
1068 evas_object_size_hint_min_set(o, w, h);
1069}
1070
1071EAPI void
1072evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1073{
1074 int cell_sz, share, inc;
1075 int sub_pixel = 0;
1076 int x, y, w, h;
1077 int n_children;
1078 Evas_Object_Box_Option *opt;
1079 Eina_List *l;
1080
1081 n_children = eina_list_count(priv->children);
1082 if (!n_children)
1083 return;
1084
1085 evas_object_geometry_get(o, &x, &y, &w, &h);
1086
1087 share = h - priv->pad.v * (n_children - 1);
1088 _fixed_point_divide_and_decompose_integer
1089 (share, n_children, &cell_sz, &inc);
1090
1091 EINA_LIST_FOREACH(priv->children, l, opt)
1092 {
1093 int child_w, child_h, max_w, min_h, max_h, new_w, new_h, off_x, off_y;
1094 int padding_l, padding_r, padding_t, padding_b;
1095 double align_x, align_y;
1096
1097 evas_object_size_hint_align_get(opt->obj, &align_x, &align_y);
1098 evas_object_size_hint_padding_get
1099 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1100 evas_object_size_hint_max_get(opt->obj, &max_w, &max_h);
1101 evas_object_size_hint_min_get(opt->obj, NULL, &min_h);
1102
1103 _sizing_eval(opt->obj);
1104 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1105 new_w = child_w;
1106 new_h = child_h;
1107
1108 _layout_set_offset_and_expand_dimension_space_max_bounded
1109 (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r);
1110
1111 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1112 (child_h, &new_h, min_h, max_h, cell_sz, &off_y, align_y,
1113 padding_t, padding_b);
1114
1115 if ((new_w != child_w) || (new_h != child_h))
1116 evas_object_resize(opt->obj, new_w, new_h);
1117 evas_object_move(opt->obj, x + off_x, y + off_y);
1118
1119 y += cell_sz + priv->pad.v;
1120 sub_pixel += inc;
1121 if (sub_pixel >= 1 << 16)
1122 {
1123 y++;
1124 sub_pixel -= 1 << 16;
1125 }
1126 }
1127
1128 evas_object_size_hint_min_set(o, w, h);
1129}
1130
1131EAPI void
1132evas_object_box_layout_homogeneous_max_size_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1133{
1134 int remaining, global_pad, pad_inc = 0, sub_pixel = 0;
1135 int cell_sz = 0;
1136 int x, y, w, h;
1137 int top_h = 0;
1138 int n_children;
1139 Evas_Object_Box_Option *opt;
1140 Eina_List *l;
1141
1142 n_children = eina_list_count(priv->children);
1143 if (!n_children)
1144 return;
1145
1146 evas_object_geometry_get(o, &x, &y, &w, &h);
1147
1148 EINA_LIST_FOREACH(priv->children, l, opt)
1149 {
1150 int child_w, padding_l, padding_r;
1151
1152 _sizing_eval(opt->obj);
1153 evas_object_size_hint_padding_get
1154 (opt->obj, &padding_l, &padding_r, NULL, NULL);
1155 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, NULL);
1156 if (child_w + padding_l + padding_r > cell_sz)
1157 cell_sz = child_w + padding_l + padding_r;
1158 }
1159
1160 global_pad = priv->pad.h;
1161 remaining = w - n_children * cell_sz - global_pad * (n_children - 1);
1162
1163 if (priv->align.h >= 0.0)
1164 x += remaining * priv->align.h;
1165 else if (n_children == 1)
1166 x += remaining / 2;
1167 else
1168 { /* justified */
1169 _fixed_point_divide_and_decompose_integer
1170 (remaining, n_children - 1, &global_pad, &pad_inc);
1171 global_pad += priv->pad.h;
1172 }
1173
1174 EINA_LIST_FOREACH(priv->children, l, opt)
1175 {
1176 int child_w, child_h, min_w, max_w, max_h, new_w, new_h, off_x, off_y;
1177 int padding_l, padding_r, padding_t, padding_b;
1178 double align_x, align_y;
1179
1180 evas_object_size_hint_align_get(opt->obj, &align_x, &align_y);
1181 evas_object_size_hint_padding_get
1182 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1183 evas_object_size_hint_max_get(opt->obj, &max_w, &max_h);
1184 evas_object_size_hint_min_get(opt->obj, &min_w, NULL);
1185
1186 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1187
1188 new_w = child_w;
1189 new_h = child_h;
1190 if (new_h > top_h) top_h = new_h;
1191
1192 _layout_set_offset_and_expand_dimension_space_max_bounded
1193 (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b);
1194
1195 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1196 (child_w, &new_w, min_w, max_w, cell_sz, &off_x, align_x,
1197 padding_l, padding_r);
1198
1199 if ((new_w != child_w) || (new_h != child_h))
1200 evas_object_resize(opt->obj, new_w, new_h);
1201 evas_object_move(opt->obj, x + off_x, y + off_y);
1202
1203 x += cell_sz + global_pad;
1204 sub_pixel += pad_inc;
1205 if (sub_pixel >= 1 << 16)
1206 {
1207 x++;
1208 sub_pixel -= 1 << 16;
1209 }
1210 }
1211
1212 evas_object_size_hint_min_set(o, x, top_h);
1213}
1214
1215EAPI void
1216evas_object_box_layout_homogeneous_max_size_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1217{
1218 int remaining, global_pad, pad_inc = 0, sub_pixel = 0;
1219 int cell_sz = 0;
1220 int x, y, w, h;
1221 int top_w = 0;
1222 int n_children;
1223 Evas_Object_Box_Option *opt;
1224 Eina_List *l;
1225
1226 n_children = eina_list_count(priv->children);
1227 if (!n_children)
1228 return;
1229
1230 evas_object_geometry_get(o, &x, &y, &w, &h);
1231
1232 EINA_LIST_FOREACH(priv->children, l, opt)
1233 {
1234 int child_h, padding_t, padding_b;
1235
1236 _sizing_eval(opt->obj);
1237 evas_object_size_hint_padding_get
1238 (opt->obj, NULL, NULL, &padding_t, &padding_b);
1239 evas_object_geometry_get(opt->obj, NULL, NULL, NULL, &child_h);
1240 if (child_h + padding_t + padding_b > cell_sz)
1241 cell_sz = child_h + padding_t + padding_b;
1242 }
1243
1244 global_pad = priv->pad.v;
1245 remaining = h - n_children * cell_sz - global_pad * (n_children - 1);
1246
1247 if (priv->align.v >= 0.0)
1248 y += remaining * priv->align.v;
1249 else if (n_children == 1)
1250 y += remaining / 2;
1251 else
1252 { /* justified */
1253 _fixed_point_divide_and_decompose_integer
1254 (remaining, n_children - 1, &global_pad, &pad_inc);
1255 global_pad += priv->pad.v;
1256 }
1257
1258 EINA_LIST_FOREACH(priv->children, l, opt)
1259 {
1260 int child_w, child_h, max_h, min_h, max_w, new_w, new_h, off_x, off_y;
1261 int padding_l, padding_r, padding_t, padding_b;
1262 double align_x, align_y;
1263
1264 evas_object_size_hint_align_get(opt->obj, &align_x, &align_y);
1265 evas_object_size_hint_padding_get
1266 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1267 evas_object_size_hint_max_get(opt->obj, &max_w, &max_h);
1268 evas_object_size_hint_min_get(opt->obj, NULL, &min_h);
1269
1270 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1271
1272 new_w = child_w;
1273 new_h = child_h;
1274 if (new_w > top_w) top_w = new_w;
1275
1276 _layout_set_offset_and_expand_dimension_space_max_bounded
1277 (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r);
1278
1279 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1280 (child_h, &new_h, min_h, max_h, cell_sz, &off_y, align_y,
1281 padding_t, padding_b);
1282
1283 if ((new_w != child_w) || (new_h != child_h))
1284 evas_object_resize(opt->obj, new_w, new_h);
1285 evas_object_move(opt->obj, x + off_x, y + off_y);
1286
1287 y += cell_sz + global_pad;
1288 sub_pixel += pad_inc;
1289 if (sub_pixel >= 1 << 16)
1290 {
1291 y++;
1292 sub_pixel -= 1 << 16;
1293 }
1294 }
1295
1296 evas_object_size_hint_min_set(o, top_w, y);
1297}
1298
1299static void
1300_evas_object_box_layout_flow_horizontal_row_info_collect(Evas_Object_Box_Data *priv, int box_w, int *row_count, int *row_max_h, int *row_break, int *row_width, int *off_y_ret, int *max_h_ret)
1301{
1302 int i, remain_w = box_w, start_i = 0;
1303 int off_y = 0, max_h = 0, n_rows = 0;
1304 Eina_List *l;
1305
1306 for (i = 0, l = priv->children; l; i++, l = l->next)
1307 {
1308 Evas_Object_Box_Option *opt = l->data;
1309 int padding_l, padding_r, padding_t, padding_b;
1310 int child_w, child_h, off_x = 0;
1311
1312 evas_object_size_hint_padding_get
1313 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1314
1315 _sizing_eval(opt->obj);
1316 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1317
1318 child_w += padding_l + padding_r + priv->pad.h;
1319 child_h += padding_t + padding_b;
1320
1321 remain_w -= child_w;
1322 if (remain_w + priv->pad.h >= 0)
1323 { /* continue "line" */
1324 if (child_h > max_h)
1325 max_h = child_h;
1326
1327 off_x += child_w;
1328 row_width[n_rows] += child_w;
1329 }
1330 else
1331 { /* break line */
1332 if (i == start_i)
1333 { /* obj goes to actual line */
1334 max_h = child_h;
1335 row_width[n_rows] = child_w;
1336 }
1337 else
1338 { /* obj goes to next line */
1339 row_max_h[n_rows] = max_h;
1340 row_break[n_rows] = i - 1;
1341 n_rows++;
1342
1343 off_x = child_w;
1344 off_y += max_h;
1345 max_h = child_h;
1346
1347 row_width[n_rows] = child_w;
1348 start_i = i;
1349
1350 remain_w = box_w - off_x;
1351 }
1352 }
1353 }
1354
1355 row_break[n_rows] = i - 1;
1356 row_max_h[n_rows] = max_h;
1357
1358 *row_count = n_rows;
1359 *off_y_ret = off_y;
1360 *max_h_ret = max_h;
1361}
1362
1363EAPI void
1364evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1365{
1366 int n_children, v_justify;
1367 int r, row_count = 0;
1368 int min_w = 0, min_h = 0;
1369 int max_h, inc_y;
1370 int remain_y, i;
1371 int x, y, w, h;
1372 Eina_List *l;
1373 int *row_max_h;
1374 int *row_break;
1375 int *row_width;
1376 int offset_y;
1377
1378 n_children = eina_list_count(priv->children);
1379 if (!n_children)
1380 return;
1381
1382 /* *per row* arrays */
1383 row_max_h = (int *)alloca(sizeof(int) * n_children);
1384 if (!row_max_h)
1385 return;
1386 row_break = (int *)alloca(sizeof(int) * n_children);
1387 if (!row_break)
1388 return;
1389 row_width = (int *)alloca(sizeof(int) * n_children);
1390 if (!row_width)
1391 return;
1392
1393 memset(row_width, 0, sizeof(row_width));
1394
1395 evas_object_geometry_get(o, &x, &y, &w, &h);
1396
1397 _evas_object_box_layout_flow_horizontal_row_info_collect
1398 (priv, w, &row_count, row_max_h, row_break, row_width, &offset_y, &max_h);
1399
1400 inc_y = 0;
1401 v_justify = 0;
1402 remain_y = h - (offset_y + max_h);
1403
1404 if (remain_y > 0)
1405 {
1406 if (priv->align.v >= 0.0)
1407 inc_y = priv->align.v * remain_y;
1408 else if (row_count == 0)
1409 y += remain_y / 2;
1410 else /* y-justified */
1411 inc_y = remain_y / row_count;
1412 }
1413
1414 inc_y += priv->pad.v;
1415
1416 for (i = 0, r = 0, l = priv->children; r <= row_count; r++)
1417 {
1418 int row_justify = 0, just_inc = 0, sub_pixel = 0;
1419 int row_size, remain_x;
1420
1421 row_size = row_break[r] - i;
1422 remain_x = (w - row_width[r]);
1423
1424 if (priv->align.h < 0.0)
1425 {
1426 if (row_size == 0)
1427 x += remain_x / 2;
1428 else
1429 _fixed_point_divide_and_decompose_integer
1430 (remain_x, row_size, &row_justify, &just_inc);
1431 }
1432
1433 row_justify += priv->pad.h;
1434
1435 for (; i <= row_break[r]; i++, l = l->next)
1436 {
1437 Evas_Object_Box_Option *opt = l->data;
1438 int off_x, off_y, y_remain;
1439 int padding_l, padding_r;
1440 int child_w, child_h;
1441 double align_y;
1442
1443 evas_object_size_hint_align_get(opt->obj, NULL, &align_y);
1444 evas_object_size_hint_padding_get
1445 (opt->obj, &padding_l, &padding_r, NULL, NULL);
1446
1447 evas_object_geometry_get
1448 (opt->obj, NULL, NULL, &child_w, &child_h);
1449
1450 y_remain = row_max_h[r] - child_h;
1451
1452 off_x = padding_l;
1453 if (priv->align.h >= 0.0)
1454 off_x += remain_x * priv->align.h;
1455 off_y = y_remain * align_y;
1456
1457 evas_object_move(opt->obj, x + off_x, y + off_y);
1458
1459 x += child_w + padding_l + padding_r + row_justify;
1460
1461 sub_pixel += just_inc;
1462 if (sub_pixel >= 1 << 16)
1463 {
1464 x++;
1465 sub_pixel -= 1 << 16;
1466 }
1467 }
1468
1469 evas_object_geometry_get(o, &x, NULL, NULL, NULL);
1470 if (min_w < row_width[r])
1471 min_w = row_width[r];
1472 min_h += row_max_h[r];
1473 y += row_max_h[r] + inc_y;
1474 }
1475
1476 evas_object_size_hint_min_set(o, min_w, min_h);
1477}
1478
1479static void
1480_evas_object_box_layout_flow_vertical_col_info_collect(Evas_Object_Box_Data *priv, int box_h, int *col_count, int *col_max_w, int *col_break, int *col_height, int *off_x_ret, int *max_w_ret)
1481{
1482 int i, remain_h = box_h, start_i = 0;
1483 int off_x = 0, max_w = 0, n_cols = 0;
1484 Eina_List *l;
1485
1486 for (i = 0, l = priv->children; l; i++, l = l->next)
1487 {
1488 Evas_Object_Box_Option *opt = l->data;
1489 int padding_l, padding_r, padding_t, padding_b;
1490 int child_w, child_h, off_y = 0;
1491
1492 evas_object_size_hint_padding_get
1493 (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b);
1494
1495 _sizing_eval(opt->obj);
1496 evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
1497
1498 child_w += padding_l + padding_r;
1499 child_h += padding_t + padding_b + priv->pad.v;
1500
1501 remain_h -= child_h;
1502 if (remain_h + priv->pad.v >= 0)
1503 { /* continue "col" */
1504 if (child_w > max_w)
1505 max_w = child_w;
1506
1507 off_y += child_h;
1508 col_height[n_cols] += child_h;
1509 }
1510 else
1511 {
1512 /* break col */
1513 if (i == start_i)
1514 { /* obj goes to actual col */
1515 max_w = child_w;
1516 col_height[n_cols] = child_h;
1517 }
1518 else
1519 { /* obj goes to next col */
1520 col_max_w[n_cols] = max_w;
1521 col_break[n_cols] = i - 1;
1522 n_cols++;
1523
1524 off_x += max_w;
1525 off_y = child_h;
1526 max_w = child_w;
1527
1528 col_height[n_cols] = child_h;
1529 start_i = i;
1530
1531 remain_h = box_h - off_y;
1532 }
1533 }
1534 }
1535
1536 col_break[n_cols] = i - 1;
1537 col_max_w[n_cols] = max_w;
1538
1539 *col_count = n_cols;
1540 *off_x_ret = off_x;
1541 *max_w_ret = max_w;
1542}
1543
1544EAPI void
1545evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1546{
1547 int n_children;
1548 int c, col_count;
1549 int min_w = 0, min_h = 0;
1550 int max_w, inc_x;
1551 int remain_x, i;
1552 int x, y, w, h;
1553 Eina_List *l;
1554 int *col_max_w;
1555 int *col_break;
1556 int *col_height;
1557 int offset_x;
1558
1559 n_children = eina_list_count(priv->children);
1560 if (!n_children)
1561 return;
1562
1563 /* *per col* arrays */
1564 col_max_w = (int *)alloca(sizeof(int) * n_children);
1565 if (!col_max_w)
1566 return;
1567 col_break = (int *)alloca(sizeof(int) * n_children);
1568 if (!col_break)
1569 return;
1570 col_height = (int *)alloca(sizeof(int) * n_children);
1571 if (!col_height)
1572 return;
1573
1574 memset(col_height, 0, sizeof(col_height));
1575
1576 evas_object_geometry_get(o, &x, &y, &w, &h);
1577
1578 _evas_object_box_layout_flow_vertical_col_info_collect
1579 (priv, h, &col_count, col_max_w, col_break, col_height, &offset_x, &max_w);
1580
1581 inc_x = 0;
1582 remain_x = w - (offset_x + max_w);
1583
1584 if (remain_x > 0)
1585 {
1586 if (priv->align.h >= 0)
1587 inc_x = priv->align.h * remain_x;
1588 else if (col_count == 0)
1589 x += remain_x / 2;
1590 else /* x-justified */
1591 inc_x = remain_x / col_count;
1592 }
1593
1594 inc_x += priv->pad.h;
1595
1596 for (i = 0, c = 0, l = priv->children; c <= col_count; c++)
1597 {
1598 int col_justify = 0, just_inc = 0, sub_pixel = 0;
1599 int col_size, remain_y;
1600
1601 col_size = col_break[c] - i;
1602 remain_y = (h - col_height[c]);
1603
1604 if (priv->align.v < 0.0)
1605 {
1606 if (col_size == 0)
1607 y += remain_y / 2;
1608 else
1609 _fixed_point_divide_and_decompose_integer
1610 (remain_y, col_size, &col_justify, &just_inc);
1611 }
1612
1613 col_justify += priv->pad.v;
1614
1615 for (; i <= col_break[c]; i++, l = l->next)
1616 {
1617 Evas_Object_Box_Option *opt = l->data;
1618 int off_x, off_y, x_remain;
1619 int padding_t, padding_b;
1620 int child_w, child_h;
1621 double align_x;
1622
1623 evas_object_size_hint_align_get(opt->obj, &align_x, NULL);
1624 evas_object_size_hint_padding_get
1625 (opt->obj, NULL, NULL, &padding_t, &padding_b);
1626
1627 evas_object_geometry_get
1628 (opt->obj, NULL, NULL, &child_w, &child_h);
1629
1630 x_remain = col_max_w[c] - child_w;
1631
1632 off_x = x_remain * align_x;
1633 off_y = padding_t;
1634 if (priv->align.v >= 0.0)
1635 off_y += remain_y * priv->align.v;
1636
1637 evas_object_move(opt->obj, x + off_x, y + off_y);
1638
1639 y += child_h + padding_t + padding_b + col_justify;
1640
1641 sub_pixel += just_inc;
1642 if (sub_pixel >= 1 << 16)
1643 {
1644 y++;
1645 sub_pixel -= 1 << 16;
1646 }
1647 }
1648
1649 evas_object_geometry_get(o, NULL, &y, NULL, NULL);
1650 min_w += col_max_w[c];
1651 if (min_h < col_height[c])
1652 min_h = col_height[c];
1653 x += col_max_w[c] + inc_x;
1654 }
1655
1656 evas_object_size_hint_min_set(o, min_w, min_h);
1657}
1658
1659EAPI void
1660evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__)
1661{
1662 Eina_List *l;
1663 Evas_Coord ox, oy, ow, oh;
1664 Evas_Coord top_w = 0, top_h = 0;
1665 Evas_Object_Box_Option *opt;
1666 Evas_Object *old_child = NULL;
1667
1668 evas_object_geometry_get(o, &ox, &oy, &ow, &oh);
1669
1670 EINA_LIST_FOREACH(priv->children, l, opt)
1671 {
1672 Evas_Object *child = opt->obj;
1673 Evas_Coord max_w, max_h, min_w, min_h, pad_l, pad_r, pad_t, pad_b,
1674 child_w, child_h, new_w, new_h, off_x, off_y;
1675 double align_x, align_y;
1676
1677 evas_object_size_hint_align_get(child, &align_x, &align_y);
1678 evas_object_size_hint_padding_get
1679 (child, &pad_l, &pad_r, &pad_t, &pad_b);
1680 evas_object_size_hint_max_get(child, &max_w, &max_h);
1681 evas_object_size_hint_min_get(child, &min_w, &min_h);
1682
1683 _sizing_eval(opt->obj);
1684 evas_object_geometry_get(child, NULL, NULL, &child_w, &child_h);
1685 new_w = child_w;
1686 new_h = child_h;
1687 if (new_w > top_w) top_w = new_w;
1688 if (new_h > top_h) top_h = new_h;
1689
1690 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1691 (child_w, &new_w, min_w, max_w, ow, &off_x, align_x, pad_l, pad_r);
1692 _layout_set_offset_and_change_dimension_min_max_cell_bounded
1693 (child_h, &new_h, min_h, max_h, oh, &off_y, align_y, pad_t, pad_b);
1694
1695 if ((new_w != child_w) || (new_h != child_h))
1696 evas_object_resize(child, new_w, new_h);
1697 evas_object_move(child, ox + off_x, oy + off_y);
1698
1699 if (old_child)
1700 evas_object_stack_above(child, old_child);
1701 old_child = child;
1702 }
1703
1704 evas_object_size_hint_min_set(o, top_w, top_h);
1705}
1706
1707EAPI void
1708evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical)
1709{
1710 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
1711 if (priv->align.h == horizontal && priv->align.v == vertical)
1712 return;
1713 priv->align.h = horizontal;
1714 priv->align.v = vertical;
1715 evas_object_smart_changed(o);
1716}
1717
1718EAPI void
1719evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vertical)
1720{
1721 EVAS_OBJECT_BOX_DATA_GET(o, priv);
1722 if (priv)
1723 {
1724 if (horizontal) *horizontal = priv->align.h;
1725 if (vertical) *vertical = priv->align.v;
1726 }
1727 else
1728 {
1729 if (horizontal) *horizontal = 0.5;
1730 if (vertical) *vertical = 0.5;
1731 }
1732}
1733
1734EAPI void
1735evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical)
1736{
1737 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
1738 if (priv->pad.h == horizontal && priv->pad.v == vertical)
1739 return;
1740 priv->pad.h = horizontal;
1741 priv->pad.v = vertical;
1742 evas_object_smart_changed(o);
1743}
1744
1745EAPI void
1746evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical)
1747{
1748 EVAS_OBJECT_BOX_DATA_GET(o, priv);
1749 if (priv)
1750 {
1751 if (horizontal) *horizontal = priv->pad.h;
1752 if (vertical) *vertical = priv->pad.v;
1753 }
1754 else
1755 {
1756 if (horizontal) *horizontal = 0;
1757 if (vertical) *vertical = 0;
1758 }
1759}
1760
1761EAPI Evas_Object_Box_Option *
1762evas_object_box_append(Evas_Object *o, Evas_Object *child)
1763{
1764 Evas_Object_Box_Option *opt;
1765 const Evas_Object_Box_Api *api;
1766
1767 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1768 if (!child)
1769 return NULL;
1770
1771 api = priv->api;
1772 if ((!api) || (!api->append))
1773 return NULL;
1774
1775 opt = api->append(o, priv, child);
1776
1777 if (opt)
1778 {
1779 evas_object_smart_member_add(child, o);
1780 evas_object_smart_changed(o);
1781 return _evas_object_box_option_callbacks_register(o, priv, opt);
1782 }
1783
1784 return NULL;
1785}
1786
1787EAPI Evas_Object_Box_Option *
1788evas_object_box_prepend(Evas_Object *o, Evas_Object *child)
1789{
1790 Evas_Object_Box_Option *opt;
1791 const Evas_Object_Box_Api *api;
1792
1793 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1794 if (!child)
1795 return NULL;
1796
1797 api = priv->api;
1798 if ((!api) || (!api->prepend))
1799 return NULL;
1800
1801 opt = api->prepend(o, priv, child);
1802
1803 if (opt)
1804 {
1805 evas_object_smart_member_add(child, o);
1806 evas_object_smart_changed(o);
1807 return _evas_object_box_option_callbacks_register(o, priv, opt);
1808 }
1809
1810 return NULL;
1811}
1812
1813EAPI Evas_Object_Box_Option *
1814evas_object_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Object *reference)
1815{
1816 Evas_Object_Box_Option *opt;
1817 const Evas_Object_Box_Api *api;
1818
1819 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1820 if (!child)
1821 return NULL;
1822
1823 api = priv->api;
1824 if ((!api) || (!api->insert_before))
1825 return NULL;
1826
1827 opt = api->insert_before(o, priv, child, reference);
1828
1829 if (opt)
1830 {
1831 evas_object_smart_member_add(child, o);
1832 evas_object_smart_changed(o);
1833 return _evas_object_box_option_callbacks_register(o, priv, opt);
1834 }
1835
1836 return NULL;
1837}
1838
1839EAPI Evas_Object_Box_Option *
1840evas_object_box_insert_after(Evas_Object *o, Evas_Object *child, const Evas_Object *reference)
1841{
1842 Evas_Object_Box_Option *opt;
1843 const Evas_Object_Box_Api *api;
1844
1845 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1846 if (!child)
1847 return NULL;
1848
1849 api = priv->api;
1850 if ((!api) || (!api->insert_after))
1851 return NULL;
1852
1853 opt = api->insert_after(o, priv, child, reference);
1854
1855 if (opt)
1856 {
1857 evas_object_smart_member_add(child, o);
1858 evas_object_smart_changed(o);
1859 return _evas_object_box_option_callbacks_register(o, priv, opt);
1860 }
1861
1862 return NULL;
1863}
1864
1865EAPI Evas_Object_Box_Option *
1866evas_object_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos)
1867{
1868 Evas_Object_Box_Option *opt;
1869 const Evas_Object_Box_Api *api;
1870
1871 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1872 if (!child)
1873 return NULL;
1874
1875 api = priv->api;
1876 if ((!api) || (!api->insert_at))
1877 return NULL;
1878
1879 opt = api->insert_at(o, priv, child, pos);
1880
1881 if (opt)
1882 {
1883 evas_object_smart_member_add(child, o);
1884 evas_object_smart_changed(o);
1885 return _evas_object_box_option_callbacks_register(o, priv, opt);
1886 }
1887
1888 return NULL;
1889}
1890
1891EAPI Eina_Bool
1892evas_object_box_remove(Evas_Object *o, Evas_Object *child)
1893{
1894 const Evas_Object_Box_Api *api;
1895 Evas_Object *obj;
1896
1897 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1898 if (!child) return EINA_FALSE;
1899
1900 api = priv->api;
1901 if ((!api) || (!api->remove))
1902 return 0;
1903
1904 obj = api->remove(o, priv, child);
1905
1906 if (obj)
1907 {
1908 _evas_object_box_child_callbacks_unregister(obj);
1909 evas_object_smart_member_del(obj);
1910 evas_object_smart_changed(o);
1911 return EINA_TRUE;
1912 }
1913
1914 return EINA_FALSE;
1915}
1916
1917EAPI Eina_Bool
1918evas_object_box_remove_at(Evas_Object *o, unsigned int pos)
1919{
1920 const Evas_Object_Box_Api *api;
1921 Evas_Object *obj;
1922
1923 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1924 api = priv->api;
1925 if ((!api) || (!api->remove_at)) return EINA_FALSE;
1926
1927 obj = api->remove_at(o, priv, pos);
1928
1929 if (obj)
1930 {
1931 _evas_object_box_child_callbacks_unregister(obj);
1932 evas_object_smart_member_del(obj);
1933 evas_object_smart_changed(o);
1934 return EINA_TRUE;
1935 }
1936
1937 return EINA_FALSE;
1938}
1939
1940EAPI Eina_Bool
1941evas_object_box_remove_all(Evas_Object *o, Eina_Bool clear)
1942{
1943 const Evas_Object_Box_Api *api;
1944
1945 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1946
1947 api = priv->api;
1948 if ((!api) || (!api->remove)) return EINA_FALSE;
1949
1950 evas_object_smart_changed(o);
1951
1952 while (priv->children)
1953 {
1954 Evas_Object_Box_Option *opt = priv->children->data;
1955 Evas_Object *obj;
1956
1957 obj = api->remove(o, priv, opt->obj);
1958 if (obj)
1959 {
1960 _evas_object_box_child_callbacks_unregister(obj);
1961 evas_object_smart_member_del(obj);
1962 if (clear)
1963 evas_object_del(obj);
1964 }
1965 else return EINA_FALSE;
1966 }
1967
1968 return EINA_TRUE;
1969}
1970
1971EAPI Eina_Iterator *
1972evas_object_box_iterator_new(const Evas_Object *o)
1973{
1974 Evas_Object_Box_Iterator *it;
1975
1976 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1977
1978 if (!priv->children) return NULL;
1979
1980 it = calloc(1, sizeof(Evas_Object_Box_Iterator));
1981 if (!it) return NULL;
1982
1983 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1984
1985 it->real_iterator = eina_list_iterator_new(priv->children);
1986 it->box = o;
1987
1988 it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_box_iterator_next);
1989 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_box_iterator_get_container);
1990 it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_box_iterator_free);
1991
1992 return &it->iterator;
1993}
1994
1995EAPI Eina_Accessor *
1996evas_object_box_accessor_new(const Evas_Object *o)
1997{
1998 Evas_Object_Box_Accessor *it;
1999
2000 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
2001
2002 if (!priv->children) return NULL;
2003
2004 it = calloc(1, sizeof(Evas_Object_Box_Accessor));
2005 if (!it) return NULL;
2006
2007 EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
2008
2009 it->real_accessor = eina_list_accessor_new(priv->children);
2010 it->box = o;
2011
2012 it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_box_accessor_get_at);
2013 it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_box_accessor_get_container);
2014 it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_box_accessor_free);
2015
2016 return &it->accessor;
2017}
2018
2019EAPI Eina_List *
2020evas_object_box_children_get(const Evas_Object *o)
2021{
2022 Eina_List *new_list = NULL, *l;
2023 Evas_Object_Box_Option *opt;
2024
2025 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
2026
2027 EINA_LIST_FOREACH(priv->children, l, opt)
2028 new_list = eina_list_append(new_list, opt->obj);
2029
2030 return new_list;
2031}
2032
2033EAPI const char *
2034evas_object_box_option_property_name_get(Evas_Object *o, int property)
2035{
2036 const Evas_Object_Box_Api *api;
2037
2038 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
2039
2040 if (property < 0)
2041 return NULL;
2042
2043 api = priv->api;
2044 if ((!api) || (!api->property_name_get))
2045 return NULL;
2046
2047 return api->property_name_get(o, property);
2048}
2049
2050EAPI int
2051evas_object_box_option_property_id_get(Evas_Object *o, const char *name)
2052{
2053 const Evas_Object_Box_Api *api;
2054
2055 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, -1);
2056
2057 if (!name)
2058 return -1;
2059
2060 api = priv->api;
2061 if ((!api) || (!api->property_id_get))
2062 return -1;
2063
2064 return api->property_id_get(o, name);
2065}
2066
2067EAPI Eina_Bool
2068evas_object_box_option_property_set(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...)
2069{
2070 Eina_Bool ret;
2071 va_list args;
2072
2073 va_start(args, property);
2074 ret = evas_object_box_option_property_vset(o, opt, property, args);
2075 va_end(args);
2076
2077 return ret;
2078}
2079
2080
2081EAPI Eina_Bool
2082evas_object_box_option_property_vset(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args)
2083{
2084 const Evas_Object_Box_Api *api;
2085
2086 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
2087
2088 if (!opt) return EINA_FALSE;
2089
2090 api = priv->api;
2091 if ((!api) || (!api->property_set))
2092 return EINA_FALSE;
2093
2094 if (!api->property_set(o, opt, property, args))
2095 return EINA_FALSE;
2096
2097 evas_object_smart_changed(o);
2098 return EINA_TRUE;
2099}
2100
2101EAPI Eina_Bool
2102evas_object_box_option_property_get(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...)
2103{
2104 Eina_Bool ret;
2105 va_list args;
2106
2107 va_start(args, property);
2108 ret = evas_object_box_option_property_vget(o, opt, property, args);
2109 va_end(args);
2110
2111 return ret;
2112}
2113
2114EAPI Eina_Bool
2115evas_object_box_option_property_vget(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args)
2116{
2117 const Evas_Object_Box_Api *api;
2118
2119 EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
2120
2121 if (!opt) return EINA_FALSE;
2122
2123 api = priv->api;
2124 if ((!api) || (!api->property_get))
2125 return EINA_FALSE;
2126
2127 return api->property_get(o, opt, property, args);
2128}
diff --git a/libraries/evas/src/lib/canvas/evas_object_grid.c b/libraries/evas/src/lib/canvas/evas_object_grid.c
new file mode 100644
index 0000000..ac96f04
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_grid.c
@@ -0,0 +1,465 @@
1#include <errno.h>
2#include "evas_common.h"
3
4typedef struct _Evas_Object_Grid_Data Evas_Object_Grid_Data;
5typedef struct _Evas_Object_Grid_Option Evas_Object_Grid_Option;
6typedef struct _Evas_Object_Grid_Iterator Evas_Object_Grid_Iterator;
7typedef struct _Evas_Object_Grid_Accessor Evas_Object_Grid_Accessor;
8
9struct _Evas_Object_Grid_Option
10{
11 Evas_Object *obj;
12 Eina_List *l;
13 int x, y, w, h;
14};
15
16struct _Evas_Object_Grid_Data
17{
18 Evas_Object_Smart_Clipped_Data base;
19 Eina_List *children;
20 struct {
21 int w, h;
22 } size;
23 Eina_Bool is_mirrored : 1;
24};
25
26struct _Evas_Object_Grid_Iterator
27{
28 Eina_Iterator iterator;
29
30 Eina_Iterator *real_iterator;
31 const Evas_Object *grid;
32};
33
34struct _Evas_Object_Grid_Accessor
35{
36 Eina_Accessor accessor;
37
38 Eina_Accessor *real_accessor;
39 const Evas_Object *grid;
40};
41
42#define EVAS_OBJECT_GRID_DATA_GET(o, ptr) \
43 Evas_Object_Grid_Data *ptr = evas_object_smart_data_get(o)
44
45#define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, ptr) \
46 EVAS_OBJECT_GRID_DATA_GET(o, ptr); \
47 if (!ptr) \
48 { \
49 CRIT("no widget data for object %p (%s)", \
50 o, evas_object_type_get(o)); \
51 abort(); \
52 return; \
53 }
54
55#define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
56 EVAS_OBJECT_GRID_DATA_GET(o, ptr); \
57 if (!ptr) \
58 { \
59 CRIT("No widget data for object %p (%s)", \
60 o, evas_object_type_get(o)); \
61 abort(); \
62 return val; \
63 }
64
65static const char EVAS_OBJECT_GRID_OPTION_KEY[] = "|EvGd";
66
67static Eina_Bool
68_evas_object_grid_iterator_next(Evas_Object_Grid_Iterator *it, void **data)
69{
70 Evas_Object_Grid_Option *opt;
71
72 if (!eina_iterator_next(it->real_iterator, (void **)&opt))
73 return EINA_FALSE;
74 if (data) *data = opt->obj;
75 return EINA_TRUE;
76}
77
78static Evas_Object *
79_evas_object_grid_iterator_get_container(Evas_Object_Grid_Iterator *it)
80{
81 return (Evas_Object *)it->grid;
82}
83
84static void
85_evas_object_grid_iterator_free(Evas_Object_Grid_Iterator *it)
86{
87 eina_iterator_free(it->real_iterator);
88 free(it);
89}
90
91static Eina_Bool
92_evas_object_grid_accessor_get_at(Evas_Object_Grid_Accessor *it, unsigned int idx, void **data)
93{
94 Evas_Object_Grid_Option *opt = NULL;
95
96 if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt))
97 return EINA_FALSE;
98 if (data) *data = opt->obj;
99 return EINA_TRUE;
100}
101
102static Evas_Object *
103_evas_object_grid_accessor_get_container(Evas_Object_Grid_Accessor *it)
104{
105 return (Evas_Object *)it->grid;
106}
107
108static void
109_evas_object_grid_accessor_free(Evas_Object_Grid_Accessor *it)
110{
111 eina_accessor_free(it->real_accessor);
112 free(it);
113}
114
115static Evas_Object_Grid_Option *
116_evas_object_grid_option_get(Evas_Object *o)
117{
118 return evas_object_data_get(o, EVAS_OBJECT_GRID_OPTION_KEY);
119}
120
121static void
122_evas_object_grid_option_set(Evas_Object *o, const Evas_Object_Grid_Option *opt)
123{
124 evas_object_data_set(o, EVAS_OBJECT_GRID_OPTION_KEY, opt);
125}
126
127static Evas_Object_Grid_Option *
128_evas_object_grid_option_del(Evas_Object *o)
129{
130 return evas_object_data_del(o, EVAS_OBJECT_GRID_OPTION_KEY);
131}
132
133static void
134_on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *child, void *einfo __UNUSED__)
135{
136 Evas_Object *grid = data;
137 evas_object_grid_unpack(grid, child);
138}
139
140static void
141_evas_object_grid_child_connect(Evas_Object *o, Evas_Object *child)
142{
143 evas_object_event_callback_add
144 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
145}
146
147static void
148_evas_object_grid_child_disconnect(Evas_Object *o, Evas_Object *child)
149{
150 evas_object_event_callback_del_full
151 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
152}
153
154EVAS_SMART_SUBCLASS_NEW("Evas_Object_Grid", _evas_object_grid,
155 Evas_Smart_Class, Evas_Smart_Class,
156 evas_object_smart_clipped_class_get, NULL)
157
158static void
159_evas_object_grid_smart_add(Evas_Object *o)
160{
161 EVAS_SMART_DATA_ALLOC(o, Evas_Object_Grid_Data)
162
163 priv->size.w = 100;
164 priv->size.h = 100;
165
166 _evas_object_grid_parent_sc->add(o);
167}
168
169static void
170_evas_object_grid_smart_del(Evas_Object *o)
171{
172 EVAS_OBJECT_GRID_DATA_GET(o, priv);
173 Eina_List *l;
174
175 l = priv->children;
176 while (l)
177 {
178 Evas_Object_Grid_Option *opt = l->data;
179 _evas_object_grid_child_disconnect(o, opt->obj);
180 _evas_object_grid_option_del(opt->obj);
181 free(opt);
182 l = eina_list_remove_list(l, l);
183 }
184 _evas_object_grid_parent_sc->del(o);
185}
186
187static void
188_evas_object_grid_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
189{
190 Evas_Coord ow, oh;
191 evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
192 if ((ow == w) && (oh == h)) return;
193 evas_object_smart_changed(o);
194}
195
196static void
197_evas_object_grid_smart_calculate(Evas_Object *o)
198{
199 Eina_List *l;
200 Evas_Object_Grid_Option *opt;
201 Evas_Coord x, y, w, h, vw, vh, t;
202 Eina_Bool mirror;
203
204 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv);
205 if (!priv) return;
206 if (!priv->children) return;
207 evas_object_geometry_get(o, &x, &y, &w, &h);
208 mirror = priv->is_mirrored;
209 vw = priv->size.w;
210 vh = priv->size.h;
211 EINA_LIST_FOREACH(priv->children, l, opt)
212 {
213 Evas_Coord x1, y1, x2, y2;
214
215 x1 = x + ((w * opt->x) / vw);
216 y1 = y + ((h * opt->y) / vh);
217 x2 = x + ((w * (opt->x + opt->w)) / vw);
218 y2 = y + ((h * (opt->y + opt->h)) / vh);
219 if (mirror)
220 {
221 t = x1; x1 = x2; x2 = t;
222 t = y1; y1 = y2; y2 = t;
223 }
224 evas_object_move(opt->obj, x1, y1);
225 evas_object_resize(opt->obj, x2 - x1, y2 - y1);
226 }
227}
228
229static void
230_evas_object_grid_smart_set_user(Evas_Smart_Class *sc)
231{
232 sc->add = _evas_object_grid_smart_add;
233 sc->del = _evas_object_grid_smart_del;
234 sc->resize = _evas_object_grid_smart_resize;
235 sc->calculate = _evas_object_grid_smart_calculate;
236}
237
238EAPI Evas_Object *
239evas_object_grid_add(Evas *evas)
240{
241 return evas_object_smart_add(evas, _evas_object_grid_smart_class_new());
242}
243
244EAPI Evas_Object *
245evas_object_grid_add_to(Evas_Object *parent)
246{
247 Evas *evas;
248 Evas_Object *o;
249
250 evas = evas_object_evas_get(parent);
251 o = evas_object_grid_add(evas);
252 evas_object_smart_member_add(o, parent);
253 return o;
254}
255
256EAPI void
257evas_object_grid_size_set(Evas_Object *o, int w, int h)
258{
259 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv);
260 if ((priv->size.w == w) && (priv->size.h == h)) return;
261 priv->size.w = w;
262 priv->size.h = h;
263 evas_object_smart_changed(o);
264}
265
266EAPI void
267evas_object_grid_size_get(const Evas_Object *o, int *w, int *h)
268{
269 if (w) *w = 0;
270 if (h) *h = 0;
271 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv);
272 if (w) *w = priv->size.w;
273 if (h) *h = priv->size.h;
274}
275
276EAPI Eina_Bool
277evas_object_grid_pack(Evas_Object *o, Evas_Object *child, int x, int y, int w, int h)
278{
279 Evas_Object_Grid_Option *opt;
280 Eina_Bool newobj = EINA_FALSE;
281
282 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0);
283
284 opt = _evas_object_grid_option_get(child);
285 if (!opt)
286 {
287 opt = malloc(sizeof(*opt));
288 if (!opt)
289 {
290 ERR("could not allocate grid option data.");
291 return EINA_FALSE;
292 }
293 newobj = EINA_TRUE;
294 }
295
296 opt->x = x;
297 opt->y = y;
298 opt->w = w;
299 opt->h = h;
300
301 if (newobj)
302 {
303 opt->obj = child;
304 priv->children = eina_list_append(priv->children, opt);
305 opt->l = eina_list_last(priv->children);
306 _evas_object_grid_option_set(child, opt);
307 evas_object_smart_member_add(child, o);
308 _evas_object_grid_child_connect(o, child);
309 }
310 // FIXME: we could keep a changed list
311 evas_object_smart_changed(o);
312 return EINA_TRUE;
313}
314
315static void
316_evas_object_grid_remove_opt(Evas_Object_Grid_Data *priv, Evas_Object_Grid_Option *opt)
317{
318 priv->children = eina_list_remove_list(priv->children, opt->l);
319 opt->l = NULL;
320}
321
322EAPI Eina_Bool
323evas_object_grid_unpack(Evas_Object *o, Evas_Object *child)
324{
325 Evas_Object_Grid_Option *opt;
326
327 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0);
328
329 if (o != evas_object_smart_parent_get(child))
330 {
331 ERR("cannot unpack child from incorrect grid!");
332 return EINA_FALSE;
333 }
334
335 opt = _evas_object_grid_option_del(child);
336 if (!opt)
337 {
338 ERR("cannot unpack child with no packing option!");
339 return EINA_FALSE;
340 }
341
342 _evas_object_grid_child_disconnect(o, child);
343 _evas_object_grid_remove_opt(priv, opt);
344 evas_object_smart_member_del(child);
345 free(opt);
346 return EINA_TRUE;
347}
348
349EAPI void
350evas_object_grid_clear(Evas_Object *o, Eina_Bool clear)
351{
352 Evas_Object_Grid_Option *opt;
353
354 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv);
355
356 EINA_LIST_FREE(priv->children, opt)
357 {
358 _evas_object_grid_child_disconnect(o, opt->obj);
359 _evas_object_grid_option_del(opt->obj);
360 evas_object_smart_member_del(opt->obj);
361 if (clear)
362 evas_object_del(opt->obj);
363 free(opt);
364 }
365}
366
367EAPI Eina_Bool
368evas_object_grid_pack_get(Evas_Object *o, Evas_Object *child, int *x, int *y, int *w, int *h)
369{
370 Evas_Object_Grid_Option *opt;
371
372 if (x) *x = 0;
373 if (y) *y = 0;
374 if (w) *w = 0;
375 if (h) *h = 0;
376 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0);
377 opt = _evas_object_grid_option_get(child);
378 if (!opt) return 0;
379 if (x) *x = opt->x;
380 if (y) *y = opt->y;
381 if (w) *w = opt->w;
382 if (h) *h = opt->h;
383 return 1;
384}
385
386EAPI Eina_Iterator *
387evas_object_grid_iterator_new(const Evas_Object *o)
388{
389 Evas_Object_Grid_Iterator *it;
390
391 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
392
393 if (!priv->children) return NULL;
394
395 it = calloc(1, sizeof(Evas_Object_Grid_Iterator));
396 if (!it) return NULL;
397
398 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
399
400 it->real_iterator = eina_list_iterator_new(priv->children);
401 it->grid = o;
402
403 it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_grid_iterator_next);
404 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_grid_iterator_get_container);
405 it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_grid_iterator_free);
406
407 return &it->iterator;
408}
409
410EAPI Eina_Accessor *
411evas_object_grid_accessor_new(const Evas_Object *o)
412{
413 Evas_Object_Grid_Accessor *it;
414
415 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
416
417 if (!priv->children) return NULL;
418
419 it = calloc(1, sizeof(Evas_Object_Grid_Accessor));
420 if (!it) return NULL;
421
422 EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
423
424 it->real_accessor = eina_list_accessor_new(priv->children);
425 it->grid = o;
426
427 it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_grid_accessor_get_at);
428 it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_grid_accessor_get_container);
429 it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_grid_accessor_free);
430
431 return &it->accessor;
432}
433
434EAPI Eina_List *
435evas_object_grid_children_get(const Evas_Object *o)
436{
437 Eina_List *new_list = NULL, *l;
438 Evas_Object_Grid_Option *opt;
439
440 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
441
442 EINA_LIST_FOREACH(priv->children, l, opt)
443 new_list = eina_list_append(new_list, opt->obj);
444
445 return new_list;
446}
447
448EAPI Eina_Bool
449evas_object_grid_mirrored_get(const Evas_Object *obj)
450{
451 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(obj, priv, EINA_FALSE);
452 return priv->is_mirrored;
453}
454
455EAPI void
456evas_object_grid_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
457{
458 EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(obj, priv);
459 mirrored = !!mirrored;
460 if (priv->is_mirrored != mirrored)
461 {
462 priv->is_mirrored = mirrored;
463 _evas_object_grid_smart_calculate(obj);
464 }
465}
diff --git a/libraries/evas/src/lib/canvas/evas_object_image.c b/libraries/evas/src/lib/canvas/evas_object_image.c
new file mode 100644
index 0000000..7f757a6
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_image.c
@@ -0,0 +1,3895 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <sys/mman.h>
5#include <math.h>
6
7#include "evas_common.h"
8#include "evas_private.h"
9#include "../engines/common/evas_convert_color.h"
10#include "../engines/common/evas_convert_colorspace.h"
11#include "../engines/common/evas_convert_yuv.h"
12
13#define VERBOSE_PROXY_ERROR 1
14
15/* private magic number for image objects */
16static const char o_type[] = "image";
17
18/* private struct for rectangle object internal data */
19typedef struct _Evas_Object_Image Evas_Object_Image;
20
21struct _Evas_Object_Image
22{
23 DATA32 magic;
24
25 struct {
26 int spread;
27 Evas_Coord_Rectangle fill;
28 struct {
29 short w, h, stride;
30 } image;
31 struct {
32 short l, r, t, b;
33 unsigned char fill;
34 double scale;
35 } border;
36
37 Evas_Object *source;
38 Evas_Map *defmap;
39 const char *file;
40 const char *key;
41 int frame;
42 Evas_Colorspace cspace;
43
44 unsigned char smooth_scale : 1;
45 unsigned char has_alpha :1;
46 unsigned char opaque :1;
47 unsigned char opaque_valid :1;
48 } cur, prev;
49
50 int pixels_checked_out;
51 int load_error;
52 Eina_List *pixel_updates;
53
54 struct {
55 unsigned char scale_down_by;
56 double dpi;
57 short w, h;
58 struct {
59 short x, y, w, h;
60 } region;
61 Eina_Bool orientation : 1;
62 } load_opts;
63
64 struct {
65 Evas_Object_Image_Pixels_Get_Cb get_pixels;
66 void *get_pixels_data;
67 } func;
68
69 Evas_Video_Surface video;
70
71 const char *tmpf;
72 int tmpf_fd;
73
74 Evas_Image_Scale_Hint scale_hint;
75 Evas_Image_Content_Hint content_hint;
76
77 void *engine_data;
78
79 unsigned char changed : 1;
80 unsigned char dirty_pixels : 1;
81 unsigned char filled : 1;
82 unsigned char proxyrendering : 1;
83 unsigned char preloading : 1;
84 unsigned char video_rendering : 1;
85 unsigned char video_surface : 1;
86 unsigned char video_visible : 1;
87 unsigned char created : 1;
88};
89
90/* private methods for image objects */
91static void evas_object_image_unload(Evas_Object *obj, Eina_Bool dirty);
92static void evas_object_image_load(Evas_Object *obj);
93static Evas_Coord evas_object_image_figure_x_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
94static Evas_Coord evas_object_image_figure_y_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
95
96static void evas_object_image_init(Evas_Object *obj);
97static void *evas_object_image_new(void);
98static void evas_object_image_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
99static void evas_object_image_free(Evas_Object *obj);
100static void evas_object_image_render_pre(Evas_Object *obj);
101static void evas_object_image_render_post(Evas_Object *obj);
102
103static unsigned int evas_object_image_id_get(Evas_Object *obj);
104static unsigned int evas_object_image_visual_id_get(Evas_Object *obj);
105static void *evas_object_image_engine_data_get(Evas_Object *obj);
106
107static int evas_object_image_is_opaque(Evas_Object *obj);
108static int evas_object_image_was_opaque(Evas_Object *obj);
109static int evas_object_image_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
110static int evas_object_image_has_opaque_rect(Evas_Object *obj);
111static int evas_object_image_get_opaque_rect(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
112static int evas_object_image_can_map(Evas_Object *obj);
113
114static void *evas_object_image_data_convert_internal(Evas_Object_Image *o, void *data, Evas_Colorspace to_cspace);
115static void evas_object_image_filled_resize_listener(void *data, Evas *e, Evas_Object *obj, void *einfo);
116
117static void _proxy_unset(Evas_Object *proxy);
118static void _proxy_set(Evas_Object *proxy, Evas_Object *src);
119static void _proxy_error(Evas_Object *proxy, void *context, void *output, void *surface, int x, int y);
120
121static void _cleanup_tmpf(Evas_Object *obj);
122
123static const Evas_Object_Func object_func =
124{
125 /* methods (compulsory) */
126 evas_object_image_free,
127 evas_object_image_render,
128 evas_object_image_render_pre,
129 evas_object_image_render_post,
130 evas_object_image_id_get,
131 evas_object_image_visual_id_get,
132 evas_object_image_engine_data_get,
133 /* these are optional. NULL = nothing */
134 NULL,
135 NULL,
136 NULL,
137 NULL,
138 evas_object_image_is_opaque,
139 evas_object_image_was_opaque,
140 evas_object_image_is_inside,
141 NULL,
142 NULL,
143 NULL,
144 evas_object_image_has_opaque_rect,
145 evas_object_image_get_opaque_rect,
146 evas_object_image_can_map
147};
148
149EVAS_MEMPOOL(_mp_obj);
150
151static void
152_evas_object_image_cleanup(Evas_Object *obj, Evas_Object_Image *o)
153{
154 if ((o->preloading) && (o->engine_data))
155 {
156 o->preloading = 0;
157 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
158 o->engine_data,
159 obj);
160 }
161 if (o->tmpf) _cleanup_tmpf(obj);
162 if (o->cur.source) _proxy_unset(obj);
163}
164
165EAPI Evas_Object *
166evas_object_image_add(Evas *e)
167{
168 Evas_Object *obj;
169 Evas_Object_Image *o;
170
171 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
172 return NULL;
173 MAGIC_CHECK_END();
174 obj = evas_object_new(e);
175 evas_object_image_init(obj);
176 evas_object_inject(obj, e);
177 o = (Evas_Object_Image *)(obj->object_data);
178 o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get(obj->layer->evas->engine.data.output,
179 o->engine_data);
180 return obj;
181}
182
183EAPI Evas_Object *
184evas_object_image_filled_add(Evas *e)
185{
186 Evas_Object *obj;
187 obj = evas_object_image_add(e);
188 evas_object_image_filled_set(obj, 1);
189 return obj;
190}
191
192static void
193_cleanup_tmpf(Evas_Object *obj)
194{
195 Evas_Object_Image *o;
196
197 o = (Evas_Object_Image *)(obj->object_data);
198 if (!o->tmpf) return;
199#ifdef __linux__
200#else
201 unlink(o->tmpf);
202#endif
203 if (o->tmpf_fd >= 0) close(o->tmpf_fd);
204 eina_stringshare_del(o->tmpf);
205 o->tmpf_fd = -1;
206 o->tmpf = NULL;
207}
208
209static void
210_create_tmpf(Evas_Object *obj, void *data, int size, char *format __UNUSED__)
211{
212 Evas_Object_Image *o;
213 char buf[4096];
214 void *dst;
215 int fd = -1;
216
217 o = (Evas_Object_Image *)(obj->object_data);
218#ifdef __linux__
219 snprintf(buf, sizeof(buf), "/dev/shm/.evas-tmpf-%i-%p-%i-XXXXXX",
220 (int)getpid(), data, (int)size);
221 fd = mkstemp(buf);
222#endif
223 if (fd < 0)
224 {
225 snprintf(buf, sizeof(buf), "/tmp/.evas-tmpf-%i-%p-%i-XXXXXX",
226 (int)getpid(), data, (int)size);
227 fd = mkstemp(buf);
228 }
229 if (fd < 0) return;
230 if (ftruncate(fd, size) < 0)
231 {
232 unlink(buf);
233 close(fd);
234 return;
235 }
236 unlink(buf);
237
238 eina_mmap_safety_enabled_set(EINA_TRUE);
239
240 dst = mmap(NULL, size,
241 PROT_READ | PROT_WRITE,
242 MAP_SHARED,
243 fd, 0);
244 if (dst == MAP_FAILED)
245 {
246 close(fd);
247 return;
248 }
249 o->tmpf_fd = fd;
250#ifdef __linux__
251 snprintf(buf, sizeof(buf), "/proc/%li/fd/%i", (long)getpid(), fd);
252#endif
253 o->tmpf = eina_stringshare_add(buf);
254 memcpy(dst, data, size);
255 munmap(dst, size);
256}
257
258EAPI void
259evas_object_image_memfile_set(Evas_Object *obj, void *data, int size, char *format, char *key)
260{
261 Evas_Object_Image *o;
262
263 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
264 return;
265 MAGIC_CHECK_END();
266 o = (Evas_Object_Image *)(obj->object_data);
267 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
268 return;
269 MAGIC_CHECK_END();
270 _cleanup_tmpf(obj);
271 evas_object_image_file_set(obj, NULL, NULL);
272 // invalidate the cache effectively
273 evas_object_image_alpha_set(obj, !o->cur.has_alpha);
274 evas_object_image_alpha_set(obj, !o->cur.has_alpha);
275
276 if ((size < 1) || (!data)) return;
277
278 _create_tmpf(obj, data, size, format);
279 evas_object_image_file_set(obj, o->tmpf, key);
280 if (!o->engine_data)
281 {
282 ERR("unable to load '%s' from memory", o->tmpf);
283 _cleanup_tmpf(obj);
284 return;
285 }
286}
287
288EAPI void
289evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key)
290{
291 Evas_Object_Image *o;
292 Evas_Image_Load_Opts lo;
293
294 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
295 return;
296 MAGIC_CHECK_END();
297 o = (Evas_Object_Image *)(obj->object_data);
298 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
299 return;
300 MAGIC_CHECK_END();
301 if ((o->tmpf) && (file != o->tmpf)) _cleanup_tmpf(obj);
302 if ((o->cur.file) && (file) && (!strcmp(o->cur.file, file)))
303 {
304 if ((!o->cur.key) && (!key))
305 return;
306 if ((o->cur.key) && (key) && (!strcmp(o->cur.key, key)))
307 return;
308 }
309/*
310 * WTF? why cancel a null image preload? this is just silly (tm)
311 if (!o->engine_data)
312 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
313 o->engine_data,
314 obj);
315 */
316 if (o->cur.source) _proxy_unset(obj);
317 if (o->cur.file) eina_stringshare_del(o->cur.file);
318 if (o->cur.key) eina_stringshare_del(o->cur.key);
319 if (file) o->cur.file = eina_stringshare_add(file);
320 else o->cur.file = NULL;
321 if (key) o->cur.key = eina_stringshare_add(key);
322 else o->cur.key = NULL;
323 o->prev.file = NULL;
324 o->prev.key = NULL;
325 if (o->engine_data)
326 {
327 if (o->preloading)
328 {
329 o->preloading = 0;
330 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
331 o->engine_data,
332 obj);
333 }
334 obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output,
335 o->engine_data);
336 }
337 o->load_error = EVAS_LOAD_ERROR_NONE;
338 lo.scale_down_by = o->load_opts.scale_down_by;
339 lo.dpi = o->load_opts.dpi;
340 lo.w = o->load_opts.w;
341 lo.h = o->load_opts.h;
342 lo.region.x = o->load_opts.region.x;
343 lo.region.y = o->load_opts.region.y;
344 lo.region.w = o->load_opts.region.w;
345 lo.region.h = o->load_opts.region.h;
346 lo.orientation = o->load_opts.orientation;
347 o->engine_data = obj->layer->evas->engine.func->image_load(obj->layer->evas->engine.data.output,
348 o->cur.file,
349 o->cur.key,
350 &o->load_error,
351 &lo);
352 if (o->engine_data)
353 {
354 int w, h;
355 int stride;
356
357 obj->layer->evas->engine.func->image_size_get(obj->layer->evas->engine.data.output,
358 o->engine_data, &w, &h);
359 if (obj->layer->evas->engine.func->image_stride_get)
360 obj->layer->evas->engine.func->image_stride_get(obj->layer->evas->engine.data.output,
361 o->engine_data, &stride);
362 else
363 stride = w * 4;
364 o->cur.has_alpha = obj->layer->evas->engine.func->image_alpha_get(obj->layer->evas->engine.data.output,
365 o->engine_data);
366 o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get(obj->layer->evas->engine.data.output,
367 o->engine_data);
368 o->cur.image.w = w;
369 o->cur.image.h = h;
370 o->cur.image.stride = stride;
371 }
372 else
373 {
374 if (o->load_error == EVAS_LOAD_ERROR_NONE)
375 o->load_error = EVAS_LOAD_ERROR_GENERIC;
376 o->cur.has_alpha = 1;
377 o->cur.cspace = EVAS_COLORSPACE_ARGB8888;
378 o->cur.image.w = 0;
379 o->cur.image.h = 0;
380 o->cur.image.stride = 0;
381 }
382 o->changed = 1;
383 evas_object_change(obj);
384}
385
386EAPI void
387evas_object_image_file_get(const Evas_Object *obj, const char **file, const char **key)
388{
389 Evas_Object_Image *o;
390
391 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
392 if (file) *file = NULL;
393 if (key) *key = NULL;
394 return;
395 MAGIC_CHECK_END();
396 o = (Evas_Object_Image *)(obj->object_data);
397 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
398 if (file) *file = NULL;
399 if (key) *key = NULL;
400 return;
401 MAGIC_CHECK_END();
402 if (file) *file = o->cur.file;
403 if (key) *key = o->cur.key;
404}
405
406EAPI Eina_Bool
407evas_object_image_source_set(Evas_Object *obj, Evas_Object *src)
408{
409 Evas_Object_Image *o;
410
411 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
412 return EINA_FALSE;
413 MAGIC_CHECK_END();
414 o = obj->object_data;
415 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
416 return EINA_FALSE;
417 MAGIC_CHECK_END();
418
419 if (src == obj) return EINA_FALSE;
420 if (o->cur.source == src) return EINA_TRUE;
421
422 _evas_object_image_cleanup(obj, o);
423 /* Kill the image if any */
424 if (o->cur.file || o->cur.key)
425 evas_object_image_file_set(obj, NULL, NULL);
426
427 if (src)
428 {
429 _proxy_set(obj, src);
430 }
431
432 return EINA_TRUE;
433}
434
435
436EAPI Evas_Object *
437evas_object_image_source_get(Evas_Object *obj)
438{
439 Evas_Object_Image *o;
440
441 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
442 return NULL;
443 MAGIC_CHECK_END();
444 o = obj->object_data;
445 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
446 return NULL;
447 MAGIC_CHECK_END();
448
449 return o->cur.source;
450}
451
452EAPI Eina_Bool
453evas_object_image_source_unset(Evas_Object *obj)
454{
455 return evas_object_image_source_set(obj, NULL);
456}
457
458EAPI void
459evas_object_image_border_set(Evas_Object *obj, int l, int r, int t, int b)
460{
461 Evas_Object_Image *o;
462
463 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
464 return;
465 MAGIC_CHECK_END();
466 o = (Evas_Object_Image *)(obj->object_data);
467 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
468 return;
469 MAGIC_CHECK_END();
470 if (l < 0) l = 0;
471 if (r < 0) r = 0;
472 if (t < 0) t = 0;
473 if (b < 0) b = 0;
474 if ((o->cur.border.l == l) &&
475 (o->cur.border.r == r) &&
476 (o->cur.border.t == t) &&
477 (o->cur.border.b == b)) return;
478 o->cur.border.l = l;
479 o->cur.border.r = r;
480 o->cur.border.t = t;
481 o->cur.border.b = b;
482 o->cur.opaque_valid = 0;
483 o->changed = 1;
484 evas_object_change(obj);
485}
486
487EAPI void
488evas_object_image_border_get(const Evas_Object *obj, int *l, int *r, int *t, int *b)
489{
490 Evas_Object_Image *o;
491
492 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
493 if (l) *l = 0;
494 if (r) *r = 0;
495 if (t) *t = 0;
496 if (b) *b = 0;
497 return;
498 MAGIC_CHECK_END();
499 o = (Evas_Object_Image *)(obj->object_data);
500 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
501 if (l) *l = 0;
502 if (r) *r = 0;
503 if (t) *t = 0;
504 if (b) *b = 0;
505 return;
506 MAGIC_CHECK_END();
507 if (l) *l = o->cur.border.l;
508 if (r) *r = o->cur.border.r;
509 if (t) *t = o->cur.border.t;
510 if (b) *b = o->cur.border.b;
511}
512
513EAPI void
514evas_object_image_border_center_fill_set(Evas_Object *obj, Evas_Border_Fill_Mode fill)
515{
516 Evas_Object_Image *o;
517
518 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
519 return;
520 MAGIC_CHECK_END();
521 o = (Evas_Object_Image *)(obj->object_data);
522 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
523 return;
524 MAGIC_CHECK_END();
525 if (fill == o->cur.border.fill) return;
526 o->cur.border.fill = fill;
527 o->changed = 1;
528 evas_object_change(obj);
529}
530
531EAPI Evas_Border_Fill_Mode
532evas_object_image_border_center_fill_get(const Evas_Object *obj)
533{
534 Evas_Object_Image *o;
535
536 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
537 return 0;
538 MAGIC_CHECK_END();
539 o = (Evas_Object_Image *)(obj->object_data);
540 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
541 return 0;
542 MAGIC_CHECK_END();
543 return o->cur.border.fill;
544}
545
546EAPI void
547evas_object_image_filled_set(Evas_Object *obj, Eina_Bool setting)
548{
549 Evas_Object_Image *o;
550
551 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
552 return;
553 MAGIC_CHECK_END();
554 o = (Evas_Object_Image *)(obj->object_data);
555 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
556 return;
557 MAGIC_CHECK_END();
558
559 setting = !!setting;
560 if (o->filled == setting) return;
561
562 o->filled = setting;
563 if (!o->filled)
564 evas_object_event_callback_del(obj, EVAS_CALLBACK_RESIZE, evas_object_image_filled_resize_listener);
565 else
566 {
567 Evas_Coord w, h;
568
569 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
570 evas_object_image_fill_set(obj, 0, 0, w, h);
571
572 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, evas_object_image_filled_resize_listener, NULL);
573 }
574}
575
576EAPI Eina_Bool
577evas_object_image_filled_get(const Evas_Object *obj)
578{
579 Evas_Object_Image *o;
580
581 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
582 return 0;
583 MAGIC_CHECK_END();
584 o = (Evas_Object_Image *)(obj->object_data);
585 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
586 return 0;
587 MAGIC_CHECK_END();
588
589 return o->filled;
590}
591
592EAPI void
593evas_object_image_border_scale_set(Evas_Object *obj, double scale)
594{
595 Evas_Object_Image *o;
596
597 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
598 return;
599 MAGIC_CHECK_END();
600 o = (Evas_Object_Image *)(obj->object_data);
601 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
602 return;
603 MAGIC_CHECK_END();
604 if (scale == o->cur.border.scale) return;
605 o->cur.border.scale = scale;
606 o->changed = 1;
607 evas_object_change(obj);
608}
609
610EAPI double
611evas_object_image_border_scale_get(const Evas_Object *obj)
612{
613 Evas_Object_Image *o;
614
615 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
616 return 1.0;
617 MAGIC_CHECK_END();
618 o = (Evas_Object_Image *)(obj->object_data);
619 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
620 return 1.0;
621 MAGIC_CHECK_END();
622 return o->cur.border.scale;
623}
624
625EAPI void
626evas_object_image_fill_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
627{
628 Evas_Object_Image *o;
629
630 if (w < 0) w = -w;
631 if (h < 0) h = -h;
632 if (w == 0) return;
633 if (h == 0) return;
634 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
635 return;
636 MAGIC_CHECK_END();
637 o = (Evas_Object_Image *)(obj->object_data);
638 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
639 return;
640 MAGIC_CHECK_END();
641 if ((o->cur.fill.x == x) &&
642 (o->cur.fill.y == y) &&
643 (o->cur.fill.w == w) &&
644 (o->cur.fill.h == h)) return;
645 o->cur.fill.x = x;
646 o->cur.fill.y = y;
647 o->cur.fill.w = w;
648 o->cur.fill.h = h;
649 o->cur.opaque_valid = 0;
650 o->changed = 1;
651 evas_object_change(obj);
652}
653
654EAPI void
655evas_object_image_fill_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
656{
657 Evas_Object_Image *o;
658
659 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
660 if (x) *x = 0;
661 if (y) *y = 0;
662 if (w) *w = 0;
663 if (h) *h = 0;
664 return;
665 MAGIC_CHECK_END();
666 o = (Evas_Object_Image *)(obj->object_data);
667 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
668 if (x) *x = 0;
669 if (y) *y = 0;
670 if (w) *w = 0;
671 if (h) *h = 0;
672 return;
673 MAGIC_CHECK_END();
674 if (x) *x = o->cur.fill.x;
675 if (y) *y = o->cur.fill.y;
676 if (w) *w = o->cur.fill.w;
677 if (h) *h = o->cur.fill.h;
678}
679
680
681EAPI void
682evas_object_image_fill_spread_set(Evas_Object *obj, Evas_Fill_Spread spread)
683{
684 Evas_Object_Image *o;
685
686 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
687 return;
688 MAGIC_CHECK_END();
689 o = (Evas_Object_Image *)(obj->object_data);
690 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
691 return;
692 MAGIC_CHECK_END();
693 if (spread == (Evas_Fill_Spread)o->cur.spread) return;
694 o->cur.spread = spread;
695 o->changed = 1;
696 evas_object_change(obj);
697}
698
699EAPI Evas_Fill_Spread
700evas_object_image_fill_spread_get(const Evas_Object *obj)
701{
702 Evas_Object_Image *o;
703
704 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
705 return EVAS_TEXTURE_REPEAT;
706 MAGIC_CHECK_END();
707 o = (Evas_Object_Image *)(obj->object_data);
708 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
709 return EVAS_TEXTURE_REPEAT;
710 MAGIC_CHECK_END();
711 return (Evas_Fill_Spread)o->cur.spread;
712}
713
714EAPI void
715evas_object_image_size_set(Evas_Object *obj, int w, int h)
716{
717 Evas_Object_Image *o;
718 int stride = 0;
719
720 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
721 return;
722 MAGIC_CHECK_END();
723 o = (Evas_Object_Image *)(obj->object_data);
724 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
725 return;
726 MAGIC_CHECK_END();
727 _evas_object_image_cleanup(obj, o);
728 if (w < 1) w = 1;
729 if (h < 1) h = 1;
730 if (w > 32768) return;
731 if (h > 32768) return;
732 if ((w == o->cur.image.w) &&
733 (h == o->cur.image.h)) return;
734 o->cur.image.w = w;
735 o->cur.image.h = h;
736 if (o->engine_data)
737 o->engine_data = obj->layer->evas->engine.func->image_size_set(obj->layer->evas->engine.data.output,
738 o->engine_data,
739 w, h);
740 else
741 o->engine_data = obj->layer->evas->engine.func->image_new_from_copied_data
742 (obj->layer->evas->engine.data.output, w, h, NULL, o->cur.has_alpha,
743 o->cur.cspace);
744
745 if (o->engine_data)
746 {
747 if (obj->layer->evas->engine.func->image_scale_hint_set)
748 obj->layer->evas->engine.func->image_scale_hint_set
749 (obj->layer->evas->engine.data.output,
750 o->engine_data, o->scale_hint);
751 if (obj->layer->evas->engine.func->image_content_hint_set)
752 obj->layer->evas->engine.func->image_content_hint_set
753 (obj->layer->evas->engine.data.output,
754 o->engine_data, o->content_hint);
755 if (obj->layer->evas->engine.func->image_stride_get)
756 obj->layer->evas->engine.func->image_stride_get
757 (obj->layer->evas->engine.data.output,
758 o->engine_data, &stride);
759 else
760 stride = w * 4;
761 }
762 else
763 stride = w * 4;
764 o->cur.image.stride = stride;
765
766/* FIXME - in engine call above
767 if (o->engine_data)
768 o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
769 o->engine_data,
770 o->cur.has_alpha);
771*/
772 EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
773 o->changed = 1;
774 evas_object_change(obj);
775}
776
777EAPI void
778evas_object_image_size_get(const Evas_Object *obj, int *w, int *h)
779{
780 Evas_Object_Image *o;
781
782 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
783 if (w) *w = 0;
784 if (h) *h = 0;
785 return;
786 MAGIC_CHECK_END();
787 o = (Evas_Object_Image *)(obj->object_data);
788 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
789 if (w) *w = 0;
790 if (h) *h = 0;
791 return;
792 MAGIC_CHECK_END();
793 if (w) *w = o->cur.image.w;
794 if (h) *h = o->cur.image.h;
795}
796
797EAPI int
798evas_object_image_stride_get(const Evas_Object *obj)
799{
800 Evas_Object_Image *o;
801
802 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
803 return 0;
804 MAGIC_CHECK_END();
805 o = (Evas_Object_Image *)(obj->object_data);
806 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
807 return 0;
808 MAGIC_CHECK_END();
809 return o->cur.image.stride;
810}
811
812EAPI Evas_Load_Error
813evas_object_image_load_error_get(const Evas_Object *obj)
814{
815 Evas_Object_Image *o;
816
817 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
818 return 0;
819 MAGIC_CHECK_END();
820 o = (Evas_Object_Image *)(obj->object_data);
821 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
822 return 0;
823 MAGIC_CHECK_END();
824 return o->load_error;
825}
826
827EAPI void *
828evas_object_image_data_convert(Evas_Object *obj, Evas_Colorspace to_cspace)
829{
830 Evas_Object_Image *o;
831 DATA32 *data;
832
833 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
834 return NULL;
835 MAGIC_CHECK_END();
836 o = (Evas_Object_Image *)(obj->object_data);
837 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
838 return NULL;
839 MAGIC_CHECK_END();
840 if ((o->preloading) && (o->engine_data))
841 {
842 o->preloading = 0;
843 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
844 o->engine_data,
845 obj);
846 }
847 if (!o->engine_data) return NULL;
848 if (o->video_surface)
849 o->video.update_pixels(o->video.data, obj, &o->video);
850 if (o->cur.cspace == to_cspace) return NULL;
851 data = NULL;
852 o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
853 o->engine_data,
854 0,
855 &data,
856 &o->load_error);
857 return evas_object_image_data_convert_internal(o, data, to_cspace);
858}
859
860EAPI void
861evas_object_image_data_set(Evas_Object *obj, void *data)
862{
863 Evas_Object_Image *o;
864 void *p_data;
865
866 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
867 return;
868 MAGIC_CHECK_END();
869 o = (Evas_Object_Image *)(obj->object_data);
870 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
871 return;
872 MAGIC_CHECK_END();
873 _evas_object_image_cleanup(obj, o);
874#ifdef EVAS_FRAME_QUEUING
875 if (o->engine_data)
876 evas_common_pipe_op_image_flush(o->engine_data);
877#endif
878 p_data = o->engine_data;
879 if (data)
880 {
881 if (o->engine_data)
882 o->engine_data = obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output,
883 o->engine_data,
884 data);
885 else
886 o->engine_data = obj->layer->evas->engine.func->image_new_from_data(obj->layer->evas->engine.data.output,
887 o->cur.image.w,
888 o->cur.image.h,
889 data,
890 o->cur.has_alpha,
891 o->cur.cspace);
892 if (o->engine_data)
893 {
894 int stride = 0;
895
896 if (obj->layer->evas->engine.func->image_scale_hint_set)
897 obj->layer->evas->engine.func->image_scale_hint_set
898 (obj->layer->evas->engine.data.output,
899 o->engine_data, o->scale_hint);
900 if (obj->layer->evas->engine.func->image_content_hint_set)
901 obj->layer->evas->engine.func->image_content_hint_set
902 (obj->layer->evas->engine.data.output,
903 o->engine_data, o->content_hint);
904 if (obj->layer->evas->engine.func->image_stride_get)
905 obj->layer->evas->engine.func->image_stride_get
906 (obj->layer->evas->engine.data.output,
907 o->engine_data, &stride);
908 else
909 stride = o->cur.image.w * 4;
910 o->cur.image.stride = stride;
911 }
912 }
913 else
914 {
915 if (o->engine_data)
916 obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output,
917 o->engine_data);
918 o->load_error = EVAS_LOAD_ERROR_NONE;
919 o->cur.image.w = 0;
920 o->cur.image.h = 0;
921 o->cur.image.stride = 0;
922 o->engine_data = NULL;
923 }
924/* FIXME - in engine call above
925 if (o->engine_data)
926 o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
927 o->engine_data,
928 o->cur.has_alpha);
929*/
930 if (o->pixels_checked_out > 0) o->pixels_checked_out--;
931 if (p_data != o->engine_data)
932 {
933 EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
934 o->pixels_checked_out = 0;
935 }
936 o->changed = 1;
937 evas_object_change(obj);
938}
939
940EAPI void *
941evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing)
942{
943 Evas_Object_Image *o;
944 DATA32 *data;
945
946 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
947 return NULL;
948 MAGIC_CHECK_END();
949 o = (Evas_Object_Image *)(obj->object_data);
950 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
951 return NULL;
952 MAGIC_CHECK_END();
953 if (!o->engine_data) return NULL;
954#ifdef EVAS_FRAME_QUEUING
955 evas_common_pipe_op_image_flush(o->engine_data);
956#endif
957
958 data = NULL;
959 if (obj->layer->evas->engine.func->image_scale_hint_set)
960 obj->layer->evas->engine.func->image_scale_hint_set
961 (obj->layer->evas->engine.data.output,
962 o->engine_data, o->scale_hint);
963 if (obj->layer->evas->engine.func->image_content_hint_set)
964 obj->layer->evas->engine.func->image_content_hint_set
965 (obj->layer->evas->engine.data.output,
966 o->engine_data, o->content_hint);
967 o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
968 o->engine_data,
969 for_writing,
970 &data,
971 &o->load_error);
972
973 /* if we fail to get engine_data, we have to return NULL */
974 if (!o->engine_data) return NULL;
975
976 if (o->engine_data)
977 {
978 int stride = 0;
979
980 if (obj->layer->evas->engine.func->image_stride_get)
981 obj->layer->evas->engine.func->image_stride_get
982 (obj->layer->evas->engine.data.output,
983 o->engine_data, &stride);
984 else
985 stride = o->cur.image.w * 4;
986 o->cur.image.stride = stride;
987 }
988 o->pixels_checked_out++;
989 if (for_writing)
990 {
991 EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
992 }
993
994 return data;
995}
996
997EAPI void
998evas_object_image_preload(Evas_Object *obj, Eina_Bool cancel)
999{
1000 Evas_Object_Image *o;
1001
1002 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1003 return ;
1004 MAGIC_CHECK_END();
1005 o = (Evas_Object_Image *)(obj->object_data);
1006 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1007 return ;
1008 MAGIC_CHECK_END();
1009 if (!o->engine_data)
1010 {
1011 o->preloading = 1;
1012 evas_object_inform_call_image_preloaded(obj);
1013 return;
1014 }
1015 // FIXME: if already busy preloading, then dont request again until
1016 // preload done
1017 if (cancel)
1018 {
1019 if (o->preloading)
1020 {
1021 o->preloading = 0;
1022 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
1023 o->engine_data,
1024 obj);
1025 }
1026 }
1027 else
1028 {
1029 if (!o->preloading)
1030 {
1031 o->preloading = 1;
1032 obj->layer->evas->engine.func->image_data_preload_request(obj->layer->evas->engine.data.output,
1033 o->engine_data,
1034 obj);
1035 }
1036 }
1037}
1038
1039EAPI void
1040evas_object_image_data_copy_set(Evas_Object *obj, void *data)
1041{
1042 Evas_Object_Image *o;
1043
1044 if (!data) return;
1045 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1046 return;
1047 MAGIC_CHECK_END();
1048 o = (Evas_Object_Image *)(obj->object_data);
1049 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1050 return;
1051 MAGIC_CHECK_END();
1052 _evas_object_image_cleanup(obj, o);
1053 if ((o->cur.image.w <= 0) ||
1054 (o->cur.image.h <= 0)) return;
1055 if (o->engine_data)
1056 obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output,
1057 o->engine_data);
1058 o->engine_data = obj->layer->evas->engine.func->image_new_from_copied_data(obj->layer->evas->engine.data.output,
1059 o->cur.image.w,
1060 o->cur.image.h,
1061 data,
1062 o->cur.has_alpha,
1063 o->cur.cspace);
1064 if (o->engine_data)
1065 {
1066 int stride = 0;
1067
1068 o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
1069 o->engine_data,
1070 o->cur.has_alpha);
1071 if (obj->layer->evas->engine.func->image_scale_hint_set)
1072 obj->layer->evas->engine.func->image_scale_hint_set
1073 (obj->layer->evas->engine.data.output,
1074 o->engine_data, o->scale_hint);
1075 if (obj->layer->evas->engine.func->image_content_hint_set)
1076 obj->layer->evas->engine.func->image_content_hint_set
1077 (obj->layer->evas->engine.data.output,
1078 o->engine_data, o->content_hint);
1079 if (obj->layer->evas->engine.func->image_stride_get)
1080 obj->layer->evas->engine.func->image_stride_get
1081 (obj->layer->evas->engine.data.output,
1082 o->engine_data, &stride);
1083 else
1084 stride = o->cur.image.w * 4;
1085 o->cur.image.stride = stride;
1086 }
1087 o->pixels_checked_out = 0;
1088 EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
1089}
1090
1091EAPI void
1092evas_object_image_data_update_add(Evas_Object *obj, int x, int y, int w, int h)
1093{
1094 Evas_Object_Image *o;
1095 Eina_Rectangle *r;
1096
1097 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1098 return;
1099 MAGIC_CHECK_END();
1100 o = (Evas_Object_Image *)(obj->object_data);
1101 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1102 return;
1103 MAGIC_CHECK_END();
1104 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, o->cur.image.w, o->cur.image.h);
1105 if ((w <= 0) || (h <= 0)) return;
1106 NEW_RECT(r, x, y, w, h);
1107 if (r) o->pixel_updates = eina_list_append(o->pixel_updates, r);
1108 o->changed = 1;
1109 evas_object_change(obj);
1110}
1111
1112EAPI void
1113evas_object_image_alpha_set(Evas_Object *obj, Eina_Bool has_alpha)
1114{
1115 Evas_Object_Image *o;
1116
1117 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1118 return;
1119 MAGIC_CHECK_END();
1120 o = (Evas_Object_Image *)(obj->object_data);
1121 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1122 return;
1123 MAGIC_CHECK_END();
1124 if ((o->preloading) && (o->engine_data))
1125 {
1126 o->preloading = 0;
1127 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
1128 o->engine_data,
1129 obj);
1130 }
1131 if (((has_alpha) && (o->cur.has_alpha)) ||
1132 ((!has_alpha) && (!o->cur.has_alpha)))
1133 return;
1134 o->cur.has_alpha = has_alpha;
1135 if (o->engine_data)
1136 {
1137 int stride = 0;
1138
1139#ifdef EVAS_FRAME_QUEUING
1140 evas_common_pipe_op_image_flush(o->engine_data);
1141#endif
1142 o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
1143 o->engine_data,
1144 o->cur.has_alpha);
1145 if (obj->layer->evas->engine.func->image_scale_hint_set)
1146 obj->layer->evas->engine.func->image_scale_hint_set
1147 (obj->layer->evas->engine.data.output,
1148 o->engine_data, o->scale_hint);
1149 if (obj->layer->evas->engine.func->image_content_hint_set)
1150 obj->layer->evas->engine.func->image_content_hint_set
1151 (obj->layer->evas->engine.data.output,
1152 o->engine_data, o->content_hint);
1153 if (obj->layer->evas->engine.func->image_stride_get)
1154 obj->layer->evas->engine.func->image_stride_get
1155 (obj->layer->evas->engine.data.output,
1156 o->engine_data, &stride);
1157 else
1158 stride = o->cur.image.w * 4;
1159 o->cur.image.stride = stride;
1160 }
1161 evas_object_image_data_update_add(obj, 0, 0, o->cur.image.w, o->cur.image.h);
1162 EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
1163}
1164
1165
1166EAPI Eina_Bool
1167evas_object_image_alpha_get(const Evas_Object *obj)
1168{
1169 Evas_Object_Image *o;
1170
1171 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1172 return 0;
1173 MAGIC_CHECK_END();
1174 o = (Evas_Object_Image *)(obj->object_data);
1175 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1176 return 0;
1177 MAGIC_CHECK_END();
1178 return o->cur.has_alpha;
1179}
1180
1181EAPI void
1182evas_object_image_smooth_scale_set(Evas_Object *obj, Eina_Bool smooth_scale)
1183{
1184 Evas_Object_Image *o;
1185
1186 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1187 return;
1188 MAGIC_CHECK_END();
1189 o = (Evas_Object_Image *)(obj->object_data);
1190 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1191 return;
1192 MAGIC_CHECK_END();
1193 if (((smooth_scale) && (o->cur.smooth_scale)) ||
1194 ((!smooth_scale) && (!o->cur.smooth_scale)))
1195 return;
1196 o->cur.smooth_scale = smooth_scale;
1197 o->changed = 1;
1198 evas_object_change(obj);
1199}
1200
1201EAPI Eina_Bool
1202evas_object_image_smooth_scale_get(const Evas_Object *obj)
1203{
1204 Evas_Object_Image *o;
1205
1206 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1207 return 0;
1208 MAGIC_CHECK_END();
1209 o = (Evas_Object_Image *)(obj->object_data);
1210 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1211 return 0;
1212 MAGIC_CHECK_END();
1213 return o->cur.smooth_scale;
1214}
1215
1216EAPI void
1217evas_object_image_reload(Evas_Object *obj)
1218{
1219 Evas_Object_Image *o;
1220
1221 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1222 return;
1223 MAGIC_CHECK_END();
1224 o = (Evas_Object_Image *)(obj->object_data);
1225 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1226 return;
1227 MAGIC_CHECK_END();
1228 if ((o->preloading) && (o->engine_data))
1229 {
1230 o->preloading = 0;
1231 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
1232 o->engine_data,
1233 obj);
1234 }
1235 if ((!o->cur.file) ||
1236 (o->pixels_checked_out > 0)) return;
1237 if (o->engine_data)
1238 o->engine_data = obj->layer->evas->engine.func->image_dirty_region(obj->layer->evas->engine.data.output, o->engine_data, 0, 0, o->cur.image.w, o->cur.image.h);
1239 evas_object_image_unload(obj, 1);
1240 evas_object_inform_call_image_unloaded(obj);
1241 evas_object_image_load(obj);
1242 o->prev.file = NULL;
1243 o->prev.key = NULL;
1244 o->changed = 1;
1245 evas_object_change(obj);
1246}
1247
1248EAPI Eina_Bool
1249evas_object_image_save(const Evas_Object *obj, const char *file, const char *key, const char *flags)
1250{
1251 Evas_Object_Image *o;
1252 DATA32 *data = NULL;
1253 int quality = 80, compress = 9, ok = 0;
1254 RGBA_Image *im;
1255
1256 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1257 return 0;
1258 MAGIC_CHECK_END();
1259 o = (Evas_Object_Image *)(obj->object_data);
1260 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1261 return 0;
1262 MAGIC_CHECK_END();
1263
1264 if (!o->engine_data) return 0;
1265 o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
1266 o->engine_data,
1267 0,
1268 &data,
1269 &o->load_error);
1270 if (flags)
1271 {
1272 char *p, *pp;
1273 char *tflags;
1274
1275 tflags = alloca(strlen(flags) + 1);
1276 strcpy(tflags, flags);
1277 p = tflags;
1278 while (p)
1279 {
1280 pp = strchr(p, ' ');
1281 if (pp) *pp = 0;
1282 sscanf(p, "quality=%i", &quality);
1283 sscanf(p, "compress=%i", &compress);
1284 if (pp) p = pp + 1;
1285 else break;
1286 }
1287 }
1288 im = (RGBA_Image*) evas_cache_image_data(evas_common_image_cache_get(),
1289 o->cur.image.w,
1290 o->cur.image.h,
1291 data,
1292 o->cur.has_alpha,
1293 EVAS_COLORSPACE_ARGB8888);
1294 if (im)
1295 {
1296 if (o->cur.cspace == EVAS_COLORSPACE_ARGB8888)
1297 im->image.data = data;
1298 else
1299 im->image.data = evas_object_image_data_convert_internal(o,
1300 data,
1301 EVAS_COLORSPACE_ARGB8888);
1302 if (im->image.data)
1303 {
1304 ok = evas_common_save_image_to_file(im, file, key, quality, compress);
1305
1306 if (o->cur.cspace != EVAS_COLORSPACE_ARGB8888)
1307 free(im->image.data);
1308 }
1309
1310 evas_cache_image_drop(&im->cache_entry);
1311 }
1312 return ok;
1313}
1314
1315EAPI Eina_Bool
1316evas_object_image_pixels_import(Evas_Object *obj, Evas_Pixel_Import_Source *pixels)
1317{
1318 Evas_Object_Image *o;
1319
1320 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1321 return 0;
1322 MAGIC_CHECK_END();
1323 o = (Evas_Object_Image *)(obj->object_data);
1324 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1325 return 0;
1326 MAGIC_CHECK_END();
1327 _evas_object_image_cleanup(obj, o);
1328 if ((pixels->w != o->cur.image.w) || (pixels->h != o->cur.image.h)) return 0;
1329 switch (pixels->format)
1330 {
1331#if 0
1332 case EVAS_PIXEL_FORMAT_ARGB32:
1333 {
1334 if (o->engine_data)
1335 {
1336 DATA32 *image_pixels = NULL;
1337
1338 o->engine_data =
1339 obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
1340 o->engine_data,
1341 1,
1342 &image_pixels,
1343 &o->load_error);
1344/* FIXME: need to actualyl support this */
1345/* memcpy(image_pixels, pixels->rows, o->cur.image.w * o->cur.image.h * 4);*/
1346 if (o->engine_data)
1347 o->engine_data =
1348 obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output,
1349 o->engine_data,
1350 image_pixels);
1351 if (o->engine_data)
1352 o->engine_data =
1353 obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
1354 o->engine_data,
1355 o->cur.has_alpha);
1356 o->changed = 1;
1357 evas_object_change(obj);
1358 }
1359 }
1360 break;
1361#endif
1362#ifdef BUILD_CONVERT_YUV
1363 case EVAS_PIXEL_FORMAT_YUV420P_601:
1364 {
1365 if (o->engine_data)
1366 {
1367 DATA32 *image_pixels = NULL;
1368
1369 o->engine_data =
1370 obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
1371 o->engine_data,
1372 1,
1373 &image_pixels,
1374 &o->load_error);
1375 if (image_pixels)
1376 evas_common_convert_yuv_420p_601_rgba((DATA8 **) pixels->rows,
1377 (DATA8 *) image_pixels,
1378 o->cur.image.w,
1379 o->cur.image.h);
1380 if (o->engine_data)
1381 o->engine_data =
1382 obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output,
1383 o->engine_data,
1384 image_pixels);
1385 if (o->engine_data)
1386 o->engine_data =
1387 obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
1388 o->engine_data,
1389 o->cur.has_alpha);
1390 o->changed = 1;
1391 evas_object_change(obj);
1392 }
1393 }
1394 break;
1395#endif
1396 default:
1397 return 0;
1398 break;
1399 }
1400 return 1;
1401}
1402
1403EAPI void
1404evas_object_image_pixels_get_callback_set(Evas_Object *obj, Evas_Object_Image_Pixels_Get_Cb func, void *data)
1405{
1406 Evas_Object_Image *o;
1407
1408 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1409 return;
1410 MAGIC_CHECK_END();
1411 o = (Evas_Object_Image *)(obj->object_data);
1412 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1413 return;
1414 MAGIC_CHECK_END();
1415 o->func.get_pixels = func;
1416 o->func.get_pixels_data = data;
1417}
1418
1419EAPI void
1420evas_object_image_pixels_dirty_set(Evas_Object *obj, Eina_Bool dirty)
1421{
1422 Evas_Object_Image *o;
1423
1424 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1425 return;
1426 MAGIC_CHECK_END();
1427 o = (Evas_Object_Image *)(obj->object_data);
1428 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1429 return;
1430 MAGIC_CHECK_END();
1431 if (dirty) o->dirty_pixels = 1;
1432 else o->dirty_pixels = 0;
1433 o->changed = 1;
1434 evas_object_change(obj);
1435}
1436
1437EAPI Eina_Bool
1438evas_object_image_pixels_dirty_get(const Evas_Object *obj)
1439{
1440 Evas_Object_Image *o;
1441
1442 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1443 return 0;
1444 MAGIC_CHECK_END();
1445 o = (Evas_Object_Image *)(obj->object_data);
1446 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1447 return 0;
1448 MAGIC_CHECK_END();
1449 if (o->dirty_pixels) return 1;
1450 return 0;
1451}
1452
1453EAPI void
1454evas_object_image_load_dpi_set(Evas_Object *obj, double dpi)
1455{
1456 Evas_Object_Image *o;
1457
1458 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1459 return;
1460 MAGIC_CHECK_END();
1461 o = (Evas_Object_Image *)(obj->object_data);
1462 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1463 return;
1464 MAGIC_CHECK_END();
1465 if (dpi == o->load_opts.dpi) return;
1466 o->load_opts.dpi = dpi;
1467 if (o->cur.file)
1468 {
1469 evas_object_image_unload(obj, 0);
1470 evas_object_inform_call_image_unloaded(obj);
1471 evas_object_image_load(obj);
1472 o->changed = 1;
1473 evas_object_change(obj);
1474 }
1475}
1476
1477EAPI double
1478evas_object_image_load_dpi_get(const Evas_Object *obj)
1479{
1480 Evas_Object_Image *o;
1481
1482 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1483 return 0.0;
1484 MAGIC_CHECK_END();
1485 o = (Evas_Object_Image *)(obj->object_data);
1486 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1487 return 0.0;
1488 MAGIC_CHECK_END();
1489 return o->load_opts.dpi;
1490}
1491
1492EAPI void
1493evas_object_image_load_size_set(Evas_Object *obj, int w, int h)
1494{
1495 Evas_Object_Image *o;
1496
1497 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1498 return;
1499 MAGIC_CHECK_END();
1500 o = (Evas_Object_Image *)(obj->object_data);
1501 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1502 return;
1503 MAGIC_CHECK_END();
1504 if ((o->load_opts.w == w) && (o->load_opts.h == h)) return;
1505 o->load_opts.w = w;
1506 o->load_opts.h = h;
1507 if (o->cur.file)
1508 {
1509 evas_object_image_unload(obj, 0);
1510 evas_object_inform_call_image_unloaded(obj);
1511 evas_object_image_load(obj);
1512 o->changed = 1;
1513 evas_object_change(obj);
1514 }
1515}
1516
1517EAPI void
1518evas_object_image_load_size_get(const Evas_Object *obj, int *w, int *h)
1519{
1520 Evas_Object_Image *o;
1521
1522 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1523 return;
1524 MAGIC_CHECK_END();
1525 o = (Evas_Object_Image *)(obj->object_data);
1526 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1527 return;
1528 MAGIC_CHECK_END();
1529 if (w) *w = o->load_opts.w;
1530 if (h) *h = o->load_opts.h;
1531}
1532
1533EAPI void
1534evas_object_image_load_scale_down_set(Evas_Object *obj, int scale_down)
1535{
1536 Evas_Object_Image *o;
1537
1538 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1539 return;
1540 MAGIC_CHECK_END();
1541 o = (Evas_Object_Image *)(obj->object_data);
1542 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1543 return;
1544 MAGIC_CHECK_END();
1545 if (o->load_opts.scale_down_by == scale_down) return;
1546 o->load_opts.scale_down_by = scale_down;
1547 if (o->cur.file)
1548 {
1549 evas_object_image_unload(obj, 0);
1550 evas_object_inform_call_image_unloaded(obj);
1551 evas_object_image_load(obj);
1552 o->changed = 1;
1553 evas_object_change(obj);
1554 }
1555}
1556
1557EAPI int
1558evas_object_image_load_scale_down_get(const Evas_Object *obj)
1559{
1560 Evas_Object_Image *o;
1561
1562 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1563 return 0;
1564 MAGIC_CHECK_END();
1565 o = (Evas_Object_Image *)(obj->object_data);
1566 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1567 return 0;
1568 MAGIC_CHECK_END();
1569 return o->load_opts.scale_down_by;
1570}
1571
1572EAPI void
1573evas_object_image_load_region_set(Evas_Object *obj, int x, int y, int w, int h)
1574{
1575 Evas_Object_Image *o;
1576
1577 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1578 return;
1579 MAGIC_CHECK_END();
1580 o = (Evas_Object_Image *)(obj->object_data);
1581 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1582 return;
1583 MAGIC_CHECK_END();
1584 if ((o->load_opts.region.x == x) && (o->load_opts.region.y == y) &&
1585 (o->load_opts.region.w == w) && (o->load_opts.region.h == h)) return;
1586 o->load_opts.region.x = x;
1587 o->load_opts.region.y = y;
1588 o->load_opts.region.w = w;
1589 o->load_opts.region.h = h;
1590 if (o->cur.file)
1591 {
1592 evas_object_image_unload(obj, 0);
1593 evas_object_inform_call_image_unloaded(obj);
1594 evas_object_image_load(obj);
1595 o->changed = 1;
1596 evas_object_change(obj);
1597 }
1598}
1599
1600EAPI void
1601evas_object_image_load_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h)
1602{
1603 Evas_Object_Image *o;
1604
1605 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1606 return;
1607 MAGIC_CHECK_END();
1608 o = (Evas_Object_Image *)(obj->object_data);
1609 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1610 return;
1611 MAGIC_CHECK_END();
1612 if (x) *x = o->load_opts.region.x;
1613 if (y) *y = o->load_opts.region.y;
1614 if (w) *w = o->load_opts.region.w;
1615 if (h) *h = o->load_opts.region.h;
1616}
1617
1618EAPI void
1619evas_object_image_load_orientation_set(Evas_Object *obj, Eina_Bool enable)
1620{
1621 Evas_Object_Image *o;
1622
1623 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1624 return;
1625 MAGIC_CHECK_END();
1626 o = (Evas_Object_Image *)(obj->object_data);
1627 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1628 return;
1629 MAGIC_CHECK_END();
1630 o->load_opts.orientation = !!enable;
1631}
1632
1633EAPI Eina_Bool
1634evas_object_image_load_orientation_get(const Evas_Object *obj)
1635{
1636 Evas_Object_Image *o;
1637
1638 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1639 return EINA_FALSE;
1640 MAGIC_CHECK_END();
1641 o = (Evas_Object_Image *)(obj->object_data);
1642 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1643 return EINA_FALSE;
1644 MAGIC_CHECK_END();
1645 return o->load_opts.orientation;
1646}
1647
1648EAPI void
1649evas_object_image_colorspace_set(Evas_Object *obj, Evas_Colorspace cspace)
1650{
1651 Evas_Object_Image *o;
1652
1653 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1654 return;
1655 MAGIC_CHECK_END();
1656 o = (Evas_Object_Image *)(obj->object_data);
1657 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1658 return;
1659 MAGIC_CHECK_END();
1660
1661 _evas_object_image_cleanup(obj, o);
1662#ifdef EVAS_FRAME_QUEUING
1663 if ((Evas_Colorspace)o->cur.cspace != cspace)
1664 {
1665 if (o->engine_data)
1666 evas_common_pipe_op_image_flush(o->engine_data);
1667 }
1668#endif
1669
1670 o->cur.cspace = cspace;
1671 if (o->engine_data)
1672 obj->layer->evas->engine.func->image_colorspace_set(obj->layer->evas->engine.data.output,
1673 o->engine_data,
1674 cspace);
1675}
1676
1677EAPI Evas_Colorspace
1678evas_object_image_colorspace_get(const Evas_Object *obj)
1679{
1680 Evas_Object_Image *o;
1681
1682 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1683 return EVAS_COLORSPACE_ARGB8888;
1684 MAGIC_CHECK_END();
1685 o = (Evas_Object_Image *)(obj->object_data);
1686 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1687 return EVAS_COLORSPACE_ARGB8888;
1688 MAGIC_CHECK_END();
1689 return o->cur.cspace;
1690}
1691
1692EAPI void
1693evas_object_image_video_surface_set(Evas_Object *obj, Evas_Video_Surface *surf)
1694{
1695 Evas_Object_Image *o;
1696
1697 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1698 return;
1699 MAGIC_CHECK_END();
1700 o = (Evas_Object_Image *)(obj->object_data);
1701 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1702 return;
1703 MAGIC_CHECK_END();
1704 _evas_object_image_cleanup(obj, o);
1705 if (o->video_surface)
1706 {
1707 o->video_surface = 0;
1708 obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, obj);
1709 }
1710
1711 if (surf)
1712 {
1713 if (surf->version != EVAS_VIDEO_SURFACE_VERSION) return ;
1714
1715 if (!surf->update_pixels ||
1716 !surf->move ||
1717 !surf->resize ||
1718 !surf->hide ||
1719 !surf->show)
1720 return ;
1721
1722 o->created = EINA_TRUE;
1723 o->video_surface = 1;
1724 o->video = *surf;
1725
1726 obj->layer->evas->video_objects = eina_list_append(obj->layer->evas->video_objects, obj);
1727 }
1728 else
1729 {
1730 o->video_surface = 0;
1731 o->video.update_pixels = NULL;
1732 o->video.move = NULL;
1733 o->video.resize = NULL;
1734 o->video.hide = NULL;
1735 o->video.show = NULL;
1736 o->video.data = NULL;
1737 }
1738}
1739
1740EAPI const Evas_Video_Surface *
1741evas_object_image_video_surface_get(const Evas_Object *obj)
1742{
1743 Evas_Object_Image *o;
1744
1745 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1746 return NULL;
1747 MAGIC_CHECK_END();
1748 o = (Evas_Object_Image *)(obj->object_data);
1749 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1750 return NULL;
1751 MAGIC_CHECK_END();
1752 if (!o->video_surface) return NULL;
1753 return &o->video;
1754}
1755
1756EAPI void
1757evas_object_image_native_surface_set(Evas_Object *obj, Evas_Native_Surface *surf)
1758{
1759 Evas_Object_Image *o;
1760
1761 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1762 return;
1763 MAGIC_CHECK_END();
1764 o = (Evas_Object_Image *)(obj->object_data);
1765 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1766 return;
1767 MAGIC_CHECK_END();
1768 _evas_object_image_cleanup(obj, o);
1769 if (!obj->layer->evas->engine.func->image_native_set) return;
1770 if ((surf) &&
1771 ((surf->version < 2) ||
1772 (surf->version > EVAS_NATIVE_SURFACE_VERSION))) return;
1773 o->engine_data =
1774 obj->layer->evas->engine.func->image_native_set(obj->layer->evas->engine.data.output,
1775 o->engine_data,
1776 surf);
1777}
1778
1779EAPI Evas_Native_Surface *
1780evas_object_image_native_surface_get(const Evas_Object *obj)
1781{
1782 Evas_Object_Image *o;
1783
1784 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1785 return NULL;
1786 MAGIC_CHECK_END();
1787 o = (Evas_Object_Image *)(obj->object_data);
1788 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1789 return NULL;
1790 MAGIC_CHECK_END();
1791 if (!obj->layer->evas->engine.func->image_native_get) return NULL;
1792 return obj->layer->evas->engine.func->image_native_get(obj->layer->evas->engine.data.output,
1793 o->engine_data);
1794}
1795
1796EAPI void
1797evas_object_image_scale_hint_set(Evas_Object *obj, Evas_Image_Scale_Hint hint)
1798{
1799 Evas_Object_Image *o;
1800
1801 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1802 return;
1803 MAGIC_CHECK_END();
1804 o = (Evas_Object_Image *)(obj->object_data);
1805 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1806 return;
1807 MAGIC_CHECK_END();
1808 if (o->scale_hint == hint) return;
1809#ifdef EVAS_FRAME_QUEUING
1810 if (o->engine_data)
1811 evas_common_pipe_op_image_flush(o->engine_data);
1812#endif
1813 o->scale_hint = hint;
1814 if (o->engine_data)
1815 {
1816 int stride = 0;
1817
1818 if (obj->layer->evas->engine.func->image_scale_hint_set)
1819 obj->layer->evas->engine.func->image_scale_hint_set
1820 (obj->layer->evas->engine.data.output,
1821 o->engine_data, o->scale_hint);
1822 if (obj->layer->evas->engine.func->image_stride_get)
1823 obj->layer->evas->engine.func->image_stride_get
1824 (obj->layer->evas->engine.data.output,
1825 o->engine_data, &stride);
1826 else
1827 stride = o->cur.image.w * 4;
1828 o->cur.image.stride = stride;
1829 }
1830}
1831
1832EAPI Evas_Image_Scale_Hint
1833evas_object_image_scale_hint_get(const Evas_Object *obj)
1834{
1835 Evas_Object_Image *o;
1836
1837 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1838 return EVAS_IMAGE_SCALE_HINT_NONE;
1839 MAGIC_CHECK_END();
1840 o = (Evas_Object_Image *)(obj->object_data);
1841 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1842 return EVAS_IMAGE_SCALE_HINT_NONE;
1843 MAGIC_CHECK_END();
1844 return o->scale_hint;
1845}
1846
1847EAPI void
1848evas_object_image_content_hint_set(Evas_Object *obj, Evas_Image_Content_Hint hint)
1849{
1850 Evas_Object_Image *o;
1851
1852 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1853 return;
1854 MAGIC_CHECK_END();
1855 o = (Evas_Object_Image *)(obj->object_data);
1856 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1857 return;
1858 MAGIC_CHECK_END();
1859 if (o->content_hint == hint) return;
1860#ifdef EVAS_FRAME_QUEUING
1861 if (o->engine_data)
1862 evas_common_pipe_op_image_flush(o->engine_data);
1863#endif
1864 o->content_hint = hint;
1865 if (o->engine_data)
1866 {
1867 int stride = 0;
1868
1869 if (obj->layer->evas->engine.func->image_content_hint_set)
1870 obj->layer->evas->engine.func->image_content_hint_set
1871 (obj->layer->evas->engine.data.output,
1872 o->engine_data, o->content_hint);
1873 if (obj->layer->evas->engine.func->image_stride_get)
1874 obj->layer->evas->engine.func->image_stride_get
1875 (obj->layer->evas->engine.data.output,
1876 o->engine_data, &stride);
1877 else
1878 stride = o->cur.image.w * 4;
1879 o->cur.image.stride = stride;
1880 }
1881}
1882
1883EAPI void
1884evas_object_image_alpha_mask_set(Evas_Object *obj, Eina_Bool ismask)
1885{
1886 Evas_Object_Image *o;
1887
1888 if (!ismask) return;
1889
1890 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1891 return;
1892 MAGIC_CHECK_END();
1893 o = (Evas_Object_Image *)(obj->object_data);
1894 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1895 return;
1896 MAGIC_CHECK_END();
1897
1898 /* Convert to A8 if not already */
1899
1900 /* done */
1901
1902}
1903
1904#define FRAME_MAX 1024
1905EAPI Evas_Image_Content_Hint
1906evas_object_image_content_hint_get(const Evas_Object *obj)
1907{
1908 Evas_Object_Image *o;
1909
1910 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1911 return EVAS_IMAGE_CONTENT_HINT_NONE;
1912 MAGIC_CHECK_END();
1913 o = (Evas_Object_Image *)(obj->object_data);
1914 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1915 return EVAS_IMAGE_CONTENT_HINT_NONE;
1916 MAGIC_CHECK_END();
1917 return o->content_hint;
1918}
1919
1920/* animated feature */
1921EAPI Eina_Bool
1922evas_object_image_animated_get(const Evas_Object *obj)
1923{
1924 Evas_Object_Image *o;
1925
1926 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1927 return EINA_FALSE;
1928 MAGIC_CHECK_END();
1929 o = (Evas_Object_Image *)(obj->object_data);
1930 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1931 return EINA_FALSE;
1932 MAGIC_CHECK_END();
1933
1934 if (obj->layer->evas->engine.func->image_animated_get)
1935 return obj->layer->evas->engine.func->image_animated_get(obj->layer->evas->engine.data.output, o->engine_data);
1936 return EINA_FALSE;
1937}
1938
1939EAPI int
1940evas_object_image_animated_frame_count_get(const Evas_Object *obj)
1941{
1942 Evas_Object_Image *o;
1943
1944 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1945 return -1;
1946 MAGIC_CHECK_END();
1947 o = (Evas_Object_Image *)(obj->object_data);
1948 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1949 return -1;
1950 MAGIC_CHECK_END();
1951
1952 if (!evas_object_image_animated_get(obj)) return -1;
1953 if (obj->layer->evas->engine.func->image_animated_frame_count_get)
1954 return obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data);
1955 return -1;
1956}
1957
1958EAPI Evas_Image_Animated_Loop_Hint
1959evas_object_image_animated_loop_type_get(const Evas_Object *obj)
1960{
1961 Evas_Object_Image *o;
1962
1963 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1964 return EVAS_IMAGE_ANIMATED_HINT_NONE;
1965 MAGIC_CHECK_END();
1966 o = (Evas_Object_Image *)(obj->object_data);
1967 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1968 return EVAS_IMAGE_ANIMATED_HINT_NONE;
1969 MAGIC_CHECK_END();
1970
1971 if (!evas_object_image_animated_get(obj)) return EVAS_IMAGE_ANIMATED_HINT_NONE;
1972
1973 if (obj->layer->evas->engine.func->image_animated_loop_type_get)
1974 return obj->layer->evas->engine.func->image_animated_loop_type_get(obj->layer->evas->engine.data.output, o->engine_data);
1975 return EVAS_IMAGE_ANIMATED_HINT_NONE;
1976}
1977
1978EAPI int
1979evas_object_image_animated_loop_count_get(const Evas_Object *obj)
1980{
1981 Evas_Object_Image *o;
1982
1983 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1984 return -1;
1985 MAGIC_CHECK_END();
1986 o = (Evas_Object_Image *)(obj->object_data);
1987 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
1988 return -1;
1989 MAGIC_CHECK_END();
1990
1991 if (!evas_object_image_animated_get(obj)) return -1;
1992
1993 if (obj->layer->evas->engine.func->image_animated_loop_count_get)
1994 return obj->layer->evas->engine.func->image_animated_loop_count_get(obj->layer->evas->engine.data.output, o->engine_data);
1995 return -1;
1996}
1997
1998EAPI double
1999evas_object_image_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num)
2000{
2001 Evas_Object_Image *o;
2002 int frame_count = 0;
2003
2004 if (start_frame < 1) return -1;
2005 if (frame_num < 0) return -1;
2006
2007 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
2008 return -1;
2009 MAGIC_CHECK_END();
2010 o = (Evas_Object_Image *)(obj->object_data);
2011 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
2012 return -1;
2013 MAGIC_CHECK_END();
2014
2015 if (!evas_object_image_animated_get(obj)) return -1;
2016
2017 if (!obj->layer->evas->engine.func->image_animated_frame_count_get) return -1;
2018
2019 frame_count = obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data);
2020
2021 if ((start_frame + frame_num) > frame_count) return -1;
2022 if (obj->layer->evas->engine.func->image_animated_frame_duration_get)
2023 return obj->layer->evas->engine.func->image_animated_frame_duration_get(obj->layer->evas->engine.data.output, o->engine_data, start_frame, frame_num);
2024 return -1;
2025}
2026
2027EAPI void
2028evas_object_image_animated_frame_set(Evas_Object *obj, int frame_index)
2029{
2030 Evas_Object_Image *o;
2031 int frame_count = 0;
2032
2033 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
2034 return;
2035 MAGIC_CHECK_END();
2036 o = (Evas_Object_Image *)(obj->object_data);
2037 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
2038 return;
2039 MAGIC_CHECK_END();
2040
2041 if (!o->cur.file) return;
2042 if (o->cur.frame == frame_index) return;
2043
2044 if (!evas_object_image_animated_get(obj)) return;
2045
2046 frame_count = evas_object_image_animated_frame_count_get(obj);
2047
2048 /* limit the size of frame to FRAME_MAX */
2049 if ((frame_count > FRAME_MAX) || (frame_count < 0) || (frame_index > frame_count))
2050 return;
2051
2052 if (!obj->layer->evas->engine.func->image_animated_frame_set) return;
2053 if (!obj->layer->evas->engine.func->image_animated_frame_set(obj->layer->evas->engine.data.output, o->engine_data, frame_index))
2054 return;
2055
2056 o->prev.frame = o->cur.frame;
2057 o->cur.frame = frame_index;
2058
2059 o->changed = 1;
2060 evas_object_change(obj);
2061
2062}
2063
2064EAPI void
2065evas_image_cache_flush(Evas *e)
2066{
2067 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2068 return;
2069 MAGIC_CHECK_END();
2070
2071 e->engine.func->image_cache_flush(e->engine.data.output);
2072}
2073
2074EAPI void
2075evas_image_cache_reload(Evas *e)
2076{
2077 Evas_Layer *layer;
2078
2079 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2080 return;
2081 MAGIC_CHECK_END();
2082
2083 evas_image_cache_flush(e);
2084 EINA_INLIST_FOREACH(e->layers, layer)
2085 {
2086 Evas_Object *obj;
2087
2088 EINA_INLIST_FOREACH(layer->objects, obj)
2089 {
2090 Evas_Object_Image *o;
2091
2092 o = (Evas_Object_Image *)(obj->object_data);
2093 if (o->magic == MAGIC_OBJ_IMAGE)
2094 {
2095 evas_object_image_unload(obj, 1);
2096 evas_object_inform_call_image_unloaded(obj);
2097 }
2098 }
2099 }
2100 evas_image_cache_flush(e);
2101 EINA_INLIST_FOREACH(e->layers, layer)
2102 {
2103 Evas_Object *obj;
2104
2105 EINA_INLIST_FOREACH(layer->objects, obj)
2106 {
2107 Evas_Object_Image *o;
2108
2109 o = (Evas_Object_Image *)(obj->object_data);
2110 if (o->magic == MAGIC_OBJ_IMAGE)
2111 {
2112 evas_object_image_load(obj);
2113 o->changed = 1;
2114 evas_object_change(obj);
2115 }
2116 }
2117 }
2118 evas_image_cache_flush(e);
2119}
2120
2121EAPI void
2122evas_image_cache_set(Evas *e, int size)
2123{
2124 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2125 return;
2126 MAGIC_CHECK_END();
2127
2128 if (size < 0) size = 0;
2129 e->engine.func->image_cache_set(e->engine.data.output, size);
2130}
2131
2132EAPI int
2133evas_image_cache_get(const Evas *e)
2134{
2135 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2136 return 0;
2137 MAGIC_CHECK_END();
2138
2139 return e->engine.func->image_cache_get(e->engine.data.output);
2140}
2141
2142EAPI Eina_Bool
2143evas_image_max_size_get(const Evas *e, int *maxw, int *maxh)
2144{
2145 int w = 0, h = 0;
2146 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
2147 return EINA_FALSE;
2148 MAGIC_CHECK_END();
2149
2150 if (maxw) *maxw = 0xffff;
2151 if (maxh) *maxh = 0xffff;
2152 if (!e->engine.func->image_max_size_get) return EINA_FALSE;
2153 e->engine.func->image_max_size_get(e->engine.data.output, &w, &h);
2154 if (maxw) *maxw = w;
2155 if (maxh) *maxh = h;
2156 return EINA_TRUE;
2157}
2158
2159/* all nice and private */
2160static void
2161_proxy_unset(Evas_Object *proxy)
2162{
2163 Evas_Object_Image *o;
2164
2165 o = proxy->object_data;
2166 if (!o->cur.source) return;
2167
2168 o->cur.source->proxy.proxies = eina_list_remove(o->cur.source->proxy.proxies, proxy);
2169
2170 o->cur.source = NULL;
2171 if (o->cur.defmap)
2172 {
2173 evas_map_free(o->cur.defmap);
2174 o->cur.defmap = NULL;
2175 }
2176}
2177
2178
2179static void
2180_proxy_set(Evas_Object *proxy, Evas_Object *src)
2181{
2182 Evas_Object_Image *o;
2183
2184 o = proxy->object_data;
2185
2186 evas_object_image_file_set(proxy, NULL, NULL);
2187
2188 o->cur.source = src;
2189
2190 src->proxy.proxies = eina_list_append(src->proxy.proxies, proxy);
2191 src->proxy.redraw = EINA_TRUE;
2192}
2193
2194/* Some moron just set a proxy on a proxy.
2195 * Give them some pixels. A random color
2196 */
2197static void
2198_proxy_error(Evas_Object *proxy, void *context, void *output, void *surface,
2199 int x, int y)
2200{
2201 Evas_Func *func;
2202 int r = rand() % 255;
2203 int g = rand() % 255;
2204 int b = rand() % 255;
2205
2206 /* XXX: Eina log error or something I'm sure
2207 * If it bugs you, just fix it. Don't tell me */
2208 if (VERBOSE_PROXY_ERROR) printf("Err: Argh! Recursive proxies.\n");
2209
2210 func = proxy->layer->evas->engine.func;
2211 func->context_color_set(output, context, r, g, b, 255);
2212 func->context_multiplier_unset(output, context);
2213 func->context_render_op_set(output, context, proxy->cur.render_op);
2214 func->rectangle_draw(output, context, surface, proxy->cur.geometry.x + x,
2215 proxy->cur.geometry.y + y,
2216 proxy->cur.geometry.w,
2217 proxy->cur.geometry.h);
2218 return;
2219}
2220
2221/*
2222static void
2223_proxy_subrender_recurse(Evas_Object *obj, Evas_Object *clip, void *output, void *surface, void *ctx, int x, int y)
2224{
2225 Evas_Object *obj2;
2226 Evas *e = obj->layer->evas;
2227
2228 if (obj->clip.clipees) return;
2229 if (!obj->cur.visible) return;
2230 if ((!clip) || (clip != obj->cur.clipper))
2231 {
2232 if (!obj->cur.cache.clip.visible) return;
2233 if ((obj->cur.cache.clip.a == 0) &&
2234 (obj->cur.render_op == EVAS_RENDER_BLEND)) return;
2235 }
2236 if ((obj->func->is_visible) && (!obj->func->is_visible(obj))) return;
2237
2238 if (!obj->pre_render_done)
2239 obj->func->render_pre(obj);
2240 ctx = e->engine.func->context_new(output);
2241 if (obj->smart.smart)
2242 {
2243 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
2244 {
2245 _proxy_subrender_recurse(obj2, clip, output, surface, ctx, x, y);
2246 }
2247 }
2248 else
2249 {
2250 obj->func->render(obj, output, ctx, surface, x, y);
2251 }
2252 e->engine.func->context_free(output, ctx);
2253}
2254*/
2255
2256/**
2257 * Render the source object when a proxy is set.
2258 *
2259 * Used to force a draw if necessary, else just makes sures it's available.
2260 */
2261static void
2262_proxy_subrender(Evas *e, Evas_Object *source)
2263{
2264 void *ctx;
2265/* Evas_Object *obj2, *clip;*/
2266 int w, h;
2267
2268 if (!source) return;
2269
2270 w = source->cur.geometry.w;
2271 h = source->cur.geometry.h;
2272
2273 source->proxy.redraw = EINA_FALSE;
2274
2275 /* We need to redraw surface then */
2276 if ((source->proxy.surface) &&
2277 ((source->proxy.w != w) || (source->proxy.h != h)))
2278 {
2279 e->engine.func->image_map_surface_free(e->engine.data.output,
2280 source->proxy.surface);
2281 source->proxy.surface = NULL;
2282 }
2283
2284 /* FIXME: Hardcoded alpha 'on' */
2285 /* FIXME (cont): Should see if the object has alpha */
2286 if (!source->proxy.surface)
2287 {
2288 source->proxy.surface = e->engine.func->image_map_surface_new
2289 (e->engine.data.output, w, h, 1);
2290 source->proxy.w = w;
2291 source->proxy.h = h;
2292 }
2293
2294 ctx = e->engine.func->context_new(e->engine.data.output);
2295 e->engine.func->context_color_set(e->engine.data.output, ctx, 0, 0, 0, 0);
2296 e->engine.func->context_render_op_set(e->engine.data.output, ctx, EVAS_RENDER_COPY);
2297 e->engine.func->rectangle_draw(e->engine.data.output, ctx,
2298 source->proxy.surface, 0, 0, w, h);
2299 e->engine.func->context_free(e->engine.data.output, ctx);
2300
2301 ctx = e->engine.func->context_new(e->engine.data.output);
2302 evas_render_mapped(e, source, ctx, source->proxy.surface,
2303 -source->cur.geometry.x,
2304 -source->cur.geometry.y,
2305 1, 0, 0, e->output.w, e->output.h);
2306 e->engine.func->context_free(e->engine.data.output, ctx);
2307 source->proxy.surface = e->engine.func->image_dirty_region
2308 (e->engine.data.output, source->proxy.surface, 0, 0, w, h);
2309/*
2310 ctx = e->engine.func->context_new(e->engine.data.output);
2311 if (source->smart.smart)
2312 {
2313 clip = evas_object_smart_clipped_clipper_get(source);
2314 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(source), obj2)
2315 {
2316 _proxy_subrender_recurse(obj2, clip, e->engine.data.output,
2317 source->proxy.surface,
2318 ctx,
2319 -source->cur.geometry.x,
2320 -source->cur.geometry.y);
2321 }
2322 }
2323 else
2324 {
2325 if (!source->pre_render_done)
2326 source->func->render_pre(source);
2327 source->func->render(source, e->engine.data.output, ctx,
2328 source->proxy.surface,
2329 -source->cur.geometry.x,
2330 -source->cur.geometry.y);
2331 }
2332
2333 e->engine.func->context_free(e->engine.data.output, ctx);
2334 source->proxy.surface = e->engine.func->image_dirty_region
2335 (e->engine.data.output, source->proxy.surface, 0, 0, w, h);
2336 */
2337}
2338
2339#if 0 // filtering disabled
2340/*
2341 *
2342 * Note that this is similar to proxy_subrender_recurse. It should be
2343 * possible to merge I guess
2344 */
2345static void
2346image_filter_draw_under_recurse(Evas *e, Evas_Object *obj, Evas_Object *stop,
2347 void *output, void *ctx, void *surface,
2348 int x, int y)
2349{
2350 Evas_Object *obj2;
2351
2352 if (obj->clip.clipees) return;
2353 /* FIXME: Doing bounding box test */
2354 if (!evas_object_is_in_output_rect(obj, stop->cur.geometry.x,
2355 stop->cur.geometry.y,
2356 stop->cur.geometry.w,
2357 stop->cur.geometry.h))
2358 return;
2359
2360 if (!evas_object_is_visible(obj)) return;
2361 obj->pre_render_done = 1;
2362 ctx = e->engine.func->context_new(output);
2363
2364 if (obj->smart.smart)
2365 {
2366 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
2367 {
2368 if (obj2 == stop) return;
2369 image_filter_draw_under_recurse(e, obj2, stop, output, surface,
2370 ctx, x, y);
2371 }
2372 }
2373 else
2374 obj->func->render(obj, output, ctx, surface, x ,y);
2375 e->engine.func->context_free(output, ctx);
2376}
2377
2378/*
2379 * Draw all visible objects intersecting an object which are _beneath_ it.
2380 */
2381static void
2382image_filter_draw_under(Evas *e, Evas_Object *stop, void *output, void *ctx, void *surface, int dx, int dy)
2383{
2384 Evas_Layer *lay;
2385 int x, y;
2386
2387 x = stop->cur.geometry.x - dx;
2388 y = stop->cur.geometry.y - dy;
2389
2390 EINA_INLIST_FOREACH(e->layers, lay)
2391 {
2392 Evas_Object *obj;
2393 EINA_INLIST_FOREACH(lay->objects, obj)
2394 {
2395 if (obj->delete_me) continue;
2396 if (obj == stop) return;
2397 /* FIXME: Do bounding box check */
2398 image_filter_draw_under_recurse(e, obj, stop, output, ctx,
2399 surface, -x, -y);
2400 }
2401 }
2402 e->engine.func->image_dirty_region(output, surface, 0, 0, 300, 300);
2403 e->engine.func->output_flush(output);
2404}
2405
2406/*
2407 * Update the filtered object.
2408 *
2409 * Creates a new context, and renders stuff (filtered) onto that.
2410 */
2411Filtered_Image *
2412image_filter_update(Evas *e, Evas_Object *obj, void *src, int imagew, int imageh, int *outw, int *outh)
2413{
2414 int w, h;
2415 void *ctx;
2416 Evas_Filter_Info *info;
2417 void *surface;
2418 Eina_Bool alpha;
2419
2420 info = obj->filter;
2421
2422 if (info->mode == EVAS_FILTER_MODE_BELOW)
2423 {
2424 w = obj->cur.geometry.w;
2425 h = obj->cur.geometry.h;
2426 evas_filter_get_size(info, w, h, &imagew, &imageh, EINA_TRUE);
2427 alpha = EINA_FALSE;
2428 }
2429 else
2430 {
2431 evas_filter_get_size(info, imagew, imageh, &w, &h, EINA_FALSE);
2432 alpha = e->engine.func->image_alpha_get(e->engine.data.output, src);
2433 }
2434
2435 /* Certain filters may make alpha images anyway */
2436 if (alpha == EINA_FALSE) alpha = evas_filter_always_alpha(info);
2437
2438 surface = e->engine.func->image_map_surface_new(e->engine.data.output, w, h,
2439 alpha);
2440
2441 if (info->mode == EVAS_FILTER_MODE_BELOW)
2442 {
2443 void *subsurface;
2444 int disw, dish;
2445 int dx, dy;
2446 disw = obj->cur.geometry.w;
2447 dish = obj->cur.geometry.h;
2448 dx = (imagew - w) >> 1;
2449 dy = (imageh - h) >> 1;
2450 subsurface = e->engine.func->image_map_surface_new
2451 (e->engine.data.output, imagew, imageh, 1);
2452 ctx = e->engine.func->context_new(e->engine.data.output);
2453 e->engine.func->context_color_set(e->engine.data.output, ctx, 0, 255, 0, 255);
2454 e->engine.func->context_render_op_set(e->engine.data.output, ctx, EVAS_RENDER_COPY);
2455 e->engine.func->rectangle_draw(e->engine.data.output, ctx,
2456 subsurface, 0, 0, imagew, imageh);
2457
2458 image_filter_draw_under(e, obj, e->engine.data.output, ctx,
2459 subsurface, dx, dy);
2460
2461 e->engine.func->context_free(e->engine.data.output, ctx);
2462
2463 ctx = e->engine.func->context_new(e->engine.data.output);
2464
2465 e->engine.func->image_draw_filtered(e->engine.data.output,
2466 ctx, surface, subsurface, info);
2467
2468 e->engine.func->context_free(e->engine.data.output, ctx);
2469
2470 e->engine.func->image_map_surface_free(e->engine.data.output,
2471 subsurface);
2472 }
2473 else
2474 {
2475 ctx = e->engine.func->context_new(e->engine.data.output);
2476 e->engine.func->image_draw_filtered(e->engine.data.output,
2477 ctx, surface, src, info);
2478 e->engine.func->context_free(e->engine.data.output, ctx);
2479 }
2480
2481 e->engine.func->image_dirty_region(e->engine.data.output, surface,
2482 0, 0, w, h);
2483 if (outw) *outw = w;
2484 if (outh) *outh = h;
2485 return e->engine.func->image_filtered_save(src, surface,
2486 obj->filter->key,
2487 obj->filter->len);
2488}
2489#endif
2490
2491static void
2492evas_object_image_unload(Evas_Object *obj, Eina_Bool dirty)
2493{
2494 Evas_Object_Image *o;
2495
2496 o = (Evas_Object_Image *)(obj->object_data);
2497
2498 if ((!o->cur.file) ||
2499 (o->pixels_checked_out > 0)) return;
2500 if (dirty)
2501 {
2502 if (o->engine_data)
2503 o->engine_data = obj->layer->evas->engine.func->image_dirty_region
2504 (obj->layer->evas->engine.data.output,
2505 o->engine_data,
2506 0, 0,
2507 o->cur.image.w, o->cur.image.h);
2508 }
2509 if (o->engine_data)
2510 {
2511 if (o->preloading)
2512 {
2513 o->preloading = 0;
2514 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
2515 o->engine_data,
2516 obj);
2517 }
2518 obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output,
2519 o->engine_data);
2520 }
2521 o->engine_data = NULL;
2522 o->load_error = EVAS_LOAD_ERROR_NONE;
2523 o->cur.has_alpha = 1;
2524 o->cur.cspace = EVAS_COLORSPACE_ARGB8888;
2525 o->cur.image.w = 0;
2526 o->cur.image.h = 0;
2527 o->cur.image.stride = 0;
2528}
2529
2530static void
2531evas_object_image_load(Evas_Object *obj)
2532{
2533 Evas_Object_Image *o;
2534 Evas_Image_Load_Opts lo;
2535
2536 o = (Evas_Object_Image *)(obj->object_data);
2537 if (o->engine_data) return;
2538
2539 lo.scale_down_by = o->load_opts.scale_down_by;
2540 lo.dpi = o->load_opts.dpi;
2541 lo.w = o->load_opts.w;
2542 lo.h = o->load_opts.h;
2543 lo.region.x = o->load_opts.region.x;
2544 lo.region.y = o->load_opts.region.y;
2545 lo.region.w = o->load_opts.region.w;
2546 lo.region.h = o->load_opts.region.h;
2547 lo.orientation = o->load_opts.orientation;
2548 o->engine_data = obj->layer->evas->engine.func->image_load
2549 (obj->layer->evas->engine.data.output,
2550 o->cur.file,
2551 o->cur.key,
2552 &o->load_error,
2553 &lo);
2554 if (o->engine_data)
2555 {
2556 int w, h;
2557 int stride = 0;
2558
2559 obj->layer->evas->engine.func->image_size_get
2560 (obj->layer->evas->engine.data.output,
2561 o->engine_data, &w, &h);
2562 if (obj->layer->evas->engine.func->image_stride_get)
2563 obj->layer->evas->engine.func->image_stride_get
2564 (obj->layer->evas->engine.data.output,
2565 o->engine_data, &stride);
2566 else
2567 stride = w * 4;
2568 o->cur.has_alpha = obj->layer->evas->engine.func->image_alpha_get
2569 (obj->layer->evas->engine.data.output,
2570 o->engine_data);
2571 o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get
2572 (obj->layer->evas->engine.data.output,
2573 o->engine_data);
2574 o->cur.image.w = w;
2575 o->cur.image.h = h;
2576 o->cur.image.stride = stride;
2577 }
2578 else
2579 {
2580 o->load_error = EVAS_LOAD_ERROR_GENERIC;
2581 }
2582}
2583
2584static Evas_Coord
2585evas_object_image_figure_x_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
2586{
2587 Evas_Coord w;
2588
2589 w = ((size * obj->layer->evas->output.w) /
2590 (Evas_Coord)obj->layer->evas->viewport.w);
2591 if (size <= 0) size = 1;
2592 if (start > 0)
2593 {
2594 while (start - size > 0) start -= size;
2595 }
2596 else if (start < 0)
2597 {
2598 while (start < 0) start += size;
2599 }
2600 start = ((start * obj->layer->evas->output.w) /
2601 (Evas_Coord)obj->layer->evas->viewport.w);
2602 *size_ret = w;
2603 return start;
2604}
2605
2606static Evas_Coord
2607evas_object_image_figure_y_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
2608{
2609 Evas_Coord h;
2610
2611 h = ((size * obj->layer->evas->output.h) /
2612 (Evas_Coord)obj->layer->evas->viewport.h);
2613 if (size <= 0) size = 1;
2614 if (start > 0)
2615 {
2616 while (start - size > 0) start -= size;
2617 }
2618 else if (start < 0)
2619 {
2620 while (start < 0) start += size;
2621 }
2622 start = ((start * obj->layer->evas->output.h) /
2623 (Evas_Coord)obj->layer->evas->viewport.h);
2624 *size_ret = h;
2625 return start;
2626}
2627
2628static void
2629evas_object_image_init(Evas_Object *obj)
2630{
2631 /* alloc image ob, setup methods and default values */
2632 obj->object_data = evas_object_image_new();
2633 /* set up default settings for this kind of object */
2634 obj->cur.color.r = 255;
2635 obj->cur.color.g = 255;
2636 obj->cur.color.b = 255;
2637 obj->cur.color.a = 255;
2638 obj->cur.geometry.x = 0;
2639 obj->cur.geometry.y = 0;
2640 obj->cur.geometry.w = 0;
2641 obj->cur.geometry.h = 0;
2642 obj->cur.layer = 0;
2643 obj->cur.anti_alias = 0;
2644 obj->cur.render_op = EVAS_RENDER_BLEND;
2645 /* set up object-specific settings */
2646 obj->prev = obj->cur;
2647 /* set up methods (compulsory) */
2648 obj->func = &object_func;
2649 obj->type = o_type;
2650}
2651
2652static void *
2653evas_object_image_new(void)
2654{
2655 Evas_Object_Image *o;
2656
2657 /* alloc obj private data */
2658 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_image", Evas_Object_Image, 256, NULL);
2659 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Image);
2660 if (!o) return NULL;
2661 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Image);
2662 o->magic = MAGIC_OBJ_IMAGE;
2663 o->cur.fill.w = 0;
2664 o->cur.fill.h = 0;
2665 o->cur.smooth_scale = 1;
2666 o->cur.border.fill = 1;
2667 o->cur.border.scale = 1.0;
2668 o->cur.cspace = EVAS_COLORSPACE_ARGB8888;
2669 o->cur.spread = EVAS_TEXTURE_REPEAT;
2670 o->cur.opaque_valid = 0;
2671 o->cur.source = NULL;
2672 o->prev = o->cur;
2673 o->tmpf_fd = -1;
2674 return o;
2675}
2676
2677static void
2678evas_object_image_free(Evas_Object *obj)
2679{
2680 Evas_Object_Image *o;
2681 Eina_Rectangle *r;
2682
2683 /* frees private object data. very simple here */
2684 o = (Evas_Object_Image *)(obj->object_data);
2685 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
2686 return;
2687 MAGIC_CHECK_END();
2688 /* free obj */
2689 _cleanup_tmpf(obj);
2690 if (o->cur.file) eina_stringshare_del(o->cur.file);
2691 if (o->cur.key) eina_stringshare_del(o->cur.key);
2692 if (o->cur.source) _proxy_unset(obj);
2693 if (o->engine_data)
2694 {
2695 if (o->preloading)
2696 {
2697 o->preloading = 0;
2698 obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output,
2699 o->engine_data,
2700 obj);
2701 }
2702 obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output,
2703 o->engine_data);
2704 }
2705 if (o->video_surface)
2706 {
2707 o->video_surface = 0;
2708 obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, obj);
2709 }
2710 o->engine_data = NULL;
2711 o->magic = 0;
2712 EINA_LIST_FREE(o->pixel_updates, r)
2713 eina_rectangle_free(r);
2714 EVAS_MEMPOOL_FREE(_mp_obj, o);
2715}
2716
2717static void
2718evas_object_image_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
2719{
2720 Evas_Object_Image *o;
2721 int imagew, imageh, uvw, uvh;
2722 void *pixels;
2723
2724 /* render object to surface with context, and offset by x,y */
2725 o = (Evas_Object_Image *)(obj->object_data);
2726
2727 if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1))
2728 return; /* no error message, already printed in pre_render */
2729
2730 /* Proxy sanity */
2731 if (o->proxyrendering)
2732 {
2733 _proxy_error(obj, context, output, surface, x, y);
2734 return;
2735 }
2736
2737 /* We are displaying the overlay */
2738 if (o->video_visible)
2739 {
2740 /* Create a transparent rectangle */
2741 obj->layer->evas->engine.func->context_color_set(output,
2742 context,
2743 0, 0, 0, 0);
2744 obj->layer->evas->engine.func->context_multiplier_unset(output,
2745 context);
2746 obj->layer->evas->engine.func->context_render_op_set(output, context,
2747 EVAS_RENDER_COPY);
2748 obj->layer->evas->engine.func->rectangle_draw(output,
2749 context,
2750 surface,
2751 obj->cur.geometry.x + x,
2752 obj->cur.geometry.y + y,
2753 obj->cur.geometry.w,
2754 obj->cur.geometry.h);
2755
2756 return ;
2757 }
2758
2759 obj->layer->evas->engine.func->context_color_set(output,
2760 context,
2761 255, 255, 255, 255);
2762
2763 if ((obj->cur.cache.clip.r == 255) &&
2764 (obj->cur.cache.clip.g == 255) &&
2765 (obj->cur.cache.clip.b == 255) &&
2766 (obj->cur.cache.clip.a == 255))
2767 {
2768 obj->layer->evas->engine.func->context_multiplier_unset(output,
2769 context);
2770 }
2771 else
2772 obj->layer->evas->engine.func->context_multiplier_set(output,
2773 context,
2774 obj->cur.cache.clip.r,
2775 obj->cur.cache.clip.g,
2776 obj->cur.cache.clip.b,
2777 obj->cur.cache.clip.a);
2778
2779 obj->layer->evas->engine.func->context_render_op_set(output, context,
2780 obj->cur.render_op);
2781
2782 if (!o->cur.source)
2783 {
2784 pixels = o->engine_data;
2785 imagew = o->cur.image.w;
2786 imageh = o->cur.image.h;
2787 uvw = imagew;
2788 uvh = imageh;
2789 }
2790 else if (o->cur.source->proxy.surface && !o->cur.source->proxy.redraw)
2791 {
2792 pixels = o->cur.source->proxy.surface;
2793 imagew = o->cur.source->proxy.w;
2794 imageh = o->cur.source->proxy.h;
2795 uvw = imagew;
2796 uvh = imageh;
2797 }
2798 else if (o->cur.source->type == o_type &&
2799 ((Evas_Object_Image *)o->cur.source->object_data)->engine_data)
2800 {
2801 Evas_Object_Image *oi;
2802 oi = o->cur.source->object_data;
2803 pixels = oi->engine_data;
2804 imagew = oi->cur.image.w;
2805 imageh = oi->cur.image.h;
2806 uvw = o->cur.source->cur.geometry.w;
2807 uvh = o->cur.source->cur.geometry.h;
2808 }
2809 else
2810 {
2811 o->proxyrendering = 1;
2812 _proxy_subrender(obj->layer->evas, o->cur.source);
2813 pixels = o->cur.source->proxy.surface;
2814 imagew = o->cur.source->proxy.w;
2815 imageh = o->cur.source->proxy.h;
2816 uvw = imagew;
2817 uvh = imageh;
2818 o->proxyrendering = 0;
2819 }
2820
2821#if 0 // filtering disabled
2822 /* Now check/update filter */
2823 if (obj->filter && obj->filter->filter)
2824 {
2825 Filtered_Image *fi = NULL;
2826 //printf("%p has filter: %s\n", obj,obj->filter->dirty?"dirty":"clean");
2827 if (obj->filter->dirty)
2828 {
2829 if (obj->filter->mode != EVAS_FILTER_MODE_BELOW)
2830 {
2831 uint32_t len;
2832 uint8_t *key;
2833
2834 if (obj->filter->key) free(obj->filter->key);
2835 obj->filter->key = NULL;
2836 obj->filter->len = 0;
2837 key = evas_filter_key_get(obj->filter, &len);
2838 if (key)
2839 {
2840 obj->filter->key = key;
2841 obj->filter->len = len;
2842 fi = obj->layer->evas->engine.func->image_filtered_get
2843 (o->engine_data, key, len);
2844 if (obj->filter->cached && fi != obj->filter->cached)
2845 {
2846 obj->layer->evas->engine.func->image_filtered_free
2847 (o->engine_data, obj->filter->cached);
2848 obj->filter->cached = NULL;
2849 }
2850 }
2851 }
2852 else if (obj->filter->cached)
2853 {
2854 obj->layer->evas->engine.func->image_filtered_free
2855 (o->engine_data, obj->filter->cached);
2856 }
2857 if (!fi)
2858 fi = image_filter_update(obj->layer->evas, obj, pixels,
2859 imagew, imageh, &imagew, &imageh);
2860 pixels = fi->image;
2861 obj->filter->dirty = 0;
2862 obj->filter->cached = fi;
2863 }
2864 else
2865 {
2866 fi = obj->filter->cached;
2867 pixels = fi->image;
2868 }
2869 }
2870#endif
2871
2872 if (pixels)
2873 {
2874 Evas_Coord idw, idh, idx, idy;
2875 int ix, iy, iw, ih;
2876
2877 if (o->dirty_pixels)
2878 {
2879 if (o->func.get_pixels)
2880 {
2881 o->func.get_pixels(o->func.get_pixels_data, obj);
2882 if (o->engine_data != pixels)
2883 pixels = o->engine_data;
2884 o->engine_data = obj->layer->evas->engine.func->image_dirty_region
2885 (obj->layer->evas->engine.data.output, o->engine_data,
2886 0, 0, o->cur.image.w, o->cur.image.h);
2887 }
2888 o->dirty_pixels = 0;
2889 }
2890 if ((obj->cur.map) && (obj->cur.map->count > 3) && (obj->cur.usemap))
2891 {
2892 const Evas_Map_Point *p, *p_end;
2893 RGBA_Map_Point pts[obj->cur.map->count], *pt;
2894
2895 p = obj->cur.map->points;
2896 p_end = p + obj->cur.map->count;
2897 pt = pts;
2898
2899 pts[0].px = obj->cur.map->persp.px << FP;
2900 pts[0].py = obj->cur.map->persp.py << FP;
2901 pts[0].foc = obj->cur.map->persp.foc << FP;
2902 pts[0].z0 = obj->cur.map->persp.z0 << FP;
2903 // draw geom +x +y
2904 for (; p < p_end; p++, pt++)
2905 {
2906 pt->x = (lround(p->x) + x) * FP1;
2907 pt->y = (lround(p->y) + y) * FP1;
2908 pt->z = (lround(p->z) ) * FP1;
2909 pt->fx = p->px;
2910 pt->fy = p->py;
2911 pt->fz = p->z;
2912 pt->u = ((lround(p->u) * imagew) / uvw) * FP1;
2913 pt->v = ((lround(p->v) * imageh) / uvh) * FP1;
2914 if (pt->u < 0) pt->u = 0;
2915 else if (pt->u > (imagew * FP1)) pt->u = (imagew * FP1);
2916 if (pt->v < 0) pt->v = 0;
2917 else if (pt->v > (imageh * FP1)) pt->v = (imageh * FP1);
2918 pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b);
2919 }
2920 if (obj->cur.map->count & 0x1)
2921 {
2922 pts[obj->cur.map->count] = pts[obj->cur.map->count -1];
2923 }
2924
2925 obj->layer->evas->engine.func->image_map_draw
2926 (output, context, surface, pixels, obj->cur.map->count,
2927 pts, o->cur.smooth_scale | obj->cur.map->smooth, 0);
2928 }
2929 else
2930 {
2931 obj->layer->evas->engine.func->image_scale_hint_set(output,
2932 pixels,
2933 o->scale_hint);
2934 /* This is technically a bug here: If the value is recreated
2935 * (which is returned)it may be a new object, however exactly 0
2936 * of all the evas engines do this. */
2937 obj->layer->evas->engine.func->image_border_set(output, pixels,
2938 o->cur.border.l, o->cur.border.r,
2939 o->cur.border.t, o->cur.border.b);
2940 idx = evas_object_image_figure_x_fill(obj, o->cur.fill.x, o->cur.fill.w, &idw);
2941 idy = evas_object_image_figure_y_fill(obj, o->cur.fill.y, o->cur.fill.h, &idh);
2942 if (idw < 1) idw = 1;
2943 if (idh < 1) idh = 1;
2944 if (idx > 0) idx -= idw;
2945 if (idy > 0) idy -= idh;
2946 while ((int)idx < obj->cur.geometry.w)
2947 {
2948 Evas_Coord ydy;
2949 int dobreak_w = 0;
2950
2951 ydy = idy;
2952 ix = idx;
2953 if ((o->cur.fill.w == obj->cur.geometry.w) &&
2954 (o->cur.fill.x == 0))
2955 {
2956 dobreak_w = 1;
2957 iw = obj->cur.geometry.w;
2958 }
2959 else
2960 iw = ((int)(idx + idw)) - ix;
2961 while ((int)idy < obj->cur.geometry.h)
2962 {
2963 int dobreak_h = 0;
2964
2965 iy = idy;
2966 if ((o->cur.fill.h == obj->cur.geometry.h) &&
2967 (o->cur.fill.y == 0))
2968 {
2969 ih = obj->cur.geometry.h;
2970 dobreak_h = 1;
2971 }
2972 else
2973 ih = ((int)(idy + idh)) - iy;
2974 if ((o->cur.border.l == 0) &&
2975 (o->cur.border.r == 0) &&
2976 (o->cur.border.t == 0) &&
2977 (o->cur.border.b == 0) &&
2978 (o->cur.border.fill != 0))
2979 obj->layer->evas->engine.func->image_draw(output,
2980 context,
2981 surface,
2982 pixels,
2983 0, 0,
2984 imagew,
2985 imageh,
2986 obj->cur.geometry.x + ix + x,
2987 obj->cur.geometry.y + iy + y,
2988 iw, ih,
2989 o->cur.smooth_scale);
2990 else
2991 {
2992 int inx, iny, inw, inh, outx, outy, outw, outh;
2993 int bl, br, bt, bb, bsl, bsr, bst, bsb;
2994 int imw, imh, ox, oy;
2995
2996 ox = obj->cur.geometry.x + ix + x;
2997 oy = obj->cur.geometry.y + iy + y;
2998 imw = imagew;
2999 imh = imageh;
3000 bl = o->cur.border.l;
3001 br = o->cur.border.r;
3002 bt = o->cur.border.t;
3003 bb = o->cur.border.b;
3004 if ((bl + br) > iw)
3005 {
3006 bl = iw / 2;
3007 br = iw - bl;
3008 }
3009 if ((bl + br) > imw)
3010 {
3011 bl = imw / 2;
3012 br = imw - bl;
3013 }
3014 if ((bt + bb) > ih)
3015 {
3016 bt = ih / 2;
3017 bb = ih - bt;
3018 }
3019 if ((bt + bb) > imh)
3020 {
3021 bt = imh / 2;
3022 bb = imh - bt;
3023 }
3024 if (o->cur.border.scale != 1.0)
3025 {
3026 bsl = ((double)bl * o->cur.border.scale);
3027 bsr = ((double)br * o->cur.border.scale);
3028 bst = ((double)bt * o->cur.border.scale);
3029 bsb = ((double)bb * o->cur.border.scale);
3030 }
3031 else
3032 {
3033 bsl = bl; bsr = br; bst = bt; bsb = bb;
3034 }
3035 // #--
3036 // |
3037 inx = 0; iny = 0;
3038 inw = bl; inh = bt;
3039 outx = ox; outy = oy;
3040 outw = bsl; outh = bst;
3041 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3042 // .##
3043 // |
3044 inx = bl; iny = 0;
3045 inw = imw - bl - br; inh = bt;
3046 outx = ox + bsl; outy = oy;
3047 outw = iw - bsl - bsr; outh = bst;
3048 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3049 // --#
3050 // |
3051 inx = imw - br; iny = 0;
3052 inw = br; inh = bt;
3053 outx = ox + iw - bsr; outy = oy;
3054 outw = bsr; outh = bst;
3055 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3056 // .--
3057 // #
3058 inx = 0; iny = bt;
3059 inw = bl; inh = imh - bt - bb;
3060 outx = ox; outy = oy + bst;
3061 outw = bsl; outh = ih - bst - bsb;
3062 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3063 // .--.
3064 // |##|
3065 if (o->cur.border.fill > EVAS_BORDER_FILL_NONE)
3066 {
3067 inx = bl; iny = bt;
3068 inw = imw - bl - br; inh = imh - bt - bb;
3069 outx = ox + bsl; outy = oy + bst;
3070 outw = iw - bsl - bsr; outh = ih - bst - bsb;
3071 if ((o->cur.border.fill == EVAS_BORDER_FILL_SOLID) &&
3072 (obj->cur.cache.clip.a == 255) &&
3073 (obj->cur.render_op == EVAS_RENDER_BLEND))
3074 {
3075 obj->layer->evas->engine.func->context_render_op_set(output, context,
3076 EVAS_RENDER_COPY);
3077 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3078 obj->layer->evas->engine.func->context_render_op_set(output, context,
3079 obj->cur.render_op);
3080 }
3081 else
3082 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3083 }
3084 // --.
3085 // #
3086 inx = imw - br; iny = bt;
3087 inw = br; inh = imh - bt - bb;
3088 outx = ox + iw - bsr; outy = oy + bst;
3089 outw = bsr; outh = ih - bst - bsb;
3090 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3091 // |
3092 // #--
3093 inx = 0; iny = imh - bb;
3094 inw = bl; inh = bb;
3095 outx = ox; outy = oy + ih - bsb;
3096 outw = bsl; outh = bsb;
3097 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3098 // |
3099 // .##
3100 inx = bl; iny = imh - bb;
3101 inw = imw - bl - br; inh = bb;
3102 outx = ox + bsl; outy = oy + ih - bsb;
3103 outw = iw - bsl - bsr; outh = bsb;
3104 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3105 // |
3106 // --#
3107 inx = imw - br; iny = imh - bb;
3108 inw = br; inh = bb;
3109 outx = ox + iw - bsr; outy = oy + ih - bsb;
3110 outw = bsr; outh = bsb;
3111 obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale);
3112 }
3113 idy += idh;
3114 if (dobreak_h) break;
3115 }
3116 idx += idw;
3117 idy = ydy;
3118 if (dobreak_w) break;
3119 }
3120 }
3121 }
3122}
3123
3124static void
3125evas_object_image_render_pre(Evas_Object *obj)
3126{
3127 Evas_Object_Image *o;
3128 int is_v = 0, was_v = 0;
3129 Evas *e;
3130
3131 /* dont pre-render the obj twice! */
3132 if (obj->pre_render_done) return;
3133 obj->pre_render_done = 1;
3134 /* pre-render phase. this does anything an object needs to do just before */
3135 /* rendering. this could mean loading the image data, retrieving it from */
3136 /* elsewhere, decoding video etc. */
3137 /* then when this is done the object needs to figure if it changed and */
3138 /* if so what and where and add the appropriate redraw rectangles */
3139 o = (Evas_Object_Image *)(obj->object_data);
3140 e = obj->layer->evas;
3141
3142 if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1))
3143 {
3144 ERR("%p has invalid fill size: %dx%d. Ignored",
3145 obj, o->cur.fill.w, o->cur.fill.h);
3146 return;
3147 }
3148
3149 /* if someone is clipping this obj - go calculate the clipper */
3150 if (obj->cur.clipper)
3151 {
3152 if (obj->cur.cache.clip.dirty)
3153 evas_object_clip_recalc(obj->cur.clipper);
3154 obj->cur.clipper->func->render_pre(obj->cur.clipper);
3155 }
3156 /* Proxy: Do it early */
3157 if (o->cur.source &&
3158 (o->cur.source->proxy.redraw || o->cur.source->changed))
3159 {
3160 /* XXX: Do I need to sort out the map here? */
3161 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3162 goto done;
3163 }
3164
3165 /* now figure what changed and add draw rects */
3166 /* if it just became visible or invisible */
3167 is_v = evas_object_is_visible(obj);
3168 was_v = evas_object_was_visible(obj);
3169 if (is_v != was_v)
3170 {
3171 evas_object_render_pre_visible_change(&e->clip_changes, obj, is_v, was_v);
3172 if (!o->pixel_updates) goto done;
3173 }
3174 if ((obj->cur.map != obj->prev.map) ||
3175 (obj->cur.usemap != obj->prev.usemap))
3176 {
3177 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3178 goto done;
3179 }
3180 /* it's not visible - we accounted for it appearing or not so just abort */
3181 if (!is_v) goto done;
3182 /* clipper changed this is in addition to anything else for obj */
3183 evas_object_render_pre_clipper_change(&e->clip_changes, obj);
3184 /* if we restacked (layer or just within a layer) and don't clip anyone */
3185 if (obj->restack)
3186 {
3187 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3188 if (!o->pixel_updates) goto done;
3189 }
3190 /* if it changed color */
3191 if ((obj->cur.color.r != obj->prev.color.r) ||
3192 (obj->cur.color.g != obj->prev.color.g) ||
3193 (obj->cur.color.b != obj->prev.color.b) ||
3194 (obj->cur.color.a != obj->prev.color.a))
3195 {
3196 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3197 if (!o->pixel_updates) goto done;
3198 }
3199 /* if it changed render op */
3200 if (obj->cur.render_op != obj->prev.render_op)
3201 {
3202 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3203 if (!o->pixel_updates) goto done;
3204 }
3205 /* if it changed anti_alias */
3206 if (obj->cur.anti_alias != obj->prev.anti_alias)
3207 {
3208 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3209 if (!o->pixel_updates) goto done;
3210 }
3211 if (o->changed)
3212 {
3213 if (((o->cur.file) && (!o->prev.file)) ||
3214 ((!o->cur.file) && (o->prev.file)) ||
3215 ((o->cur.key) && (!o->prev.key)) ||
3216 ((!o->cur.key) && (o->prev.key))
3217 )
3218 {
3219 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3220 if (!o->pixel_updates) goto done;
3221 }
3222 if ((o->cur.image.w != o->prev.image.w) ||
3223 (o->cur.image.h != o->prev.image.h) ||
3224 (o->cur.has_alpha != o->prev.has_alpha) ||
3225 (o->cur.cspace != o->prev.cspace) ||
3226 (o->cur.smooth_scale != o->prev.smooth_scale))
3227 {
3228 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3229 if (!o->pixel_updates) goto done;
3230 }
3231 if ((o->cur.border.l != o->prev.border.l) ||
3232 (o->cur.border.r != o->prev.border.r) ||
3233 (o->cur.border.t != o->prev.border.t) ||
3234 (o->cur.border.b != o->prev.border.b) ||
3235 (o->cur.border.fill != o->prev.border.fill) ||
3236 (o->cur.border.scale != o->prev.border.scale))
3237 {
3238 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3239 if (!o->pixel_updates) goto done;
3240 }
3241 if (o->dirty_pixels)
3242 {
3243 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3244 if (!o->pixel_updates) goto done;
3245 }
3246 if (o->cur.frame != o->prev.frame)
3247 {
3248 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3249 if (!o->pixel_updates) goto done;
3250 }
3251
3252 }
3253 /* if it changed geometry - and obviously not visibility or color */
3254 /* calculate differences since we have a constant color fill */
3255 /* we really only need to update the differences */
3256#if 0 // XXX: maybe buggy?
3257 if (((obj->cur.geometry.x != obj->prev.geometry.x) ||
3258 (obj->cur.geometry.y != obj->prev.geometry.y) ||
3259 (obj->cur.geometry.w != obj->prev.geometry.w) ||
3260 (obj->cur.geometry.h != obj->prev.geometry.h)) &&
3261 (o->cur.fill.w == o->prev.fill.w) &&
3262 (o->cur.fill.h == o->prev.fill.h) &&
3263 ((o->cur.fill.x + obj->cur.geometry.x) == (o->prev.fill.x + obj->prev.geometry.x)) &&
3264 ((o->cur.fill.y + obj->cur.geometry.y) == (o->prev.fill.y + obj->prev.geometry.y)) &&
3265 (!o->pixel_updates)
3266 )
3267 {
3268 evas_rects_return_difference_rects(&e->clip_changes,
3269 obj->cur.geometry.x,
3270 obj->cur.geometry.y,
3271 obj->cur.geometry.w,
3272 obj->cur.geometry.h,
3273 obj->prev.geometry.x,
3274 obj->prev.geometry.y,
3275 obj->prev.geometry.w,
3276 obj->prev.geometry.h);
3277 if (!o->pixel_updates) goto done;
3278 }
3279#endif
3280 if (((obj->cur.geometry.x != obj->prev.geometry.x) ||
3281 (obj->cur.geometry.y != obj->prev.geometry.y) ||
3282 (obj->cur.geometry.w != obj->prev.geometry.w) ||
3283 (obj->cur.geometry.h != obj->prev.geometry.h))
3284 )
3285 {
3286 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3287 if (!o->pixel_updates) goto done;
3288 }
3289 if (o->changed)
3290 {
3291 if ((o->cur.fill.x != o->prev.fill.x) ||
3292 (o->cur.fill.y != o->prev.fill.y) ||
3293 (o->cur.fill.w != o->prev.fill.w) ||
3294 (o->cur.fill.h != o->prev.fill.h))
3295 {
3296 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3297 if (!o->pixel_updates) goto done;
3298 }
3299 if (o->pixel_updates)
3300 {
3301 if ((o->cur.border.l == 0) &&
3302 (o->cur.border.r == 0) &&
3303 (o->cur.border.t == 0) &&
3304 (o->cur.border.b == 0) &&
3305 (o->cur.image.w > 0) &&
3306 (o->cur.image.h > 0) &&
3307 (!((obj->cur.map) && (obj->cur.usemap))))
3308 {
3309 Eina_Rectangle *rr;
3310
3311 EINA_LIST_FREE(o->pixel_updates, rr)
3312 {
3313 Evas_Coord idw, idh, idx, idy;
3314 int x, y, w, h;
3315
3316 e->engine.func->image_dirty_region(e->engine.data.output, o->engine_data, rr->x, rr->y, rr->w, rr->h);
3317
3318 idx = evas_object_image_figure_x_fill(obj, o->cur.fill.x, o->cur.fill.w, &idw);
3319 idy = evas_object_image_figure_y_fill(obj, o->cur.fill.y, o->cur.fill.h, &idh);
3320
3321 if (idw < 1) idw = 1;
3322 if (idh < 1) idh = 1;
3323 if (idx > 0) idx -= idw;
3324 if (idy > 0) idy -= idh;
3325 while (idx < obj->cur.geometry.w)
3326 {
3327 Evas_Coord ydy;
3328
3329 ydy = idy;
3330 x = idx;
3331 w = ((int)(idx + idw)) - x;
3332 while (idy < obj->cur.geometry.h)
3333 {
3334 Eina_Rectangle r;
3335
3336 y = idy;
3337 h = ((int)(idy + idh)) - y;
3338
3339 r.x = ((rr->x - 1) * w) / o->cur.image.w;
3340 r.y = ((rr->y - 1) * h) / o->cur.image.h;
3341 r.w = ((rr->w + 2) * w) / o->cur.image.w;
3342 r.h = ((rr->h + 2) * h) / o->cur.image.h;
3343 r.x += obj->cur.geometry.x + x;
3344 r.y += obj->cur.geometry.y + y;
3345 RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h,
3346 obj->cur.cache.clip.x, obj->cur.cache.clip.y,
3347 obj->cur.cache.clip.w, obj->cur.cache.clip.h);
3348 evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h);
3349 idy += h;
3350 }
3351 idx += idw;
3352 idy = ydy;
3353 }
3354 eina_rectangle_free(rr);
3355 }
3356 goto done;
3357 }
3358 else
3359 {
3360 Eina_Rectangle *r;
3361
3362 EINA_LIST_FREE(o->pixel_updates, r)
3363 eina_rectangle_free(r);
3364 e->engine.func->image_dirty_region(e->engine.data.output, o->engine_data, 0, 0, o->cur.image.w, o->cur.image.h);
3365 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3366 goto done;
3367 }
3368 }
3369 }
3370#if 0 // filtering disabled
3371 if (obj->filter && obj->filter->dirty)
3372 {
3373 evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
3374 }
3375#endif
3376 /* it obviously didn't change - add a NO obscure - this "unupdates" this */
3377 /* area so if there were updates for it they get wiped. don't do it if we */
3378 /* aren't fully opaque and we are visible */
3379 if (evas_object_is_visible(obj) &&
3380 evas_object_is_opaque(obj))
3381 {
3382 Evas_Coord x, y, w, h;
3383
3384 x = obj->cur.cache.clip.x;
3385 y = obj->cur.cache.clip.y;
3386 w = obj->cur.cache.clip.w;
3387 h = obj->cur.cache.clip.h;
3388 if (obj->cur.clipper)
3389 {
3390 RECTS_CLIP_TO_RECT(x, y, w, h,
3391 obj->cur.clipper->cur.cache.clip.x,
3392 obj->cur.clipper->cur.cache.clip.y,
3393 obj->cur.clipper->cur.cache.clip.w,
3394 obj->cur.clipper->cur.cache.clip.h);
3395 }
3396 e->engine.func->output_redraws_rect_del(e->engine.data.output,
3397 x, y, w, h);
3398 }
3399 done:
3400 evas_object_render_pre_effect_updates(&e->clip_changes, obj, is_v, was_v);
3401}
3402
3403static void
3404evas_object_image_render_post(Evas_Object *obj)
3405{
3406 Evas_Object_Image *o;
3407 Eina_Rectangle *r;
3408
3409 /* this moves the current data to the previous state parts of the object */
3410 /* in whatever way is safest for the object. also if we don't need object */
3411 /* data anymore we can free it if the object deems this is a good idea */
3412 o = (Evas_Object_Image *)(obj->object_data);
3413 /* remove those pesky changes */
3414 evas_object_clip_changes_clean(obj);
3415 EINA_LIST_FREE(o->pixel_updates, r)
3416 eina_rectangle_free(r);
3417 /* move cur to prev safely for object data */
3418 obj->prev = obj->cur;
3419 o->prev = o->cur;
3420 o->changed = 0;
3421 /* FIXME: copy strings across */
3422}
3423
3424static unsigned int evas_object_image_id_get(Evas_Object *obj)
3425{
3426 Evas_Object_Image *o;
3427
3428 o = (Evas_Object_Image *)(obj->object_data);
3429 if (!o) return 0;
3430 return MAGIC_OBJ_IMAGE;
3431}
3432
3433static unsigned int evas_object_image_visual_id_get(Evas_Object *obj)
3434{
3435 Evas_Object_Image *o;
3436
3437 o = (Evas_Object_Image *)(obj->object_data);
3438 if (!o) return 0;
3439 return MAGIC_OBJ_IMAGE;
3440}
3441
3442static void *evas_object_image_engine_data_get(Evas_Object *obj)
3443{
3444 Evas_Object_Image *o;
3445
3446 o = (Evas_Object_Image *)(obj->object_data);
3447 if (!o) return NULL;
3448 return o->engine_data;
3449}
3450
3451static int
3452evas_object_image_is_opaque(Evas_Object *obj)
3453{
3454 Evas_Object_Image *o;
3455
3456 /* this returns 1 if the internal object data implies that the object is */
3457 /* currently fully opaque over the entire rectangle it occupies */
3458 o = (Evas_Object_Image *)(obj->object_data);
3459/* disable caching due tyo maps screwing with this
3460 o->cur.opaque_valid = 0;
3461 if (o->cur.opaque_valid)
3462 {
3463 if (!o->cur.opaque) return 0;
3464 }
3465 else
3466*/
3467 {
3468 o->cur.opaque = 0;
3469/* disable caching */
3470/* o->cur.opaque_valid = 1; */
3471 if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1))
3472 return o->cur.opaque;
3473 if (((o->cur.border.l != 0) ||
3474 (o->cur.border.r != 0) ||
3475 (o->cur.border.t != 0) ||
3476 (o->cur.border.b != 0)) &&
3477 (!o->cur.border.fill)) return o->cur.opaque;
3478 if (!o->engine_data) return o->cur.opaque;
3479 o->cur.opaque = 1;
3480 }
3481 // FIXME: use proxy
3482 if (o->cur.source)
3483 {
3484 o->cur.opaque = evas_object_is_opaque(o->cur.source);
3485 return o->cur.opaque; /* FIXME: Should go poke at the object */
3486 }
3487 if (o->cur.has_alpha)
3488 {
3489 o->cur.opaque = 0;
3490 return o->cur.opaque;
3491 }
3492 if ((obj->cur.map) && (obj->cur.usemap))
3493 {
3494 Evas_Map *m = obj->cur.map;
3495
3496 if ((m->points[0].a == 255) &&
3497 (m->points[1].a == 255) &&
3498 (m->points[2].a == 255) &&
3499 (m->points[3].a == 255))
3500 {
3501 if (
3502 ((m->points[0].x == m->points[3].x) &&
3503 (m->points[1].x == m->points[2].x) &&
3504 (m->points[0].y == m->points[1].y) &&
3505 (m->points[2].y == m->points[3].y))
3506 ||
3507 ((m->points[0].x == m->points[1].x) &&
3508 (m->points[2].x == m->points[3].x) &&
3509 (m->points[0].y == m->points[3].y) &&
3510 (m->points[1].y == m->points[2].y))
3511 )
3512 {
3513 if ((m->points[0].x == obj->cur.geometry.x) &&
3514 (m->points[0].y == obj->cur.geometry.y) &&
3515 (m->points[2].x == (obj->cur.geometry.x + obj->cur.geometry.w)) &&
3516 (m->points[2].y == (obj->cur.geometry.y + obj->cur.geometry.h)))
3517 return o->cur.opaque;
3518 }
3519 }
3520 o->cur.opaque = 0;
3521 return o->cur.opaque;
3522 }
3523 if (obj->cur.render_op == EVAS_RENDER_COPY) return o->cur.opaque;
3524 return o->cur.opaque;
3525}
3526
3527static int
3528evas_object_image_was_opaque(Evas_Object *obj)
3529{
3530 Evas_Object_Image *o;
3531
3532 /* this returns 1 if the internal object data implies that the object was */
3533 /* previously fully opaque over the entire rectangle it occupies */
3534 o = (Evas_Object_Image *)(obj->object_data);
3535 if (o->prev.opaque_valid)
3536 {
3537 if (!o->prev.opaque) return 0;
3538 }
3539 else
3540 {
3541 o->prev.opaque = 0;
3542 o->prev.opaque_valid = 1;
3543 if ((o->prev.fill.w < 1) || (o->prev.fill.h < 1))
3544 return 0;
3545 if (((o->prev.border.l != 0) ||
3546 (o->prev.border.r != 0) ||
3547 (o->prev.border.t != 0) ||
3548 (o->prev.border.b != 0)) &&
3549 (!o->prev.border.fill)) return 0;
3550 if (!o->engine_data) return 0;
3551 o->prev.opaque = 1;
3552 }
3553 // FIXME: use proxy
3554 if (o->prev.source) return 0; /* FIXME: Should go poke at the object */
3555 if (obj->prev.usemap) return 0;
3556 if (obj->prev.render_op == EVAS_RENDER_COPY) return 1;
3557 if (o->prev.has_alpha) return 0;
3558 if (obj->prev.render_op != EVAS_RENDER_BLEND) return 0;
3559 return 1;
3560}
3561
3562static int
3563evas_object_image_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
3564{
3565 Evas_Object_Image *o;
3566 DATA32 *data;
3567 int w, h, stride, iw, ih;
3568 int a;
3569
3570 o = (Evas_Object_Image *)(obj->object_data);
3571
3572 x -= obj->cur.cache.clip.x;
3573 y -= obj->cur.cache.clip.y;
3574 w = obj->cur.cache.clip.w;
3575 h = obj->cur.cache.clip.h;
3576 iw = o->cur.image.w;
3577 ih = o->cur.image.h;
3578
3579 if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return 0;
3580 if (!o->cur.has_alpha) return 1;
3581
3582 // FIXME: proxy needs to be honored
3583 if (obj->cur.map)
3584 {
3585 x = obj->cur.map->mx;
3586 y = obj->cur.map->my;
3587 }
3588 else
3589 {
3590 int bl, br, bt, bb, bsl, bsr, bst, bsb;
3591
3592 bl = o->cur.border.l;
3593 br = o->cur.border.r;
3594 bt = o->cur.border.t;
3595 bb = o->cur.border.b;
3596 if ((bl + br) > iw)
3597 {
3598 bl = iw / 2;
3599 br = iw - bl;
3600 }
3601 if ((bl + br) > iw)
3602 {
3603 bl = iw / 2;
3604 br = iw - bl;
3605 }
3606 if ((bt + bb) > ih)
3607 {
3608 bt = ih / 2;
3609 bb = ih - bt;
3610 }
3611 if ((bt + bb) > ih)
3612 {
3613 bt = ih / 2;
3614 bb = ih - bt;
3615 }
3616 if (o->cur.border.scale != 1.0)
3617 {
3618 bsl = ((double)bl * o->cur.border.scale);
3619 bsr = ((double)br * o->cur.border.scale);
3620 bst = ((double)bt * o->cur.border.scale);
3621 bsb = ((double)bb * o->cur.border.scale);
3622 }
3623 else
3624 {
3625 bsl = bl; bsr = br; bst = bt; bsb = bb;
3626 }
3627
3628 w = o->cur.fill.w;
3629 h = o->cur.fill.h;
3630 x -= o->cur.fill.x;
3631 y -= o->cur.fill.y;
3632 x %= w;
3633 y %= h;
3634
3635 if (x < 0) x += w;
3636 if (y < 0) y += h;
3637
3638 if (o->cur.border.fill != EVAS_BORDER_FILL_DEFAULT)
3639 {
3640 if ((x > bsl) && (x < (w - bsr)) &&
3641 (y > bst) && (y < (h - bsb)))
3642 {
3643 if (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) return 1;
3644 return 0;
3645 }
3646 }
3647
3648 if (x < bsl) x = (x * bl) / bsl;
3649 else if (x > (w - bsr)) x = iw - (((w - x) * br) / bsr);
3650 else if ((bsl + bsr) < w) x = bl + (((x - bsl) * (iw - bl - br)) / (w - bsl - bsr));
3651 else return 1;
3652
3653 if (y < bst) y = (y * bt) / bst;
3654 else if (y > (h - bsb)) y = ih - (((h - y) * bb) / bsb);
3655 else if ((bst + bsb) < h) y = bt + (((y - bst) * (ih - bt - bb)) / (h - bst - bsb));
3656 else return 1;
3657 }
3658
3659 if (x < 0) x = 0;
3660 if (y < 0) y = 0;
3661 if (x >= iw) x = iw - 1;
3662 if (y >= ih) y = ih - 1;
3663
3664 stride = o->cur.image.stride;
3665
3666 o->engine_data = obj->layer->evas->engine.func->image_data_get
3667 (obj->layer->evas->engine.data.output,
3668 o->engine_data,
3669 0,
3670 &data,
3671 &o->load_error);
3672 if (!data)
3673 return 0;
3674
3675 switch (o->cur.cspace)
3676 {
3677 case EVAS_COLORSPACE_ARGB8888:
3678 data = ((DATA32*)(data) + ((y * (stride >> 2)) + x));
3679 a = (*((DATA32*)(data)) >> 24) & 0xff;
3680 break;
3681 case EVAS_COLORSPACE_RGB565_A5P:
3682 data = (void*) ((DATA16*)(data) + (h * (stride >> 1)));
3683 data = (void*) ((DATA8*)(data) + ((y * (stride >> 1)) + x));
3684 a = (*((DATA8*)(data))) & 0x1f;
3685 break;
3686 default:
3687 return 1;
3688 break;
3689 }
3690
3691 return (a != 0);
3692}
3693
3694static int
3695evas_object_image_has_opaque_rect(Evas_Object *obj)
3696{
3697 Evas_Object_Image *o;
3698
3699 o = (Evas_Object_Image *)(obj->object_data);
3700 if ((obj->cur.map) && (obj->cur.usemap)) return 0;
3701 if (((o->cur.border.l | o->cur.border.r | o->cur.border.t | o->cur.border.b) != 0) &&
3702 (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) &&
3703 (obj->cur.render_op == EVAS_RENDER_BLEND) &&
3704 (obj->cur.cache.clip.a == 255) &&
3705 (o->cur.fill.x == 0) &&
3706 (o->cur.fill.y == 0) &&
3707 (o->cur.fill.w == obj->cur.geometry.w) &&
3708 (o->cur.fill.h == obj->cur.geometry.h)
3709 ) return 1;
3710 return 0;
3711}
3712
3713static int
3714evas_object_image_get_opaque_rect(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3715{
3716 Evas_Object_Image *o;
3717
3718 o = (Evas_Object_Image *)(obj->object_data);
3719 if (o->cur.border.scale == 1.0)
3720 {
3721 *x = obj->cur.geometry.x + o->cur.border.l;
3722 *y = obj->cur.geometry.y + o->cur.border.t;
3723 *w = obj->cur.geometry.w - (o->cur.border.l + o->cur.border.r);
3724 if (*w < 0) *w = 0;
3725 *h = obj->cur.geometry.h - (o->cur.border.t + o->cur.border.b);
3726 if (*h < 0) *h = 0;
3727 }
3728 else
3729 {
3730 *x = obj->cur.geometry.x + (o->cur.border.l * o->cur.border.scale);
3731 *y = obj->cur.geometry.y + (o->cur.border.t * o->cur.border.scale);
3732 *w = obj->cur.geometry.w - ((o->cur.border.l * o->cur.border.scale) + (o->cur.border.r * o->cur.border.scale));
3733 if (*w < 0) *w = 0;
3734 *h = obj->cur.geometry.h - ((o->cur.border.t * o->cur.border.scale) + (o->cur.border.b * o->cur.border.scale));
3735 if (*h < 0) *h = 0;
3736 }
3737 return 1;
3738}
3739
3740static int
3741evas_object_image_can_map(Evas_Object *obj __UNUSED__)
3742{
3743 return 1;
3744}
3745
3746static void *
3747evas_object_image_data_convert_internal(Evas_Object_Image *o, void *data, Evas_Colorspace to_cspace)
3748{
3749 void *out = NULL;
3750
3751 if (!data)
3752 return NULL;
3753
3754 switch (o->cur.cspace)
3755 {
3756 case EVAS_COLORSPACE_ARGB8888:
3757 out = evas_common_convert_argb8888_to(data,
3758 o->cur.image.w,
3759 o->cur.image.h,
3760 o->cur.image.stride >> 2,
3761 o->cur.has_alpha,
3762 to_cspace);
3763 break;
3764 case EVAS_COLORSPACE_RGB565_A5P:
3765 out = evas_common_convert_rgb565_a5p_to(data,
3766 o->cur.image.w,
3767 o->cur.image.h,
3768 o->cur.image.stride >> 1,
3769 o->cur.has_alpha,
3770 to_cspace);
3771 break;
3772 case EVAS_COLORSPACE_YCBCR422601_PL:
3773 fprintf(stderr, "EVAS_COLORSPACE_YCBCR422601_PL:\n");
3774 out = evas_common_convert_yuv_422_601_to(data,
3775 o->cur.image.w,
3776 o->cur.image.h,
3777 to_cspace);
3778 break;
3779 case EVAS_COLORSPACE_YCBCR422P601_PL:
3780 out = evas_common_convert_yuv_422P_601_to(data,
3781 o->cur.image.w,
3782 o->cur.image.h,
3783 to_cspace);
3784 break;
3785 case EVAS_COLORSPACE_YCBCR420NV12601_PL:
3786 out = evas_common_convert_yuv_420_601_to(data,
3787 o->cur.image.w,
3788 o->cur.image.h,
3789 to_cspace);
3790 break;
3791 case EVAS_COLORSPACE_YCBCR420TM12601_PL:
3792 out = evas_common_convert_yuv_420T_601_to(data,
3793 o->cur.image.w,
3794 o->cur.image.h,
3795 to_cspace);
3796 break;
3797 default:
3798 fprintf(stderr, "unknow colorspace: %i\n", o->cur.cspace);
3799 break;
3800 }
3801
3802 return out;
3803}
3804
3805static void
3806evas_object_image_filled_resize_listener(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *einfo __UNUSED__)
3807{
3808 Evas_Coord w, h;
3809 Evas_Object_Image *o;
3810
3811 o = obj->object_data;
3812 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
3813 evas_object_image_fill_set(obj, 0, 0, w, h);
3814}
3815
3816
3817Eina_Bool
3818_evas_object_image_preloading_get(const Evas_Object *obj)
3819{
3820 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3821 if (!o) return EINA_FALSE;
3822 MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
3823 return EINA_FALSE;
3824 MAGIC_CHECK_END();
3825 return o->preloading;
3826}
3827
3828void
3829_evas_object_image_preloading_set(Evas_Object *obj, Eina_Bool preloading)
3830{
3831 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3832 o->preloading = preloading;
3833}
3834
3835void
3836_evas_object_image_preloading_check(Evas_Object *obj)
3837{
3838 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3839 if (obj->layer->evas->engine.func->image_load_error_get)
3840 o->load_error = obj->layer->evas->engine.func->image_load_error_get
3841 (obj->layer->evas->engine.data.output, o->engine_data);
3842}
3843
3844Evas_Object *
3845_evas_object_image_video_parent_get(Evas_Object *obj)
3846{
3847 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3848
3849 return o->video_surface ? o->video.parent : NULL;
3850}
3851
3852void
3853_evas_object_image_video_overlay_show(Evas_Object *obj)
3854{
3855 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3856
3857 if (obj->cur.cache.clip.x != obj->prev.cache.clip.x ||
3858 obj->cur.cache.clip.y != obj->prev.cache.clip.y ||
3859 o->created || !o->video_visible)
3860 o->video.move(o->video.data, obj, &o->video, obj->cur.cache.clip.x, obj->cur.cache.clip.y);
3861 if (obj->cur.cache.clip.w != obj->prev.cache.clip.w ||
3862 obj->cur.cache.clip.h != obj->prev.cache.clip.h ||
3863 o->created || !o->video_visible)
3864 o->video.resize(o->video.data, obj, &o->video, obj->cur.cache.clip.w, obj->cur.cache.clip.h);
3865 if (!o->video_visible || o->created)
3866 {
3867 o->video.show(o->video.data, obj, &o->video);
3868 }
3869 else
3870 {
3871 /* Cancel dirty on the image */
3872 Eina_Rectangle *r;
3873
3874 o->dirty_pixels = 0;
3875 EINA_LIST_FREE(o->pixel_updates, r)
3876 eina_rectangle_free(r);
3877 }
3878 o->video_visible = EINA_TRUE;
3879 o->created = EINA_FALSE;
3880}
3881
3882void
3883_evas_object_image_video_overlay_hide(Evas_Object *obj)
3884{
3885 Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data);
3886
3887 if (o->video_visible || o->created)
3888 o->video.hide(o->video.data, obj, &o->video);
3889 if (evas_object_is_visible(obj))
3890 o->video.update_pixels(o->video.data, obj, &o->video);
3891 o->video_visible = EINA_FALSE;
3892 o->created = EINA_FALSE;
3893}
3894
3895/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
diff --git a/libraries/evas/src/lib/canvas/evas_object_inform.c b/libraries/evas/src/lib/canvas/evas_object_inform.c
new file mode 100644
index 0000000..bc09eb9
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_inform.c
@@ -0,0 +1,79 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* local calls */
5
6void
7evas_object_inform_call_show(Evas_Object *obj)
8{
9 _evas_object_event_new();
10
11 evas_object_event_callback_call(obj, EVAS_CALLBACK_SHOW, NULL);
12 _evas_post_event_callback_call(obj->layer->evas);
13}
14
15void
16evas_object_inform_call_hide(Evas_Object *obj)
17{
18 _evas_object_event_new();
19
20 evas_object_event_callback_call(obj, EVAS_CALLBACK_HIDE, NULL);
21 _evas_post_event_callback_call(obj->layer->evas);
22}
23
24void
25evas_object_inform_call_move(Evas_Object *obj)
26{
27 _evas_object_event_new();
28
29 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOVE, NULL);
30 _evas_post_event_callback_call(obj->layer->evas);
31}
32
33void
34evas_object_inform_call_resize(Evas_Object *obj)
35{
36 _evas_object_event_new();
37
38 evas_object_event_callback_call(obj, EVAS_CALLBACK_RESIZE, NULL);
39 _evas_post_event_callback_call(obj->layer->evas);
40}
41
42void
43evas_object_inform_call_restack(Evas_Object *obj)
44{
45 _evas_object_event_new();
46
47 evas_object_event_callback_call(obj, EVAS_CALLBACK_RESTACK, NULL);
48 _evas_post_event_callback_call(obj->layer->evas);
49}
50
51void
52evas_object_inform_call_changed_size_hints(Evas_Object *obj)
53{
54 _evas_object_event_new();
55
56 evas_object_event_callback_call(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, NULL);
57 _evas_post_event_callback_call(obj->layer->evas);
58}
59
60void
61evas_object_inform_call_image_preloaded(Evas_Object *obj)
62{
63 if (!_evas_object_image_preloading_get(obj)) return;
64 _evas_object_image_preloading_check(obj);
65 _evas_object_image_preloading_set(obj, 0);
66 _evas_object_event_new();
67
68 evas_object_event_callback_call(obj, EVAS_CALLBACK_IMAGE_PRELOADED, NULL);
69 _evas_post_event_callback_call(obj->layer->evas);
70}
71
72void
73evas_object_inform_call_image_unloaded(Evas_Object *obj)
74{
75 _evas_object_event_new();
76
77 evas_object_event_callback_call(obj, EVAS_CALLBACK_IMAGE_UNLOADED, NULL);
78 _evas_post_event_callback_call(obj->layer->evas);
79}
diff --git a/libraries/evas/src/lib/canvas/evas_object_intercept.c b/libraries/evas/src/lib/canvas/evas_object_intercept.c
new file mode 100644
index 0000000..c3e5e24
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_intercept.c
@@ -0,0 +1,625 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* local calls */
5
6static void evas_object_intercept_init(Evas_Object *obj);
7static void evas_object_intercept_deinit(Evas_Object *obj);
8
9static void
10evas_object_intercept_init(Evas_Object *obj)
11{
12 /* MEM OK */
13 if (!obj->interceptors)
14 obj->interceptors = evas_mem_calloc(sizeof(Evas_Intercept_Func));
15}
16
17static void
18evas_object_intercept_deinit(Evas_Object *obj)
19{
20 /* MEM OK */
21 if (!obj->interceptors) return;
22 if ((obj->interceptors->show.func) ||
23 (obj->interceptors->hide.func) ||
24 (obj->interceptors->move.func) ||
25 (obj->interceptors->resize.func) ||
26 (obj->interceptors->raise.func) ||
27 (obj->interceptors->lower.func) ||
28 (obj->interceptors->stack_above.func) ||
29 (obj->interceptors->stack_below.func) ||
30 (obj->interceptors->layer_set.func) ||
31 (obj->interceptors->color_set.func) ||
32 (obj->interceptors->clip_set.func) ||
33 (obj->interceptors->clip_unset.func))
34 return;
35 free(obj->interceptors);
36 obj->interceptors = NULL;
37}
38
39/* private calls */
40
41void
42evas_object_intercept_cleanup(Evas_Object *obj)
43{
44 /* MEM OK */
45 if (obj->interceptors) free(obj->interceptors);
46}
47
48int
49evas_object_intercept_call_show(Evas_Object *obj)
50{
51 /* MEM OK */
52 int ret;
53
54 if (!obj->interceptors) return 0;
55 if (obj->intercepted) return 0;
56 obj->intercepted = 1;
57 ret = !!(obj->interceptors->show.func);
58 if (obj->interceptors->show.func)
59 obj->interceptors->show.func(obj->interceptors->show.data, obj);
60 obj->intercepted = 0;
61 return ret;
62}
63
64int
65evas_object_intercept_call_hide(Evas_Object *obj)
66{
67 /* MEM OK */
68 int ret;
69
70 if (!obj->interceptors) return 0;
71 if (obj->intercepted) return 0;
72 obj->intercepted = 1;
73 ret = !!(obj->interceptors->hide.func);
74 if (obj->interceptors->hide.func)
75 obj->interceptors->hide.func(obj->interceptors->hide.data, obj);
76 obj->intercepted = 0;
77 return ret;
78}
79
80int
81evas_object_intercept_call_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
82{
83 /* MEM OK */
84 int ret;
85
86 if (!obj->interceptors) return 0;
87 if (obj->intercepted) return 0;
88 obj->intercepted = 1;
89 ret = !!(obj->interceptors->move.func);
90 if (obj->interceptors->move.func)
91 obj->interceptors->move.func(obj->interceptors->move.data, obj, x, y);
92 obj->intercepted = 0;
93 return ret;
94}
95
96int
97evas_object_intercept_call_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
98{
99 /* MEM OK */
100 int ret;
101
102 if (!obj->interceptors) return 0;
103 if (obj->intercepted) return 0;
104 obj->intercepted = 1;
105 ret = !!(obj->interceptors->resize.func);
106 if (obj->interceptors->resize.func)
107 obj->interceptors->resize.func(obj->interceptors->resize.data, obj, w, h);
108 obj->intercepted = 0;
109 return ret;
110}
111
112int
113evas_object_intercept_call_raise(Evas_Object *obj)
114{
115 /* MEM OK */
116 int ret;
117
118 if (!obj->interceptors) return 0;
119 if (obj->intercepted) return 0;
120 obj->intercepted = 1;
121 ret = !!(obj->interceptors->raise.func);
122 if (obj->interceptors->raise.func)
123 obj->interceptors->raise.func(obj->interceptors->raise.data, obj);
124 obj->intercepted = 0;
125 return ret;
126}
127
128int
129evas_object_intercept_call_lower(Evas_Object *obj)
130{
131 /* MEM OK */
132 int ret;
133
134 if (!obj->interceptors) return 0;
135 if (obj->intercepted) return 0;
136 obj->intercepted = 1;
137 ret = !!(obj->interceptors->lower.func);
138 if (obj->interceptors->lower.func)
139 obj->interceptors->lower.func(obj->interceptors->lower.data, obj);
140 obj->intercepted = 0;
141 return ret;
142}
143
144int
145evas_object_intercept_call_stack_above(Evas_Object *obj, Evas_Object *above)
146{
147 /* MEM OK */
148 int ret;
149
150 if (!obj->interceptors) return 0;
151 if (obj->intercepted) return 0;
152 obj->intercepted = 1;
153 ret = !!(obj->interceptors->stack_above.func);
154 if (obj->interceptors->stack_above.func)
155 obj->interceptors->stack_above.func(obj->interceptors->stack_above.data, obj, above);
156 obj->intercepted = 0;
157 return ret;
158}
159
160int
161evas_object_intercept_call_stack_below(Evas_Object *obj, Evas_Object *below)
162{
163 /* MEM OK */
164 int ret;
165
166 if (!obj->interceptors) return 0;
167 if (obj->intercepted) return 0;
168 obj->intercepted = 1;
169 ret = !!(obj->interceptors->stack_below.func);
170 if (obj->interceptors->stack_below.func)
171 obj->interceptors->stack_below.func(obj->interceptors->stack_below.data, obj, below);
172 obj->intercepted = 0;
173 return ret;
174}
175
176int
177evas_object_intercept_call_layer_set(Evas_Object *obj, int l)
178{
179 /* MEM OK */
180 int ret;
181
182 if (!obj->interceptors) return 0;
183 if (obj->intercepted) return 0;
184 obj->intercepted = 1;
185 ret = !!(obj->interceptors->layer_set.func);
186 if (obj->interceptors->layer_set.func)
187 obj->interceptors->layer_set.func(obj->interceptors->layer_set.data, obj, l);
188 obj->intercepted = 0;
189 return ret;
190}
191
192int
193evas_object_intercept_call_color_set(Evas_Object *obj, int r, int g, int b, int a)
194{
195 /* MEM OK */
196 int ret;
197
198 if (!obj->interceptors) return 0;
199 if (obj->intercepted) return 0;
200 obj->intercepted = 1;
201 ret = !!(obj->interceptors->color_set.func);
202 if (obj->interceptors->color_set.func)
203 obj->interceptors->color_set.func(obj->interceptors->color_set.data, obj, r, g, b, a);
204 obj->intercepted = 0;
205 return ret;
206}
207
208int
209evas_object_intercept_call_clip_set(Evas_Object *obj, Evas_Object *clip)
210{
211 /* MEM OK */
212 int ret;
213
214 if (!obj->interceptors) return 0;
215 if (obj->intercepted) return 0;
216 obj->intercepted = 1;
217 ret = !!(obj->interceptors->clip_set.func);
218 if (obj->interceptors->clip_set.func)
219 obj->interceptors->clip_set.func(obj->interceptors->clip_set.data, obj, clip);
220 obj->intercepted = 0;
221 return ret;
222}
223
224int
225evas_object_intercept_call_clip_unset(Evas_Object *obj)
226{
227 /* MEM OK */
228 int ret;
229
230 if (!obj->interceptors) return 0;
231 if (obj->intercepted) return 0;
232 obj->intercepted = 1;
233 ret = !!(obj->interceptors->clip_unset.func);
234 if (obj->interceptors->clip_unset.func)
235 obj->interceptors->clip_unset.func(obj->interceptors->clip_unset.data, obj);
236 obj->intercepted = 0;
237 return ret;
238}
239
240/* public calls */
241
242EAPI void
243evas_object_intercept_show_callback_add(Evas_Object *obj, Evas_Object_Intercept_Show_Cb func, const void *data)
244{
245 /* MEM OK */
246
247 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
248 return;
249 MAGIC_CHECK_END();
250 if (!func) return;
251 evas_object_intercept_init(obj);
252 if (!obj->interceptors) return;
253 obj->interceptors->show.func = func;
254 obj->interceptors->show.data = (void *)data;
255}
256
257EAPI void *
258evas_object_intercept_show_callback_del(Evas_Object *obj, Evas_Object_Intercept_Show_Cb func)
259{
260 /* MEM OK */
261 void *data;
262
263 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
264 return NULL;
265 MAGIC_CHECK_END();
266 if (!func) return NULL;
267 if (!obj->interceptors) return NULL;
268 obj->interceptors->show.func = NULL;
269 data = obj->interceptors->show.data;
270 obj->interceptors->show.data = NULL;
271 evas_object_intercept_deinit(obj);
272 return data;
273}
274
275EAPI void
276evas_object_intercept_hide_callback_add(Evas_Object *obj, Evas_Object_Intercept_Hide_Cb func, const void *data)
277{
278 /* MEM OK */
279 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
280 return;
281 MAGIC_CHECK_END();
282 if (!func) return;
283 evas_object_intercept_init(obj);
284 if (!obj->interceptors) return;
285 obj->interceptors->hide.func = func;
286 obj->interceptors->hide.data = (void *)data;
287}
288
289EAPI void *
290evas_object_intercept_hide_callback_del(Evas_Object *obj, Evas_Object_Intercept_Hide_Cb func)
291{
292 /* MEM OK */
293 void *data;
294
295 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
296 return NULL;
297 MAGIC_CHECK_END();
298 if (!func) return NULL;
299 if (!obj->interceptors) return NULL;
300 obj->interceptors->hide.func = NULL;
301 data = obj->interceptors->hide.data;
302 obj->interceptors->hide.data = NULL;
303 evas_object_intercept_deinit(obj);
304 return data;
305}
306
307EAPI void
308evas_object_intercept_move_callback_add(Evas_Object *obj, Evas_Object_Intercept_Move_Cb func, const void *data)
309{
310 /* MEM OK */
311 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
312 return;
313 MAGIC_CHECK_END();
314 if (!func) return;
315 evas_object_intercept_init(obj);
316 if (!obj->interceptors) return;
317 obj->interceptors->move.func = func;
318 obj->interceptors->move.data = (void *)data;
319}
320
321EAPI void *
322evas_object_intercept_move_callback_del(Evas_Object *obj, Evas_Object_Intercept_Move_Cb func)
323{
324 /* MEM OK */
325 void *data;
326
327 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
328 return NULL;
329 MAGIC_CHECK_END();
330 if (!func) return NULL;
331 if (!obj->interceptors) return NULL;
332 obj->interceptors->move.func = NULL;
333 data = obj->interceptors->move.data;
334 obj->interceptors->move.data = NULL;
335 evas_object_intercept_deinit(obj);
336 return data;
337}
338
339EAPI void
340evas_object_intercept_resize_callback_add(Evas_Object *obj, Evas_Object_Intercept_Resize_Cb func, const void *data)
341{
342 /* MEM OK */
343 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
344 return;
345 MAGIC_CHECK_END();
346 if (!func) return;
347 evas_object_intercept_init(obj);
348 if (!obj->interceptors) return;
349 obj->interceptors->resize.func = func;
350 obj->interceptors->resize.data = (void *)data;
351}
352
353EAPI void *
354evas_object_intercept_resize_callback_del(Evas_Object *obj, Evas_Object_Intercept_Resize_Cb func)
355{
356 /* MEM OK */
357 void *data;
358
359 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
360 return NULL;
361 MAGIC_CHECK_END();
362 if (!func) return NULL;
363 if (!obj->interceptors) return NULL;
364 obj->interceptors->resize.func = NULL;
365 data = obj->interceptors->resize.data;
366 obj->interceptors->resize.data = NULL;
367 evas_object_intercept_deinit(obj);
368 return data;
369}
370
371EAPI void
372evas_object_intercept_raise_callback_add(Evas_Object *obj, Evas_Object_Intercept_Raise_Cb func, const void *data)
373{
374 /* MEM OK */
375 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
376 return;
377 MAGIC_CHECK_END();
378 if (!func) return;
379 evas_object_intercept_init(obj);
380 if (!obj->interceptors) return;
381 obj->interceptors->raise.func = func;
382 obj->interceptors->raise.data = (void *)data;
383}
384
385EAPI void *
386evas_object_intercept_raise_callback_del(Evas_Object *obj, Evas_Object_Intercept_Raise_Cb func)
387{
388 /* MEM OK */
389 void *data;
390
391 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
392 return NULL;
393 MAGIC_CHECK_END();
394 if (!func) return NULL;
395 if (!obj->interceptors) return NULL;
396 obj->interceptors->raise.func = NULL;
397 data = obj->interceptors->raise.data;
398 obj->interceptors->raise.data = NULL;
399 evas_object_intercept_deinit(obj);
400 return data;
401}
402
403EAPI void
404evas_object_intercept_lower_callback_add(Evas_Object *obj, Evas_Object_Intercept_Lower_Cb func, const void *data)
405{
406 /* MEM OK */
407 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
408 return;
409 MAGIC_CHECK_END();
410 if (!func) return;
411 evas_object_intercept_init(obj);
412 if (!obj->interceptors) return;
413 obj->interceptors->lower.func = func;
414 obj->interceptors->lower.data = (void *)data;
415}
416
417EAPI void *
418evas_object_intercept_lower_callback_del(Evas_Object *obj, Evas_Object_Intercept_Lower_Cb func)
419{
420 /* MEM OK */
421 void *data;
422
423 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
424 return NULL;
425 MAGIC_CHECK_END();
426 if (!func) return NULL;
427 if (!obj->interceptors) return NULL;
428 obj->interceptors->lower.func = NULL;
429 data = obj->interceptors->lower.data;
430 obj->interceptors->lower.data = NULL;
431 evas_object_intercept_deinit(obj);
432 return data;
433}
434
435EAPI void
436evas_object_intercept_stack_above_callback_add(Evas_Object *obj, Evas_Object_Intercept_Stack_Above_Cb func, const void *data)
437{
438 /* MEM OK */
439 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
440 return;
441 MAGIC_CHECK_END();
442 if (!func) return;
443 evas_object_intercept_init(obj);
444 if (!obj->interceptors) return;
445 obj->interceptors->stack_above.func = func;
446 obj->interceptors->stack_above.data = (void *)data;
447}
448
449EAPI void *
450evas_object_intercept_stack_above_callback_del(Evas_Object *obj, Evas_Object_Intercept_Stack_Above_Cb func)
451{
452 /* MEM OK */
453 void *data;
454
455 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
456 return NULL;
457 MAGIC_CHECK_END();
458 if (!func) return NULL;
459 if (!obj->interceptors) return NULL;
460 obj->interceptors->stack_above.func = NULL;
461 data = obj->interceptors->stack_above.data;
462 obj->interceptors->stack_above.data = NULL;
463 evas_object_intercept_deinit(obj);
464 return data;
465}
466
467EAPI void
468evas_object_intercept_stack_below_callback_add(Evas_Object *obj, Evas_Object_Intercept_Stack_Below_Cb func, const void *data)
469{
470 /* MEM OK */
471 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
472 return;
473 MAGIC_CHECK_END();
474 if (!func) return;
475 evas_object_intercept_init(obj);
476 if (!obj->interceptors) return;
477 obj->interceptors->stack_below.func = func;
478 obj->interceptors->stack_below.data = (void *)data;
479}
480
481EAPI void *
482evas_object_intercept_stack_below_callback_del(Evas_Object *obj, Evas_Object_Intercept_Stack_Below_Cb func)
483{
484 /* MEM OK */
485 void *data;
486
487 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
488 return NULL;
489 MAGIC_CHECK_END();
490 if (!func) return NULL;
491 if (!obj->interceptors) return NULL;
492 obj->interceptors->stack_below.func = NULL;
493 data = obj->interceptors->stack_below.data;
494 obj->interceptors->stack_below.data = NULL;
495 evas_object_intercept_deinit(obj);
496 return data;
497}
498
499EAPI void
500evas_object_intercept_layer_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Layer_Set_Cb func, const void *data)
501{
502 /* MEM OK */
503 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
504 return;
505 MAGIC_CHECK_END();
506 if (!func) return;
507 evas_object_intercept_init(obj);
508 if (!obj->interceptors) return;
509 obj->interceptors->layer_set.func = func;
510 obj->interceptors->layer_set.data = (void *)data;
511}
512
513EAPI void *
514evas_object_intercept_layer_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Layer_Set_Cb func)
515{
516 /* MEM OK */
517 void *data;
518
519 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
520 return NULL;
521 MAGIC_CHECK_END();
522 if (!func) return NULL;
523 if (!obj->interceptors) return NULL;
524 obj->interceptors->layer_set.func = NULL;
525 data = obj->interceptors->layer_set.data;
526 obj->interceptors->layer_set.data = NULL;
527 evas_object_intercept_deinit(obj);
528 return data;
529}
530
531EAPI void
532evas_object_intercept_color_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Color_Set_Cb func, const void *data)
533{
534 /* MEM OK */
535 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
536 return;
537 MAGIC_CHECK_END();
538 if (!func) return;
539 evas_object_intercept_init(obj);
540 if (!obj->interceptors) return;
541 obj->interceptors->color_set.func = func;
542 obj->interceptors->color_set.data = (void *)data;
543}
544
545EAPI void *
546evas_object_intercept_color_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Color_Set_Cb func)
547{
548 /* MEM OK */
549 void *data;
550
551 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
552 return NULL;
553 MAGIC_CHECK_END();
554 if (!func) return NULL;
555 if (!obj->interceptors) return NULL;
556 obj->interceptors->color_set.func = NULL;
557 data = obj->interceptors->color_set.data;
558 obj->interceptors->color_set.data = NULL;
559 evas_object_intercept_deinit(obj);
560 return data;
561}
562
563EAPI void
564evas_object_intercept_clip_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Clip_Set_Cb func, const void *data)
565{
566 /* MEM OK */
567 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
568 return;
569 MAGIC_CHECK_END();
570 if (!func) return;
571 evas_object_intercept_init(obj);
572 if (!obj->interceptors) return;
573 obj->interceptors->clip_set.func = func;
574 obj->interceptors->clip_set.data = (void *)data;
575}
576
577EAPI void *
578evas_object_intercept_clip_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Clip_Set_Cb func)
579{
580 /* MEM OK */
581 void *data;
582
583 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
584 return NULL;
585 MAGIC_CHECK_END();
586 if (!func) return NULL;
587 if (!obj->interceptors) return NULL;
588 obj->interceptors->clip_set.func = NULL;
589 data = obj->interceptors->clip_set.data;
590 obj->interceptors->clip_set.data = NULL;
591 evas_object_intercept_deinit(obj);
592 return data;
593}
594
595EAPI void
596evas_object_intercept_clip_unset_callback_add(Evas_Object *obj, Evas_Object_Intercept_Clip_Unset_Cb func, const void *data)
597{
598 /* MEM OK */
599 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
600 return;
601 MAGIC_CHECK_END();
602 if (!func) return;
603 evas_object_intercept_init(obj);
604 if (!obj->interceptors) return;
605 obj->interceptors->clip_unset.func = func;
606 obj->interceptors->clip_unset.data = (void *)data;
607}
608
609EAPI void *
610evas_object_intercept_clip_unset_callback_del(Evas_Object *obj, Evas_Object_Intercept_Clip_Unset_Cb func)
611{
612 /* MEM OK */
613 void *data;
614
615 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
616 return NULL;
617 MAGIC_CHECK_END();
618 if (!func) return NULL;
619 if (!obj->interceptors) return NULL;
620 obj->interceptors->clip_unset.func = NULL;
621 data = obj->interceptors->clip_unset.data;
622 obj->interceptors->clip_unset.data = NULL;
623 evas_object_intercept_deinit(obj);
624 return data;
625}
diff --git a/libraries/evas/src/lib/canvas/evas_object_line.c b/libraries/evas/src/lib/canvas/evas_object_line.c
new file mode 100644
index 0000000..b09a6e2
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_line.c
@@ -0,0 +1,461 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private magic number for line objects */
5static const char o_type[] = "line";
6
7/* private struct for line object internal data */
8typedef struct _Evas_Object_Line Evas_Object_Line;
9
10struct _Evas_Object_Line
11{
12 DATA32 magic;
13 struct {
14 struct {
15 int x1, y1, x2, y2;
16 struct {
17 Evas_Coord w, h;
18 } object;
19 } cache;
20 Evas_Coord x1, y1, x2, y2;
21 } cur, prev;
22
23 void *engine_data;
24
25 char changed : 1;
26};
27
28/* private methods for line objects */
29static void evas_object_line_init(Evas_Object *obj);
30static void *evas_object_line_new(void);
31static void evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
32static void evas_object_line_free(Evas_Object *obj);
33static void evas_object_line_render_pre(Evas_Object *obj);
34static void evas_object_line_render_post(Evas_Object *obj);
35
36static unsigned int evas_object_line_id_get(Evas_Object *obj);
37static unsigned int evas_object_line_visual_id_get(Evas_Object *obj);
38static void *evas_object_line_engine_data_get(Evas_Object *obj);
39
40static int evas_object_line_is_opaque(Evas_Object *obj);
41static int evas_object_line_was_opaque(Evas_Object *obj);
42static int evas_object_line_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
43static int evas_object_line_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
44static void evas_object_line_coords_recalc(Evas_Object *obj);
45
46static const Evas_Object_Func object_func =
47{
48 /* methods (compulsory) */
49 evas_object_line_free,
50 evas_object_line_render,
51 evas_object_line_render_pre,
52 evas_object_line_render_post,
53 evas_object_line_id_get,
54 evas_object_line_visual_id_get,
55 evas_object_line_engine_data_get,
56 /* these are optional. NULL = nothing */
57 NULL,
58 NULL,
59 NULL,
60 NULL,
61 evas_object_line_is_opaque,
62 evas_object_line_was_opaque,
63 evas_object_line_is_inside,
64 evas_object_line_was_inside,
65 evas_object_line_coords_recalc,
66 NULL,
67 NULL,
68 NULL,
69 NULL
70};
71
72/* the actual api call to add a rect */
73/* it has no other api calls as all properties are standard */
74
75EVAS_MEMPOOL(_mp_obj);
76
77EAPI Evas_Object *
78evas_object_line_add(Evas *e)
79{
80 Evas_Object *obj;
81
82 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
83 return NULL;
84 MAGIC_CHECK_END();
85 obj = evas_object_new(e);
86 evas_object_line_init(obj);
87 evas_object_inject(obj, e);
88 return obj;
89}
90
91EAPI void
92evas_object_line_xy_set(Evas_Object *obj, Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
93{
94 Evas_Object_Line *o;
95 Evas_Coord min_x, max_x, min_y, max_y;
96 int is, was = 0;
97
98 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
99 return;
100 MAGIC_CHECK_END();
101 o = (Evas_Object_Line *)(obj->object_data);
102 MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
103 return;
104 MAGIC_CHECK_END();
105 if ((x1 == o->cur.x1) && (y1 == o->cur.y1) &&
106 (x2 == o->cur.x2) && (y2 == o->cur.y2)) return;
107 if (obj->layer->evas->events_frozen <= 0)
108 {
109 if (!evas_event_passes_through(obj) &&
110 !evas_event_freezes_through(obj))
111 was = evas_object_is_in_output_rect(obj,
112 obj->layer->evas->pointer.x,
113 obj->layer->evas->pointer.y,
114 1, 1);
115 }
116 if (x1 < x2)
117 {
118 min_x = x1;
119 max_x = x2;
120 }
121 else
122 {
123 min_x = x2;
124 max_x = x1;
125 }
126 if (y1 < y2)
127 {
128 min_y = y1;
129 max_y = y2;
130 }
131 else
132 {
133 min_y = y2;
134 max_y = y1;
135 }
136 obj->cur.geometry.x = min_x;
137 obj->cur.geometry.y = min_y;
138 obj->cur.geometry.w = max_x - min_x + 2;
139 obj->cur.geometry.h = max_y - min_y + 2;
140//// obj->cur.cache.geometry.validity = 0;
141 o->cur.x1 = x1 - min_x;
142 o->cur.y1 = y1 - min_y;
143 o->cur.x2 = x2 - min_x;
144 o->cur.y2 = y2 - min_y;
145 o->changed = 1;
146 evas_object_change(obj);
147 evas_object_coords_recalc(obj);
148 evas_object_clip_dirty(obj);
149 if (obj->layer->evas->events_frozen <= 0)
150 {
151 is = evas_object_is_in_output_rect(obj,
152 obj->layer->evas->pointer.x,
153 obj->layer->evas->pointer.y, 1, 1);
154 if (!evas_event_passes_through(obj) &&
155 !evas_event_freezes_through(obj))
156 {
157 if ((is ^ was) && obj->cur.visible)
158 evas_event_feed_mouse_move(obj->layer->evas,
159 obj->layer->evas->pointer.x,
160 obj->layer->evas->pointer.y,
161 obj->layer->evas->last_timestamp,
162 NULL);
163 }
164 }
165 evas_object_inform_call_move(obj);
166 evas_object_inform_call_resize(obj);
167}
168
169EAPI void
170evas_object_line_xy_get(const Evas_Object *obj, Evas_Coord *x1, Evas_Coord *y1, Evas_Coord *x2, Evas_Coord *y2)
171{
172 Evas_Object_Line *o;
173
174 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
175 if (x1) *x1 = 0;
176 if (y1) *y1 = 0;
177 if (x2) *x2 = 0;
178 if (y2) *y2 = 0;
179 return;
180 MAGIC_CHECK_END();
181 o = (Evas_Object_Line *)(obj->object_data);
182 MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
183 if (x1) *x1 = 0;
184 if (y1) *y1 = 0;
185 if (x2) *x2 = 0;
186 if (y2) *y2 = 0;
187 return;
188 MAGIC_CHECK_END();
189 if (x1) *x1 = obj->cur.geometry.x + o->cur.x1;
190 if (y1) *y1 = obj->cur.geometry.y + o->cur.y1;
191 if (x2) *x2 = obj->cur.geometry.x + o->cur.x2;
192 if (y2) *y2 = obj->cur.geometry.y + o->cur.y2;
193}
194
195/* all nice and private */
196static void
197evas_object_line_init(Evas_Object *obj)
198{
199 /* alloc image ob, setup methods and default values */
200 obj->object_data = evas_object_line_new();
201 /* set up default settings for this kind of object */
202 obj->cur.color.r = 255;
203 obj->cur.color.g = 255;
204 obj->cur.color.b = 255;
205 obj->cur.color.a = 255;
206 obj->cur.geometry.x = 0;
207 obj->cur.geometry.y = 0;
208 obj->cur.geometry.w = 0;
209 obj->cur.geometry.h = 0;
210 obj->cur.layer = 0;
211 obj->cur.anti_alias = 1;
212 obj->cur.render_op = EVAS_RENDER_BLEND;
213 /* set up object-specific settings */
214 obj->prev = obj->cur;
215 /* set up methods (compulsory) */
216 obj->func = &object_func;
217 obj->type = o_type;
218}
219
220static void *
221evas_object_line_new(void)
222{
223 Evas_Object_Line *o;
224
225 /* alloc obj private data */
226 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_line", Evas_Object_Line, 16, NULL);
227 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Line);
228 if (!o) return NULL;
229 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Line);
230 o->magic = MAGIC_OBJ_LINE;
231 o->cur.x1 = 0;
232 o->cur.y1 = 0;
233 o->cur.x2 = 31;
234 o->cur.y2 = 31;
235 o->prev = o->cur;
236 return o;
237}
238
239static void
240evas_object_line_free(Evas_Object *obj)
241{
242 Evas_Object_Line *o;
243
244 /* frees private object data. very simple here */
245 o = (Evas_Object_Line *)(obj->object_data);
246 MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
247 return;
248 MAGIC_CHECK_END();
249 /* free obj */
250 o->magic = 0;
251 EVAS_MEMPOOL_FREE(_mp_obj, o);
252}
253
254static void
255evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
256{
257 Evas_Object_Line *o;
258
259 /* render object to surface with context, and offxet by x,y */
260 o = (Evas_Object_Line *)(obj->object_data);
261 obj->layer->evas->engine.func->context_color_set(output,
262 context,
263 obj->cur.cache.clip.r,
264 obj->cur.cache.clip.g,
265 obj->cur.cache.clip.b,
266 obj->cur.cache.clip.a);
267 obj->layer->evas->engine.func->context_multiplier_unset(output,
268 context);
269 obj->layer->evas->engine.func->context_anti_alias_set(output, context,
270 obj->cur.anti_alias);
271 obj->layer->evas->engine.func->context_render_op_set(output, context,
272 obj->cur.render_op);
273 obj->layer->evas->engine.func->line_draw(output,
274 context,
275 surface,
276 o->cur.cache.x1 + x,
277 o->cur.cache.y1 + y,
278 o->cur.cache.x2 + x,
279 o->cur.cache.y2 + y);
280}
281
282static void
283evas_object_line_render_pre(Evas_Object *obj)
284{
285 Evas_Object_Line *o;
286 int is_v, was_v;
287
288 /* dont pre-render the obj twice! */
289 if (obj->pre_render_done) return;
290 obj->pre_render_done = 1;
291 /* pre-render phase. this does anything an object needs to do just before */
292 /* rendering. this could mean loading the image data, retrieving it from */
293 /* elsewhere, decoding video etc. */
294 /* then when this is done the object needs to figure if it changed and */
295 /* if so what and where and add the appropriate redraw lines */
296 o = (Evas_Object_Line *)(obj->object_data);
297 /* if someone is clipping this obj - go calculate the clipper */
298 if (obj->cur.clipper)
299 {
300 if (obj->cur.cache.clip.dirty)
301 evas_object_clip_recalc(obj->cur.clipper);
302 obj->cur.clipper->func->render_pre(obj->cur.clipper);
303 }
304 /* now figure what changed and add draw rects */
305 /* if it just became visible or invisible */
306 is_v = evas_object_is_visible(obj);
307 was_v = evas_object_was_visible(obj);
308 if (is_v != was_v)
309 {
310 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
311 goto done;
312 }
313 if ((obj->cur.map != obj->prev.map) ||
314 (obj->cur.usemap != obj->prev.usemap))
315 {
316 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
317 goto done;
318 }
319 /* it's not visible - we accounted for it appearing or not so just abort */
320 if (!is_v) goto done;
321 /* clipper changed this is in addition to anything else for obj */
322 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
323 /* if we restacked (layer or just within a layer) */
324 if (obj->restack)
325 {
326 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
327 goto done;
328 }
329 /* if it changed anti_alias */
330 if (obj->cur.anti_alias != obj->prev.anti_alias)
331 {
332 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
333 goto done;
334 }
335 /* if it changed render op */
336 if (obj->cur.render_op != obj->prev.render_op)
337 {
338 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
339 goto done;
340 }
341 /* if it changed color */
342 if ((obj->cur.color.r != obj->prev.color.r) ||
343 (obj->cur.color.g != obj->prev.color.g) ||
344 (obj->cur.color.b != obj->prev.color.b) ||
345 (obj->cur.color.a != obj->prev.color.a))
346 {
347 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
348 goto done;
349 }
350 /* if it changed geometry - and obviously not visibility or color */
351 /* calculate differences since we have a constant color fill */
352 /* we really only need to update the differences */
353 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
354 (obj->cur.geometry.y != obj->prev.geometry.y) ||
355 (obj->cur.geometry.w != obj->prev.geometry.w) ||
356 (obj->cur.geometry.h != obj->prev.geometry.h) ||
357 ((o->changed) &&
358 ((o->cur.x1 != o->prev.x1) ||
359 (o->cur.y1 != o->prev.y1) ||
360 (o->cur.x2 != o->prev.x2) ||
361 (o->cur.y2 != o->prev.y2)))
362 )
363 {
364 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
365 goto done;
366 }
367 done:
368 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
369}
370
371static void
372evas_object_line_render_post(Evas_Object *obj)
373{
374 Evas_Object_Line *o;
375
376 /* this moves the current data to the previous state parts of the object */
377 /* in whatever way is safest for the object. also if we don't need object */
378 /* data anymore we can free it if the object deems this is a good idea */
379 o = (Evas_Object_Line *)(obj->object_data);
380 /* remove those pesky changes */
381 evas_object_clip_changes_clean(obj);
382 /* move cur to prev safely for object data */
383 obj->prev = obj->cur;
384 o->prev = o->cur;
385 o->changed = 0;
386}
387
388static unsigned int evas_object_line_id_get(Evas_Object *obj)
389{
390 Evas_Object_Line *o;
391
392 o = (Evas_Object_Line *)(obj->object_data);
393 if (!o) return 0;
394 return MAGIC_OBJ_LINE;
395}
396
397static unsigned int evas_object_line_visual_id_get(Evas_Object *obj)
398{
399 Evas_Object_Line *o;
400
401 o = (Evas_Object_Line *)(obj->object_data);
402 if (!o) return 0;
403 return MAGIC_OBJ_SHAPE;
404}
405
406static void *evas_object_line_engine_data_get(Evas_Object *obj)
407{
408 Evas_Object_Line *o;
409
410 o = (Evas_Object_Line *)(obj->object_data);
411 if (!o) return NULL;
412 return o->engine_data;
413}
414
415static int
416evas_object_line_is_opaque(Evas_Object *obj __UNUSED__)
417{
418 /* this returns 1 if the internal object data implies that the object is */
419 /* currently fully opaque over the entire line it occupies */
420 return 0;
421}
422
423static int
424evas_object_line_was_opaque(Evas_Object *obj __UNUSED__)
425{
426 /* this returns 1 if the internal object data implies that the object was */
427 /* previously fully opaque over the entire line it occupies */
428 return 0;
429}
430
431static int
432evas_object_line_is_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
433{
434 /* this returns 1 if the canvas co-ordinates are inside the object based */
435 /* on object private data. not much use for rects, but for polys, images */
436 /* and other complex objects it might be */
437 return 1;
438}
439
440static int
441evas_object_line_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
442{
443 /* this returns 1 if the canvas co-ordinates were inside the object based */
444 /* on object private data. not much use for rects, but for polys, images */
445 /* and other complex objects it might be */
446 return 1;
447}
448
449static void
450evas_object_line_coords_recalc(Evas_Object *obj)
451{
452 Evas_Object_Line *o;
453
454 o = (Evas_Object_Line *)(obj->object_data);
455 o->cur.cache.x1 = obj->cur.geometry.x + o->cur.x1;
456 o->cur.cache.y1 = obj->cur.geometry.y + o->cur.y1;
457 o->cur.cache.x2 = obj->cur.geometry.x + o->cur.x2;
458 o->cur.cache.y2 = obj->cur.geometry.y + o->cur.y2;
459 o->cur.cache.object.w = obj->cur.geometry.w;
460 o->cur.cache.object.h = obj->cur.geometry.h;
461}
diff --git a/libraries/evas/src/lib/canvas/evas_object_main.c b/libraries/evas/src/lib/canvas/evas_object_main.c
new file mode 100644
index 0000000..3eaded9
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_main.c
@@ -0,0 +1,1319 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4EVAS_MEMPOOL(_mp_obj);
5EVAS_MEMPOOL(_mp_sh);
6
7static Eina_Inlist *
8get_layer_objects(Evas_Layer *l)
9{
10 if ((!l) || (!l->objects)) return NULL;
11 return (EINA_INLIST_GET(l->objects));
12}
13
14/* evas internal stuff */
15Evas_Object *
16evas_object_new(Evas *e __UNUSED__)
17{
18 Evas_Object *obj;
19
20 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object", Evas_Object, 512, NULL);
21 obj = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object);
22 if (!obj) return NULL;
23 EVAS_MEMPOOL_PREP(_mp_obj, obj, Evas_Object);
24
25 obj->magic = MAGIC_OBJ;
26 obj->cur.scale = 1.0;
27 obj->prev.scale = 1.0;
28
29 return obj;
30}
31
32void
33evas_object_free(Evas_Object *obj, int clean_layer)
34{
35 int was_smart_child = 0;
36
37#if 0 // filtering disabled
38 evas_filter_free(obj);
39#endif
40 if (!strcmp(obj->type, "image")) evas_object_image_video_surface_set(obj, NULL);
41 evas_object_map_set(obj, NULL);
42 evas_object_grabs_cleanup(obj);
43 evas_object_intercept_cleanup(obj);
44 if (obj->smart.parent) was_smart_child = 1;
45 evas_object_smart_cleanup(obj);
46 obj->func->free(obj);
47 if (!was_smart_child) evas_object_release(obj, clean_layer);
48 if (obj->clip.clipees)
49 eina_list_free(obj->clip.clipees);
50 evas_object_clip_changes_clean(obj);
51 evas_object_event_callback_all_del(obj);
52 evas_object_event_callback_cleanup(obj);
53 while (obj->data.elements)
54 {
55 Evas_Data_Node *node;
56
57 node = obj->data.elements->data;
58 obj->data.elements = eina_list_remove(obj->data.elements, node);
59 free(node);
60 }
61 obj->magic = 0;
62 if (obj->size_hints)
63 {
64 EVAS_MEMPOOL_FREE(_mp_sh, obj->size_hints);
65 }
66 EVAS_MEMPOOL_FREE(_mp_obj, obj);
67}
68
69void
70evas_object_change(Evas_Object *obj)
71{
72 Eina_List *l;
73 Evas_Object *obj2;
74 Eina_Bool movch = 0;
75
76 if (obj->layer->evas->nochange)
77 {
78// printf("nochange %p\n", obj);
79 return;
80 }
81// else
82// printf("ch %p\n", obj);
83 obj->layer->evas->changed = 1;
84 if (obj->changed_move)
85 {
86 movch = 1;
87 obj->changed_move = 0;
88 if (!obj->changed_nomove) obj->changed_move_only = 1;
89 if (obj->changed) return;
90 }
91 else
92 {
93 obj->changed_move_only = 0;
94 obj->changed_nomove = 1;
95 if (obj->changed) return;
96 }
97// obj->changed = 1;
98 evas_render_object_recalc(obj);
99 /* set changed flag on all objects this one clips too */
100 if (!((movch) && (obj->is_static_clip)))
101 {
102 EINA_LIST_FOREACH(obj->clip.clipees, l, obj2) evas_object_change(obj2);
103 }
104 EINA_LIST_FOREACH(obj->proxy.proxies, l, obj2)
105 {
106 evas_object_change(obj2);
107 }
108 if (obj->smart.parent) evas_object_change(obj->smart.parent);
109}
110
111void
112evas_object_render_pre_visible_change(Eina_Array *rects, Evas_Object *obj, int is_v, int was_v)
113{
114 if (obj->smart.smart) return ;
115 if (is_v == was_v) return ;
116 if (is_v)
117 {
118 evas_add_rect(rects,
119 obj->cur.cache.clip.x,
120 obj->cur.cache.clip.y,
121 obj->cur.cache.clip.w,
122 obj->cur.cache.clip.h);
123 }
124 else
125 {
126 evas_add_rect(rects,
127 obj->prev.cache.clip.x,
128 obj->prev.cache.clip.y,
129 obj->prev.cache.clip.w,
130 obj->prev.cache.clip.h);
131 }
132}
133
134void
135evas_object_render_pre_clipper_change(Eina_Array *rects, Evas_Object *obj)
136{
137 if (obj->smart.smart) return ;
138 if (obj->cur.clipper == obj->prev.clipper) return ;
139 if ((obj->cur.clipper) && (obj->prev.clipper))
140 {
141 /* get difference rects between clippers */
142 evas_rects_return_difference_rects(rects,
143 obj->cur.clipper->cur.cache.clip.x,
144 obj->cur.clipper->cur.cache.clip.y,
145 obj->cur.clipper->cur.cache.clip.w,
146 obj->cur.clipper->cur.cache.clip.h,
147 obj->prev.clipper->prev.cache.clip.x,
148 obj->prev.clipper->prev.cache.clip.y,
149 obj->prev.clipper->prev.cache.clip.w,
150 obj->prev.clipper->prev.cache.clip.h);
151 }
152 else if (obj->cur.clipper)
153 {
154 evas_rects_return_difference_rects(rects,
155 obj->cur.geometry.x,
156 obj->cur.geometry.y,
157 obj->cur.geometry.w,
158 obj->cur.geometry.h,
159//// rl = evas_rects_return_difference_rects(obj->cur.cache.geometry.x,
160//// obj->cur.cache.geometry.y,
161//// obj->cur.cache.geometry.w,
162//// obj->cur.cache.geometry.h,
163 obj->cur.clipper->cur.cache.clip.x,
164 obj->cur.clipper->cur.cache.clip.y,
165 obj->cur.clipper->cur.cache.clip.w,
166 obj->cur.clipper->cur.cache.clip.h);
167 }
168 else if (obj->prev.clipper)
169 {
170 evas_rects_return_difference_rects(rects,
171 obj->prev.geometry.x,
172 obj->prev.geometry.y,
173 obj->prev.geometry.w,
174 obj->prev.geometry.h,
175//// rl = evas_rects_return_difference_rects(obj->prev.cache.geometry.x,
176//// obj->prev.cache.geometry.y,
177//// obj->prev.cache.geometry.w,
178//// obj->prev.cache.geometry.h,
179 obj->prev.clipper->prev.cache.clip.x,
180 obj->prev.clipper->prev.cache.clip.y,
181 obj->prev.clipper->prev.cache.clip.w,
182 obj->prev.clipper->prev.cache.clip.h);
183 }
184}
185
186void
187evas_object_render_pre_prev_cur_add(Eina_Array *rects, Evas_Object *obj)
188{
189 evas_add_rect(rects,
190 obj->cur.cache.clip.x,
191 obj->cur.cache.clip.y,
192 obj->cur.cache.clip.w,
193 obj->cur.cache.clip.h);
194 evas_add_rect(rects,
195 obj->prev.cache.clip.x,
196 obj->prev.cache.clip.y,
197 obj->prev.cache.clip.w,
198 obj->prev.cache.clip.h);
199/*
200 evas_add_rect(rects,
201 obj->cur.geometry.x,
202 obj->cur.geometry.y,
203 obj->cur.geometry.w,
204 obj->cur.geometry.h);
205//// obj->cur.cache.geometry.x,
206//// obj->cur.cache.geometry.y,
207//// obj->cur.cache.geometry.w,
208//// obj->cur.cache.geometry.h);
209 evas_add_rect(rects,
210 obj->prev.geometry.x,
211 obj->prev.geometry.y,
212 obj->prev.geometry.w,
213 obj->prev.geometry.h);
214//// obj->prev.cache.geometry.x,
215//// obj->prev.cache.geometry.y,
216//// obj->prev.cache.geometry.w,
217//// obj->prev.cache.geometry.h);
218*/
219}
220
221void
222evas_object_clip_changes_clean(Evas_Object *obj)
223{
224 Eina_Rectangle *r;
225
226 EINA_LIST_FREE(obj->clip.changes, r) eina_rectangle_free(r);
227}
228
229void
230evas_object_render_pre_effect_updates(Eina_Array *rects, Evas_Object *obj, int is_v, int was_v)
231{
232 Eina_Rectangle *r;
233 Evas_Object *clipper;
234 Eina_List *l;
235 unsigned int i;
236 Eina_Array_Iterator it;
237 int x, y, w, h;
238
239 if (obj->smart.smart) goto end;
240 /* FIXME: was_v isn't used... why? */
241 was_v = 0;
242 if (!obj->clip.clipees)
243 {
244 EINA_ARRAY_ITER_NEXT(rects, i, r, it)
245 {
246 /* get updates and clip to current clip */
247 x = r->x;
248 y = r->y;
249 w = r->w;
250 h = r->h;
251 RECTS_CLIP_TO_RECT(x, y, w, h,
252 obj->cur.cache.clip.x,
253 obj->cur.cache.clip.y,
254 obj->cur.cache.clip.w,
255 obj->cur.cache.clip.h);
256 if ((w > 0) && (h > 0))
257 obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output,
258 x, y, w, h);
259 /* get updates and clip to previous clip */
260 x = r->x;
261 y = r->y;
262 w = r->w;
263 h = r->h;
264 RECTS_CLIP_TO_RECT(x, y, w, h,
265 obj->prev.cache.clip.x,
266 obj->prev.cache.clip.y,
267 obj->prev.cache.clip.w,
268 obj->prev.cache.clip.h);
269 if ((w > 0) && (h > 0))
270 obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output,
271 x, y, w, h);
272 }
273 /* if the object is actually visible, take any parent clip changes */
274 if (is_v)
275 {
276 clipper = obj->cur.clipper;
277 while (clipper)
278 {
279 EINA_LIST_FOREACH(clipper->clip.changes, l, r)
280 {
281 /* get updates and clip to current clip */
282 x = r->x; y = r->y; w = r->w; h = r->h;
283 RECTS_CLIP_TO_RECT(x, y, w, h,
284 obj->cur.cache.clip.x,
285 obj->cur.cache.clip.y,
286 obj->cur.cache.clip.w,
287 obj->cur.cache.clip.h);
288 if ((w > 0) && (h > 0))
289 obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output,
290 x, y, w, h);
291 /* get updates and clip to previous clip */
292 x = r->x; y = r->y; w = r->w; h = r->h;
293 RECTS_CLIP_TO_RECT(x, y, w, h,
294 obj->prev.cache.clip.x,
295 obj->prev.cache.clip.y,
296 obj->prev.cache.clip.w,
297 obj->prev.cache.clip.h);
298 if ((w > 0) && (h > 0))
299 obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output,
300 x, y, w, h);
301 }
302 clipper = clipper->cur.clipper;
303 }
304 }
305 }
306 else
307 {
308 evas_object_clip_changes_clean(obj);
309 EINA_ARRAY_ITER_NEXT(rects, i, r, it)
310 obj->clip.changes = eina_list_append(obj->clip.changes, r);
311 eina_array_clean(rects);
312 }
313
314 end:
315 EINA_ARRAY_ITER_NEXT(rects, i, r, it)
316 eina_rectangle_free(r);
317 eina_array_clean(rects);
318}
319
320int
321evas_object_was_in_output_rect(Evas_Object *obj, int x, int y, int w, int h)
322{
323 if (obj->smart.smart) return 0;
324 /* assumes coords have been recalced */
325 if ((RECTS_INTERSECT(x, y, w, h,
326 obj->prev.cache.clip.x,
327 obj->prev.cache.clip.y,
328 obj->prev.cache.clip.w,
329 obj->prev.cache.clip.h)))
330 return 1;
331 return 0;
332}
333
334int
335evas_object_was_opaque(Evas_Object *obj)
336{
337 if (obj->smart.smart) return 0;
338 if (obj->prev.cache.clip.a == 255)
339 {
340 if (obj->func->was_opaque)
341 return obj->func->was_opaque(obj);
342 return 1;
343 }
344 return 0;
345}
346
347int
348evas_object_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
349{
350 if (obj->smart.smart) return 0;
351 if (obj->func->is_inside)
352 return obj->func->is_inside(obj, x, y);
353 return 0;
354}
355
356int
357evas_object_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
358{
359 if (obj->smart.smart) return 0;
360 if (obj->func->was_inside)
361 return obj->func->was_inside(obj, x, y);
362 return 0;
363}
364/* routines apps will call */
365
366EAPI void
367evas_object_ref(Evas_Object *obj)
368{
369 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
370 return;
371 MAGIC_CHECK_END();
372 obj->ref++;
373 if (obj->ref == 0) obj->ref--;
374}
375
376EAPI void
377evas_object_unref(Evas_Object *obj)
378{
379 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
380 return;
381 MAGIC_CHECK_END();
382 if (obj->ref == 0) return;
383 obj->ref--;
384 if ((obj->del_ref) && (obj->ref == 0)) evas_object_del(obj);
385}
386
387EAPI void
388evas_object_del(Evas_Object *obj)
389{
390 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
391 return;
392 MAGIC_CHECK_END();
393
394 if (obj->delete_me) return;
395
396 if (obj->ref > 0)
397 {
398 obj->del_ref = 1;
399 return;
400 }
401#ifdef EVAS_FRAME_QUEUING
402 evas_common_frameq_flush();
403#endif
404
405 evas_object_hide(obj);
406 if (obj->focused)
407 {
408 obj->focused = 0;
409 obj->layer->evas->focused = NULL;
410 _evas_object_event_new();
411 evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_OUT, NULL);
412 _evas_post_event_callback_call(obj->layer->evas);
413 }
414 _evas_object_event_new();
415 evas_object_event_callback_call(obj, EVAS_CALLBACK_DEL, NULL);
416 _evas_post_event_callback_call(obj->layer->evas);
417 if (obj->mouse_grabbed > 0)
418 obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed;
419 if ((obj->mouse_in) || (obj->mouse_grabbed > 0))
420 obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj);
421 obj->mouse_grabbed = 0;
422 obj->mouse_in = 0;
423 if (obj->name) evas_object_name_set(obj, NULL);
424 if (!obj->layer)
425 {
426 evas_object_free(obj, 1);
427 return;
428 }
429 obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed;
430 obj->mouse_grabbed = 0;
431 obj->mouse_in = 0;
432 evas_object_grabs_cleanup(obj);
433 while (obj->clip.clipees)
434 evas_object_clip_unset(obj->clip.clipees->data);
435 while (obj->proxy.proxies)
436 evas_object_image_source_unset(obj->proxy.proxies->data);
437 if (obj->cur.clipper) evas_object_clip_unset(obj);
438 if (obj->smart.smart) evas_object_smart_del(obj);
439 evas_object_map_set(obj, NULL);
440 _evas_object_event_new();
441 evas_object_event_callback_call(obj, EVAS_CALLBACK_FREE, NULL);
442 _evas_post_event_callback_call(obj->layer->evas);
443 evas_object_smart_cleanup(obj);
444 obj->delete_me = 1;
445 evas_object_change(obj);
446}
447
448EAPI void
449evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
450{
451 int is, was = 0, pass = 0, freeze = 0;
452
453 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
454 return;
455 MAGIC_CHECK_END();
456 if (obj->delete_me) return;
457 if (evas_object_intercept_call_move(obj, x, y)) return;
458 if (obj->doing.in_move > 0)
459 {
460 WRN("evas_object_move() called on object %p when in the middle of moving the same object", obj);
461 return;
462 }
463 if ((obj->cur.geometry.x == x) && (obj->cur.geometry.y == y)) return;
464 if (obj->layer->evas->events_frozen <= 0)
465 {
466 pass = evas_event_passes_through(obj);
467 freeze = evas_event_freezes_through(obj);
468 if ((!pass) && (!freeze))
469 was = evas_object_is_in_output_rect(obj,
470 obj->layer->evas->pointer.x,
471 obj->layer->evas->pointer.y, 1, 1);
472 }
473 obj->doing.in_move++;
474 if (obj->smart.smart)
475 {
476 if (obj->smart.smart->smart_class->move)
477 obj->smart.smart->smart_class->move(obj, x, y);
478 }
479 obj->cur.geometry.x = x;
480 obj->cur.geometry.y = y;
481//// obj->cur.cache.geometry.validity = 0;
482 obj->changed_move = 1;
483 evas_object_change(obj);
484 evas_object_clip_dirty(obj);
485 obj->doing.in_move--;
486 if (obj->layer->evas->events_frozen <= 0)
487 {
488 evas_object_recalc_clippees(obj);
489 if (!pass)
490 {
491 if (!obj->smart.smart)
492 {
493 is = evas_object_is_in_output_rect(obj,
494 obj->layer->evas->pointer.x,
495 obj->layer->evas->pointer.y, 1, 1);
496 if ((is ^ was) && obj->cur.visible)
497 evas_event_feed_mouse_move(obj->layer->evas,
498 obj->layer->evas->pointer.x,
499 obj->layer->evas->pointer.y,
500 obj->layer->evas->last_timestamp,
501 NULL);
502 }
503 }
504 }
505 evas_object_inform_call_move(obj);
506}
507
508EAPI void
509evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
510{
511 int is, was = 0, pass = 0, freeze =0;
512
513 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
514 return;
515 MAGIC_CHECK_END();
516 if (obj->delete_me) return;
517 if (w < 0) w = 0; if (h < 0) h = 0;
518 if (evas_object_intercept_call_resize(obj, w, h)) return;
519 if (obj->doing.in_resize > 0)
520 {
521 WRN("evas_object_resize() called on object %p when in the middle of resizing the same object", obj);
522 return;
523 }
524 if ((obj->cur.geometry.w == w) && (obj->cur.geometry.h == h)) return;
525 if (obj->layer->evas->events_frozen <= 0)
526 {
527 pass = evas_event_passes_through(obj);
528 freeze = evas_event_freezes_through(obj);
529 if ((!pass) && (!freeze))
530 was = evas_object_is_in_output_rect(obj,
531 obj->layer->evas->pointer.x,
532 obj->layer->evas->pointer.y, 1, 1);
533 }
534 obj->doing.in_resize++;
535 if (obj->smart.smart)
536 {
537 if (obj->smart.smart->smart_class->resize)
538 obj->smart.smart->smart_class->resize(obj, w, h);
539 }
540 obj->cur.geometry.w = w;
541 obj->cur.geometry.h = h;
542//// obj->cur.cache.geometry.validity = 0;
543 evas_object_change(obj);
544 evas_object_clip_dirty(obj);
545 obj->doing.in_resize--;
546 /* NB: evas_object_recalc_clippees was here previously ( < 08/07/2009) */
547 if (obj->layer->evas->events_frozen <= 0)
548 {
549 /* NB: If this creates glitches on screen then move to above position */
550 evas_object_recalc_clippees(obj);
551
552 // if (obj->func->coords_recalc) obj->func->coords_recalc(obj);
553 if (!pass)
554 {
555 if (!obj->smart.smart)
556 {
557 is = evas_object_is_in_output_rect(obj,
558 obj->layer->evas->pointer.x,
559 obj->layer->evas->pointer.y, 1, 1);
560 if ((is ^ was) && (obj->cur.visible))
561 evas_event_feed_mouse_move(obj->layer->evas,
562 obj->layer->evas->pointer.x,
563 obj->layer->evas->pointer.y,
564 obj->layer->evas->last_timestamp,
565 NULL);
566 }
567 }
568 }
569 evas_object_inform_call_resize(obj);
570}
571
572EAPI void
573evas_object_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
574{
575 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
576 if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0;
577 return;
578 MAGIC_CHECK_END();
579 if (obj->delete_me)
580 {
581 if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0;
582 return;
583 }
584 if (x) *x = obj->cur.geometry.x;
585 if (y) *y = obj->cur.geometry.y;
586 if (w) *w = obj->cur.geometry.w;
587 if (h) *h = obj->cur.geometry.h;
588}
589
590static void
591_evas_object_size_hint_alloc(Evas_Object *obj)
592{
593 if (obj->size_hints) return;
594
595 EVAS_MEMPOOL_INIT(_mp_sh, "evas_size_hints", Evas_Size_Hints, 512, );
596 obj->size_hints = EVAS_MEMPOOL_ALLOC(_mp_sh, Evas_Size_Hints);
597 if (!obj->size_hints) return;
598 EVAS_MEMPOOL_PREP(_mp_sh, obj->size_hints, Evas_Size_Hints);
599 obj->size_hints->max.w = -1;
600 obj->size_hints->max.h = -1;
601 obj->size_hints->align.x = 0.5;
602 obj->size_hints->align.y = 0.5;
603}
604
605EAPI void
606evas_object_size_hint_min_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
607{
608 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
609 if (w) *w = 0; if (h) *h = 0;
610 return;
611 MAGIC_CHECK_END();
612 if ((!obj->size_hints) || obj->delete_me)
613 {
614 if (w) *w = 0; if (h) *h = 0;
615 return;
616 }
617 if (w) *w = obj->size_hints->min.w;
618 if (h) *h = obj->size_hints->min.h;
619}
620
621EAPI void
622evas_object_size_hint_min_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
623{
624 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
625 return;
626 MAGIC_CHECK_END();
627 if (obj->delete_me)
628 return;
629 _evas_object_size_hint_alloc(obj);
630 if ((obj->size_hints->min.w == w) && (obj->size_hints->min.h == h)) return;
631 obj->size_hints->min.w = w;
632 obj->size_hints->min.h = h;
633
634 evas_object_inform_call_changed_size_hints(obj);
635}
636
637EAPI void
638evas_object_size_hint_max_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
639{
640 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
641 if (w) *w = -1; if (h) *h = -1;
642 return;
643 MAGIC_CHECK_END();
644 if ((!obj->size_hints) || obj->delete_me)
645 {
646 if (w) *w = -1; if (h) *h = -1;
647 return;
648 }
649 if (w) *w = obj->size_hints->max.w;
650 if (h) *h = obj->size_hints->max.h;
651}
652
653EAPI void
654evas_object_size_hint_max_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
655{
656 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
657 return;
658 MAGIC_CHECK_END();
659 if (obj->delete_me)
660 return;
661 _evas_object_size_hint_alloc(obj);
662 if ((obj->size_hints->max.w == w) && (obj->size_hints->max.h == h)) return;
663 obj->size_hints->max.w = w;
664 obj->size_hints->max.h = h;
665
666 evas_object_inform_call_changed_size_hints(obj);
667}
668
669EAPI void
670evas_object_size_hint_request_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
671{
672 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
673 if (w) *w = 0; if (h) *h = 0;
674 return;
675 MAGIC_CHECK_END();
676 if ((!obj->size_hints) || obj->delete_me)
677 {
678 if (w) *w = 0; if (h) *h = 0;
679 return;
680 }
681 if (w) *w = obj->size_hints->request.w;
682 if (h) *h = obj->size_hints->request.h;
683}
684
685EAPI void
686evas_object_size_hint_request_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
687{
688 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
689 return;
690 MAGIC_CHECK_END();
691 if (obj->delete_me)
692 return;
693 _evas_object_size_hint_alloc(obj);
694 if ((obj->size_hints->request.w == w) && (obj->size_hints->request.h == h)) return;
695 obj->size_hints->request.w = w;
696 obj->size_hints->request.h = h;
697
698 evas_object_inform_call_changed_size_hints(obj);
699}
700
701EAPI void
702evas_object_size_hint_aspect_get(const Evas_Object *obj, Evas_Aspect_Control *aspect, Evas_Coord *w, Evas_Coord *h)
703{
704 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
705 if (aspect) *aspect = EVAS_ASPECT_CONTROL_NONE;
706 if (w) *w = 0; if (h) *h = 0;
707 return;
708 MAGIC_CHECK_END();
709 if ((!obj->size_hints) || obj->delete_me)
710 {
711 if (aspect) *aspect = EVAS_ASPECT_CONTROL_NONE;
712 if (w) *w = 0; if (h) *h = 0;
713 return;
714 }
715 if (aspect) *aspect = obj->size_hints->aspect.mode;
716 if (w) *w = obj->size_hints->aspect.size.w;
717 if (h) *h = obj->size_hints->aspect.size.h;
718}
719
720EAPI void
721evas_object_size_hint_aspect_set(Evas_Object *obj, Evas_Aspect_Control aspect, Evas_Coord w, Evas_Coord h)
722{
723 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
724 return;
725 MAGIC_CHECK_END();
726 if (obj->delete_me)
727 return;
728 _evas_object_size_hint_alloc(obj);
729 if ((obj->size_hints->aspect.mode == aspect) && (obj->size_hints->aspect.size.w == w) && (obj->size_hints->aspect.size.h == h)) return;
730 obj->size_hints->aspect.mode = aspect;
731 obj->size_hints->aspect.size.w = w;
732 obj->size_hints->aspect.size.h = h;
733
734 evas_object_inform_call_changed_size_hints(obj);
735}
736
737EAPI void
738evas_object_size_hint_align_get(const Evas_Object *obj, double *x, double *y)
739{
740 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
741 if (x) *x = 0.5; if (y) *y = 0.5;
742 return;
743 MAGIC_CHECK_END();
744 if ((!obj->size_hints) || obj->delete_me)
745 {
746 if (x) *x = 0.5; if (y) *y = 0.5;
747 return;
748 }
749 if (x) *x = obj->size_hints->align.x;
750 if (y) *y = obj->size_hints->align.y;
751}
752
753EAPI void
754evas_object_size_hint_align_set(Evas_Object *obj, double x, double y)
755{
756 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
757 return;
758 MAGIC_CHECK_END();
759 if (obj->delete_me)
760 return;
761 _evas_object_size_hint_alloc(obj);
762 if ((obj->size_hints->align.x == x) && (obj->size_hints->align.y == y)) return;
763 obj->size_hints->align.x = x;
764 obj->size_hints->align.y = y;
765
766 evas_object_inform_call_changed_size_hints(obj);
767}
768
769EAPI void
770evas_object_size_hint_weight_get(const Evas_Object *obj, double *x, double *y)
771{
772 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
773 if (x) *x = 0.0; if (y) *y = 0.0;
774 return;
775 MAGIC_CHECK_END();
776 if ((!obj->size_hints) || obj->delete_me)
777 {
778 if (x) *x = 0.0; if (y) *y = 0.0;
779 return;
780 }
781 if (x) *x = obj->size_hints->weight.x;
782 if (y) *y = obj->size_hints->weight.y;
783}
784
785EAPI void
786evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y)
787{
788 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
789 return;
790 MAGIC_CHECK_END();
791 if (obj->delete_me)
792 return;
793 _evas_object_size_hint_alloc(obj);
794 if ((obj->size_hints->weight.x == x) && (obj->size_hints->weight.y == y)) return;
795 obj->size_hints->weight.x = x;
796 obj->size_hints->weight.y = y;
797
798 evas_object_inform_call_changed_size_hints(obj);
799}
800
801EAPI void
802evas_object_size_hint_padding_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
803{
804 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
805 if (l) *l = 0; if (r) *r = 0;
806 if (t) *t = 0; if (b) *b = 0;
807 return;
808 MAGIC_CHECK_END();
809 if ((!obj->size_hints) || obj->delete_me)
810 {
811 if (l) *l = 0; if (r) *r = 0;
812 if (t) *t = 0; if (b) *b = 0;
813 return;
814 }
815 if (l) *l = obj->size_hints->padding.l;
816 if (r) *r = obj->size_hints->padding.r;
817 if (t) *t = obj->size_hints->padding.t;
818 if (b) *b = obj->size_hints->padding.b;
819}
820
821EAPI void
822evas_object_size_hint_padding_set(Evas_Object *obj, Evas_Coord l, Evas_Coord r, Evas_Coord t, Evas_Coord b)
823{
824 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
825 return;
826 MAGIC_CHECK_END();
827 if (obj->delete_me)
828 return;
829 _evas_object_size_hint_alloc(obj);
830 if ((obj->size_hints->padding.l == l) && (obj->size_hints->padding.r == r) && (obj->size_hints->padding.t == t) && (obj->size_hints->padding.b == b)) return;
831 obj->size_hints->padding.l = l;
832 obj->size_hints->padding.r = r;
833 obj->size_hints->padding.t = t;
834 obj->size_hints->padding.b = b;
835
836 evas_object_inform_call_changed_size_hints(obj);
837}
838
839EAPI void
840evas_object_show(Evas_Object *obj)
841{
842 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
843 return;
844 MAGIC_CHECK_END();
845 if (obj->delete_me) return;
846 if (evas_object_intercept_call_show(obj)) return;
847 if (obj->smart.smart)
848 {
849 if (obj->smart.smart->smart_class->show)
850 obj->smart.smart->smart_class->show(obj);
851 }
852 if (obj->cur.visible)
853 {
854 return;
855 }
856 obj->cur.visible = 1;
857 evas_object_change(obj);
858 evas_object_clip_dirty(obj);
859 if (obj->layer->evas->events_frozen <= 0)
860 {
861 evas_object_clip_across_clippees_check(obj);
862 evas_object_recalc_clippees(obj);
863 if ((!evas_event_passes_through(obj)) &&
864 (!evas_event_freezes_through(obj)))
865 {
866 if (!obj->smart.smart)
867 {
868 if (evas_object_is_in_output_rect(obj,
869 obj->layer->evas->pointer.x,
870 obj->layer->evas->pointer.y, 1, 1))
871 evas_event_feed_mouse_move(obj->layer->evas,
872 obj->layer->evas->pointer.x,
873 obj->layer->evas->pointer.y,
874 obj->layer->evas->last_timestamp,
875 NULL);
876 }
877 }
878 }
879 evas_object_inform_call_show(obj);
880}
881
882EAPI void
883evas_object_hide(Evas_Object *obj)
884{
885 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
886 return;
887 MAGIC_CHECK_END();
888 if (obj->delete_me) return;
889 if (evas_object_intercept_call_hide(obj)) return;
890 if (obj->smart.smart)
891 {
892 if (obj->smart.smart->smart_class->hide)
893 obj->smart.smart->smart_class->hide(obj);
894 }
895 if (!obj->cur.visible)
896 {
897 return;
898 }
899 obj->cur.visible = 0;
900 evas_object_change(obj);
901 evas_object_clip_dirty(obj);
902 if (obj->layer->evas->events_frozen <= 0)
903 {
904 evas_object_clip_across_clippees_check(obj);
905 evas_object_recalc_clippees(obj);
906 if ((!evas_event_passes_through(obj)) &&
907 (!evas_event_freezes_through(obj)))
908 {
909 if ((!obj->smart.smart) ||
910 ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap)))
911 {
912 if (!obj->mouse_grabbed)
913 {
914 if (evas_object_is_in_output_rect(obj,
915 obj->layer->evas->pointer.x,
916 obj->layer->evas->pointer.y, 1, 1))
917 evas_event_feed_mouse_move(obj->layer->evas,
918 obj->layer->evas->pointer.x,
919 obj->layer->evas->pointer.y,
920 obj->layer->evas->last_timestamp,
921 NULL);
922 }
923/* this is at odds to handling events when an obj is moved out of the mouse
924 * ore resized out or clipped out. if mouse is grabbed - regardless of
925 * visibility, mouse move events should keep happening and mouse up.
926 * for better or worse it's at least consistent.
927 if (obj->delete_me) return;
928 if (obj->mouse_grabbed > 0)
929 obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed;
930 if ((obj->mouse_in) || (obj->mouse_grabbed > 0))
931 obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj);
932 obj->mouse_grabbed = 0;
933 if (obj->layer->evas->events_frozen > 0)
934 {
935 obj->mouse_in = 0;
936 return;
937 }
938 if (obj->mouse_in)
939 {
940 Evas_Event_Mouse_Out ev;
941
942 _evas_object_event_new();
943
944 obj->mouse_in = 0;
945 ev.buttons = obj->layer->evas->pointer.button;
946 ev.output.x = obj->layer->evas->pointer.x;
947 ev.output.y = obj->layer->evas->pointer.y;
948 ev.canvas.x = obj->layer->evas->pointer.x;
949 ev.canvas.y = obj->layer->evas->pointer.y;
950 ev.data = NULL;
951 ev.modifiers = &(obj->layer->evas->modifiers);
952 ev.locks = &(obj->layer->evas->locks);
953 ev.timestamp = obj->layer->evas->last_timestamp;
954 ev.event_flags = EVAS_EVENT_FLAG_NONE;
955 evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev);
956 _evas_post_event_callback_call(obj->layer->evas);
957 }
958 */
959 }
960 }
961 }
962 else
963 {
964/*
965 if (obj->mouse_grabbed > 0)
966 obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed;
967 if ((obj->mouse_in) || (obj->mouse_grabbed > 0))
968 obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj);
969 obj->mouse_grabbed = 0;
970 obj->mouse_in = 0;
971 */
972 }
973 evas_object_inform_call_hide(obj);
974}
975
976EAPI Eina_Bool
977evas_object_visible_get(const Evas_Object *obj)
978{
979 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
980 return 0;
981 MAGIC_CHECK_END();
982 if (obj->delete_me) return 0;
983 return obj->cur.visible;
984}
985
986EAPI void
987evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a)
988{
989 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
990 return;
991 MAGIC_CHECK_END();
992 if (obj->delete_me) return;
993 if (r > 255) r = 255; if (r < 0) r = 0;
994 if (g > 255) g = 255; if (g < 0) g = 0;
995 if (b > 255) b = 255; if (b < 0) b = 0;
996 if (a > 255) a = 255; if (a < 0) a = 0;
997 if (evas_object_intercept_call_color_set(obj, r, g, b, a)) return;
998 if (obj->smart.smart)
999 {
1000 if (obj->smart.smart->smart_class->color_set)
1001 obj->smart.smart->smart_class->color_set(obj, r, g, b, a);
1002 }
1003 if ((obj->cur.color.r == r) &&
1004 (obj->cur.color.g == g) &&
1005 (obj->cur.color.b == b) &&
1006 (obj->cur.color.a == a)) return;
1007 obj->cur.color.r = r;
1008 obj->cur.color.g = g;
1009 obj->cur.color.b = b;
1010 evas_object_clip_dirty(obj);
1011 if ((obj->cur.color.a == 0) && (a == 0) && (obj->cur.render_op == EVAS_RENDER_BLEND)) return;
1012 obj->cur.color.a = a;
1013 evas_object_change(obj);
1014}
1015
1016EAPI void
1017evas_object_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1018{
1019 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1020 if (r) *r = 0; if (g) *g = 0; if (b) *b = 0; if (a) *a = 0;
1021 return;
1022 MAGIC_CHECK_END();
1023 if (obj->delete_me)
1024 {
1025 if (r) *r = 0; if (g) *g = 0; if (b) *b = 0; if (a) *a = 0;
1026 return;
1027 }
1028 if (r) *r = obj->cur.color.r;
1029 if (g) *g = obj->cur.color.g;
1030 if (b) *b = obj->cur.color.b;
1031 if (a) *a = obj->cur.color.a;
1032}
1033
1034EAPI void
1035evas_object_anti_alias_set(Evas_Object *obj, Eina_Bool anti_alias)
1036{
1037 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1038 return;
1039 MAGIC_CHECK_END();
1040 if (obj->delete_me) return;
1041 anti_alias = !!anti_alias;
1042 if (obj->cur.anti_alias == anti_alias)return;
1043 obj->cur.anti_alias = anti_alias;
1044 evas_object_change(obj);
1045}
1046
1047EAPI Eina_Bool
1048evas_object_anti_alias_get(const Evas_Object *obj)
1049{
1050 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1051 return 0;
1052 MAGIC_CHECK_END();
1053 if (obj->delete_me) return 0;
1054 return obj->cur.anti_alias;
1055}
1056
1057EAPI void
1058evas_object_scale_set(Evas_Object *obj, double scale)
1059{
1060 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1061 return;
1062 MAGIC_CHECK_END();
1063 if (obj->delete_me) return;
1064 if (obj->cur.scale == scale) return;
1065 obj->cur.scale = scale;
1066 evas_object_change(obj);
1067 if (obj->func->scale_update) obj->func->scale_update(obj);
1068}
1069
1070EAPI double
1071evas_object_scale_get(const Evas_Object *obj)
1072{
1073 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1074 return 0;
1075 MAGIC_CHECK_END();
1076 if (obj->delete_me) return 1.0;
1077 return obj->cur.scale;
1078}
1079
1080EAPI void
1081evas_object_render_op_set(Evas_Object *obj, Evas_Render_Op render_op)
1082{
1083 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1084 return;
1085 MAGIC_CHECK_END();
1086 if (obj->delete_me) return;
1087 if ((Evas_Render_Op)obj->cur.render_op == render_op)
1088 return;
1089 obj->cur.render_op = render_op;
1090 evas_object_change(obj);
1091}
1092
1093EAPI Evas_Render_Op
1094evas_object_render_op_get(const Evas_Object *obj)
1095{
1096 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1097 return 0;
1098 MAGIC_CHECK_END();
1099 if (obj->delete_me) return EVAS_RENDER_BLEND;
1100 return obj->cur.render_op;
1101}
1102
1103EAPI Evas *
1104evas_object_evas_get(const Evas_Object *obj)
1105{
1106 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1107 return NULL;
1108 MAGIC_CHECK_END();
1109 if (obj->delete_me) return NULL;
1110 return obj->layer->evas;
1111}
1112
1113EAPI Evas_Object *
1114evas_object_top_at_xy_get(const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects)
1115{
1116 Evas_Layer *lay;
1117 int xx, yy;
1118
1119 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1120 return NULL;
1121 MAGIC_CHECK_END();
1122 xx = x;
1123 yy = y;
1124//// xx = evas_coord_world_x_to_screen(e, x);
1125//// yy = evas_coord_world_y_to_screen(e, y);
1126 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay)
1127 {
1128 Evas_Object *obj;
1129
1130 EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj)
1131 {
1132 if (obj->delete_me) continue;
1133 if ((!include_pass_events_objects) &&
1134 (evas_event_passes_through(obj))) continue;
1135 if ((!include_hidden_objects) && (!obj->cur.visible)) continue;
1136 evas_object_clip_recalc(obj);
1137 if ((evas_object_is_in_output_rect(obj, xx, yy, 1, 1)) &&
1138 (!obj->clip.clipees))
1139 return obj;
1140 }
1141 }
1142 return NULL;
1143}
1144
1145EAPI Evas_Object *
1146evas_object_top_at_pointer_get(const Evas *e)
1147{
1148 return evas_object_top_at_xy_get(e, e->pointer.x, e->pointer.y, EINA_TRUE,
1149 EINA_TRUE);
1150}
1151
1152EAPI Evas_Object *
1153evas_object_top_in_rectangle_get(const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects)
1154{
1155 Evas_Layer *lay;
1156 int xx, yy, ww, hh;
1157
1158 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1159 return NULL;
1160 MAGIC_CHECK_END();
1161 xx = x;
1162 yy = y;
1163 ww = w;
1164 hh = h;
1165//// xx = evas_coord_world_x_to_screen(e, x);
1166//// yy = evas_coord_world_y_to_screen(e, y);
1167//// ww = evas_coord_world_x_to_screen(e, w);
1168//// hh = evas_coord_world_y_to_screen(e, h);
1169 if (ww < 1) ww = 1;
1170 if (hh < 1) hh = 1;
1171 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay)
1172 {
1173 Evas_Object *obj;
1174
1175 EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj)
1176 {
1177 if (obj->delete_me) continue;
1178 if ((!include_pass_events_objects) &&
1179 (evas_event_passes_through(obj))) continue;
1180 if ((!include_hidden_objects) && (!obj->cur.visible)) continue;
1181 evas_object_clip_recalc(obj);
1182 if ((evas_object_is_in_output_rect(obj, xx, yy, ww, hh)) &&
1183 (!obj->clip.clipees))
1184 return obj;
1185 }
1186 }
1187 return NULL;
1188}
1189
1190EAPI Eina_List *
1191evas_objects_at_xy_get(const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects)
1192{
1193 Eina_List *in = NULL;
1194 Evas_Layer *lay;
1195 int xx, yy;
1196
1197 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1198 return NULL;
1199 MAGIC_CHECK_END();
1200 xx = x;
1201 yy = y;
1202//// xx = evas_coord_world_x_to_screen(e, x);
1203//// yy = evas_coord_world_y_to_screen(e, y);
1204 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay)
1205 {
1206 Evas_Object *obj;
1207
1208 EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj)
1209 {
1210 if (obj->delete_me) continue;
1211 if ((!include_pass_events_objects) &&
1212 (evas_event_passes_through(obj))) continue;
1213 if ((!include_hidden_objects) && (!obj->cur.visible)) continue;
1214 evas_object_clip_recalc(obj);
1215 if ((evas_object_is_in_output_rect(obj, xx, yy, 1, 1)) &&
1216 (!obj->clip.clipees))
1217 in = eina_list_prepend(in, obj);
1218 }
1219 }
1220 return in;
1221}
1222
1223/**
1224 * Retrieves the objects in the given rectangle region
1225 * @param e The given evas object.
1226 * @param x The horizontal coordinate.
1227 * @param y The vertical coordinate.
1228 * @param w The width size.
1229 * @param h The height size.
1230 * @param include_pass_events_objects Boolean Flag to include or not pass events objects
1231 * @param include_hidden_objects Boolean Flag to include or not hidden objects
1232 * @return The list of evas object in the rectangle region.
1233 *
1234 */
1235EAPI Eina_List *
1236evas_objects_in_rectangle_get(const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects)
1237{
1238 Eina_List *in = NULL;
1239 Evas_Layer *lay;
1240 int xx, yy, ww, hh;
1241
1242 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1243 return NULL;
1244 MAGIC_CHECK_END();
1245 xx = x;
1246 yy = y;
1247 ww = w;
1248 hh = h;
1249//// xx = evas_coord_world_x_to_screen(e, x);
1250//// yy = evas_coord_world_y_to_screen(e, y);
1251//// ww = evas_coord_world_x_to_screen(e, w);
1252//// hh = evas_coord_world_y_to_screen(e, h);
1253 if (ww < 1) ww = 1;
1254 if (hh < 1) hh = 1;
1255 EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay)
1256 {
1257 Evas_Object *obj;
1258
1259 EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj)
1260 {
1261 if (obj->delete_me) continue;
1262 if ((!include_pass_events_objects) &&
1263 (evas_event_passes_through(obj))) continue;
1264 if ((!include_hidden_objects) && (!obj->cur.visible)) continue;
1265 evas_object_clip_recalc(obj);
1266 if ((evas_object_is_in_output_rect(obj, xx, yy, ww, hh)) &&
1267 (!obj->clip.clipees))
1268 in = eina_list_prepend(in, obj);
1269 }
1270 }
1271 return in;
1272}
1273
1274EAPI const char *
1275evas_object_type_get(const Evas_Object *obj)
1276{
1277 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1278 return NULL;
1279 MAGIC_CHECK_END();
1280 if (obj->delete_me) return "";
1281 return obj->type;
1282}
1283
1284EAPI void
1285evas_object_precise_is_inside_set(Evas_Object *obj, Eina_Bool precise)
1286{
1287 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1288 return;
1289 MAGIC_CHECK_END();
1290 obj->precise_is_inside = precise;
1291}
1292
1293EAPI Eina_Bool
1294evas_object_precise_is_inside_get(const Evas_Object *obj)
1295{
1296 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1297 return 0;
1298 MAGIC_CHECK_END();
1299 return obj->precise_is_inside;
1300}
1301
1302EAPI void
1303evas_object_static_clip_set(Evas_Object *obj, Eina_Bool is_static_clip)
1304{
1305 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1306 return;
1307 MAGIC_CHECK_END();
1308 obj->is_static_clip = is_static_clip;
1309}
1310
1311EAPI Eina_Bool
1312evas_object_static_clip_get(const Evas_Object *obj)
1313{
1314 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1315 return 0;
1316 MAGIC_CHECK_END();
1317 return obj->is_static_clip;
1318}
1319
diff --git a/libraries/evas/src/lib/canvas/evas_object_polygon.c b/libraries/evas/src/lib/canvas/evas_object_polygon.c
new file mode 100644
index 0000000..cbc1802
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_polygon.c
@@ -0,0 +1,554 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private magic number for polygon objects */
5static const char o_type[] = "polygon";
6
7/* private struct for line object internal data */
8typedef struct _Evas_Object_Polygon Evas_Object_Polygon;
9typedef struct _Evas_Polygon_Point Evas_Polygon_Point;
10
11struct _Evas_Object_Polygon
12{
13 DATA32 magic;
14 Eina_List *points;
15 void *engine_data;
16 struct {
17 int x, y;
18 } offset;
19 Evas_Coord_Rectangle geometry;
20 char changed : 1;
21};
22
23struct _Evas_Polygon_Point
24{
25 Evas_Coord x, y;
26};
27
28/* private methods for polygon objects */
29static void evas_object_polygon_init(Evas_Object *obj);
30static void *evas_object_polygon_new(void);
31static void evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
32static void evas_object_polygon_free(Evas_Object *obj);
33static void evas_object_polygon_render_pre(Evas_Object *obj);
34static void evas_object_polygon_render_post(Evas_Object *obj);
35
36static unsigned int evas_object_polygon_id_get(Evas_Object *obj);
37static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj);
38static void *evas_object_polygon_engine_data_get(Evas_Object *obj);
39
40static int evas_object_polygon_is_opaque(Evas_Object *obj);
41static int evas_object_polygon_was_opaque(Evas_Object *obj);
42static int evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
43static int evas_object_polygon_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
44
45static const Evas_Object_Func object_func =
46{
47 /* methods (compulsory) */
48 evas_object_polygon_free,
49 evas_object_polygon_render,
50 evas_object_polygon_render_pre,
51 evas_object_polygon_render_post,
52 evas_object_polygon_id_get,
53 evas_object_polygon_visual_id_get,
54 evas_object_polygon_engine_data_get,
55 /* these are optional. NULL = nothing */
56 NULL,
57 NULL,
58 NULL,
59 NULL,
60 evas_object_polygon_is_opaque,
61 evas_object_polygon_was_opaque,
62 evas_object_polygon_is_inside,
63 evas_object_polygon_was_inside,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL
69};
70
71/* the actual api call to add a rect */
72/* it has no other api calls as all properties are standard */
73
74EVAS_MEMPOOL(_mp_obj);
75
76EAPI Evas_Object *
77evas_object_polygon_add(Evas *e)
78{
79 Evas_Object *obj;
80
81 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
82 return NULL;
83 MAGIC_CHECK_END();
84 obj = evas_object_new(e);
85 evas_object_polygon_init(obj);
86 evas_object_inject(obj, e);
87 return obj;
88}
89
90EAPI void
91evas_object_polygon_point_add(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
92{
93 Evas_Object_Polygon *o;
94 Evas_Polygon_Point *p;
95 Evas_Coord min_x, max_x, min_y, max_y;
96 int is, was = 0;
97
98 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
99 return;
100 MAGIC_CHECK_END();
101 o = (Evas_Object_Polygon *)(obj->object_data);
102 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
103 return;
104 MAGIC_CHECK_END();
105
106 if (obj->layer->evas->events_frozen <= 0)
107 {
108 if (!evas_event_passes_through(obj) &&
109 !evas_event_freezes_through(obj))
110 was = evas_object_is_in_output_rect(obj,
111 obj->layer->evas->pointer.x,
112 obj->layer->evas->pointer.y,
113 1, 1);
114 }
115 if (!o->points)
116 {
117 o->offset.x = obj->cur.geometry.x;
118 o->offset.y = obj->cur.geometry.y;
119 }
120 else
121 {
122 /* Update all points and take offset into account. */
123 Eina_List *over;
124
125 EINA_LIST_FOREACH(o->points, over, p)
126 {
127 p->x += o->offset.x;
128 p->y += o->offset.y;
129 }
130 }
131
132 p = malloc(sizeof(Evas_Polygon_Point));
133 if (!p) return;
134 p->x = x + o->offset.x;
135 p->y = y + o->offset.y;
136
137 if (!o->points)
138 {
139 obj->cur.geometry.x = p->x;
140 obj->cur.geometry.y = p->y;
141 obj->cur.geometry.w = 2;
142 obj->cur.geometry.h = 2;
143 }
144 else
145 {
146 if (p->x < obj->cur.geometry.x) min_x = p->x;
147 else min_x = obj->cur.geometry.x;
148 if (p->x > (obj->cur.geometry.x + obj->cur.geometry.w - 2))
149 max_x = p->x;
150 else max_x = obj->cur.geometry.x + obj->cur.geometry.w - 2;
151 if (p->y < obj->cur.geometry.y) min_y = p->y;
152 else min_y = obj->cur.geometry.y;
153 if (p->y > (obj->cur.geometry.y + obj->cur.geometry.h - 2))
154 max_y = p->y;
155 else max_y = obj->cur.geometry.y + obj->cur.geometry.h - 2;
156 obj->cur.geometry.x = min_x;
157 obj->cur.geometry.y = min_y;
158 obj->cur.geometry.w = max_x - min_x + 2;
159 obj->cur.geometry.h = max_y - min_y + 2;
160 }
161 o->points = eina_list_append(o->points, p);
162
163 o->geometry = obj->cur.geometry;
164 o->offset.x = 0;
165 o->offset.y = 0;
166
167 //// obj->cur.cache.geometry.validity = 0;
168 o->changed = EINA_TRUE;
169 evas_object_change(obj);
170 evas_object_clip_dirty(obj);
171 evas_object_coords_recalc(obj);
172 if (obj->layer->evas->events_frozen <= 0)
173 {
174 is = evas_object_is_in_output_rect(obj,
175 obj->layer->evas->pointer.x,
176 obj->layer->evas->pointer.y, 1, 1);
177 if (!evas_event_passes_through(obj) &&
178 !evas_event_freezes_through(obj) )
179 {
180 if ((is ^ was) && obj->cur.visible)
181 evas_event_feed_mouse_move(obj->layer->evas,
182 obj->layer->evas->pointer.x,
183 obj->layer->evas->pointer.y,
184 obj->layer->evas->last_timestamp,
185 NULL);
186 }
187 }
188 evas_object_inform_call_move(obj);
189 evas_object_inform_call_resize(obj);
190}
191
192EAPI void
193evas_object_polygon_points_clear(Evas_Object *obj)
194{
195 Evas_Object_Polygon *o;
196 int is, was;
197
198 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
199 return;
200 MAGIC_CHECK_END();
201 o = (Evas_Object_Polygon *)(obj->object_data);
202 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
203 return;
204 MAGIC_CHECK_END();
205 was = evas_object_is_in_output_rect(obj,
206 obj->layer->evas->pointer.x,
207 obj->layer->evas->pointer.y, 1, 1);
208 while (o->points)
209 {
210 free(o->points->data);
211 o->points = eina_list_remove(o->points, o->points->data);
212 }
213 obj->cur.geometry.x = 0;
214 obj->cur.geometry.y = 0;
215 obj->cur.geometry.w = 0;
216 obj->cur.geometry.h = 0;
217 //// obj->cur.cache.geometry.validity = 0;
218 o->changed = EINA_TRUE;
219 evas_object_change(obj);
220 evas_object_clip_dirty(obj);
221 evas_object_coords_recalc(obj);
222 is = evas_object_is_in_output_rect(obj,
223 obj->layer->evas->pointer.x,
224 obj->layer->evas->pointer.y, 1, 1);
225 if ((is || was) && obj->cur.visible)
226 evas_event_feed_mouse_move(obj->layer->evas,
227 obj->layer->evas->pointer.x,
228 obj->layer->evas->pointer.y,
229 obj->layer->evas->last_timestamp,
230 NULL);
231 evas_object_inform_call_move(obj);
232 evas_object_inform_call_resize(obj);
233}
234
235/* all nice and private */
236static void
237evas_object_polygon_init(Evas_Object *obj)
238{
239 /* alloc image ob, setup methods and default values */
240 obj->object_data = evas_object_polygon_new();
241 /* set up default settings for this kind of object */
242 obj->cur.color.r = 255;
243 obj->cur.color.g = 255;
244 obj->cur.color.b = 255;
245 obj->cur.color.a = 255;
246 obj->cur.geometry.x = 0;
247 obj->cur.geometry.y = 0;
248 obj->cur.geometry.w = 0;
249 obj->cur.geometry.h = 0;
250 obj->cur.layer = 0;
251 /* set up object-specific settings */
252 obj->prev = obj->cur;
253 /* set up methods (compulsory) */
254 obj->func = &object_func;
255 obj->type = o_type;
256}
257
258static void *
259evas_object_polygon_new(void)
260{
261 Evas_Object_Polygon *o;
262
263 /* alloc obj private data */
264 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_polygon", Evas_Object_Polygon, 32, NULL);
265 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Polygon);
266 if (!o) return NULL;
267 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Polygon);
268 o->magic = MAGIC_OBJ_POLYGON;
269 return o;
270}
271
272static void
273evas_object_polygon_free(Evas_Object *obj)
274{
275 Evas_Object_Polygon *o;
276
277 /* frees private object data. very simple here */
278 o = (Evas_Object_Polygon *)(obj->object_data);
279 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
280 return;
281 MAGIC_CHECK_END();
282 /* free obj */
283 while (o->points)
284 {
285 free(o->points->data);
286 o->points = eina_list_remove(o->points, o->points->data);
287 }
288 o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output,
289 obj->layer->evas->engine.data.context,
290 o->engine_data);
291 o->magic = 0;
292 EVAS_MEMPOOL_FREE(_mp_obj, o);
293}
294
295static void
296evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
297{
298 Evas_Object_Polygon *o;
299 Eina_List *l;
300 Evas_Polygon_Point *p;
301
302 /* render object to surface with context, and offxet by x,y */
303 o = (Evas_Object_Polygon *)(obj->object_data);
304 obj->layer->evas->engine.func->context_color_set(output,
305 context,
306 obj->cur.cache.clip.r,
307 obj->cur.cache.clip.g,
308 obj->cur.cache.clip.b,
309 obj->cur.cache.clip.a);
310 obj->layer->evas->engine.func->context_multiplier_unset(output,
311 context);
312 obj->layer->evas->engine.func->context_render_op_set(output, context,
313 obj->cur.render_op);
314 if (o->changed)
315 {
316 o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output,
317 obj->layer->evas->engine.data.context,
318 o->engine_data);
319 EINA_LIST_FOREACH(o->points, l, p)
320 {
321 //px = evas_coord_world_x_to_screen(obj->layer->evas, p->x);
322 //py = evas_coord_world_y_to_screen(obj->layer->evas, p->y);
323 o->engine_data = obj->layer->evas->engine.func->polygon_point_add(obj->layer->evas->engine.data.output,
324 obj->layer->evas->engine.data.context,
325 o->engine_data,
326 p->x, p->y);
327 }
328 }
329
330 if (o->engine_data)
331 obj->layer->evas->engine.func->polygon_draw(output,
332 context,
333 surface,
334 o->engine_data,
335 o->offset.x + x, o->offset.y + y);
336}
337
338static void
339evas_object_polygon_render_pre(Evas_Object *obj)
340{
341 Evas_Object_Polygon *o;
342 int is_v, was_v;
343
344 /* dont pre-render the obj twice! */
345 if (obj->pre_render_done) return;
346 obj->pre_render_done = 1;
347 /* pre-render phase. this does anything an object needs to do just before */
348 /* rendering. this could mean loading the image data, retrieving it from */
349 /* elsewhere, decoding video etc. */
350 /* then when this is done the object needs to figure if it changed and */
351 /* if so what and where and add the appropriate redraw lines */
352 o = (Evas_Object_Polygon *)(obj->object_data);
353 /* if someone is clipping this obj - go calculate the clipper */
354 if (obj->cur.clipper)
355 {
356 if (obj->cur.cache.clip.dirty)
357 evas_object_clip_recalc(obj->cur.clipper);
358 obj->cur.clipper->func->render_pre(obj->cur.clipper);
359 }
360 /* now figure what changed and add draw rects */
361 /* if it just became visible or invisible */
362 is_v = evas_object_is_visible(obj);
363 was_v = evas_object_was_visible(obj);
364 if (is_v != was_v)
365 {
366 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
367 goto done;
368 }
369 if ((obj->cur.map != obj->prev.map) ||
370 (obj->cur.usemap != obj->prev.usemap))
371 {
372 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
373 goto done;
374 }
375 /* it's not visible - we accounted for it appearing or not so just abort */
376 if (!is_v) goto done;
377 /* clipper changed this is in addition to anything else for obj */
378 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
379 /* if we restacked (layer or just within a layer) */
380 if (obj->restack)
381 {
382 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
383 goto done;
384 }
385 /* if it changed render op */
386 if (obj->cur.render_op != obj->prev.render_op)
387 {
388 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
389 goto done;
390 }
391 /* if it changed color */
392 if ((obj->cur.color.r != obj->prev.color.r) ||
393 (obj->cur.color.g != obj->prev.color.g) ||
394 (obj->cur.color.b != obj->prev.color.b) ||
395 (obj->cur.color.a != obj->prev.color.a))
396 {
397 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
398 goto done;
399 }
400 /* if it changed geometry - and obviously not visibility or color */
401 /* calculate differences since we have a constant color fill */
402 /* we really only need to update the differences */
403 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
404 (obj->cur.geometry.y != obj->prev.geometry.y) ||
405 (obj->cur.geometry.w != obj->prev.geometry.w) ||
406 (obj->cur.geometry.h != obj->prev.geometry.h) ||
407 (o->changed))
408 {
409 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
410 goto done;
411 }
412 done:
413 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
414 (obj->cur.geometry.y != obj->prev.geometry.y))
415 {
416 if (!o->changed)
417 {
418 o->offset.x += obj->cur.geometry.x - obj->prev.geometry.x;
419 o->offset.y += obj->cur.geometry.y - obj->prev.geometry.y;
420 }
421 else
422 {
423 o->offset.x += obj->cur.geometry.x - o->geometry.x;
424 o->offset.y += obj->cur.geometry.y - o->geometry.y;
425 }
426 }
427 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
428}
429
430static void
431evas_object_polygon_render_post(Evas_Object *obj)
432{
433 Evas_Object_Polygon *o;
434
435 /* this moves the current data to the previous state parts of the object */
436 /* in whatever way is safest for the object. also if we don't need object */
437 /* data anymore we can free it if the object deems this is a good idea */
438 o = (Evas_Object_Polygon *)(obj->object_data);
439 /* remove those pesky changes */
440 evas_object_clip_changes_clean(obj);
441 /* move cur to prev safely for object data */
442 obj->prev = obj->cur;
443 o->changed = 0;
444}
445
446static unsigned int evas_object_polygon_id_get(Evas_Object *obj)
447{
448 Evas_Object_Polygon *o;
449
450 o = (Evas_Object_Polygon *)(obj->object_data);
451 if (!o) return 0;
452 return MAGIC_OBJ_POLYGON;
453}
454
455static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj)
456{
457 Evas_Object_Polygon *o;
458
459 o = (Evas_Object_Polygon *)(obj->object_data);
460 if (!o) return 0;
461 return MAGIC_OBJ_SHAPE;
462}
463
464static void *evas_object_polygon_engine_data_get(Evas_Object *obj)
465{
466 Evas_Object_Polygon *o;
467
468 o = (Evas_Object_Polygon *)(obj->object_data);
469 if (!o) return NULL;
470 return o->engine_data;
471}
472
473static int
474evas_object_polygon_is_opaque(Evas_Object *obj __UNUSED__)
475{
476 /* this returns 1 if the internal object data implies that the object is */
477 /* currently fully opaque over the entire line it occupies */
478 return 0;
479}
480
481static int
482evas_object_polygon_was_opaque(Evas_Object *obj __UNUSED__)
483{
484 /* this returns 1 if the internal object data implies that the object was */
485 /* previously fully opaque over the entire line it occupies */
486 return 0;
487}
488
489/* We count the number of edges a "ray" 90 degs upwards from our point
490 * intersects with. If it's even, we are outside of the polygon, if it's odd,
491 * we are inside of it. */
492static int
493evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
494{
495 Evas_Object_Polygon *o;
496 int num_edges = 0; /* Number of edges we crossed */
497 Eina_List *itr;
498 Evas_Polygon_Point *p;
499
500 o = (Evas_Object_Polygon *)(obj->object_data);
501 if (!o) return 0;
502 if (!o->points) return 0;
503
504 /* Adjust X and Y according to current geometry */
505 x -= o->offset.x;
506 y -= o->offset.y;
507
508 if (eina_list_count(o->points) == 1)
509 {
510 p = eina_list_data_get(o->points);
511 return ((p->x == x) && (p->y == y));
512 }
513
514 EINA_LIST_FOREACH(o->points, itr, p)
515 {
516 Evas_Coord line_y;
517 Eina_List *next = eina_list_next(itr);
518 Evas_Polygon_Point *p_next;
519 /* Get the next, or if there's no next, take the first */
520 if (next)
521 {
522 p_next = eina_list_data_get(next);
523 }
524 else
525 {
526 p_next = eina_list_data_get(o->points);
527 }
528
529 /* Make sure that we are directly below the edge,
530 * and that p->x != p_next->x */
531 if (((p->x < p_next->x) && (p->x <= x) && (x < p_next->x)) ||
532 ((p->x > p_next->x) && (p_next->x < x) && (x <= p->x)))
533 {
534 line_y = ((double) (p->y - p_next->y) /
535 (double) (p->x - p_next->x)) *
536 (x - p_next->x) + p_next->y;
537 /* We crossed that edge if the line is directly above us */
538 if (line_y < y)
539 num_edges++;
540 }
541 }
542
543 /* Return true if num_edges is odd */
544 return ((num_edges % 2) == 1);
545}
546
547static int
548evas_object_polygon_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
549{
550 /* this returns 1 if the canvas co-ordinates were inside the object based */
551 /* on object private data. not much use for rects, but for polys, images */
552 /* and other complex objects it might be */
553 return 1;
554}
diff --git a/libraries/evas/src/lib/canvas/evas_object_rectangle.c b/libraries/evas/src/lib/canvas/evas_object_rectangle.c
new file mode 100644
index 0000000..36678e7
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_rectangle.c
@@ -0,0 +1,387 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private magic number for rectangle objects */
5static const char o_type[] = "rectangle";
6
7const char *o_rect_type = o_type;
8
9/* private struct for rectangle object internal data */
10typedef struct _Evas_Object_Rectangle Evas_Object_Rectangle;
11
12struct _Evas_Object_Rectangle
13{
14 DATA32 magic;
15 void *engine_data;
16};
17
18/* private methods for rectangle objects */
19static void evas_object_rectangle_init(Evas_Object *obj);
20static void *evas_object_rectangle_new(void);
21static void evas_object_rectangle_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
22static void evas_object_rectangle_free(Evas_Object *obj);
23static void evas_object_rectangle_render_pre(Evas_Object *obj);
24static void evas_object_rectangle_render_post(Evas_Object *obj);
25
26static unsigned int evas_object_rectangle_id_get(Evas_Object *obj);
27static unsigned int evas_object_rectangle_visual_id_get(Evas_Object *obj);
28static void *evas_object_rectangle_engine_data_get(Evas_Object *obj);
29
30static int evas_object_rectangle_is_opaque(Evas_Object *obj);
31static int evas_object_rectangle_was_opaque(Evas_Object *obj);
32
33#if 0 /* usless calls for a rect object. much more useful for images etc. */
34static void evas_object_rectangle_store(Evas_Object *obj);
35static void evas_object_rectangle_unstore(Evas_Object *obj);
36static int evas_object_rectangle_is_visible(Evas_Object *obj);
37static int evas_object_rectangle_was_visible(Evas_Object *obj);
38static int evas_object_rectangle_is_inside(Evas_Object *obj, double x, double y);
39static int evas_object_rectangle_was_inside(Evas_Object *obj, double x, double y);
40#endif
41
42static const Evas_Object_Func object_func =
43{
44 /* methods (compulsory) */
45 evas_object_rectangle_free,
46 evas_object_rectangle_render,
47 evas_object_rectangle_render_pre,
48 evas_object_rectangle_render_post,
49 evas_object_rectangle_id_get,
50 evas_object_rectangle_visual_id_get,
51 evas_object_rectangle_engine_data_get,
52 /* these are optional. NULL = nothing */
53 NULL,
54 NULL,
55 NULL,
56 NULL,
57 evas_object_rectangle_is_opaque,
58 evas_object_rectangle_was_opaque,
59 NULL,
60 NULL,
61 NULL,
62 NULL,
63 NULL,
64 NULL,
65 NULL
66};
67
68/* the actual api call to add a rect */
69/* it has no other api calls as all properties are standard */
70
71EVAS_MEMPOOL(_mp_obj);
72
73EAPI Evas_Object *
74evas_object_rectangle_add(Evas *e)
75{
76 Evas_Object *obj;
77
78 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
79 return NULL;
80 MAGIC_CHECK_END();
81 obj = evas_object_new(e);
82 evas_object_rectangle_init(obj);
83 evas_object_inject(obj, e);
84 return obj;
85}
86
87/* all nice and private */
88static void
89evas_object_rectangle_init(Evas_Object *obj)
90{
91 /* alloc image ob, setup methods and default values */
92 obj->object_data = evas_object_rectangle_new();
93 /* set up default settings for this kind of object */
94 obj->cur.color.r = 255;
95 obj->cur.color.g = 255;
96 obj->cur.color.b = 255;
97 obj->cur.color.a = 255;
98 obj->cur.geometry.x = 0;
99 obj->cur.geometry.y = 0;
100 obj->cur.geometry.w = 0;
101 obj->cur.geometry.h = 0;
102 obj->cur.layer = 0;
103 obj->cur.render_op = EVAS_RENDER_BLEND;
104 /* set up object-specific settings */
105 obj->prev = obj->cur;
106 /* set up methods (compulsory) */
107 obj->func = &object_func;
108 obj->type = o_type;
109}
110
111static void *
112evas_object_rectangle_new(void)
113{
114 Evas_Object_Rectangle *o;
115
116 /* alloc obj private data */
117 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_rectangle", Evas_Object_Rectangle, 256, NULL);
118 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Rectangle);
119 if (!o) return NULL;
120 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Rectangle);
121 o->magic = MAGIC_OBJ_RECTANGLE;
122 return o;
123}
124
125static void
126evas_object_rectangle_free(Evas_Object *obj)
127{
128 Evas_Object_Rectangle *o;
129
130 /* frees private object data. very simple here */
131 o = (Evas_Object_Rectangle *)(obj->object_data);
132 MAGIC_CHECK(o, Evas_Object_Rectangle, MAGIC_OBJ_RECTANGLE);
133 return;
134 MAGIC_CHECK_END();
135 /* free obj */
136 o->magic = 0;
137 EVAS_MEMPOOL_FREE(_mp_obj, o);
138}
139
140static void
141evas_object_rectangle_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
142{
143 /* render object to surface with context, and offxet by x,y */
144 obj->layer->evas->engine.func->context_color_set(output,
145 context,
146 obj->cur.cache.clip.r,
147 obj->cur.cache.clip.g,
148 obj->cur.cache.clip.b,
149 obj->cur.cache.clip.a);
150 obj->layer->evas->engine.func->context_multiplier_unset(output,
151 context);
152 obj->layer->evas->engine.func->context_render_op_set(output, context,
153 obj->cur.render_op);
154 obj->layer->evas->engine.func->rectangle_draw(output,
155 context,
156 surface,
157 obj->cur.geometry.x + x,
158 obj->cur.geometry.y + y,
159 obj->cur.geometry.w,
160 obj->cur.geometry.h);
161//// obj->cur.cache.geometry.x + x,
162//// obj->cur.cache.geometry.y + y,
163//// obj->cur.cache.geometry.w,
164//// obj->cur.cache.geometry.h);
165}
166
167static void
168evas_object_rectangle_render_pre(Evas_Object *obj)
169{
170 int is_v, was_v;
171
172 /* dont pre-render the obj twice! */
173 if (obj->pre_render_done) return;
174 obj->pre_render_done = 1;
175 /* pre-render phase. this does anything an object needs to do just before */
176 /* rendering. this could mean loading the image data, retrieving it from */
177 /* elsewhere, decoding video etc. */
178 /* then when this is done the object needs to figure if it changed and */
179 /* if so what and where and add the appropriate redraw rectangles */
180 /* if someone is clipping this obj - go calculate the clipper */
181 if (obj->cur.clipper)
182 {
183 if (obj->cur.cache.clip.dirty)
184 evas_object_clip_recalc(obj->cur.clipper);
185 obj->cur.clipper->func->render_pre(obj->cur.clipper);
186 }
187 /* now figure what changed and add draw rects */
188 /* if it just became visible or invisible */
189 is_v = evas_object_is_visible(obj);
190 was_v = evas_object_was_visible(obj);
191 if (!(is_v | was_v)) goto done;
192 if (is_v != was_v)
193 {
194 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
195 goto done;
196 }
197 if ((obj->cur.map != obj->prev.map) ||
198 (obj->cur.usemap != obj->prev.usemap))
199 {
200 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
201 goto done;
202 }
203 /* it's not visible - we accounted for it appearing or not so just abort */
204 if (!is_v) goto done;
205 /* clipper changed this is in addition to anything else for obj */
206 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
207 /* if we restacked (layer or just within a layer) and don't clip anyone */
208 if ((obj->restack) && (!obj->clip.clipees))
209 {
210 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
211 goto done;
212 }
213 /* if it changed render op */
214 if (obj->cur.render_op != obj->prev.render_op)
215 {
216 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
217 goto done;
218 }
219 /* if it changed color */
220 if ((obj->cur.color.r != obj->prev.color.r) ||
221 (obj->cur.color.g != obj->prev.color.g) ||
222 (obj->cur.color.b != obj->prev.color.b) ||
223 (obj->cur.color.a != obj->prev.color.a))
224 {
225 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
226 goto done;
227 }
228 /* if it changed geometry - and obviously not visibility or color */
229 /* calculate differences since we have a constant color fill */
230 /* we really only need to update the differences */
231 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
232 (obj->cur.geometry.y != obj->prev.geometry.y) ||
233 (obj->cur.geometry.w != obj->prev.geometry.w) ||
234 (obj->cur.geometry.h != obj->prev.geometry.h))
235 {
236 evas_rects_return_difference_rects(&obj->layer->evas->clip_changes,
237 obj->cur.geometry.x,
238 obj->cur.geometry.y,
239 obj->cur.geometry.w,
240 obj->cur.geometry.h,
241 obj->prev.geometry.x,
242 obj->prev.geometry.y,
243 obj->prev.geometry.w,
244 obj->prev.geometry.h);
245//// rl = evas_rects_return_difference_rects(obj->cur.cache.geometry.x,
246//// obj->cur.cache.geometry.y,
247//// obj->cur.cache.geometry.w,
248//// obj->cur.cache.geometry.h,
249//// obj->prev.cache.geometry.x,
250//// obj->prev.cache.geometry.y,
251//// obj->prev.cache.geometry.w,
252//// obj->prev.cache.geometry.h);
253 goto done;
254 }
255 /* it obviously didn't change - add a NO obscure - this "unupdates" this */
256 /* area so if there were updates for it they get wiped. don't do it if we */
257 /* arent fully opaque and we are visible */
258 /*
259 if (evas_object_is_visible(obj) &&
260 evas_object_is_opaque(obj) &&
261 (!obj->clip.clipees))
262 obj->layer->evas->engine.func->output_redraws_rect_del(obj->layer->evas->engine.data.output,
263 obj->cur.cache.clip.x,
264 obj->cur.cache.clip.y,
265 obj->cur.cache.clip.w,
266 obj->cur.cache.clip.h);
267 */
268 done:
269 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
270}
271
272static void
273evas_object_rectangle_render_post(Evas_Object *obj)
274{
275
276 /* this moves the current data to the previous state parts of the object */
277 /* in whatever way is safest for the object. also if we don't need object */
278 /* data anymore we can free it if the object deems this is a good idea */
279 /* remove those pesky changes */
280 evas_object_clip_changes_clean(obj);
281 /* move cur to prev safely for object data */
282 obj->prev = obj->cur;
283}
284
285static int
286evas_object_rectangle_is_opaque(Evas_Object *obj)
287{
288 /* this returns 1 if the internal object data implies that the object is */
289 /* currently fully opaque over the entire rectangle it occupies */
290 if ((obj->cur.map) && (obj->cur.usemap)) return 0;
291 if (obj->cur.render_op == EVAS_RENDER_COPY)
292 return 1;
293 if (obj->cur.render_op != EVAS_RENDER_BLEND)
294 return 0;
295 return 1;
296}
297
298static int
299evas_object_rectangle_was_opaque(Evas_Object *obj)
300{
301 /* this returns 1 if the internal object data implies that the object was */
302 /* previously fully opaque over the entire rectangle it occupies */
303 if (obj->prev.render_op == EVAS_RENDER_COPY)
304 return 1;
305 if (obj->prev.render_op != EVAS_RENDER_BLEND)
306 return 0;
307 return 1;
308}
309
310static unsigned int evas_object_rectangle_id_get(Evas_Object *obj)
311{
312 Evas_Object_Rectangle *o;
313
314 o = (Evas_Object_Rectangle *)(obj->object_data);
315 if (!o) return 0;
316 return MAGIC_OBJ_RECTANGLE;
317}
318
319static unsigned int evas_object_rectangle_visual_id_get(Evas_Object *obj)
320{
321 Evas_Object_Rectangle *o;
322
323 o = (Evas_Object_Rectangle *)(obj->object_data);
324 if (!o) return 0;
325 return MAGIC_OBJ_SHAPE;
326}
327
328static void *evas_object_rectangle_engine_data_get(Evas_Object *obj)
329{
330 Evas_Object_Rectangle *o;
331
332 o = (Evas_Object_Rectangle *)(obj->object_data);
333 if (!o) return NULL;
334 return o->engine_data;
335}
336
337
338#if 0 /* usless calls for a rect object. much more useful for images etc. */
339static void
340evas_object_rectangle_store(Evas_Object *obj)
341{
342 /* store... nothing for rectangle objects... it's a bit silly */
343 /* but for others that may have expensive caluclations to do to */
344 /* generate the object data, hint that they might want to be pre-calced */
345 /* once and stored */
346}
347
348static void
349evas_object_rectangle_unstore(Evas_Object *obj)
350{
351 /* store... nothing for rectangle objects... it's a bit silly */
352}
353
354static int
355evas_object_rectangle_is_visible(Evas_Object *obj)
356{
357 /* this returns 1 if the internal object data would imply that it is */
358 /* visible (ie drawing it draws something. this is not to do with events */
359 return 1;
360}
361
362static int
363evas_object_rectangle_was_visible(Evas_Object *obj)
364{
365 /* this returns 1 if the internal object data would imply that it was */
366 /* visible (ie drawing it draws something. this is not to do with events */
367 return 1;
368}
369
370static int
371evas_object_rectangle_is_inside(Evas_Object *obj, double x, double y)
372{
373 /* this returns 1 if the canvas co-ordinates are inside the object based */
374 /* on object private data. not much use for rects, but for polys, images */
375 /* and other complex objects it might be */
376 return 1;
377}
378
379static int
380evas_object_rectangle_was_inside(Evas_Object *obj, double x, double y)
381{
382 /* this returns 1 if the canvas co-ordinates were inside the object based */
383 /* on object private data. not much use for rects, but for polys, images */
384 /* and other complex objects it might be */
385 return 1;
386}
387#endif
diff --git a/libraries/evas/src/lib/canvas/evas_object_smart.c b/libraries/evas/src/lib/canvas/evas_object_smart.c
new file mode 100644
index 0000000..a7dfcdf
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_smart.c
@@ -0,0 +1,920 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4typedef struct _Evas_Object_Smart Evas_Object_Smart;
5typedef struct _Evas_Smart_Callback Evas_Smart_Callback;
6
7struct _Evas_Object_Smart
8{
9 DATA32 magic;
10 void *engine_data;
11 void *data;
12 Eina_List *callbacks;
13 Eina_Inlist *contained;
14 Evas_Smart_Cb_Description_Array callbacks_descriptions;
15 int walking_list;
16 Eina_Bool deletions_waiting : 1;
17 Eina_Bool need_recalculate : 1;
18};
19
20struct _Evas_Smart_Callback
21{
22 const char *event;
23 Evas_Smart_Cb func;
24 void *func_data;
25 Evas_Callback_Priority priority;
26 char delete_me : 1;
27};
28
29/* private methods for smart objects */
30static void evas_object_smart_callbacks_clear(Evas_Object *obj);
31static void evas_object_smart_init(Evas_Object *obj);
32static void *evas_object_smart_new(void);
33static void evas_object_smart_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
34static void evas_object_smart_free(Evas_Object *obj);
35static void evas_object_smart_render_pre(Evas_Object *obj);
36static void evas_object_smart_render_post(Evas_Object *obj);
37
38static unsigned int evas_object_smart_id_get(Evas_Object *obj);
39static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj);
40static void *evas_object_smart_engine_data_get(Evas_Object *obj);
41
42static const Evas_Object_Func object_func =
43{
44 /* methods (compulsory) */
45 evas_object_smart_free,
46 evas_object_smart_render,
47 evas_object_smart_render_pre,
48 evas_object_smart_render_post,
49 evas_object_smart_id_get,
50 evas_object_smart_visual_id_get,
51 evas_object_smart_engine_data_get,
52 /* these are optional. NULL = nothing */
53 NULL,
54 NULL,
55 NULL,
56 NULL,
57 NULL,
58 NULL,
59 NULL,
60 NULL,
61 NULL,
62 NULL,
63 NULL,
64 NULL,
65 NULL
66};
67
68EVAS_MEMPOOL(_mp_obj);
69EVAS_MEMPOOL(_mp_cb);
70
71/* public funcs */
72EAPI void
73evas_object_smart_data_set(Evas_Object *obj, void *data)
74{
75 Evas_Object_Smart *o;
76
77 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
78 return;
79 MAGIC_CHECK_END();
80 o = (Evas_Object_Smart *)(obj->object_data);
81 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
82 return;
83 MAGIC_CHECK_END();
84 o->data = data;
85}
86
87EAPI void *
88evas_object_smart_data_get(const Evas_Object *obj)
89{
90 Evas_Object_Smart *o;
91
92 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
93 return NULL;
94 MAGIC_CHECK_END();
95 o = (Evas_Object_Smart *)(obj->object_data);
96 if (!o) return NULL;
97 return o->data;
98}
99
100EAPI Evas_Smart *
101evas_object_smart_smart_get(const Evas_Object *obj)
102{
103 Evas_Object_Smart *o;
104
105 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
106 return NULL;
107 MAGIC_CHECK_END();
108 o = (Evas_Object_Smart *)(obj->object_data);
109 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
110 return NULL;
111 MAGIC_CHECK_END();
112 return obj->smart.smart;
113}
114
115EAPI void
116evas_object_smart_member_add(Evas_Object *obj, Evas_Object *smart_obj)
117{
118 Evas_Object_Smart *o;
119
120 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
121 return;
122 MAGIC_CHECK_END();
123 MAGIC_CHECK(smart_obj, Evas_Object, MAGIC_OBJ);
124 return;
125 MAGIC_CHECK_END();
126 o = (Evas_Object_Smart *)(smart_obj->object_data);
127 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
128 return;
129 MAGIC_CHECK_END();
130
131 if (obj->delete_me)
132 {
133 CRIT("Adding deleted object %p to smart obj %p", obj, smart_obj);
134 abort();
135 return;
136 }
137 if (smart_obj->delete_me)
138 {
139 CRIT("Adding object %p to deleted smart obj %p", obj, smart_obj);
140 abort();
141 return;
142 }
143 if (!smart_obj->layer)
144 {
145 CRIT("No evas surface associated with smart object (%p)", smart_obj);
146 abort();
147 return;
148 }
149 if ((obj->layer && smart_obj->layer) &&
150 (obj->layer->evas != smart_obj->layer->evas))
151 {
152 CRIT("Adding object %p from Evas (%p) from another Evas (%p)", obj, obj->layer->evas, smart_obj->layer->evas);
153 abort();
154 return;
155 }
156
157 if (obj->smart.parent == smart_obj) return;
158
159 if (obj->smart.parent) evas_object_smart_member_del(obj);
160
161 evas_object_release(obj, 1);
162 obj->layer = smart_obj->layer;
163 obj->cur.layer = obj->layer->layer;
164 obj->layer->usage++;
165 obj->smart.parent = smart_obj;
166 o->contained = eina_inlist_append(o->contained, EINA_INLIST_GET(obj));
167 evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE);
168 obj->restack = 1;
169 evas_object_change(obj);
170 evas_object_mapped_clip_across_mark(obj);
171 if (smart_obj->smart.smart->smart_class->member_add)
172 smart_obj->smart.smart->smart_class->member_add(smart_obj, obj);
173}
174
175EAPI void
176evas_object_smart_member_del(Evas_Object *obj)
177{
178 Evas_Object_Smart *o;
179 Evas_Object *smart_obj;
180
181 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
182 return;
183 MAGIC_CHECK_END();
184
185 if (!obj->smart.parent) return;
186
187 smart_obj = obj->smart.parent;
188 if (smart_obj->smart.smart->smart_class->member_del)
189 smart_obj->smart.smart->smart_class->member_del(smart_obj, obj);
190
191 o = (Evas_Object_Smart *)(obj->smart.parent->object_data);
192 o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(obj));
193 obj->smart.parent = NULL;
194 evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE);
195 obj->layer->usage--;
196 obj->cur.layer = obj->layer->layer;
197 evas_object_inject(obj, obj->layer->evas);
198 obj->restack = 1;
199 evas_object_change(obj);
200 evas_object_mapped_clip_across_mark(obj);
201}
202
203EAPI Evas_Object *
204evas_object_smart_parent_get(const Evas_Object *obj)
205{
206 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
207 return NULL;
208 MAGIC_CHECK_END();
209
210 return obj->smart.parent;
211}
212
213EAPI Eina_Bool
214evas_object_smart_type_check(const Evas_Object *obj, const char *type)
215{
216 const Evas_Smart_Class *sc;
217
218 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
219 return EINA_FALSE;
220 MAGIC_CHECK_END();
221
222 if (!obj->smart.smart)
223 return EINA_FALSE;
224 sc = obj->smart.smart->smart_class;
225 while (sc)
226 {
227 if (!strcmp(sc->name, type))
228 return EINA_TRUE;
229 sc = sc->parent;
230 }
231
232 return EINA_FALSE;
233}
234
235EAPI Eina_Bool
236evas_object_smart_type_check_ptr(const Evas_Object *obj, const char *type)
237{
238 const Evas_Smart_Class *sc;
239
240 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
241 return EINA_FALSE;
242 MAGIC_CHECK_END();
243
244 if (!obj->smart.smart)
245 return EINA_FALSE;
246 sc = obj->smart.smart->smart_class;
247 while (sc)
248 {
249 if (sc->name == type)
250 return EINA_TRUE;
251 sc = sc->parent;
252 }
253
254 return EINA_FALSE;
255}
256
257EAPI Eina_List *
258evas_object_smart_members_get(const Evas_Object *obj)
259{
260 Evas_Object_Smart *o;
261 Eina_List *members;
262 Eina_Inlist *member;
263
264 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
265 return NULL;
266 MAGIC_CHECK_END();
267 o = (Evas_Object_Smart *)(obj->object_data);
268 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
269 return NULL;
270 MAGIC_CHECK_END();
271
272 members = NULL;
273 for (member = o->contained; member; member = member->next)
274 members = eina_list_append(members, member);
275
276 return members;
277}
278
279const Eina_Inlist *
280evas_object_smart_members_get_direct(const Evas_Object *obj)
281{
282 Evas_Object_Smart *o;
283
284 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
285 return NULL;
286 MAGIC_CHECK_END();
287 o = (Evas_Object_Smart *)(obj->object_data);
288 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
289 return NULL;
290 MAGIC_CHECK_END();
291 return o->contained;
292}
293
294void
295_evas_object_smart_members_all_del(Evas_Object *obj)
296{
297 Evas_Object_Smart *o = (Evas_Object_Smart *)(obj->object_data);
298 while (o->contained)
299 evas_object_del((Evas_Object *)(o->contained));
300}
301
302EAPI Evas_Object *
303evas_object_smart_add(Evas *e, Evas_Smart *s)
304{
305 Evas_Object *obj;
306
307 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
308 return NULL;
309 MAGIC_CHECK_END();
310 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
311 return NULL;
312 MAGIC_CHECK_END();
313
314 obj = evas_object_new(e);
315 if (!obj) return NULL;
316 obj->smart.smart = s;
317 obj->type = s->smart_class->name;
318 evas_object_smart_init(obj);
319 evas_object_inject(obj, e);
320
321 evas_object_smart_use(s);
322
323 if (s->smart_class->add) s->smart_class->add(obj);
324
325 return obj;
326}
327
328static int
329_callback_priority_cmp(const void *_a, const void *_b)
330{
331 const Evas_Smart_Callback *a, *b;
332 a = (const Evas_Smart_Callback *) _a;
333 b = (const Evas_Smart_Callback *) _b;
334 if (a->priority < b->priority)
335 return -1;
336 else
337 return 1;
338}
339
340EAPI void
341evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data)
342{
343 evas_object_smart_callback_priority_add(obj, event,
344 EVAS_CALLBACK_PRIORITY_DEFAULT, func, data);
345}
346
347EAPI void
348evas_object_smart_callback_priority_add(Evas_Object *obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data)
349{
350 Evas_Object_Smart *o;
351 Evas_Smart_Callback *cb;
352
353 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
354 return;
355 MAGIC_CHECK_END();
356 o = (Evas_Object_Smart *)(obj->object_data);
357 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
358 return;
359 MAGIC_CHECK_END();
360 if (!event) return;
361 if (!func) return;
362 EVAS_MEMPOOL_INIT(_mp_cb, "evas_smart_callback", Evas_Smart_Callback, 512, );
363 cb = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Smart_Callback);
364 if (!cb) return;
365 EVAS_MEMPOOL_PREP(_mp_cb, cb, Evas_Smart_Callback);
366 cb->event = eina_stringshare_add(event);
367 cb->func = func;
368 cb->func_data = (void *)data;
369 cb->priority = priority;
370 o->callbacks = eina_list_sorted_insert(o->callbacks, _callback_priority_cmp,
371 cb);
372}
373
374EAPI void *
375evas_object_smart_callback_del(Evas_Object *obj, const char *event, Evas_Smart_Cb func)
376{
377 Evas_Object_Smart *o;
378 Eina_List *l;
379 Evas_Smart_Callback *cb;
380
381 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
382 return NULL;
383 MAGIC_CHECK_END();
384 o = (Evas_Object_Smart *)(obj->object_data);
385 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
386 return NULL;
387 MAGIC_CHECK_END();
388 if (!event) return NULL;
389 EINA_LIST_FOREACH(o->callbacks, l, cb)
390 {
391 if ((!strcmp(cb->event, event)) && (cb->func == func))
392 {
393 void *data;
394
395 data = cb->func_data;
396 cb->delete_me = 1;
397 o->deletions_waiting = 1;
398 evas_object_smart_callbacks_clear(obj);
399 return data;
400 }
401 }
402 return NULL;
403}
404
405EAPI void
406evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *event_info)
407{
408 Evas_Object_Smart *o;
409 Eina_List *l;
410 Evas_Smart_Callback *cb;
411 const char *strshare;
412
413 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
414 return;
415 MAGIC_CHECK_END();
416 o = (Evas_Object_Smart *)(obj->object_data);
417 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
418 return;
419 MAGIC_CHECK_END();
420 if (!event) return;
421 if (obj->delete_me) return;
422 o->walking_list++;
423 strshare = eina_stringshare_add(event);
424 EINA_LIST_FOREACH(o->callbacks, l, cb)
425 {
426 if (!cb->delete_me)
427 {
428 if (cb->event == strshare)
429 cb->func(cb->func_data, obj, event_info);
430 }
431 if (obj->delete_me)
432 break;
433 }
434 eina_stringshare_del(strshare);
435 o->walking_list--;
436 evas_object_smart_callbacks_clear(obj);
437}
438
439EAPI Eina_Bool
440evas_object_smart_callbacks_descriptions_set(Evas_Object *obj, const Evas_Smart_Cb_Description *descriptions)
441{
442 const Evas_Smart_Cb_Description *d;
443 Evas_Object_Smart *o;
444 unsigned int i, count = 0;
445
446 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
447 return EINA_FALSE;
448 MAGIC_CHECK_END();
449 o = (Evas_Object_Smart *)(obj->object_data);
450 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
451 return EINA_FALSE;
452 MAGIC_CHECK_END();
453
454 if ((!descriptions) || (!descriptions->name))
455 {
456 evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
457 return EINA_TRUE;
458 }
459
460 for (count = 0, d = descriptions; d->name; d++)
461 count++;
462
463 evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, count);
464 if (count == 0) return EINA_TRUE;
465
466 for (i = 0, d = descriptions; i < count; d++, i++)
467 o->callbacks_descriptions.array[i] = d;
468
469 evas_smart_cb_descriptions_fix(&o->callbacks_descriptions);
470
471 return EINA_TRUE;
472}
473
474EAPI void
475evas_object_smart_callbacks_descriptions_get(const Evas_Object *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count)
476{
477 Evas_Object_Smart *o;
478
479 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
480 if (class_descriptions) *class_descriptions = NULL;
481 if (class_count) *class_count = 0;
482 if (instance_descriptions) *instance_descriptions = NULL;
483 if (instance_count) *instance_count = 0;
484 return;
485 MAGIC_CHECK_END();
486 o = (Evas_Object_Smart *)(obj->object_data);
487 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
488 if (class_descriptions) *class_descriptions = NULL;
489 if (class_count) *class_count = 0;
490 if (instance_descriptions) *instance_descriptions = NULL;
491 if (instance_count) *instance_count = 0;
492 return;
493 MAGIC_CHECK_END();
494
495 if (class_descriptions)
496 *class_descriptions = obj->smart.smart->callbacks.array;
497 if (class_count)
498 *class_count = obj->smart.smart->callbacks.size;
499
500 if (instance_descriptions)
501 *instance_descriptions = o->callbacks_descriptions.array;
502 if (instance_count)
503 *instance_count = o->callbacks_descriptions.size;
504}
505
506EAPI void
507evas_object_smart_callback_description_find(const Evas_Object *obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description)
508{
509 Evas_Object_Smart *o;
510
511 if (!name)
512 {
513 if (class_description) *class_description = NULL;
514 if (instance_description) *instance_description = NULL;
515 return;
516 }
517
518 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
519 if (class_description) *class_description = NULL;
520 if (instance_description) *instance_description = NULL;
521 return;
522 MAGIC_CHECK_END();
523 o = (Evas_Object_Smart *)(obj->object_data);
524 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
525 if (class_description) *class_description = NULL;
526 if (instance_description) *instance_description = NULL;
527 return;
528 MAGIC_CHECK_END();
529
530 if (class_description)
531 *class_description = evas_smart_cb_description_find
532 (&obj->smart.smart->callbacks, name);
533
534 if (instance_description)
535 *instance_description = evas_smart_cb_description_find
536 (&o->callbacks_descriptions, name);
537}
538
539EAPI void
540evas_object_smart_need_recalculate_set(Evas_Object *obj, Eina_Bool value)
541{
542 Evas_Object_Smart *o;
543 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
544 return;
545 MAGIC_CHECK_END();
546 o = obj->object_data;
547 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
548 return;
549 MAGIC_CHECK_END();
550
551 // XXX: do i need this?
552 if (obj->delete_me) return;
553
554 /* remove this entry from calc_list or processed list */
555 if (eina_clist_element_is_linked(&obj->calc_entry))
556 eina_clist_remove(&obj->calc_entry);
557
558 value = !!value;
559 if (value)
560 eina_clist_add_tail(&obj->layer->evas->calc_list, &obj->calc_entry);
561 else
562 eina_clist_add_tail(&obj->layer->evas->calc_done, &obj->calc_entry);
563
564 if (o->need_recalculate == value) return;
565
566 if (obj->recalculate_cycle > 254)
567 {
568 ERR("Object %p is not stable during recalc loop", obj);
569 return;
570 }
571 if (obj->layer->evas->in_smart_calc) obj->recalculate_cycle++;
572 o->need_recalculate = value;
573}
574
575EAPI Eina_Bool
576evas_object_smart_need_recalculate_get(const Evas_Object *obj)
577{
578 Evas_Object_Smart *o;
579 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
580 return EINA_FALSE;
581 MAGIC_CHECK_END();
582 o = obj->object_data;
583 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
584 return EINA_FALSE;
585 MAGIC_CHECK_END();
586
587 return o->need_recalculate;
588}
589
590EAPI void
591evas_object_smart_calculate(Evas_Object *obj)
592{
593 Evas_Object_Smart *o;
594 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
595 return;
596 MAGIC_CHECK_END();
597 o = obj->object_data;
598 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
599 return;
600 MAGIC_CHECK_END();
601
602 if (!obj->smart.smart->smart_class->calculate)
603 return;
604
605 o->need_recalculate = 0;
606 obj->smart.smart->smart_class->calculate(obj);
607}
608
609EAPI void
610evas_smart_objects_calculate(Evas *e)
611{
612 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
613 return;
614 MAGIC_CHECK_END();
615 evas_call_smarts_calculate(e);
616}
617
618EAPI int
619evas_smart_objects_calculate_count_get(const Evas *e)
620{
621 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
622 return 0;
623 MAGIC_CHECK_END();
624 return e->smart_calc_count;
625}
626
627/**
628 * Call calculate() on all smart objects that need_recalculate.
629 *
630 * @internal
631 */
632void
633evas_call_smarts_calculate(Evas *e)
634{
635 Eina_Clist *elem;
636 Evas_Object *obj;
637
638// printf("+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALC-----------v\n");
639 evas_event_freeze(e);
640 e->in_smart_calc++;
641
642 while (NULL != (elem = eina_clist_head(&e->calc_list)))
643 {
644 Evas_Object_Smart *o;
645
646 /* move the item to the processed list */
647 obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry);
648 eina_clist_remove(&obj->calc_entry);
649 if (obj->delete_me) continue;
650 eina_clist_add_tail(&e->calc_done, &obj->calc_entry);
651
652 o = obj->object_data;
653
654 if (o->need_recalculate)
655 {
656 o->need_recalculate = 0;
657 obj->smart.smart->smart_class->calculate(obj);
658 }
659 }
660
661 while (NULL != (elem = eina_clist_head(&e->calc_done)))
662 {
663 obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry);
664 obj->recalculate_cycle = 0;
665 eina_clist_remove(&obj->calc_entry);
666 }
667
668 e->in_smart_calc--;
669 if (e->in_smart_calc == 0) e->smart_calc_count++;
670 evas_event_thaw(e);
671 evas_event_thaw_eval(e);
672}
673
674EAPI void
675evas_object_smart_changed(Evas_Object *obj)
676{
677 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
678 return;
679 MAGIC_CHECK_END();
680 evas_object_change(obj);
681 evas_object_smart_need_recalculate_set(obj, 1);
682}
683
684/* internal calls */
685static void
686evas_object_smart_callbacks_clear(Evas_Object *obj)
687{
688 Evas_Object_Smart *o;
689 Eina_List *l;
690 Evas_Smart_Callback *cb;
691
692 o = (Evas_Object_Smart *)(obj->object_data);
693
694 if (o->walking_list) return;
695 if (!o->deletions_waiting) return;
696 for (l = o->callbacks; l;)
697 {
698 cb = eina_list_data_get(l);
699 l = eina_list_next(l);
700 if (cb->delete_me)
701 {
702 o->callbacks = eina_list_remove(o->callbacks, cb);
703 if (cb->event) eina_stringshare_del(cb->event);
704 EVAS_MEMPOOL_FREE(_mp_cb, cb);
705 }
706 }
707}
708
709void
710evas_object_smart_del(Evas_Object *obj)
711{
712 Evas_Smart *s;
713
714 if (obj->delete_me) return;
715 s = obj->smart.smart;
716 if ((s) && (s->smart_class->del)) s->smart_class->del(obj);
717 if (obj->smart.parent) evas_object_smart_member_del(obj);
718 if (s) evas_object_smart_unuse(s);
719}
720
721void
722evas_object_smart_cleanup(Evas_Object *obj)
723{
724 Evas_Object_Smart *o;
725
726 if (obj->smart.parent)
727 evas_object_smart_member_del(obj);
728
729 o = (Evas_Object_Smart *)(obj->object_data);
730 if (o->magic == MAGIC_OBJ_SMART)
731 {
732 if (obj->calc_entry.next)
733 eina_clist_remove(&obj->calc_entry);
734
735 while (o->contained)
736 evas_object_smart_member_del((Evas_Object *)o->contained);
737
738 while (o->callbacks)
739 {
740 Evas_Smart_Callback *cb = o->callbacks->data;
741 o->callbacks = eina_list_remove(o->callbacks, cb);
742 if (cb->event) eina_stringshare_del(cb->event);
743 EVAS_MEMPOOL_FREE(_mp_cb, cb);
744 }
745
746 evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0);
747 o->data = NULL;
748 }
749
750 obj->smart.parent = NULL;
751 obj->smart.smart = NULL;
752}
753
754void
755evas_object_smart_member_cache_invalidate(Evas_Object *obj,
756 Eina_Bool pass_events,
757 Eina_Bool freeze_events)
758{
759 Evas_Object_Smart *o;
760 Evas_Object *member;
761
762 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
763 return;
764 MAGIC_CHECK_END();
765
766 if (pass_events)
767 obj->parent_cache.pass_events_valid = EINA_FALSE;
768 if (freeze_events)
769 obj->parent_cache.freeze_events_valid = EINA_FALSE;
770
771 o = obj->object_data;
772 if (o->magic != MAGIC_OBJ_SMART) return;
773
774 EINA_INLIST_FOREACH(o->contained, member)
775 evas_object_smart_member_cache_invalidate(member,
776 pass_events,
777 freeze_events);
778}
779
780void
781evas_object_smart_member_raise(Evas_Object *member)
782{
783 Evas_Object_Smart *o;
784
785 o = (Evas_Object_Smart *)(member->smart.parent->object_data);
786 o->contained = eina_inlist_demote(o->contained, EINA_INLIST_GET(member));
787}
788
789void
790evas_object_smart_member_lower(Evas_Object *member)
791{
792 Evas_Object_Smart *o;
793
794 o = (Evas_Object_Smart *)(member->smart.parent->object_data);
795 o->contained = eina_inlist_promote(o->contained, EINA_INLIST_GET(member));
796}
797
798void
799evas_object_smart_member_stack_above(Evas_Object *member, Evas_Object *other)
800{
801 Evas_Object_Smart *o;
802
803 o = (Evas_Object_Smart *)(member->smart.parent->object_data);
804 o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
805 o->contained = eina_inlist_append_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
806}
807
808void
809evas_object_smart_member_stack_below(Evas_Object *member, Evas_Object *other)
810{
811 Evas_Object_Smart *o;
812
813 o = (Evas_Object_Smart *)(member->smart.parent->object_data);
814 o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member));
815 o->contained = eina_inlist_prepend_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other));
816}
817
818/* all nice and private */
819static void
820evas_object_smart_init(Evas_Object *obj)
821{
822 /* alloc smart obj, setup methods and default values */
823 obj->object_data = evas_object_smart_new();
824 /* set up default settings for this kind of object */
825 obj->cur.color.r = 255;
826 obj->cur.color.g = 255;
827 obj->cur.color.b = 255;
828 obj->cur.color.a = 255;
829 obj->cur.geometry.x = 0;
830 obj->cur.geometry.y = 0;
831 obj->cur.geometry.w = 0;
832 obj->cur.geometry.h = 0;
833 obj->cur.layer = 0;
834 /* set up object-specific settings */
835 obj->prev = obj->cur;
836 /* set up methods (compulsory) */
837 obj->func = &object_func;
838}
839
840static void *
841evas_object_smart_new(void)
842{
843 Evas_Object_Smart *o;
844
845 /* alloc obj private data */
846 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_smart", Evas_Object_Smart, 256, NULL);
847 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Smart);
848 if (!o) return NULL;
849 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Smart);
850 o->magic = MAGIC_OBJ_SMART;
851 return o;
852}
853
854static void
855evas_object_smart_free(Evas_Object *obj)
856{
857 Evas_Object_Smart *o;
858
859 /* frees private object data. very simple here */
860 o = (Evas_Object_Smart *)(obj->object_data);
861 MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART);
862 return;
863 MAGIC_CHECK_END();
864 /* free obj */
865 o->magic = 0;
866 EVAS_MEMPOOL_FREE(_mp_obj, o);
867}
868
869static void
870evas_object_smart_render(Evas_Object *obj __UNUSED__, void *output __UNUSED__, void *context __UNUSED__, void *surface __UNUSED__, int x __UNUSED__, int y __UNUSED__)
871{
872 return;
873}
874
875static void
876evas_object_smart_render_pre(Evas_Object *obj)
877{
878 if (obj->pre_render_done) return;
879 if ((obj->cur.map != obj->prev.map) ||
880 (obj->cur.usemap != obj->prev.usemap))
881 {
882 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
883 goto done;
884 }
885done:
886 obj->pre_render_done = 1;
887}
888
889static void
890evas_object_smart_render_post(Evas_Object *obj)
891{
892 obj->prev = obj->cur;
893}
894
895static unsigned int evas_object_smart_id_get(Evas_Object *obj)
896{
897 Evas_Object_Smart *o;
898
899 o = (Evas_Object_Smart *)(obj->object_data);
900 if (!o) return 0;
901 return MAGIC_OBJ_SMART;
902}
903
904static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj)
905{
906 Evas_Object_Smart *o;
907
908 o = (Evas_Object_Smart *)(obj->object_data);
909 if (!o) return 0;
910 return MAGIC_OBJ_CONTAINER;
911}
912
913static void *evas_object_smart_engine_data_get(Evas_Object *obj)
914{
915 Evas_Object_Smart *o;
916
917 o = (Evas_Object_Smart *)(obj->object_data);
918 if (!o) return NULL;
919 return o->engine_data;
920}
diff --git a/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c b/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c
new file mode 100644
index 0000000..9b9fa6d
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c
@@ -0,0 +1,183 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4#define CSO_DATA_GET_OR_RETURN(obj, ptr) \
5 Evas_Object_Smart_Clipped_Data *ptr = evas_object_smart_data_get(obj); \
6 if (!ptr) return;
7
8EAPI void
9evas_object_smart_move_children_relative(Evas_Object *obj, Evas_Coord dx, Evas_Coord dy)
10{
11 const Eina_Inlist *lst;
12 Evas_Object *child;
13
14 if ((dx == 0) && (dy == 0))
15 return;
16
17 lst = evas_object_smart_members_get_direct(obj);
18 EINA_INLIST_FOREACH(lst, child)
19 {
20 Evas_Coord orig_x, orig_y;
21
22// shortcut as we are in evas
23// evas_object_geometry_get(child, &orig_x, &orig_y, NULL, NULL);
24 if (child->delete_me) continue;
25 if (child->is_static_clip) continue;
26 orig_x = child->cur.geometry.x;
27 orig_y = child->cur.geometry.y;
28 evas_object_move(child, orig_x + dx, orig_y + dy);
29 }
30}
31
32EAPI Evas_Object *
33evas_object_smart_clipped_clipper_get(Evas_Object *obj)
34{
35 Evas_Object_Smart_Clipped_Data *cso = evas_object_smart_data_get(obj);
36 if (!cso)
37 return NULL;
38
39 return cso->clipper;
40}
41
42static void
43evas_object_smart_clipped_smart_add(Evas_Object *obj)
44{
45 Evas_Object_Smart_Clipped_Data *cso;
46 Evas_Object *clipper;
47
48 cso = evas_object_smart_data_get(obj);
49 if (!cso)
50 cso = calloc(1, sizeof(*cso)); /* users can provide it or realloc() later */
51
52 cso->evas = evas_object_evas_get(obj);
53 clipper = evas_object_rectangle_add(cso->evas);
54 evas_object_static_clip_set(clipper, 1);
55 cso->clipper = NULL;
56 evas_object_smart_member_add(clipper, obj);
57 cso->clipper = clipper;
58 evas_object_color_set(cso->clipper, 255, 255, 255, 255);
59 evas_object_move(cso->clipper, -100000, -100000);
60 evas_object_resize(cso->clipper, 200000, 200000);
61 evas_object_pass_events_set(cso->clipper, 1);
62 evas_object_hide(cso->clipper); /* show when have something clipped to it */
63
64 evas_object_smart_data_set(obj, cso);
65}
66
67static void
68evas_object_smart_clipped_smart_del(Evas_Object *obj)
69{
70 CSO_DATA_GET_OR_RETURN(obj, cso);
71
72 if (cso->clipper)
73 {
74 Evas_Object *clipper = cso->clipper;
75 cso->clipper = NULL;
76 evas_object_del(clipper);
77 }
78
79 _evas_object_smart_members_all_del(obj);
80
81 free(cso);
82 evas_object_smart_data_set(obj, NULL);
83}
84
85static void
86evas_object_smart_clipped_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
87{
88 Evas_Coord orig_x, orig_y;
89
90 evas_object_geometry_get(obj, &orig_x, &orig_y, NULL, NULL);
91 evas_object_smart_move_children_relative(obj, x - orig_x, y - orig_y);
92}
93
94static void
95evas_object_smart_clipped_smart_show(Evas_Object *obj)
96{
97 CSO_DATA_GET_OR_RETURN(obj, cso);
98 if (evas_object_clipees_get(cso->clipper))
99 evas_object_show(cso->clipper); /* just show if clipper being used */
100}
101
102static void
103evas_object_smart_clipped_smart_hide(Evas_Object *obj)
104{
105 CSO_DATA_GET_OR_RETURN(obj, cso);
106 evas_object_hide(cso->clipper);
107}
108
109static void
110evas_object_smart_clipped_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
111{
112 CSO_DATA_GET_OR_RETURN(obj, cso);
113 evas_object_color_set(cso->clipper, r, g, b, a);
114}
115
116static void
117evas_object_smart_clipped_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
118{
119 CSO_DATA_GET_OR_RETURN(obj, cso);
120 evas_object_clip_set(cso->clipper, clip);
121}
122
123static void
124evas_object_smart_clipped_smart_clip_unset(Evas_Object *obj)
125{
126 CSO_DATA_GET_OR_RETURN(obj, cso);
127 evas_object_clip_unset(cso->clipper);
128}
129
130static void
131evas_object_smart_clipped_smart_member_add(Evas_Object *obj, Evas_Object *member)
132{
133 CSO_DATA_GET_OR_RETURN(obj, cso);
134 if (!cso->clipper)
135 return;
136 evas_object_clip_set(member, cso->clipper);
137 if (evas_object_visible_get(obj))
138 evas_object_show(cso->clipper);
139}
140
141static void
142evas_object_smart_clipped_smart_member_del(Evas_Object *obj, Evas_Object *member)
143{
144 CSO_DATA_GET_OR_RETURN(obj, cso);
145 if (!cso->clipper)
146 return;
147 evas_object_clip_unset(member);
148 if (!evas_object_clipees_get(cso->clipper))
149 evas_object_hide(cso->clipper);
150}
151
152EAPI void
153evas_object_smart_clipped_smart_set(Evas_Smart_Class *sc)
154{
155 if (!sc)
156 return;
157
158 sc->add = evas_object_smart_clipped_smart_add;
159 sc->del = evas_object_smart_clipped_smart_del;
160 sc->move = evas_object_smart_clipped_smart_move;
161 sc->show = evas_object_smart_clipped_smart_show;
162 sc->hide = evas_object_smart_clipped_smart_hide;
163 sc->color_set = evas_object_smart_clipped_smart_color_set;
164 sc->clip_set = evas_object_smart_clipped_smart_clip_set;
165 sc->clip_unset = evas_object_smart_clipped_smart_clip_unset;
166 sc->calculate = NULL;
167 sc->member_add = evas_object_smart_clipped_smart_member_add;
168 sc->member_del = evas_object_smart_clipped_smart_member_del;
169}
170
171EAPI const Evas_Smart_Class *
172evas_object_smart_clipped_class_get(void)
173{
174 static Evas_Smart_Class _sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("EvasObjectSmartClipped");
175 static const Evas_Smart_Class *class = NULL;
176
177 if (class)
178 return class;
179
180 evas_object_smart_clipped_smart_set(&_sc);
181 class = &_sc;
182 return class;
183}
diff --git a/libraries/evas/src/lib/canvas/evas_object_table.c b/libraries/evas/src/lib/canvas/evas_object_table.c
new file mode 100644
index 0000000..6e28fce
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_table.c
@@ -0,0 +1,1373 @@
1#include <errno.h>
2#include "evas_common.h"
3
4typedef struct _Evas_Object_Table_Data Evas_Object_Table_Data;
5typedef struct _Evas_Object_Table_Option Evas_Object_Table_Option;
6typedef struct _Evas_Object_Table_Cache Evas_Object_Table_Cache;
7typedef struct _Evas_Object_Table_Iterator Evas_Object_Table_Iterator;
8typedef struct _Evas_Object_Table_Accessor Evas_Object_Table_Accessor;
9
10struct _Evas_Object_Table_Option
11{
12 Evas_Object *obj;
13 unsigned short col, row, colspan, rowspan, end_col, end_row;
14 struct {
15 Evas_Coord w, h;
16 } min, max;
17 struct {
18 double h, v;
19 } align;
20 struct {
21 Evas_Coord l, r, t, b;
22 } pad;
23 Eina_Bool expand_h : 1; /* XXX required? */
24 Eina_Bool expand_v : 1; /* XXX required? */
25 Eina_Bool fill_h : 1;
26 Eina_Bool fill_v : 1;
27};
28
29struct _Evas_Object_Table_Cache
30{
31 struct {
32 struct {
33 double h, v;
34 } weights;
35 struct {
36 int h, v;
37 } expands;
38 struct {
39 Evas_Coord w, h;
40 } min;
41 } total;
42 struct {
43 double *h, *v;
44 } weights;
45 struct {
46 Evas_Coord *h, *v;
47 } sizes;
48 struct {
49 Eina_Bool *h, *v;
50 } expands;
51 double ___pad; // padding to make sure doubles at end can be aligned
52};
53
54struct _Evas_Object_Table_Data
55{
56 Evas_Object_Smart_Clipped_Data base;
57 Eina_List *children;
58 struct {
59 Evas_Coord h, v;
60 } pad;
61 struct {
62 double h, v;
63 } align;
64 struct {
65 int cols, rows;
66 } size;
67 Evas_Object_Table_Cache *cache;
68 Evas_Object_Table_Homogeneous_Mode homogeneous;
69 Eina_Bool hints_changed : 1;
70 Eina_Bool expand_h : 1;
71 Eina_Bool expand_v : 1;
72 Eina_Bool is_mirrored : 1;
73};
74
75struct _Evas_Object_Table_Iterator
76{
77 Eina_Iterator iterator;
78
79 Eina_Iterator *real_iterator;
80 const Evas_Object *table;
81};
82
83struct _Evas_Object_Table_Accessor
84{
85 Eina_Accessor accessor;
86
87 Eina_Accessor *real_accessor;
88 const Evas_Object *table;
89};
90
91#define EVAS_OBJECT_TABLE_DATA_GET(o, ptr) \
92 Evas_Object_Table_Data *ptr = evas_object_smart_data_get(o)
93
94#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, ptr) \
95 EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
96 if (!ptr) \
97 { \
98 CRIT("no widget data for object %p (%s)", \
99 o, evas_object_type_get(o)); \
100 abort(); \
101 return; \
102}
103
104#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
105 EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
106 if (!ptr) \
107 { \
108 CRIT("No widget data for object %p (%s)", \
109 o, evas_object_type_get(o)); \
110 abort(); \
111 return val; \
112 }
113
114static const char EVAS_OBJECT_TABLE_OPTION_KEY[] = "|EvTb";
115
116static Eina_Bool
117_evas_object_table_iterator_next(Evas_Object_Table_Iterator *it, void **data)
118{
119 Evas_Object_Table_Option *opt;
120
121 if (!eina_iterator_next(it->real_iterator, (void **)&opt))
122 return EINA_FALSE;
123 if (data) *data = opt->obj;
124 return EINA_TRUE;
125}
126
127static Evas_Object *
128_evas_object_table_iterator_get_container(Evas_Object_Table_Iterator *it)
129{
130 return (Evas_Object *)it->table;
131}
132
133static void
134_evas_object_table_iterator_free(Evas_Object_Table_Iterator *it)
135{
136 eina_iterator_free(it->real_iterator);
137 free(it);
138}
139
140static Eina_Bool
141_evas_object_table_accessor_get_at(Evas_Object_Table_Accessor *it, unsigned int idx, void **data)
142{
143 Evas_Object_Table_Option *opt = NULL;
144
145 if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt))
146 return EINA_FALSE;
147 if (data) *data = opt->obj;
148 return EINA_TRUE;
149}
150
151static Evas_Object *
152_evas_object_table_accessor_get_container(Evas_Object_Table_Accessor *it)
153{
154 return (Evas_Object *)it->table;
155}
156
157static void
158_evas_object_table_accessor_free(Evas_Object_Table_Accessor *it)
159{
160 eina_accessor_free(it->real_accessor);
161 free(it);
162}
163
164static Evas_Object_Table_Cache *
165_evas_object_table_cache_alloc(int cols, int rows)
166{
167 Evas_Object_Table_Cache *cache;
168 int size;
169
170 size = sizeof(Evas_Object_Table_Cache) +
171 ((cols + rows) *
172 (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool)));
173 cache = malloc(size);
174 if (!cache)
175 {
176 ERR("Could not allocate table cache %dx%d (%d bytes): %s",
177 cols, rows, size, strerror(errno));
178 return NULL;
179 }
180
181 cache->weights.h = (double *)(cache + 1);
182 cache->weights.v = (double *)(cache->weights.h + cols);
183 cache->sizes.h = (Evas_Coord *)(cache->weights.v + rows);
184 cache->sizes.v = (Evas_Coord *)(cache->sizes.h + cols);
185 cache->expands.h = (Eina_Bool *)(cache->sizes.v + rows);
186 cache->expands.v = (Eina_Bool *)(cache->expands.h + cols);
187
188 return cache;
189}
190
191static void
192_evas_object_table_cache_free(Evas_Object_Table_Cache *cache)
193{
194 free(cache);
195}
196
197static void
198_evas_object_table_cache_reset(Evas_Object_Table_Data *priv)
199{
200 Evas_Object_Table_Cache *c = priv->cache;
201 int size;
202
203 c->total.expands.v = 0;
204 c->total.expands.h = 0;
205 c->total.min.w = 0;
206 c->total.min.h = 0;
207
208 size = ((priv->size.rows + priv->size.cols) *
209 (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool)));
210 memset(c + 1, 0, size);
211}
212
213static void
214_evas_object_table_cache_invalidate(Evas_Object_Table_Data *priv)
215{
216 priv->hints_changed = 1;
217 if (priv->cache)
218 {
219 _evas_object_table_cache_free(priv->cache);
220 priv->cache = NULL;
221 }
222}
223
224static Evas_Object_Table_Option *
225_evas_object_table_option_get(Evas_Object *o)
226{
227 return evas_object_data_get(o, EVAS_OBJECT_TABLE_OPTION_KEY);
228}
229
230static void
231_evas_object_table_option_set(Evas_Object *o, const Evas_Object_Table_Option *opt)
232{
233 evas_object_data_set(o, EVAS_OBJECT_TABLE_OPTION_KEY, opt);
234}
235
236static Evas_Object_Table_Option *
237_evas_object_table_option_del(Evas_Object *o)
238{
239 return evas_object_data_del(o, EVAS_OBJECT_TABLE_OPTION_KEY);
240}
241
242static void
243_on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *child, void *einfo __UNUSED__)
244{
245 Evas_Object *table = data;
246 evas_object_table_unpack(table, child);
247}
248
249static void
250_on_child_hints_changed(void *data, Evas *evas __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
251{
252 Evas_Object *table = data;
253 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(table, priv);
254 _evas_object_table_cache_invalidate(priv);
255 evas_object_smart_changed(table);
256}
257
258static void
259_evas_object_table_child_connect(Evas_Object *o, Evas_Object *child)
260{
261 evas_object_event_callback_add
262 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
263 evas_object_event_callback_add
264 (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
265}
266
267static void
268_evas_object_table_child_disconnect(Evas_Object *o, Evas_Object *child)
269{
270 evas_object_event_callback_del_full
271 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
272 evas_object_event_callback_del_full
273 (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
274}
275
276static void
277_evas_object_table_calculate_cell(const Evas_Object_Table_Option *opt, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
278{
279 Evas_Coord cw, ch;
280
281 *w -= opt->pad.l + opt->pad.r;
282 if (*w < opt->min.w)
283 cw = opt->min.w;
284 else if ((opt->max.w > -1) && (*w > opt->max.w))
285 cw = opt->max.w;
286 else if (opt->fill_h)
287 cw = *w;
288 else
289 cw = opt->min.w;
290
291 *h -= opt->pad.t + opt->pad.b;
292 if (*h < opt->min.h)
293 ch = opt->min.h;
294 else if ((opt->max.h > -1) && (*h > opt->max.h))
295 ch = opt->max.h;
296 else if (opt->fill_v)
297 ch = *h;
298 else
299 ch = opt->min.h;
300
301 *x += opt->pad.l;
302 if (cw != *w)
303 {
304 *x += (*w - cw) * opt->align.h;
305 *w = cw;
306 }
307
308 *y += opt->pad.t;
309 if (ch != *h)
310 {
311 *y += (*h - ch) * opt->align.v;
312 *h = ch;
313 }
314}
315
316static void
317_evas_object_table_calculate_hints_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
318{
319 Eina_List *l;
320 Evas_Object_Table_Option *opt;
321 Evas_Coord minw, minh, o_minw, o_minh;
322 Eina_Bool expand_h, expand_v;
323
324 o_minw = 0;
325 o_minh = 0;
326 minw = 0;
327 minh = 0;
328 expand_h = 0;
329 expand_v = 0;
330
331 EINA_LIST_FOREACH(priv->children, l, opt)
332 {
333 Evas_Object *child = opt->obj;
334 Evas_Coord child_minw, child_minh, cell_minw, cell_minh;
335 double weightw, weighth;
336
337 evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h);
338 evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h);
339 evas_object_size_hint_padding_get
340 (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b);
341 evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v);
342 evas_object_size_hint_weight_get(child, &weightw, &weighth);
343
344 child_minw = opt->min.w + opt->pad.l + opt->pad.r;
345 child_minh = opt->min.h + opt->pad.t + opt->pad.b;
346
347 cell_minw = (child_minw + opt->colspan - 1) / opt->colspan;
348 cell_minh = (child_minh + opt->rowspan - 1) / opt->rowspan;
349
350 opt->expand_h = 0;
351 if ((weightw > 0.0) &&
352 ((opt->max.w < 0) ||
353 ((opt->max.w > -1) && (opt->min.w < opt->max.w))))
354 {
355 opt->expand_h = 1;
356 expand_h = 1;
357 }
358
359 opt->expand_v = 0;
360 if ((weighth > 0.0) &&
361 ((opt->max.h < 0) ||
362 ((opt->max.h > -1) && (opt->min.h < opt->max.h))))
363 {
364 opt->expand_v = 1;
365 expand_v = 1;
366 }
367
368 opt->fill_h = 0;
369 if (opt->align.h < 0.0)
370 {
371 opt->align.h = 0.5;
372 opt->fill_h = 1;
373 }
374 opt->fill_v = 0;
375 if (opt->align.v < 0.0)
376 {
377 opt->align.v = 0.5;
378 opt->fill_v = 1;
379 }
380
381 /* greatest mininum values, with paddings */
382 if (minw < cell_minw)
383 minw = cell_minw;
384 if (minh < cell_minh)
385 minh = cell_minh;
386 /* greatest mininum values, without paddings */
387 if (o_minw < opt->min.w)
388 o_minw = opt->min.w;
389 if (o_minh < opt->min.h)
390 o_minh = opt->min.h;
391 }
392
393 if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
394 {
395 if (o_minw < 1)
396 {
397 ERR("homogeneous table based on item size but no "
398 "horizontal mininum size specified! Using expand.");
399 expand_h = 1;
400 }
401 if (o_minh < 1)
402 {
403 ERR("homogeneous table based on item size but no "
404 "vertical mininum size specified! Using expand.");
405 expand_v = 1;
406 }
407 }
408
409 minw = priv->size.cols * (minw + priv->pad.h) - priv->pad.h;
410 minh = priv->size.rows * (minh + priv->pad.v) - priv->pad.v;
411
412 priv->hints_changed = 0;
413 priv->expand_h = expand_h;
414 priv->expand_v = expand_v;
415
416 if ((minw > 0 ) || (minh > 0))
417 evas_object_size_hint_min_set(o, minw, minh);
418
419 // XXX hint max?
420}
421
422static void
423_evas_object_table_calculate_layout_homogeneous_sizes_item(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
424{
425 Evas_Coord minw, minh;
426 Eina_Bool expand_h, expand_v;
427
428 evas_object_size_hint_min_get(o, &minw, &minh);
429 expand_h = priv->expand_h;
430 expand_v = priv->expand_v;
431
432 if (*w < minw)
433 expand_h = 0;
434 if (!expand_h)
435 {
436 *x += (*w - minw) * priv->align.h;
437 *w = minw;
438 }
439
440 if (*h < minh)
441 expand_v = 0;
442 if (!expand_v)
443 {
444 *y += (*h - minh) * priv->align.v;
445 *h = minh;
446 }
447}
448
449static void
450_evas_object_table_calculate_layout_homogeneous_sizes(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h, Evas_Coord *cellw, Evas_Coord *cellh)
451{
452 evas_object_geometry_get(o, x, y, w, h);
453 if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
454 _evas_object_table_calculate_layout_homogeneous_sizes_item
455 (o, priv, x, y, w, h);
456
457 *cellw = (*w + priv->size.cols - 1) / priv->size.cols;
458 *cellh = (*h + priv->size.rows - 1) / priv->size.rows;
459}
460
461static void
462_evas_object_table_calculate_layout_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
463{
464 Evas_Coord x = 0, y = 0, w = 0, h = 0, ww, hh, cellw = 0, cellh = 0;
465 Eina_List *l;
466 Evas_Object_Table_Option *opt;
467
468 _evas_object_table_calculate_layout_homogeneous_sizes
469 (o, priv, &x, &y, &w, &h, &cellw, &cellh);
470
471 ww = w - ((priv->size.cols - 1) * priv->pad.h);
472 hh = h - ((priv->size.rows - 1) * priv->pad.v);
473
474 if (ww < 0) ww = 0;
475 if (ww < 0) ww = 0;
476
477 EINA_LIST_FOREACH(priv->children, l, opt)
478 {
479 Evas_Object *child = opt->obj;
480 Evas_Coord cx, cy, cw, ch, cox, coy, cow, coh;
481
482 cx = x + ((opt->col * ww) / priv->size.cols);
483 cw = x + (((opt->col + opt->colspan) * ww) / priv->size.cols) - cx;
484 cy = y + ((opt->row * hh) / priv->size.rows);
485 ch = y + (((opt->row + opt->rowspan) * hh) / priv->size.rows) - cy;
486
487 cx += (opt->col) * priv->pad.h;
488 cy += (opt->row) * priv->pad.v;
489
490 cox = cx;
491 coy = cy;
492 cow = cw;
493 coh = ch;
494
495 _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch);
496 if (cw > cow)
497 {
498 cx = cox;
499 cw = cow;
500 }
501 if (ch > coh)
502 {
503 cy = coy;
504 ch = coh;
505 }
506
507 if (priv->is_mirrored)
508 {
509 evas_object_move(opt->obj, x + w - (cx - x + cw), cy);
510 }
511 else
512 {
513 evas_object_move(child, cx, cy);
514 }
515 evas_object_resize(child, cw, ch);
516 }
517}
518
519static void
520_evas_object_table_smart_calculate_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
521{
522 if (priv->hints_changed)
523 _evas_object_table_calculate_hints_homogeneous(o, priv);
524 _evas_object_table_calculate_layout_homogeneous(o, priv);
525}
526
527static int
528_evas_object_table_count_expands(const Eina_Bool *expands, int start, int end)
529{
530 const Eina_Bool *itr = expands + start, *itr_end = expands + end;
531 int count = 0;
532
533 for (; itr < itr_end; itr++)
534 {
535 if (*itr)
536 count++;
537 }
538
539 return count;
540}
541
542static Evas_Coord
543_evas_object_table_sum_sizes(const Evas_Coord *sizes, int start, int end)
544{
545 const Evas_Coord *itr = sizes + start, *itr_end = sizes + end;
546 Evas_Coord sum = 0;
547
548 for (; itr < itr_end; itr++)
549 sum += *itr;
550
551 return sum;
552}
553
554static void
555_evas_object_table_sizes_calc_noexpand(Evas_Coord *sizes, int start, int end, Evas_Coord space)
556{
557 Evas_Coord *itr = sizes + start, *itr_end = sizes + end - 1;
558 Evas_Coord step;
559 int units;
560
561 /* XXX move to fixed point math and spread errors among cells */
562 units = end - start;
563 step = space / units;
564 for (; itr < itr_end; itr++)
565 *itr += step;
566
567 *itr += space - step * (units - 1);
568}
569
570static void
571_evas_object_table_sizes_calc_expand(Evas_Coord *sizes, int start, int end, Evas_Coord space, const Eina_Bool *expands, int expand_count, double *weights, double weighttot)
572{
573 Evas_Coord *itr = sizes + start, *itr_end = sizes + end;
574 const Eina_Bool *itr_expand = expands + start;
575 Evas_Coord step = 0, last_space = 0;
576 int total = 0, i = start;
577
578 /* XXX move to fixed point math and spread errors among cells */
579 if (weighttot > 0.0)
580 {
581 step = space / expand_count;
582 last_space = space - step * (expand_count - 1);
583 }
584
585 for (; itr < itr_end; itr++, itr_expand++, i++)
586 {
587 if (weighttot <= 0.0)
588 {
589 if (*itr_expand)
590 {
591 expand_count--;
592 if (expand_count > 0)
593 *itr += step;
594 else
595 {
596 *itr += last_space;
597 break;
598 }
599 }
600 }
601 else
602 {
603 if (*itr_expand)
604 {
605 expand_count--;
606 if (expand_count > 0)
607 {
608 step = (weights[i] / weighttot) * space;
609 *itr += step;
610 total += step;
611 }
612 else
613 {
614 *itr += space - total;
615 break;
616 }
617 }
618 }
619 }
620}
621
622static void
623_evas_object_table_calculate_hints_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
624{
625 Evas_Object_Table_Option *opt;
626 Evas_Object_Table_Cache *c;
627 Eina_List *l;
628 double totweightw = 0.0, totweighth = 0.0;
629 int i;
630
631 if (!priv->cache)
632 {
633 priv->cache = _evas_object_table_cache_alloc
634 (priv->size.cols, priv->size.rows);
635 if (!priv->cache)
636 return;
637 }
638 c = priv->cache;
639 _evas_object_table_cache_reset(priv);
640
641 /* cache interesting data */
642 memset(c->expands.h, 1, priv->size.cols);
643 memset(c->expands.v, 1, priv->size.rows);
644 memset(c->weights.h, 0, priv->size.cols);
645 memset(c->weights.v, 0, priv->size.rows);
646 EINA_LIST_FOREACH(priv->children, l, opt)
647 {
648 Evas_Object *child = opt->obj;
649 double weightw, weighth;
650
651 evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h);
652 evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h);
653 evas_object_size_hint_padding_get
654 (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b);
655 evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v);
656 evas_object_size_hint_weight_get(child, &weightw, &weighth);
657
658 opt->expand_h = 0;
659 if ((weightw > 0.0) &&
660 ((opt->max.w < 0) ||
661 ((opt->max.w > -1) && (opt->min.w < opt->max.w))))
662 opt->expand_h = 1;
663
664 opt->expand_v = 0;
665 if ((weighth > 0.0) &&
666 ((opt->max.h < 0) ||
667 ((opt->max.h > -1) && (opt->min.h < opt->max.h))))
668 opt->expand_v = 1;
669
670 opt->fill_h = 0;
671 if (opt->align.h < 0.0)
672 {
673 opt->align.h = 0.5;
674 opt->fill_h = 1;
675 }
676 opt->fill_v = 0;
677 if (opt->align.v < 0.0)
678 {
679 opt->align.v = 0.5;
680 opt->fill_v = 1;
681 }
682
683 if (!opt->expand_h)
684 memset(c->expands.h + opt->col, 0, opt->colspan);
685 else
686 {
687 for (i = opt->col; i < opt->col + opt->colspan; i++)
688 c->weights.h[i] += (weightw / (double)opt->colspan);
689 }
690 if (!opt->expand_v)
691 memset(c->expands.v + opt->row, 0, opt->rowspan);
692 else
693 {
694 for (i = opt->row; i < opt->row + opt->rowspan; i++)
695 c->weights.v[i] += (weighth / (double)opt->rowspan);
696 }
697 }
698 for (i = 0; i < priv->size.cols; i++) totweightw += c->weights.h[i];
699 for (i = 0; i < priv->size.rows; i++) totweighth += c->weights.v[i];
700
701 /* calculate sizes for each row and column */
702 EINA_LIST_FOREACH(priv->children, l, opt)
703 {
704 Evas_Coord tot, need;
705
706 /* handle horizontal */
707 tot = _evas_object_table_sum_sizes(c->sizes.h, opt->col, opt->end_col);
708 need = opt->min.w + opt->pad.l + opt->pad.r;
709 if (tot < need)
710 {
711 Evas_Coord space = need - tot;
712 int count;
713
714 count = _evas_object_table_count_expands
715 (c->expands.h, opt->col, opt->end_col);
716
717 if (count > 0)
718 _evas_object_table_sizes_calc_expand
719 (c->sizes.h, opt->col, opt->end_col, space,
720 c->expands.h, count, c->weights.h, totweightw);
721 else
722 _evas_object_table_sizes_calc_noexpand
723 (c->sizes.h, opt->col, opt->end_col, space);
724 }
725
726 /* handle vertical */
727 tot = _evas_object_table_sum_sizes(c->sizes.v, opt->row, opt->end_row);
728 need = opt->min.h + opt->pad.t + opt->pad.b;
729 if (tot < opt->min.h)
730 {
731 Evas_Coord space = need - tot;
732 int count;
733
734 count = _evas_object_table_count_expands
735 (c->expands.v, opt->row, opt->end_row);
736
737 if (count > 0)
738 _evas_object_table_sizes_calc_expand
739 (c->sizes.v, opt->row, opt->end_row, space,
740 c->expands.v, count, c->weights.v, totweighth);
741 else
742 _evas_object_table_sizes_calc_noexpand
743 (c->sizes.v, opt->row, opt->end_row, space);
744 }
745 }
746
747 c->total.weights.h = totweightw;
748 c->total.weights.v = totweighth;
749
750 c->total.expands.h = _evas_object_table_count_expands
751 (c->expands.h, 0, priv->size.cols);
752 c->total.expands.v = _evas_object_table_count_expands
753 (c->expands.v, 0, priv->size.rows);
754
755 c->total.min.w = _evas_object_table_sum_sizes
756 (c->sizes.h, 0, priv->size.cols);
757 c->total.min.h = _evas_object_table_sum_sizes
758 (c->sizes.v, 0, priv->size.rows);
759
760 c->total.min.w += priv->pad.h * (priv->size.cols - 1);
761 c->total.min.h += priv->pad.v * (priv->size.rows - 1);
762
763 if ((c->total.min.w > 0) || (c->total.min.h > 0))
764 evas_object_size_hint_min_set(o, c->total.min.w, c->total.min.h);
765
766 // XXX hint max?
767}
768
769static void
770_evas_object_table_calculate_layout_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
771{
772 Evas_Object_Table_Option *opt;
773 Evas_Object_Table_Cache *c;
774 Eina_List *l;
775 Evas_Coord *cols = NULL, *rows = NULL;
776 Evas_Coord x, y, w, h;
777
778 evas_object_geometry_get(o, &x, &y, &w, &h);
779 c = priv->cache;
780
781 /* handle horizontal */
782 if ((c->total.expands.h <= 0) || (c->total.min.w >= w))
783 {
784 x += (w - c->total.min.w) * priv->align.h;
785 w = c->total.min.w;
786 cols = c->sizes.h;
787 }
788 else
789 {
790 int size = priv->size.cols * sizeof(Evas_Coord);
791 cols = malloc(size);
792 if (!cols)
793 {
794 ERR("Could not allocate temp columns (%d bytes): %s",
795 size, strerror(errno));
796 goto end;
797 }
798 memcpy(cols, c->sizes.h, size);
799 _evas_object_table_sizes_calc_expand
800 (cols, 0, priv->size.cols, w - c->total.min.w,
801 c->expands.h, c->total.expands.h, c->weights.h, c->total.weights.h);
802 }
803
804 /* handle vertical */
805 if ((c->total.expands.v <= 0) || (c->total.min.h >= h))
806 {
807 y += (h - c->total.min.h) * priv->align.v;
808 h = c->total.min.h;
809 rows = c->sizes.v;
810 }
811 else
812 {
813 int size = priv->size.rows * sizeof(Evas_Coord);
814 rows = malloc(size);
815 if (!rows)
816 {
817 ERR("could not allocate temp rows (%d bytes): %s",
818 size, strerror(errno));
819 goto end;
820 }
821 memcpy(rows, c->sizes.v, size);
822 _evas_object_table_sizes_calc_expand
823 (rows, 0, priv->size.rows, h - c->total.min.h,
824 c->expands.v, c->total.expands.v, c->weights.v, c->total.weights.v);
825 }
826
827 EINA_LIST_FOREACH(priv->children, l, opt)
828 {
829 Evas_Object *child = opt->obj;
830 Evas_Coord cx, cy, cw, ch;
831
832 cx = x + opt->col * (priv->pad.h);
833 cx += _evas_object_table_sum_sizes(cols, 0, opt->col);
834 cw = _evas_object_table_sum_sizes(cols, opt->col, opt->end_col);
835
836 cy = y + opt->row * (priv->pad.v);
837 cy += _evas_object_table_sum_sizes(rows, 0, opt->row);
838 ch = _evas_object_table_sum_sizes(rows, opt->row, opt->end_row);
839
840 _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch);
841
842 if (priv->is_mirrored)
843 {
844 evas_object_move(opt->obj, x + w - (cx - x + cw), cy);
845 }
846 else
847 {
848 evas_object_move(child, cx, cy);
849 }
850 evas_object_resize(child, cw, ch);
851 }
852
853 end:
854 if (cols != c->sizes.h)
855 {
856 if (cols) free(cols);
857 }
858 if (rows != c->sizes.v)
859 {
860 if (rows) free(rows);
861 }
862}
863
864static void
865_evas_object_table_smart_calculate_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
866{
867 if (priv->hints_changed)
868 _evas_object_table_calculate_hints_regular(o, priv);
869 _evas_object_table_calculate_layout_regular(o, priv);
870}
871
872EVAS_SMART_SUBCLASS_NEW("Evas_Object_Table", _evas_object_table,
873 Evas_Smart_Class, Evas_Smart_Class,
874 evas_object_smart_clipped_class_get, NULL)
875
876static void
877_evas_object_table_smart_add(Evas_Object *o)
878{
879 EVAS_SMART_DATA_ALLOC(o, Evas_Object_Table_Data)
880
881 priv->pad.h = 0;
882 priv->pad.v = 0;
883 priv->align.h = 0.5;
884 priv->align.v = 0.5;
885 priv->size.cols = 0;
886 priv->size.rows = 0;
887 priv->cache = NULL;
888 priv->homogeneous = EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE;
889 priv->hints_changed = 1;
890 priv->expand_h = 0;
891 priv->expand_v = 0;
892
893 _evas_object_table_parent_sc->add(o);
894}
895
896static void
897_evas_object_table_smart_del(Evas_Object *o)
898{
899 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
900 Eina_List *l;
901
902 l = priv->children;
903 while (l)
904 {
905 Evas_Object_Table_Option *opt = l->data;
906 _evas_object_table_child_disconnect(o, opt->obj);
907 _evas_object_table_option_del(opt->obj);
908 free(opt);
909 l = eina_list_remove_list(l, l);
910 }
911
912 if (priv->cache)
913 {
914 _evas_object_table_cache_free(priv->cache);
915 priv->cache = NULL;
916 }
917
918 _evas_object_table_parent_sc->del(o);
919}
920
921static void
922_evas_object_table_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
923{
924 Evas_Coord ow, oh;
925 evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
926 if ((ow == w) && (oh == h)) return;
927 evas_object_smart_changed(o);
928}
929
930static void
931_evas_object_table_smart_calculate(Evas_Object *o)
932{
933 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
934
935 if ((priv->size.cols < 1) || (priv->size.rows < 1))
936 {
937 DBG("Nothing to do: cols=%d, rows=%d",
938 priv->size.cols, priv->size.rows);
939 return;
940 }
941
942 if (priv->homogeneous)
943 _evas_object_table_smart_calculate_homogeneous(o, priv);
944 else
945 _evas_object_table_smart_calculate_regular(o, priv);
946}
947
948static void
949_evas_object_table_smart_set_user(Evas_Smart_Class *sc)
950{
951 sc->add = _evas_object_table_smart_add;
952 sc->del = _evas_object_table_smart_del;
953 sc->resize = _evas_object_table_smart_resize;
954 sc->calculate = _evas_object_table_smart_calculate;
955}
956
957EAPI Evas_Object *
958evas_object_table_add(Evas *evas)
959{
960 return evas_object_smart_add(evas, _evas_object_table_smart_class_new());
961}
962
963EAPI Evas_Object *
964evas_object_table_add_to(Evas_Object *parent)
965{
966 Evas *evas;
967 Evas_Object *o;
968
969 evas = evas_object_evas_get(parent);
970 o = evas_object_table_add(evas);
971 evas_object_smart_member_add(o, parent);
972 return o;
973}
974
975EAPI void
976evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous)
977{
978 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
979 if (priv->homogeneous == homogeneous)
980 return;
981 priv->homogeneous = homogeneous;
982 _evas_object_table_cache_invalidate(priv);
983 evas_object_smart_changed(o);
984}
985
986EAPI Evas_Object_Table_Homogeneous_Mode
987evas_object_table_homogeneous_get(const Evas_Object *o)
988{
989 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
990 return priv->homogeneous;
991}
992
993EAPI void
994evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical)
995{
996 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
997 if (priv->align.h == horizontal && priv->align.v == vertical)
998 return;
999 priv->align.h = horizontal;
1000 priv->align.v = vertical;
1001 evas_object_smart_changed(o);
1002}
1003
1004EAPI void
1005evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical)
1006{
1007 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1008 if (priv)
1009 {
1010 if (horizontal) *horizontal = priv->align.h;
1011 if (vertical) *vertical = priv->align.v;
1012 }
1013 else
1014 {
1015 if (horizontal) *horizontal = 0.5;
1016 if (vertical) *vertical = 0.5;
1017 }
1018}
1019
1020EAPI void
1021evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical)
1022{
1023 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
1024 if (priv->pad.h == horizontal && priv->pad.v == vertical)
1025 return;
1026 priv->pad.h = horizontal;
1027 priv->pad.v = vertical;
1028 _evas_object_table_cache_invalidate(priv);
1029 evas_object_smart_changed(o);
1030}
1031
1032EAPI void
1033evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical)
1034{
1035 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1036 if (priv)
1037 {
1038 if (horizontal) *horizontal = priv->pad.h;
1039 if (vertical) *vertical = priv->pad.v;
1040 }
1041 else
1042 {
1043 if (horizontal) *horizontal = 0;
1044 if (vertical) *vertical = 0;
1045 }
1046}
1047
1048EAPI Eina_Bool
1049evas_object_table_pack_get(Evas_Object *o, Evas_Object *child, unsigned short *col, unsigned short *row, unsigned short *colspan, unsigned short *rowspan)
1050{
1051 Evas_Object_Table_Option *opt;
1052
1053 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1054 opt = _evas_object_table_option_get(child);
1055 if (!opt)
1056 {
1057 if (col) *col = 0;
1058 if (row) *row = 0;
1059 if (colspan) *colspan = 0;
1060 if (rowspan) *rowspan = 0;
1061 return EINA_FALSE;
1062 }
1063 if (col) *col = opt->col;
1064 if (row) *row = opt->row;
1065 if (colspan) *colspan = opt->colspan;
1066 if (rowspan) *rowspan = opt->rowspan;
1067 return EINA_TRUE;
1068}
1069
1070EAPI Eina_Bool
1071evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
1072{
1073 Evas_Object_Table_Option *opt;
1074
1075 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1076
1077 if (rowspan < 1)
1078 {
1079 ERR("rowspan < 1");
1080 return EINA_FALSE;
1081 }
1082 if (colspan < 1)
1083 {
1084 ERR("colspan < 1");
1085 return EINA_FALSE;
1086 }
1087
1088 opt = _evas_object_table_option_get(child);
1089 if (!opt)
1090 {
1091 opt = malloc(sizeof(*opt));
1092 if (!opt)
1093 {
1094 ERR("could not allocate table option data.");
1095 return EINA_FALSE;
1096 }
1097 }
1098
1099 opt->obj = child;
1100 opt->col = col;
1101 opt->row = row;
1102 opt->colspan = colspan;
1103 opt->rowspan = rowspan;
1104 opt->end_col = col + colspan;
1105 opt->end_row = row + rowspan;
1106
1107 if (evas_object_smart_parent_get(child) == o)
1108 {
1109 Eina_Bool need_shrink = EINA_FALSE;
1110
1111 if (priv->size.cols < opt->end_col)
1112 priv->size.cols = opt->end_col;
1113 else
1114 need_shrink = EINA_TRUE;
1115 if (priv->size.rows < opt->end_row)
1116 priv->size.rows = opt->end_row;
1117 else
1118 need_shrink = EINA_TRUE;
1119
1120 if (need_shrink)
1121 {
1122 Eina_List *l;
1123 Evas_Object_Table_Option *opt2;
1124 int max_row = 0, max_col = 0;
1125
1126 EINA_LIST_FOREACH(priv->children, l, opt2)
1127 {
1128 if (max_col < opt2->end_col) max_col = opt2->end_col;
1129 if (max_row < opt2->end_row) max_row = opt2->end_row;
1130 }
1131 priv->size.cols = max_col;
1132 priv->size.rows = max_row;
1133 }
1134 }
1135 else
1136 {
1137 opt->min.w = 0;
1138 opt->min.h = 0;
1139 opt->max.w = 0;
1140 opt->max.h = 0;
1141 opt->align.h = 0.5;
1142 opt->align.v = 0.5;
1143 opt->pad.l = 0;
1144 opt->pad.r = 0;
1145 opt->pad.t = 0;
1146 opt->pad.b = 0;
1147 opt->expand_h = 0;
1148 opt->expand_v = 0;
1149
1150 priv->children = eina_list_append(priv->children, opt);
1151
1152 if (priv->size.cols < opt->end_col)
1153 priv->size.cols = opt->end_col;
1154 if (priv->size.rows < opt->end_row)
1155 priv->size.rows = opt->end_row;
1156
1157 _evas_object_table_option_set(child, opt);
1158 evas_object_smart_member_add(child, o);
1159 _evas_object_table_child_connect(o, child);
1160 }
1161 _evas_object_table_cache_invalidate(priv);
1162 evas_object_smart_changed(o);
1163 return EINA_TRUE;
1164}
1165
1166static void
1167_evas_object_table_remove_opt(Evas_Object_Table_Data *priv, Evas_Object_Table_Option *opt)
1168{
1169 Eina_List *l;
1170 int max_row, max_col, was_greatest;
1171
1172 max_row = 0;
1173 max_col = 0;
1174 was_greatest = 0;
1175 l = priv->children;
1176 while (l)
1177 {
1178 Evas_Object_Table_Option *cur_opt = l->data;
1179
1180 if (cur_opt != opt)
1181 {
1182 if (max_col < cur_opt->end_col)
1183 max_col = cur_opt->end_col;
1184 if (max_row < cur_opt->end_row)
1185 max_row = cur_opt->end_row;
1186
1187 l = l->next;
1188 }
1189 else
1190 {
1191 Eina_List *tmp = l->next;
1192 priv->children = eina_list_remove_list(priv->children, l);
1193
1194 if ((priv->size.cols > opt->end_col) &&
1195 (priv->size.rows > opt->end_row))
1196 break;
1197 else
1198 {
1199 was_greatest = 1;
1200 l = tmp;
1201 }
1202 }
1203 }
1204
1205 if (was_greatest)
1206 {
1207 priv->size.cols = max_col;
1208 priv->size.rows = max_row;
1209 }
1210}
1211
1212EAPI Eina_Bool
1213evas_object_table_unpack(Evas_Object *o, Evas_Object *child)
1214{
1215 Evas_Object_Table_Option *opt;
1216
1217 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1218
1219 if (o != evas_object_smart_parent_get(child))
1220 {
1221 ERR("cannot unpack child from incorrect table!");
1222 return EINA_FALSE;
1223 }
1224
1225 opt = _evas_object_table_option_del(child);
1226 if (!opt)
1227 {
1228 ERR("cannot unpack child with no packing option!");
1229 return EINA_FALSE;
1230 }
1231
1232 _evas_object_table_child_disconnect(o, child);
1233 _evas_object_table_remove_opt(priv, opt);
1234 evas_object_smart_member_del(child);
1235 free(opt);
1236 _evas_object_table_cache_invalidate(priv);
1237 evas_object_smart_changed(o);
1238
1239 return EINA_TRUE;
1240}
1241
1242EAPI void
1243evas_object_table_clear(Evas_Object *o, Eina_Bool clear)
1244{
1245 Evas_Object_Table_Option *opt;
1246
1247 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
1248
1249 EINA_LIST_FREE(priv->children, opt)
1250 {
1251 _evas_object_table_child_disconnect(o, opt->obj);
1252 _evas_object_table_option_del(opt->obj);
1253 evas_object_smart_member_del(opt->obj);
1254 if (clear)
1255 evas_object_del(opt->obj);
1256 free(opt);
1257 }
1258 priv->size.cols = 0;
1259 priv->size.rows = 0;
1260 _evas_object_table_cache_invalidate(priv);
1261 evas_object_smart_changed(o);
1262}
1263
1264EAPI void
1265evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows)
1266{
1267 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1268 if (priv)
1269 {
1270 if (cols) *cols = priv->size.cols;
1271 if (rows) *rows = priv->size.rows;
1272 }
1273 else
1274 {
1275 if (cols) *cols = -1;
1276 if (rows) *rows = -1;
1277 }
1278}
1279
1280EAPI Eina_Iterator *
1281evas_object_table_iterator_new(const Evas_Object *o)
1282{
1283 Evas_Object_Table_Iterator *it;
1284
1285 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1286
1287 if (!priv->children) return NULL;
1288
1289 it = calloc(1, sizeof(Evas_Object_Table_Iterator));
1290 if (!it) return NULL;
1291
1292 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1293
1294 it->real_iterator = eina_list_iterator_new(priv->children);
1295 it->table = o;
1296
1297 it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_table_iterator_next);
1298 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_table_iterator_get_container);
1299 it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_table_iterator_free);
1300
1301 return &it->iterator;
1302}
1303
1304EAPI Eina_Accessor *
1305evas_object_table_accessor_new(const Evas_Object *o)
1306{
1307 Evas_Object_Table_Accessor *it;
1308
1309 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1310
1311 if (!priv->children) return NULL;
1312
1313 it = calloc(1, sizeof(Evas_Object_Table_Accessor));
1314 if (!it) return NULL;
1315
1316 EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
1317
1318 it->real_accessor = eina_list_accessor_new(priv->children);
1319 it->table = o;
1320
1321 it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_table_accessor_get_at);
1322 it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_table_accessor_get_container);
1323 it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_table_accessor_free);
1324
1325 return &it->accessor;
1326}
1327
1328EAPI Eina_List *
1329evas_object_table_children_get(const Evas_Object *o)
1330{
1331 Eina_List *new_list = NULL, *l;
1332 Evas_Object_Table_Option *opt;
1333
1334 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1335
1336 EINA_LIST_FOREACH(priv->children, l, opt)
1337 new_list = eina_list_append(new_list, opt->obj);
1338
1339 return new_list;
1340}
1341
1342Evas_Object *
1343evas_object_table_child_get(const Evas_Object *o, unsigned short col, unsigned short row)
1344{
1345 Eina_List *l;
1346 Evas_Object_Table_Option *opt;
1347
1348 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1349
1350 EINA_LIST_FOREACH(priv->children, l, opt)
1351 if (opt->col == col && opt->row == row)
1352 return opt->obj;
1353 return NULL;
1354}
1355
1356EAPI Eina_Bool
1357evas_object_table_mirrored_get(const Evas_Object *obj)
1358{
1359 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(obj, priv, EINA_FALSE);
1360
1361 return priv->is_mirrored;
1362}
1363
1364EAPI void
1365evas_object_table_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
1366{
1367 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(obj, priv);
1368 if (priv->is_mirrored != mirrored)
1369 {
1370 priv->is_mirrored = mirrored;
1371 _evas_object_table_smart_calculate(obj);
1372 }
1373}
diff --git a/libraries/evas/src/lib/canvas/evas_object_text.c b/libraries/evas/src/lib/canvas/evas_object_text.c
new file mode 100644
index 0000000..6c30fcc
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_text.c
@@ -0,0 +1,1943 @@
1#include "evas_common.h" /* Includes evas_bidi_utils stuff. */
2#include "evas_private.h"
3
4/* save typing */
5#define ENFN obj->layer->evas->engine.func
6#define ENDT obj->layer->evas->engine.data.output
7
8/* private magic number for text objects */
9static const char o_type[] = "text";
10
11/* private struct for text object internal data */
12typedef struct _Evas_Object_Text Evas_Object_Text;
13typedef struct _Evas_Object_Text_Item Evas_Object_Text_Item;
14
15struct _Evas_Object_Text
16{
17 DATA32 magic;
18
19 struct {
20 const char *utf8_text; /* The text exposed to the API */
21 const char *font;
22 Evas_Font_Description *fdesc;
23 const char *source;
24 Evas_Font_Size size;
25 struct {
26 unsigned char r, g, b, a;
27 } outline, shadow, glow, glow2;
28
29 unsigned char style;
30 } cur, prev;
31
32 float ascent, descent;
33 float max_ascent, max_descent;
34 Evas_BiDi_Paragraph_Props *bidi_par_props;
35 const char *bidi_delimiters;
36 Evas_Object_Text_Item *items;
37
38 Evas_Font_Set *font;
39
40 char changed : 1;
41};
42
43struct _Evas_Object_Text_Item
44{
45 EINA_INLIST;
46
47 size_t text_pos;
48 size_t visual_pos;
49 Evas_Text_Props text_props;
50 Evas_Coord x, w, h, adv;
51};
52
53/* private methods for text objects */
54static void evas_object_text_init(Evas_Object *obj);
55static void *evas_object_text_new(void);
56static void evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
57static void evas_object_text_free(Evas_Object *obj);
58static void evas_object_text_render_pre(Evas_Object *obj);
59static void evas_object_text_render_post(Evas_Object *obj);
60
61static unsigned int evas_object_text_id_get(Evas_Object *obj);
62static unsigned int evas_object_text_visual_id_get(Evas_Object *obj);
63static void *evas_object_text_engine_data_get(Evas_Object *obj);
64
65static int evas_object_text_is_opaque(Evas_Object *obj);
66static int evas_object_text_was_opaque(Evas_Object *obj);
67
68static void evas_object_text_scale_update(Evas_Object *obj);
69static void _evas_object_text_recalc(Evas_Object *obj);
70
71static const Evas_Object_Func object_func =
72{
73 /* methods (compulsory) */
74 evas_object_text_free,
75 evas_object_text_render,
76 evas_object_text_render_pre,
77 evas_object_text_render_post,
78 evas_object_text_id_get,
79 evas_object_text_visual_id_get,
80 evas_object_text_engine_data_get,
81 /* these are optional. NULL = nothing */
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 evas_object_text_is_opaque,
87 evas_object_text_was_opaque,
88 NULL,
89 NULL,
90 NULL,
91 evas_object_text_scale_update,
92 NULL,
93 NULL,
94 NULL
95};
96
97/* the actual api call to add a rect */
98/* it has no other api calls as all properties are standard */
99
100EVAS_MEMPOOL(_mp_obj);
101
102static int
103_evas_object_text_char_coords_get(const Evas_Object *obj,
104 const Evas_Object_Text *o,
105 size_t pos, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
106{
107 Evas_Object_Text_Item *it;
108
109 EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
110 {
111 if ((it->text_pos <= pos) &&
112 (pos < (it->text_pos + it->text_props.text_len)))
113 {
114 int ret;
115 ret = ENFN->font_char_coords_get(ENDT, o->font,
116 &it->text_props, pos - it->text_pos, x, y, w, h);
117 if (x) *x += it->x;
118 return ret;
119 }
120 }
121 return 0;
122}
123
124static void
125_evas_object_text_item_clean(Evas_Object_Text_Item *it)
126{
127 evas_common_text_props_content_unref(&it->text_props);
128}
129
130static void
131_evas_object_text_items_clear(Evas_Object_Text *o)
132{
133 Evas_Object_Text_Item *it;
134
135 while (o->items)
136 {
137 it = o->items;
138 o->items = (Evas_Object_Text_Item *) eina_inlist_remove(
139 EINA_INLIST_GET(o->items),
140 EINA_INLIST_GET(it));
141 _evas_object_text_item_clean(it);
142 free(it);
143 }
144}
145
146#ifdef BIDI_SUPPORT
147static int
148_evas_object_text_it_compare_logical(const void *_it1, const void *_it2)
149{
150 const Evas_Object_Text_Item *it1 = _it1, *it2 = _it2;
151 if (it1->text_pos < it2->text_pos)
152 return -1;
153 else if (it1->text_pos == it2->text_pos)
154 return 0;
155 else
156 return 1;
157
158}
159#endif
160
161static int
162_evas_object_text_last_up_to_pos(const Evas_Object *obj,
163 const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy)
164{
165 Evas_Object_Text_Item *it;
166
167#ifdef BIDI_SUPPORT
168 /*FIXME: not very efficient, sort the items arrays. */
169 /* Reorder if it's a bidi text */
170 if (o->bidi_par_props)
171 {
172 Eina_List *logical_it = NULL;
173 Evas_Object_Text_Item *i;
174 Eina_List *itr;
175 Evas_Coord x = 0;
176 /* Insert all to the logical list */
177 EINA_INLIST_FOREACH(o->items, i)
178 {
179 logical_it = eina_list_sorted_insert(logical_it,
180 _evas_object_text_it_compare_logical, i);
181 }
182 EINA_LIST_FOREACH(logical_it, itr, it)
183 {
184 if ((x <= cx) && (cx < x + it->adv))
185 {
186 return it->text_pos + ENFN->font_last_up_to_pos(ENDT,
187 o->font,
188 &it->text_props,
189 cx - x,
190 cy);
191 }
192 x += it->adv;
193 }
194 eina_list_free(logical_it);
195 }
196 else
197#endif
198 {
199 EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
200 {
201 if ((it->x <= cx) && (cx < it->x + it->adv))
202 {
203 return it->text_pos + ENFN->font_last_up_to_pos(ENDT,
204 o->font,
205 &it->text_props,
206 cx - it->x,
207 cy);
208 }
209 }
210 }
211 return -1;
212}
213
214static int
215_evas_object_text_char_at_coords(const Evas_Object *obj,
216 const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy,
217 Evas_Coord *rx, Evas_Coord *ry, Evas_Coord *rw, Evas_Coord *rh)
218{
219 Evas_Object_Text_Item *it;
220
221 EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
222 {
223 if ((it->x <= cx) && (cx < it->x + it->adv))
224 {
225 return it->text_pos + ENFN->font_char_at_coords_get(ENDT,
226 o->font,
227 &it->text_props,
228 cx - it->x,
229 cy,
230 rx, ry,
231 rw, rh);
232 }
233 }
234 return -1;
235}
236
237static Evas_Coord
238_evas_object_text_horiz_advance_get(const Evas_Object *obj,
239 const Evas_Object_Text *o)
240{
241 Evas_Object_Text_Item *it;
242 Evas_Coord adv;
243 (void) obj;
244
245 adv = 0;
246 EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
247 {
248 adv += it->adv;
249 }
250 return adv;
251}
252
253static Evas_Coord
254_evas_object_text_vert_advance_get(const Evas_Object *obj __UNUSED__,
255 const Evas_Object_Text *o)
256{
257 return o->max_ascent + o->max_descent;
258}
259
260EAPI Evas_Object *
261evas_object_text_add(Evas *e)
262{
263 Evas_Object *obj;
264
265 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
266 return NULL;
267 MAGIC_CHECK_END();
268 obj = evas_object_new(e);
269 evas_object_text_init(obj);
270 evas_object_inject(obj, e);
271 return obj;
272}
273
274EAPI void
275evas_object_text_font_source_set(Evas_Object *obj, const char *font_source)
276{
277 Evas_Object_Text *o;
278
279 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
280 return;
281 MAGIC_CHECK_END();
282 o = (Evas_Object_Text *)(obj->object_data);
283 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
284 return;
285 MAGIC_CHECK_END();
286
287 if ((o->cur.source) && (font_source) &&
288 (!strcmp(o->cur.source, font_source)))
289 return;
290 /*
291 if (o->cur.source) eina_stringshare_del(o->cur.source);
292 if (font_source) o->cur.source = eina_stringshare_add(font_source);
293 else o->cur.source = NULL;
294 */
295 eina_stringshare_replace(&o->cur.source, font_source);
296}
297
298EAPI const char *
299evas_object_text_font_source_get(const Evas_Object *obj)
300{
301 Evas_Object_Text *o;
302
303 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
304 return NULL;
305 MAGIC_CHECK_END();
306 o = (Evas_Object_Text *)(obj->object_data);
307 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
308 return NULL;
309 MAGIC_CHECK_END();
310 return o->cur.source;
311}
312
313EAPI void
314evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size size)
315{
316 Evas_Object_Text *o;
317 int is, was = 0, pass = 0, freeze = 0;
318 Evas_Font_Description *fdesc;
319
320 if ((!font) || (size <= 0)) return;
321 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
322 return;
323 MAGIC_CHECK_END();
324 o = (Evas_Object_Text *)(obj->object_data);
325 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
326 return;
327 MAGIC_CHECK_END();
328
329 fdesc = evas_font_desc_new();
330 evas_font_name_parse(fdesc, font);
331 if (o->cur.fdesc && !evas_font_desc_cmp(fdesc, o->cur.fdesc) &&
332 (size == o->cur.size))
333 {
334 evas_font_desc_unref(fdesc);
335 return;
336 }
337
338 if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
339 o->cur.fdesc = fdesc;
340
341 o->cur.size = size;
342 eina_stringshare_replace(&o->cur.font, font);
343 o->prev.font = NULL;
344
345 if (obj->layer->evas->events_frozen <= 0)
346 {
347 pass = evas_event_passes_through(obj);
348 freeze = evas_event_freezes_through(obj);
349 if ((!pass) && (!freeze))
350 was = evas_object_is_in_output_rect(obj,
351 obj->layer->evas->pointer.x,
352 obj->layer->evas->pointer.y, 1, 1);
353 }
354
355#ifdef EVAS_FRAME_QUEUING
356 if (o->font)
357 evas_common_pipe_op_text_flush((RGBA_Font *) o->font);
358#endif
359
360 /* DO IT */
361 if (o->font)
362 {
363 evas_font_free(obj->layer->evas, o->font);
364 o->font = NULL;
365 }
366
367 o->font = evas_font_load(obj->layer->evas, o->cur.fdesc, o->cur.source,
368 (int)(((double) o->cur.size) * obj->cur.scale));
369 if (o->font)
370 {
371 o->ascent = ENFN->font_ascent_get(ENDT, o->font);
372 o->descent = ENFN->font_descent_get(ENDT, o->font);
373 o->max_ascent = ENFN->font_max_ascent_get(ENDT, o->font);
374 o->max_descent = ENFN->font_max_descent_get(ENDT, o->font);
375 }
376 else
377 {
378 o->ascent = 0;
379 o->descent = 0;
380 o->max_ascent = 0;
381 o->max_descent = 0;
382 }
383 _evas_object_text_recalc(obj);
384 o->changed = 1;
385 evas_object_change(obj);
386 evas_object_clip_dirty(obj);
387 evas_object_coords_recalc(obj);
388 if (obj->layer->evas->events_frozen <= 0)
389 {
390 if ((!pass) && (!freeze))
391 {
392 is = evas_object_is_in_output_rect(obj,
393 obj->layer->evas->pointer.x,
394 obj->layer->evas->pointer.y,
395 1, 1);
396 if ((is ^ was) && obj->cur.visible)
397 evas_event_feed_mouse_move(obj->layer->evas,
398 obj->layer->evas->pointer.x,
399 obj->layer->evas->pointer.y,
400 obj->layer->evas->last_timestamp,
401 NULL);
402 }
403 }
404 evas_object_inform_call_resize(obj);
405}
406
407EAPI void
408evas_object_text_font_get(const Evas_Object *obj, const char **font, Evas_Font_Size *size)
409{
410 Evas_Object_Text *o;
411
412 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
413 if (font) *font = "";
414 if (size) *size = 0;
415 return;
416 MAGIC_CHECK_END();
417 o = (Evas_Object_Text *)(obj->object_data);
418 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
419 if (font) *font = "";
420 if (size) *size = 0;
421 return;
422 MAGIC_CHECK_END();
423 if (font) *font = o->cur.font;
424 if (size) *size = o->cur.size;
425}
426
427
428/**
429 * @internal
430 * Create a new text layout item from the string and the format.
431 *
432 * @param c the context to work on - Not NULL.
433 * @param fmt the format to use.
434 * @param str the string to use.
435 */
436static Evas_Object_Text_Item *
437_evas_object_text_item_new(Evas_Object *obj, Evas_Object_Text *o,
438 Evas_Font_Instance *fi, const Eina_Unicode *str, Evas_Script_Type script,
439 size_t pos, size_t visual_pos, size_t len)
440{
441 Evas_Object_Text_Item *it;
442
443 it = calloc(1, sizeof(Evas_Object_Text_Item));
444 it->text_pos = pos;
445 it->visual_pos = visual_pos;
446 evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props,
447 it->text_pos);
448 evas_common_text_props_script_set(&it->text_props, script);
449
450 if (fi)
451 {
452 ENFN->font_text_props_info_create(ENDT,
453 fi, str + pos, &it->text_props,
454 o->bidi_par_props, it->text_pos, len);
455
456 ENFN->font_string_size_get(ENDT,
457 o->font,
458 &it->text_props,
459 &it->w, &it->h);
460 it->adv = ENFN->font_h_advance_get(ENDT, o->font,
461 &it->text_props);
462 }
463 o->items = (Evas_Object_Text_Item *)
464 eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(it));
465 return it;
466}
467
468/**
469 * @internal
470 * Orders o->items according to the visual position.
471 *
472 * @param obj the evas object
473 * @param o the text object
474 */
475static void
476_evas_object_text_item_order(Evas_Object *obj, Evas_Object_Text *o)
477{
478 (void) obj;
479#ifdef BIDI_SUPPORT
480 /*FIXME: not very efficient, sort the items arrays. */
481 /* Reorder if it's a bidi text */
482 if (o->bidi_par_props)
483 {
484 Evas_Object_Text_Item *i, *j, *min;
485 i = o->items;
486 while (i)
487 {
488 min = i;
489 EINA_INLIST_FOREACH(i, j)
490 {
491 if (j->visual_pos < min->visual_pos)
492 {
493 min = j;
494 }
495 }
496 if (min != i)
497 {
498 o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min));
499 o->items = (Evas_Object_Text_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
500 }
501
502 i = (Evas_Object_Text_Item *) EINA_INLIST_GET(min)->next;
503 }
504 }
505#endif
506
507 /* calculate the positions according to the order. */
508 {
509 Evas_Object_Text_Item *it = o->items;
510 Evas_Coord x = 0;
511
512 while (it)
513 {
514 it->x = x;
515 x += it->adv;
516 it = (Evas_Object_Text_Item *) EINA_INLIST_GET(it)->next;
517 }
518 }
519}
520
521/**
522 * @internal
523 * Populates o->items with the items of the text according to text
524 *
525 * @param obj the evas object
526 * @param o the text object
527 * @param text the text to layout
528 */
529static void
530_evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unicode *text)
531{
532 EvasBiDiStrIndex *v_to_l = NULL;
533 size_t pos, visual_pos;
534 int len = eina_unicode_strlen(text), par_len;
535#ifdef BIDI_SUPPORT
536 int *segment_idxs = NULL;
537 if (o->bidi_delimiters)
538 segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
539 evas_bidi_paragraph_props_unref(o->bidi_par_props);
540 o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs);
541 evas_bidi_props_reorder_line(NULL, 0, len, o->bidi_par_props, &v_to_l);
542 if (segment_idxs) free(segment_idxs);
543#endif
544 visual_pos = pos = 0;
545
546 par_len = len;
547 while (len > 0)
548 {
549 Evas_Font_Instance *script_fi = NULL;
550 int script_len = len, tmp_cut;
551 Evas_Script_Type script;
552 tmp_cut = evas_common_language_script_end_of_run_get(
553 text + pos,
554 o->bidi_par_props,
555 pos, len);
556 if (tmp_cut > 0)
557 script_len = tmp_cut;
558
559 script = evas_common_language_script_type_get(text, script_len);
560
561 while (script_len > 0)
562 {
563 Evas_Font_Instance *cur_fi = NULL;
564 int run_len = script_len;
565 if (o->font)
566 {
567 run_len = ENFN->font_run_end_get(ENDT,
568 o->font, &script_fi, &cur_fi,
569 script, text + pos, script_len);
570 }
571#ifdef BIDI_SUPPORT
572 visual_pos = evas_bidi_position_logical_to_visual(
573 v_to_l, par_len, pos);
574#else
575 visual_pos = pos;
576#endif
577 _evas_object_text_item_new(obj, o, cur_fi, text, script,
578 pos, visual_pos, run_len);
579
580 pos += run_len;
581 script_len -= run_len;
582 len -= run_len;
583 }
584 }
585
586 _evas_object_text_item_order(obj, o);
587
588 if (v_to_l) free(v_to_l);
589}
590
591
592EAPI void
593evas_object_text_text_set(Evas_Object *obj, const char *_text)
594{
595 Evas_Object_Text *o;
596 int is, was, len;
597 Eina_Unicode *text;
598
599 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
600 return;
601 MAGIC_CHECK_END();
602 o = (Evas_Object_Text *)(obj->object_data);
603 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
604 return;
605 MAGIC_CHECK_END();
606
607 if ((o->cur.utf8_text) && (_text) && (!strcmp(o->cur.utf8_text, _text)))
608 return;
609 text = eina_unicode_utf8_to_unicode(_text, &len);
610
611 if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
612 was = evas_object_is_in_output_rect(obj,
613 obj->layer->evas->pointer.x,
614 obj->layer->evas->pointer.y, 1, 1);
615 /* DO II */
616 /*Update bidi_props*/
617
618 if (o->items) _evas_object_text_items_clear(o);
619
620 if ((text) && (*text))
621 {
622 _evas_object_text_layout(obj, o, text);
623 eina_stringshare_replace(&o->cur.utf8_text, _text);
624 o->prev.utf8_text = NULL;
625 }
626 else
627 {
628 eina_stringshare_replace(&o->cur.utf8_text, NULL);
629 }
630 if (text)
631 {
632 free(text);
633 text = NULL;
634 }
635 _evas_object_text_recalc(obj);
636 o->changed = 1;
637 evas_object_change(obj);
638 evas_object_clip_dirty(obj);
639 evas_object_coords_recalc(obj);
640 is = evas_object_is_in_output_rect(obj,
641 obj->layer->evas->pointer.x,
642 obj->layer->evas->pointer.y, 1, 1);
643 if ((is || was) && obj->cur.visible)
644 evas_event_feed_mouse_move(obj->layer->evas,
645 obj->layer->evas->pointer.x,
646 obj->layer->evas->pointer.y,
647 obj->layer->evas->last_timestamp,
648 NULL);
649 evas_object_inform_call_resize(obj);
650 if (text) free(text);
651}
652
653EAPI void
654evas_object_text_bidi_delimiters_set(Evas_Object *obj, const char *delim)
655{
656 Evas_Object_Text *o;
657
658 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
659 return;
660 MAGIC_CHECK_END();
661 o = (Evas_Object_Text *)(obj->object_data);
662 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
663 return;
664 MAGIC_CHECK_END();
665
666 eina_stringshare_replace(&o->bidi_delimiters, delim);
667}
668
669EAPI const char *
670evas_object_text_bidi_delimiters_get(const Evas_Object *obj)
671{
672 Evas_Object_Text *o;
673
674 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
675 return NULL;
676 MAGIC_CHECK_END();
677 o = (Evas_Object_Text *)(obj->object_data);
678 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
679 return NULL;
680 MAGIC_CHECK_END();
681
682 return o->bidi_delimiters;
683}
684
685
686EAPI const char *
687evas_object_text_text_get(const Evas_Object *obj)
688{
689 Evas_Object_Text *o;
690
691 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
692 return NULL;
693 MAGIC_CHECK_END();
694 o = (Evas_Object_Text *)(obj->object_data);
695 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
696 return NULL;
697 MAGIC_CHECK_END();
698 return o->cur.utf8_text;
699}
700
701EAPI Evas_BiDi_Direction
702evas_object_text_direction_get(const Evas_Object *obj)
703{
704 Evas_Object_Text *o;
705
706 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
707 return EVAS_BIDI_DIRECTION_NEUTRAL;
708 MAGIC_CHECK_END();
709 o = (Evas_Object_Text *)(obj->object_data);
710 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
711 return EVAS_BIDI_DIRECTION_NEUTRAL;
712 MAGIC_CHECK_END();
713 if (o->items)
714 {
715 return o->items->text_props.bidi.dir;
716 }
717 return EVAS_BIDI_DIRECTION_NEUTRAL;
718}
719
720EAPI Evas_Coord
721evas_object_text_ascent_get(const Evas_Object *obj)
722{
723 Evas_Object_Text *o;
724
725 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
726 return 0;
727 MAGIC_CHECK_END();
728 o = (Evas_Object_Text *)(obj->object_data);
729 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
730 return 0;
731 MAGIC_CHECK_END();
732 return o->ascent;
733}
734
735EAPI Evas_Coord
736evas_object_text_descent_get(const Evas_Object *obj)
737{
738 Evas_Object_Text *o;
739
740 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
741 return 0;
742 MAGIC_CHECK_END();
743 o = (Evas_Object_Text *)(obj->object_data);
744 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
745 return 0;
746 MAGIC_CHECK_END();
747 return o->descent;
748}
749
750EAPI Evas_Coord
751evas_object_text_max_ascent_get(const Evas_Object *obj)
752{
753 Evas_Object_Text *o;
754
755 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
756 return 0;
757 MAGIC_CHECK_END();
758 o = (Evas_Object_Text *)(obj->object_data);
759 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
760 return 0;
761 MAGIC_CHECK_END();
762 return o->max_ascent;
763}
764
765EAPI Evas_Coord
766evas_object_text_max_descent_get(const Evas_Object *obj)
767{
768 Evas_Object_Text *o;
769
770 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
771 return 0;
772 MAGIC_CHECK_END();
773 o = (Evas_Object_Text *)(obj->object_data);
774 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
775 return 0;
776 MAGIC_CHECK_END();
777 return o->max_descent;
778}
779
780EAPI Evas_Coord
781evas_object_text_inset_get(const Evas_Object *obj)
782{
783 Evas_Object_Text *o;
784
785 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
786 return 0;
787 MAGIC_CHECK_END();
788 o = (Evas_Object_Text *)(obj->object_data);
789 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
790 return 0;
791 MAGIC_CHECK_END();
792 if (!o->font) return 0;
793 if (!o->items) return 0;
794 return ENFN->font_inset_get(ENDT, o->font, &o->items->text_props);
795}
796
797EAPI Evas_Coord
798evas_object_text_horiz_advance_get(const Evas_Object *obj)
799{
800 Evas_Object_Text *o;
801
802 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
803 return 0;
804 MAGIC_CHECK_END();
805 o = (Evas_Object_Text *)(obj->object_data);
806 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
807 return 0;
808 MAGIC_CHECK_END();
809 if (!o->font) return 0;
810 if (!o->items) return 0;
811 return _evas_object_text_horiz_advance_get(obj, o);
812}
813
814EAPI Evas_Coord
815evas_object_text_vert_advance_get(const Evas_Object *obj)
816{
817 Evas_Object_Text *o;
818
819 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
820 return 0;
821 MAGIC_CHECK_END();
822 o = (Evas_Object_Text *)(obj->object_data);
823 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
824 return 0;
825 MAGIC_CHECK_END();
826 if (!o->font) return 0;
827 if (!o->items) return o->ascent + o->descent;
828 return _evas_object_text_vert_advance_get(obj, o);
829}
830
831EAPI Eina_Bool
832evas_object_text_char_pos_get(const Evas_Object *obj, int pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
833{
834 Evas_Object_Text *o;
835 int l = 0, r = 0, t = 0, b = 0;
836 int ret, x = 0, y = 0, w = 0, h = 0;
837
838 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
839 return EINA_FALSE;
840 MAGIC_CHECK_END();
841 o = (Evas_Object_Text *)(obj->object_data);
842 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
843 return EINA_FALSE;
844 MAGIC_CHECK_END();
845 if (!o->font) return EINA_FALSE;
846 if (!o->items || (pos < 0)) return EINA_FALSE;
847 ret = _evas_object_text_char_coords_get(obj, o, (size_t) pos,
848 &x, &y, &w, &h);
849 evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
850 y += o->max_ascent - t;
851 x -= l;
852 if (x < 0)
853 {
854 w += x;
855 x = 0;
856 }
857 if ((x + w) > obj->cur.geometry.w) w = obj->cur.geometry.w - x;
858 if (w < 0) w = 0;
859 if (y < 0)
860 {
861 h += y;
862 y = 0;
863 }
864 if ((y + h) > obj->cur.geometry.h) h = obj->cur.geometry.h - y;
865 if (h < 0) h = 0;
866 if (cx) *cx = x;
867 if (cy) *cy = y;
868 if (cw) *cw = w + l + r;
869 if (ch) *ch = h + t + b;
870 return ret;
871}
872
873
874EAPI int
875evas_object_text_last_up_to_pos(const Evas_Object *obj, Evas_Coord x, Evas_Coord y)
876{
877 Evas_Object_Text *o;
878
879 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
880 return -1;
881 MAGIC_CHECK_END();
882 o = (Evas_Object_Text *)(obj->object_data);
883 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
884 return -1;
885 MAGIC_CHECK_END();
886 if (!o->font) return -1;
887 if (!o->items) return -1;
888 return _evas_object_text_last_up_to_pos(obj, o, x, y - o->max_ascent);
889}
890
891EAPI int
892evas_object_text_char_coords_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
893{
894 Evas_Object_Text *o;
895 int l = 0, r = 0, t = 0, b = 0;
896 int ret, rx = 0, ry = 0, rw = 0, rh = 0;
897
898 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
899 return -1;
900 MAGIC_CHECK_END();
901 o = (Evas_Object_Text *)(obj->object_data);
902 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
903 return -1;
904 MAGIC_CHECK_END();
905 if (!o->font) return -1;
906 if (!o->items) return -1;
907 ret = _evas_object_text_char_at_coords(obj, o, x, y - o->max_ascent,
908 &rx, &ry, &rw, &rh);
909 evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
910 ry += o->max_ascent - t;
911 rx -= l;
912 if (rx < 0)
913 {
914 rw += rx;
915 rx = 0;
916 }
917 if ((rx + rw) > obj->cur.geometry.w) rw = obj->cur.geometry.w - rx;
918 if (rw < 0) rw = 0;
919 if (ry < 0)
920 {
921 rh += ry;
922 ry = 0;
923 }
924 if ((ry + rh) > obj->cur.geometry.h) rh = obj->cur.geometry.h - ry;
925 if (rh < 0) rh = 0;
926 if (cx) *cx = rx;
927 if (cy) *cy = ry;
928 if (cw) *cw = rw + l + r;
929 if (ch) *ch = rh + t + b;
930 return ret;
931}
932
933EAPI void
934evas_object_text_style_set(Evas_Object *obj, Evas_Text_Style_Type style)
935{
936 Evas_Object_Text *o;
937 int pl = 0, pr = 0, pt = 0, pb = 0, l = 0, r = 0, t = 0, b = 0;
938
939 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
940 return;
941 MAGIC_CHECK_END();
942 o = (Evas_Object_Text *)(obj->object_data);
943 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
944 return;
945 MAGIC_CHECK_END();
946 if (o->cur.style == style) return;
947 evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb);
948 o->cur.style = style;
949 evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
950 if (o->items)
951 obj->cur.geometry.w += (l - pl) + (r - pr);
952 else
953 obj->cur.geometry.w = 0;
954 obj->cur.geometry.h += (t - pt) + (b - pb);
955 evas_object_change(obj);
956 evas_object_clip_dirty(obj);
957}
958
959EAPI Evas_Text_Style_Type
960evas_object_text_style_get(const Evas_Object *obj)
961{
962 Evas_Object_Text *o;
963
964 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
965 return EVAS_TEXT_STYLE_PLAIN;
966 MAGIC_CHECK_END();
967 o = (Evas_Object_Text *)(obj->object_data);
968 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
969 return EVAS_TEXT_STYLE_PLAIN;
970 MAGIC_CHECK_END();
971 return o->cur.style;
972}
973
974EAPI void
975evas_object_text_shadow_color_set(Evas_Object *obj, int r, int g, int b, int a)
976{
977 Evas_Object_Text *o;
978
979 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
980 return;
981 MAGIC_CHECK_END();
982 o = (Evas_Object_Text *)(obj->object_data);
983 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
984 return;
985 MAGIC_CHECK_END();
986 if ((o->cur.shadow.r == r) && (o->cur.shadow.g == g) &&
987 (o->cur.shadow.b == b) && (o->cur.shadow.a == a))
988 return;
989 o->cur.shadow.r = r;
990 o->cur.shadow.g = g;
991 o->cur.shadow.b = b;
992 o->cur.shadow.a = a;
993 o->changed = 1;
994 evas_object_change(obj);
995}
996
997EAPI void
998evas_object_text_shadow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
999{
1000 Evas_Object_Text *o;
1001
1002 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1003 if (r) *r = 0;
1004 if (g) *g = 0;
1005 if (b) *b = 0;
1006 if (a) *a = 0;
1007 return;
1008 MAGIC_CHECK_END();
1009 o = (Evas_Object_Text *)(obj->object_data);
1010 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1011 if (r) *r = 0;
1012 if (g) *g = 0;
1013 if (b) *b = 0;
1014 if (a) *a = 0;
1015 return;
1016 MAGIC_CHECK_END();
1017 if (r) *r = o->cur.shadow.r;
1018 if (g) *g = o->cur.shadow.g;
1019 if (b) *b = o->cur.shadow.b;
1020 if (a) *a = o->cur.shadow.a;
1021}
1022
1023EAPI void
1024evas_object_text_glow_color_set(Evas_Object *obj, int r, int g, int b, int a)
1025{
1026 Evas_Object_Text *o;
1027
1028 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1029 return;
1030 MAGIC_CHECK_END();
1031 o = (Evas_Object_Text *)(obj->object_data);
1032 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1033 return;
1034 MAGIC_CHECK_END();
1035 if ((o->cur.glow.r == r) && (o->cur.glow.g == g) &&
1036 (o->cur.glow.b == b) && (o->cur.glow.a == a))
1037 return;
1038 o->cur.glow.r = r;
1039 o->cur.glow.g = g;
1040 o->cur.glow.b = b;
1041 o->cur.glow.a = a;
1042 o->changed = 1;
1043 evas_object_change(obj);
1044}
1045
1046EAPI void
1047evas_object_text_glow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1048{
1049 Evas_Object_Text *o;
1050
1051 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1052 if (r) *r = 0;
1053 if (g) *g = 0;
1054 if (b) *b = 0;
1055 if (a) *a = 0;
1056 return;
1057 MAGIC_CHECK_END();
1058 o = (Evas_Object_Text *)(obj->object_data);
1059 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1060 if (r) *r = 0;
1061 if (g) *g = 0;
1062 if (b) *b = 0;
1063 if (a) *a = 0;
1064 return;
1065 MAGIC_CHECK_END();
1066 if (r) *r = o->cur.glow.r;
1067 if (g) *g = o->cur.glow.g;
1068 if (b) *b = o->cur.glow.b;
1069 if (a) *a = o->cur.glow.a;
1070}
1071
1072EAPI void
1073evas_object_text_glow2_color_set(Evas_Object *obj, int r, int g, int b, int a)
1074{
1075 Evas_Object_Text *o;
1076
1077 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1078 return;
1079 MAGIC_CHECK_END();
1080 o = (Evas_Object_Text *)(obj->object_data);
1081 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1082 return;
1083 MAGIC_CHECK_END();
1084 if ((o->cur.glow2.r == r) && (o->cur.glow2.g == g) &&
1085 (o->cur.glow2.b == b) && (o->cur.glow2.a == a))
1086 return;
1087 o->cur.glow2.r = r;
1088 o->cur.glow2.g = g;
1089 o->cur.glow2.b = b;
1090 o->cur.glow2.a = a;
1091 o->changed = 1;
1092 evas_object_change(obj);
1093}
1094
1095EAPI void
1096evas_object_text_glow2_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1097{
1098 Evas_Object_Text *o;
1099
1100 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1101 if (r) *r = 0;
1102 if (g) *g = 0;
1103 if (b) *b = 0;
1104 if (a) *a = 0;
1105 return;
1106 MAGIC_CHECK_END();
1107 o = (Evas_Object_Text *)(obj->object_data);
1108 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1109 if (r) *r = 0;
1110 if (g) *g = 0;
1111 if (b) *b = 0;
1112 if (a) *a = 0;
1113 return;
1114 MAGIC_CHECK_END();
1115 if (r) *r = o->cur.glow2.r;
1116 if (g) *g = o->cur.glow2.g;
1117 if (b) *b = o->cur.glow2.b;
1118 if (a) *a = o->cur.glow2.a;
1119}
1120
1121EAPI void
1122evas_object_text_outline_color_set(Evas_Object *obj, int r, int g, int b, int a)
1123{
1124 Evas_Object_Text *o;
1125
1126 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1127 return;
1128 MAGIC_CHECK_END();
1129 o = (Evas_Object_Text *)(obj->object_data);
1130 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1131 return;
1132 MAGIC_CHECK_END();
1133 if ((o->cur.outline.r == r) && (o->cur.outline.g == g) &&
1134 (o->cur.outline.b == b) && (o->cur.outline.a == a))
1135 return;
1136 o->cur.outline.r = r;
1137 o->cur.outline.g = g;
1138 o->cur.outline.b = b;
1139 o->cur.outline.a = a;
1140 o->changed = 1;
1141 evas_object_change(obj);
1142}
1143
1144EAPI void
1145evas_object_text_outline_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1146{
1147 Evas_Object_Text *o;
1148
1149 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1150 if (r) *r = 0;
1151 if (g) *g = 0;
1152 if (b) *b = 0;
1153 if (a) *a = 0;
1154 return;
1155 MAGIC_CHECK_END();
1156 o = (Evas_Object_Text *)(obj->object_data);
1157 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1158 if (r) *r = 0;
1159 if (g) *g = 0;
1160 if (b) *b = 0;
1161 if (a) *a = 0;
1162 return;
1163 MAGIC_CHECK_END();
1164 if (r) *r = o->cur.outline.r;
1165 if (g) *g = o->cur.outline.g;
1166 if (b) *b = o->cur.outline.b;
1167 if (a) *a = o->cur.outline.a;
1168}
1169
1170EAPI void
1171evas_object_text_style_pad_get(const Evas_Object *obj, int *l, int *r, int *t, int *b)
1172{
1173 int sl = 0, sr = 0, st = 0, sb = 0;
1174 Evas_Object_Text *o;
1175
1176 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1177 if (l) *l = 0;
1178 if (r) *r = 0;
1179 if (t) *t = 0;
1180 if (b) *b = 0;
1181 return;
1182 MAGIC_CHECK_END();
1183 o = (Evas_Object_Text *)(obj->object_data);
1184 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1185 if (l) *l = 0;
1186 if (r) *r = 0;
1187 if (t) *t = 0;
1188 if (b) *b = 0;
1189 return;
1190 MAGIC_CHECK_END();
1191 /* use temps to be certain we have initialized values */
1192 evas_text_style_pad_get(o->cur.style, &sl, &sr, &st, &sb);
1193 if (l) *l = sl;
1194 if (r) *r = sr;
1195 if (t) *t = st;
1196 if (b) *b = sb;
1197}
1198
1199
1200
1201
1202EAPI int
1203evas_string_char_next_get(const char *str, int pos, int *decoded)
1204{
1205 int p, d;
1206
1207 if (decoded) *decoded = 0;
1208 if ((!str) || (pos < 0)) return 0;
1209 p = pos;
1210 d = eina_unicode_utf8_get_next(str, &p);
1211 if (decoded) *decoded = d;
1212 return p;
1213}
1214
1215EAPI int
1216evas_string_char_prev_get(const char *str, int pos, int *decoded)
1217{
1218 int p, d;
1219
1220 if (decoded) *decoded = 0;
1221 if ((!str) || (pos < 1)) return 0;
1222 p = pos;
1223 d = eina_unicode_utf8_get_prev(str, &p);
1224 if (decoded) *decoded = d;
1225 return p;
1226}
1227
1228EAPI int
1229evas_string_char_len_get(const char *str)
1230{
1231 if (!str) return 0;
1232 return eina_unicode_utf8_get_len(str);
1233}
1234
1235void
1236evas_text_style_pad_get(Evas_Text_Style_Type style, int *l, int *r, int *t, int *b)
1237{
1238 int sl = 0, sr = 0, st = 0, sb = 0;
1239
1240 /* Don't calc anything if there's no style. */
1241 if (style != EVAS_TEXT_STYLE_PLAIN)
1242 {
1243 int shad_sz = 0, shad_dst = 0, out_sz = 0;
1244 int dx = 0, minx = 0, maxx = 0;
1245 int dy = 0, miny = 0, maxy = 0;
1246 Eina_Bool have_shadow = EINA_FALSE;
1247
1248 switch (style & EVAS_TEXT_STYLE_MASK_BASIC)
1249 {
1250 case EVAS_TEXT_STYLE_SHADOW:
1251 shad_dst = 1;
1252 have_shadow = EINA_TRUE;
1253 break;
1254 case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1255 case EVAS_TEXT_STYLE_FAR_SHADOW:
1256 shad_dst = 2;
1257 out_sz = 1;
1258 have_shadow = EINA_TRUE;
1259 break;
1260 case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1261 shad_dst = 1;
1262 shad_sz = 2;
1263 out_sz = 1;
1264 have_shadow = EINA_TRUE;
1265 break;
1266 case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1267 shad_dst = 2;
1268 shad_sz = 2;
1269 have_shadow = EINA_TRUE;
1270 break;
1271 case EVAS_TEXT_STYLE_SOFT_SHADOW:
1272 shad_dst = 1;
1273 shad_sz = 2;
1274 have_shadow = EINA_TRUE;
1275 break;
1276 case EVAS_TEXT_STYLE_GLOW:
1277 case EVAS_TEXT_STYLE_SOFT_OUTLINE:
1278 out_sz = 2;
1279 break;
1280 case EVAS_TEXT_STYLE_OUTLINE:
1281 out_sz = 1;
1282 break;
1283 default:
1284 break;
1285 }
1286
1287 minx = -out_sz;
1288 maxx = out_sz;
1289 miny = -out_sz;
1290 maxy = out_sz;
1291 if (have_shadow)
1292 {
1293 int shx1, shx2, shy1, shy2;
1294 switch (style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1295 {
1296 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1297 dx = 1;
1298 dy = 1;
1299 break;
1300 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1301 dx = 0;
1302 dy = 1;
1303 break;
1304 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1305 dx = -1;
1306 dy = 1;
1307 break;
1308 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1309 dx = -1;
1310 dy = 0;
1311 break;
1312 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1313 dx = -1;
1314 dy = -1;
1315 break;
1316 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1317 dx = 0;
1318 dy = -1;
1319 break;
1320 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1321 dx = 1;
1322 dy = -1;
1323 break;
1324 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1325 dx = 1;
1326 dy = 0;
1327 default:
1328 break;
1329 }
1330 shx1 = dx * shad_dst;
1331 shx1 -= shad_sz;
1332 shx2 = dx * shad_dst;
1333 shx2 += shad_sz;
1334 if (shx1 < minx) minx = shx1;
1335 if (shx2 > maxx) maxx = shx2;
1336
1337 shy1 = dy * shad_dst;
1338 shy1 -= shad_sz;
1339 shy2 = dy * shad_dst;
1340 shy2 += shad_sz;
1341 if (shy1 < miny) miny = shy1;
1342 if (shy2 > maxy) maxy = shy2;
1343 }
1344
1345 if (l) sl = *l;
1346 if (r) sr = *r;
1347 if (t) st = *t;
1348 if (b) sb = *b;
1349
1350 if (sr < maxx) sr = maxx;
1351 if (sl < -minx) sl = -minx;
1352 if (sb < maxy) sb = maxy;
1353 if (st < -miny) st = -miny;
1354 }
1355
1356 if (l) *l = sl;
1357 if (r) *r = sr;
1358 if (t) *t = st;
1359 if (b) *b = sb;
1360}
1361
1362/* all nice and private */
1363static void
1364evas_object_text_init(Evas_Object *obj)
1365{
1366 /* alloc text ob, setup methods and default values */
1367 obj->object_data = evas_object_text_new();
1368 /* set up default settings for this kind of object */
1369 obj->cur.color.r = 255;
1370 obj->cur.color.g = 255;
1371 obj->cur.color.b = 255;
1372 obj->cur.color.a = 255;
1373 obj->cur.geometry.x = 0;
1374 obj->cur.geometry.y = 0;
1375 obj->cur.geometry.w = 0;
1376 obj->cur.geometry.h = 0;
1377 obj->cur.layer = 0;
1378 /* set up object-specific settings */
1379 obj->prev = obj->cur;
1380 /* set up methods (compulsory) */
1381 obj->func = &object_func;
1382 obj->type = o_type;
1383}
1384
1385static void *
1386evas_object_text_new(void)
1387{
1388 Evas_Object_Text *o;
1389
1390 /* alloc obj private data */
1391 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_text", Evas_Object_Text, 128, NULL);
1392 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Text);
1393 if (!o) return NULL;
1394 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Text);
1395 o->magic = MAGIC_OBJ_TEXT;
1396 o->prev = o->cur;
1397#ifdef BIDI_SUPPORT
1398 o->bidi_par_props = evas_bidi_paragraph_props_new();
1399#endif
1400 return o;
1401}
1402
1403static void
1404evas_object_text_free(Evas_Object *obj)
1405{
1406 Evas_Object_Text *o;
1407
1408 /* frees private object data. very simple here */
1409 o = (Evas_Object_Text *)(obj->object_data);
1410 MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT);
1411 return;
1412 MAGIC_CHECK_END();
1413 /* free obj */
1414 if (o->items) _evas_object_text_items_clear(o);
1415 if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text);
1416 if (o->cur.font) eina_stringshare_del(o->cur.font);
1417 if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
1418 if (o->cur.source) eina_stringshare_del(o->cur.source);
1419 if (o->font) evas_font_free(obj->layer->evas, o->font);
1420#ifdef BIDI_SUPPORT
1421 evas_bidi_paragraph_props_unref(o->bidi_par_props);
1422#endif
1423 o->magic = 0;
1424 EVAS_MEMPOOL_FREE(_mp_obj, o);
1425}
1426
1427static void
1428evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
1429{
1430 int i, j;
1431 Evas_Object_Text *o;
1432 Evas_Object_Text_Item *it;
1433 const char vals[5][5] =
1434 {
1435 {0, 1, 2, 1, 0},
1436 {1, 3, 4, 3, 1},
1437 {2, 4, 5, 4, 2},
1438 {1, 3, 4, 3, 1},
1439 {0, 1, 2, 1, 0}
1440 };
1441 int sl = 0, st = 0;
1442 int shad_dst, shad_sz, dx, dy, haveshad;
1443
1444 /* render object to surface with context, and offxet by x,y */
1445 o = (Evas_Object_Text *)(obj->object_data);
1446 evas_text_style_pad_get(o->cur.style, &sl, NULL, &st, NULL);
1447 ENFN->context_multiplier_unset(output, context);
1448 ENFN->context_render_op_set(output, context, obj->cur.render_op);
1449 /* FIXME: This clipping is just until we fix inset handling correctly. */
1450 ENFN->context_clip_clip(output, context,
1451 obj->cur.geometry.x + x,
1452 obj->cur.geometry.y + y,
1453 obj->cur.geometry.w,
1454 obj->cur.geometry.h);
1455/*
1456 ENFN->context_color_set(output,
1457 context,
1458 230, 160, 30, 100);
1459 ENFN->rectangle_draw(output,
1460 context,
1461 surface,
1462 obj->cur.geometry.x + x,
1463 obj->cur.geometry.y + y,
1464 obj->cur.geometry.w,
1465 obj->cur.geometry.h);
1466 */
1467#define COLOR_ONLY_SET(object, sub, col) \
1468 ENFN->context_color_set(output, context, \
1469 object->sub.col.r, \
1470 object->sub.col.g, \
1471 object->sub.col.b, \
1472 object->sub.col.a);
1473
1474#define COLOR_SET(object, sub, col) \
1475 if (obj->cur.clipper)\
1476 ENFN->context_color_set(output, context, \
1477 ((int)object->sub.col.r * ((int)obj->cur.clipper->cur.cache.clip.r + 1)) >> 8, \
1478 ((int)object->sub.col.g * ((int)obj->cur.clipper->cur.cache.clip.g + 1)) >> 8, \
1479 ((int)object->sub.col.b * ((int)obj->cur.clipper->cur.cache.clip.b + 1)) >> 8, \
1480 ((int)object->sub.col.a * ((int)obj->cur.clipper->cur.cache.clip.a + 1)) >> 8); \
1481 else\
1482 ENFN->context_color_set(output, context, \
1483 object->sub.col.r, \
1484 object->sub.col.g, \
1485 object->sub.col.b, \
1486 object->sub.col.a);
1487
1488#define COLOR_SET_AMUL(object, sub, col, amul) \
1489 if (obj->cur.clipper) \
1490 ENFN->context_color_set(output, context, \
1491 (((int)object->sub.col.r) * ((int)obj->cur.clipper->cur.cache.clip.r) * (amul)) / 65025, \
1492 (((int)object->sub.col.g) * ((int)obj->cur.clipper->cur.cache.clip.g) * (amul)) / 65025, \
1493 (((int)object->sub.col.b) * ((int)obj->cur.clipper->cur.cache.clip.b) * (amul)) / 65025, \
1494 (((int)object->sub.col.a) * ((int)obj->cur.clipper->cur.cache.clip.a) * (amul)) / 65025); \
1495 else \
1496 ENFN->context_color_set(output, context, \
1497 (((int)object->sub.col.r) * (amul)) / 255, \
1498 (((int)object->sub.col.g) * (amul)) / 255, \
1499 (((int)object->sub.col.b) * (amul)) / 255, \
1500 (((int)object->sub.col.a) * (amul)) / 255);
1501
1502#define DRAW_TEXT(ox, oy) \
1503 if ((o->font) && (it->text_props.len > 0)) \
1504 ENFN->font_draw(output, \
1505 context, \
1506 surface, \
1507 o->font, \
1508 obj->cur.geometry.x + x + sl + ox + it->x, \
1509 obj->cur.geometry.y + y + st + oy + \
1510 (int) \
1511 (((o->max_ascent * obj->cur.geometry.h) / obj->cur.geometry.h) - 0.5), \
1512 obj->cur.geometry.w, \
1513 obj->cur.geometry.h, \
1514 obj->cur.geometry.w, \
1515 obj->cur.geometry.h, \
1516 &it->text_props);
1517
1518 /* shadows */
1519 shad_dst = shad_sz = dx = dy = haveshad = 0;
1520 switch (o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC)
1521 {
1522 case EVAS_TEXT_STYLE_SHADOW:
1523 case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
1524 shad_dst = 1;
1525 haveshad = 1;
1526 break;
1527 case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
1528 case EVAS_TEXT_STYLE_FAR_SHADOW:
1529 shad_dst = 2;
1530 haveshad = 1;
1531 break;
1532 case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
1533 shad_dst = 2;
1534 shad_sz = 2;
1535 haveshad = 1;
1536 break;
1537 case EVAS_TEXT_STYLE_SOFT_SHADOW:
1538 shad_dst = 1;
1539 shad_sz = 2;
1540 haveshad = 1;
1541 break;
1542 default:
1543 break;
1544 }
1545 if (haveshad)
1546 {
1547 if (shad_dst > 0)
1548 {
1549 switch (o->cur.style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
1550 {
1551 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
1552 dx = 1;
1553 dy = 1;
1554 break;
1555 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
1556 dx = 0;
1557 dy = 1;
1558 break;
1559 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
1560 dx = -1;
1561 dy = 1;
1562 break;
1563 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
1564 dx = -1;
1565 dy = 0;
1566 break;
1567 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
1568 dx = -1;
1569 dy = -1;
1570 break;
1571 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
1572 dx = 0;
1573 dy = -1;
1574 break;
1575 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
1576 dx = 1;
1577 dy = -1;
1578 break;
1579 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
1580 dx = 1;
1581 dy = 0;
1582 default:
1583 break;
1584 }
1585 dx *= shad_dst;
1586 dy *= shad_dst;
1587 }
1588 }
1589 EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
1590 {
1591 /* Shadows */
1592 if (haveshad)
1593 {
1594 switch (shad_sz)
1595 {
1596 case 0:
1597 COLOR_SET(o, cur, shadow);
1598 DRAW_TEXT(dx, dy);
1599 break;
1600 case 2:
1601 for (j = 0; j < 5; j++)
1602 {
1603 for (i = 0; i < 5; i++)
1604 {
1605 if (vals[i][j] != 0)
1606 {
1607 COLOR_SET_AMUL(o, cur, shadow, vals[i][j] * 50);
1608 DRAW_TEXT(i - 2 + dx, j - 2 + dy);
1609 }
1610 }
1611 }
1612 break;
1613 default:
1614 break;
1615 }
1616 }
1617
1618 /* glows */
1619 if (o->cur.style == EVAS_TEXT_STYLE_GLOW)
1620 {
1621 for (j = 0; j < 5; j++)
1622 {
1623 for (i = 0; i < 5; i++)
1624 {
1625 if (vals[i][j] != 0)
1626 {
1627 COLOR_SET_AMUL(o, cur, glow, vals[i][j] * 50);
1628 DRAW_TEXT(i - 2, j - 2);
1629 }
1630 }
1631 }
1632 COLOR_SET(o, cur, glow2);
1633 DRAW_TEXT(-1, 0);
1634 DRAW_TEXT(1, 0);
1635 DRAW_TEXT(0, -1);
1636 DRAW_TEXT(0, 1);
1637 }
1638
1639 /* outlines */
1640 if ((o->cur.style == EVAS_TEXT_STYLE_OUTLINE) ||
1641 (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
1642 (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
1643 {
1644 COLOR_SET(o, cur, outline);
1645 DRAW_TEXT(-1, 0);
1646 DRAW_TEXT(1, 0);
1647 DRAW_TEXT(0, -1);
1648 DRAW_TEXT(0, 1);
1649 }
1650 else if (o->cur.style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
1651 {
1652 for (j = 0; j < 5; j++)
1653 {
1654 for (i = 0; i < 5; i++)
1655 {
1656 if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
1657 {
1658 COLOR_SET_AMUL(o, cur, outline, vals[i][j] * 50);
1659 DRAW_TEXT(i - 2, j - 2);
1660 }
1661 }
1662 }
1663 }
1664
1665 /* normal text */
1666 COLOR_ONLY_SET(obj, cur.cache, clip);
1667 DRAW_TEXT(0, 0);
1668 }
1669}
1670
1671static void
1672evas_object_text_render_pre(Evas_Object *obj)
1673{
1674 Evas_Object_Text *o;
1675 int is_v, was_v;
1676
1677 /* dont pre-render the obj twice! */
1678 if (obj->pre_render_done) return;
1679 obj->pre_render_done = 1;
1680 /* pre-render phase. this does anything an object needs to do just before
1681 rendering. This could mean loading the image data, retrieving it from
1682 elsewhere, decoding video etc.
1683 Then when this is done the object needs to figure if it changed and
1684 if so what and where and add the appropriate redraw rectangles */
1685 o = (Evas_Object_Text *)(obj->object_data);
1686 /* if someone is clipping this obj - go calculate the clipper */
1687 if (obj->cur.clipper)
1688 {
1689 if (obj->cur.cache.clip.dirty)
1690 evas_object_clip_recalc(obj->cur.clipper);
1691 obj->cur.clipper->func->render_pre(obj->cur.clipper);
1692 }
1693 /* now figure what changed and add draw rects
1694 if it just became visible or invisible */
1695 is_v = evas_object_is_visible(obj);
1696 was_v = evas_object_was_visible(obj);
1697 if (is_v != was_v)
1698 {
1699 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes,
1700 obj, is_v, was_v);
1701 goto done;
1702 }
1703 if ((obj->cur.map != obj->prev.map) ||
1704 (obj->cur.usemap != obj->prev.usemap))
1705 {
1706 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1707 obj);
1708 goto done;
1709 }
1710 /* its not visible - we accounted for it appearing or not so just abort */
1711 if (!is_v) goto done;
1712 /* clipper changed this is in addition to anything else for obj */
1713 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
1714 /* if we restacked (layer or just within a layer) and dont clip anyone */
1715 if (obj->restack)
1716 {
1717 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1718 obj);
1719 goto done;
1720 }
1721 /* if it changed color */
1722 if ((obj->cur.color.r != obj->prev.color.r) ||
1723 (obj->cur.color.g != obj->prev.color.g) ||
1724 (obj->cur.color.b != obj->prev.color.b) ||
1725 (obj->cur.color.a != obj->prev.color.a))
1726 {
1727 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1728 obj);
1729 goto done;
1730 }
1731 /* if it changed geometry - and obviously not visibility or color
1732 calculate differences since we have a constant color fill
1733 we really only need to update the differences */
1734 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
1735 (obj->cur.geometry.y != obj->prev.geometry.y) ||
1736 (obj->cur.geometry.w != obj->prev.geometry.w) ||
1737 (obj->cur.geometry.h != obj->prev.geometry.h))
1738 {
1739 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1740 obj);
1741 goto done;
1742 }
1743 if (obj->cur.render_op != obj->prev.render_op)
1744 {
1745 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1746 obj);
1747 goto done;
1748 }
1749 if (obj->cur.scale != obj->prev.scale)
1750 {
1751 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1752 obj);
1753 goto done;
1754 }
1755 if (o->changed)
1756 {
1757 if ((o->cur.size != o->prev.size) ||
1758 ((o->cur.font != o->prev.font)) ||
1759 ((o->cur.utf8_text != o->prev.utf8_text)) ||
1760 ((o->cur.style != o->prev.style)) ||
1761 ((o->cur.shadow.r != o->prev.shadow.r)) ||
1762 ((o->cur.shadow.g != o->prev.shadow.g)) ||
1763 ((o->cur.shadow.b != o->prev.shadow.b)) ||
1764 ((o->cur.shadow.a != o->prev.shadow.a)) ||
1765 ((o->cur.outline.r != o->prev.outline.r)) ||
1766 ((o->cur.outline.g != o->prev.outline.g)) ||
1767 ((o->cur.outline.b != o->prev.outline.b)) ||
1768 ((o->cur.outline.a != o->prev.outline.a)) ||
1769 ((o->cur.glow.r != o->prev.glow.r)) ||
1770 ((o->cur.glow.g != o->prev.glow.g)) ||
1771 ((o->cur.glow.b != o->prev.glow.b)) ||
1772 ((o->cur.glow.a != o->prev.glow.a)) ||
1773 ((o->cur.glow2.r != o->prev.glow2.r)) ||
1774 ((o->cur.glow2.g != o->prev.glow2.g)) ||
1775 ((o->cur.glow2.b != o->prev.glow2.b)) ||
1776 ((o->cur.glow2.a != o->prev.glow2.a)))
1777 {
1778 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
1779 obj);
1780 goto done;
1781 }
1782 }
1783 done:
1784 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes,
1785 obj, is_v, was_v);
1786}
1787
1788static void
1789evas_object_text_render_post(Evas_Object *obj)
1790{
1791 Evas_Object_Text *o;
1792
1793 /* this moves the current data to the previous state parts of the object
1794 in whatever way is safest for the object. also if we don't need object
1795 data anymore we can free it if the object deems this is a good idea */
1796 o = (Evas_Object_Text *)(obj->object_data);
1797 /* remove those pesky changes */
1798 evas_object_clip_changes_clean(obj);
1799 /* move cur to prev safely for object data */
1800 obj->prev = obj->cur;
1801 o->prev = o->cur;
1802 o->changed = 0;
1803}
1804
1805static unsigned int
1806evas_object_text_id_get(Evas_Object *obj)
1807{
1808 Evas_Object_Text *o;
1809
1810 o = (Evas_Object_Text *)(obj->object_data);
1811 if (!o) return 0;
1812 return MAGIC_OBJ_TEXT;
1813}
1814
1815static unsigned int
1816evas_object_text_visual_id_get(Evas_Object *obj)
1817{
1818 Evas_Object_Text *o;
1819
1820 o = (Evas_Object_Text *)(obj->object_data);
1821 if (!o) return 0;
1822 return MAGIC_OBJ_SHAPE;
1823}
1824
1825static void *
1826evas_object_text_engine_data_get(Evas_Object *obj)
1827{
1828 Evas_Object_Text *o;
1829
1830 o = (Evas_Object_Text *)(obj->object_data);
1831 if (!o) return NULL;
1832 return o->font;
1833}
1834
1835static int
1836evas_object_text_is_opaque(Evas_Object *obj __UNUSED__)
1837{
1838 /* this returns 1 if the internal object data implies that the object is
1839 currently fully opaque over the entire gradient it occupies */
1840 return 0;
1841}
1842
1843static int
1844evas_object_text_was_opaque(Evas_Object *obj __UNUSED__)
1845{
1846 /* this returns 1 if the internal object data implies that the object was
1847 currently fully opaque over the entire gradient it occupies */
1848 return 0;
1849}
1850
1851static void
1852evas_object_text_scale_update(Evas_Object *obj)
1853{
1854 Evas_Object_Text *o;
1855 int size;
1856 const char *font;
1857
1858 o = (Evas_Object_Text *)(obj->object_data);
1859 font = eina_stringshare_add(o->cur.font);
1860 size = o->cur.size;
1861 if (o->cur.font) eina_stringshare_del(o->cur.font);
1862 o->cur.font = NULL;
1863 o->prev.font = NULL;
1864 o->cur.size = 0;
1865 o->prev.size = 0;
1866 evas_object_text_font_set(obj, font, size);
1867}
1868
1869void
1870_evas_object_text_rehint(Evas_Object *obj)
1871{
1872 Evas_Object_Text *o;
1873 int is, was;
1874
1875 o = (Evas_Object_Text *)(obj->object_data);
1876 if (!o->font) return;
1877#ifdef EVAS_FRAME_QUEUING
1878 evas_common_pipe_op_text_flush((RGBA_Font *) o->font);
1879#endif
1880 evas_font_load_hinting_set(obj->layer->evas, o->font,
1881 obj->layer->evas->hinting);
1882 was = evas_object_is_in_output_rect(obj,
1883 obj->layer->evas->pointer.x,
1884 obj->layer->evas->pointer.y, 1, 1);
1885 /* DO II */
1886 _evas_object_text_recalc(obj);
1887 o->changed = 1;
1888 evas_object_change(obj);
1889 evas_object_clip_dirty(obj);
1890 evas_object_coords_recalc(obj);
1891 is = evas_object_is_in_output_rect(obj,
1892 obj->layer->evas->pointer.x,
1893 obj->layer->evas->pointer.y, 1, 1);
1894 if ((is || was) && obj->cur.visible)
1895 evas_event_feed_mouse_move(obj->layer->evas,
1896 obj->layer->evas->pointer.x,
1897 obj->layer->evas->pointer.y,
1898 obj->layer->evas->last_timestamp,
1899 NULL);
1900 evas_object_inform_call_resize(obj);
1901}
1902
1903static void
1904_evas_object_text_recalc(Evas_Object *obj)
1905{
1906 Evas_Object_Text *o;
1907 Eina_Unicode *text = NULL;
1908 o = (Evas_Object_Text *)(obj->object_data);
1909
1910 if (o->items) _evas_object_text_items_clear(o);
1911 if (o->cur.utf8_text)
1912 text = eina_unicode_utf8_to_unicode(o->cur.utf8_text,
1913 NULL);
1914
1915 if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING);
1916
1917 _evas_object_text_layout(obj, o, text);
1918
1919 if (text) free(text);
1920
1921 if ((o->font) && (o->items))
1922 {
1923 int w, h;
1924 int l = 0, r = 0, t = 0, b = 0;
1925
1926 w = _evas_object_text_horiz_advance_get(obj, o);
1927 h = _evas_object_text_vert_advance_get(obj, o);
1928 evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
1929 obj->cur.geometry.w = w + l + r;
1930 obj->cur.geometry.h = h + t + b;
1931//// obj->cur.cache.geometry.validity = 0;
1932 }
1933 else
1934 {
1935 int t = 0, b = 0;
1936
1937 evas_text_style_pad_get(o->cur.style, NULL, NULL, &t, &b);
1938 obj->cur.geometry.w = 0;
1939 obj->cur.geometry.h = o->max_ascent + o->max_descent + t + b;
1940//// obj->cur.cache.geometry.validity = 0;
1941 }
1942}
1943
diff --git a/libraries/evas/src/lib/canvas/evas_object_textblock.c b/libraries/evas/src/lib/canvas/evas_object_textblock.c
new file mode 100644
index 0000000..7941a45
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_textblock.c
@@ -0,0 +1,9569 @@
1/**
2 * @internal
3 * @section Evas_Object_Textblock_Internal Internal Textblock Object Tutorial
4 *
5 * This explains the internal design of the Evas Textblock Object, it's assumed
6 * that the reader of this section has already read @ref Evas_Object_Textblock_Tutorial "Textblock's usage docs.".
7 *
8 * @subsection textblock_internal_intro Introduction
9 * There are two main parts to the textblock object, the first being the node
10 * system, and the second being the layout system. The former is just an
11 * internal representation of the markup text, while the latter is the internal
12 * visual representation of the text (i.e positioning, sizing, fonts and etc).
13 *
14 * @subsection textblock_nodes The Nodes system
15 * The nodes mechanism consists of two main data types:
16 * ::Evas_Object_Textblock_Node_Text and ::Evas_Object_Textblock_Node_Format
17 * the former is for Text nodes and the latter is for format nodes.
18 * There's always at least one text node, even if there are only formats.
19 *
20 * @subsection textblock_nodes_text Text nodes
21 * Each text node is essentially a paragraph, it includes an @ref Eina_UStrbuf
22 * that stores the actual paragraph text, a utf8 string to store the paragraph
23 * text in utf8 (which is not used internally at all), A pointer to it's
24 * main @ref textblock_nodes_format_internal "Format Node" and the paragraph's
25 * @ref evas_bidi_props "BiDi properties". The pointer to the format node may be
26 * NULL if there's no format node anywhere before the end of the text node,
27 * not even in previous text nodes. If not NULL, it points to the first format
28 * node pointing to text inside of the text node, or if there is none, it points
29 * to the previous's text nodes format node. Each paragraph has a format node
30 * representing a paragraph separator pointing to it's last position except
31 * for the last paragraph, which has no such constraint. This constraint
32 * happens because text nodes are paragraphs and paragraphs are delimited by
33 * paragraph separators.
34 *
35 * @subsection textblock_nodes_format_internal Format Nodes - Internal
36 * Each format node stores a group of format information, for example the
37 * markup: \<font=Vera,Kochi font_size=10 align=left\> will all be inserted
38 * inside the same format node, altohugh it consists of different formatting
39 * commands.
40 * Each node has a pointer to it's text node, this pointer is NEVER NULL, even
41 * if there's only one format, and no text, a text node is created. Each format
42 * node includes an offset from the last format node of the same text node. For
43 * example, the markup "0<b>12</b>" will create two format nodes, the first
44 * having an offset of 1 and the second an offset of 2. Each format node also
45 * includes a @ref Eina_Strbuf that includes the textual representation of the
46 * format, and a boolean stating if the format is a visible format or not, see
47 * @ref textblock_nodes_format_visible
48 *
49 * @subsection textblock_nodes_format_visible Visible Format Nodes
50 * There are two types of format nodes, visible and invisible. They are the same
51 * in every way, except for the representation in the text node. While invisible
52 * format nodes have no representation in the text node, the visible ones do.
53 * The Uniceode object replacement character (0xFFFC) is inserted to every place
54 * a visible format node points to. This makes it very easy to treat visible
55 * formats as items in the text, both for BiDi purposes and cursor handling
56 * purposes.
57 * Here are a few example visible an invisible formats:
58 * Visible: newline char, tab, paragraph separator and an embedded item.
59 * Invisible: setting the color, font or alignment of the text.
60 *
61 * @subsection textblock_layout The layout system
62 * @todo write @ref textblock_layout
63 */
64#include <stdlib.h>
65
66#include "evas_common.h"
67#include "evas_private.h"
68
69#ifdef HAVE_LINEBREAK
70#include "linebreak.h"
71#endif
72
73/* save typing */
74#define ENFN obj->layer->evas->engine.func
75#define ENDT obj->layer->evas->engine.data.output
76
77/* private magic number for textblock objects */
78static const char o_type[] = "textblock";
79
80/* The char to be inserted instead of visible formats */
81#define EVAS_TEXTBLOCK_REPLACEMENT_CHAR 0xFFFC
82#define _PARAGRAPH_SEPARATOR 0x2029
83#define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \
84 (((ch) == EVAS_TEXTBLOCK_REPLACEMENT_CHAR) || \
85 ((ch) == '\n') || \
86 ((ch) == '\t') || \
87 ((ch) == _PARAGRAPH_SEPARATOR))
88
89/* private struct for textblock object internal data */
90/**
91 * @internal
92 * @typedef Evas_Object_Textblock
93 * The actual textblock object.
94 */
95typedef struct _Evas_Object_Textblock Evas_Object_Textblock;
96/**
97 * @internal
98 * @typedef Evas_Object_Style_Tag
99 * The structure used for finding style tags.
100 */
101typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag;
102/**
103 * @internal
104 * @typedef Evas_Object_Textblock_Node_Text
105 * A text node.
106 */
107typedef struct _Evas_Object_Textblock_Node_Text Evas_Object_Textblock_Node_Text;
108/*
109 * Defined in Evas.h
110typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format;
111*/
112
113/**
114 * @internal
115 * @typedef Evas_Object_Textblock_Paragraph
116 * A layouting paragraph.
117 */
118typedef struct _Evas_Object_Textblock_Paragraph Evas_Object_Textblock_Paragraph;
119/**
120 * @internal
121 * @typedef Evas_Object_Textblock_Line
122 * A layouting line.
123 */
124typedef struct _Evas_Object_Textblock_Line Evas_Object_Textblock_Line;
125/**
126 * @internal
127 * @typedef Evas_Object_Textblock_Item
128 * A layouting item.
129 */
130typedef struct _Evas_Object_Textblock_Item Evas_Object_Textblock_Item;
131/**
132 * @internal
133 * @typedef Evas_Object_Textblock_Item
134 * A layouting text item.
135 */
136typedef struct _Evas_Object_Textblock_Text_Item Evas_Object_Textblock_Text_Item;
137/**
138 * @internal
139 * @typedef Evas_Object_Textblock_Format_Item
140 * A layouting format item.
141 */
142typedef struct _Evas_Object_Textblock_Format_Item Evas_Object_Textblock_Format_Item;
143/**
144 * @internal
145 * @typedef Evas_Object_Textblock_Format
146 * A textblock format.
147 */
148typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format;
149
150/**
151 * @internal
152 * @def IS_AT_END(ti, ind)
153 * Return true if ind is at the end of the text item, false otherwise.
154 */
155#define IS_AT_END(ti, ind) (ind == ti->text_props.text_len)
156
157/**
158 * @internal
159 * @def MOVE_PREV_UNTIL(limit, ind)
160 * This decrements ind as long as ind > limit.
161 */
162#define MOVE_PREV_UNTIL(limit, ind) \
163 do \
164 { \
165 if ((limit) < (ind)) \
166 (ind)--; \
167 } \
168 while (0)
169
170/**
171 * @internal
172 * @def MOVE_NEXT_UNTIL(limit, ind)
173 * This increments ind as long as ind < limit
174 */
175#define MOVE_NEXT_UNTIL(limit, ind) \
176 do \
177 { \
178 if ((ind) < (limit)) \
179 (ind)++; \
180 } \
181 while (0)
182
183/**
184 * @internal
185 * @def GET_ITEM_TEXT(ti)
186 * Returns a const reference to the text of the ti (not null terminated).
187 */
188#define GET_ITEM_TEXT(ti) \
189 (((ti)->parent.text_node) ? \
190 (eina_ustrbuf_string_get((ti)->parent.text_node->unicode) + \
191 (ti)->parent.text_pos) : EINA_UNICODE_EMPTY_STRING)
192/**
193 * @internal
194 * @def _FORMAT_IS_CLOSER_OF(base, closer, closer_len)
195 * Returns true if closer is the closer of base.
196 */
197#define _FORMAT_IS_CLOSER_OF(base, closer, closer_len) \
198 (!strncmp(base + 1, closer, closer_len) && \
199 (!base[closer_len + 1] || \
200 (base[closer_len + 1] == '=') || \
201 _is_white(base[closer_len + 1])))
202
203/*FIXME: document the structs and struct items. */
204struct _Evas_Object_Style_Tag
205{
206 EINA_INLIST;
207 char *tag;
208 char *replace;
209 size_t tag_len;
210 size_t replace_len;
211};
212
213struct _Evas_Object_Textblock_Node_Text
214{
215 EINA_INLIST;
216 Eina_UStrbuf *unicode;
217 char *utf8;
218 Evas_Object_Textblock_Node_Format *format_node;
219 Evas_Object_Textblock_Paragraph *par;
220 Eina_Bool dirty : 1;
221 Eina_Bool is_new : 1;
222};
223
224struct _Evas_Object_Textblock_Node_Format
225{
226 EINA_INLIST;
227 const char *format;
228 const char *orig_format;
229 Evas_Object_Textblock_Node_Text *text_node;
230 size_t offset;
231 unsigned char anchor : 2;
232 Eina_Bool visible : 1;
233 Eina_Bool format_change : 1;
234 Eina_Bool is_new : 1;
235};
236
237#define ANCHOR_NONE 0
238#define ANCHOR_A 1
239#define ANCHOR_ITEM 2
240
241/**
242 * @internal
243 * @def _NODE_TEXT(x)
244 * A convinience macro for casting to a text node.
245 */
246#define _NODE_TEXT(x) ((Evas_Object_Textblock_Node_Text *) (x))
247/**
248 * @internal
249 * @def _NODE_FORMAT(x)
250 * A convinience macro for casting to a format node.
251 */
252#define _NODE_FORMAT(x) ((Evas_Object_Textblock_Node_Format *) (x))
253/**
254 * @internal
255 * @def _ITEM(x)
256 * A convinience macro for casting to a generic item.
257 */
258#define _ITEM(x) ((Evas_Object_Textblock_Item *) (x))
259/**
260 * @internal
261 * @def _ITEM_TEXT(x)
262 * A convinience macro for casting to a text item.
263 */
264#define _ITEM_TEXT(x) ((Evas_Object_Textblock_Text_Item *) (x))
265/**
266 * @internal
267 * @def _ITEM_FORMAT(x)
268 * A convinience macro for casting to a format item.
269 */
270#define _ITEM_FORMAT(x) ((Evas_Object_Textblock_Format_Item *) (x))
271
272struct _Evas_Object_Textblock_Paragraph
273{
274 EINA_INLIST;
275 Evas_Object_Textblock_Line *lines;
276 Evas_Object_Textblock_Node_Text *text_node;
277 Eina_List *logical_items;
278 Evas_BiDi_Paragraph_Props *bidi_props; /* Only valid during layout */
279 Evas_BiDi_Direction direction;
280 Evas_Coord y, w, h;
281 int line_no;
282 Eina_Bool is_bidi : 1;
283 Eina_Bool visible : 1;
284 Eina_Bool rendered : 1;
285};
286
287struct _Evas_Object_Textblock_Line
288{
289 EINA_INLIST;
290 Evas_Object_Textblock_Item *items;
291 Evas_Object_Textblock_Paragraph *par;
292 Evas_Coord x, y, w, h;
293 int baseline;
294 int line_no;
295};
296
297typedef enum _Evas_Textblock_Item_Type
298{
299 EVAS_TEXTBLOCK_ITEM_TEXT,
300 EVAS_TEXTBLOCK_ITEM_FORMAT,
301} Evas_Textblock_Item_Type;
302
303struct _Evas_Object_Textblock_Item
304{
305 EINA_INLIST;
306 Evas_Textblock_Item_Type type;
307 Evas_Object_Textblock_Node_Text *text_node;
308 Evas_Object_Textblock_Format *format;
309 size_t text_pos;
310#ifdef BIDI_SUPPORT
311 size_t visual_pos;
312#endif
313 Evas_Coord adv, x, w, h;
314 Eina_Bool merge : 1; /* Indicates whether this
315 item should merge to the
316 previous item or not */
317 Eina_Bool visually_deleted : 1;
318 /* Indicates whether this
319 item is used in the visual
320 layout or not. */
321};
322
323struct _Evas_Object_Textblock_Text_Item
324{
325 Evas_Object_Textblock_Item parent;
326 Evas_Text_Props text_props;
327 Evas_Coord inset;
328 Evas_Coord x_adjustment; /* Used to indicate by how
329 much we adjusted sizes */
330};
331
332struct _Evas_Object_Textblock_Format_Item
333{
334 Evas_Object_Textblock_Item parent;
335 Evas_BiDi_Direction bidi_dir;
336 const char *item;
337 int y;
338 unsigned char vsize : 2;
339 unsigned char size : 2;
340 Eina_Bool formatme : 1;
341};
342
343struct _Evas_Object_Textblock_Format
344{
345 Evas_Object_Textblock_Node_Format *fnode;
346 double halign;
347 double valign;
348 struct {
349 Evas_Font_Description *fdesc;
350 const char *source;
351 Evas_Font_Set *font;
352 Evas_Font_Size size;
353 } font;
354 struct {
355 struct {
356 unsigned char r, g, b, a;
357 } normal, underline, underline2, underline_dash, outline, shadow, glow, glow2, backing,
358 strikethrough;
359 } color;
360 struct {
361 int l, r;
362 } margin;
363 int ref;
364 int tabstops;
365 int linesize;
366 int linegap;
367 int underline_dash_width;
368 int underline_dash_gap;
369 double linerelsize;
370 double linerelgap;
371 double linefill;
372 double ellipsis;
373 unsigned char style;
374 Eina_Bool wrap_word : 1;
375 Eina_Bool wrap_char : 1;
376 Eina_Bool wrap_mixed : 1;
377 Eina_Bool underline : 1;
378 Eina_Bool underline2 : 1;
379 Eina_Bool underline_dash : 1;
380 Eina_Bool strikethrough : 1;
381 Eina_Bool backing : 1;
382 Eina_Bool password : 1;
383 Eina_Bool halign_auto : 1;
384};
385
386struct _Evas_Textblock_Style
387{
388 const char *style_text;
389 char *default_tag;
390 Evas_Object_Style_Tag *tags;
391 Eina_List *objects;
392 Eina_Bool delete_me : 1;
393};
394
395struct _Evas_Textblock_Cursor
396{
397 Evas_Object *obj;
398 size_t pos;
399 Evas_Object_Textblock_Node_Text *node;
400};
401
402/* Size of the index array */
403#define TEXTBLOCK_PAR_INDEX_SIZE 10
404struct _Evas_Object_Textblock
405{
406 DATA32 magic;
407 Evas_Textblock_Style *style;
408 Evas_Textblock_Cursor *cursor;
409 Eina_List *cursors;
410 Evas_Object_Textblock_Node_Text *text_nodes;
411 Evas_Object_Textblock_Node_Format *format_nodes;
412
413 int num_paragraphs;
414 Evas_Object_Textblock_Paragraph *paragraphs;
415 Evas_Object_Textblock_Paragraph *par_index[TEXTBLOCK_PAR_INDEX_SIZE];
416
417 Evas_Object_Textblock_Text_Item *ellip_ti;
418 Eina_List *anchors_a;
419 Eina_List *anchors_item;
420 int last_w, last_h;
421 struct {
422 int l, r, t, b;
423 } style_pad;
424 double valign;
425 char *markup_text;
426 void *engine_data;
427 const char *repch;
428 const char *bidi_delimiters;
429 struct {
430 int w, h;
431 Eina_Bool valid : 1;
432 } formatted, native;
433 Eina_Bool redraw : 1;
434 Eina_Bool changed : 1;
435 Eina_Bool content_changed : 1;
436 Eina_Bool format_changed : 1;
437 Eina_Bool have_ellipsis : 1;
438 Eina_Bool legacy_newline : 1;
439};
440
441/* private methods for textblock objects */
442static void evas_object_textblock_init(Evas_Object *obj);
443static void *evas_object_textblock_new(void);
444static void evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
445static void evas_object_textblock_free(Evas_Object *obj);
446static void evas_object_textblock_render_pre(Evas_Object *obj);
447static void evas_object_textblock_render_post(Evas_Object *obj);
448
449static unsigned int evas_object_textblock_id_get(Evas_Object *obj);
450static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj);
451static void *evas_object_textblock_engine_data_get(Evas_Object *obj);
452
453static int evas_object_textblock_is_opaque(Evas_Object *obj);
454static int evas_object_textblock_was_opaque(Evas_Object *obj);
455
456static void evas_object_textblock_coords_recalc(Evas_Object *obj);
457
458static void evas_object_textblock_scale_update(Evas_Object *obj);
459
460static const Evas_Object_Func object_func =
461{
462 /* methods (compulsory) */
463 evas_object_textblock_free,
464 evas_object_textblock_render,
465 evas_object_textblock_render_pre,
466 evas_object_textblock_render_post,
467 evas_object_textblock_id_get,
468 evas_object_textblock_visual_id_get,
469 evas_object_textblock_engine_data_get,
470 /* these are optional. NULL = nothing */
471 NULL,
472 NULL,
473 NULL,
474 NULL,
475 evas_object_textblock_is_opaque,
476 evas_object_textblock_was_opaque,
477 NULL,
478 NULL,
479 evas_object_textblock_coords_recalc,
480 evas_object_textblock_scale_update,
481 NULL,
482 NULL,
483 NULL
484};
485
486/* the actual api call to add a textblock */
487
488#define TB_HEAD() \
489 Evas_Object_Textblock *o; \
490 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
491 return; \
492 MAGIC_CHECK_END(); \
493 o = (Evas_Object_Textblock *)(obj->object_data); \
494 MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
495 return; \
496 MAGIC_CHECK_END();
497
498#define TB_HEAD_RETURN(x) \
499 Evas_Object_Textblock *o; \
500 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \
501 return (x); \
502 MAGIC_CHECK_END(); \
503 o = (Evas_Object_Textblock *)(obj->object_data); \
504 MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \
505 return (x); \
506 MAGIC_CHECK_END();
507
508
509
510static Eina_Bool _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur);
511static void _evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n);
512static void _evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n, int start, int end);
513static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur);
514static size_t _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt);
515static void _evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment);
516static void _evas_textblock_node_format_free(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n);
517static void _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n);
518static void _evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj);
519static void _evas_textblock_invalidate_all(Evas_Object_Textblock *o);
520static void _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset);
521static void _evas_textblock_cursors_set_node(Evas_Object_Textblock *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node);
522
523/* styles */
524/**
525 * @internal
526 * Clears the textblock style passed except for the style_text which is replaced.
527 * @param ts The ts to be cleared. Must not be NULL.
528 * @param style_text the style's text.
529 */
530static void
531_style_replace(Evas_Textblock_Style *ts, const char *style_text)
532{
533 eina_stringshare_replace(&ts->style_text, style_text);
534 if (ts->default_tag) free(ts->default_tag);
535 while (ts->tags)
536 {
537 Evas_Object_Style_Tag *tag;
538
539 tag = (Evas_Object_Style_Tag *)ts->tags;
540 ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
541 free(tag->tag);
542 free(tag->replace);
543 free(tag);
544 }
545 ts->default_tag = NULL;
546 ts->tags = NULL;
547}
548
549/**
550 * @internal
551 * Clears the textblock style passed.
552 * @param ts The ts to be cleared. Must not be NULL.
553 */
554static void
555_style_clear(Evas_Textblock_Style *ts)
556{
557 _style_replace(ts, NULL);
558}
559
560/**
561 * @internal
562 * Searches inside the tags stored in the style for the tag matching s.
563 * @param ts The ts to be cleared. Must not be NULL.
564 * @param s The tag to be matched.
565 * @param tag_len the length of the tag string.
566 * @param[out] replace_len The length of the replcaement found. - Must not be NULL.
567 * @return The replacement string found.
568 */
569static inline const char *
570_style_match_tag(Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len)
571{
572 Evas_Object_Style_Tag *tag;
573
574 EINA_INLIST_FOREACH(ts->tags, tag)
575 {
576 if (tag->tag_len != tag_len) continue;
577 if (!strncmp(tag->tag, s, tag_len))
578 {
579 *replace_len = tag->replace_len;
580 return tag->replace;
581 }
582 }
583 *replace_len = 0;
584 return NULL;
585}
586
587/**
588 * @internal
589 * Clears all the nodes (text and format) of the textblock object.
590 * @param obj The evas object, must not be NULL.
591 */
592static void
593_nodes_clear(const Evas_Object *obj)
594{
595 Evas_Object_Textblock *o;
596
597 o = (Evas_Object_Textblock *)(obj->object_data);
598 while (o->text_nodes)
599 {
600 Evas_Object_Textblock_Node_Text *n;
601
602 n = o->text_nodes;
603 o->text_nodes = _NODE_TEXT(eina_inlist_remove(
604 EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n)));
605 _evas_textblock_node_text_free(n);
606 }
607 while (o->format_nodes)
608 {
609 Evas_Object_Textblock_Node_Format *n;
610
611 n = o->format_nodes;
612 o->format_nodes = _NODE_FORMAT(eina_inlist_remove(EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n)));
613 _evas_textblock_node_format_free(o, n);
614 }
615}
616
617/**
618 * @internal
619 * Unrefs and frees (if needed) a textblock format.
620 * @param obj The Evas_Object, Must not be NULL.
621 * @param fmt the format to be cleaned, must not be NULL.
622 */
623static void
624_format_unref_free(const Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
625{
626 fmt->ref--;
627 if (fmt->ref > 0) return;
628 if (fmt->font.fdesc) evas_font_desc_unref(fmt->font.fdesc);
629 if (fmt->font.source) eina_stringshare_del(fmt->font.source);
630 evas_font_free(obj->layer->evas, fmt->font.font);
631 free(fmt);
632}
633
634/**
635 * @internal
636 * Free a layout item
637 * @param obj The evas object, must not be NULL.
638 * @param ln the layout line on which the item is in, must not be NULL.
639 * @param it the layout item to be freed
640 */
641static void
642_item_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln, Evas_Object_Textblock_Item *it)
643{
644 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
645 {
646 Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
647
648 evas_common_text_props_content_unref(&ti->text_props);
649 }
650 else
651 {
652 Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
653
654 if (fi->item) eina_stringshare_del(fi->item);
655 }
656 _format_unref_free(obj, it->format);
657 if (ln)
658 {
659 ln->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(
660 EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items));
661 }
662 free(it);
663}
664
665/**
666 * @internal
667 * Free a layout line.
668 * @param obj The evas object, must not be NULL.
669 * @param ln the layout line to be freed, must not be NULL.
670 */
671static void
672_line_free(Evas_Object_Textblock_Line *ln)
673{
674 /* Items are freed from the logical list, except for the ellip item */
675 if (ln) free(ln);
676}
677
678/* table of html escapes (that i can find) this should be ordered with the
679 * most common first as it's a linear search to match - no hash for this.
680 *
681 * these are stored as one large string and one additional array that
682 * contains the offsets to the tokens for space efficiency.
683 */
684/**
685 * @internal
686 * @var escape_strings[]
687 * This string consists of NULL terminated pairs of strings, the first of
688 * every pair is an escape and the second is the value of the escape.
689 */
690static const char escape_strings[] =
691/* most common escaped stuff */
692"&quot;\0" "\x22\0"
693"&amp;\0" "\x26\0"
694"&lt;\0" "\x3c\0"
695"&gt;\0" "\x3e\0"
696/* all the rest */
697"&nbsp;\0" "\xc2\xa0\0"
698"&iexcl;\0" "\xc2\xa1\0"
699"&cent;\0" "\xc2\xa2\0"
700"&pound;\0" "\xc2\xa3\0"
701"&curren;\0" "\xc2\xa4\0"
702"&yen;\0" "\xc2\xa5\0"
703"&brvbar;\0" "\xc2\xa6\0"
704"&sect;\0" "\xc2\xa7\0"
705"&uml;\0" "\xc2\xa8\0"
706"&copy;\0" "\xc2\xa9\0"
707"&ordf;\0" "\xc2\xaa\0"
708"&laquo;\0" "\xc2\xab\0"
709"&not;\0" "\xc2\xac\0"
710"&reg;\0" "\xc2\xae\0"
711"&macr;\0" "\xc2\xaf\0"
712"&deg;\0" "\xc2\xb0\0"
713"&plusmn;\0" "\xc2\xb1\0"
714"&sup2;\0" "\xc2\xb2\0"
715"&sup3;\0" "\xc2\xb3\0"
716"&acute;\0" "\xc2\xb4\0"
717"&micro;\0" "\xc2\xb5\0"
718"&para;\0" "\xc2\xb6\0"
719"&middot;\0" "\xc2\xb7\0"
720"&cedil;\0" "\xc2\xb8\0"
721"&sup1;\0" "\xc2\xb9\0"
722"&ordm;\0" "\xc2\xba\0"
723"&raquo;\0" "\xc2\xbb\0"
724"&frac14;\0" "\xc2\xbc\0"
725"&frac12;\0" "\xc2\xbd\0"
726"&frac34;\0" "\xc2\xbe\0"
727"&iquest;\0" "\xc2\xbf\0"
728"&Agrave;\0" "\xc3\x80\0"
729"&Aacute;\0" "\xc3\x81\0"
730"&Acirc;\0" "\xc3\x82\0"
731"&Atilde;\0" "\xc3\x83\0"
732"&Auml;\0" "\xc3\x84\0"
733"&Aring;\0" "\xc3\x85\0"
734"&Aelig;\0" "\xc3\x86\0"
735"&Ccedil;\0" "\xc3\x87\0"
736"&Egrave;\0" "\xc3\x88\0"
737"&Eacute;\0" "\xc3\x89\0"
738"&Ecirc;\0" "\xc3\x8a\0"
739"&Euml;\0" "\xc3\x8b\0"
740"&Igrave;\0" "\xc3\x8c\0"
741"&Iacute;\0" "\xc3\x8d\0"
742"&Icirc;\0" "\xc3\x8e\0"
743"&Iuml;\0" "\xc3\x8f\0"
744"&Eth;\0" "\xc3\x90\0"
745"&Ntilde;\0" "\xc3\x91\0"
746"&Ograve;\0" "\xc3\x92\0"
747"&Oacute;\0" "\xc3\x93\0"
748"&Ocirc;\0" "\xc3\x94\0"
749"&Otilde;\0" "\xc3\x95\0"
750"&Ouml;\0" "\xc3\x96\0"
751"&times;\0" "\xc3\x97\0"
752"&Oslash;\0" "\xc3\x98\0"
753"&Ugrave;\0" "\xc3\x99\0"
754"&Uacute;\0" "\xc3\x9a\0"
755"&Ucirc;\0" "\xc3\x9b\0"
756"&Yacute;\0" "\xc3\x9d\0"
757"&Thorn;\0" "\xc3\x9e\0"
758"&szlig;\0" "\xc3\x9f\0"
759"&agrave;\0" "\xc3\xa0\0"
760"&aacute;\0" "\xc3\xa1\0"
761"&acirc;\0" "\xc3\xa2\0"
762"&atilde;\0" "\xc3\xa3\0"
763"&auml;\0" "\xc3\xa4\0"
764"&aring;\0" "\xc3\xa5\0"
765"&aelig;\0" "\xc3\xa6\0"
766"&ccedil;\0" "\xc3\xa7\0"
767"&egrave;\0" "\xc3\xa8\0"
768"&eacute;\0" "\xc3\xa9\0"
769"&ecirc;\0" "\xc3\xaa\0"
770"&euml;\0" "\xc3\xab\0"
771"&igrave;\0" "\xc3\xac\0"
772"&iacute;\0" "\xc3\xad\0"
773"&icirc;\0" "\xc3\xae\0"
774"&iuml;\0" "\xc3\xaf\0"
775"&eth;\0" "\xc3\xb0\0"
776"&ntilde;\0" "\xc3\xb1\0"
777"&ograve;\0" "\xc3\xb2\0"
778"&oacute;\0" "\xc3\xb3\0"
779"&ocirc;\0" "\xc3\xb4\0"
780"&otilde;\0" "\xc3\xb5\0"
781"&ouml;\0" "\xc3\xb6\0"
782"&divide;\0" "\xc3\xb7\0"
783"&oslash;\0" "\xc3\xb8\0"
784"&ugrave;\0" "\xc3\xb9\0"
785"&uacute;\0" "\xc3\xba\0"
786"&ucirc;\0" "\xc3\xbb\0"
787"&uuml;\0" "\xc3\xbc\0"
788"&yacute;\0" "\xc3\xbd\0"
789"&thorn;\0" "\xc3\xbe\0"
790"&yuml;\0" "\xc3\xbf\0"
791"&alpha;\0" "\xce\x91\0"
792"&beta;\0" "\xce\x92\0"
793"&gamma;\0" "\xce\x93\0"
794"&delta;\0" "\xce\x94\0"
795"&epsilon;\0" "\xce\x95\0"
796"&zeta;\0" "\xce\x96\0"
797"&eta;\0" "\xce\x97\0"
798"&theta;\0" "\xce\x98\0"
799"&iota;\0" "\xce\x99\0"
800"&kappa;\0" "\xce\x9a\0"
801"&lambda;\0" "\xce\x9b\0"
802"&mu;\0" "\xce\x9c\0"
803"&nu;\0" "\xce\x9d\0"
804"&xi;\0" "\xce\x9e\0"
805"&omicron;\0" "\xce\x9f\0"
806"&pi;\0" "\xce\xa0\0"
807"&rho;\0" "\xce\xa1\0"
808"&sigma;\0" "\xce\xa3\0"
809"&tau;\0" "\xce\xa4\0"
810"&upsilon;\0" "\xce\xa5\0"
811"&phi;\0" "\xce\xa6\0"
812"&chi;\0" "\xce\xa7\0"
813"&psi;\0" "\xce\xa8\0"
814"&omega;\0" "\xce\xa9\0"
815"&hellip;\0" "\xe2\x80\xa6\0"
816"&euro;\0" "\xe2\x82\xac\0"
817"&larr;\0" "\xe2\x86\x90\0"
818"&uarr;\0" "\xe2\x86\x91\0"
819"&rarr;\0" "\xe2\x86\x92\0"
820"&darr;\0" "\xe2\x86\x93\0"
821"&harr;\0" "\xe2\x86\x94\0"
822"&larr;\0" "\xe2\x87\x90\0"
823"&rarr;\0" "\xe2\x87\x92\0"
824"&forall;\0" "\xe2\x88\x80\0"
825"&exist;\0" "\xe2\x88\x83\0"
826"&nabla;\0" "\xe2\x88\x87\0"
827"&prod;\0" "\xe2\x88\x8f\0"
828"&sum;\0" "\xe2\x88\x91\0"
829"&and;\0" "\xe2\x88\xa7\0"
830"&or;\0" "\xe2\x88\xa8\0"
831"&int;\0" "\xe2\x88\xab\0"
832"&ne;\0" "\xe2\x89\xa0\0"
833"&equiv;\0" "\xe2\x89\xa1\0"
834"&oplus;\0" "\xe2\x8a\x95\0"
835"&perp;\0" "\xe2\x8a\xa5\0"
836"&dagger;\0" "\xe2\x80\xa0\0"
837"&Dagger;\0" "\xe2\x80\xa1\0"
838"&bull;\0" "\xe2\x80\xa2\0"
839;
840
841EVAS_MEMPOOL(_mp_obj);
842
843/**
844 * @internal
845 * Checks if a char is a whitespace.
846 * @param c the unicode codepoint.
847 * @return EINA_TRUE if the unicode codepoint is a whitespace, EINA_FALSE otherwise.
848 */
849static Eina_Bool
850_is_white(Eina_Unicode c)
851{
852 /*
853 * unicode list of whitespace chars
854 *
855 * 0009..000D <control-0009>..<control-000D>
856 * 0020 SPACE
857 * 0085 <control-0085>
858 * 00A0 NO-BREAK SPACE
859 * 1680 OGHAM SPACE MARK
860 * 180E MONGOLIAN VOWEL SEPARATOR
861 * 2000..200A EN QUAD..HAIR SPACE
862 * 2028 LINE SEPARATOR
863 * 2029 PARAGRAPH SEPARATOR
864 * 202F NARROW NO-BREAK SPACE
865 * 205F MEDIUM MATHEMATICAL SPACE
866 * 3000 IDEOGRAPHIC SPACE
867 */
868 if (
869 (c == 0x20) ||
870 ((c >= 0x9) && (c <= 0xd)) ||
871 (c == 0x85) ||
872 (c == 0xa0) ||
873 (c == 0x1680) ||
874 (c == 0x180e) ||
875 ((c >= 0x2000) && (c <= 0x200a)) ||
876 (c == 0x2028) ||
877 (c == 0x2029) ||
878 (c == 0x202f) ||
879 (c == 0x205f) ||
880 (c == 0x3000)
881 )
882 return EINA_TRUE;
883 return EINA_FALSE;
884}
885
886/**
887 * @internal
888 * Prepends the text between s and p to the main cursor of the object.
889 *
890 * @param cur the cursor to prepend to.
891 * @param[in] s start of the string
892 * @param[in] p end of the string
893 */
894static void
895_prepend_text_run(Evas_Textblock_Cursor *cur, const char *s, const char *p)
896{
897 if ((s) && (p > s))
898 {
899 char *ts;
900
901 ts = alloca(p - s + 1);
902 strncpy(ts, s, p - s);
903 ts[p - s] = 0;
904 evas_textblock_cursor_text_prepend(cur, ts);
905 }
906}
907
908
909/**
910 * @internal
911 * Returns the numeric value of HEX chars for example for ch = 'A'
912 * the function will return 10.
913 *
914 * @param ch The HEX char.
915 * @return numeric value of HEX.
916 */
917static int
918_hex_string_get(char ch)
919{
920 if ((ch >= '0') && (ch <= '9')) return (ch - '0');
921 else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
922 else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
923 return 0;
924}
925
926/**
927 * @internal
928 * Parses a string of one of the formas:
929 * 1. "#RRGGBB"
930 * 2. "#RRGGBBAA"
931 * 3. "#RGB"
932 * 4. "#RGBA"
933 * To the rgba values.
934 *
935 * @param[in] str The string to parse - NOT NULL.
936 * @param[out] r The Red value - NOT NULL.
937 * @param[out] g The Green value - NOT NULL.
938 * @param[out] b The Blue value - NOT NULL.
939 * @param[out] a The Alpha value - NOT NULL.
940 */
941static void
942_format_color_parse(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a)
943{
944 int slen;
945
946 slen = strlen(str);
947 *r = *g = *b = *a = 0;
948
949 if (slen == 7) /* #RRGGBB */
950 {
951 *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
952 *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
953 *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
954 *a = 0xff;
955 }
956 else if (slen == 9) /* #RRGGBBAA */
957 {
958 *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
959 *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
960 *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
961 *a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8]));
962 }
963 else if (slen == 4) /* #RGB */
964 {
965 *r = _hex_string_get(str[1]);
966 *r = (*r << 4) | *r;
967 *g = _hex_string_get(str[2]);
968 *g = (*g << 4) | *g;
969 *b = _hex_string_get(str[3]);
970 *b = (*b << 4) | *b;
971 *a = 0xff;
972 }
973 else if (slen == 5) /* #RGBA */
974 {
975 *r = _hex_string_get(str[1]);
976 *r = (*r << 4) | *r;
977 *g = _hex_string_get(str[2]);
978 *g = (*g << 4) | *g;
979 *b = _hex_string_get(str[3]);
980 *b = (*b << 4) | *b;
981 *a = _hex_string_get(str[4]);
982 *a = (*a << 4) | *a;
983 }
984 *r = (*r * *a) / 255;
985 *g = (*g * *a) / 255;
986 *b = (*b * *a) / 255;
987}
988
989/* The refcount for the formats. */
990static int format_refcount = 0;
991/* Holders for the stringshares */
992static const char *fontstr = NULL;
993static const char *font_fallbacksstr = NULL;
994static const char *font_sizestr = NULL;
995static const char *font_sourcestr = NULL;
996static const char *font_weightstr = NULL;
997static const char *font_stylestr = NULL;
998static const char *font_widthstr = NULL;
999static const char *langstr = NULL;
1000static const char *colorstr = NULL;
1001static const char *underline_colorstr = NULL;
1002static const char *underline2_colorstr = NULL;
1003static const char *underline_dash_colorstr = NULL;
1004static const char *outline_colorstr = NULL;
1005static const char *shadow_colorstr = NULL;
1006static const char *glow_colorstr = NULL;
1007static const char *glow2_colorstr = NULL;
1008static const char *backing_colorstr = NULL;
1009static const char *strikethrough_colorstr = NULL;
1010static const char *alignstr = NULL;
1011static const char *valignstr = NULL;
1012static const char *wrapstr = NULL;
1013static const char *left_marginstr = NULL;
1014static const char *right_marginstr = NULL;
1015static const char *underlinestr = NULL;
1016static const char *strikethroughstr = NULL;
1017static const char *backingstr = NULL;
1018static const char *stylestr = NULL;
1019static const char *tabstopsstr = NULL;
1020static const char *linesizestr = NULL;
1021static const char *linerelsizestr = NULL;
1022static const char *linegapstr = NULL;
1023static const char *linerelgapstr = NULL;
1024static const char *itemstr = NULL;
1025static const char *linefillstr = NULL;
1026static const char *ellipsisstr = NULL;
1027static const char *passwordstr = NULL;
1028static const char *underline_dash_widthstr = NULL;
1029static const char *underline_dash_gapstr = NULL;
1030
1031/**
1032 * @internal
1033 * Init the format strings.
1034 */
1035static void
1036_format_command_init(void)
1037{
1038 if (format_refcount == 0)
1039 {
1040 fontstr = eina_stringshare_add("font");
1041 font_fallbacksstr = eina_stringshare_add("font_fallbacks");
1042 font_sizestr = eina_stringshare_add("font_size");
1043 font_sourcestr = eina_stringshare_add("font_source");
1044 font_weightstr = eina_stringshare_add("font_weight");
1045 font_stylestr = eina_stringshare_add("font_style");
1046 font_widthstr = eina_stringshare_add("font_width");
1047 langstr = eina_stringshare_add("lang");
1048 colorstr = eina_stringshare_add("color");
1049 underline_colorstr = eina_stringshare_add("underline_color");
1050 underline2_colorstr = eina_stringshare_add("underline2_color");
1051 underline_dash_colorstr = eina_stringshare_add("underline_dash_color");
1052 outline_colorstr = eina_stringshare_add("outline_color");
1053 shadow_colorstr = eina_stringshare_add("shadow_color");
1054 glow_colorstr = eina_stringshare_add("glow_color");
1055 glow2_colorstr = eina_stringshare_add("glow2_color");
1056 backing_colorstr = eina_stringshare_add("backing_color");
1057 strikethrough_colorstr = eina_stringshare_add("strikethrough_color");
1058 alignstr = eina_stringshare_add("align");
1059 valignstr = eina_stringshare_add("valign");
1060 wrapstr = eina_stringshare_add("wrap");
1061 left_marginstr = eina_stringshare_add("left_margin");
1062 right_marginstr = eina_stringshare_add("right_margin");
1063 underlinestr = eina_stringshare_add("underline");
1064 strikethroughstr = eina_stringshare_add("strikethrough");
1065 backingstr = eina_stringshare_add("backing");
1066 stylestr = eina_stringshare_add("style");
1067 tabstopsstr = eina_stringshare_add("tabstops");
1068 linesizestr = eina_stringshare_add("linesize");
1069 linerelsizestr = eina_stringshare_add("linerelsize");
1070 linegapstr = eina_stringshare_add("linegap");
1071 linerelgapstr = eina_stringshare_add("linerelgap");
1072 itemstr = eina_stringshare_add("item");
1073 linefillstr = eina_stringshare_add("linefill");
1074 ellipsisstr = eina_stringshare_add("ellipsis");
1075 passwordstr = eina_stringshare_add("password");
1076 underline_dash_widthstr = eina_stringshare_add("underline_dash_width");
1077 underline_dash_gapstr = eina_stringshare_add("underline_dash_gap");
1078 }
1079 format_refcount++;
1080}
1081
1082/**
1083 * @internal
1084 * Shutdown the format strings.
1085 */
1086static void
1087_format_command_shutdown(void)
1088{
1089 if (--format_refcount > 0) return;
1090
1091 eina_stringshare_del(fontstr);
1092 eina_stringshare_del(font_fallbacksstr);
1093 eina_stringshare_del(font_sizestr);
1094 eina_stringshare_del(font_sourcestr);
1095 eina_stringshare_del(font_weightstr);
1096 eina_stringshare_del(font_stylestr);
1097 eina_stringshare_del(font_widthstr);
1098 eina_stringshare_del(langstr);
1099 eina_stringshare_del(colorstr);
1100 eina_stringshare_del(underline_colorstr);
1101 eina_stringshare_del(underline2_colorstr);
1102 eina_stringshare_del(underline_dash_colorstr);
1103 eina_stringshare_del(outline_colorstr);
1104 eina_stringshare_del(shadow_colorstr);
1105 eina_stringshare_del(glow_colorstr);
1106 eina_stringshare_del(glow2_colorstr);
1107 eina_stringshare_del(backing_colorstr);
1108 eina_stringshare_del(strikethrough_colorstr);
1109 eina_stringshare_del(alignstr);
1110 eina_stringshare_del(valignstr);
1111 eina_stringshare_del(wrapstr);
1112 eina_stringshare_del(left_marginstr);
1113 eina_stringshare_del(right_marginstr);
1114 eina_stringshare_del(underlinestr);
1115 eina_stringshare_del(strikethroughstr);
1116 eina_stringshare_del(backingstr);
1117 eina_stringshare_del(stylestr);
1118 eina_stringshare_del(tabstopsstr);
1119 eina_stringshare_del(linesizestr);
1120 eina_stringshare_del(linerelsizestr);
1121 eina_stringshare_del(linegapstr);
1122 eina_stringshare_del(linerelgapstr);
1123 eina_stringshare_del(itemstr);
1124 eina_stringshare_del(linefillstr);
1125 eina_stringshare_del(ellipsisstr);
1126 eina_stringshare_del(passwordstr);
1127 eina_stringshare_del(underline_dash_widthstr);
1128 eina_stringshare_del(underline_dash_gapstr);
1129}
1130
1131/**
1132 * @internal
1133 * Copies str to dst while removing the \\ char, i.e unescape the escape sequences.
1134 *
1135 * @param[out] dst the destination string - Should not be NULL.
1136 * @param[in] src the source string - Should not be NULL.
1137 */
1138static void
1139_format_clean_param(char *dst, const char *src)
1140{
1141 const char *ss;
1142 char *ds;
1143
1144 ds = dst;
1145 for (ss = src; *ss; ss++, ds++)
1146 {
1147 if ((*ss == '\\') && *(ss + 1)) ss++;
1148 *ds = *ss;
1149 }
1150 *ds = 0;
1151}
1152
1153/**
1154 * @internal
1155 * Parses the cmd and parameter and adds the parsed format to fmt.
1156 *
1157 * @param obj the evas object - should not be NULL.
1158 * @param fmt The format to populate - should not be NULL.
1159 * @param[in] cmd the command to process, should be stringshared.
1160 * @param[in] param the parameter of the command.
1161 */
1162static void
1163_format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *cmd, const char *param)
1164{
1165 int len;
1166 char *tmp_param;
1167
1168 len = strlen(param);
1169 tmp_param = alloca(len + 1);
1170
1171 _format_clean_param(tmp_param, param);
1172
1173 /* If we are changing the font, create the fdesc. */
1174 if ((cmd == font_weightstr) || (cmd == font_widthstr) ||
1175 (cmd == font_stylestr) || (cmd == langstr) ||
1176 (cmd == fontstr) || (cmd == font_fallbacksstr))
1177 {
1178 if (!fmt->font.fdesc)
1179 {
1180 fmt->font.fdesc = evas_font_desc_new();
1181 }
1182 else if (!fmt->font.fdesc->is_new)
1183 {
1184 Evas_Font_Description *old = fmt->font.fdesc;
1185 fmt->font.fdesc = evas_font_desc_dup(fmt->font.fdesc);
1186 if (old) evas_font_desc_unref(old);
1187 }
1188 }
1189
1190
1191 if (cmd == fontstr)
1192 {
1193 evas_font_name_parse(fmt->font.fdesc, tmp_param);
1194 }
1195 else if (cmd == font_fallbacksstr)
1196 {
1197 eina_stringshare_replace(&(fmt->font.fdesc->fallbacks), tmp_param);
1198 }
1199 else if (cmd == font_sizestr)
1200 {
1201 int v;
1202
1203 v = atoi(tmp_param);
1204 if (v != fmt->font.size)
1205 {
1206 fmt->font.size = v;
1207 }
1208 }
1209 else if (cmd == font_sourcestr)
1210 {
1211 if ((!fmt->font.source) ||
1212 ((fmt->font.source) && (strcmp(fmt->font.source, tmp_param))))
1213 {
1214 if (fmt->font.source) eina_stringshare_del(fmt->font.source);
1215 fmt->font.source = eina_stringshare_add(tmp_param);
1216 }
1217 }
1218 else if (cmd == font_weightstr)
1219 {
1220 fmt->font.fdesc->weight = evas_font_style_find(tmp_param,
1221 tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_WEIGHT);
1222 }
1223 else if (cmd == font_stylestr)
1224 {
1225 fmt->font.fdesc->slant = evas_font_style_find(tmp_param,
1226 tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_SLANT);
1227 }
1228 else if (cmd == font_widthstr)
1229 {
1230 fmt->font.fdesc->width = evas_font_style_find(tmp_param,
1231 tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_WIDTH);
1232 }
1233 else if (cmd == langstr)
1234 {
1235 eina_stringshare_replace(&(fmt->font.fdesc->lang), tmp_param);
1236 }
1237 else if (cmd == colorstr)
1238 _format_color_parse(tmp_param,
1239 &(fmt->color.normal.r), &(fmt->color.normal.g),
1240 &(fmt->color.normal.b), &(fmt->color.normal.a));
1241 else if (cmd == underline_colorstr)
1242 _format_color_parse(tmp_param,
1243 &(fmt->color.underline.r), &(fmt->color.underline.g),
1244 &(fmt->color.underline.b), &(fmt->color.underline.a));
1245 else if (cmd == underline2_colorstr)
1246 _format_color_parse(tmp_param,
1247 &(fmt->color.underline2.r), &(fmt->color.underline2.g),
1248 &(fmt->color.underline2.b), &(fmt->color.underline2.a));
1249 else if (cmd == underline_dash_colorstr)
1250 _format_color_parse(tmp_param,
1251 &(fmt->color.underline_dash.r), &(fmt->color.underline_dash.g),
1252 &(fmt->color.underline_dash.b), &(fmt->color.underline_dash.a));
1253 else if (cmd == outline_colorstr)
1254 _format_color_parse(tmp_param,
1255 &(fmt->color.outline.r), &(fmt->color.outline.g),
1256 &(fmt->color.outline.b), &(fmt->color.outline.a));
1257 else if (cmd == shadow_colorstr)
1258 _format_color_parse(tmp_param,
1259 &(fmt->color.shadow.r), &(fmt->color.shadow.g),
1260 &(fmt->color.shadow.b), &(fmt->color.shadow.a));
1261 else if (cmd == glow_colorstr)
1262 _format_color_parse(tmp_param,
1263 &(fmt->color.glow.r), &(fmt->color.glow.g),
1264 &(fmt->color.glow.b), &(fmt->color.glow.a));
1265 else if (cmd == glow2_colorstr)
1266 _format_color_parse(tmp_param,
1267 &(fmt->color.glow2.r), &(fmt->color.glow2.g),
1268 &(fmt->color.glow2.b), &(fmt->color.glow2.a));
1269 else if (cmd == backing_colorstr)
1270 _format_color_parse(tmp_param,
1271 &(fmt->color.backing.r), &(fmt->color.backing.g),
1272 &(fmt->color.backing.b), &(fmt->color.backing.a));
1273 else if (cmd == strikethrough_colorstr)
1274 _format_color_parse(tmp_param,
1275 &(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g),
1276 &(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a));
1277 else if (cmd == alignstr)
1278 {
1279 if (!strcmp(tmp_param, "auto"))
1280 {
1281 fmt->halign_auto = EINA_TRUE;
1282 }
1283 else
1284 {
1285 if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5;
1286 else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5;
1287 else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0;
1288 else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0;
1289 else
1290 {
1291 char *endptr = NULL;
1292 double val = strtod(tmp_param, &endptr);
1293 if (endptr)
1294 {
1295 while (*endptr && _is_white(*endptr))
1296 endptr++;
1297 if (*endptr == '%')
1298 val /= 100.0;
1299 }
1300 fmt->halign = val;
1301 if (fmt->halign < 0.0) fmt->halign = 0.0;
1302 else if (fmt->halign > 1.0) fmt->halign = 1.0;
1303 }
1304 fmt->halign_auto = EINA_FALSE;
1305 }
1306 }
1307 else if (cmd == valignstr)
1308 {
1309 if (!strcmp(tmp_param, "top")) fmt->valign = 0.0;
1310 else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5;
1311 else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5;
1312 else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0;
1313 else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0;
1314 else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0;
1315 else
1316 {
1317 char *endptr = NULL;
1318 double val = strtod(tmp_param, &endptr);
1319 if (endptr)
1320 {
1321 while (*endptr && _is_white(*endptr))
1322 endptr++;
1323 if (*endptr == '%')
1324 val /= 100.0;
1325 }
1326 fmt->valign = val;
1327 if (fmt->valign < 0.0) fmt->valign = 0.0;
1328 else if (fmt->valign > 1.0) fmt->valign = 1.0;
1329 }
1330 }
1331 else if (cmd == wrapstr)
1332 {
1333 if (!strcmp(tmp_param, "word"))
1334 {
1335 fmt->wrap_word = 1;
1336 fmt->wrap_char = fmt->wrap_mixed = 0;
1337 }
1338 else if (!strcmp(tmp_param, "char"))
1339 {
1340 fmt->wrap_word = fmt->wrap_mixed = 0;
1341 fmt->wrap_char = 1;
1342 }
1343 else if (!strcmp(tmp_param, "mixed"))
1344 {
1345 fmt->wrap_word = fmt->wrap_char = 0;
1346 fmt->wrap_mixed = 1;
1347 }
1348 else
1349 {
1350 fmt->wrap_word = fmt->wrap_mixed = fmt->wrap_char = 0;
1351 }
1352 }
1353 else if (cmd == left_marginstr)
1354 {
1355 if (!strcmp(tmp_param, "reset"))
1356 fmt->margin.l = 0;
1357 else
1358 {
1359 if (tmp_param[0] == '+')
1360 fmt->margin.l += atoi(&(tmp_param[1]));
1361 else if (tmp_param[0] == '-')
1362 fmt->margin.l -= atoi(&(tmp_param[1]));
1363 else
1364 fmt->margin.l = atoi(tmp_param);
1365 if (fmt->margin.l < 0) fmt->margin.l = 0;
1366 }
1367 }
1368 else if (cmd == right_marginstr)
1369 {
1370 if (!strcmp(tmp_param, "reset"))
1371 fmt->margin.r = 0;
1372 else
1373 {
1374 if (tmp_param[0] == '+')
1375 fmt->margin.r += atoi(&(tmp_param[1]));
1376 else if (tmp_param[0] == '-')
1377 fmt->margin.r -= atoi(&(tmp_param[1]));
1378 else
1379 fmt->margin.r = atoi(tmp_param);
1380 if (fmt->margin.r < 0) fmt->margin.r = 0;
1381 }
1382 }
1383 else if (cmd == underlinestr)
1384 {
1385 if (!strcmp(tmp_param, "off"))
1386 {
1387 fmt->underline = 0;
1388 fmt->underline2 = 0;
1389 }
1390 else if ((!strcmp(tmp_param, "on")) ||
1391 (!strcmp(tmp_param, "single")))
1392 {
1393 fmt->underline = 1;
1394 fmt->underline2 = 0;
1395 }
1396 else if (!strcmp(tmp_param, "double"))
1397 {
1398 fmt->underline = 1;
1399 fmt->underline2 = 1;
1400 }
1401 else if (!strcmp(tmp_param, "dashed"))
1402 fmt->underline_dash = 1;
1403 }
1404 else if (cmd == strikethroughstr)
1405 {
1406 if (!strcmp(tmp_param, "off"))
1407 fmt->strikethrough = 0;
1408 else if (!strcmp(tmp_param, "on"))
1409 fmt->strikethrough = 1;
1410 }
1411 else if (cmd == backingstr)
1412 {
1413 if (!strcmp(tmp_param, "off"))
1414 fmt->backing = 0;
1415 else if (!strcmp(tmp_param, "on"))
1416 fmt->backing = 1;
1417 }
1418 else if (cmd == stylestr)
1419 {
1420 char *p1, *p2, *p, *pp;
1421
1422 p1 = alloca(len + 1);
1423 *p1 = 0;
1424 p2 = alloca(len + 1);
1425 *p2 = 0;
1426 /* no comma */
1427 if (!strstr(tmp_param, ",")) p1 = tmp_param;
1428 else
1429 {
1430 /* split string "str1,str2" into p1 and p2 (if we have more than
1431 * 1 str2 eg "str1,str2,str3,str4" then we don't care. p2 just
1432 * ends up being the last one as right now it's only valid to have
1433 * 1 comma and 2 strings */
1434 pp = p1;
1435 for (p = tmp_param; *p; p++)
1436 {
1437 if (*p == ',')
1438 {
1439 *pp = 0;
1440 pp = p2;
1441 continue;
1442 }
1443 *pp = *p;
1444 pp++;
1445 }
1446 *pp = 0;
1447 }
1448 if (!strcmp(p1, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1449 else if (!strcmp(p1, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1450 else if (!strcmp(p1, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN;
1451 else if (!strcmp(p1, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW;
1452 else if (!strcmp(p1, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE;
1453 else if (!strcmp(p1, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
1454 else if (!strcmp(p1, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
1455 else if (!strcmp(p1, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
1456 else if (!strcmp(p1, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW;
1457 else if (!strcmp(p1, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW;
1458 else if (!strcmp(p1, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW;
1459 else if (!strcmp(p1, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
1460 else fmt->style = EVAS_TEXT_STYLE_PLAIN;
1461
1462 if (*p2)
1463 {
1464 if (!strcmp(p2, "bottom_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
1465 else if (!strcmp(p2, "bottom")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM);
1466 else if (!strcmp(p2, "bottom_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT);
1467 else if (!strcmp(p2, "left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT);
1468 else if (!strcmp(p2, "top_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT);
1469 else if (!strcmp(p2, "top")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP);
1470 else if (!strcmp(p2, "top_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT);
1471 else if (!strcmp(p2, "right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT);
1472 else EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT);
1473 }
1474 }
1475 else if (cmd == tabstopsstr)
1476 {
1477 fmt->tabstops = atoi(tmp_param);
1478 if (fmt->tabstops < 1) fmt->tabstops = 1;
1479 }
1480 else if (cmd == linesizestr)
1481 {
1482 fmt->linesize = atoi(tmp_param);
1483 fmt->linerelsize = 0.0;
1484 }
1485 else if (cmd == linerelsizestr)
1486 {
1487 char *endptr = NULL;
1488 double val = strtod(tmp_param, &endptr);
1489 if (endptr)
1490 {
1491 while (*endptr && _is_white(*endptr))
1492 endptr++;
1493 if (*endptr == '%')
1494 {
1495 fmt->linerelsize = val / 100.0;
1496 fmt->linesize = 0;
1497 if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0;
1498 }
1499 }
1500 }
1501 else if (cmd == linegapstr)
1502 {
1503 fmt->linegap = atoi(tmp_param);
1504 fmt->linerelgap = 0.0;
1505 }
1506 else if (cmd == linerelgapstr)
1507 {
1508 char *endptr = NULL;
1509 double val = strtod(tmp_param, &endptr);
1510 if (endptr)
1511 {
1512 while (*endptr && _is_white(*endptr))
1513 endptr++;
1514 if (*endptr == '%')
1515 {
1516 fmt->linerelgap = val / 100.0;
1517 fmt->linegap = 0;
1518 if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0;
1519 }
1520 }
1521 }
1522 else if (cmd == itemstr)
1523 {
1524 // itemstr == replacement object items in textblock - inline imges
1525 // for example
1526 }
1527 else if (cmd == linefillstr)
1528 {
1529 char *endptr = NULL;
1530 double val = strtod(tmp_param, &endptr);
1531 if (endptr)
1532 {
1533 while (*endptr && _is_white(*endptr))
1534 endptr++;
1535 if (*endptr == '%')
1536 {
1537 fmt->linefill = val / 100.0;
1538 if (fmt->linefill < 0.0) fmt->linefill = 0.0;
1539 }
1540 }
1541 }
1542 else if (cmd == ellipsisstr)
1543 {
1544 char *endptr = NULL;
1545 fmt->ellipsis = strtod(tmp_param, &endptr);
1546 if ((fmt->ellipsis < 0.0) || (fmt->ellipsis > 1.0))
1547 fmt->ellipsis = -1.0;
1548 else
1549 {
1550 Evas_Object_Textblock *o;
1551
1552 o = (Evas_Object_Textblock *)(obj->object_data);
1553 o->have_ellipsis = 1;
1554 }
1555 }
1556 else if (cmd == passwordstr)
1557 {
1558 if (!strcmp(tmp_param, "off"))
1559 fmt->password = 0;
1560 else if (!strcmp(tmp_param, "on"))
1561 fmt->password = 1;
1562 }
1563 else if (cmd == underline_dash_widthstr)
1564 {
1565 fmt->underline_dash_width = atoi(tmp_param);
1566 if (fmt->underline_dash_width <= 0) fmt->underline_dash_width = 1;
1567 }
1568 else if (cmd == underline_dash_gapstr)
1569 {
1570 fmt->underline_dash_gap = atoi(tmp_param);
1571 if (fmt->underline_dash_gap <= 0) fmt->underline_dash_gap = 1;
1572 }
1573}
1574
1575/**
1576 * @internal
1577 * Returns #EINA_TRUE if the item is a format parameter, #EINA_FALSE otherwise.
1578 *
1579 * @param[in] item the item to check - Not NULL.
1580 */
1581static Eina_Bool
1582_format_is_param(const char *item)
1583{
1584 if (strchr(item, '=')) return EINA_TRUE;
1585 return EINA_FALSE;
1586}
1587
1588/**
1589 * @internal
1590 * Parse the format item and populate key and val with the stringshares that
1591 * corrospond to the formats parsed.
1592 * It expects item to be of the structure:
1593 * "key=val"
1594 *
1595 * @param[in] item the item to parse - Not NULL.
1596 * @param[out] key where to store the key at - Not NULL.
1597 * @param[out] val where to store the value at - Not NULL.
1598 */
1599static void
1600_format_param_parse(const char *item, const char **key, const char **val)
1601{
1602 const char *start, *end, *quote;
1603
1604 start = strchr(item, '=');
1605 *key = eina_stringshare_add_length(item, start - item);
1606 start++; /* Advance after the '=' */
1607 /* If we can find a quote, our new delimiter is a quote, not a space. */
1608 if ((quote = strchr(start, '\'')))
1609 {
1610 start = quote + 1;
1611 end = strchr(start, '\'');
1612 }
1613 else
1614 {
1615 end = strchr(start, ' ');
1616 }
1617
1618 /* Null terminate before the spaces */
1619 if (end)
1620 {
1621 *val = eina_stringshare_add_length(start, end - start);
1622 }
1623 else
1624 {
1625 *val = eina_stringshare_add(start);
1626 }
1627}
1628
1629/**
1630 * @internal
1631 * This function parses the format passed in *s and advances s to point to the
1632 * next format item, while returning the current one as the return value.
1633 * @param s The current and returned position in the format string.
1634 * @return the current item parsed from the string.
1635 */
1636static const char *
1637_format_parse(const char **s)
1638{
1639 const char *p;
1640 const char *s1 = NULL, *s2 = NULL;
1641 Eina_Bool quote = EINA_FALSE;;
1642
1643 p = *s;
1644 if (*p == 0) return NULL;
1645 for (;;)
1646 {
1647 if (!s1)
1648 {
1649 if (*p != ' ') s1 = p;
1650 if (*p == 0) break;
1651 }
1652 else if (!s2)
1653 {
1654 if (*p == '\'')
1655 {
1656 quote = !quote;
1657 }
1658
1659 if ((p > *s) && (p[-1] != '\\') && (!quote))
1660 {
1661 if (*p == ' ') s2 = p;
1662 }
1663 if (*p == 0) s2 = p;
1664 }
1665 p++;
1666 if (s1 && s2)
1667 {
1668 *s = s2;
1669 return s1;
1670 }
1671 }
1672 *s = p;
1673 return NULL;
1674}
1675
1676/**
1677 * @internal
1678 * Parse the format str and populate fmt with the formats found.
1679 *
1680 * @param obj The evas object - Not NULL.
1681 * @param[out] fmt The format to populate - Not NULL.
1682 * @param[in] str the string to parse.- Not NULL.
1683 */
1684static void
1685_format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *str)
1686{
1687 const char *s;
1688 const char *item;
1689
1690 s = str;
1691
1692 /* get rid of anything +s or -s off the start of the string */
1693 while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
1694
1695 while ((item = _format_parse(&s)))
1696 {
1697 if (_format_is_param(item))
1698 {
1699 const char *key = NULL, *val = NULL;
1700
1701 _format_param_parse(item, &key, &val);
1702 _format_command(obj, fmt, key, val);
1703 eina_stringshare_del(key);
1704 eina_stringshare_del(val);
1705 }
1706 else
1707 {
1708 /* immediate - not handled here */
1709 }
1710 }
1711}
1712
1713/**
1714 * @internal
1715 * Duplicate a format and return the duplicate.
1716 *
1717 * @param obj The evas object - Not NULL.
1718 * @param[in] fmt The format to duplicate - Not NULL.
1719 * @return the copy of the format.
1720 */
1721static Evas_Object_Textblock_Format *
1722_format_dup(Evas_Object *obj, const Evas_Object_Textblock_Format *fmt)
1723{
1724 Evas_Object_Textblock_Format *fmt2;
1725
1726 fmt2 = calloc(1, sizeof(Evas_Object_Textblock_Format));
1727 memcpy(fmt2, fmt, sizeof(Evas_Object_Textblock_Format));
1728 fmt2->ref = 1;
1729 fmt2->font.fdesc = evas_font_desc_ref(fmt->font.fdesc);
1730
1731 if (fmt->font.source) fmt2->font.source = eina_stringshare_add(fmt->font.source);
1732
1733 /* FIXME: just ref the font here... */
1734 fmt2->font.font = evas_font_load(obj->layer->evas, fmt2->font.fdesc,
1735 fmt2->font.source, (int)(((double) fmt2->font.size) * obj->cur.scale));
1736 return fmt2;
1737}
1738
1739
1740
1741
1742/**
1743 * @internal
1744 * @typedef Ctxt
1745 *
1746 * A pack of information that needed to be passed around in the layout engine,
1747 * packed for easier access.
1748 */
1749typedef struct _Ctxt Ctxt;
1750
1751struct _Ctxt
1752{
1753 Evas_Object *obj;
1754 Evas_Object_Textblock *o;
1755
1756 Evas_Object_Textblock_Paragraph *paragraphs;
1757 Evas_Object_Textblock_Paragraph *par;
1758 Evas_Object_Textblock_Line *ln;
1759
1760
1761 Eina_List *format_stack;
1762 Evas_Object_Textblock_Format *fmt;
1763
1764 int x, y;
1765 int w, h;
1766 int wmax, hmax;
1767 int maxascent, maxdescent;
1768 int marginl, marginr;
1769 int line_no;
1770 int underline_extend;
1771 int have_underline, have_underline2;
1772 double align, valign;
1773 Eina_Bool align_auto : 1;
1774 Eina_Bool width_changed : 1;
1775};
1776
1777static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, Eina_List *rel);
1778static void _text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti);
1779static void _layout_do_format(const Evas_Object *obj, Ctxt *c, Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n, int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b, Eina_Bool create_item);
1780/**
1781 * @internal
1782 * Adjust the ascent/descent of the format and context.
1783 *
1784 * @param maxascent The ascent to update - Not NUL.
1785 * @param maxdescent The descent to update - Not NUL.
1786 * @param fmt The format to adjust - NOT NULL.
1787 */
1788static void
1789_layout_format_ascent_descent_adjust(const Evas_Object *obj,
1790 Evas_Coord *maxascent, Evas_Coord *maxdescent,
1791 Evas_Object_Textblock_Format *fmt)
1792{
1793 int ascent, descent;
1794
1795 if (fmt->font.font)
1796 {
1797 // ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font);
1798 // descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font);
1799 ascent = ENFN->font_ascent_get(ENDT, fmt->font.font);
1800 descent = ENFN->font_descent_get(ENDT, fmt->font.font);
1801 if (fmt->linesize > 0)
1802 {
1803 if ((ascent + descent) < fmt->linesize)
1804 {
1805 ascent = ((fmt->linesize * ascent) / (ascent + descent));
1806 descent = fmt->linesize - ascent;
1807 }
1808 }
1809 else if (fmt->linerelsize > 0.0)
1810 {
1811 descent = descent * fmt->linerelsize;
1812 ascent = ascent * fmt->linerelsize;
1813 }
1814 descent += fmt->linegap;
1815 descent += ((ascent + descent) * fmt->linerelgap);
1816 if (*maxascent < ascent) *maxascent = ascent;
1817 if (*maxdescent < descent) *maxdescent = descent;
1818 if (fmt->linefill > 0.0)
1819 {
1820 int dh;
1821
1822 dh = obj->cur.geometry.h - (*maxascent + *maxdescent);
1823 if (dh < 0) dh = 0;
1824 dh = fmt->linefill * dh;
1825 *maxdescent += dh / 2;
1826 *maxascent += dh - (dh / 2);
1827 // FIXME: set flag that says "if heigh changes - reformat"
1828 }
1829 }
1830}
1831
1832/**
1833 * @internal
1834 * Create a new line using the info from the format and update the format
1835 * and context.
1836 *
1837 * @param c The context to work on - Not NULL.
1838 * @param fmt The format to use info from - NOT NULL.
1839 */
1840static void
1841_layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt)
1842{
1843 c->ln = calloc(1, sizeof(Evas_Object_Textblock_Line));
1844 c->align = fmt->halign;
1845 c->align_auto = fmt->halign_auto;
1846 c->marginl = fmt->margin.l;
1847 c->marginr = fmt->margin.r;
1848 c->par->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->par->lines), EINA_INLIST_GET(c->ln));
1849 c->x = 0;
1850 c->maxascent = c->maxdescent = 0;
1851 c->ln->line_no = -1;
1852 c->ln->par = c->par;
1853}
1854
1855static inline Evas_Object_Textblock_Paragraph *
1856_layout_find_paragraph_by_y(Evas_Object_Textblock *o, Evas_Coord y)
1857{
1858 Evas_Object_Textblock_Paragraph *start, *par;
1859 int i;
1860
1861 start = o->paragraphs;
1862
1863 for (i = 0 ; i < TEXTBLOCK_PAR_INDEX_SIZE ; i++)
1864 {
1865 if (!o->par_index[i] || (o->par_index[i]->y > y))
1866 {
1867 break;
1868 }
1869 start = o->par_index[i];
1870 }
1871
1872 EINA_INLIST_FOREACH(start, par)
1873 {
1874 if ((par->y <= y) && (y < par->y + par->h))
1875 return par;
1876 }
1877
1878 return NULL;
1879}
1880
1881static inline Evas_Object_Textblock_Paragraph *
1882_layout_find_paragraph_by_line_no(Evas_Object_Textblock *o, int line_no)
1883{
1884 Evas_Object_Textblock_Paragraph *start, *par;
1885 int i;
1886
1887 start = o->paragraphs;
1888
1889 for (i = 0 ; i < TEXTBLOCK_PAR_INDEX_SIZE ; i++)
1890 {
1891 if (!o->par_index[i] || (o->par_index[i]->line_no > line_no))
1892 {
1893 break;
1894 }
1895 start = o->par_index[i];
1896 }
1897
1898 EINA_INLIST_FOREACH(start, par)
1899 {
1900 Evas_Object_Textblock_Paragraph *npar =
1901 (Evas_Object_Textblock_Paragraph *) EINA_INLIST_GET(par)->next;
1902 if ((par->line_no <= line_no) &&
1903 (!npar || (line_no < npar->line_no)))
1904 return par;
1905 }
1906
1907 return NULL;
1908}
1909/* End of rbtree index functios */
1910
1911/**
1912 * @internal
1913 * Create a new layout paragraph.
1914 * If c->par is not NULL, the paragraph is appended/prepended according
1915 * to the append parameter. If it is NULL, the paragraph is appended at
1916 * the end of the list.
1917 *
1918 * @param c The context to work on - Not NULL.
1919 * @param n the associated text node
1920 * @param append true to append, false to prpend.
1921 */
1922static void
1923_layout_paragraph_new(Ctxt *c, Evas_Object_Textblock_Node_Text *n,
1924 Eina_Bool append)
1925{
1926 Evas_Object_Textblock_Paragraph *rel_par = c->par;
1927 c->par = calloc(1, sizeof(Evas_Object_Textblock_Paragraph));
1928 if (append || !rel_par)
1929 c->paragraphs = (Evas_Object_Textblock_Paragraph *)
1930 eina_inlist_append_relative(EINA_INLIST_GET(c->paragraphs),
1931 EINA_INLIST_GET(c->par),
1932 EINA_INLIST_GET(rel_par));
1933 else
1934 c->paragraphs = (Evas_Object_Textblock_Paragraph *)
1935 eina_inlist_prepend_relative(EINA_INLIST_GET(c->paragraphs),
1936 EINA_INLIST_GET(c->par),
1937 EINA_INLIST_GET(rel_par));
1938
1939 c->ln = NULL;
1940 c->par->text_node = n;
1941 if (n)
1942 n->par = c->par;
1943 c->par->line_no = -1;
1944 c->par->visible = 1;
1945 c->o->num_paragraphs++;
1946}
1947
1948#ifdef BIDI_SUPPORT
1949/**
1950 * @internal
1951 * Update bidi paragraph props.
1952 *
1953 * @param par The paragraph to update
1954 */
1955static inline void
1956_layout_update_bidi_props(const Evas_Object_Textblock *o,
1957 Evas_Object_Textblock_Paragraph *par)
1958{
1959 if (par->text_node)
1960 {
1961 const Eina_Unicode *text;
1962 int *segment_idxs = NULL;
1963 text = eina_ustrbuf_string_get(par->text_node->unicode);
1964
1965 if (o->bidi_delimiters)
1966 segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters);
1967
1968 evas_bidi_paragraph_props_unref(par->bidi_props);
1969 par->bidi_props = evas_bidi_paragraph_props_get(text,
1970 eina_ustrbuf_length_get(par->text_node->unicode),
1971 segment_idxs);
1972 par->direction = EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(par->bidi_props) ?
1973 EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
1974 par->is_bidi = !!par->bidi_props;
1975 if (segment_idxs) free(segment_idxs);
1976 }
1977}
1978#endif
1979
1980
1981/**
1982 * @internal
1983 * Free the visual lines in the paragraph (logical items are kept)
1984 */
1985static void
1986_paragraph_clear(const Evas_Object *obj __UNUSED__,
1987 Evas_Object_Textblock_Paragraph *par)
1988{
1989 while (par->lines)
1990 {
1991 Evas_Object_Textblock_Line *ln;
1992
1993 ln = (Evas_Object_Textblock_Line *) par->lines;
1994 par->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(par->lines), EINA_INLIST_GET(par->lines));
1995 _line_free(ln);
1996 }
1997}
1998
1999/**
2000 * @internal
2001 * Free the layout paragraph and all of it's lines and logical items.
2002 */
2003static void
2004_paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par)
2005{
2006 Evas_Object_Textblock *o;
2007 o = (Evas_Object_Textblock *)(obj->object_data);
2008 _paragraph_clear(obj, par);
2009
2010 {
2011 Eina_List *i, *i_prev;
2012 Evas_Object_Textblock_Item *it;
2013 EINA_LIST_FOREACH_SAFE(par->logical_items, i, i_prev, it)
2014 {
2015 _item_free(obj, NULL, it);
2016 }
2017 eina_list_free(par->logical_items);
2018 }
2019#ifdef BIDI_SUPPORT
2020 if (par->bidi_props)
2021 evas_bidi_paragraph_props_unref(par->bidi_props);
2022#endif
2023 /* If we are the active par of the text node, set to NULL */
2024 if (par->text_node && (par->text_node->par == par))
2025 par->text_node->par = NULL;
2026
2027 o->num_paragraphs--;
2028
2029 free(par);
2030}
2031
2032/**
2033 * @internal
2034 * Clear all the paragraphs from the inlist pars.
2035 *
2036 * @param obj the evas object - Not NULL.
2037 * @param pars the paragraphs to clean - Not NULL.
2038 */
2039static void
2040_paragraphs_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
2041{
2042 Evas_Object_Textblock_Paragraph *par;
2043
2044 EINA_INLIST_FOREACH(EINA_INLIST_GET(pars), par)
2045 {
2046 _paragraph_clear(obj, par);
2047 }
2048}
2049
2050/**
2051 * @internal
2052 * Free the paragraphs from the inlist pars, the difference between this and
2053 * _paragraphs_clear is that the latter keeps the logical items and the par
2054 * items, while the former frees them as well.
2055 *
2056 * @param obj the evas object - Not NULL.
2057 * @param pars the paragraphs to clean - Not NULL.
2058 */
2059static void
2060_paragraphs_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars)
2061{
2062 Evas_Object_Textblock *o;
2063 o = (Evas_Object_Textblock *)(obj->object_data);
2064
2065 o->num_paragraphs = 0;
2066
2067 while (pars)
2068 {
2069 Evas_Object_Textblock_Paragraph *par;
2070
2071 par = (Evas_Object_Textblock_Paragraph *) pars;
2072 pars = (Evas_Object_Textblock_Paragraph *)eina_inlist_remove(EINA_INLIST_GET(pars), EINA_INLIST_GET(par));
2073 _paragraph_free(obj, par);
2074 }
2075}
2076
2077/**
2078 * @internal
2079 * Push fmt to the format stack, if fmt is NULL, will fush a default item.
2080 *
2081 * @param c the context to work on - Not NULL.
2082 * @param fmt the format to push.
2083 * @see _layout_format_pop()
2084 */
2085static Evas_Object_Textblock_Format *
2086_layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt,
2087 Evas_Object_Textblock_Node_Format *fnode)
2088{
2089 if (fmt)
2090 {
2091 fmt = _format_dup(c->obj, fmt);
2092 c->format_stack = eina_list_prepend(c->format_stack, fmt);
2093 fmt->fnode = fnode;
2094 }
2095 else
2096 {
2097 fmt = calloc(1, sizeof(Evas_Object_Textblock_Format));
2098 c->format_stack = eina_list_prepend(c->format_stack, fmt);
2099 fmt->ref = 1;
2100 fmt->halign = 0.0;
2101 fmt->halign_auto = EINA_TRUE;
2102 fmt->valign = -1.0;
2103 fmt->style = EVAS_TEXT_STYLE_PLAIN;
2104 fmt->tabstops = 32;
2105 fmt->linesize = 0;
2106 fmt->linerelsize = 0.0;
2107 fmt->linegap = 0;
2108 fmt->underline_dash_width = 6;
2109 fmt->underline_dash_gap = 2;
2110 fmt->linerelgap = 0.0;
2111 fmt->password = 1;
2112 }
2113 return fmt;
2114}
2115
2116/**
2117 * @internal
2118 * Pop fmt to the format stack, if there's something in the stack free fmt
2119 * and set it to point to the next item instead, else return fmt.
2120 *
2121 * @param c the context to work on - Not NULL.
2122 * @param format - the text of the format to free (assured to start with '-').
2123 * @return the next format in the stack, or format if there's none.
2124 * @see _layout_format_push()
2125 */
2126static Evas_Object_Textblock_Format *
2127_layout_format_pop(Ctxt *c, const char *format)
2128{
2129 Evas_Object_Textblock_Format *fmt = eina_list_data_get(c->format_stack);
2130
2131 if ((c->format_stack) && (c->format_stack->next))
2132 {
2133 Eina_List *redo_nodes = NULL;
2134 format++; /* Skip the '-' */
2135
2136 /* Generic pop, should just pop. */
2137 if (((format[0] == ' ') && !format[1]) ||
2138 !format[0])
2139 {
2140 _format_unref_free(c->obj, fmt);
2141 c->format_stack =
2142 eina_list_remove_list(c->format_stack, c->format_stack);
2143 }
2144 else
2145 {
2146 size_t len = strlen(format);
2147 Eina_List *i, *i_next;
2148 /* Remove only the matching format. */
2149 EINA_LIST_FOREACH_SAFE(c->format_stack, i, i_next, fmt)
2150 {
2151 /* Stop when we reach the base item */
2152 if (!i_next)
2153 break;
2154
2155 c->format_stack =
2156 eina_list_remove_list(c->format_stack, c->format_stack);
2157
2158 /* Make sure the ending tag matches the starting tag.
2159 * I.e whole of the ending tag matches the start of the
2160 * starting tag, and the starting tag's next char is either
2161 * NULL or white. Skip the starting '+'. */
2162 if (_FORMAT_IS_CLOSER_OF(
2163 fmt->fnode->orig_format, format, len))
2164 {
2165 _format_unref_free(c->obj, fmt);
2166 break;
2167 }
2168 else
2169 {
2170 redo_nodes = eina_list_prepend(redo_nodes, fmt->fnode);
2171 _format_unref_free(c->obj, fmt);
2172 }
2173 }
2174 }
2175
2176 /* Redo all the nodes needed to be redone */
2177 {
2178 Evas_Object_Textblock_Node_Format *fnode;
2179 Eina_List *i, *i_next;
2180
2181 EINA_LIST_FOREACH_SAFE(redo_nodes, i, i_next, fnode)
2182 {
2183 /* FIXME: Actually do something with the new acquired padding,
2184 * the can be different and affect our padding! */
2185 Evas_Coord style_pad_l, style_pad_r, style_pad_t, style_pad_b;
2186 style_pad_l = style_pad_r = style_pad_t = style_pad_b = 0;
2187 redo_nodes = eina_list_remove_list(redo_nodes, i);
2188 fmt = eina_list_data_get(c->format_stack);
2189 _layout_do_format(c->obj, c, &fmt, fnode,
2190 &style_pad_l, &style_pad_r,
2191 &style_pad_t, &style_pad_b, EINA_FALSE);
2192 }
2193 }
2194
2195 fmt = eina_list_data_get(c->format_stack);
2196 }
2197 return fmt;
2198}
2199
2200/**
2201 * @internal
2202 * Parse item and fill fmt with the item.
2203 *
2204 * @param c the context to work on - Not NULL.
2205 * @param fmt the format to fill - not null.
2206 */
2207static void
2208_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item)
2209{
2210 const char *key = NULL, *val = NULL;
2211
2212 _format_param_parse(item, &key, &val);
2213 if ((key) && (val)) _format_command(c->obj, fmt, key, val);
2214 if (key) eina_stringshare_del(key);
2215 if (val) eina_stringshare_del(val);
2216 c->align = fmt->halign;
2217 c->align_auto = fmt->halign_auto;
2218 c->marginl = fmt->margin.l;
2219 c->marginr = fmt->margin.r;
2220}
2221
2222#define VSIZE_FULL 0
2223#define VSIZE_ASCENT 1
2224
2225#define SIZE 0
2226#define SIZE_ABS 1
2227#define SIZE_REL 2
2228
2229/**
2230 * @internal
2231 * Get the current line's alignment from the context.
2232 *
2233 * @param c the context to work on - Not NULL.
2234 */
2235static inline double
2236_layout_line_align_get(Ctxt *c)
2237{
2238#ifdef BIDI_SUPPORT
2239 if (c->align_auto && c->ln)
2240 {
2241 if (c->ln->items && c->ln->items->text_node &&
2242 (c->ln->par->direction == EVAS_BIDI_DIRECTION_RTL))
2243 {
2244 /* Align right*/
2245 return 1.0;
2246 }
2247 else
2248 {
2249 /* Align left */
2250 return 0.0;
2251 }
2252 }
2253#endif
2254 return c->align;
2255}
2256
2257#ifdef BIDI_SUPPORT
2258/**
2259 * @internal
2260 * Reorder the items in visual order
2261 *
2262 * @param line the line to reorder
2263 */
2264static void
2265_layout_line_reorder(Evas_Object_Textblock_Line *line)
2266{
2267 /*FIXME: do it a bit more efficient - not very efficient ATM. */
2268 Evas_Object_Textblock_Item *it;
2269 EvasBiDiStrIndex *v_to_l = NULL;
2270 Evas_Coord x;
2271 size_t start, end;
2272 size_t len;
2273
2274 if (line->items && line->items->text_node &&
2275 line->par->bidi_props)
2276 {
2277 Evas_BiDi_Paragraph_Props *props;
2278 props = line->par->bidi_props;
2279 start = end = line->items->text_pos;
2280
2281 /* Find the first and last positions in the line */
2282
2283 EINA_INLIST_FOREACH(line->items, it)
2284 {
2285 if (it->text_pos < start)
2286 {
2287 start = it->text_pos;
2288 }
2289 else
2290 {
2291 int tlen;
2292 tlen = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
2293 _ITEM_TEXT(it)->text_props.text_len : 1;
2294 if (it->text_pos + tlen > end)
2295 {
2296 end = it->text_pos + tlen;
2297 }
2298 }
2299 }
2300
2301 len = end - start;
2302 evas_bidi_props_reorder_line(NULL, start, len, props, &v_to_l);
2303
2304 /* Update visual pos */
2305 {
2306 Evas_Object_Textblock_Item *i;
2307 i = line->items;
2308 while (i)
2309 {
2310 i->visual_pos = evas_bidi_position_logical_to_visual(
2311 v_to_l, len, i->text_pos - start);
2312 i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(i)->next;
2313 }
2314 }
2315
2316 /*FIXME: not very efficient, sort the items arrays. Anyhow, should only
2317 * reorder if it's a bidi paragraph */
2318 {
2319 Evas_Object_Textblock_Item *i, *j, *min;
2320 i = line->items;
2321 while (i)
2322 {
2323 min = i;
2324 EINA_INLIST_FOREACH(i, j)
2325 {
2326 if (j->visual_pos < min->visual_pos)
2327 {
2328 min = j;
2329 }
2330 }
2331 if (min != i)
2332 {
2333 line->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min));
2334 line->items = (Evas_Object_Textblock_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
2335 }
2336
2337 i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(min)->next;
2338 }
2339 }
2340 }
2341
2342 if (v_to_l) free(v_to_l);
2343 x = 0;
2344 EINA_INLIST_FOREACH(line->items, it)
2345 {
2346 it->x = x;
2347 x += it->adv;
2348 }
2349}
2350#endif
2351
2352/* FIXME: doc */
2353static void
2354_layout_calculate_format_item_size(const Evas_Object *obj,
2355 const Evas_Object_Textblock_Format_Item *fi,
2356 Evas_Coord *maxascent, Evas_Coord *maxdescent,
2357 Evas_Coord *_y, Evas_Coord *_w, Evas_Coord *_h)
2358{
2359 /* Adjust sizes according to current line height/scale */
2360 Evas_Coord w, h;
2361 const char *p, *s;
2362
2363 s = fi->item;
2364 w = fi->parent.w;
2365 h = fi->parent.h;
2366 switch (fi->size)
2367 {
2368 case SIZE:
2369 p = strstr(s, " size=");
2370 if (p)
2371 {
2372 p += 6;
2373 if (sscanf(p, "%ix%i", &w, &h) == 2)
2374 {
2375 w = w * obj->cur.scale;
2376 h = h * obj->cur.scale;
2377 }
2378 }
2379 break;
2380 case SIZE_REL:
2381 p = strstr((char *) s, " relsize=");
2382 p += 9;
2383 if (sscanf(p, "%ix%i", &w, &h) == 2)
2384 {
2385 int sz = 1;
2386 if (fi->vsize == VSIZE_FULL)
2387 {
2388 sz = *maxdescent + *maxascent;
2389 }
2390 else if (fi->vsize == VSIZE_ASCENT)
2391 {
2392 sz = *maxascent;
2393 }
2394 w = (w * sz) / h;
2395 h = sz;
2396 }
2397 break;
2398 case SIZE_ABS:
2399 /* Nothing to do */
2400 default:
2401 break;
2402 }
2403
2404 switch (fi->size)
2405 {
2406 case SIZE:
2407 case SIZE_ABS:
2408 switch (fi->vsize)
2409 {
2410 case VSIZE_FULL:
2411 if (h > (*maxdescent + *maxascent))
2412 {
2413 *maxascent += h - (*maxdescent + *maxascent);
2414 *_y = -*maxascent;
2415 }
2416 else
2417 *_y = -(h - *maxdescent);
2418 break;
2419 case VSIZE_ASCENT:
2420 if (h > *maxascent)
2421 {
2422 *maxascent = h;
2423 *_y = -h;
2424 }
2425 else
2426 *_y = -h;
2427 break;
2428 default:
2429 break;
2430 }
2431 break;
2432 case SIZE_REL:
2433 switch (fi->vsize)
2434 {
2435 case VSIZE_FULL:
2436 case VSIZE_ASCENT:
2437 *_y = -*maxascent;
2438 break;
2439 default:
2440 break;
2441 }
2442 break;
2443 default:
2444 break;
2445 }
2446
2447 *_w = w;
2448 *_h = h;
2449}
2450
2451/**
2452 * @internal
2453 * Order the items in the line, update it's properties and update it's
2454 * corresponding paragraph.
2455 *
2456 * @param c the context to work on - Not NULL.
2457 * @param fmt the format to use.
2458 * @param add_line true if we should create a line, false otherwise.
2459 */
2460static void
2461_layout_line_finalize(Ctxt *c, Evas_Object_Textblock_Format *fmt)
2462{
2463 Evas_Object_Textblock_Item *it;
2464 Evas_Coord x = 0;
2465
2466 /* If there are no text items yet, calc ascent/descent
2467 * according to the current format. */
2468 if (c->maxascent + c->maxdescent == 0)
2469 _layout_format_ascent_descent_adjust(c->obj, &c->maxascent,
2470 &c->maxdescent, fmt);
2471
2472 /* Adjust all the item sizes according to the final line size,
2473 * and update the x positions of all the items of the line. */
2474 EINA_INLIST_FOREACH(c->ln->items, it)
2475 {
2476 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
2477 {
2478 Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
2479 if (!fi->formatme) goto loop_advance;
2480 _layout_calculate_format_item_size(c->obj, fi, &c->maxascent,
2481 &c->maxdescent, &fi->y, &fi->parent.w, &fi->parent.h);
2482 fi->parent.adv = fi->parent.w;
2483 }
2484
2485loop_advance:
2486 it->x = x;
2487 x += it->adv;
2488
2489 if ((it->x + it->adv) > c->ln->w) c->ln->w = it->x + it->adv;
2490 }
2491
2492 c->ln->y = (c->y - c->par->y) + c->o->style_pad.t;
2493 c->ln->h = c->maxascent + c->maxdescent;
2494 c->ln->baseline = c->maxascent;
2495 if (c->have_underline2)
2496 {
2497 if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent;
2498 }
2499 else if (c->have_underline)
2500 {
2501 if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent;
2502 }
2503 c->ln->line_no = c->line_no - c->ln->par->line_no;
2504 c->line_no++;
2505 c->y += c->maxascent + c->maxdescent;
2506 if (c->w >= 0)
2507 {
2508 c->ln->x = c->marginl + c->o->style_pad.l +
2509 ((c->w - c->ln->w -
2510 c->o->style_pad.l - c->o->style_pad.r -
2511 c->marginl - c->marginr) * _layout_line_align_get(c));
2512 }
2513 else
2514 {
2515 c->ln->x = c->marginl + c->o->style_pad.l;
2516 }
2517
2518 c->par->h = c->ln->y + c->ln->h;
2519 if (c->ln->w > c->par->w)
2520 c->par->w = c->ln->w;
2521
2522 {
2523 Evas_Coord new_wmax = c->ln->w +
2524 c->marginl + c->marginr - (c->o->style_pad.l + c->o->style_pad.r);
2525 if (new_wmax > c->wmax)
2526 c->wmax = new_wmax;
2527 }
2528}
2529
2530/**
2531 * @internal
2532 * Create a new line and append it to the lines in the context.
2533 *
2534 * @param c the context to work on - Not NULL.
2535 * @param fmt the format to use.
2536 * @param add_line true if we should create a line, false otherwise.
2537 */
2538static void
2539_layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt)
2540{
2541 _layout_line_finalize(c, fmt);
2542 _layout_line_new(c, fmt);
2543}
2544
2545/**
2546 * @internal
2547 * Create a new text layout item from the string and the format.
2548 *
2549 * @param c the context to work on - Not NULL.
2550 * @param fmt the format to use.
2551 * @param str the string to use.
2552 * @param len the length of the string.
2553 */
2554static Evas_Object_Textblock_Text_Item *
2555_layout_text_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt)
2556{
2557 Evas_Object_Textblock_Text_Item *ti;
2558
2559 ti = calloc(1, sizeof(Evas_Object_Textblock_Text_Item));
2560 ti->parent.format = fmt;
2561 ti->parent.format->ref++;
2562 ti->parent.type = EVAS_TEXTBLOCK_ITEM_TEXT;
2563 return ti;
2564}
2565
2566/**
2567 * @internal
2568 * Return the cutoff of the text in the text item.
2569 *
2570 * @param c the context to work on - Not NULL.
2571 * @param fmt the format to use. - Not NULL.
2572 * @param it the item to check - Not null.
2573 * @return -1 if there is no cutoff (either because there is really none,
2574 * or because of an error), cutoff index on success.
2575 */
2576static int
2577_layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt,
2578 const Evas_Object_Textblock_Text_Item *ti)
2579{
2580 if (fmt->font.font)
2581 {
2582 Evas_Coord x;
2583 x = c->w - c->o->style_pad.l - c->o->style_pad.r - c->marginl -
2584 c->marginr - c->x - ti->x_adjustment;
2585 if (x < 0)
2586 x = 0;
2587 return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font,
2588 &ti->text_props, x, 0);
2589 }
2590 return -1;
2591}
2592
2593/**
2594 * @internal
2595 * Split before cut, and strip if str[cut - 1] is a whitespace.
2596 *
2597 * @param c the context to work on - Not NULL.
2598 * @param ti the item to cut - not null.
2599 * @param lti the logical list item of the item.
2600 * @param cut the cut index.
2601 * @return the second (newly created) item.
2602 */
2603static Evas_Object_Textblock_Text_Item *
2604_layout_item_text_split_strip_white(Ctxt *c,
2605 Evas_Object_Textblock_Text_Item *ti, Eina_List *lti, size_t cut)
2606{
2607 const Eina_Unicode *ts;
2608 Evas_Object_Textblock_Text_Item *new_ti = NULL, *white_ti = NULL;
2609
2610 ts = GET_ITEM_TEXT(ti);
2611
2612 if (!IS_AT_END(ti, cut) && (ti->text_props.text_len > 0))
2613 {
2614 new_ti = _layout_text_item_new(c, ti->parent.format);
2615 new_ti->parent.text_node = ti->parent.text_node;
2616 new_ti->parent.text_pos = ti->parent.text_pos + cut;
2617 new_ti->parent.merge = EINA_TRUE;
2618
2619 evas_common_text_props_split(&ti->text_props,
2620 &new_ti->text_props, cut);
2621 _layout_text_add_logical_item(c, new_ti, lti);
2622 }
2623
2624 /* Strip the previous white if needed */
2625 if ((cut >= 1) && _is_white(ts[cut - 1]) && (ti->text_props.text_len > 0))
2626 {
2627 if (cut - 1 > 0)
2628 {
2629 size_t white_cut = cut - 1;
2630 white_ti = _layout_text_item_new(c, ti->parent.format);
2631 white_ti->parent.text_node = ti->parent.text_node;
2632 white_ti->parent.text_pos = ti->parent.text_pos + white_cut;
2633 white_ti->parent.merge = EINA_TRUE;
2634 white_ti->parent.visually_deleted = EINA_TRUE;
2635
2636 evas_common_text_props_split(&ti->text_props,
2637 &white_ti->text_props, white_cut);
2638 _layout_text_add_logical_item(c, white_ti, lti);
2639 }
2640 else
2641 {
2642 /* Mark this one as the visually deleted. */
2643 ti->parent.visually_deleted = EINA_TRUE;
2644 }
2645 }
2646
2647 if (new_ti || white_ti)
2648 {
2649 _text_item_update_sizes(c, ti);
2650 }
2651 return new_ti;
2652}
2653
2654/**
2655 * @internal
2656 * Merge item2 into item1 and free item2.
2657 *
2658 * @param c the context to work on - Not NULL.
2659 * @param item1 the item to copy to
2660 * @param item2 the item to copy from
2661 */
2662static void
2663_layout_item_merge_and_free(Ctxt *c,
2664 Evas_Object_Textblock_Text_Item *item1,
2665 Evas_Object_Textblock_Text_Item *item2)
2666{
2667 evas_common_text_props_merge(&item1->text_props,
2668 &item2->text_props);
2669
2670 _text_item_update_sizes(c, item1);
2671
2672 item1->parent.merge = EINA_FALSE;
2673 item1->parent.visually_deleted = EINA_FALSE;
2674
2675 _item_free(c->obj, NULL, _ITEM(item2));
2676}
2677
2678/**
2679 * @internal
2680 * Calculates an item's size.
2681 *
2682 * @param c the context
2683 * @param it the item itself.
2684 */
2685static void
2686_text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti)
2687{
2688 int tw, th, inset, advw;
2689 const Evas_Object_Textblock_Format *fmt = ti->parent.format;
2690 int shad_sz = 0, shad_dst = 0, out_sz = 0;
2691 int dx = 0, minx = 0, maxx = 0, shx1, shx2;
2692
2693 tw = th = 0;
2694 if (fmt->font.font)
2695 c->ENFN->font_string_size_get(c->ENDT, fmt->font.font,
2696 &ti->text_props, &tw, &th);
2697 inset = 0;
2698 if (fmt->font.font)
2699 inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font,
2700 &ti->text_props);
2701 advw = 0;
2702 if (fmt->font.font)
2703 advw = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font,
2704 &ti->text_props);
2705
2706
2707 /* These adjustments are calculated and thus heavily linked to those in
2708 * textblock_render!!! Don't change one without the other. */
2709
2710 switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC)
2711 {
2712 case EVAS_TEXT_STYLE_SHADOW:
2713 shad_dst = 1;
2714 break;
2715 case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
2716 case EVAS_TEXT_STYLE_FAR_SHADOW:
2717 shad_dst = 2;
2718 out_sz = 1;
2719 break;
2720 case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
2721 shad_dst = 1;
2722 shad_sz = 2;
2723 out_sz = 1;
2724 break;
2725 case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
2726 shad_dst = 2;
2727 shad_sz = 2;
2728 break;
2729 case EVAS_TEXT_STYLE_SOFT_SHADOW:
2730 shad_dst = 1;
2731 shad_sz = 2;
2732 break;
2733 case EVAS_TEXT_STYLE_GLOW:
2734 case EVAS_TEXT_STYLE_SOFT_OUTLINE:
2735 out_sz = 2;
2736 break;
2737 case EVAS_TEXT_STYLE_OUTLINE:
2738 out_sz = 1;
2739 break;
2740 default:
2741 break;
2742 }
2743 switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
2744 {
2745 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
2746 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
2747 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
2748 dx = -1;
2749 break;
2750 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
2751 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
2752 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
2753 dx = 1;
2754 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
2755 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
2756 default:
2757 dx = 0;
2758 break;
2759 }
2760 minx = -out_sz;
2761 maxx = out_sz;
2762 shx1 = dx * shad_dst;
2763 shx1 -= shad_sz;
2764 shx2 = dx * shad_dst;
2765 shx2 += shad_sz;
2766 if (shx1 < minx) minx = shx1;
2767 if (shx2 > maxx) maxx = shx2;
2768 inset += -minx;
2769 ti->x_adjustment = maxx - minx;
2770
2771 ti->inset = inset;
2772 ti->parent.w = tw + ti->x_adjustment;
2773 ti->parent.h = th;
2774 ti->parent.adv = advw;
2775 ti->parent.x = 0;
2776}
2777
2778/**
2779 * @internal
2780 * Adds the item to the list, updates the item's properties (e.g, x,w,h)
2781 *
2782 * @param c the context
2783 * @param it the item itself.
2784 * @param rel item ti will be appened after, NULL = last.
2785 */
2786static void
2787_layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti,
2788 Eina_List *rel)
2789{
2790 _text_item_update_sizes(c, ti);
2791
2792 c->par->logical_items = eina_list_append_relative_list(
2793 c->par->logical_items, ti, rel);
2794}
2795
2796/**
2797 * @internal
2798 * Appends the text from node n starting at start ending at off to the layout.
2799 * It uses the fmt for the formatting.
2800 *
2801 * @param c the current context- NOT NULL.
2802 * @param fmt the format to use.
2803 * @param n the text node. - Not null.
2804 * @param start the start position. - in range.
2805 * @param off the offset - start + offset in range. if offset is -1, it'll add everything to the end of the string if offset = 0 it'll return with doing nothing.
2806 * @param repch a replacement char to print instead of the original string, for example, * when working with passwords.
2807 */
2808static void
2809_layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node_Text *n, int start, int off, const char *repch)
2810{
2811 const Eina_Unicode *str = EINA_UNICODE_EMPTY_STRING;
2812 const Eina_Unicode *tbase;
2813 Evas_Object_Textblock_Text_Item *ti;
2814 size_t cur_len = 0;
2815 Eina_Unicode urepch = 0;
2816
2817 /* prepare a working copy of the string, either filled by the repch or
2818 * filled with the true values */
2819 if (n)
2820 {
2821 int len;
2822 int orig_off = off;
2823
2824 /* Figure out if we want to bail, work with an empty string,
2825 * or continue with a slice of the passed string */
2826 len = eina_ustrbuf_length_get(n->unicode);
2827 if (off == 0) return;
2828 else if (off < 0) off = len - start;
2829
2830 if (start < 0)
2831 {
2832 start = 0;
2833 }
2834 else if ((start == 0) && (off == 0) && (orig_off == -1))
2835 {
2836 /* Special case that means that we need to add an empty
2837 * item */
2838 str = EINA_UNICODE_EMPTY_STRING;
2839 goto skip;
2840 }
2841 else if ((start >= len) || (start + off > len))
2842 {
2843 return;
2844 }
2845
2846 /* If we work with a replacement char, create a string which is the same
2847 * but with replacement chars instead of regular chars. */
2848 if ((fmt->password) && (repch) && (eina_ustrbuf_length_get(n->unicode)))
2849 {
2850 int i, ind;
2851 Eina_Unicode *ptr;
2852
2853 tbase = str = ptr = alloca((off + 1) * sizeof(Eina_Unicode));
2854 ind = 0;
2855 urepch = eina_unicode_utf8_get_next(repch, &ind);
2856 for (i = 0 ; i < off; ptr++, i++)
2857 *ptr = urepch;
2858 *ptr = 0;
2859 }
2860 /* Use the string, just cut the relevant parts */
2861 else
2862 {
2863 str = eina_ustrbuf_string_get(n->unicode) + start;
2864 }
2865
2866 cur_len = off;
2867 }
2868
2869skip:
2870 tbase = str;
2871
2872 /* If there's no parent text node, only create an empty item */
2873 if (!n)
2874 {
2875 ti = _layout_text_item_new(c, fmt);
2876 ti->parent.text_node = NULL;
2877 ti->parent.text_pos = 0;
2878 _layout_text_add_logical_item(c, ti, NULL);
2879
2880 return;
2881 }
2882
2883 while (cur_len > 0)
2884 {
2885 Evas_Font_Instance *script_fi = NULL;
2886 int script_len, tmp_cut;
2887 Evas_Script_Type script;
2888
2889 script_len = cur_len;
2890
2891 tmp_cut = evas_common_language_script_end_of_run_get(str,
2892 c->par->bidi_props, start + str - tbase, script_len);
2893 if (tmp_cut > 0)
2894 {
2895 script_len = tmp_cut;
2896 }
2897 cur_len -= script_len;
2898
2899 script = evas_common_language_script_type_get(str, script_len);
2900
2901
2902 while (script_len > 0)
2903 {
2904 Evas_Font_Instance *cur_fi = NULL;
2905 int run_len = script_len;
2906 ti = _layout_text_item_new(c, fmt);
2907 ti->parent.text_node = n;
2908 ti->parent.text_pos = start + str - tbase;
2909
2910 if (ti->parent.format->font.font)
2911 {
2912 run_len = c->ENFN->font_run_end_get(c->ENDT,
2913 ti->parent.format->font.font, &script_fi, &cur_fi,
2914 script, str, script_len);
2915 }
2916
2917 evas_common_text_props_bidi_set(&ti->text_props,
2918 c->par->bidi_props, ti->parent.text_pos);
2919 evas_common_text_props_script_set(&ti->text_props, script);
2920
2921 if (cur_fi)
2922 {
2923 c->ENFN->font_text_props_info_create(c->ENDT,
2924 cur_fi, str, &ti->text_props, c->par->bidi_props,
2925 ti->parent.text_pos, run_len);
2926 }
2927 str += run_len;
2928 script_len -= run_len;
2929
2930 _layout_text_add_logical_item(c, ti, NULL);
2931 }
2932 }
2933}
2934
2935/**
2936 * @internal
2937 * Add a format item from the format node n and the item item.
2938 *
2939 * @param c the current context- NOT NULL.
2940 * @param n the source format node - not null.
2941 * @param item the format text.
2942 *
2943 * @return the new format item.
2944 */
2945static Evas_Object_Textblock_Format_Item *
2946_layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const char *item, Evas_Object_Textblock_Format *fmt)
2947{
2948 Evas_Object_Textblock_Format_Item *fi;
2949
2950 fi = calloc(1, sizeof(Evas_Object_Textblock_Format_Item));
2951 fi->item = eina_stringshare_add(item);
2952 fi->parent.type = EVAS_TEXTBLOCK_ITEM_FORMAT;
2953 fi->parent.format = fmt;
2954 fi->parent.format->ref++;
2955 c->par->logical_items = eina_list_append(c->par->logical_items, fi);
2956 if (n)
2957 {
2958 fi->parent.text_node = n->text_node;
2959 /* FIXME: make it more efficient */
2960 fi->parent.text_pos = _evas_textblock_node_format_pos_get(n);
2961#ifdef BIDI_SUPPORT
2962 fi->bidi_dir = (evas_bidi_is_rtl_char(
2963 c->par->bidi_props,
2964 0,
2965 fi->parent.text_pos)) ?
2966 EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
2967#else
2968 fi->bidi_dir = EVAS_BIDI_DIRECTION_LTR;
2969#endif
2970 }
2971 return fi;
2972}
2973
2974/**
2975 * @internal
2976 * Should be call after we finish filling a format.
2977 * FIXME: doc.
2978 */
2979static void
2980_format_finalize(Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
2981{
2982 void *of;
2983
2984 of = fmt->font.font;
2985
2986 fmt->font.font = evas_font_load(obj->layer->evas, fmt->font.fdesc,
2987 fmt->font.source, (int)(((double) fmt->font.size) * obj->cur.scale));
2988 if (of) evas_font_free(obj->layer->evas, of);
2989}
2990
2991/**
2992 * @internal
2993 * Returns true if the item is a tab
2994 * @def _IS_TAB(item)
2995 */
2996#define _IS_TAB(item) \
2997 (!strcmp(item, "\t") || !strcmp(item, "\\t"))
2998/**
2999 * @internal
3000 * Returns true if the item is a line spearator, false otherwise
3001 * @def _IS_LINE_SEPARATOR(item)
3002 */
3003#define _IS_LINE_SEPARATOR(item) \
3004 (!strcmp(item, "\n") || !strcmp(item, "\\n"))
3005/**
3006 * @internal
3007 * Returns true if the item is a paragraph separator, false otherwise
3008 * @def _IS_PARAGRAPH_SEPARATOR(item)
3009 */
3010#define _IS_PARAGRAPH_SEPARATOR(o, item) \
3011 (!strcmp(item, "ps") || \
3012 (o->legacy_newline && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */
3013
3014/**
3015 * @internal
3016 * Handles a format by processing a format node. It returns the relevant format
3017 * through _fmt and updates the padding through style_pad_*. If needed,
3018 * it creates a format item.
3019 *
3020 * @param obj the evas object - NOT NULL.
3021 * @param c the current context- NOT NULL.
3022 * @param _fmt the format that holds the result.
3023 * @param n the source format node - not null.
3024 * @param style_pad_l the pad to update.
3025 * @param style_pad_r the pad to update.
3026 * @param style_pad_t the pad to update.
3027 * @param style_pad_b the pad to update.
3028 * @param create_item Create a new format item if true, only process otherwise.
3029 */
3030static void
3031_layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c,
3032 Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n,
3033 int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b,
3034 Eina_Bool create_item)
3035{
3036 Evas_Object_Textblock_Format *fmt = *_fmt;
3037 /* FIXME: comment the algo */
3038
3039 const char *s;
3040 const char *item;
3041 int handled = 0;
3042
3043 s = n->format;
3044 if (!strncmp(s, "+ item ", 7))
3045 {
3046 // one of:
3047 // item size=20x10 href=name
3048 // item relsize=20x10 href=name
3049 // item abssize=20x10 href=name
3050 //
3051 // optional arguments:
3052 // vsize=full
3053 // vsize=ascent
3054 //
3055 // size == item size (modifies line size) - can be multiplied by
3056 // scale factor
3057 // relsize == relative size (height is current font height, width
3058 // modified accordingly keeping aspect)
3059 // abssize == absolute size (modifies line size) - never mulitplied by
3060 // scale factor
3061 // href == name of item - to be found and matched later and used for
3062 // positioning
3063 Evas_Object_Textblock_Format_Item *fi;
3064 int w = 1, h = 1;
3065 int vsize = 0, size = 0;
3066 char *p;
3067
3068 // don't care
3069 //href = strstr(s, " href=");
3070 p = strstr(s, " vsize=");
3071 if (p)
3072 {
3073 p += 7;
3074 if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL;
3075 else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT;
3076 }
3077 p = strstr(s, " size=");
3078 if (p)
3079 {
3080 p += 6;
3081 if (sscanf(p, "%ix%i", &w, &h) == 2)
3082 {
3083 /* this is handled somewhere else because it depends
3084 * on the current scaling factor of the object which
3085 * may change and break because the results of this
3086 * function are cached */
3087 size = SIZE;
3088 }
3089 }
3090 else
3091 {
3092 p = strstr(s, " absize=");
3093 if (p)
3094 {
3095 p += 8;
3096 if (sscanf(p, "%ix%i", &w, &h) == 2)
3097 {
3098 size = SIZE_ABS;
3099 }
3100 }
3101 else
3102 {
3103 p = strstr(s, " relsize=");
3104 if (p)
3105 {
3106 /* this is handled somewhere else because it depends
3107 * on the line it resides in, which is not defined
3108 * at this point and will change anyway, which will
3109 * break because the results of this function are
3110 * cached */
3111 size = SIZE_REL;
3112 }
3113 }
3114 }
3115
3116 if (create_item)
3117 {
3118 fi = _layout_format_item_add(c, n, s, fmt);
3119 fi->vsize = vsize;
3120 fi->size = size;
3121 fi->formatme = 1;
3122 /* For formats items it's usually
3123 the same, we don't handle the
3124 special cases yet. */
3125 fi->parent.w = fi->parent.adv = w;
3126 fi->parent.h = h;
3127 }
3128 /* Not sure if it's the best handling, but will do it for now. */
3129 fmt = _layout_format_push(c, fmt, n);
3130 handled = 1;
3131 }
3132
3133 if (!handled)
3134 {
3135 Eina_Bool push_fmt = EINA_FALSE;
3136 if (s[0] == '+')
3137 {
3138 fmt = _layout_format_push(c, fmt, n);
3139 s++;
3140 push_fmt = EINA_TRUE;
3141 }
3142 else if (s[0] == '-')
3143 {
3144 fmt = _layout_format_pop(c, n->orig_format);
3145 s++;
3146 }
3147 while ((item = _format_parse(&s)))
3148 {
3149 if (_format_is_param(item))
3150 {
3151 /* Only handle it if it's a push format, otherwise,
3152 * don't let overwrite the format stack.. */
3153 if (push_fmt)
3154 {
3155 _layout_format_value_handle(c, fmt, item);
3156 }
3157 }
3158 else if (create_item)
3159 {
3160 if ((_IS_PARAGRAPH_SEPARATOR(c->o, item)) ||
3161 (_IS_LINE_SEPARATOR(item)))
3162 {
3163 Evas_Object_Textblock_Format_Item *fi;
3164
3165 fi = _layout_format_item_add(c, n, item, fmt);
3166
3167 fi->parent.w = fi->parent.adv = 0;
3168 }
3169 else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t")))
3170 {
3171 Evas_Object_Textblock_Format_Item *fi;
3172
3173 fi = _layout_format_item_add(c, n, item, fmt);
3174 fi->parent.w = fi->parent.adv = fmt->tabstops;
3175 fi->formatme = 1;
3176 }
3177 }
3178 }
3179 _format_finalize(c->obj, fmt);
3180 }
3181
3182 {
3183 Evas_Coord pad_l, pad_r, pad_t, pad_b;
3184 pad_l = pad_r = pad_t = pad_b = 0;
3185 evas_text_style_pad_get(fmt->style, &pad_l, &pad_r, &pad_t, &pad_b);
3186 if (pad_l > *style_pad_l) *style_pad_l = pad_l;
3187 if (pad_r > *style_pad_r) *style_pad_r = pad_r;
3188 if (pad_t > *style_pad_t) *style_pad_t = pad_t;
3189 if (pad_b > *style_pad_b) *style_pad_b = pad_b;
3190 }
3191
3192 if (fmt->underline2)
3193 c->have_underline2 = 1;
3194 else if (fmt->underline || fmt->underline_dash)
3195 c->have_underline = 1;
3196 *_fmt = fmt;
3197}
3198
3199static void
3200_layout_update_par(Ctxt *c)
3201{
3202 Evas_Object_Textblock_Paragraph *last_par;
3203 last_par = (Evas_Object_Textblock_Paragraph *)
3204 EINA_INLIST_GET(c->par)->prev;
3205 if (last_par)
3206 {
3207 c->par->y = last_par->y + last_par->h;
3208 }
3209 else
3210 {
3211 c->par->y = 0;
3212 }
3213}
3214
3215/* -1 means no wrap */
3216static int
3217_layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
3218 const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
3219 const char *breaks)
3220{
3221 int wrap;
3222 size_t uwrap;
3223 size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode);
3224 /* Currently not being used, because it doesn't contain relevant
3225 * information */
3226 (void) breaks;
3227
3228 {
3229 wrap = _layout_text_cutoff_get(c, fmt, ti);
3230 if (wrap < 0)
3231 return -1;
3232 uwrap = (size_t) wrap + ti->parent.text_pos;
3233 }
3234
3235
3236 if (uwrap == line_start)
3237 {
3238 uwrap = ti->parent.text_pos +
3239 (size_t) evas_common_text_props_cluster_next(&ti->text_props, wrap);
3240 }
3241 if ((uwrap <= line_start) || (uwrap > len))
3242 return -1;
3243
3244 return uwrap;
3245}
3246
3247/* -1 means no wrap */
3248#ifdef HAVE_LINEBREAK
3249
3250/* Allow break means: if we can break after the current char */
3251#define ALLOW_BREAK(i) \
3252 (breaks[i] <= LINEBREAK_ALLOWBREAK)
3253
3254#else
3255
3256#define ALLOW_BREAK(i) \
3257 (_is_white(str[i]))
3258
3259#endif
3260static int
3261_layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt,
3262 const Evas_Object_Textblock_Text_Item *ti, Eina_Bool mixed_wrap,
3263 size_t line_start, const char *breaks)
3264{
3265 Eina_Bool wrap_after = EINA_FALSE;
3266 size_t wrap;
3267 size_t orig_wrap;
3268 const Eina_Unicode *str = eina_ustrbuf_string_get(
3269 ti->parent.text_node->unicode);
3270 int item_start = ti->parent.text_pos;
3271 size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode);
3272#ifndef HAVE_LINEBREAK
3273 /* Not used without liblinebreak ATM. */
3274 (void) breaks;
3275#endif
3276
3277 {
3278 int swrap = -1;
3279 swrap = _layout_text_cutoff_get(c, fmt, ti);
3280 /* Avoiding too small textblocks to even contain one char.
3281 * FIXME: This can cause breaking inside ligatures. */
3282
3283 if (swrap < 0)
3284 return -1;
3285
3286 orig_wrap = wrap = swrap + item_start;
3287 }
3288
3289 if (wrap > line_start)
3290 {
3291 /* The wrapping point found is the first char of the next string
3292 the rest works on the last char of the previous string.
3293 If it's a whitespace, then it's ok, and no need to go back
3294 because we'll remove it anyway. */
3295 if (!_is_white(str[wrap]))
3296 MOVE_PREV_UNTIL(line_start, wrap);
3297 /* If there's a breakable point inside the text, scan backwards until
3298 * we find it */
3299 while (wrap > line_start)
3300 {
3301 if (ALLOW_BREAK(wrap))
3302 break;
3303 wrap--;
3304 }
3305
3306 if ((wrap > line_start) ||
3307 ((wrap == line_start) && (ALLOW_BREAK(wrap)) && (wrap < len)))
3308 {
3309 /* We found a suitable wrapping point, break here. */
3310 MOVE_NEXT_UNTIL(len, wrap);
3311 return wrap;
3312 }
3313 else
3314 {
3315 if (mixed_wrap)
3316 {
3317 return ((orig_wrap >= line_start) && (orig_wrap < len)) ?
3318 ((int) orig_wrap) : -1;
3319 }
3320 else
3321 {
3322 /* Scan forward to find the next wrapping point */
3323 wrap = orig_wrap;
3324 wrap_after = EINA_TRUE;
3325 }
3326 }
3327 }
3328
3329 /* If we need to find the position after the cutting point */
3330 if ((wrap == line_start) || (wrap_after))
3331 {
3332 if (mixed_wrap)
3333 {
3334 return _layout_get_charwrap(c, fmt, ti,
3335 line_start, breaks);
3336 }
3337 else
3338 {
3339 while (wrap < len)
3340 {
3341 if (ALLOW_BREAK(wrap))
3342 break;
3343 wrap++;
3344 }
3345
3346
3347 if ((wrap < len) && (wrap > line_start))
3348 {
3349 MOVE_NEXT_UNTIL(len, wrap);
3350 return wrap;
3351 }
3352 else
3353 {
3354 return -1;
3355 }
3356 }
3357 }
3358
3359 return -1;
3360}
3361
3362/* -1 means no wrap */
3363static int
3364_layout_get_wordwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
3365 const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
3366 const char *breaks)
3367{
3368 return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_FALSE, line_start,
3369 breaks);
3370}
3371
3372/* -1 means no wrap */
3373static int
3374_layout_get_mixedwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt,
3375 const Evas_Object_Textblock_Text_Item *ti, size_t line_start,
3376 const char *breaks)
3377{
3378 return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_TRUE, line_start,
3379 breaks);
3380}
3381
3382/* Should be moved inside _layout_ellipsis_item_new once we fix the hack in
3383 * textblock render */
3384static const Eina_Unicode _ellip_str[2] = { 0x2026, '\0' };
3385
3386static Evas_Object_Textblock_Text_Item *
3387_layout_ellipsis_item_new(Ctxt *c, const Evas_Object_Textblock_Item *cur_it)
3388{
3389 Evas_Object_Textblock_Text_Item *ellip_ti;
3390 Evas_Script_Type script;
3391 Evas_Font_Instance *script_fi = NULL, *cur_fi;
3392 size_t len = 1; /* The length of _ellip_str */
3393
3394 /* We can free it here, cause there's only one ellipsis item per tb. */
3395 if (c->o->ellip_ti) _item_free(c->obj, NULL, _ITEM(c->o->ellip_ti));
3396 c->o->ellip_ti = ellip_ti = _layout_text_item_new(c,
3397 eina_list_data_get(eina_list_last(c->format_stack)));
3398 ellip_ti->parent.text_node = cur_it->text_node;
3399 ellip_ti->parent.text_pos = cur_it->text_pos;
3400 script = evas_common_language_script_type_get(_ellip_str, len);
3401
3402 evas_common_text_props_bidi_set(&ellip_ti->text_props,
3403 c->par->bidi_props, ellip_ti->parent.text_pos);
3404 evas_common_text_props_script_set (&ellip_ti->text_props, script);
3405
3406 if (ellip_ti->parent.format->font.font)
3407 {
3408 /* It's only 1 char anyway, we don't need the run end. */
3409 (void) c->ENFN->font_run_end_get(c->ENDT,
3410 ellip_ti->parent.format->font.font, &script_fi, &cur_fi,
3411 script, _ellip_str, len);
3412
3413 c->ENFN->font_text_props_info_create(c->ENDT,
3414 cur_fi, _ellip_str, &ellip_ti->text_props,
3415 c->par->bidi_props, ellip_ti->parent.text_pos, len);
3416 }
3417
3418 _text_item_update_sizes(c, ellip_ti);
3419
3420 if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
3421 {
3422 ellip_ti->parent.text_pos += _ITEM_TEXT(cur_it)->text_props.text_len
3423 - 1;
3424 }
3425 else
3426 {
3427 ellip_ti->parent.text_pos++;
3428 }
3429
3430 return ellip_ti;
3431}
3432
3433/**
3434 * @internel
3435 * Handle ellipsis
3436 */
3437static inline void
3438_layout_handle_ellipsis(Ctxt *c, Evas_Object_Textblock_Item *it, Eina_List *i)
3439{
3440 Evas_Object_Textblock_Text_Item *ellip_ti;
3441 Evas_Object_Textblock_Item *last_it;
3442 Evas_Coord save_cx;
3443 int wrap;
3444 ellip_ti = _layout_ellipsis_item_new(c, it);
3445 last_it = it;
3446
3447 save_cx = c->x;
3448 c->w -= ellip_ti->parent.w;
3449
3450 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
3451 {
3452 Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
3453
3454 wrap = _layout_text_cutoff_get(c, last_it->format, ti);
3455 if ((wrap > 0) && !IS_AT_END(ti, (size_t) wrap))
3456 {
3457 _layout_item_text_split_strip_white(c, ti, i, wrap);
3458 }
3459 else if ((wrap == 0) && (c->ln->items))
3460 {
3461 last_it = _ITEM(EINA_INLIST_GET(c->ln->items)->last);
3462 }
3463 }
3464 else if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
3465 {
3466 /* We don't want to add this format item. */
3467 last_it = NULL;
3468 }
3469
3470 c->x = save_cx;
3471 c->w += ellip_ti->parent.w;
3472 /* If we should add this item, do it */
3473 if (last_it == it)
3474 {
3475 c->ln->items = (Evas_Object_Textblock_Item *)
3476 eina_inlist_append(EINA_INLIST_GET(c->ln->items),
3477 EINA_INLIST_GET(it));
3478 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
3479 {
3480 Evas_Object_Textblock_Format_Item *fi;
3481 fi = _ITEM_FORMAT(it);
3482 fi->y = c->y;
3483 }
3484 }
3485 c->ln->items = (Evas_Object_Textblock_Item *)
3486 eina_inlist_append(EINA_INLIST_GET(c->ln->items),
3487 EINA_INLIST_GET(_ITEM(ellip_ti)));
3488 _layout_line_finalize(c, ellip_ti->parent.format);
3489}
3490
3491#ifdef BIDI_SUPPORT
3492static void
3493_layout_paragraph_reorder_lines(Evas_Object_Textblock_Paragraph *par)
3494{
3495 Evas_Object_Textblock_Line *ln;
3496
3497 EINA_INLIST_FOREACH(EINA_INLIST_GET(par->lines), ln)
3498 {
3499 _layout_line_reorder(ln);
3500 }
3501}
3502#endif
3503
3504static void
3505_layout_paragraph_render(Evas_Object_Textblock *o,
3506 Evas_Object_Textblock_Paragraph *par)
3507{
3508 if (par->rendered)
3509 return;
3510 par->rendered = EINA_TRUE;
3511
3512#ifdef BIDI_SUPPORT
3513 if (par->is_bidi)
3514 {
3515 _layout_update_bidi_props(o, par);
3516 _layout_paragraph_reorder_lines(par);
3517 /* Clear the bidi props because we don't need them anymore. */
3518 if (par->bidi_props)
3519 {
3520 evas_bidi_paragraph_props_unref(par->bidi_props);
3521 par->bidi_props = NULL;
3522 }
3523 }
3524#endif
3525}
3526
3527/* 0 means go ahead, 1 means break without an error, 2 means
3528 * break with an error, should probably clean this a bit (enum/macro)
3529 * FIXME ^ */
3530static int
3531_layout_par(Ctxt *c)
3532{
3533 Evas_Object_Textblock_Item *it;
3534 Eina_List *i;
3535 int ret = 0;
3536 int wrap = -1;
3537 char *line_breaks = NULL;
3538
3539 if (!c->par->logical_items)
3540 return 2;
3541
3542 /* We want to show it. */
3543 c->par->visible = 1;
3544
3545 /* Check if we need to skip this paragraph because it's already layouted
3546 * correctly, and mark handled nodes as dirty. */
3547 c->par->line_no = c->line_no;
3548
3549 if (c->par->text_node)
3550 {
3551 /* Skip this paragraph if width is the same, there is no ellipsis
3552 * and we aren't just calculating. */
3553 if (!c->par->text_node->is_new && !c->par->text_node->dirty &&
3554 !c->width_changed && c->par->lines &&
3555 !c->o->have_ellipsis)
3556 {
3557 Evas_Object_Textblock_Line *ln;
3558 /* Update c->line_no */
3559 ln = (Evas_Object_Textblock_Line *)
3560 EINA_INLIST_GET(c->par->lines)->last;
3561 if (ln)
3562 c->line_no = c->par->line_no + ln->line_no + 1;
3563 return 0;
3564 }
3565 c->par->text_node->dirty = EINA_FALSE;
3566 c->par->text_node->is_new = EINA_FALSE;
3567 c->par->rendered = EINA_FALSE;
3568
3569 /* Merge back and clear the paragraph */
3570 {
3571 Eina_List *itr, *itr_next;
3572 Evas_Object_Textblock_Item *ititr, *prev_it = NULL;
3573 _paragraph_clear(c->obj, c->par);
3574 EINA_LIST_FOREACH_SAFE(c->par->logical_items, itr, itr_next, ititr)
3575 {
3576 if (ititr->merge && prev_it &&
3577 (prev_it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
3578 (ititr->type == EVAS_TEXTBLOCK_ITEM_TEXT))
3579 {
3580 _layout_item_merge_and_free(c, _ITEM_TEXT(prev_it),
3581 _ITEM_TEXT(ititr));
3582 c->par->logical_items =
3583 eina_list_remove_list(c->par->logical_items, itr);
3584 }
3585 else
3586 {
3587 prev_it = ititr;
3588 }
3589 }
3590 }
3591 }
3592
3593 c->y = c->par->y;
3594
3595 it = _ITEM(eina_list_data_get(c->par->logical_items));
3596 _layout_line_new(c, it->format);
3597 /* We walk on our own because we want to be able to add items from
3598 * inside the list and then walk them on the next iteration. */
3599 for (i = c->par->logical_items ; i ; )
3600 {
3601 int adv_line = 0;
3602 int redo_item = 0;
3603 it = _ITEM(eina_list_data_get(i));
3604 /* Skip visually deleted items */
3605 if (it->visually_deleted)
3606 {
3607 i = eina_list_next(i);
3608 continue;
3609 }
3610
3611 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
3612 {
3613 Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
3614 _layout_format_ascent_descent_adjust(c->obj, &c->maxascent,
3615 &c->maxdescent, ti->parent.format);
3616 }
3617 else
3618 {
3619 Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
3620 if (fi->formatme)
3621 {
3622 /* If there are no text items yet, calc ascent/descent
3623 * according to the current format. */
3624 if (c->maxascent + c->maxdescent == 0)
3625 _layout_format_ascent_descent_adjust(c->obj, &c->maxascent,
3626 &c->maxdescent, it->format);
3627
3628 _layout_calculate_format_item_size(c->obj, fi, &c->maxascent,
3629 &c->maxdescent, &fi->y, &fi->parent.w, &fi->parent.h);
3630 fi->parent.adv = fi->parent.w;
3631 }
3632 }
3633
3634
3635 /* Check if we need to wrap, i.e the text is bigger than the width,
3636 or we already found a wrap point. */
3637 if ((c->w >= 0) &&
3638 (((c->x + it->adv) >
3639 (c->w - c->o->style_pad.l - c->o->style_pad.r -
3640 c->marginl - c->marginr)) || (wrap > 0)))
3641 {
3642 /* Handle ellipsis here. If we don't have more width left
3643 * and no height left, or no more width left and no wrapping. */
3644 if ((it->format->ellipsis == 1.0) && (c->h >= 0) &&
3645 ((2 * it->h + c->y >
3646 c->h - c->o->style_pad.t - c->o->style_pad.b) ||
3647 (!it->format->wrap_word && !it->format->wrap_char &&
3648 !it->format->wrap_mixed)))
3649 {
3650 _layout_handle_ellipsis(c, it, i);
3651 ret = 1;
3652 goto end;
3653 }
3654 /* If we want to wrap and it's worth checking for wrapping
3655 * (i.e there's actually text). */
3656 else if ((it->format->wrap_word || it->format->wrap_char ||
3657 it->format->wrap_mixed) && it->text_node)
3658 {
3659 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
3660 {
3661 /* Don't wrap if it's the only item */
3662 if (c->ln->items)
3663 {
3664 /*FIXME: I should handle format correctly,
3665 i.e verify we are allowed to break here */
3666 _layout_line_advance(c, it->format);
3667 wrap = -1;
3668 }
3669 }
3670 else
3671 {
3672 Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
3673 size_t line_start;
3674
3675#ifdef HAVE_LINEBREAK
3676 /* If we haven't calculated the linebreaks yet,
3677 * do */
3678 if (!line_breaks)
3679 {
3680 /* Only relevant in those cases */
3681 if (it->format->wrap_word || it->format->wrap_mixed)
3682 {
3683 const char *lang;
3684 lang = (it->format->font.fdesc) ?
3685 it->format->font.fdesc->lang : "";
3686 size_t len =
3687 eina_ustrbuf_length_get(
3688 it->text_node->unicode);
3689 line_breaks = malloc(len);
3690 set_linebreaks_utf32((const utf32_t *)
3691 eina_ustrbuf_string_get(
3692 it->text_node->unicode),
3693 len, lang, line_breaks);
3694 }
3695 }
3696#endif
3697 if (c->ln->items)
3698 line_start = c->ln->items->text_pos;
3699 else
3700 line_start = ti->parent.text_pos;
3701
3702 adv_line = 1;
3703 /* If we don't already have a wrap point from before */
3704 if (wrap < 0)
3705 {
3706 if (it->format->wrap_word)
3707 wrap = _layout_get_wordwrap(c, it->format, ti,
3708 line_start, line_breaks);
3709 else if (it->format->wrap_char)
3710 wrap = _layout_get_charwrap(c, it->format, ti,
3711 line_start, line_breaks);
3712 else if (it->format->wrap_mixed)
3713 wrap = _layout_get_mixedwrap(c, it->format, ti,
3714 line_start, line_breaks);
3715 else
3716 wrap = -1;
3717 }
3718
3719 /* If it's before the item, rollback and apply.
3720 if it's in the item, cut.
3721 If it's after the item, delay the cut */
3722 if (wrap > 0)
3723 {
3724 size_t uwrap = (size_t) wrap;
3725 if (uwrap < ti->parent.text_pos)
3726 {
3727 /* Rollback latest additions, and cut that
3728 item */
3729 i = eina_list_prev(i);
3730 it = eina_list_data_get(i);
3731 while (uwrap < it->text_pos)
3732 {
3733 c->ln->items = _ITEM(
3734 eina_inlist_remove(
3735 EINA_INLIST_GET(c->ln->items),
3736 EINA_INLIST_GET(it)));
3737 i = eina_list_prev(i);
3738 it = eina_list_data_get(i);
3739 }
3740 c->x = it->x;
3741 c->ln->items = _ITEM(
3742 eina_inlist_remove(
3743 EINA_INLIST_GET(c->ln->items),
3744 EINA_INLIST_GET(it)));
3745 continue;
3746 }
3747 /* If it points to the end, it means the previous
3748 * char is a whitespace we should remove, so this
3749 * is a wanted cutting point. */
3750 else if (uwrap > ti->parent.text_pos +
3751 ti->text_props.text_len)
3752 wrap = -1; /* Delay the cut in a smart way
3753 i.e use the item_pos as the line_start, because
3754 there's already no cut before*/
3755 else
3756 wrap -= ti->parent.text_pos; /* Cut here */
3757 }
3758
3759 if (wrap > 0)
3760 {
3761 _layout_item_text_split_strip_white(c, ti, i, wrap);
3762 }
3763 else if (wrap == 0)
3764 {
3765 /* Should wrap before the item */
3766 adv_line = 0;
3767 redo_item = 1;
3768 _layout_line_advance(c, it->format);
3769 }
3770 /* Reset wrap */
3771 wrap = -1;
3772 }
3773 }
3774 }
3775
3776 if (!redo_item && !it->visually_deleted)
3777 {
3778 c->ln->items = (Evas_Object_Textblock_Item *)
3779 eina_inlist_append(EINA_INLIST_GET(c->ln->items),
3780 EINA_INLIST_GET(it));
3781 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
3782 {
3783 Evas_Object_Textblock_Format_Item *fi;
3784 fi = _ITEM_FORMAT(it);
3785 fi->y = c->y;
3786 /* If it's a newline, and we are not in newline compat
3787 * mode, or we are in newline compat mode, and this is
3788 * not used as a paragraph separator, advance */
3789 if (fi->item && _IS_LINE_SEPARATOR(fi->item) &&
3790 (!c->o->legacy_newline ||
3791 eina_list_next(i)))
3792 {
3793 adv_line = 1;
3794 }
3795 }
3796 c->x += it->adv;
3797 i = eina_list_next(i);
3798 }
3799 if (adv_line)
3800 {
3801 /* Each line is according to the first item in it, and here
3802 * i is already the next item (or the current if we redo it) */
3803 if (i)
3804 {
3805 it = _ITEM(eina_list_data_get(i));
3806 }
3807 _layout_line_advance(c, it->format);
3808 }
3809 }
3810 if (c->ln->items)
3811 {
3812 /* Here 'it' is the last format used */
3813 _layout_line_finalize(c, it->format);
3814 }
3815
3816end:
3817#ifdef HAVE_LINEBREAK
3818 if (line_breaks)
3819 free(line_breaks);
3820#endif
3821
3822 return ret;
3823}
3824
3825/**
3826 * @internal
3827 * Invalidate text nodes according to format changes
3828 * This goes through all the new format changes and marks the text nodes
3829 * that should be invalidated because of format changes.
3830 *
3831 * @param c the working context.
3832 */
3833static inline void
3834_format_changes_invalidate_text_nodes(Ctxt *c)
3835{
3836 Evas_Object_Textblock_Node_Format *fnode = c->o->format_nodes;
3837 Evas_Object_Textblock_Node_Text *start_n = NULL;
3838 Eina_List *fstack = NULL;
3839 int balance = 0;
3840 while (fnode)
3841 {
3842 if (fnode->is_new)
3843 {
3844 const char *fstr = fnode->orig_format;
3845 /* balance < 0 means we gave up and everything should be
3846 * invalidated */
3847 if (*fstr == '+')
3848 {
3849 balance++;
3850 if (!fstack)
3851 start_n = fnode->text_node;
3852 fstack = eina_list_prepend(fstack, fnode);
3853 }
3854 else if (*fstr == '-')
3855 {
3856 size_t fstr_len;
3857 /* Skip the '-' */
3858 fstr++;
3859 fstr_len = strlen(fstr);
3860 /* Generic popper, just pop */
3861 if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0])
3862 {
3863 fstack = eina_list_remove_list(fstack, fstack);
3864 balance--;
3865 }
3866 /* Find the matching format and pop it, if the matching format
3867 * is out format, i.e the last one, pop and break. */
3868 else
3869 {
3870 Eina_List *i;
3871 Evas_Object_Textblock_Node_Format *fnode2;
3872 EINA_LIST_FOREACH(fstack, i, fnode2)
3873 {
3874 if (_FORMAT_IS_CLOSER_OF(
3875 fnode2->orig_format, fstr, fstr_len))
3876 {
3877 fstack = eina_list_remove_list(fstack, i);
3878 break;
3879 }
3880 }
3881 balance--;
3882 }
3883
3884 if (!fstack)
3885 {
3886 Evas_Object_Textblock_Node_Text *f_tnode =
3887 fnode->text_node;
3888 while (start_n)
3889 {
3890 start_n->dirty = EINA_TRUE;
3891 if (start_n == f_tnode)
3892 break;
3893 start_n =
3894 _NODE_TEXT(EINA_INLIST_GET(start_n)->next);
3895 }
3896 start_n = NULL;
3897 }
3898 }
3899 else if (!fnode->visible)
3900 balance = -1;
3901
3902 if (balance < 0)
3903 {
3904 /* if we don't already have a starting point, use the
3905 * current paragraph. */
3906 if (!start_n)
3907 start_n = fnode->text_node;
3908 break;
3909 }
3910 }
3911 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
3912 }
3913
3914 if (balance != 0)
3915 {
3916 while (start_n)
3917 {
3918 start_n->dirty = EINA_TRUE;
3919 start_n = _NODE_TEXT(EINA_INLIST_GET(start_n)->next);
3920 }
3921 }
3922}
3923
3924
3925/** FIXME: Document */
3926static void
3927_layout_pre(Ctxt *c, int *style_pad_l, int *style_pad_r, int *style_pad_t,
3928 int *style_pad_b)
3929{
3930 Evas_Object *obj = c->obj;
3931 Evas_Object_Textblock *o = c->o;
3932 /* Mark text nodes as dirty if format have changed. */
3933 if (c->o->format_changed)
3934 {
3935 _format_changes_invalidate_text_nodes(c);
3936 }
3937
3938 if (o->content_changed)
3939 {
3940 Evas_Object_Textblock_Node_Text *n;
3941 c->o->have_ellipsis = 0;
3942 c->par = c->paragraphs = o->paragraphs;
3943 /* Go through all the text nodes to create the logical layout */
3944 EINA_INLIST_FOREACH(c->o->text_nodes, n)
3945 {
3946 Evas_Object_Textblock_Node_Format *fnode;
3947 size_t start;
3948 int off;
3949
3950 /* If it's not a new paragraph, either update it or skip it.
3951 * Remove all the paragraphs that were deleted */
3952 if (!n->is_new)
3953 {
3954 /* Remove all the deleted paragraphs at this point */
3955 while (c->par->text_node != n)
3956 {
3957 Evas_Object_Textblock_Paragraph *tmp_par =
3958 (Evas_Object_Textblock_Paragraph *)
3959 EINA_INLIST_GET(c->par)->next;
3960
3961 c->paragraphs = (Evas_Object_Textblock_Paragraph *)
3962 eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
3963 EINA_INLIST_GET(c->par));
3964 _paragraph_free(obj, c->par);
3965
3966 c->par = tmp_par;
3967 }
3968
3969 /* If it's dirty, remove and recreate, if it's clean,
3970 * skip to the next. */
3971 if (n->dirty)
3972 {
3973 Evas_Object_Textblock_Paragraph *prev_par = c->par;
3974
3975 _layout_paragraph_new(c, n, EINA_TRUE);
3976
3977 c->paragraphs = (Evas_Object_Textblock_Paragraph *)
3978 eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
3979 EINA_INLIST_GET(prev_par));
3980 _paragraph_free(obj, prev_par);
3981 }
3982 else
3983 {
3984 c->par = (Evas_Object_Textblock_Paragraph *)
3985 EINA_INLIST_GET(c->par)->next;
3986
3987 /* Update the format stack according to the node's
3988 * formats */
3989 fnode = n->format_node;
3990 while (fnode && (fnode->text_node == n))
3991 {
3992 /* Only do this if this actually changes format */
3993 if (fnode->format_change)
3994 _layout_do_format(obj, c, &c->fmt, fnode,
3995 style_pad_l, style_pad_r,
3996 style_pad_t, style_pad_b, EINA_FALSE);
3997 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
3998 }
3999 continue;
4000 }
4001 }
4002 else
4003 {
4004 /* If it's a new paragraph, just add it. */
4005 _layout_paragraph_new(c, n, EINA_FALSE);
4006 }
4007
4008#ifdef BIDI_SUPPORT
4009 _layout_update_bidi_props(c->o, c->par);
4010#endif
4011
4012 /* For each text node to thorugh all of it's format nodes
4013 * append text from the start to the offset of the next format
4014 * using the last format got. if needed it also creates format
4015 * items this is the core algorithm of the layout mechanism.
4016 * Skip the unicode replacement chars when there are because
4017 * we don't want to print them. */
4018 fnode = n->format_node;
4019 start = off = 0;
4020 while (fnode && (fnode->text_node == n))
4021 {
4022 off += fnode->offset;
4023 /* No need to skip on the first run, or a non-visible one */
4024 _layout_text_append(c, c->fmt, n, start, off, o->repch);
4025 _layout_do_format(obj, c, &c->fmt, fnode, style_pad_l,
4026 style_pad_r, style_pad_t, style_pad_b, EINA_TRUE);
4027 if ((c->have_underline2) || (c->have_underline))
4028 {
4029 if (*style_pad_b < c->underline_extend)
4030 *style_pad_b = c->underline_extend;
4031 c->have_underline = 0;
4032 c->have_underline2 = 0;
4033 c->underline_extend = 0;
4034 }
4035 start += off;
4036 if (fnode->visible)
4037 {
4038 off = -1;
4039 start++;
4040 }
4041 else
4042 {
4043 off = 0;
4044 }
4045 fnode->is_new = EINA_FALSE;
4046 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
4047 }
4048 _layout_text_append(c, c->fmt, n, start, -1, o->repch);
4049#ifdef BIDI_SUPPORT
4050 /* Clear the bidi props because we don't need them anymore. */
4051 if (c->par->bidi_props)
4052 {
4053 evas_bidi_paragraph_props_unref(c->par->bidi_props);
4054 c->par->bidi_props = NULL;
4055 }
4056#endif
4057 c->par = (Evas_Object_Textblock_Paragraph *)
4058 EINA_INLIST_GET(c->par)->next;
4059 }
4060
4061 /* Delete the rest of the layout paragraphs */
4062 while (c->par)
4063 {
4064 Evas_Object_Textblock_Paragraph *tmp_par =
4065 (Evas_Object_Textblock_Paragraph *)
4066 EINA_INLIST_GET(c->par)->next;
4067
4068 c->paragraphs = (Evas_Object_Textblock_Paragraph *)
4069 eina_inlist_remove(EINA_INLIST_GET(c->paragraphs),
4070 EINA_INLIST_GET(c->par));
4071 _paragraph_free(obj, c->par);
4072
4073 c->par = tmp_par;
4074 }
4075 o->paragraphs = c->paragraphs;
4076 c->par = NULL;
4077 }
4078
4079}
4080
4081/**
4082 * @internal
4083 * Create the layout from the nodes.
4084 *
4085 * @param obj the evas object - NOT NULL.
4086 * @param calc_only true if should only calc sizes false if should also create the layout.. It assumes native size is being calculated, doesn't support formatted size atm.
4087 * @param w the object's w, -1 means no wrapping (i.e infinite size)
4088 * @param h the object's h, -1 means inifinte size.
4089 * @param w_ret the object's calculated w.
4090 * @param h_ret the object's calculated h.
4091 */
4092static void
4093_layout(const Evas_Object *obj, int w, int h, int *w_ret, int *h_ret)
4094{
4095 Evas_Object_Textblock *o;
4096 Ctxt ctxt, *c;
4097 int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0;
4098
4099 /* setup context */
4100 o = (Evas_Object_Textblock *)(obj->object_data);
4101 c = &ctxt;
4102 c->obj = (Evas_Object *)obj;
4103 c->o = o;
4104 c->paragraphs = c->par = NULL;
4105 c->format_stack = NULL;
4106 c->fmt = NULL;
4107 c->x = c->y = 0;
4108 c->w = w;
4109 c->h = h;
4110 c->wmax = c->hmax = 0;
4111 c->maxascent = c->maxdescent = 0;
4112 c->marginl = c->marginr = 0;
4113 c->have_underline = 0;
4114 c->have_underline2 = 0;
4115 c->underline_extend = 0;
4116 c->line_no = 0;
4117 c->align = 0.0;
4118 c->align_auto = EINA_TRUE;
4119 c->ln = NULL;
4120 c->width_changed = (obj->cur.geometry.w != o->last_w);
4121
4122 /* Start of logical layout creation */
4123 /* setup default base style */
4124 if ((c->o->style) && (c->o->style->default_tag))
4125 {
4126 c->fmt = _layout_format_push(c, NULL, NULL);
4127 _format_fill(c->obj, c->fmt, c->o->style->default_tag);
4128 _format_finalize(c->obj, c->fmt);
4129 }
4130 if (!c->fmt)
4131 {
4132 if (w_ret) *w_ret = 0;
4133 if (h_ret) *h_ret = 0;
4134 return;
4135 }
4136
4137 _layout_pre(c, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b);
4138 c->paragraphs = o->paragraphs;
4139
4140 /* If there are no paragraphs, create the minimum needed,
4141 * if the last paragraph has no lines/text, create that as well */
4142 if (!c->paragraphs)
4143 {
4144 _layout_paragraph_new(c, NULL, EINA_TRUE);
4145 o->paragraphs = c->paragraphs;
4146 }
4147 c->par = (Evas_Object_Textblock_Paragraph *)
4148 EINA_INLIST_GET(c->paragraphs)->last;
4149 if (!c->par->logical_items)
4150 {
4151 Evas_Object_Textblock_Text_Item *ti;
4152 ti = _layout_text_item_new(c, c->fmt);
4153 ti->parent.text_node = c->par->text_node;
4154 ti->parent.text_pos = 0;
4155 _layout_text_add_logical_item(c, ti, NULL);
4156 }
4157
4158 /* End of logical layout creation */
4159
4160 /* Start of visual layout creation */
4161 {
4162 Evas_Object_Textblock_Paragraph *last_vis_par = NULL;
4163 int par_index_step = o->num_paragraphs / TEXTBLOCK_PAR_INDEX_SIZE;
4164 int par_count = 1; /* Force it to take the first one */
4165 int par_index_pos = 0;
4166
4167 if (par_index_step == 0) par_index_step = 1;
4168
4169 /* Clear all of the index */
4170 memset(o->par_index, 0, sizeof(o->par_index));
4171
4172 EINA_INLIST_FOREACH(c->paragraphs, c->par)
4173 {
4174 _layout_update_par(c);
4175
4176 /* Break if we should stop here. */
4177 if (_layout_par(c))
4178 {
4179 last_vis_par = c->par;
4180 break;
4181 }
4182
4183 if ((par_index_pos < TEXTBLOCK_PAR_INDEX_SIZE) && (--par_count == 0))
4184 {
4185 par_count = par_index_step;
4186
4187 o->par_index[par_index_pos++] = c->par;
4188 }
4189 }
4190
4191 /* Mark all the rest of the paragraphs as invisible */
4192 if (c->par)
4193 {
4194 c->par = (Evas_Object_Textblock_Paragraph *)
4195 EINA_INLIST_GET(c->par)->next;
4196 while (c->par)
4197 {
4198 c->par->visible = 0;
4199 c->par = (Evas_Object_Textblock_Paragraph *)
4200 EINA_INLIST_GET(c->par)->next;
4201 }
4202 }
4203
4204 /* Get the last visible paragraph in the layout */
4205 if (!last_vis_par && c->paragraphs)
4206 last_vis_par = (Evas_Object_Textblock_Paragraph *)
4207 EINA_INLIST_GET(c->paragraphs)->last;
4208
4209 if (last_vis_par)
4210 c->hmax = last_vis_par->y + last_vis_par->h;
4211 }
4212
4213 /* Clean the rest of the format stack */
4214 while (c->format_stack)
4215 {
4216 c->fmt = c->format_stack->data;
4217 c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack);
4218 _format_unref_free(c->obj, c->fmt);
4219 }
4220
4221 if (w_ret) *w_ret = c->wmax;
4222 if (h_ret) *h_ret = c->hmax;
4223
4224 /* Vertically align the textblock */
4225 if ((o->valign > 0.0) && (c->h > c->hmax))
4226 {
4227 Evas_Coord adjustment = (c->h - c->hmax) * o->valign;
4228 Evas_Object_Textblock_Paragraph *par;
4229 EINA_INLIST_FOREACH(c->paragraphs, par)
4230 {
4231 par->y += adjustment;
4232 }
4233 }
4234
4235 if ((o->style_pad.l != style_pad_l) || (o->style_pad.r != style_pad_r) ||
4236 (o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b))
4237 {
4238 o->style_pad.l = style_pad_l;
4239 o->style_pad.r = style_pad_r;
4240 o->style_pad.t = style_pad_t;
4241 o->style_pad.b = style_pad_b;
4242 _paragraphs_clear(obj, c->paragraphs);
4243 _layout(obj, w, h, w_ret, h_ret);
4244 }
4245}
4246
4247/*
4248 * @internal
4249 * Relayout the object according to current object size.
4250 *
4251 * @param obj the evas object - NOT NULL.
4252 */
4253static void
4254_relayout(const Evas_Object *obj)
4255{
4256 Evas_Object_Textblock *o;
4257
4258 o = (Evas_Object_Textblock *)(obj->object_data);
4259 _layout(obj, obj->cur.geometry.w, obj->cur.geometry.h,
4260 &o->formatted.w, &o->formatted.h);
4261 o->formatted.valid = 1;
4262 o->last_w = obj->cur.geometry.w;
4263 o->last_h = obj->cur.geometry.h;
4264 o->changed = 0;
4265 o->content_changed = 0;
4266 o->format_changed = EINA_FALSE;
4267 o->redraw = 1;
4268}
4269
4270/**
4271 * @internal
4272 * Find the layout item and line that match the text node and position passed.
4273 *
4274 * @param obj the evas object - NOT NULL.
4275 * @param n the text node - Not null.
4276 * @param pos the position to look for - valid.
4277 * @param[out] lnr the line found - not null.
4278 * @param[out] tir the item found - not null.
4279 * @see _find_layout_format_item_line_match()
4280 */
4281static void
4282_find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Text *n, int pos, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
4283{
4284 Evas_Object_Textblock_Paragraph *found_par;
4285 Evas_Object_Textblock_Line *ln;
4286 Evas_Object_Textblock *o;
4287
4288 o = (Evas_Object_Textblock *)(obj->object_data);
4289 if (!o->formatted.valid) _relayout(obj);
4290
4291 found_par = n->par;
4292 if (found_par)
4293 {
4294 _layout_paragraph_render(o, found_par);
4295 EINA_INLIST_FOREACH(found_par->lines, ln)
4296 {
4297 Evas_Object_Textblock_Item *it;
4298
4299 EINA_INLIST_FOREACH(ln->items, it)
4300 {
4301 /* FIXME: p should be size_t, same goes for pos */
4302 int p = (int) it->text_pos;
4303
4304 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
4305 {
4306 Evas_Object_Textblock_Text_Item *ti =
4307 _ITEM_TEXT(it);
4308
4309 p += (int) ti->text_props.text_len;
4310 }
4311 else
4312 {
4313 p++;
4314 }
4315
4316 if (((pos >= (int) it->text_pos) && (pos < p)))
4317 {
4318 *lnr = ln;
4319 *itr = it;
4320 return;
4321 }
4322 else if (p == pos)
4323 {
4324 *lnr = ln;
4325 *itr = it;
4326 }
4327 }
4328 }
4329 }
4330}
4331
4332/**
4333 * @internal
4334 * Return the line number 'line'.
4335 *
4336 * @param obj the evas object - NOT NULL.
4337 * @param line the line to find
4338 * @return the line of line number or NULL if no line found.
4339 */
4340static Evas_Object_Textblock_Line *
4341_find_layout_line_num(const Evas_Object *obj, int line)
4342{
4343 Evas_Object_Textblock_Paragraph *par;
4344 Evas_Object_Textblock_Line *ln;
4345 Evas_Object_Textblock *o;
4346
4347 o = (Evas_Object_Textblock *)(obj->object_data);
4348
4349 par = _layout_find_paragraph_by_line_no(o, line);
4350 if (par)
4351 {
4352 _layout_paragraph_render(o, par);
4353 EINA_INLIST_FOREACH(par->lines, ln)
4354 {
4355 if (par->line_no + ln->line_no == line) return ln;
4356 }
4357 }
4358 return NULL;
4359}
4360
4361EAPI Evas_Object *
4362evas_object_textblock_add(Evas *e)
4363{
4364 Evas_Object *obj;
4365
4366 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
4367 return NULL;
4368 MAGIC_CHECK_END();
4369 obj = evas_object_new(e);
4370 evas_object_textblock_init(obj);
4371 evas_object_inject(obj, e);
4372 return obj;
4373}
4374
4375EAPI Evas_Textblock_Style *
4376evas_textblock_style_new(void)
4377{
4378 Evas_Textblock_Style *ts;
4379
4380 ts = calloc(1, sizeof(Evas_Textblock_Style));
4381 return ts;
4382}
4383
4384EAPI void
4385evas_textblock_style_free(Evas_Textblock_Style *ts)
4386{
4387 if (!ts) return;
4388 if (ts->objects)
4389 {
4390 ts->delete_me = 1;
4391 return;
4392 }
4393 _style_clear(ts);
4394 free(ts);
4395}
4396
4397EAPI void
4398evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text)
4399{
4400 Eina_List *l;
4401 Evas_Object *obj;
4402
4403 if (!ts) return;
4404 /* If the style wasn't really changed, abort. */
4405 if ((!ts->style_text && !text) ||
4406 (ts->style_text && text && !strcmp(text, ts->style_text)))
4407 return;
4408
4409 EINA_LIST_FOREACH(ts->objects, l, obj)
4410 {
4411 Evas_Object_Textblock *o;
4412
4413 o = (Evas_Object_Textblock *)(obj->object_data);
4414 _evas_textblock_invalidate_all(o);
4415 _evas_textblock_changed(o, obj);
4416 }
4417
4418 _style_replace(ts, text);
4419
4420 if (ts->style_text)
4421 {
4422 // format MUST be KEY='VALUE'[KEY='VALUE']...
4423 const char *p;
4424 const char *key_start, *key_stop, *val_start, *val_stop;
4425
4426 key_start = key_stop = val_start = val_stop = NULL;
4427 p = ts->style_text;
4428 while (*p)
4429 {
4430 if (!key_start)
4431 {
4432 if (!isspace(*p))
4433 key_start = p;
4434 }
4435 else if (!key_stop)
4436 {
4437 if ((*p == '=') || (isspace(*p)))
4438 key_stop = p;
4439 }
4440 else if (!val_start)
4441 {
4442 if (((*p) == '\'') && (*(p + 1)))
4443 val_start = p + 1;
4444 }
4445 else if (!val_stop)
4446 {
4447 if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\'))
4448 val_stop = p;
4449 }
4450 if ((key_start) && (key_stop) && (val_start) && (val_stop))
4451 {
4452 char *tags, *replaces;
4453 Evas_Object_Style_Tag *tag;
4454 size_t tag_len = key_stop - key_start;
4455 size_t replace_len = val_stop - val_start;
4456
4457 tags = malloc(tag_len + 1);
4458 if (tags)
4459 {
4460 memcpy(tags, key_start, tag_len);
4461 tags[tag_len] = 0;
4462 }
4463
4464 replaces = malloc(replace_len + 1);
4465 if (replaces)
4466 {
4467 memcpy(replaces, val_start, replace_len);
4468 replaces[replace_len] = 0;
4469 }
4470 if ((tags) && (replaces))
4471 {
4472 if (!strcmp(tags, "DEFAULT"))
4473 {
4474 ts->default_tag = replaces;
4475 free(tags);
4476 }
4477 else
4478 {
4479 tag = calloc(1, sizeof(Evas_Object_Style_Tag));
4480 if (tag)
4481 {
4482 tag->tag = tags;
4483 tag->replace = replaces;
4484 tag->tag_len = tag_len;
4485 tag->replace_len = replace_len;
4486 ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag));
4487 }
4488 else
4489 {
4490 free(tags);
4491 free(replaces);
4492 }
4493 }
4494 }
4495 else
4496 {
4497 if (tags) free(tags);
4498 if (replaces) free(replaces);
4499 }
4500 key_start = key_stop = val_start = val_stop = NULL;
4501 }
4502 p++;
4503 }
4504 }
4505}
4506
4507EAPI const char *
4508evas_textblock_style_get(const Evas_Textblock_Style *ts)
4509{
4510 if (!ts) return NULL;
4511 return ts->style_text;
4512}
4513
4514/* textblock styles */
4515EAPI void
4516evas_object_textblock_style_set(Evas_Object *obj, Evas_Textblock_Style *ts)
4517{
4518 TB_HEAD();
4519 if (ts == o->style) return;
4520 if ((ts) && (ts->delete_me)) return;
4521 if (o->style)
4522 {
4523 Evas_Textblock_Style *old_ts;
4524 if (o->markup_text)
4525 {
4526 free(o->markup_text);
4527 o->markup_text = NULL;
4528 }
4529
4530 old_ts = o->style;
4531 old_ts->objects = eina_list_remove(old_ts->objects, obj);
4532 if ((old_ts->delete_me) && (!old_ts->objects))
4533 evas_textblock_style_free(old_ts);
4534 }
4535 if (ts)
4536 {
4537 ts->objects = eina_list_append(ts->objects, obj);
4538 }
4539 o->style = ts;
4540
4541 _evas_textblock_invalidate_all(o);
4542 _evas_textblock_changed(o, obj);
4543}
4544
4545EAPI const Evas_Textblock_Style *
4546evas_object_textblock_style_get(const Evas_Object *obj)
4547{
4548 TB_HEAD_RETURN(NULL);
4549 return o->style;
4550}
4551
4552EAPI void
4553evas_object_textblock_replace_char_set(Evas_Object *obj, const char *ch)
4554{
4555 TB_HEAD();
4556 if (o->repch) eina_stringshare_del(o->repch);
4557 if (ch) o->repch = eina_stringshare_add(ch);
4558 else o->repch = NULL;
4559 _evas_textblock_invalidate_all(o);
4560 _evas_textblock_changed(o, obj);
4561}
4562
4563EAPI void
4564evas_object_textblock_legacy_newline_set(Evas_Object *obj, Eina_Bool mode)
4565{
4566 TB_HEAD();
4567 if (o->legacy_newline == mode)
4568 return;
4569
4570 o->legacy_newline = mode;
4571 /* FIXME: Should recreate all the textnodes... For now, it's just
4572 * for new text inserted. */
4573}
4574
4575EAPI Eina_Bool
4576evas_object_textblock_legacy_newline_get(const Evas_Object *obj)
4577{
4578 TB_HEAD_RETURN(EINA_FALSE);
4579 return o->legacy_newline;
4580}
4581
4582EAPI void
4583evas_object_textblock_valign_set(Evas_Object *obj, double align)
4584{
4585 TB_HEAD();
4586 if (align < 0.0) align = 0.0;
4587 else if (align > 1.0) align = 1.0;
4588 if (o->valign == align) return;
4589 o->valign = align;
4590 _evas_textblock_changed(o, obj);
4591}
4592
4593EAPI double
4594evas_object_textblock_valign_get(const Evas_Object *obj)
4595{
4596 TB_HEAD_RETURN(0.0);
4597 return o->valign;
4598}
4599
4600EAPI void
4601evas_object_textblock_bidi_delimiters_set(Evas_Object *obj, const char *delim)
4602{
4603 TB_HEAD();
4604 eina_stringshare_replace(&o->bidi_delimiters, delim);
4605}
4606
4607EAPI const char *
4608evas_object_textblock_bidi_delimiters_get(const Evas_Object *obj)
4609{
4610 TB_HEAD_RETURN(NULL);
4611 return o->bidi_delimiters;
4612}
4613
4614EAPI const char *
4615evas_object_textblock_replace_char_get(Evas_Object *obj)
4616{
4617 TB_HEAD_RETURN(NULL);
4618 return o->repch;
4619}
4620
4621/**
4622 * @internal
4623 * Advance p_buff to point after the end of the string. It's used with the
4624 * @ref escaped_strings[] variable.
4625 *
4626 * @param p_buff the pointer to the current string.
4627 */
4628static inline void
4629_escaped_advance_after_end_of_string(const char **p_buf)
4630{
4631 while (**p_buf != 0) (*p_buf)++;
4632 (*p_buf)++;
4633}
4634
4635/**
4636 * @internal
4637 * Advance p_buff to point after the end of the string. It's used with the
4638 * @ref escaped_strings[] variable. Also chec if matches.
4639 * FIXME: doc.
4640 *
4641 * @param p_buff the pointer to the current string.
4642 */
4643static inline int
4644_escaped_is_eq_and_advance(const char *s, const char *s_end,
4645 const char **p_m, const char *m_end)
4646{
4647 Eina_Bool reached_end;
4648 for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++)
4649 {
4650 if (*s != **p_m)
4651 {
4652 _escaped_advance_after_end_of_string(p_m);
4653 return 0;
4654 }
4655 }
4656
4657 reached_end = !**p_m;
4658 if (*p_m < m_end)
4659 _escaped_advance_after_end_of_string(p_m);
4660
4661 return ((s == s_end) && reached_end);
4662}
4663
4664/**
4665 * @internal
4666 *
4667 * @param s the string to match
4668 */
4669static inline const char *
4670_escaped_char_match(const char *s, int *adv)
4671{
4672 const char *map_itr, *map_end, *mc, *sc;
4673
4674 map_itr = escape_strings;
4675 map_end = map_itr + sizeof(escape_strings);
4676
4677 while (map_itr < map_end)
4678 {
4679 const char *escape;
4680 int match;
4681
4682 escape = map_itr;
4683 _escaped_advance_after_end_of_string(&map_itr);
4684 if (map_itr >= map_end) break;
4685
4686 mc = map_itr;
4687 sc = s;
4688 match = 1;
4689 while ((*mc) && (*sc))
4690 {
4691 if ((unsigned char)*sc < (unsigned char)*mc) return NULL;
4692 if (*sc != *mc) match = 0;
4693 mc++;
4694 sc++;
4695 }
4696 if (match)
4697 {
4698 *adv = mc - map_itr;
4699 return escape;
4700 }
4701 _escaped_advance_after_end_of_string(&map_itr);
4702 }
4703 return NULL;
4704}
4705
4706/**
4707 * @internal
4708 * FIXME: TBD.
4709 *
4710 * @param s the string to match
4711 */
4712static inline const char *
4713_escaped_char_get(const char *s, const char *s_end)
4714{
4715 /* Handle numeric escape codes. */
4716 if (s[1] == '#')
4717 {
4718 static char utf8_escape[7]; /* Support up to 6 bytes utf8 */
4719 char ustr[10];
4720 Eina_Unicode uchar[2] = { 0, 0 };
4721 char *utf8_char;
4722 size_t len = 0;
4723 int base = 10;
4724 s += 2; /* Skip "&#" */
4725
4726 if (tolower(*s) == 'x')
4727 {
4728 s++;
4729 base = 16;
4730 }
4731
4732 len = s_end - s;
4733 if (len >= sizeof(ustr) + 1)
4734 len = sizeof(ustr);
4735
4736 memcpy(ustr, s, len);
4737 ustr[len] = '\0';
4738 uchar[0] = strtol(ustr, NULL, base);
4739
4740 if (uchar[0] == 0)
4741 return NULL;
4742
4743 utf8_char = eina_unicode_unicode_to_utf8(uchar, NULL);
4744 strcpy(utf8_escape, utf8_char);
4745 free(utf8_char);
4746
4747 return utf8_escape;
4748 }
4749 else
4750 {
4751 const char *map_itr, *map_end;
4752
4753 map_itr = escape_strings;
4754 map_end = map_itr + sizeof(escape_strings);
4755
4756 while (map_itr < map_end)
4757 {
4758 if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end))
4759 return map_itr;
4760 if (map_itr < map_end)
4761 _escaped_advance_after_end_of_string(&map_itr);
4762 }
4763 }
4764
4765 return NULL;
4766}
4767
4768EAPI const char *
4769evas_textblock_escape_string_get(const char *escape)
4770{
4771 /* &amp; -> & */
4772 return _escaped_char_get(escape, escape + strlen(escape));
4773}
4774
4775EAPI const char *
4776evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end)
4777{
4778 return _escaped_char_get(escape_start, escape_end);
4779}
4780
4781EAPI const char *
4782evas_textblock_string_escape_get(const char *string, int *len_ret)
4783{
4784 /* & -> &amp; */
4785 return _escaped_char_match(string, len_ret);
4786}
4787
4788/**
4789 * @internal
4790 * Appends the escaped char beteewn s and s_end to the curosr
4791 *
4792 *
4793 * @param s the start of the string
4794 * @param s_end the end of the string.
4795 */
4796static inline void
4797_append_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
4798 const char *s_end)
4799{
4800 const char *escape;
4801
4802 escape = _escaped_char_get(s, s_end);
4803 if (escape)
4804 evas_textblock_cursor_text_append(cur, escape);
4805}
4806
4807/**
4808 * @internal
4809 * prepends the escaped char beteewn s and s_end to the curosr
4810 *
4811 *
4812 * @param s the start of the string
4813 * @param s_end the end of the string.
4814 */
4815static inline void
4816_prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s,
4817 const char *s_end)
4818{
4819 const char *escape;
4820
4821 escape = _escaped_char_get(s, s_end);
4822 if (escape)
4823 evas_textblock_cursor_text_prepend(cur, escape);
4824}
4825
4826
4827EAPI void
4828evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text)
4829{
4830 TB_HEAD();
4831 if ((text != o->markup_text) && (o->markup_text))
4832 {
4833 free(o->markup_text);
4834 o->markup_text = NULL;
4835 }
4836 _nodes_clear(obj);
4837 if (!o->style)
4838 {
4839 if (text != o->markup_text)
4840 {
4841 if (text) o->markup_text = strdup(text);
4842 }
4843 return;
4844 }
4845 evas_textblock_cursor_paragraph_first(o->cursor);
4846
4847 evas_object_textblock_text_markup_prepend(o->cursor, text);
4848 /* Point all the cursors to the starrt */
4849 {
4850 Eina_List *l;
4851 Evas_Textblock_Cursor *data;
4852
4853 evas_textblock_cursor_paragraph_first(o->cursor);
4854 EINA_LIST_FOREACH(o->cursors, l, data)
4855 evas_textblock_cursor_paragraph_first(data);
4856 }
4857}
4858
4859EAPI void
4860evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text)
4861{
4862 Evas_Object *obj = cur->obj;
4863 TB_HEAD();
4864 if (text)
4865 {
4866 char *s, *p;
4867 char *tag_start, *tag_end, *esc_start, *esc_end;
4868
4869 tag_start = tag_end = esc_start = esc_end = NULL;
4870 p = (char *)text;
4871 s = p;
4872 /* This loop goes through all of the mark up text until it finds format
4873 * tags, escape sequences or the terminating NULL. When it finds either
4874 * of those, it appends the text found up until that point to the textblock
4875 * proccesses whatever found. It repeats itself until the termainating
4876 * NULL is reached. */
4877 for (;;)
4878 {
4879 /* If we got to the end of string or just finished/started tag
4880 * or escape sequence handling. */
4881 if ((*p == 0) ||
4882 (tag_end) || (esc_end) ||
4883 (tag_start) || (esc_start))
4884 {
4885 if (tag_end)
4886 {
4887 /* If we reached to a tag ending, analyze the tag */
4888 char *ttag;
4889 size_t ttag_len = tag_end - tag_start;
4890
4891
4892 ttag = malloc(ttag_len + 1);
4893 if (ttag)
4894 {
4895 memcpy(ttag, tag_start, ttag_len);
4896 ttag[ttag_len] = 0;
4897 evas_textblock_cursor_format_prepend(cur, ttag);
4898 free(ttag);
4899 }
4900 tag_start = tag_end = NULL;
4901 }
4902 else if (esc_end)
4903 {
4904 _prepend_escaped_char(cur, esc_start, esc_end + 1);
4905 esc_start = esc_end = NULL;
4906 }
4907 else if (*p == 0)
4908 {
4909 _prepend_text_run(cur, s, p);
4910 s = NULL;
4911 }
4912 if (*p == 0)
4913 break;
4914 }
4915 if (*p == '<')
4916 {
4917 if (!esc_start)
4918 {
4919 /* Append the text prior to this to the textblock and mark
4920 * the start of the tag */
4921 tag_start = p;
4922 tag_end = NULL;
4923 _prepend_text_run(cur, s, p);
4924 s = NULL;
4925 }
4926 }
4927 else if (*p == '>')
4928 {
4929 if (tag_start)
4930 {
4931 tag_end = p + 1;
4932 s = p + 1;
4933 }
4934 }
4935 else if (*p == '&')
4936 {
4937 if (!tag_start)
4938 {
4939 /* Append the text prior to this to the textblock and mark
4940 * the start of the escape sequence */
4941 esc_start = p;
4942 esc_end = NULL;
4943 _prepend_text_run(cur, s, p);
4944 s = NULL;
4945 }
4946 }
4947 else if (*p == ';')
4948 {
4949 if (esc_start)
4950 {
4951 esc_end = p;
4952 s = p + 1;
4953 }
4954 }
4955 /* Unicode object replcament char */
4956 else if (!strncmp("\xEF\xBF\xBC", p, 3))
4957 {
4958 /*FIXME: currently just remove them, maybe do something
4959 * fancier in the future, atm it breaks if this char
4960 * is inside <> */
4961 _prepend_text_run(cur, s, p);
4962 p += 2; /* it's also advanced later in this loop need +3
4963 * in total*/
4964 s = p + 1; /* One after the end of the replacement char */
4965 }
4966 p++;
4967 }
4968 }
4969 _evas_textblock_changed(o, obj);
4970}
4971
4972
4973/**
4974 * @internal
4975 * An helper function to markup get. Appends the format from fnode to the strbugf txt.
4976 *
4977 * @param o the textblock object.
4978 * @param txt the strbuf to append to.
4979 * @param fnode the format node to process.
4980 */
4981static void
4982_markup_get_format_append(Evas_Object_Textblock *o __UNUSED__, Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode)
4983{
4984 eina_strbuf_append_char(txt, '<');
4985 {
4986 const char *s;
4987 int pop = 0;
4988
4989 // FIXME: need to escape
4990 s = fnode->orig_format;
4991 if (*s == '-') pop = 1;
4992 while ((*s == ' ') || (*s == '+') || (*s == '-')) s++;
4993 if (pop) eina_strbuf_append_char(txt, '/');
4994 eina_strbuf_append(txt, s);
4995 }
4996 eina_strbuf_append_char(txt, '>');
4997}
4998
4999/**
5000 * @internal
5001 * An helper function to markup get. Appends the text in text.
5002 *
5003 * @param txt the strbuf to append to.
5004 * @param text the text to process.
5005 */
5006static void
5007_markup_get_text_append(Eina_Strbuf *txt, const Eina_Unicode *text)
5008{
5009 char *p = eina_unicode_unicode_to_utf8(text, NULL);
5010 char *base = p;
5011 while (*p)
5012 {
5013 const char *escape;
5014 int adv;
5015
5016 escape = _escaped_char_match(p, &adv);
5017 if (escape)
5018 {
5019 p += adv;
5020 eina_strbuf_append(txt, escape);
5021 }
5022 else
5023 {
5024 eina_strbuf_append_char(txt, *p);
5025 p++;
5026 }
5027 }
5028 free(base);
5029}
5030EAPI const char *
5031evas_object_textblock_text_markup_get(const Evas_Object *obj)
5032{
5033 Evas_Object_Textblock_Node_Text *n;
5034 Eina_Strbuf *txt = NULL;
5035
5036 TB_HEAD_RETURN(NULL);
5037 if (o->markup_text) return(o->markup_text);
5038 txt = eina_strbuf_new();
5039 EINA_INLIST_FOREACH(o->text_nodes, n)
5040 {
5041 Evas_Object_Textblock_Node_Format *fnode;
5042 Eina_Unicode *text_base, *text;
5043 int off;
5044
5045 /* For each text node to thorugh all of it's format nodes
5046 * append text from the start to the offset of the next format
5047 * using the last format got. if needed it also creates format items
5048 * this is the core algorithm of the layout mechanism.
5049 * Skip the unicode replacement chars when there are because
5050 * we don't want to print them. */
5051 text_base = text =
5052 eina_unicode_strndup(eina_ustrbuf_string_get(n->unicode),
5053 eina_ustrbuf_length_get(n->unicode));
5054 fnode = n->format_node;
5055 off = 0;
5056 while (fnode && (fnode->text_node == n))
5057 {
5058 Eina_Unicode tmp_ch;
5059 off += fnode->offset;
5060 /* No need to skip on the first run */
5061 tmp_ch = text[off];
5062 text[off] = 0; /* Null terminate the part of the string */
5063 _markup_get_text_append(txt, text);
5064 _markup_get_format_append(o, txt, fnode);
5065 text[off] = tmp_ch; /* Restore the char */
5066 text += off;
5067 if (fnode->visible)
5068 {
5069 off = -1;
5070 text++;
5071 }
5072 else
5073 {
5074 off = 0;
5075 }
5076 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
5077 }
5078 /* Add the rest, skip replacement */
5079 _markup_get_text_append(txt, text);
5080 free(text_base);
5081 }
5082
5083
5084 o->markup_text = eina_strbuf_string_steal(txt);
5085 eina_strbuf_free(txt);
5086 return o->markup_text;
5087}
5088
5089/* cursors */
5090
5091/**
5092 * @internal
5093 * Merge the current node with the next, no need to remove PS, already
5094 * not there.
5095 *
5096 * @param o the text block object.
5097 * @param to merge into to.
5098 */
5099static void
5100_evas_textblock_nodes_merge(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *to)
5101{
5102 Evas_Object_Textblock_Node_Format *itr;
5103 Evas_Object_Textblock_Node_Format *pnode;
5104 Evas_Object_Textblock_Node_Text *from;
5105 const Eina_Unicode *text;
5106 int to_len, len;
5107
5108 if (!to) return;
5109 from = _NODE_TEXT(EINA_INLIST_GET(to)->next);
5110
5111 to_len = eina_ustrbuf_length_get(to->unicode);
5112 text = eina_ustrbuf_string_get(from->unicode);
5113 len = eina_ustrbuf_length_get(from->unicode);
5114 eina_ustrbuf_append_length(to->unicode, text, len);
5115
5116 itr = from->format_node;
5117 if (itr && (itr->text_node == from))
5118 {
5119 pnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->prev);
5120 if (pnode && (pnode->text_node == to))
5121 {
5122 itr->offset += to_len - _evas_textblock_node_format_pos_get(pnode);
5123 }
5124 else
5125 {
5126 itr->offset += to_len;
5127 }
5128 }
5129
5130 while (itr && (itr->text_node == from))
5131 {
5132 itr->text_node = to;
5133 itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
5134 }
5135 if (!to->format_node || (to->format_node->text_node != to))
5136 {
5137 to->format_node = from->format_node;
5138 }
5139
5140 /* When it comes to how we handle it, merging is like removing both nodes
5141 * and creating a new one, se we need to do the needed cleanups. */
5142 if (to->par)
5143 to->par->text_node = NULL;
5144 to->par = NULL;
5145
5146 to->is_new = EINA_TRUE;
5147
5148 _evas_textblock_cursors_set_node(o, from, to);
5149 _evas_textblock_node_text_remove(o, from);
5150}
5151
5152/**
5153 * @internal
5154 * Merge the current node with the next, no need to remove PS, already
5155 * not there.
5156 *
5157 * @param cur the cursor that points to the current node
5158 */
5159static void
5160_evas_textblock_cursor_nodes_merge(Evas_Textblock_Cursor *cur)
5161{
5162 Evas_Object_Textblock_Node_Text *nnode;
5163 Evas_Object_Textblock *o;
5164 int len;
5165 if (!cur) return;
5166
5167 len = eina_ustrbuf_length_get(cur->node->unicode);
5168
5169 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5170 nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next);
5171 _evas_textblock_nodes_merge(o, cur->node);
5172 _evas_textblock_cursors_update_offset(cur, nnode, 0, len);
5173 _evas_textblock_cursors_set_node(o, nnode, cur->node);
5174 if (nnode == o->cursor->node)
5175 {
5176 o->cursor->node = cur->node;
5177 o->cursor->pos += len;
5178 }
5179}
5180
5181/**
5182 * @internal
5183 * Return the format at a specific position.
5184 *
5185 * @param cur the cursor to the position.
5186 * @return the format node at the specific position or NULL if not found.
5187 */
5188static Evas_Object_Textblock_Node_Format *
5189_evas_textblock_cursor_node_format_at_pos_get(const Evas_Textblock_Cursor *cur)
5190{
5191 Evas_Object_Textblock_Node_Format *node;
5192 Evas_Object_Textblock_Node_Format *itr;
5193 int position = 0;
5194
5195 if (!cur->node) return NULL;
5196
5197 node = cur->node->format_node;
5198 if (!node) return NULL;
5199 /* If there is no exclusive format node to this paragraph return the
5200 * previous's node */
5201 /* Find the main format node */
5202 EINA_INLIST_FOREACH(node, itr)
5203 {
5204 if (itr->text_node != cur->node)
5205 {
5206 return NULL;
5207 }
5208 if ((position + itr->offset) == cur->pos)
5209 {
5210 return itr;
5211 }
5212 position += itr->offset;
5213 }
5214 return NULL;
5215}
5216
5217/**
5218 * @internal
5219 * Return the last format node at the position of the format node n.
5220 *
5221 * @param n a format node at the position.
5222 * @return the last format node at the position of n.
5223 */
5224static Evas_Object_Textblock_Node_Format *
5225_evas_textblock_node_format_last_at_off(const Evas_Object_Textblock_Node_Format *n)
5226{
5227 const Evas_Object_Textblock_Node_Format *nnode;
5228 const Evas_Object_Textblock_Node_Text *tnode;
5229 if (!n) return NULL;
5230 nnode = n;
5231 tnode = n->text_node;
5232 do
5233 {
5234 n = nnode;
5235 nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
5236 }
5237 while (nnode && (nnode->text_node == tnode) && (nnode->offset == 0));
5238
5239 return (Evas_Object_Textblock_Node_Format *) n;
5240}
5241
5242/**
5243 * @internal
5244 * Returns the visible format at a specific location.
5245 *
5246 * @param n a format at the specific position.
5247 * @return the format node at the specific position or NULL if not found.
5248 */
5249static Evas_Object_Textblock_Node_Format *
5250_evas_textblock_node_visible_at_pos_get(const Evas_Object_Textblock_Node_Format *n)
5251{
5252 const Evas_Object_Textblock_Node_Format *nnode;
5253 if (!n) return NULL;
5254 /* The visible format is the last one, because it inserts a replacement
5255 * char that advances the next formats. */
5256
5257 nnode = n;
5258 do
5259 {
5260 n = nnode;
5261 if (n->visible) return (Evas_Object_Textblock_Node_Format *) n;
5262 nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
5263 }
5264 while (nnode && (nnode->offset == 0));
5265
5266 return NULL;
5267}
5268
5269/**
5270 * @internal
5271 * Return the last format that applies to a specific cursor or at the specific
5272 * position the cursor points to. This means either a cursor at or before the
5273 * position of the cursor in the text node is returned or the previous's text
5274 * node's format node.
5275 *
5276 * @param cur the position to look at.
5277 * @return the format node found.
5278 */
5279static Evas_Object_Textblock_Node_Format *
5280_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur)
5281{
5282 Evas_Object_Textblock_Node_Format *node, *pitr = NULL;
5283 Evas_Object_Textblock_Node_Format *itr;
5284 size_t position = 0;
5285
5286 if (!cur->node) return NULL;
5287
5288 node = cur->node->format_node;
5289 if (!node) return NULL;
5290 /* If there is no exclusive format node to this paragraph return the
5291 * previous's node */
5292 if (node->text_node != cur->node)
5293 {
5294 return node;
5295 }
5296 else if (node->offset > cur->pos)
5297 {
5298 return _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
5299 }
5300 /* Find the main format node */
5301 pitr = _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
5302 EINA_INLIST_FOREACH(node, itr)
5303 {
5304 if ((itr->text_node != cur->node) ||
5305 ((position + itr->offset) > cur->pos))
5306 {
5307 return pitr;
5308 }
5309 else if ((position + itr->offset) == cur->pos)
5310 {
5311 return itr;
5312 }
5313 pitr = itr;
5314 position += itr->offset;
5315 }
5316 return pitr;
5317}
5318
5319/**
5320 * @internal
5321 * Find the layout item and line that match the cursor.
5322 *
5323 * @param cur the cursor we are currently at. - NOT NULL.
5324 * @param[out] lnr the line found - not null.
5325 * @param[out] itr the item found - not null.
5326 * @return EINA_TRUE if we matched the previous format, EINA_FALSE otherwise.
5327 */
5328static Eina_Bool
5329_find_layout_item_match(const Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr)
5330{
5331 Evas_Textblock_Cursor cur2;
5332 Eina_Bool previous_format = EINA_FALSE;
5333
5334 cur2.obj = cur->obj;
5335 evas_textblock_cursor_copy(cur, &cur2);
5336 if (cur2.pos > 0)
5337 {
5338 cur2.pos--;
5339 }
5340
5341 if (_evas_textblock_cursor_is_at_the_end(cur) &&
5342 evas_textblock_cursor_format_is_visible_get(&cur2))
5343 {
5344 _find_layout_item_line_match(cur2.obj, cur2.node, cur2.pos, lnr, itr);
5345 previous_format = EINA_TRUE;
5346 }
5347 else
5348 {
5349 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, lnr, itr);
5350 }
5351 return previous_format;
5352}
5353
5354EAPI Evas_Textblock_Cursor *
5355evas_object_textblock_cursor_get(const Evas_Object *obj)
5356{
5357 TB_HEAD_RETURN(NULL);
5358 return o->cursor;
5359}
5360
5361EAPI Evas_Textblock_Cursor *
5362evas_object_textblock_cursor_new(const Evas_Object *obj)
5363{
5364 Evas_Textblock_Cursor *cur;
5365
5366 TB_HEAD_RETURN(NULL);
5367 cur = calloc(1, sizeof(Evas_Textblock_Cursor));
5368 cur->obj = (Evas_Object *) obj;
5369 cur->node = o->text_nodes;
5370 cur->pos = 0;
5371
5372 o->cursors = eina_list_append(o->cursors, cur);
5373 return cur;
5374}
5375
5376EAPI void
5377evas_textblock_cursor_free(Evas_Textblock_Cursor *cur)
5378{
5379 Evas_Object_Textblock *o;
5380
5381 if (!cur) return;
5382 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5383 if (cur == o->cursor) return;
5384 o->cursors = eina_list_remove(o->cursors, cur);
5385 free(cur);
5386}
5387
5388EAPI Eina_Bool
5389evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur)
5390{
5391 if (!cur || !cur->node) return EINA_FALSE;
5392 if (evas_textblock_cursor_format_is_visible_get(cur)) return EINA_TRUE;
5393 return (_evas_textblock_cursor_node_format_at_pos_get(cur)) ?
5394 EINA_TRUE : EINA_FALSE;
5395}
5396
5397EAPI const Eina_List *
5398evas_textblock_node_format_list_get(const Evas_Object *obj, const char *anchor)
5399{
5400 TB_HEAD_RETURN(NULL);
5401 if (!strcmp(anchor, "a"))
5402 return o->anchors_a;
5403 else if (!strcmp(anchor, "item"))
5404 return o->anchors_item;
5405
5406 return NULL;
5407}
5408
5409EAPI const Evas_Object_Textblock_Node_Format *
5410evas_textblock_node_format_first_get(const Evas_Object *obj)
5411{
5412 TB_HEAD_RETURN(NULL);
5413 return o->format_nodes;
5414}
5415
5416EAPI const Evas_Object_Textblock_Node_Format *
5417evas_textblock_node_format_last_get(const Evas_Object *obj)
5418{
5419 TB_HEAD_RETURN(NULL);
5420 if (o->format_nodes)
5421 {
5422 return _NODE_FORMAT(EINA_INLIST_GET(o->format_nodes)->last);
5423 }
5424 return NULL;
5425}
5426
5427EAPI const Evas_Object_Textblock_Node_Format *
5428evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n)
5429{
5430 return _NODE_FORMAT(EINA_INLIST_GET(n)->next);
5431}
5432
5433EAPI const Evas_Object_Textblock_Node_Format *
5434evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n)
5435{
5436 return _NODE_FORMAT(EINA_INLIST_GET(n)->prev);
5437}
5438
5439EAPI void
5440evas_textblock_node_format_remove_pair(Evas_Object *obj,
5441 Evas_Object_Textblock_Node_Format *n)
5442{
5443 Evas_Object_Textblock_Node_Text *tnode1;
5444 Evas_Object_Textblock_Node_Format *fmt, *found_node = NULL;
5445 Eina_List *fstack = NULL;
5446 TB_HEAD();
5447
5448 if (!n) return;
5449
5450 fmt = n;
5451
5452 do
5453 {
5454 const char *fstr = fmt->orig_format;
5455
5456 if (fstr && (*fstr == '+'))
5457 {
5458 fstack = eina_list_prepend(fstack, fmt);
5459 }
5460 else if (fstr && (*fstr == '-'))
5461 {
5462 size_t fstr_len;
5463 /* Skip the '-' */
5464 fstr++;
5465 fstr_len = strlen(fstr);
5466 /* Generic popper, just pop */
5467 if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0])
5468 {
5469 fstack = eina_list_remove_list(fstack, fstack);
5470 if (!fstack)
5471 {
5472 found_node = fmt;
5473 goto found;
5474 }
5475 }
5476 /* Find the matching format and pop it, if the matching format
5477 * is out format, i.e the last one, pop and break. */
5478 else
5479 {
5480 Eina_List *i;
5481 Evas_Object_Textblock_Node_Format *fnode;
5482 EINA_LIST_FOREACH(fstack, i, fnode)
5483 {
5484 if (_FORMAT_IS_CLOSER_OF(
5485 fnode->orig_format, fstr, fstr_len))
5486 {
5487 /* Last one, this is our item! */
5488 if (!eina_list_next(i))
5489 {
5490 found_node = fmt;
5491 goto found;
5492 }
5493 fstack = eina_list_remove_list(fstack, i);
5494 break;
5495 }
5496 }
5497 }
5498 }
5499
5500 fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
5501 }
5502 while (fmt && fstack);
5503
5504found:
5505
5506 fstack = eina_list_free(fstack);
5507
5508 if (n->visible)
5509 {
5510 size_t ind = _evas_textblock_node_format_pos_get(n);
5511 const char *format = n->format;
5512 Evas_Textblock_Cursor cur;
5513 cur.obj = obj;
5514
5515 eina_ustrbuf_remove(n->text_node->unicode, ind, ind + 1);
5516 if (format && _IS_PARAGRAPH_SEPARATOR(o, format))
5517 {
5518 evas_textblock_cursor_at_format_set(&cur, n);
5519 _evas_textblock_cursor_nodes_merge(&cur);
5520 }
5521 _evas_textblock_cursors_update_offset(&cur, n->text_node, ind, -1);
5522 }
5523 tnode1 = n->text_node;
5524 _evas_textblock_node_format_remove(o, n, 0);
5525 if (found_node && (found_node != n))
5526 {
5527 Evas_Object_Textblock_Node_Text *tnode2;
5528 tnode2 = found_node->text_node;
5529 /* found_node can never be visible! (it's the closing format) */
5530 _evas_textblock_node_format_remove(o, found_node, 0);
5531
5532 /* FIXME: Should be unified in the layout, for example, added to a list
5533 * that checks this kind of removals. But until then, this is very fast
5534 * and works. */
5535 /* Mark all the text nodes in between the removed formats as dirty. */
5536 while (tnode1)
5537 {
5538 tnode1->dirty = EINA_TRUE;
5539 if (tnode1 == tnode2)
5540 break;
5541 tnode1 =
5542 _NODE_TEXT(EINA_INLIST_GET(tnode1)->next);
5543 }
5544 }
5545
5546 _evas_textblock_changed(o, obj);
5547}
5548
5549EAPI void
5550evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur)
5551{
5552 Evas_Object_Textblock *o;
5553 if (!cur) return;
5554 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5555 cur->node = o->text_nodes;
5556 cur->pos = 0;
5557
5558}
5559
5560EAPI void
5561evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur)
5562{
5563 Evas_Object_Textblock *o;
5564 Evas_Object_Textblock_Node_Text *node;
5565
5566 if (!cur) return;
5567 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5568 node = o->text_nodes;
5569 if (node)
5570 {
5571 node = _NODE_TEXT(EINA_INLIST_GET(node)->last);
5572 cur->node = node;
5573 cur->pos = 0;
5574
5575 evas_textblock_cursor_paragraph_char_last(cur);
5576 }
5577 else
5578 {
5579 cur->node = NULL;
5580 cur->pos = 0;
5581
5582 }
5583}
5584
5585EAPI Eina_Bool
5586evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur)
5587{
5588 if (!cur) return EINA_FALSE;
5589 if (!cur->node) return EINA_FALSE;
5590 /* If there is a current text node, return the next text node (if exists)
5591 * otherwise, just return False. */
5592 if (cur->node)
5593 {
5594 Evas_Object_Textblock_Node_Text *nnode;
5595 nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next);
5596 if (nnode)
5597 {
5598 cur->node = nnode;
5599 cur->pos = 0;
5600
5601 return EINA_TRUE;
5602 }
5603 }
5604 return EINA_FALSE;
5605}
5606
5607EAPI Eina_Bool
5608evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur)
5609{
5610 Evas_Object_Textblock_Node_Text *node;
5611 if (!cur) return EINA_FALSE;
5612 if (!cur->node) return EINA_FALSE;
5613 /* If the current node is a text node, just get the prev if any,
5614 * if it's a format, get the current text node out of the format and return
5615 * the prev text node if any. */
5616 node = cur->node;
5617 /* If there is a current text node, return the prev text node
5618 * (if exists) otherwise, just return False. */
5619 if (node)
5620 {
5621 Evas_Object_Textblock_Node_Text *pnode;
5622 pnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->prev);
5623 if (pnode)
5624 {
5625 cur->node = pnode;
5626 evas_textblock_cursor_paragraph_char_last(cur);
5627 return EINA_TRUE;
5628 }
5629 }
5630 return EINA_FALSE;
5631}
5632
5633EAPI void
5634evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n)
5635{
5636 evas_textblock_cursor_at_format_set(cur, n);
5637}
5638
5639EAPI Eina_Bool
5640evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur)
5641{
5642 Evas_Object_Textblock_Node_Format *node;
5643
5644 if (!cur) return EINA_FALSE;
5645 if (!cur->node) return EINA_FALSE;
5646 /* If the current node is a format node, just get the next if any,
5647 * if it's a text, get the current format node out of the text and return
5648 * the next format node if any. */
5649 node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
5650 node = _evas_textblock_node_format_last_at_off(node);
5651 if (!node)
5652 {
5653 if (cur->node->format_node)
5654 {
5655 cur->pos = _evas_textblock_node_format_pos_get(node);
5656 return EINA_TRUE;
5657 }
5658 }
5659 /* If there is a current text node, return the next format node (if exists)
5660 * otherwise, just return False. */
5661 else
5662 {
5663 Evas_Object_Textblock_Node_Format *nnode;
5664 nnode = _NODE_FORMAT(EINA_INLIST_GET(node)->next);
5665 if (nnode)
5666 {
5667 cur->node = nnode->text_node;
5668 cur->pos = _evas_textblock_node_format_pos_get(nnode);
5669
5670 return EINA_TRUE;
5671 }
5672 }
5673 return EINA_FALSE;
5674}
5675
5676EAPI Eina_Bool
5677evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur)
5678{
5679 const Evas_Object_Textblock_Node_Format *node;
5680 if (!cur) return EINA_FALSE;
5681 if (!cur->node) return EINA_FALSE;
5682 node = evas_textblock_cursor_format_get(cur);
5683 if (!node)
5684 {
5685 node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
5686 if (node)
5687 {
5688 cur->node = node->text_node;
5689 cur->pos = _evas_textblock_node_format_pos_get(node);
5690
5691 return EINA_TRUE;
5692 }
5693 }
5694 /* If there is a current text node, return the next text node (if exists)
5695 * otherwise, just return False. */
5696 if (node)
5697 {
5698 Evas_Object_Textblock_Node_Format *pnode;
5699 pnode = _NODE_FORMAT(EINA_INLIST_GET(node)->prev);
5700 if (pnode)
5701 {
5702 cur->node = pnode->text_node;
5703 cur->pos = _evas_textblock_node_format_pos_get(pnode);
5704
5705 return EINA_TRUE;
5706 }
5707 }
5708 return EINA_FALSE;
5709}
5710
5711EAPI Eina_Bool
5712evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur)
5713{
5714 int ind;
5715 const Eina_Unicode *text;
5716
5717 if (!cur) return EINA_FALSE;
5718 if (!cur->node) return EINA_FALSE;
5719
5720 ind = cur->pos;
5721 text = eina_ustrbuf_string_get(cur->node->unicode);
5722 if (text[ind]) ind++;
5723 /* Only allow pointing a null if it's the last paragraph.
5724 * because we don't have a PS there. */
5725 if (text[ind])
5726 {
5727 cur->pos = ind;
5728 return EINA_TRUE;
5729 }
5730 else
5731 {
5732 if (!evas_textblock_cursor_paragraph_next(cur))
5733 {
5734 /* If we already were at the end, that means we don't have
5735 * where to go next we should return FALSE */
5736 if (cur->pos == (size_t) ind)
5737 return EINA_FALSE;
5738
5739 cur->pos = ind;
5740 return EINA_TRUE;
5741 }
5742 else
5743 {
5744 return EINA_TRUE;
5745 }
5746 }
5747}
5748
5749EAPI Eina_Bool
5750evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur)
5751{
5752 if (!cur) return EINA_FALSE;
5753 if (!cur->node) return EINA_FALSE;
5754
5755 if (cur->pos != 0)
5756 {
5757 cur->pos--;
5758 return EINA_TRUE;
5759 }
5760 return evas_textblock_cursor_paragraph_prev(cur);
5761}
5762
5763EAPI void
5764evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur)
5765{
5766 if (!cur) return;
5767 cur->pos = 0;
5768
5769}
5770
5771EAPI void
5772evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur)
5773{
5774 int ind;
5775
5776 if (!cur) return;
5777 if (!cur->node) return;
5778 ind = eina_ustrbuf_length_get(cur->node->unicode);
5779 /* If it's not the last paragraph, go back one, because we want to point
5780 * to the PS, not the NULL */
5781 if (EINA_INLIST_GET(cur->node)->next)
5782 ind--;
5783
5784 if (ind >= 0)
5785 cur->pos = ind;
5786 else
5787 cur->pos = 0;
5788
5789}
5790
5791EAPI void
5792evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur)
5793{
5794 Evas_Object_Textblock *o;
5795 Evas_Object_Textblock_Line *ln = NULL;
5796 Evas_Object_Textblock_Item *it = NULL;
5797
5798 if (!cur) return;
5799 if (!cur->node) return;
5800 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5801 if (!o->formatted.valid) _relayout(cur->obj);
5802
5803 _find_layout_item_match(cur, &ln, &it);
5804
5805 if (!ln) return;
5806 if (ln->items)
5807 {
5808 Evas_Object_Textblock_Item *i;
5809 it = ln->items;
5810 EINA_INLIST_FOREACH(ln->items, i)
5811 {
5812 if (it->text_pos > i->text_pos)
5813 {
5814 it = i;
5815 }
5816 }
5817 }
5818 if (it)
5819 {
5820 cur->pos = it->text_pos;
5821 cur->node = it->text_node;
5822 }
5823}
5824
5825EAPI void
5826evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur)
5827{
5828 Evas_Object_Textblock *o;
5829 Evas_Object_Textblock_Line *ln = NULL;
5830 Evas_Object_Textblock_Item *it = NULL;
5831
5832 if (!cur) return;
5833 if (!cur->node) return;
5834 o = (Evas_Object_Textblock *)(cur->obj->object_data);
5835 if (!o->formatted.valid) _relayout(cur->obj);
5836
5837 _find_layout_item_match(cur, &ln, &it);
5838
5839 if (!ln) return;
5840 if (ln->items)
5841 {
5842 Evas_Object_Textblock_Item *i;
5843 it = ln->items;
5844 EINA_INLIST_FOREACH(ln->items, i)
5845 {
5846 if (it->text_pos < i->text_pos)
5847 {
5848 it = i;
5849 }
5850 }
5851 }
5852 if (it)
5853 {
5854 size_t ind;
5855
5856 cur->node = it->text_node;
5857 cur->pos = it->text_pos;
5858 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
5859 {
5860 ind = _ITEM_TEXT(it)->text_props.text_len - 1;
5861 if (!IS_AT_END(_ITEM_TEXT(it), ind)) ind++;
5862 cur->pos += ind;
5863 }
5864 else if (!EINA_INLIST_GET(ln)->next && !EINA_INLIST_GET(ln->par)->next)
5865 {
5866 cur->pos++;
5867 }
5868 }
5869}
5870
5871/**
5872 * @internal
5873 * checks if a format (as a string) is visible/changes format and sets the
5874 * fnode properties accordingly.
5875 *
5876 * @param fnode the format node
5877 * @param s the string.
5878 */
5879static void
5880_evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode,
5881 const char *s)
5882{
5883 const char *item;
5884 Eina_Bool is_opener = EINA_TRUE;
5885
5886 fnode->visible = fnode->format_change = EINA_FALSE;
5887 fnode->anchor = ANCHOR_NONE;
5888 if (!s) return;
5889
5890 if (s[0] == '+' || s[0] == '-')
5891 {
5892 is_opener = (s[0] == '+');
5893 s++;
5894 fnode->format_change = EINA_TRUE;
5895 }
5896
5897 while ((item = _format_parse(&s)))
5898 {
5899 int itlen = s - item;
5900 /* We care about all of the formats even after a - except for
5901 * item which we don't care after a - because it's just a standard
5902 * closing */
5903 if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) ||
5904 (!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) ||
5905 (!strncmp(item, "ps", itlen) && (itlen >= 2)) ||
5906 (!strncmp(item, "item", itlen) && (itlen >= 4) && is_opener))
5907 {
5908 fnode->visible = EINA_TRUE;
5909 }
5910
5911 if (is_opener && !strncmp(item, "a", itlen))
5912 {
5913 fnode->anchor = ANCHOR_A;
5914 }
5915 else if (is_opener && !strncmp(item, "item", itlen) && (itlen >= 4))
5916 {
5917 fnode->anchor = ANCHOR_ITEM;
5918 }
5919 }
5920}
5921
5922/**
5923 * Sets the cursor to the position of where the fmt points to.
5924 *
5925 * @param cur the cursor to update.
5926 * @param fmt the format to set according to.
5927 * @return nothing.
5928 */
5929static void __UNUSED__
5930_evas_textblock_cursor_node_text_at_format(Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Node_Format *fmt)
5931{
5932 Evas_Object_Textblock_Node_Text *text;
5933 Evas_Object_Textblock_Node_Format *base_format;
5934 Evas_Object_Textblock_Node_Format *itr;
5935 size_t position = 0;
5936
5937 if (!cur || !fmt) return;
5938 /* Find the main format node */
5939 text = fmt->text_node;
5940 cur->node = text;
5941 base_format = text->format_node;
5942 EINA_INLIST_FOREACH(base_format, itr)
5943 {
5944 if (itr == fmt)
5945 {
5946 break;
5947 }
5948 position += itr->offset;
5949 }
5950 cur->pos = position;
5951
5952}
5953
5954
5955/**
5956 * @internal
5957 * Remove pairs of + and - formats and also remove formats without + or -
5958 * i.e formats that pair to themselves. Only removes invisible formats
5959 * that pair themselves, if you want to remove invisible formats that pair
5960 * themselves, please first change fmt->visible to EINA_FALSE.
5961 *
5962 * @param o the textblock object.
5963 * @param fmt the current format.
5964 */
5965static void
5966_evas_textblock_node_format_remove_matching(Evas_Object_Textblock *o,
5967 Evas_Object_Textblock_Node_Format *fmt)
5968{
5969 Evas_Object_Textblock_Node_Text *tnode;
5970 Eina_List *formats = NULL;
5971 size_t offset = 0;
5972
5973 if (!fmt) return;
5974
5975 tnode = fmt->text_node;
5976
5977 do
5978 {
5979 Evas_Object_Textblock_Node_Format *nnode;
5980 const char *fstr = fmt->orig_format;
5981
5982 nnode = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
5983 if (nnode)
5984 {
5985 offset = nnode->offset;
5986 }
5987
5988
5989 if (fstr && (*fstr == '+'))
5990 {
5991 formats = eina_list_prepend(formats, fmt);
5992 }
5993 else if (fstr && (*fstr == '-'))
5994 {
5995 Evas_Object_Textblock_Node_Format *fnode;
5996 size_t fstr_len;
5997 /* Skip the '-' */
5998 fstr++;
5999 fstr_len = strlen(fstr);
6000 /* Generic popper, just pop */
6001 if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0])
6002 {
6003 fnode = eina_list_data_get(formats);
6004 formats = eina_list_remove_list(formats, formats);
6005 _evas_textblock_node_format_remove(o, fnode, 0);
6006 _evas_textblock_node_format_remove(o, fmt, 0);
6007 }
6008 /* Find the matching format and pop it, if the matching format
6009 * is our format, i.e the last one, pop and break. */
6010 else
6011 {
6012 Eina_List *i, *next;
6013 EINA_LIST_FOREACH_SAFE(formats, i, next, fnode)
6014 {
6015 if (_FORMAT_IS_CLOSER_OF(
6016 fnode->orig_format, fstr, fstr_len))
6017 {
6018 fnode = eina_list_data_get(i);
6019 formats = eina_list_remove_list(formats, i);
6020 _evas_textblock_node_format_remove(o, fnode, 0);
6021 _evas_textblock_node_format_remove(o, fmt, 0);
6022 break;
6023 }
6024 }
6025 }
6026 }
6027 else if (!fmt->visible)
6028 {
6029 _evas_textblock_node_format_remove(o, fmt, 0);
6030 }
6031 fmt = nnode;
6032 }
6033 while (fmt && (offset == 0) && (fmt->text_node == tnode));
6034 eina_list_free(formats);
6035}
6036/**
6037 * @internal
6038 * Add the offset (may be negative) to the first node after fmt which is
6039 * pointing to the text node tnode or to o->format_nodes if fmt is null
6040 * and it points to tnode.
6041 *
6042 * @param o the textblock object.
6043 * @param tnode the text node the format should point to.
6044 * @param fmt the current format.
6045 * @param offset the offest to add (may be negative).
6046 */
6047static void
6048_evas_textblock_node_format_adjust_offset(Evas_Object_Textblock *o,
6049 Evas_Object_Textblock_Node_Text *tnode,
6050 Evas_Object_Textblock_Node_Format *fmt, int offset)
6051{
6052 if (fmt)
6053 {
6054 fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next);
6055 }
6056 else
6057 {
6058 fmt = o->format_nodes;
6059 }
6060 if (fmt && (tnode == fmt->text_node))
6061 {
6062 fmt->offset += offset;
6063 }
6064}
6065
6066/**
6067 * @internal
6068 * Removes a format node updating the offset of the next format node and the
6069 * text nodes pointing to this node.
6070 *
6071 * @param o the textblock object.
6072 * @param n the fromat node to remove
6073 */
6074static void
6075_evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visible_adjustment)
6076{
6077 /* Update the text nodes about the change */
6078 {
6079 Evas_Object_Textblock_Node_Format *nnode;
6080 nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->next);
6081 /* If there's a next node that belongs to the same text node
6082 * and the curret node was the main one, advance the format node */
6083 if (nnode && (nnode->text_node == n->text_node))
6084 {
6085 if (nnode->text_node->format_node == n)
6086 {
6087 nnode->text_node->format_node = nnode;
6088 }
6089 }
6090 else
6091 {
6092 Evas_Object_Textblock_Node_Text *tnode;
6093 /* If there's no next one update the text nodes */
6094 nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->prev);
6095 tnode = n->text_node;
6096 /* Even if it's not the current text_node's main node
6097 * it can still be the next's. */
6098 if (tnode && (tnode->format_node != n))
6099 {
6100 tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next);
6101 }
6102 while (tnode && (tnode->format_node == n))
6103 {
6104 tnode->format_node = nnode;
6105 tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next);
6106 }
6107 }
6108 }
6109 _evas_textblock_node_format_adjust_offset(o, n->text_node, n,
6110 n->offset - visible_adjustment);
6111
6112 o->format_nodes = _NODE_FORMAT(eina_inlist_remove(
6113 EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n)));
6114 _evas_textblock_node_format_free(o, n);
6115}
6116
6117/**
6118 * @internal
6119 * Sets all the offsets of the format nodes between start and end in the text
6120 * node n to 0 and sets visibility to EINA_FALSE.
6121 * If end == -1 end means the end of the string.
6122 * Assumes there is a prev node or the current node will be preserved.
6123 *
6124 * @param n the text node the positinos refer to.
6125 * @param start the start of where to delete from.
6126 * @param end the end of the section to delete, if end == -1 it means the end of the string.
6127 * @returns #EINA_TRUE if removed a PS, false otherwise.
6128 */
6129static Eina_Bool
6130_evas_textblock_node_text_adjust_offsets_to_start(Evas_Object_Textblock *o,
6131 Evas_Object_Textblock_Node_Text *n, size_t start, int end)
6132{
6133 Evas_Object_Textblock_Node_Format *last_node, *itr;
6134 Evas_Object_Textblock_Node_Text *new_node;
6135 int use_end = 1;
6136 int delta = 0;
6137 int first = 1;
6138 int update_format_node;
6139 size_t pos = 0;
6140 int orig_end;
6141
6142 itr = n->format_node;
6143 if (!itr || (itr->text_node != n)) return EINA_FALSE;
6144
6145 orig_end = end;
6146 if ((end < 0) || ((size_t) end == eina_ustrbuf_length_get(n->unicode)))
6147 {
6148 use_end = 0;
6149 }
6150 else if (end > 0)
6151 {
6152 /* We don't want the last one */
6153 end--;
6154 }
6155
6156 /* If we are not removing the text node, all should stay in this text
6157 * node, otherwise, everything should move to the previous node */
6158 if ((start == 0) && !use_end)
6159 {
6160 new_node = _NODE_TEXT(EINA_INLIST_GET(n)->prev);
6161 if (!new_node)
6162 {
6163 new_node = n;
6164 }
6165 }
6166 else
6167 {
6168 new_node = n;
6169 }
6170
6171 /* Find the first node after start */
6172 while (itr && (itr->text_node == n))
6173 {
6174 pos += itr->offset;
6175 if (pos >= start)
6176 {
6177 break;
6178 }
6179 itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
6180 }
6181
6182 if (!itr || (itr->text_node != n))
6183 {
6184 return EINA_FALSE;
6185 }
6186
6187 update_format_node = ((itr == n->format_node) && (new_node != n));
6188 delta = orig_end - pos;
6189 itr->offset -= pos - start;
6190
6191 while (itr && (itr->text_node == n))
6192 {
6193 last_node = itr;
6194 itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
6195
6196 if (!first)
6197 {
6198 pos += last_node->offset;
6199 }
6200
6201 /* start is negative when this gets relevant */
6202 if (use_end && (pos > (size_t) end))
6203 {
6204 last_node->offset -= delta;
6205 break;
6206 }
6207
6208 delta = orig_end - pos;
6209 if (!first)
6210 {
6211 last_node->offset = 0;
6212 }
6213 else
6214 {
6215 first = 0;
6216 }
6217 last_node->visible = EINA_FALSE;
6218
6219 if (!itr || (itr && (itr->text_node != n)))
6220 {
6221 /* Remove the PS, and return since it's the end of the node */
6222 if (_IS_PARAGRAPH_SEPARATOR(o, last_node->format))
6223 {
6224 _evas_textblock_node_format_remove(o, last_node, 0);
6225 return EINA_TRUE;
6226 }
6227
6228 }
6229 last_node->text_node = new_node;
6230 if (update_format_node)
6231 {
6232 n->format_node = last_node;
6233 }
6234 }
6235
6236 return EINA_FALSE;
6237}
6238
6239/**
6240 * @internal
6241 * Removes all the format nodes between start and end in the text node n.
6242 * This function updates the offset of the next format node and the
6243 * text nodes pointing to it. if end == -1 end means the end of the string.
6244 *
6245 * @param o the textblock object.
6246 * @param n the text node the positinos refer to.
6247 * @param start the start of where to delete from.
6248 * @param end the end of the section to delete, if end == -1 it means the end of the string.
6249 */
6250static void
6251_evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o,
6252 Evas_Object_Textblock_Node_Text *n, int start, int end)
6253{
6254 Evas_Object_Textblock_Node_Format *itr;
6255 int use_end = 1;
6256 int offset = end - start;
6257 itr = n->format_node;
6258
6259 if (itr)
6260 start -= itr->offset;
6261 if (offset < 0) offset = 0;
6262 if (end < 0) use_end = 0;
6263 while (itr && (itr->text_node == n))
6264 {
6265 Evas_Object_Textblock_Node_Format *nnode;
6266 int tmp_offset = 0;
6267
6268 /* start is negative when this gets relevant */
6269 if ((offset + start < 0) && use_end)
6270 {
6271 break;
6272 }
6273 nnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
6274 if (nnode)
6275 {
6276 tmp_offset = nnode->offset;
6277 }
6278 if (start <= 0)
6279 {
6280 /* Don't do visible adjustments because we are removing the visual
6281 * chars anyway and taking those into account */
6282 _evas_textblock_node_format_remove(o, itr, 0);
6283 }
6284 start -= tmp_offset;
6285 itr = nnode;
6286 }
6287}
6288
6289/**
6290 * @internal
6291 * Returns the first format in the range between start and end in the textblock
6292 * n.
6293 *
6294 * @param o the textblock object.
6295 * @param n the text node the positinos refer to.
6296 * @param start the start of where to delete from.
6297 * @param end the end of the section to delete, if end == -1 it means the end of the string.
6298 */
6299static Evas_Object_Textblock_Node_Format *
6300_evas_textblock_node_text_get_first_format_between(
6301 Evas_Object_Textblock_Node_Text *n, int start, int end)
6302{
6303 Evas_Object_Textblock_Node_Format *itr;
6304 int use_end = 1;
6305 itr = n->format_node;
6306 if (end < 0) use_end = 0;
6307 while (itr && (itr->text_node == n))
6308 {
6309 start -= itr->offset;
6310 end -= itr->offset;
6311 if ((end <= 0) && use_end)
6312 {
6313 break;
6314 }
6315 if (start <= 0)
6316 {
6317 return itr;
6318 }
6319 itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next);
6320 }
6321 return NULL;
6322}
6323
6324/**
6325 * Removes a text node and the corresponding format nodes.
6326 *
6327 * @param o the textblock objec.t
6328 * @param n the node to remove.
6329 */
6330static void
6331_evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n)
6332{
6333 _evas_textblock_node_text_adjust_offsets_to_start(o, n, 0, -1);
6334
6335 o->text_nodes = _NODE_TEXT(eina_inlist_remove(
6336 EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n)));
6337 _evas_textblock_node_text_free(n);
6338}
6339
6340/**
6341 * @internal
6342 * Return the position where the formats starts at.
6343 *
6344 * @param fmt the format to return the position of.
6345 * @return the position of the format in the text node it points to.
6346 */
6347static size_t
6348_evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt)
6349{
6350 Evas_Object_Textblock_Node_Text *text;
6351 Evas_Object_Textblock_Node_Format *base_format;
6352 Evas_Object_Textblock_Node_Format *itr;
6353 size_t position = 0;
6354
6355 if (!fmt) return 0;
6356 /* Find the main format node */
6357 text = fmt->text_node;
6358 base_format = text->format_node;
6359 EINA_INLIST_FOREACH(base_format, itr)
6360 {
6361 if (itr == fmt)
6362 {
6363 break;
6364 }
6365 position += itr->offset;
6366 }
6367 return position + fmt->offset;
6368}
6369
6370EAPI int
6371evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur)
6372{
6373 Evas_Object_Textblock *o;
6374 Evas_Object_Textblock_Node_Text *n;
6375 size_t npos = 0;
6376
6377 if (!cur) return -1;
6378 if (!cur->node) return 0;
6379 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6380 n = o->text_nodes;
6381 while (n != cur->node)
6382 {
6383 npos += eina_ustrbuf_length_get(n->unicode);
6384 n = _NODE_TEXT(EINA_INLIST_GET(n)->next);
6385 }
6386 return npos + cur->pos;
6387}
6388
6389EAPI void
6390evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int _pos)
6391{
6392 Evas_Object_Textblock *o;
6393 Evas_Object_Textblock_Node_Text *n;
6394 size_t pos;
6395
6396 if (!cur) return;
6397 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6398
6399 if (_pos < 0)
6400 {
6401 pos = 0;
6402 }
6403 else
6404 {
6405 pos = (size_t) _pos;
6406 }
6407
6408 n = o->text_nodes;
6409 while (n && (pos >= eina_ustrbuf_length_get(n->unicode)))
6410 {
6411 pos -= eina_ustrbuf_length_get(n->unicode);
6412 n = _NODE_TEXT(EINA_INLIST_GET(n)->next);
6413 }
6414
6415 if (n)
6416 {
6417 cur->node = n;
6418 cur->pos = pos;
6419 }
6420 else if (o->text_nodes)
6421 {
6422 /* In case we went pass the last node, we need to put the cursor
6423 * at the absolute end. */
6424 Evas_Object_Textblock_Node_Text *last_n;
6425
6426 last_n = _NODE_TEXT(EINA_INLIST_GET(o->text_nodes)->last);
6427 pos = eina_ustrbuf_length_get(last_n->unicode);
6428
6429 cur->node = last_n;
6430 cur->pos = pos;
6431 }
6432
6433}
6434
6435EAPI Eina_Bool
6436evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line)
6437{
6438 Evas_Object_Textblock *o;
6439 Evas_Object_Textblock_Line *ln;
6440 Evas_Object_Textblock_Item *it;
6441
6442 if (!cur) return EINA_FALSE;
6443 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6444 if (!o->formatted.valid) _relayout(cur->obj);
6445
6446 ln = _find_layout_line_num(cur->obj, line);
6447 if (!ln) return EINA_FALSE;
6448 it = (Evas_Object_Textblock_Item *)ln->items;
6449 if (it)
6450 {
6451 cur->pos = it->text_pos;
6452 cur->node = it->text_node;
6453 }
6454 else
6455 {
6456 cur->pos = 0;
6457
6458 cur->node = o->text_nodes;
6459 }
6460 return EINA_TRUE;
6461}
6462
6463EAPI int
6464evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
6465{
6466 Eina_Inlist *l1, *l2;
6467
6468 if (!cur1) return 0;
6469 if (!cur2) return 0;
6470 if (cur1->obj != cur2->obj) return 0;
6471 if ((!cur1->node) || (!cur2->node)) return 0;
6472 if (cur1->node == cur2->node)
6473 {
6474 if (cur1->pos < cur2->pos) return -1; /* cur1 < cur2 */
6475 else if (cur1->pos > cur2->pos) return 1; /* cur2 < cur1 */
6476 return 0;
6477 }
6478 for (l1 = EINA_INLIST_GET(cur1->node),
6479 l2 = EINA_INLIST_GET(cur1->node); (l1) || (l2);)
6480 {
6481 if (l1 == EINA_INLIST_GET(cur2->node)) return 1; /* cur2 < cur 1 */
6482 else if (l2 == EINA_INLIST_GET(cur2->node)) return -1; /* cur1 < cur 2 */
6483 else if (!l1) return -1; /* cur1 < cur 2 */
6484 else if (!l2) return 1; /* cur2 < cur 1 */
6485 l1 = l1->prev;
6486 l2 = l2->next;
6487 }
6488 return 0;
6489}
6490
6491EAPI void
6492evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest)
6493{
6494 if (!cur) return;
6495 if (!cur_dest) return;
6496 if (cur->obj != cur_dest->obj) return;
6497 cur_dest->pos = cur->pos;
6498 cur_dest->node = cur->node;
6499
6500}
6501
6502
6503/* text controls */
6504/**
6505 * @internal
6506 * Free a text node. Shouldn't be used usually, it's better to use
6507 * @ref _evas_textblock_node_text_remove for most cases .
6508 *
6509 * @param n the text node to free
6510 * @see _evas_textblock_node_text_remove
6511 */
6512static void
6513_evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n)
6514{
6515 if (!n) return;
6516 eina_ustrbuf_free(n->unicode);
6517 if (n->utf8)
6518 free(n->utf8);
6519 if (n->par)
6520 n->par->text_node = NULL;
6521 free(n);
6522}
6523
6524/**
6525 * @internal
6526 * Create a new text node
6527 *
6528 * @return the new text node.
6529 */
6530static Evas_Object_Textblock_Node_Text *
6531_evas_textblock_node_text_new(void)
6532{
6533 Evas_Object_Textblock_Node_Text *n;
6534
6535 n = calloc(1, sizeof(Evas_Object_Textblock_Node_Text));
6536 n->unicode = eina_ustrbuf_new();
6537 /* We want to layout each paragraph at least once. */
6538 n->dirty = EINA_TRUE;
6539 n->is_new = EINA_TRUE;
6540
6541 return n;
6542}
6543
6544/**
6545 * @internal
6546 * Break a paragraph. This does not add a PS but only splits the paragraph
6547 * where a ps was just added!
6548 *
6549 * @param cur the cursor to break at.
6550 * @param fnode the format node of the PS just added.
6551 * @return Returns no value.
6552 */
6553static void
6554_evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur,
6555 Evas_Object_Textblock_Node_Format *fnode)
6556{
6557 Evas_Object_Textblock *o;
6558 Evas_Object_Textblock_Node_Text *n;
6559
6560 if (!cur) return;
6561 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6562
6563 n = _evas_textblock_node_text_new();
6564 o->text_nodes = _NODE_TEXT(eina_inlist_append_relative(
6565 EINA_INLIST_GET(o->text_nodes),
6566 EINA_INLIST_GET(n),
6567 EINA_INLIST_GET(cur->node)));
6568 /* Handle text and format changes. */
6569 if (cur->node)
6570 {
6571 Evas_Object_Textblock_Node_Format *nnode;
6572 size_t len, start;
6573 const Eina_Unicode *text;
6574
6575 /* If there was a format node in the delete range,
6576 * make it our format and update the text_node fields,
6577 * otherwise, use the paragraph separator
6578 * of the previous paragraph. */
6579 nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
6580 if (nnode && (nnode->text_node == cur->node))
6581 {
6582 n->format_node = nnode;
6583 nnode->offset--; /* We don't have to take the replacement char
6584 into account anymore */
6585 while (nnode && (nnode->text_node == cur->node))
6586 {
6587 nnode->text_node = n;
6588 nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next);
6589 }
6590 }
6591 else
6592 {
6593 n->format_node = fnode;
6594 }
6595
6596 /* cur->pos now points to the PS, move after. */
6597 start = cur->pos + 1;
6598 len = eina_ustrbuf_length_get(cur->node->unicode) - start;
6599 if (len > 0)
6600 {
6601 text = eina_ustrbuf_string_get(cur->node->unicode);
6602 eina_ustrbuf_append_length(n->unicode, text + start, len);
6603 eina_ustrbuf_remove(cur->node->unicode, start, start + len);
6604 cur->node->dirty = EINA_TRUE;
6605 }
6606 }
6607 else
6608 {
6609 fnode = o->format_nodes;
6610 if (fnode)
6611 {
6612 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->last);
6613 }
6614 n->format_node = fnode;
6615 }
6616}
6617
6618/**
6619 * @internal
6620 * Set the node and offset of all the curs after cur.
6621 *
6622 * @param cur the cursor.
6623 * @param n the current textblock node.
6624 * @param new_node the new node to set.
6625 */
6626static void
6627_evas_textblock_cursors_set_node(Evas_Object_Textblock *o,
6628 const Evas_Object_Textblock_Node_Text *n,
6629 Evas_Object_Textblock_Node_Text *new_node)
6630{
6631 Eina_List *l;
6632 Evas_Textblock_Cursor *data;
6633
6634 if (n == o->cursor->node)
6635 {
6636 o->cursor->pos = 0;
6637 o->cursor->node = new_node;
6638 }
6639 EINA_LIST_FOREACH(o->cursors, l, data)
6640 {
6641 if (n == data->node)
6642 {
6643 data->pos = 0;
6644 data->node = new_node;
6645 }
6646 }
6647}
6648
6649/**
6650 * @internal
6651 * Update the offset of all the cursors after cur.
6652 *
6653 * @param cur the cursor.
6654 * @param n the current textblock node.
6655 * @param start the starting pos.
6656 * @param offset how much to adjust (can be negative).
6657 */
6658static void
6659_evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur,
6660 const Evas_Object_Textblock_Node_Text *n,
6661 size_t start, int offset)
6662{
6663 Eina_List *l;
6664 Evas_Textblock_Cursor *data;
6665 Evas_Object_Textblock *o;
6666 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6667
6668 if (cur != o->cursor)
6669 {
6670 if ((n == o->cursor->node) &&
6671 (o->cursor->pos > start))
6672 {
6673 if ((offset < 0) && (o->cursor->pos <= (size_t) (-1 * offset)))
6674 {
6675 o->cursor->pos = 0;
6676 }
6677 else
6678 {
6679 o->cursor->pos += offset;
6680 }
6681 }
6682 }
6683 EINA_LIST_FOREACH(o->cursors, l, data)
6684 {
6685 if (data != cur)
6686 {
6687 if ((n == data->node) &&
6688 (data->pos > start))
6689 {
6690 if ((offset < 0) && (data->pos <= (size_t) (-1 * offset)))
6691 {
6692 data->pos = 0;
6693 }
6694 else
6695 {
6696 data->pos += offset;
6697 }
6698 }
6699 else if (!data->node)
6700 {
6701 data->node = o->text_nodes;
6702 data->pos = 0;
6703 }
6704 }
6705 }
6706}
6707
6708/**
6709 * @internal
6710 * Mark that the textblock has changed.
6711 *
6712 * @param o the textblock object.
6713 * @param obj the evas object.
6714 */
6715static void
6716_evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj)
6717{
6718 o->formatted.valid = 0;
6719 o->native.valid = 0;
6720 o->content_changed = 1;
6721 if (o->markup_text)
6722 {
6723 free(o->markup_text);
6724 o->markup_text = NULL;
6725 }
6726
6727 evas_object_change(obj);
6728}
6729
6730static void
6731_evas_textblock_invalidate_all(Evas_Object_Textblock *o)
6732{
6733 Evas_Object_Textblock_Node_Text *n;
6734
6735 EINA_INLIST_FOREACH(o->text_nodes, n)
6736 {
6737 n->dirty = EINA_TRUE;
6738 }
6739}
6740
6741EAPI int
6742evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text)
6743{
6744 Evas_Object_Textblock *o;
6745 Evas_Object_Textblock_Node_Text *n;
6746 Evas_Object_Textblock_Node_Format *fnode = NULL;
6747 Eina_Unicode *text;
6748 int len = 0;
6749
6750 if (!cur) return 0;
6751 text = eina_unicode_utf8_to_unicode(_text, &len);
6752 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6753
6754 n = cur->node;
6755 if (n)
6756 {
6757 Evas_Object_Textblock_Node_Format *nnode;
6758 fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
6759 fnode = _evas_textblock_node_format_last_at_off(fnode);
6760 /* find the node after the current in the same paragraph
6761 * either we find one and then take the next, or we try to get
6762 * the first for the paragraph which must be after our position */
6763 if (fnode)
6764 {
6765 if (!evas_textblock_cursor_format_is_visible_get(cur))
6766 {
6767 nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
6768 if (nnode && (nnode->text_node == n))
6769 {
6770 fnode = nnode;
6771 }
6772 else
6773 {
6774 fnode = NULL;
6775 }
6776 }
6777 }
6778 else
6779 {
6780 fnode = n->format_node;
6781 }
6782 }
6783 else if (o->text_nodes)
6784 {
6785 n = cur->node = o->text_nodes;
6786 cur->pos = 0;
6787 }
6788 else
6789 {
6790 n = _evas_textblock_node_text_new();
6791 o->text_nodes = _NODE_TEXT(eina_inlist_append(
6792 EINA_INLIST_GET(o->text_nodes),
6793 EINA_INLIST_GET(n)));
6794 cur->node = n;
6795 }
6796
6797 eina_ustrbuf_insert_length(n->unicode, text, len, cur->pos);
6798 /* Advance the formats */
6799 if (fnode && (fnode->text_node == cur->node))
6800 fnode->offset += len;
6801
6802 /* Update all the cursors after our position. */
6803 _evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, len);
6804
6805 _evas_textblock_changed(o, cur->obj);
6806 n->dirty = EINA_TRUE;
6807 free(text);
6808
6809 if (!o->cursor->node)
6810 o->cursor->node = o->text_nodes;
6811 return len;
6812}
6813
6814EAPI int
6815evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text)
6816{
6817 int len;
6818 /*append is essentially prepend without advancing */
6819 len = evas_textblock_cursor_text_append(cur, _text);
6820 cur->pos += len; /*Advance */
6821 return len;
6822}
6823
6824/**
6825 * @internal
6826 * Free a format node
6827 *
6828 * @param o the textblock object
6829 * @param n the format node to free
6830 */
6831static void
6832_evas_textblock_node_format_free(Evas_Object_Textblock *o,
6833 Evas_Object_Textblock_Node_Format *n)
6834{
6835 if (!n) return;
6836 eina_stringshare_del(n->format);
6837 eina_stringshare_del(n->orig_format);
6838 if (n->anchor == ANCHOR_ITEM)
6839 o->anchors_item = eina_list_remove(o->anchors_item, n);
6840 else if (n->anchor == ANCHOR_A)
6841 o->anchors_a = eina_list_remove(o->anchors_a, n);
6842 free(n);
6843}
6844
6845/**
6846 * @internal
6847 * Create a new format node.
6848 *
6849 * @param format the text to create the format node from.
6850 * @param o the textblock object.
6851 * @return Returns the new format node
6852 */
6853static Evas_Object_Textblock_Node_Format *
6854_evas_textblock_node_format_new(Evas_Object_Textblock *o, const char *_format)
6855{
6856 Evas_Object_Textblock_Node_Format *n;
6857 const char *format = _format;
6858
6859 n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format));
6860 /* Create orig_format and format */
6861 if (format[0] == '<')
6862 {
6863 const char *match;
6864 size_t format_len;
6865 size_t replace_len;
6866
6867 format++; /* Advance after '<' */
6868 format_len = strlen(format);
6869 if (format[format_len - 1] == '>')
6870 format_len--; /* We don't care about '>' */
6871
6872 match = _style_match_tag(o->style, format, format_len, &replace_len);
6873 if (match)
6874 {
6875 if ((match[0] == '+') || (match[0] == '-'))
6876 {
6877 char *norm_format;
6878 norm_format = malloc(format_len + 2 + 1);
6879 memcpy(norm_format, match, 2);
6880 memcpy(norm_format + 2, format, format_len);
6881 norm_format[format_len + 2] = '\0';
6882 n->orig_format =
6883 eina_stringshare_add_length(norm_format, format_len + 2);
6884 free(norm_format);
6885 }
6886 else
6887 {
6888 n->orig_format =
6889 eina_stringshare_add_length(format, format_len);
6890 }
6891 n->format = eina_stringshare_add(match);
6892 }
6893 else
6894 {
6895 char *norm_format;
6896
6897 norm_format = malloc(format_len + 2 + 1);
6898 if (norm_format)
6899 {
6900 if (format[0] == '/')
6901 {
6902 memcpy(norm_format, "- ", 2);
6903 memcpy(norm_format + 2, format + 1, format_len - 1);
6904 norm_format[format_len + 2 - 1] = '\0';
6905 }
6906 else
6907 {
6908 memcpy(norm_format, "+ ", 2);
6909 memcpy(norm_format + 2, format, format_len);
6910 norm_format[format_len + 2] = '\0';
6911 }
6912 n->orig_format = eina_stringshare_add(norm_format);
6913 free(norm_format);
6914 }
6915 n->format = eina_stringshare_ref(n->orig_format);
6916 }
6917 }
6918 /* Just use as is, it's a special format. */
6919 else
6920 {
6921 n->orig_format = eina_stringshare_add(format);
6922 n->format = eina_stringshare_ref(n->orig_format);
6923 }
6924
6925 format = n->format;
6926
6927 _evas_textblock_format_is_visible(n, format);
6928 if (n->anchor == ANCHOR_A)
6929 {
6930 o->anchors_a = eina_list_append(o->anchors_a, n);
6931 }
6932 else if (n->anchor == ANCHOR_ITEM)
6933 {
6934 o->anchors_item = eina_list_append(o->anchors_item, n);
6935 }
6936 n->is_new = EINA_TRUE;
6937
6938 return n;
6939}
6940
6941static Eina_Bool
6942_evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur)
6943{
6944 const Eina_Unicode *text;
6945
6946 if (!cur) return EINA_FALSE;
6947 if (!cur->node) return EINA_FALSE;
6948 text = eina_ustrbuf_string_get(cur->node->unicode);
6949 return ((text[cur->pos] == 0) && (!EINA_INLIST_GET(cur->node)->next)) ?
6950 EINA_TRUE : EINA_FALSE;
6951}
6952
6953EAPI Eina_Bool
6954evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format)
6955{
6956 Evas_Object_Textblock *o;
6957 Evas_Object_Textblock_Node_Format *n;
6958 Eina_Bool is_visible;
6959
6960 if (!cur) return EINA_FALSE;
6961 if ((!format) || (format[0] == 0)) return EINA_FALSE;
6962 o = (Evas_Object_Textblock *)(cur->obj->object_data);
6963 /* We should always have at least one text node */
6964 if (!o->text_nodes)
6965 {
6966 evas_textblock_cursor_text_prepend(cur, "");
6967 }
6968
6969 n = _evas_textblock_node_format_new(o, format);
6970 is_visible = n->visible;
6971 format = n->format;
6972 if (!cur->node)
6973 {
6974 o->format_nodes = _NODE_FORMAT(eina_inlist_append(
6975 EINA_INLIST_GET(o->format_nodes),
6976 EINA_INLIST_GET(n)));
6977 cur->pos = 0;
6978 n->text_node = (EINA_INLIST_GET(n)->prev) ?
6979 _NODE_FORMAT(EINA_INLIST_GET(n)->prev)->text_node :
6980 o->text_nodes;
6981 cur->node = n->text_node;
6982 }
6983 else
6984 {
6985 Evas_Object_Textblock_Node_Format *fmt;
6986 fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
6987 n->text_node = cur->node;
6988 if (!fmt)
6989 {
6990 o->format_nodes = _NODE_FORMAT(eina_inlist_prepend(
6991 EINA_INLIST_GET(o->format_nodes),
6992 EINA_INLIST_GET(n)));
6993 n->offset = cur->pos;
6994 }
6995 else
6996 {
6997 if (evas_textblock_cursor_format_is_visible_get(cur))
6998 {
6999 o->format_nodes = _NODE_FORMAT(eina_inlist_prepend_relative(
7000 EINA_INLIST_GET(o->format_nodes),
7001 EINA_INLIST_GET(n),
7002 EINA_INLIST_GET(fmt)
7003 ));
7004 n->offset = fmt->offset;
7005 if (fmt->text_node->format_node == fmt)
7006 {
7007 fmt->text_node->format_node = n;
7008 }
7009 }
7010 else
7011 {
7012 fmt = _evas_textblock_node_format_last_at_off(fmt);
7013 o->format_nodes = _NODE_FORMAT(eina_inlist_append_relative(
7014 EINA_INLIST_GET(o->format_nodes),
7015 EINA_INLIST_GET(n),
7016 EINA_INLIST_GET(fmt)
7017 ));
7018 if (fmt->text_node != cur->node)
7019 {
7020 n->offset = cur->pos;
7021 }
7022 else
7023 {
7024 n->offset = cur->pos -
7025 _evas_textblock_node_format_pos_get(fmt);
7026 }
7027 }
7028 }
7029 /* Adjust differently if we insert a format char */
7030 if (is_visible)
7031 {
7032 _evas_textblock_node_format_adjust_offset(o, cur->node, n,
7033 -(n->offset - 1));
7034 }
7035 else
7036 {
7037 _evas_textblock_node_format_adjust_offset(o, cur->node, n,
7038 -n->offset);
7039 }
7040
7041 if (!fmt || (fmt->text_node != cur->node))
7042 {
7043 cur->node->format_node = n;
7044 }
7045 }
7046 if (is_visible && cur->node)
7047 {
7048 Eina_Unicode insert_char;
7049 /* Insert a visual representation according to the type of the
7050 format */
7051 if (_IS_PARAGRAPH_SEPARATOR(o, format))
7052 insert_char = _PARAGRAPH_SEPARATOR;
7053 else if (_IS_LINE_SEPARATOR(format))
7054 insert_char = '\n';
7055 else if (_IS_TAB(format))
7056 insert_char = '\t';
7057 else
7058 insert_char = EVAS_TEXTBLOCK_REPLACEMENT_CHAR;
7059
7060 eina_ustrbuf_insert_char(cur->node->unicode, insert_char, cur->pos);
7061
7062 /* Advance all the cursors after our cursor */
7063 _evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1);
7064 if (_IS_PARAGRAPH_SEPARATOR(o, format))
7065 {
7066 _evas_textblock_cursor_break_paragraph(cur, n);
7067 }
7068 else
7069 {
7070 /* Handle visible format nodes here */
7071 cur->node->dirty = EINA_TRUE;
7072 n->is_new = EINA_FALSE;
7073 }
7074 }
7075 else
7076 {
7077 o->format_changed = EINA_TRUE;
7078 }
7079
7080 _evas_textblock_changed(o, cur->obj);
7081
7082 if (!o->cursor->node)
7083 o->cursor->node = o->text_nodes;
7084 return is_visible;
7085}
7086
7087EAPI Eina_Bool
7088evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format)
7089{
7090 Eina_Bool is_visible;
7091 /* append is essentially prepend without advancing */
7092 is_visible = evas_textblock_cursor_format_append(cur, format);
7093 if (is_visible)
7094 {
7095 /* Advance after the replacement char */
7096 evas_textblock_cursor_char_next(cur);
7097 }
7098
7099 return is_visible;
7100}
7101
7102
7103EAPI void
7104evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur)
7105{
7106 Evas_Object_Textblock *o;
7107 Evas_Object_Textblock_Node_Text *n, *n2;
7108 const Eina_Unicode *text;
7109 int chr, ind, ppos;
7110
7111 if (!cur || !cur->node) return;
7112 o = (Evas_Object_Textblock *)(cur->obj->object_data);
7113 n = cur->node;
7114
7115 text = eina_ustrbuf_string_get(n->unicode);
7116 ind = cur->pos;
7117 if (text[ind])
7118 chr = text[ind++];
7119 else
7120 chr = 0;
7121
7122 if (chr == 0) return;
7123 ppos = cur->pos;
7124 eina_ustrbuf_remove(n->unicode, cur->pos, ind);
7125 /* Remove a format node if needed, and remove the char only if the
7126 * fmt node is not visible */
7127 {
7128 Eina_Bool should_merge = EINA_FALSE;
7129 Evas_Object_Textblock_Node_Format *fmt, *fmt2;
7130 fmt = _evas_textblock_cursor_node_format_at_pos_get(cur);
7131 if (fmt)
7132 {
7133 const char *format = NULL;
7134 Evas_Object_Textblock_Node_Format *last_fmt;
7135 /* If there's a PS it must be the last become it delimits paragraphs */
7136 last_fmt = _evas_textblock_node_format_last_at_off(fmt);
7137 format = last_fmt->format;
7138 if (format && _IS_PARAGRAPH_SEPARATOR(o, format))
7139 {
7140 /* If it was a paragraph separator, we should merge the
7141 * current with the next, there must be a next. */
7142 should_merge = EINA_TRUE;
7143 }
7144 /* If a singnular, mark as invisible, so we'll delete it. */
7145 if (!format || ((*format != '+') && (*format != '-')))
7146 {
7147 last_fmt->visible = EINA_FALSE;
7148 }
7149 }
7150
7151 fmt2 = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur);
7152 fmt2 = _evas_textblock_node_format_last_at_off(fmt2);
7153 _evas_textblock_node_format_adjust_offset(o, cur->node, fmt2,
7154 -(ind - cur->pos));
7155
7156 if (should_merge)
7157 {
7158 _evas_textblock_cursor_nodes_merge(cur);
7159 }
7160
7161 _evas_textblock_node_format_remove_matching(o, fmt);
7162 }
7163
7164 if (cur->pos == eina_ustrbuf_length_get(n->unicode))
7165 {
7166 n2 = _NODE_TEXT(EINA_INLIST_GET(n)->next);
7167 if (n2)
7168 {
7169 cur->node = n2;
7170 cur->pos = 0;
7171 }
7172 }
7173
7174 _evas_textblock_cursors_update_offset(cur, n, ppos, -(ind - ppos));
7175 _evas_textblock_changed(o, cur->obj);
7176 cur->node->dirty = EINA_TRUE;
7177}
7178
7179EAPI void
7180evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2)
7181{
7182 Evas_Object_Textblock_Node_Format *fnode = NULL;
7183 Evas_Object_Textblock *o;
7184 Evas_Object_Textblock_Node_Text *n1, *n2;
7185 Eina_Bool should_merge = EINA_FALSE, reset_cursor = EINA_FALSE;
7186
7187 if (!cur1 || !cur1->node) return;
7188 if (!cur2 || !cur2->node) return;
7189 if (cur1->obj != cur2->obj) return;
7190 o = (Evas_Object_Textblock *)(cur1->obj->object_data);
7191 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
7192 {
7193 Evas_Textblock_Cursor *tc;
7194
7195 tc = cur1;
7196 cur1 = cur2;
7197 cur2 = tc;
7198 }
7199 n1 = cur1->node;
7200 n2 = cur2->node;
7201 if ((evas_textblock_cursor_compare(o->cursor, cur1) >= 0) &&
7202 (evas_textblock_cursor_compare(cur2, o->cursor) >= 0))
7203 {
7204 reset_cursor = EINA_TRUE;
7205 }
7206
7207
7208 if (n1 == n2)
7209 {
7210 if ((cur1->pos == 0) &&
7211 (cur2->pos == eina_ustrbuf_length_get(n1->unicode)))
7212 {
7213 _evas_textblock_node_text_remove_formats_between(o, n1, 0, -1);
7214 }
7215 else
7216 {
7217 should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o,
7218 n1, cur1->pos, cur2->pos);
7219 }
7220 eina_ustrbuf_remove(n1->unicode, cur1->pos, cur2->pos);
7221 _evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos, - (cur2->pos - cur1->pos));
7222 }
7223 else
7224 {
7225 Evas_Object_Textblock_Node_Text *n;
7226 int len;
7227 _evas_textblock_node_text_adjust_offsets_to_start(o, n1, cur1->pos, -1);
7228 n = _NODE_TEXT(EINA_INLIST_GET(n1)->next);
7229 /* Remove all the text nodes between */
7230 while (n && (n != n2))
7231 {
7232 Evas_Object_Textblock_Node_Text *nnode;
7233
7234 nnode = _NODE_TEXT(EINA_INLIST_GET(n)->next);
7235 _evas_textblock_cursors_set_node(o, n, n1);
7236 _evas_textblock_node_text_remove(o, n);
7237 n = nnode;
7238 }
7239 should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o, n2,
7240 0, cur2->pos);
7241
7242 /* Remove the formats and the strings in the first and last nodes */
7243 len = eina_ustrbuf_length_get(n1->unicode);
7244 eina_ustrbuf_remove(n1->unicode, cur1->pos, len);
7245 eina_ustrbuf_remove(n2->unicode, 0, cur2->pos);
7246 /* Merge the nodes because we removed the PS */
7247 _evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos,
7248 - cur1->pos);
7249 _evas_textblock_cursors_update_offset(cur2, cur2->node, 0, - cur2->pos);
7250 _evas_textblock_nodes_merge(o, n1);
7251 }
7252 fnode = _evas_textblock_cursor_node_format_at_pos_get(cur1);
7253
7254 if (should_merge)
7255 {
7256 /* We call this function instead of the cursor one because we already
7257 * updated the cursors */
7258 _evas_textblock_nodes_merge(o, n1);
7259 }
7260 _evas_textblock_node_format_remove_matching(o, fnode);
7261
7262 evas_textblock_cursor_copy(cur1, cur2);
7263 if (reset_cursor)
7264 evas_textblock_cursor_copy(cur1, o->cursor);
7265
7266 _evas_textblock_changed(o, cur1->obj);
7267 n1->dirty = n2->dirty = EINA_TRUE;
7268}
7269
7270
7271EAPI char *
7272evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur)
7273{
7274 const Eina_Unicode *ustr;
7275 Eina_Unicode buf[2];
7276 char *s;
7277 if (!cur || !cur->node) return NULL;
7278 if (evas_textblock_cursor_format_is_visible_get(cur))
7279 {
7280 size_t len;
7281 const char *fstr;
7282 char *ret;
7283 int pop = 0;
7284 fstr = evas_textblock_node_format_text_get(
7285 _evas_textblock_node_visible_at_pos_get(
7286 evas_textblock_cursor_format_get(cur)));
7287
7288 if (!fstr)
7289 return NULL;
7290
7291 if (*fstr == '-') pop = 1;
7292 while ((*fstr == ' ') || (*fstr == '+') || (*fstr == '-')) fstr++;
7293 len = strlen(fstr);
7294
7295 {
7296 char *tmp;
7297 if (pop)
7298 {
7299 ret = tmp = malloc(len + 3 + 1); /* </> and the null */
7300 memcpy(tmp, "</", 2);
7301 tmp += 2;
7302 }
7303 else
7304 {
7305 ret = tmp = malloc(len + 2 + 1); /* <> and the null */
7306 *tmp = '<';
7307 tmp++;
7308 }
7309 memcpy(tmp, fstr, len);
7310 memcpy(tmp + len, ">", 2); /* Including the null */
7311 }
7312
7313 return ret;
7314 }
7315
7316 ustr = eina_ustrbuf_string_get(cur->node->unicode);
7317 buf[0] = ustr[cur->pos];
7318 buf[1] = 0;
7319 s = eina_unicode_unicode_to_utf8(buf, NULL);
7320
7321 return s;
7322}
7323
7324static char *
7325_evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
7326{
7327 Evas_Object_Textblock *o;
7328 Evas_Object_Textblock_Node_Text *tnode;
7329 Eina_Strbuf *buf;
7330 Evas_Textblock_Cursor *cur2;
7331 buf = eina_strbuf_new();
7332
7333 if (!cur1 || !cur1->node) return NULL;
7334 if (!_cur2 || !_cur2->node) return NULL;
7335 if (cur1->obj != _cur2->obj) return NULL;
7336 o = (Evas_Object_Textblock *)(cur1->obj->object_data);
7337 if (evas_textblock_cursor_compare(cur1, _cur2) > 0)
7338 {
7339 const Evas_Textblock_Cursor *tc;
7340
7341 tc = cur1;
7342 cur1 = _cur2;
7343 _cur2 = tc;
7344 }
7345 /* Work on a local copy of the cur */
7346 cur2 = alloca(sizeof(Evas_Textblock_Cursor));
7347 cur2->obj = _cur2->obj;
7348 evas_textblock_cursor_copy(_cur2, cur2);
7349
7350 /* Parse the text between the cursors. */
7351 for (tnode = cur1->node ; tnode ;
7352 tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next))
7353 {
7354 Evas_Object_Textblock_Node_Format *fnode;
7355 Eina_Unicode *text_base, *text;
7356 int off = 0;
7357
7358 text_base = text =
7359 eina_unicode_strndup(eina_ustrbuf_string_get(tnode->unicode),
7360 eina_ustrbuf_length_get(tnode->unicode));
7361 if (tnode == cur2->node)
7362 {
7363 fnode = _evas_textblock_node_text_get_first_format_between(tnode,
7364 cur1->pos, cur2->pos);
7365 }
7366 else if (tnode == cur1->node)
7367 {
7368 fnode = _evas_textblock_node_text_get_first_format_between(tnode,
7369 cur1->pos, -1);
7370 }
7371 else
7372 {
7373 fnode = _evas_textblock_node_text_get_first_format_between(tnode,
7374 0, -1);
7375 }
7376 /* Init the offset so the first one will count starting from cur1->pos
7377 * and not the previous format node */
7378 if (tnode == cur1->node)
7379 {
7380 if (fnode)
7381 {
7382 off = _evas_textblock_node_format_pos_get(fnode) -
7383 cur1->pos - fnode->offset;
7384 }
7385 text += cur1->pos;
7386 }
7387 else
7388 {
7389 off = 0;
7390 }
7391 while (fnode && (fnode->text_node == tnode))
7392 {
7393 Eina_Unicode tmp_ch;
7394 off += fnode->offset;
7395 if ((tnode == cur2->node) &&
7396 ((size_t) (text - text_base + off) >= cur2->pos))
7397 {
7398 break;
7399 }
7400 /* No need to skip on the first run */
7401 tmp_ch = text[off];
7402 text[off] = 0; /* Null terminate the part of the string */
7403 _markup_get_text_append(buf, text);
7404 _markup_get_format_append(o, buf, fnode);
7405 text[off] = tmp_ch; /* Restore the char */
7406 text += off;
7407 if (fnode->visible)
7408 {
7409 off = -1;
7410 text++;
7411 }
7412 else
7413 {
7414 off = 0;
7415 }
7416 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
7417 }
7418 /* If we got to the last node, stop and add the rest outside */
7419 if (cur2->node == tnode)
7420 {
7421 /* Add the rest, skip replacement */
7422 /* Don't go past the second cursor pos */
7423 text_base[cur2->pos] = '\0';
7424 _markup_get_text_append(buf, text);
7425 free(text_base);
7426 break;
7427 }
7428 else
7429 {
7430 /* Add the rest, skip replacement */
7431 _markup_get_text_append(buf, text);
7432 free(text_base);
7433 }
7434 }
7435 /* return the string */
7436 {
7437 char *ret;
7438 ret = eina_strbuf_string_steal(buf);
7439 eina_strbuf_free(buf);
7440 return ret;
7441 }
7442}
7443
7444static char *
7445_evas_textblock_cursor_range_text_plain_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2)
7446{
7447 Eina_UStrbuf *buf;
7448 Evas_Object_Textblock_Node_Text *n1, *n2;
7449 Evas_Textblock_Cursor *cur2;
7450
7451 buf = eina_ustrbuf_new();
7452
7453 if (!cur1 || !cur1->node) return NULL;
7454 if (!_cur2 || !_cur2->node) return NULL;
7455 if (cur1->obj != _cur2->obj) return NULL;
7456 if (evas_textblock_cursor_compare(cur1, _cur2) > 0)
7457 {
7458 const Evas_Textblock_Cursor *tc;
7459
7460 tc = cur1;
7461 cur1 = _cur2;
7462 _cur2 = tc;
7463 }
7464 n1 = cur1->node;
7465 n2 = _cur2->node;
7466 /* Work on a local copy of the cur */
7467 cur2 = alloca(sizeof(Evas_Textblock_Cursor));
7468 cur2->obj = _cur2->obj;
7469 evas_textblock_cursor_copy(_cur2, cur2);
7470
7471
7472 if (n1 == n2)
7473 {
7474 const Eina_Unicode *tmp;
7475 tmp = eina_ustrbuf_string_get(n1->unicode);
7476 eina_ustrbuf_append_length(buf, tmp + cur1->pos, cur2->pos - cur1->pos);
7477 }
7478 else
7479 {
7480 const Eina_Unicode *tmp;
7481 tmp = eina_ustrbuf_string_get(n1->unicode);
7482 eina_ustrbuf_append(buf, tmp + cur1->pos);
7483 n1 = _NODE_TEXT(EINA_INLIST_GET(n1)->next);
7484 while (n1 != n2)
7485 {
7486 tmp = eina_ustrbuf_string_get(n1->unicode);
7487 eina_ustrbuf_append_length(buf, tmp,
7488 eina_ustrbuf_length_get(n1->unicode));
7489 n1 = _NODE_TEXT(EINA_INLIST_GET(n1)->next);
7490 }
7491 tmp = eina_ustrbuf_string_get(n2->unicode);
7492 eina_ustrbuf_append_length(buf, tmp, cur2->pos);
7493 }
7494
7495 /* Free and return */
7496 {
7497 char *ret;
7498 ret = eina_unicode_unicode_to_utf8(eina_ustrbuf_string_get(buf), NULL);
7499 eina_ustrbuf_free(buf);
7500 return ret;
7501 }
7502}
7503
7504EAPI Eina_List *
7505evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
7506{
7507 Evas_Object *obj = cur1->obj;
7508 Eina_List *ret = NULL;
7509 Evas_Object_Textblock_Node_Text *n1, *n2;
7510 Evas_Object_Textblock_Node_Format *first, *last;
7511 TB_HEAD_RETURN(NULL);
7512 if (!cur1 || !cur1->node) return NULL;
7513 if (!cur2 || !cur2->node) return NULL;
7514 if (cur1->obj != cur2->obj) return NULL;
7515 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
7516 {
7517 const Evas_Textblock_Cursor *tc;
7518
7519 tc = cur1;
7520 cur1 = cur2;
7521 cur2 = tc;
7522 }
7523 n1 = cur1->node;
7524 n2 = cur2->node;
7525
7526 /* FIXME: Change first and last getting to format_before_or_at_pos_get */
7527
7528 last = n2->format_node;
7529
7530 /* If n2->format_node is NULL, we don't have formats in the tb/range. */
7531 if (!last)
7532 return NULL;
7533 /* If the found format is on our text node, we should go to the last
7534 * one, otherwise, the one we found is good enough. */
7535 if (last->text_node == n2)
7536 {
7537 Evas_Object_Textblock_Node_Format *fnode = last;
7538 while (fnode && (fnode->text_node == n2))
7539 {
7540 last = fnode;
7541 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
7542 }
7543 }
7544
7545 /* If the first format node is within the range (i.e points to n1) or if
7546 * we have other formats in the range, go through them */
7547 first = n1->format_node;
7548 if ((first->text_node == n1) || (first != last))
7549 {
7550 Evas_Object_Textblock_Node_Format *fnode = first;
7551 /* Go to the first one in the range */
7552 if (first->text_node != n1)
7553 {
7554 first = _NODE_FORMAT(EINA_INLIST_GET(first)->next);
7555 }
7556
7557 while (fnode)
7558 {
7559 ret = eina_list_append(ret, fnode);
7560 if (fnode == last)
7561 break;
7562 fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next);
7563 }
7564 }
7565
7566 return ret;
7567
7568}
7569
7570EAPI char *
7571evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format)
7572{
7573 if (format == EVAS_TEXTBLOCK_TEXT_MARKUP)
7574 return _evas_textblock_cursor_range_text_markup_get(cur1, cur2);
7575 else if (format == EVAS_TEXTBLOCK_TEXT_PLAIN)
7576 return _evas_textblock_cursor_range_text_plain_get(cur1, cur2);
7577 else
7578 return NULL; /* Not yet supported */
7579}
7580
7581EAPI const char *
7582evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur)
7583{
7584 Evas_Textblock_Cursor cur1, cur2;
7585 if (!cur) return NULL;
7586 if (!cur->node) return NULL;
7587 if (cur->node->utf8)
7588 {
7589 free(cur->node->utf8);
7590 }
7591 cur1.obj = cur2.obj = cur->obj;
7592 cur1.node = cur2.node = cur->node;
7593 evas_textblock_cursor_paragraph_char_first(&cur1);
7594 evas_textblock_cursor_paragraph_char_last(&cur2);
7595
7596 cur->node->utf8 = evas_textblock_cursor_range_text_get(&cur1, &cur2,
7597 EVAS_TEXTBLOCK_TEXT_MARKUP);
7598 return cur->node->utf8;
7599}
7600
7601EAPI int
7602evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur)
7603{
7604 int len;
7605 if (!cur) return -1;
7606 if (!cur->node) return -1;
7607 len = eina_ustrbuf_length_get(cur->node->unicode);
7608
7609 if (EINA_INLIST_GET(cur->node)->next)
7610 return len - 1; /* Remove the paragraph separator */
7611 else
7612 return len;
7613}
7614
7615EAPI const Evas_Object_Textblock_Node_Format *
7616evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur)
7617{
7618 if (!cur) return NULL;
7619 if (!cur->node) return NULL;
7620 return _evas_textblock_cursor_node_format_at_pos_get(cur);
7621}
7622
7623EAPI const char *
7624evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt)
7625{
7626 if (!fmt) return NULL;
7627 return fmt->orig_format;
7628}
7629
7630EAPI void
7631evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt)
7632{
7633 if (!fmt || !cur) return;
7634 cur->node = fmt->text_node;
7635 cur->pos = _evas_textblock_node_format_pos_get(fmt);
7636}
7637
7638EAPI Eina_Bool
7639evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur)
7640{
7641 const Eina_Unicode *text;
7642
7643 if (!cur) return EINA_FALSE;
7644 if (!cur->node) return EINA_FALSE;
7645 text = eina_ustrbuf_string_get(cur->node->unicode);
7646 return EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(text[cur->pos]);
7647}
7648
7649EAPI int
7650evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype)
7651{
7652 int ret = -1;
7653 const Evas_Textblock_Cursor *dir_cur;
7654 Evas_Textblock_Cursor cur2;
7655 Evas_Object_Textblock *o;
7656 o = (Evas_Object_Textblock *)(cur->obj->object_data);
7657 if (!o->formatted.valid) _relayout(cur->obj);
7658
7659 dir_cur = cur;
7660 if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER)
7661 {
7662 ret = evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch);
7663 }
7664 else if (ctype == EVAS_TEXTBLOCK_CURSOR_BEFORE)
7665 {
7666 /* In the case of a "before cursor", we should get the coordinates
7667 * of just after the previous char (which in bidi text may not be
7668 * just before the current char). */
7669 Evas_Coord x, y, h, w;
7670 Evas_Object_Textblock_Node_Format *fmt;
7671
7672 /* If it's at the end of the line, we want to get the position, not
7673 * the position of the previous */
7674 if ((cur->pos > 0) && !_evas_textblock_cursor_is_at_the_end(cur))
7675 {
7676 Eina_Bool before_char = EINA_FALSE;
7677 cur2.obj = cur->obj;
7678 evas_textblock_cursor_copy(cur, &cur2);
7679 evas_textblock_cursor_char_prev(&cur2);
7680
7681 fmt = _evas_textblock_cursor_node_format_at_pos_get(&cur2);
7682
7683 if (!fmt || !_IS_LINE_SEPARATOR(fmt->format))
7684 {
7685 dir_cur = &cur2;
7686 before_char = EINA_FALSE;
7687 }
7688 else
7689 {
7690 before_char = EINA_TRUE;
7691 }
7692 ret = evas_textblock_cursor_pen_geometry_get(
7693 dir_cur, &x, &y, &w, &h);
7694#ifdef BIDI_SUPPORT
7695 /* Adjust if the char is an rtl char */
7696 if (ret >= 0)
7697 {
7698 Eina_Bool is_rtl = EINA_FALSE;
7699 if (dir_cur->node->par->is_bidi)
7700 {
7701 Evas_Object_Textblock_Line *ln;
7702 Evas_Object_Textblock_Item *it;
7703 _find_layout_item_match(dir_cur, &ln, &it);
7704 if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
7705 (_ITEM_TEXT(it)->text_props.bidi.dir ==
7706 EVAS_BIDI_DIRECTION_RTL))
7707 is_rtl = EINA_TRUE;
7708 else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
7709 (_ITEM_FORMAT(it)->bidi_dir ==
7710 EVAS_BIDI_DIRECTION_RTL))
7711 is_rtl = EINA_TRUE;
7712 }
7713
7714 if ((!before_char && is_rtl) ||
7715 (before_char && !is_rtl))
7716 {
7717 /* Just don't advance the width */
7718 w = 0;
7719 }
7720 }
7721#endif
7722 }
7723 else if (cur->pos == 0)
7724 {
7725 ret = evas_textblock_cursor_pen_geometry_get(
7726 dir_cur, &x, &y, &w, &h);
7727#ifdef BIDI_SUPPORT
7728 Eina_Bool is_rtl = EINA_FALSE;
7729 if (dir_cur->node && dir_cur->node->par->is_bidi)
7730 {
7731 Evas_Object_Textblock_Line *ln;
7732 Evas_Object_Textblock_Item *it;
7733 _find_layout_item_match(dir_cur, &ln, &it);
7734 if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
7735 (_ITEM_TEXT(it)->text_props.bidi.dir ==
7736 EVAS_BIDI_DIRECTION_RTL))
7737 is_rtl = EINA_TRUE;
7738 else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
7739 (_ITEM_FORMAT(it)->bidi_dir ==
7740 EVAS_BIDI_DIRECTION_RTL))
7741 is_rtl = EINA_TRUE;
7742 }
7743
7744 /* Adjust if the char is an rtl char */
7745 if ((ret >= 0) && (!is_rtl))
7746 {
7747 /* Just don't advance the width */
7748 w = 0;
7749 }
7750#endif
7751 }
7752 else
7753 {
7754 ret = evas_textblock_cursor_pen_geometry_get(
7755 dir_cur, &x, &y, &w, &h);
7756 }
7757 if (ret >= 0)
7758 {
7759 if (cx) *cx = x + w;
7760 if (cy) *cy = y;
7761 if (cw) *cw = 0;
7762 if (ch) *ch = h;
7763 }
7764 }
7765
7766 if (dir && dir_cur && dir_cur->node)
7767 {
7768#ifdef BIDI_SUPPORT
7769 Eina_Bool is_rtl = EINA_FALSE;
7770 if (dir_cur->node->par->is_bidi)
7771 {
7772 Evas_Object_Textblock_Line *ln;
7773 Evas_Object_Textblock_Item *it;
7774 _find_layout_item_match(dir_cur, &ln, &it);
7775 if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
7776 (_ITEM_TEXT(it)->text_props.bidi.dir ==
7777 EVAS_BIDI_DIRECTION_RTL))
7778 is_rtl = EINA_TRUE;
7779 else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
7780 (_ITEM_FORMAT(it)->bidi_dir ==
7781 EVAS_BIDI_DIRECTION_RTL))
7782 is_rtl = EINA_TRUE;
7783 }
7784
7785 if (_evas_textblock_cursor_is_at_the_end(dir_cur) && (dir_cur->pos > 0))
7786 {
7787 *dir = (is_rtl) ?
7788 EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
7789 }
7790 else if (dir_cur->pos > 0)
7791 {
7792 *dir = (is_rtl) ?
7793 EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR;
7794 }
7795 else
7796#endif
7797 {
7798 *dir = EVAS_BIDI_DIRECTION_LTR;
7799 }
7800 }
7801 return ret;
7802}
7803
7804/**
7805 * @internal
7806 * Returns the geometry/pen position (depending on query_func) of the char
7807 * at pos.
7808 *
7809 * @param cur the position of the char.
7810 * @param query_func the query function to use.
7811 * @param cx the x of the char (or pen_x in the case of pen position).
7812 * @param cy the y of the char.
7813 * @param cw the w of the char (or advance in the case pen position).
7814 * @param ch the h of the char.
7815 * @return line number of the char on success, -1 on error.
7816 */
7817static int
7818_evas_textblock_cursor_char_pen_geometry_common_get(int (*query_func) (void *data, Evas_Font_Set *font, const Evas_Text_Props *intl_props, int pos, int *cx, int *cy, int *cw, int *ch), const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
7819{
7820 Evas_Object_Textblock *o;
7821 Evas_Object_Textblock_Line *ln = NULL;
7822 Evas_Object_Textblock_Item *it = NULL;
7823 Evas_Object_Textblock_Text_Item *ti = NULL;
7824 Evas_Object_Textblock_Format_Item *fi = NULL;
7825 int x = 0, y = 0, w = 0, h = 0;
7826 int pos;
7827 Eina_Bool previous_format;
7828
7829 if (!cur) return -1;
7830 o = (Evas_Object_Textblock *)(cur->obj->object_data);
7831 if (!o->formatted.valid) _relayout(cur->obj);
7832
7833 if (!cur->node)
7834 {
7835 if (!o->text_nodes)
7836 {
7837 if (!o->paragraphs) return -1;
7838 ln = o->paragraphs->lines;
7839 if (!ln) return -1;
7840 if (cx) *cx = ln->x;
7841 if (cy) *cy = ln->par->y + ln->y;
7842 if (cw) *cw = ln->w;
7843 if (ch) *ch = ln->h;
7844 return ln->par->line_no + ln->line_no;
7845 }
7846 else
7847 return -1;
7848 }
7849
7850 previous_format = _find_layout_item_match(cur, &ln, &it);
7851 if (!it)
7852 {
7853 return -1;
7854 }
7855 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
7856 {
7857 ti = _ITEM_TEXT(it);
7858 }
7859 else
7860 {
7861 fi = _ITEM_FORMAT(it);
7862 }
7863
7864 if (ln && ti)
7865 {
7866 pos = cur->pos - ti->parent.text_pos;
7867
7868 if (pos < 0) pos = 0;
7869 if (ti->parent.format->font.font)
7870 {
7871 query_func(cur->ENDT,
7872 ti->parent.format->font.font,
7873 &ti->text_props,
7874 pos,
7875 &x, &y, &w, &h);
7876 }
7877
7878 x += ln->x + _ITEM(ti)->x;
7879
7880 if (x < ln->x)
7881 {
7882 x = ln->x;
7883 }
7884 y = ln->par->y + ln->y;
7885 h = ln->h;
7886 }
7887 else if (ln && fi)
7888 {
7889 if (previous_format)
7890 {
7891 if (_IS_LINE_SEPARATOR(fi->item))
7892 {
7893 x = 0;
7894 y = ln->par->y + ln->y + ln->h;
7895 }
7896 else
7897 {
7898#ifdef BIDI_SUPPORT
7899 if (ln->par->direction == EVAS_BIDI_DIRECTION_RTL)
7900 {
7901 x = ln->x;
7902 }
7903 else
7904#endif
7905 {
7906 x = ln->x + ln->w;
7907 }
7908 y = ln->par->y + ln->y;
7909 }
7910 w = 0;
7911 h = ln->h;
7912 }
7913 else
7914 {
7915 x = ln->x + _ITEM(fi)->x;
7916 y = ln->par->y + ln->y;
7917 w = _ITEM(fi)->w;
7918 h = ln->h;
7919 }
7920 }
7921 else
7922 {
7923 return -1;
7924 }
7925 if (cx) *cx = x;
7926 if (cy) *cy = y;
7927 if (cw) *cw = w;
7928 if (ch) *ch = h;
7929 return ln->par->line_no + ln->line_no;
7930}
7931
7932EAPI int
7933evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
7934{
7935 return _evas_textblock_cursor_char_pen_geometry_common_get(
7936 cur->ENFN->font_char_coords_get, cur, cx, cy, cw, ch);
7937}
7938
7939EAPI int
7940evas_textblock_cursor_pen_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
7941{
7942 return _evas_textblock_cursor_char_pen_geometry_common_get(
7943 cur->ENFN->font_pen_coords_get, cur, cx, cy, cw, ch);
7944}
7945
7946EAPI int
7947evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
7948{
7949 Evas_Object_Textblock *o;
7950 Evas_Object_Textblock_Line *ln = NULL;
7951 Evas_Object_Textblock_Item *it = NULL;
7952 int x, y, w, h;
7953
7954 if (!cur) return -1;
7955 o = (Evas_Object_Textblock *)(cur->obj->object_data);
7956 if (!o->formatted.valid) _relayout(cur->obj);
7957 if (!cur->node)
7958 {
7959 ln = o->paragraphs->lines;
7960 }
7961 else
7962 {
7963 _find_layout_item_match(cur, &ln, &it);
7964 }
7965 if (!ln) return -1;
7966 x = ln->x;
7967 y = ln->par->y + ln->y;
7968 w = ln->w;
7969 h = ln->h;
7970 if (cx) *cx = x;
7971 if (cy) *cy = y;
7972 if (cw) *cw = w;
7973 if (ch) *ch = h;
7974 return ln->par->line_no + ln->line_no;
7975}
7976
7977EAPI Eina_Bool
7978evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textblock_Cursor *end)
7979{
7980 Evas *e;
7981 Evas_Coord cy, ch;
7982 Evas_Object *obj = start->obj;
7983 TB_HEAD_RETURN(EINA_FALSE);
7984 e = evas_object_evas_get(obj);
7985 cy = 0 - obj->cur.geometry.y;
7986 ch = e->viewport.h;
7987 evas_textblock_cursor_line_coord_set(start, cy);
7988 evas_textblock_cursor_line_coord_set(end, cy + ch);
7989 evas_textblock_cursor_line_char_last(end);
7990
7991 return EINA_TRUE;
7992}
7993
7994EAPI Eina_Bool
7995evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y)
7996{
7997 Evas_Object_Textblock *o;
7998 Evas_Object_Textblock_Paragraph *found_par;
7999 Evas_Object_Textblock_Line *ln;
8000 Evas_Object_Textblock_Item *it = NULL;
8001
8002 if (!cur) return EINA_FALSE;
8003 o = (Evas_Object_Textblock *)(cur->obj->object_data);
8004 if (!o->formatted.valid) _relayout(cur->obj);
8005 x += o->style_pad.l;
8006 y += o->style_pad.t;
8007
8008 found_par = _layout_find_paragraph_by_y(o, y);
8009 if (found_par)
8010 {
8011 _layout_paragraph_render(o, found_par);
8012 EINA_INLIST_FOREACH(found_par->lines, ln)
8013 {
8014 if (ln->par->y + ln->y > y) break;
8015 if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y))
8016 {
8017 /* If before or after the line, go to start/end according
8018 * to paragraph direction. */
8019 if (x < ln->x)
8020 {
8021 cur->pos = ln->items->text_pos;
8022 cur->node = found_par->text_node;
8023 if (found_par->direction == EVAS_BIDI_DIRECTION_RTL)
8024 {
8025 evas_textblock_cursor_line_char_last(cur);
8026 }
8027 else
8028 {
8029 evas_textblock_cursor_line_char_first(cur);
8030 }
8031 return EINA_TRUE;
8032 }
8033 else if (x >= ln->x + ln->w)
8034 {
8035 cur->pos = ln->items->text_pos;
8036 cur->node = found_par->text_node;
8037 if (found_par->direction == EVAS_BIDI_DIRECTION_RTL)
8038 {
8039 evas_textblock_cursor_line_char_first(cur);
8040 }
8041 else
8042 {
8043 evas_textblock_cursor_line_char_last(cur);
8044 }
8045 return EINA_TRUE;
8046 }
8047
8048 EINA_INLIST_FOREACH(ln->items, it)
8049 {
8050 if (((it->x + ln->x) <= x) && (((it->x + ln->x) + it->adv) > x))
8051 {
8052 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
8053 {
8054 int pos;
8055 int cx, cy, cw, ch;
8056 Evas_Object_Textblock_Text_Item *ti;
8057 ti = _ITEM_TEXT(it);
8058
8059 pos = -1;
8060 if (ti->parent.format->font.font)
8061 pos = cur->ENFN->font_char_at_coords_get(
8062 cur->ENDT,
8063 ti->parent.format->font.font,
8064 &ti->text_props,
8065 x - it->x - ln->x, 0,
8066 &cx, &cy, &cw, &ch);
8067 if (pos < 0)
8068 return EINA_FALSE;
8069 cur->pos = pos + it->text_pos;
8070 cur->node = it->text_node;
8071 return EINA_TRUE;
8072 }
8073 else
8074 {
8075 Evas_Object_Textblock_Format_Item *fi;
8076 fi = _ITEM_FORMAT(it);
8077 cur->pos = fi->parent.text_pos;
8078 cur->node = found_par->text_node;
8079 return EINA_TRUE;
8080 }
8081 }
8082 }
8083 }
8084 }
8085 }
8086 else if (o->paragraphs && (y >= o->paragraphs->y + o->formatted.h))
8087 {
8088 /* If we are after the last paragraph, use the last position in the
8089 * text. */
8090 evas_textblock_cursor_paragraph_last(cur);
8091 return EINA_TRUE;
8092 }
8093 else if (o->paragraphs && (y < o->paragraphs->y))
8094 {
8095 evas_textblock_cursor_paragraph_first(cur);
8096 return EINA_TRUE;
8097 }
8098
8099 return EINA_FALSE;
8100}
8101
8102EAPI int
8103evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y)
8104{
8105 Evas_Object_Textblock *o;
8106 Evas_Object_Textblock_Paragraph *found_par;
8107 Evas_Object_Textblock_Line *ln;
8108
8109 if (!cur) return -1;
8110 o = (Evas_Object_Textblock *)(cur->obj->object_data);
8111 if (!o->formatted.valid) _relayout(cur->obj);
8112 y += o->style_pad.t;
8113
8114 found_par = _layout_find_paragraph_by_y(o, y);
8115
8116 if (found_par)
8117 {
8118 _layout_paragraph_render(o, found_par);
8119 EINA_INLIST_FOREACH(found_par->lines, ln)
8120 {
8121 if (ln->par->y + ln->y > y) break;
8122 if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y))
8123 {
8124 evas_textblock_cursor_line_set(cur, ln->par->line_no +
8125 ln->line_no);
8126 return ln->par->line_no + ln->line_no;
8127 }
8128 }
8129 }
8130 else if (o->paragraphs && (y >= o->paragraphs->y + o->formatted.h))
8131 {
8132 int line_no = 0;
8133 /* If we are after the last paragraph, use the last position in the
8134 * text. */
8135 evas_textblock_cursor_paragraph_last(cur);
8136 if (cur->node && cur->node->par)
8137 {
8138 line_no = cur->node->par->line_no;
8139 if (cur->node->par->lines)
8140 {
8141 line_no += ((Evas_Object_Textblock_Line *)
8142 EINA_INLIST_GET(cur->node->par->lines)->last)->line_no;
8143 }
8144 }
8145 return line_no;
8146 }
8147 else if (o->paragraphs && (y < o->paragraphs->y))
8148 {
8149 int line_no = 0;
8150 evas_textblock_cursor_paragraph_first(cur);
8151 if (cur->node && cur->node->par)
8152 {
8153 line_no = cur->node->par->line_no;
8154 }
8155 return line_no;
8156 }
8157 return -1;
8158}
8159
8160/**
8161 * @internal
8162 * Updates x and w according to the text direction, position in text and
8163 * if it's a special case switch
8164 *
8165 * @param ti the text item we are working on
8166 * @param x the current x (we get) and the x we return
8167 * @param w the current w (we get) and the w we return
8168 * @param start if this is the first item or not
8169 * @param switch_items toogles item switching (rtl cases)
8170 */
8171static void
8172_evas_textblock_range_calc_x_w(const Evas_Object_Textblock_Item *it,
8173 Evas_Coord *x, Evas_Coord *w, Eina_Bool start, Eina_Bool switch_items)
8174{
8175 if ((start && !switch_items) || (!start && switch_items))
8176 {
8177#ifdef BIDI_SUPPORT
8178 if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
8179 _ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
8180 ||
8181 ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
8182 _ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL))
8183 {
8184 *w = *x + *w;
8185 *x = 0;
8186 }
8187 else
8188#endif
8189 {
8190 *w = it->adv - *x;
8191 }
8192 }
8193 else
8194 {
8195#ifdef BIDI_SUPPORT
8196 if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) &&
8197 _ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
8198 ||
8199 ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) &&
8200 _ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL))
8201 {
8202 *x = *x + *w;
8203 *w = it->adv - *x;
8204 }
8205 else
8206#endif
8207 {
8208 *w = *x;
8209 *x = 0;
8210 }
8211 }
8212
8213}
8214
8215/**
8216 * @internal
8217 * Returns the geometry of the range in line ln. Cur1 is the start cursor,
8218 * cur2 is the end cursor, NULL means from the start or to the end accordingly.
8219 * Assumes that ln is valid, and that at least one of cur1 and cur2 is not NULL.
8220 *
8221 * @param ln the line to work on.
8222 * @param cur1 the start cursor
8223 * @param cur2 the end cursor
8224 * @return Returns the geometry of the range
8225 */
8226static Eina_List *
8227_evas_textblock_cursor_range_in_line_geometry_get(
8228 const Evas_Object_Textblock_Line *ln, const Evas_Textblock_Cursor *cur1,
8229 const Evas_Textblock_Cursor *cur2)
8230{
8231 Evas_Object_Textblock_Item *it;
8232 Evas_Object_Textblock_Item *it1, *it2;
8233 Eina_List *rects = NULL;
8234 Evas_Textblock_Rectangle *tr;
8235 size_t start, end;
8236 Eina_Bool switch_items;
8237 const Evas_Textblock_Cursor *cur;
8238
8239 cur = (cur1) ? cur1 : cur2;
8240
8241 if (!cur) return NULL;
8242
8243 /* Find the first and last items */
8244 it1 = it2 = NULL;
8245 start = end = 0;
8246 EINA_INLIST_FOREACH(ln->items, it)
8247 {
8248 size_t item_len;
8249 item_len = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
8250 _ITEM_TEXT(it)->text_props.text_len
8251 : 1;
8252 if ((!cur1 || (cur1->pos < it->text_pos + item_len)) &&
8253 (!cur2 || (cur2->pos >= it->text_pos)))
8254 {
8255 if (!it1)
8256 {
8257 it1 = it;
8258 start = item_len; /* start stores the first item_len */
8259 }
8260 it2 = it;
8261 end = item_len; /* end stores the last item_len */
8262 }
8263 }
8264
8265 /* If we couldn't find even one item, return */
8266 if (!it1) return NULL;
8267
8268 /* If the first item is logically before or equal the second item
8269 * we have to set start and end differently than in the other case */
8270 if (it1->text_pos <= it2->text_pos)
8271 {
8272 start = (cur1) ? (cur1->pos - it1->text_pos) : 0;
8273 end = (cur2) ? (cur2->pos - it2->text_pos) : end;
8274 switch_items = EINA_FALSE;
8275 }
8276 else
8277 {
8278 start = (cur2) ? (cur2->pos - it1->text_pos) : start;
8279 end = (cur1) ? (cur1->pos - it2->text_pos) : 0;
8280 switch_items = EINA_TRUE;
8281 }
8282
8283 /* IMPORTANT: Don't use cur1/cur2 past this point (because they probably
8284 * don't make sense anymore. That's why there are start and end),
8285 * unless you know what you are doing */
8286
8287 /* Special case when they share the same item and it's a text item */
8288 if ((it1 == it2) && (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT))
8289 {
8290 Evas_Coord x1, w1, x2, w2;
8291 Evas_Coord x, w, y, h;
8292 Evas_Object_Textblock_Text_Item *ti;
8293 int ret = 0;
8294
8295 ti = _ITEM_TEXT(it1);
8296 if (ti->parent.format->font.font)
8297 {
8298 ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
8299 ti->parent.format->font.font,
8300 &ti->text_props,
8301 start,
8302 &x1, &y, &w1, &h);
8303 }
8304 if (!ret)
8305 {
8306 return NULL;
8307 }
8308 ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
8309 ti->parent.format->font.font,
8310 &ti->text_props,
8311 end,
8312 &x2, &y, &w2, &h);
8313 if (!ret)
8314 {
8315 return NULL;
8316 }
8317
8318 /* Make x2 the one on the right */
8319 if (x2 < x1)
8320 {
8321 Evas_Coord tmp;
8322 tmp = x1;
8323 x1 = x2;
8324 x2 = tmp;
8325
8326 tmp = w1;
8327 w1 = w2;
8328 w2 = tmp;
8329 }
8330
8331#ifdef BIDI_SUPPORT
8332 if (ti->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL)
8333 {
8334 x = x1 + w1;
8335 w = x2 + w2 - x;
8336 }
8337 else
8338#endif
8339 {
8340 x = x1;
8341 w = x2 - x1;
8342 }
8343 if (w > 0)
8344 {
8345 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
8346 rects = eina_list_append(rects, tr);
8347 tr->x = ln->x + it1->x + x;
8348 tr->y = ln->par->y + ln->y;
8349 tr->h = ln->h;
8350 tr->w = w;
8351 }
8352 }
8353 else if (it1 != it2)
8354 {
8355 /* Get the middle items */
8356 Evas_Coord min_x, max_x;
8357 Evas_Coord x, w;
8358 it = _ITEM(EINA_INLIST_GET(it1)->next);
8359 min_x = max_x = it->x;
8360
8361 if (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT)
8362 {
8363 Evas_Coord y, h;
8364 Evas_Object_Textblock_Text_Item *ti;
8365 int ret;
8366 ti = _ITEM_TEXT(it1);
8367
8368 ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
8369 ti->parent.format->font.font,
8370 &ti->text_props,
8371 start,
8372 &x, &y, &w, &h);
8373 if (!ret)
8374 {
8375 /* BUG! Skip the first item */
8376 x = w = 0;
8377 }
8378 else
8379 {
8380 _evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE,
8381 switch_items);
8382 }
8383 }
8384 else
8385 {
8386 x = 0;
8387 w = it1->w;
8388 _evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE,
8389 switch_items);
8390 }
8391 if (w > 0)
8392 {
8393 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
8394 rects = eina_list_append(rects, tr);
8395 tr->x = ln->x + it1->x + x;
8396 tr->y = ln->par->y + ln->y;
8397 tr->h = ln->h;
8398 tr->w = w;
8399 }
8400
8401 while (it && (it != it2))
8402 {
8403 max_x = it->x + it->adv;
8404 it = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(it)->next;
8405 }
8406 if (min_x != max_x)
8407 {
8408 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
8409 rects = eina_list_append(rects, tr);
8410 tr->x = ln->x + min_x;
8411 tr->y = ln->par->y + ln->y;
8412 tr->h = ln->h;
8413 tr->w = max_x - min_x;
8414 }
8415 if (it2->type == EVAS_TEXTBLOCK_ITEM_TEXT)
8416 {
8417 Evas_Coord y, h;
8418 Evas_Object_Textblock_Text_Item *ti;
8419 int ret;
8420 ti = _ITEM_TEXT(it2);
8421
8422 ret = cur->ENFN->font_pen_coords_get(cur->ENDT,
8423 ti->parent.format->font.font,
8424 &ti->text_props,
8425 end,
8426 &x, &y, &w, &h);
8427 if (!ret)
8428 {
8429 /* BUG! skip the last item */
8430 x = w = 0;
8431 }
8432 else
8433 {
8434 _evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE,
8435 switch_items);
8436 }
8437 }
8438 else
8439 {
8440 x = 0;
8441 w = it2->w;
8442 _evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE,
8443 switch_items);
8444 }
8445 if (w > 0)
8446 {
8447 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
8448 rects = eina_list_append(rects, tr);
8449 tr->x = ln->x + it2->x + x;
8450 tr->y = ln->par->y + ln->y;
8451 tr->h = ln->h;
8452 tr->w = w;
8453 }
8454 }
8455 return rects;
8456}
8457
8458EAPI Eina_List *
8459evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2)
8460{
8461 Evas_Object_Textblock *o;
8462 Evas_Object_Textblock_Line *ln1, *ln2;
8463 Evas_Object_Textblock_Item *it1, *it2;
8464 Eina_List *rects = NULL;
8465 Evas_Textblock_Rectangle *tr;
8466
8467 if (!cur1 || !cur1->node) return NULL;
8468 if (!cur2 || !cur2->node) return NULL;
8469 if (cur1->obj != cur2->obj) return NULL;
8470 o = (Evas_Object_Textblock *)(cur1->obj->object_data);
8471 if (!o->formatted.valid) _relayout(cur1->obj);
8472 if (evas_textblock_cursor_compare(cur1, cur2) > 0)
8473 {
8474 const Evas_Textblock_Cursor *tc;
8475
8476 tc = cur1;
8477 cur1 = cur2;
8478 cur2 = tc;
8479 }
8480
8481 ln1 = ln2 = NULL;
8482 it1 = it2 = NULL;
8483 _find_layout_item_match(cur1, &ln1, &it1);
8484 if (!ln1 || !it1) return NULL;
8485 _find_layout_item_match(cur2, &ln2, &it2);
8486 if (!ln2 || !it2) return NULL;
8487
8488 if (ln1 == ln2)
8489 {
8490 rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1,
8491 cur1, cur2);
8492 }
8493 else
8494 {
8495 Evas_Object_Textblock_Line *plni, *lni;
8496 Eina_List *rects2 = NULL;
8497 /* Handle the first line */
8498 rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1,
8499 cur1, NULL);
8500
8501 /* Handle the lines between the first and the last line */
8502 lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(ln1)->next;
8503 if (!lni && (ln1->par != ln2->par))
8504 {
8505 lni = ((Evas_Object_Textblock_Paragraph *)
8506 EINA_INLIST_GET(ln1->par)->next)->lines;
8507 }
8508 while (lni && (lni != ln2))
8509 {
8510 tr = calloc(1, sizeof(Evas_Textblock_Rectangle));
8511 rects = eina_list_append(rects, tr);
8512 tr->x = lni->x;
8513 tr->y = lni->par->y + lni->y;
8514 tr->h = lni->h;
8515 tr->w = lni->w;
8516 plni = lni;
8517 lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(lni)->next;
8518 if (!lni && (plni->par != ln2->par))
8519 {
8520 lni = ((Evas_Object_Textblock_Paragraph *)
8521 EINA_INLIST_GET(plni->par)->next)->lines;
8522 }
8523 }
8524 rects2 = _evas_textblock_cursor_range_in_line_geometry_get(ln2,
8525 NULL, cur2);
8526 rects = eina_list_merge(rects, rects2);
8527 }
8528 return rects;
8529}
8530
8531EAPI Eina_Bool
8532evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
8533{
8534 Evas_Object_Textblock *o;
8535 Evas_Object_Textblock_Line *ln = NULL;
8536 Evas_Object_Textblock_Format_Item *fi;
8537 Evas_Object_Textblock_Item *it = NULL;
8538 Evas_Coord x, y, w, h;
8539
8540 if (!cur || !evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE;
8541 o = (Evas_Object_Textblock *)(cur->obj->object_data);
8542 if (!o->formatted.valid) _relayout(cur->obj);
8543 if (!evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE;
8544 _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it);
8545 fi = _ITEM_FORMAT(it);
8546 if ((!ln) || (!fi)) return EINA_FALSE;
8547 x = ln->x + fi->parent.x;
8548 y = ln->par->y + ln->y + ln->baseline + fi->y;
8549 w = fi->parent.w;
8550 h = fi->parent.h;
8551 if (cx) *cx = x;
8552 if (cy) *cy = y;
8553 if (cw) *cw = w;
8554 if (ch) *ch = h;
8555 return EINA_TRUE;
8556}
8557
8558EAPI Eina_Bool
8559evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur)
8560{
8561 Eina_Bool ret = EINA_FALSE;
8562 Evas_Textblock_Cursor cur2;
8563 if (!cur) return EINA_FALSE;
8564
8565 cur2.obj = cur->obj;
8566 evas_textblock_cursor_copy(cur, &cur2);
8567 evas_textblock_cursor_line_char_last(&cur2);
8568 if (cur2.pos == cur->pos)
8569 {
8570 ret = EINA_TRUE;
8571 }
8572 return ret;
8573}
8574
8575/* general controls */
8576EAPI Eina_Bool
8577evas_object_textblock_line_number_geometry_get(const Evas_Object *obj, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
8578{
8579 Evas_Object_Textblock_Line *ln;
8580
8581 TB_HEAD_RETURN(0);
8582 ln = _find_layout_line_num(obj, line);
8583 if (!ln) return EINA_FALSE;
8584 if (cx) *cx = ln->x;
8585 if (cy) *cy = ln->par->y + ln->y;
8586 if (cw) *cw = ln->w;
8587 if (ch) *ch = ln->h;
8588 return EINA_TRUE;
8589}
8590
8591EAPI void
8592evas_object_textblock_clear(Evas_Object *obj)
8593{
8594 Eina_List *l;
8595 Evas_Textblock_Cursor *cur;
8596
8597 TB_HEAD();
8598 if (o->paragraphs)
8599 {
8600 _paragraphs_free(obj, o->paragraphs);
8601 o->paragraphs = NULL;
8602 }
8603
8604 _nodes_clear(obj);
8605 o->cursor->node = NULL;
8606 o->cursor->pos = 0;
8607 EINA_LIST_FOREACH(o->cursors, l, cur)
8608 {
8609 cur->node = NULL;
8610 cur->pos = 0;
8611
8612 }
8613 _evas_textblock_changed(o, obj);
8614}
8615
8616EAPI void
8617evas_object_textblock_size_formatted_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
8618{
8619 TB_HEAD();
8620 if (!o->formatted.valid) _relayout(obj);
8621 if (w) *w = o->formatted.w;
8622 if (h) *h = o->formatted.h;
8623}
8624
8625static void
8626_size_native_calc_line_finalize(const Evas_Object *obj, Eina_List *items,
8627 Evas_Coord *ascent, Evas_Coord *descent, Evas_Coord *w)
8628{
8629 Evas_Object_Textblock_Item *it;
8630 Eina_List *i;
8631
8632 it = eina_list_data_get(items);
8633 /* If there are no text items yet, calc ascent/descent
8634 * according to the current format. */
8635 if (it && (*ascent + *descent == 0))
8636 _layout_format_ascent_descent_adjust(obj, ascent, descent, it->format);
8637
8638 *w = 0;
8639 /* Adjust all the item sizes according to the final line size,
8640 * and update the x positions of all the items of the line. */
8641 EINA_LIST_FOREACH(items, i, it)
8642 {
8643 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
8644 {
8645 Evas_Coord fw, fh, fy;
8646
8647 Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
8648 if (!fi->formatme) goto loop_advance;
8649 _layout_calculate_format_item_size(obj, fi, ascent,
8650 descent, &fy, &fw, &fh);
8651 }
8652
8653loop_advance:
8654 *w += it->adv;
8655 }
8656}
8657
8658/* FIXME: doc */
8659static void
8660_size_native_calc_paragraph_size(const Evas_Object *obj,
8661 const Evas_Object_Textblock *o,
8662 const Evas_Object_Textblock_Paragraph *par,
8663 Evas_Coord *_w, Evas_Coord *_h)
8664{
8665 Eina_List *i;
8666 Evas_Object_Textblock_Item *it;
8667 Eina_List *line_items = NULL;
8668 Evas_Coord w = 0, y = 0, wmax = 0, h = 0, ascent = 0, descent = 0;
8669
8670 EINA_LIST_FOREACH(par->logical_items, i, it)
8671 {
8672 line_items = eina_list_append(line_items, it);
8673 if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT)
8674 {
8675 Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it);
8676 if (fi->item && (_IS_LINE_SEPARATOR(fi->item) ||
8677 _IS_PARAGRAPH_SEPARATOR(o, fi->item)))
8678 {
8679 _size_native_calc_line_finalize(obj, line_items, &ascent,
8680 &descent, &w);
8681
8682 if (ascent + descent > h)
8683 h = ascent + descent;
8684
8685 y += h;
8686 if (w > wmax)
8687 wmax = w;
8688 h = 0;
8689 ascent = descent = 0;
8690 line_items = eina_list_free(line_items);
8691 }
8692 else
8693 {
8694 Evas_Coord fw, fh, fy;
8695 /* If there are no text items yet, calc ascent/descent
8696 * according to the current format. */
8697 if (it && (ascent + descent == 0))
8698 _layout_format_ascent_descent_adjust(obj, &ascent,
8699 &descent, it->format);
8700
8701 _layout_calculate_format_item_size(obj, fi, &ascent,
8702 &descent, &fy, &fw, &fh);
8703 }
8704 }
8705 else
8706 {
8707 _layout_format_ascent_descent_adjust(obj, &ascent,
8708 &descent, it->format);
8709 }
8710 }
8711
8712 _size_native_calc_line_finalize(obj, line_items, &ascent, &descent, &w);
8713
8714 line_items = eina_list_free(line_items);
8715
8716 /* Do the last addition */
8717 if (ascent + descent > h)
8718 h = ascent + descent;
8719
8720 if (w > wmax)
8721 wmax = w;
8722
8723 *_h = y + h;
8724 *_w = wmax;
8725}
8726
8727EAPI void
8728evas_object_textblock_size_native_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
8729{
8730 TB_HEAD();
8731 if (!o->native.valid)
8732 {
8733 Evas_Coord wmax = 0, hmax = 0;
8734 Evas_Object_Textblock_Paragraph *par;
8735 /* We just want the layout objects to update, should probably
8736 * split that. */
8737 if (!o->formatted.valid) _relayout(obj);
8738 EINA_INLIST_FOREACH(o->paragraphs, par)
8739 {
8740 Evas_Coord tw, th;
8741 _size_native_calc_paragraph_size(obj, o, par, &tw, &th);
8742 if (tw > wmax)
8743 wmax = tw;
8744 hmax += th;
8745 }
8746
8747 o->native.w = wmax;
8748 o->native.h = hmax;
8749
8750 o->native.valid = 1;
8751 o->content_changed = 0;
8752 o->format_changed = EINA_FALSE;
8753 }
8754 if (w) *w = o->native.w;
8755 if (h) *h = o->native.h;
8756}
8757
8758EAPI void
8759evas_object_textblock_style_insets_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b)
8760{
8761 TB_HEAD();
8762 if (!o->formatted.valid) _relayout(obj);
8763 if (l) *l = o->style_pad.l;
8764 if (r) *r = o->style_pad.r;
8765 if (t) *t = o->style_pad.t;
8766 if (b) *b = o->style_pad.b;
8767}
8768
8769/** @internal
8770 * FIXME: DELETE ME! DELETE ME!
8771 * This is an ugly workaround to get around the fact that
8772 * evas_object_textblock_coords_recalc isn't really called when it's supposed
8773 * to. When that bug is fixed please remove this. */
8774static void
8775_workaround_object_coords_recalc(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
8776{
8777 evas_object_textblock_coords_recalc(obj);
8778}
8779
8780/* all nice and private */
8781static void
8782evas_object_textblock_init(Evas_Object *obj)
8783{
8784 Evas_Object_Textblock *o;
8785#ifdef HAVE_LINEBREAK
8786 static Eina_Bool linebreak_init = EINA_FALSE;
8787 if (!linebreak_init)
8788 {
8789 linebreak_init = EINA_TRUE;
8790 init_linebreak();
8791 }
8792#endif
8793
8794 /* alloc image ob, setup methods and default values */
8795 obj->object_data = evas_object_textblock_new();
8796 /* set up default settings for this kind of object */
8797 obj->cur.color.r = 255;
8798 obj->cur.color.g = 255;
8799 obj->cur.color.b = 255;
8800 obj->cur.color.a = 255;
8801 obj->cur.geometry.x = 0.0;
8802 obj->cur.geometry.y = 0.0;
8803 obj->cur.geometry.w = 0.0;
8804 obj->cur.geometry.h = 0.0;
8805 obj->cur.layer = 0;
8806 /* set up object-specific settings */
8807 obj->prev = obj->cur;
8808 /* set up methods (compulsory) */
8809 obj->func = &object_func;
8810 obj->type = o_type;
8811
8812 o = (Evas_Object_Textblock *)(obj->object_data);
8813 o->cursor->obj = obj;
8814 o->legacy_newline = EINA_TRUE;
8815 evas_object_event_callback_priority_add(obj, EVAS_CALLBACK_RESIZE, -1000,
8816 _workaround_object_coords_recalc, NULL);
8817}
8818
8819static void *
8820evas_object_textblock_new(void)
8821{
8822 Evas_Object_Textblock *o;
8823
8824 /* alloc obj private data */
8825 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_textblock", Evas_Object_Textblock, 64, NULL);
8826 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Textblock);
8827 if (!o) return NULL;
8828 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Textblock);
8829 o->magic = MAGIC_OBJ_TEXTBLOCK;
8830 o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor));
8831 _format_command_init();
8832 return o;
8833}
8834
8835static void
8836evas_object_textblock_free(Evas_Object *obj)
8837{
8838 Evas_Object_Textblock *o;
8839
8840 evas_object_textblock_clear(obj);
8841 evas_object_textblock_style_set(obj, NULL);
8842 o = (Evas_Object_Textblock *)(obj->object_data);
8843 free(o->cursor);
8844 while (o->cursors)
8845 {
8846 Evas_Textblock_Cursor *cur;
8847
8848 cur = (Evas_Textblock_Cursor *)o->cursors->data;
8849 o->cursors = eina_list_remove_list(o->cursors, o->cursors);
8850 free(cur);
8851 }
8852 if (o->repch) eina_stringshare_del(o->repch);
8853 if (o->ellip_ti) _item_free(obj, NULL, _ITEM(o->ellip_ti));
8854 o->magic = 0;
8855 EVAS_MEMPOOL_FREE(_mp_obj, o);
8856 _format_command_shutdown();
8857}
8858
8859
8860static void
8861evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
8862{
8863 Evas_Object_Textblock_Paragraph *par, *start = NULL;
8864 Evas_Object_Textblock_Line *ln;
8865 Evas_Object_Textblock *o;
8866 int i, j;
8867 int cx, cy, cw, ch, clip;
8868 const char vals[5][5] =
8869 {
8870 {0, 1, 2, 1, 0},
8871 {1, 3, 4, 3, 1},
8872 {2, 4, 5, 4, 2},
8873 {1, 3, 4, 3, 1},
8874 {0, 1, 2, 1, 0}
8875 };
8876
8877 /* render object to surface with context, and offxet by x,y */
8878 o = (Evas_Object_Textblock *)(obj->object_data);
8879 obj->layer->evas->engine.func->context_multiplier_unset(output,
8880 context);
8881 /* FIXME: This clipping is just until we fix inset handling correctly. */
8882 ENFN->context_clip_clip(output, context,
8883 obj->cur.geometry.x + x,
8884 obj->cur.geometry.y + y,
8885 obj->cur.geometry.w,
8886 obj->cur.geometry.h);
8887 clip = ENFN->context_clip_get(output, context, &cx, &cy, &cw, &ch);
8888 /* If there are no paragraphs and thus there are no lines,
8889 * there's nothing left to do. */
8890 if (!o->paragraphs) return;
8891
8892#define ITEM_WALK() \
8893 EINA_INLIST_FOREACH(start, par) \
8894 { \
8895 if (!par->visible) continue; \
8896 if (clip) \
8897 { \
8898 if ((obj->cur.geometry.y + y + par->y + par->h) < (cy - 20)) \
8899 continue; \
8900 if ((obj->cur.geometry.y + y + par->y) > (cy + ch + 20)) \
8901 break; \
8902 } \
8903 _layout_paragraph_render(o, par); \
8904 EINA_INLIST_FOREACH(par->lines, ln) \
8905 { \
8906 Evas_Object_Textblock_Item *itr; \
8907 \
8908 if (clip) \
8909 { \
8910 if ((obj->cur.geometry.y + y + par->y + ln->y + ln->h) < (cy - 20)) \
8911 continue; \
8912 if ((obj->cur.geometry.y + y + par->y + ln->y) > (cy + ch + 20)) \
8913 break; \
8914 } \
8915 EINA_INLIST_FOREACH(ln->items, itr) \
8916 { \
8917 Evas_Coord yoff; \
8918 yoff = ln->baseline; \
8919 if (itr->format->valign != -1.0) \
8920 { \
8921 yoff += itr->format->valign * (ln->h - itr->h); \
8922 } \
8923 if (clip) \
8924 { \
8925 if ((obj->cur.geometry.x + x + ln->x + itr->x + itr->w) < (cx - 20)) \
8926 continue; \
8927 if ((obj->cur.geometry.x + x + ln->x + itr->x) > (cx + cw + 20)) \
8928 break; \
8929 } \
8930 if ((ln->x + itr->x + itr->w) <= 0) continue; \
8931 if (ln->x + itr->x > obj->cur.geometry.w) break; \
8932 do
8933
8934#define ITEM_WALK_END() \
8935 while (0); \
8936 } \
8937 } \
8938 } \
8939 do {} while(0)
8940#define COLOR_SET(col) \
8941 ENFN->context_color_set(output, context, \
8942 (obj->cur.cache.clip.r * ti->parent.format->color.col.r) / 255, \
8943 (obj->cur.cache.clip.g * ti->parent.format->color.col.g) / 255, \
8944 (obj->cur.cache.clip.b * ti->parent.format->color.col.b) / 255, \
8945 (obj->cur.cache.clip.a * ti->parent.format->color.col.a) / 255);
8946#define COLOR_SET_AMUL(col, amul) \
8947 ENFN->context_color_set(output, context, \
8948 (obj->cur.cache.clip.r * ti->parent.format->color.col.r * (amul)) / 65025, \
8949 (obj->cur.cache.clip.g * ti->parent.format->color.col.g * (amul)) / 65025, \
8950 (obj->cur.cache.clip.b * ti->parent.format->color.col.b * (amul)) / 65025, \
8951 (obj->cur.cache.clip.a * ti->parent.format->color.col.a * (amul)) / 65025);
8952#define DRAW_TEXT(ox, oy) \
8953 if (ti->parent.format->font.font) ENFN->font_draw(output, context, surface, ti->parent.format->font.font, \
8954 obj->cur.geometry.x + ln->x + ti->parent.x + x + (ox), \
8955 obj->cur.geometry.y + ln->par->y + ln->y + yoff + y + (oy), \
8956 ti->parent.w, ti->parent.h, ti->parent.w, ti->parent.h, \
8957 &ti->text_props);
8958
8959 /* backing */
8960#define DRAW_RECT(ox, oy, ow, oh, or, og, ob, oa) \
8961 do \
8962 { \
8963 ENFN->context_color_set(output, \
8964 context, \
8965 (obj->cur.cache.clip.r * or) / 255, \
8966 (obj->cur.cache.clip.g * og) / 255, \
8967 (obj->cur.cache.clip.b * ob) / 255, \
8968 (obj->cur.cache.clip.a * oa) / 255); \
8969 ENFN->rectangle_draw(output, \
8970 context, \
8971 surface, \
8972 obj->cur.geometry.x + ln->x + x + (ox), \
8973 obj->cur.geometry.y + ln->par->y + ln->y + y + (oy), \
8974 (ow), \
8975 (oh)); \
8976 } \
8977 while (0)
8978
8979#define DRAW_FORMAT_DASHED(oname, oy, oh, dw, dp) \
8980 do \
8981 { \
8982 if (itr->format->oname) \
8983 { \
8984 unsigned char _or, _og, _ob, _oa; \
8985 int _ind, _dx = 0, _dn, _dr; \
8986 _or = itr->format->color.oname.r; \
8987 _og = itr->format->color.oname.g; \
8988 _ob = itr->format->color.oname.b; \
8989 _oa = itr->format->color.oname.a; \
8990 if (!EINA_INLIST_GET(itr)->next) \
8991 { \
8992 _dn = itr->w / (dw + dp); \
8993 _dr = itr->w % (dw + dp); \
8994 } \
8995 else \
8996 { \
8997 _dn = itr->adv / (dw + dp); \
8998 _dr = itr->adv % (dw + dp); \
8999 } \
9000 if (_dr > dw) _dr = dw; \
9001 for (_ind = 0 ; _ind < _dn ; _ind++) \
9002 { \
9003 DRAW_RECT(itr->x + _dx, oy, dw, oh, _or, _og, _ob, _oa); \
9004 _dx += dw + dp; \
9005 } \
9006 DRAW_RECT(itr->x + _dx, oy, _dr, oh, _or, _og, _ob, _oa); \
9007 } \
9008 } \
9009 while (0)
9010
9011#define DRAW_FORMAT(oname, oy, oh) \
9012 do \
9013 { \
9014 if (itr->format->oname) \
9015 { \
9016 unsigned char _or, _og, _ob, _oa; \
9017 _or = itr->format->color.oname.r; \
9018 _og = itr->format->color.oname.g; \
9019 _ob = itr->format->color.oname.b; \
9020 _oa = itr->format->color.oname.a; \
9021 if (!EINA_INLIST_GET(itr)->next) \
9022 { \
9023 DRAW_RECT(itr->x, oy, itr->w, oh, _or, _og, _ob, _oa); \
9024 } \
9025 else \
9026 { \
9027 DRAW_RECT(itr->x, oy, itr->adv, oh, _or, _og, _ob, _oa); \
9028 } \
9029 } \
9030 } \
9031 while (0)
9032
9033 {
9034 Evas_Coord look_for_y = 0 - (obj->cur.geometry.y + y);
9035 if (clip)
9036 {
9037 Evas_Coord tmp_lfy = cy - (obj->cur.geometry.y + y);
9038 if (tmp_lfy > look_for_y)
9039 look_for_y = tmp_lfy;
9040 }
9041
9042 if (look_for_y >= 0)
9043 start = _layout_find_paragraph_by_y(o, look_for_y);
9044
9045 if (!start)
9046 start = o->paragraphs;
9047 }
9048
9049 ITEM_WALK()
9050 {
9051 DRAW_FORMAT(backing, 0, ln->h);
9052 }
9053 ITEM_WALK_END();
9054
9055 /* There are size adjustments that depend on the styles drawn here back
9056 * in "_text_item_update_sizes" should not modify one without the other. */
9057
9058 /* prepare everything for text draw */
9059
9060 /* shadows */
9061 ITEM_WALK()
9062 {
9063 int shad_dst, shad_sz, dx, dy, haveshad;
9064 Evas_Object_Textblock_Text_Item *ti;
9065 ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
9066 if (!ti) continue;
9067
9068 shad_dst = shad_sz = dx = dy = haveshad = 0;
9069 switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC)
9070 {
9071 case EVAS_TEXT_STYLE_SHADOW:
9072 case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW:
9073 shad_dst = 1;
9074 haveshad = 1;
9075 break;
9076 case EVAS_TEXT_STYLE_OUTLINE_SHADOW:
9077 case EVAS_TEXT_STYLE_FAR_SHADOW:
9078 shad_dst = 2;
9079 haveshad = 1;
9080 break;
9081 case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW:
9082 shad_dst = 2;
9083 shad_sz = 2;
9084 haveshad = 1;
9085 break;
9086 case EVAS_TEXT_STYLE_SOFT_SHADOW:
9087 shad_dst = 1;
9088 shad_sz = 2;
9089 haveshad = 1;
9090 break;
9091 default:
9092 break;
9093 }
9094 if (haveshad)
9095 {
9096 if (shad_dst > 0)
9097 {
9098 switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION)
9099 {
9100 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT:
9101 dx = 1;
9102 dy = 1;
9103 break;
9104 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM:
9105 dx = 0;
9106 dy = 1;
9107 break;
9108 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT:
9109 dx = -1;
9110 dy = 1;
9111 break;
9112 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT:
9113 dx = -1;
9114 dy = 0;
9115 break;
9116 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT:
9117 dx = -1;
9118 dy = -1;
9119 break;
9120 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP:
9121 dx = 0;
9122 dy = -1;
9123 break;
9124 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT:
9125 dx = 1;
9126 dy = -1;
9127 break;
9128 case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT:
9129 dx = 1;
9130 dy = 0;
9131 default:
9132 break;
9133 }
9134 dx *= shad_dst;
9135 dy *= shad_dst;
9136 }
9137 switch (shad_sz)
9138 {
9139 case 0:
9140 COLOR_SET(shadow);
9141 DRAW_TEXT(dx, dy);
9142 break;
9143 case 2:
9144 for (j = 0; j < 5; j++)
9145 {
9146 for (i = 0; i < 5; i++)
9147 {
9148 if (vals[i][j] != 0)
9149 {
9150 COLOR_SET_AMUL(shadow, vals[i][j] * 50);
9151 DRAW_TEXT(i - 2 + dx, j - 2 + dy);
9152 }
9153 }
9154 }
9155 break;
9156 default:
9157 break;
9158 }
9159 }
9160 }
9161 ITEM_WALK_END();
9162
9163 /* glows */
9164 ITEM_WALK()
9165 {
9166 Evas_Object_Textblock_Text_Item *ti;
9167 ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
9168 if (!ti) continue;
9169
9170 if (ti->parent.format->style == EVAS_TEXT_STYLE_GLOW)
9171 {
9172 for (j = 0; j < 5; j++)
9173 {
9174 for (i = 0; i < 5; i++)
9175 {
9176 if (vals[i][j] != 0)
9177 {
9178 COLOR_SET_AMUL(glow, vals[i][j] * 50);
9179 DRAW_TEXT(i - 2, j - 2);
9180 }
9181 }
9182 }
9183 COLOR_SET(glow2);
9184 DRAW_TEXT(-1, 0);
9185 DRAW_TEXT(1, 0);
9186 DRAW_TEXT(0, -1);
9187 DRAW_TEXT(0, 1);
9188 }
9189 }
9190 ITEM_WALK_END();
9191
9192 /* outlines */
9193 ITEM_WALK()
9194 {
9195 Evas_Object_Textblock_Text_Item *ti;
9196 ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
9197 if (!ti) continue;
9198
9199 if ((ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE) ||
9200 (ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) ||
9201 (ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW))
9202 {
9203 COLOR_SET(outline);
9204 DRAW_TEXT(-1, 0);
9205 DRAW_TEXT(1, 0);
9206 DRAW_TEXT(0, -1);
9207 DRAW_TEXT(0, 1);
9208 }
9209 else if (ti->parent.format->style == EVAS_TEXT_STYLE_SOFT_OUTLINE)
9210 {
9211 for (j = 0; j < 5; j++)
9212 {
9213 for (i = 0; i < 5; i++)
9214 {
9215 if (((i != 2) || (j != 2)) && (vals[i][j] != 0))
9216 {
9217 COLOR_SET_AMUL(outline, vals[i][j] * 50);
9218 DRAW_TEXT(i - 2, j - 2);
9219 }
9220 }
9221 }
9222 }
9223 }
9224 ITEM_WALK_END();
9225
9226 /* normal text and lines */
9227 ITEM_WALK()
9228 {
9229 Evas_Object_Textblock_Text_Item *ti;
9230 ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL;
9231 /* NORMAL TEXT */
9232 if (ti)
9233 {
9234 COLOR_SET(normal);
9235 DRAW_TEXT(0, 0);
9236 }
9237
9238 /* STRIKETHROUGH */
9239 DRAW_FORMAT(strikethrough, (ln->h / 2), 1);
9240
9241 /* UNDERLINE */
9242 DRAW_FORMAT(underline, ln->baseline + 1, 1);
9243
9244 /* UNDERLINE DASHED */
9245 DRAW_FORMAT_DASHED(underline_dash, ln->baseline + 1, 1,
9246 ti->parent.format->underline_dash_width,
9247 ti->parent.format->underline_dash_gap);
9248
9249 /* UNDERLINE2 */
9250 DRAW_FORMAT(underline2, ln->baseline + 3, 1);
9251 }
9252 ITEM_WALK_END();
9253}
9254
9255static void
9256evas_object_textblock_render_pre(Evas_Object *obj)
9257{
9258 Evas_Object_Textblock *o;
9259 int is_v, was_v;
9260
9261 /* dont pre-render the obj twice! */
9262 if (obj->pre_render_done) return;
9263 obj->pre_render_done = 1;
9264 /* pre-render phase. this does anything an object needs to do just before */
9265 /* rendering. this could mean loading the image data, retrieving it from */
9266 /* elsewhere, decoding video etc. */
9267 /* then when this is done the object needs to figure if it changed and */
9268 /* if so what and where and add the appropriate redraw textblocks */
9269 o = (Evas_Object_Textblock *)(obj->object_data);
9270 if ((o->changed) || (o->content_changed) || (o->format_changed) ||
9271 ((obj->cur.geometry.w != o->last_w) ||
9272 (((o->valign != 0.0) || (o->have_ellipsis)) &&
9273 (obj->cur.geometry.h != o->last_h))))
9274 {
9275 _relayout(obj);
9276 o->redraw = 0;
9277 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9278 is_v = evas_object_is_visible(obj);
9279 was_v = evas_object_was_visible(obj);
9280 goto done;
9281 }
9282 if (o->redraw)
9283 {
9284 o->redraw = 0;
9285 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9286 is_v = evas_object_is_visible(obj);
9287 was_v = evas_object_was_visible(obj);
9288 goto done;
9289 }
9290 /* if someone is clipping this obj - go calculate the clipper */
9291 if (obj->cur.clipper)
9292 {
9293 if (obj->cur.cache.clip.dirty)
9294 evas_object_clip_recalc(obj->cur.clipper);
9295 obj->cur.clipper->func->render_pre(obj->cur.clipper);
9296 }
9297 /* now figure what changed and add draw rects */
9298 /* if it just became visible or invisible */
9299 is_v = evas_object_is_visible(obj);
9300 was_v = evas_object_was_visible(obj);
9301 if (is_v != was_v)
9302 {
9303 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
9304 goto done;
9305 }
9306 if ((obj->cur.map != obj->prev.map) ||
9307 (obj->cur.usemap != obj->prev.usemap))
9308 {
9309 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9310 goto done;
9311 }
9312 /* it's not visible - we accounted for it appearing or not so just abort */
9313 if (!is_v) goto done;
9314 /* clipper changed this is in addition to anything else for obj */
9315 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
9316 /* if we restacked (layer or just within a layer) and don't clip anyone */
9317 if (obj->restack)
9318 {
9319 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9320 goto done;
9321 }
9322 /* if it changed color */
9323 if ((obj->cur.color.r != obj->prev.color.r) ||
9324 (obj->cur.color.g != obj->prev.color.g) ||
9325 (obj->cur.color.b != obj->prev.color.b) ||
9326 (obj->cur.color.a != obj->prev.color.a))
9327 {
9328 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9329 goto done;
9330 }
9331 /* if it changed geometry - and obviously not visibility or color */
9332 /* calculate differences since we have a constant color fill */
9333 /* we really only need to update the differences */
9334 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
9335 (obj->cur.geometry.y != obj->prev.geometry.y) ||
9336 (obj->cur.geometry.w != obj->prev.geometry.w) ||
9337 (obj->cur.geometry.h != obj->prev.geometry.h))
9338 {
9339 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
9340 goto done;
9341 }
9342 done:
9343 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
9344}
9345
9346static void
9347evas_object_textblock_render_post(Evas_Object *obj)
9348{
9349/* Evas_Object_Textblock *o; */
9350
9351 /* this moves the current data to the previous state parts of the object */
9352 /* in whatever way is safest for the object. also if we don't need object */
9353 /* data anymore we can free it if the object deems this is a good idea */
9354/* o = (Evas_Object_Textblock *)(obj->object_data); */
9355 /* remove those pesky changes */
9356 evas_object_clip_changes_clean(obj);
9357 /* move cur to prev safely for object data */
9358 obj->prev = obj->cur;
9359/* o->prev = o->cur; */
9360/* o->changed = 0; */
9361}
9362
9363static unsigned int evas_object_textblock_id_get(Evas_Object *obj)
9364{
9365 Evas_Object_Textblock *o;
9366
9367 o = (Evas_Object_Textblock *)(obj->object_data);
9368 if (!o) return 0;
9369 return MAGIC_OBJ_TEXTBLOCK;
9370}
9371
9372static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj)
9373{
9374 Evas_Object_Textblock *o;
9375
9376 o = (Evas_Object_Textblock *)(obj->object_data);
9377 if (!o) return 0;
9378 return MAGIC_OBJ_CUSTOM;
9379}
9380
9381static void *evas_object_textblock_engine_data_get(Evas_Object *obj)
9382{
9383 Evas_Object_Textblock *o;
9384
9385 o = (Evas_Object_Textblock *)(obj->object_data);
9386 if (!o) return NULL;
9387 return o->engine_data;
9388}
9389
9390static int
9391evas_object_textblock_is_opaque(Evas_Object *obj __UNUSED__)
9392{
9393 /* this returns 1 if the internal object data implies that the object is */
9394 /* currently fulyl opque over the entire gradient it occupies */
9395 return 0;
9396}
9397
9398static int
9399evas_object_textblock_was_opaque(Evas_Object *obj __UNUSED__)
9400{
9401 /* this returns 1 if the internal object data implies that the object was */
9402 /* currently fulyl opque over the entire gradient it occupies */
9403 return 0;
9404}
9405
9406static void
9407evas_object_textblock_coords_recalc(Evas_Object *obj)
9408{
9409 Evas_Object_Textblock *o;
9410
9411 o = (Evas_Object_Textblock *)(obj->object_data);
9412 if ((obj->cur.geometry.w != o->last_w) ||
9413 (((o->valign != 0.0) || (o->have_ellipsis)) &&
9414 (obj->cur.geometry.h != o->last_h)))
9415 {
9416 o->formatted.valid = 0;
9417 o->changed = 1;
9418 }
9419}
9420
9421static void
9422evas_object_textblock_scale_update(Evas_Object *obj)
9423{
9424 Evas_Object_Textblock *o;
9425
9426 o = (Evas_Object_Textblock *)(obj->object_data);
9427 _evas_textblock_invalidate_all(o);
9428 _evas_textblock_changed(o, obj);
9429}
9430
9431void
9432_evas_object_textblock_rehint(Evas_Object *obj)
9433{
9434 Evas_Object_Textblock *o;
9435 Evas_Object_Textblock_Paragraph *par;
9436 Evas_Object_Textblock_Line *ln;
9437
9438 o = (Evas_Object_Textblock *)(obj->object_data);
9439 EINA_INLIST_FOREACH(o->paragraphs, par)
9440 {
9441 EINA_INLIST_FOREACH(par->lines, ln)
9442 {
9443 Evas_Object_Textblock_Item *it;
9444
9445 EINA_INLIST_FOREACH(ln->items, it)
9446 {
9447 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
9448 {
9449 Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
9450 if (ti->parent.format->font.font)
9451 {
9452#ifdef EVAS_FRAME_QUEUING
9453 evas_common_pipe_op_text_flush((RGBA_Font *) ti->parent.format->font.font);
9454#endif
9455 evas_font_load_hinting_set(obj->layer->evas,
9456 ti->parent.format->font.font,
9457 obj->layer->evas->hinting);
9458 }
9459 }
9460 }
9461 }
9462 }
9463 _evas_textblock_invalidate_all(o);
9464 _evas_textblock_changed(o, obj);
9465}
9466
9467/**
9468 * @}
9469 */
9470
9471#ifdef HAVE_TESTS
9472/* return EINA_FALSE on error, used in unit_testing */
9473EAPI Eina_Bool
9474_evas_textblock_check_item_node_link(Evas_Object *obj)
9475{
9476 Evas_Object_Textblock *o;
9477 Evas_Object_Textblock_Paragraph *par;
9478 Evas_Object_Textblock_Line *ln;
9479 Evas_Object_Textblock_Item *it;
9480
9481 o = (Evas_Object_Textblock *)(obj->object_data);
9482 if (!o) return EINA_FALSE;
9483
9484 if (!o->formatted.valid) _relayout(obj);
9485
9486 EINA_INLIST_FOREACH(o->paragraphs, par)
9487 {
9488 EINA_INLIST_FOREACH(par->lines, ln)
9489 {
9490 EINA_INLIST_FOREACH(ln->items, it)
9491 {
9492 if (it->text_node != par->text_node)
9493 return EINA_FALSE;
9494 }
9495 }
9496 }
9497 return EINA_TRUE;
9498}
9499
9500EAPI int
9501_evas_textblock_format_offset_get(const Evas_Object_Textblock_Node_Format *n)
9502{
9503 return n->offset;
9504}
9505#endif
9506
9507#if 0
9508/* Good for debugging */
9509void
9510pfnode(Evas_Object_Textblock_Node_Format *n)
9511{
9512 printf("Format Node: %p\n", n);
9513 printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
9514 printf("text_node = %p, offset = %u, visible = %d\n", n->text_node, n->offset, n->visible);
9515 printf("'%s'\n", eina_strbuf_string_get(n->format));
9516}
9517
9518void
9519ptnode(Evas_Object_Textblock_Node_Text *n)
9520{
9521 printf("Text Node: %p\n", n);
9522 printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
9523 printf("format_node = %p\n", n->format_node);
9524 printf("'%ls'\n", eina_ustrbuf_string_get(n->unicode));
9525}
9526
9527void
9528pitem(Evas_Object_Textblock_Item *it)
9529{
9530 Evas_Object_Textblock_Text_Item *ti;
9531 Evas_Object_Textblock_Format_Item *fi;
9532 printf("Item: %p\n", it);
9533 printf("Type: %s (%d)\n", (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ?
9534 "TEXT" : "FORMAT", it->type);
9535 printf("Text pos: %d Visual pos: %d\n", it->text_pos,
9536#ifdef BIDI_SUPPORT
9537 it->visual_pos
9538#else
9539 it->text_pos
9540#endif
9541 );
9542 printf("Coords: x = %d w = %d adv = %d\n", (int) it->x, (int) it->w,
9543 (int) it->adv);
9544 if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
9545 {
9546 ti = _ITEM_TEXT(it);
9547 printf("Text: '%*ls'\n", ti->text_props.text_len, GET_ITEM_TEXT(ti));
9548 }
9549 else
9550 {
9551 fi = _ITEM_FORMAT(it);
9552 printf("Format: '%s'\n", fi->item);
9553 }
9554}
9555
9556void
9557ppar(Evas_Object_Textblock_Paragraph *par)
9558{
9559 Evas_Object_Textblock_Item *it;
9560 Eina_List *i;
9561 EINA_LIST_FOREACH(par->logical_items, i, it)
9562 {
9563 printf("***********************\n");
9564 pitem(it);
9565 }
9566}
9567
9568#endif
9569
diff --git a/libraries/evas/src/lib/canvas/evas_rectangle.c b/libraries/evas/src/lib/canvas/evas_rectangle.c
new file mode 100644
index 0000000..da6b701
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_rectangle.c
@@ -0,0 +1,98 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4void
5evas_rects_return_difference_rects(Eina_Array *rects, int x, int y, int w, int h, int xx, int yy, int ww, int hh)
6{
7 if (!RECTS_INTERSECT(x, y, w, h, xx, yy, ww, hh))
8 {
9 evas_add_rect(rects, x, y, w, h);
10 evas_add_rect(rects, xx, yy, ww, hh);
11 }
12 else
13 {
14 int pt_x[4], pt_y[4], i, j;
15
16 if (x < xx)
17 {
18 pt_x[0] = x;
19 pt_x[1] = xx;
20 }
21 else
22 {
23 pt_x[0] = xx;
24 pt_x[1] = x;
25 }
26 if ((x + w) < (xx + ww))
27 {
28 pt_x[2] = x + w;
29 pt_x[3] = xx + ww;
30 }
31 else
32 {
33 pt_x[2] = xx + ww;
34 pt_x[3] = x + w;
35 }
36 if (y < yy)
37 {
38 pt_y[0] = y;
39 pt_y[1] = yy;
40 }
41 else
42 {
43 pt_y[0] = yy;
44 pt_y[1] = y;
45 }
46 if ((y + h) < (yy + hh))
47 {
48 pt_y[2] = y + h;
49 pt_y[3] = yy + hh;
50 }
51 else
52 {
53 pt_y[2] = yy + hh;
54 pt_y[3] = y + h;
55 }
56 for (j = 0; j < 3; j++)
57 {
58 for (i = 0; i < 3; i++)
59 {
60 int intsec1, intsec2;
61 int tx, ty, tw, th;
62
63 tx = pt_x[i];
64 ty = pt_y[j];
65 tw = pt_x[i + 1] - pt_x[i];
66 th = pt_y[j + 1] - pt_y[j];
67
68 intsec1 = (RECTS_INTERSECT(tx, ty, tw, th, x, y, w, h));
69 intsec2 = (RECTS_INTERSECT(tx, ty, tw, th, xx, yy, ww, hh));
70 if (intsec1 ^ intsec2)
71 {
72 evas_add_rect(rects, tx, ty, tw, th);
73 }
74 }
75 }
76/* if (tmp.count > 0) */
77/* { */
78/* unsigned int i; */
79
80/* for (i = 0; i < tmp.count; ++i) */
81/* { */
82/* if ((tmp.array[i].w > 0) && (tmp.array[i].h > 0)) */
83/* { */
84/* int intsec1, intsec2; */
85
86/* intsec1 = (RECTS_INTERSECT(tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h, x, y, w, h)); */
87/* intsec2 = (RECTS_INTERSECT(tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h, xx, yy, ww, hh)); */
88/* if (intsec1 ^ intsec2) */
89/* { */
90/* evas_add_rect(rects, tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h); */
91/* } */
92/* } */
93/* } */
94/* free(tmp.array); */
95/* } */
96
97 }
98}
diff --git a/libraries/evas/src/lib/canvas/evas_render.c b/libraries/evas/src/lib/canvas/evas_render.c
new file mode 100644
index 0000000..0abee97
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_render.c
@@ -0,0 +1,1866 @@
1#include "evas_common.h"
2#include "evas_private.h"
3#include <math.h>
4
5// debug rendering
6/* #define REND_DGB 1 */
7/* #define STDOUT_DBG 1 */
8
9#ifdef REND_DGB
10static FILE *dbf = NULL;
11
12static void
13rend_dbg(const char *txt)
14{
15 if (!dbf)
16 {
17#ifdef STDOUT_DBG
18 dbf = stdout;
19#else
20 dbf = fopen("EVAS-RENDER-DEBUG.log", "w");
21#endif
22 if (!dbf) return;
23 }
24 fputs(txt, dbf);
25 fflush(dbf);
26}
27#define RD(args...) \
28 { \
29 char __tmpbuf[4096]; \
30 \
31 snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
32 rend_dbg(__tmpbuf); \
33 }
34#define RDI(xxxx) \
35 { \
36 char __tmpbuf[4096]; int __tmpi; \
37 for (__tmpi = 0; __tmpi < xxxx; __tmpi++) \
38 __tmpbuf[__tmpi] = ' '; \
39 __tmpbuf[__tmpi] = 0; \
40 rend_dbg(__tmpbuf); \
41 }
42#else
43#define RD(args...)
44#define RDI(x)
45#endif
46
47static Eina_List *
48evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char do_draw);
49
50EAPI void
51evas_damage_rectangle_add(Evas *e, int x, int y, int w, int h)
52{
53 Eina_Rectangle *r;
54
55 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
56 return;
57 MAGIC_CHECK_END();
58 NEW_RECT(r, x, y, w, h);
59 if (!r) return;
60 e->damages = eina_list_append(e->damages, r);
61 e->changed = 1;
62}
63
64EAPI void
65evas_obscured_rectangle_add(Evas *e, int x, int y, int w, int h)
66{
67 Eina_Rectangle *r;
68
69 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
70 return;
71 MAGIC_CHECK_END();
72 NEW_RECT(r, x, y, w, h);
73 if (!r) return;
74 e->obscures = eina_list_append(e->obscures, r);
75}
76
77EAPI void
78evas_obscured_clear(Evas *e)
79{
80 Eina_Rectangle *r;
81
82 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
83 return;
84 MAGIC_CHECK_END();
85 EINA_LIST_FREE(e->obscures, r)
86 {
87 eina_rectangle_free(r);
88 }
89}
90
91static Eina_Bool
92_evas_render_has_map(Evas_Object *obj)
93{
94 return ((!((obj->func->can_map) && (obj->func->can_map(obj)))) &&
95 ((obj->cur.map) && (obj->cur.usemap)));
96 // return ((obj->cur.map) && (obj->cur.usemap));
97}
98
99static Eina_Bool
100_evas_render_had_map(Evas_Object *obj)
101{
102 return ((obj->prev.map) && (obj->prev.usemap));
103 // return ((!obj->cur.map) && (obj->prev.usemap));
104}
105
106static Eina_Bool
107_evas_render_is_relevant(Evas_Object *obj)
108{
109 return ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
110 (evas_object_was_visible(obj) && (!obj->prev.have_clipees)));
111}
112
113static Eina_Bool
114_evas_render_can_render(Evas_Object *obj)
115{
116 return (evas_object_is_visible(obj) && (!obj->cur.have_clipees));
117}
118
119static void
120_evas_render_prev_cur_clip_cache_add(Evas *e, Evas_Object *obj)
121{
122 e->engine.func->output_redraws_rect_add(e->engine.data.output,
123 obj->prev.cache.clip.x,
124 obj->prev.cache.clip.y,
125 obj->prev.cache.clip.w,
126 obj->prev.cache.clip.h);
127 e->engine.func->output_redraws_rect_add(e->engine.data.output,
128 obj->cur.cache.clip.x,
129 obj->cur.cache.clip.y,
130 obj->cur.cache.clip.w,
131 obj->cur.cache.clip.h);
132}
133
134static void
135_evas_render_cur_clip_cache_del(Evas *e, Evas_Object *obj)
136{
137 Evas_Coord x, y, w, h;
138
139 x = obj->cur.cache.clip.x;
140 y = obj->cur.cache.clip.y;
141 w = obj->cur.cache.clip.w;
142 h = obj->cur.cache.clip.h;
143 if (obj->cur.clipper)
144 {
145 RECTS_CLIP_TO_RECT(x, y, w, h,
146 obj->cur.clipper->cur.cache.clip.x,
147 obj->cur.clipper->cur.cache.clip.y,
148 obj->cur.clipper->cur.cache.clip.w,
149 obj->cur.clipper->cur.cache.clip.h);
150 }
151 e->engine.func->output_redraws_rect_del(e->engine.data.output,
152 x, y, w, h);
153}
154
155static void
156_evas_render_phase1_direct(Evas *e,
157 Eina_Array *active_objects,
158 Eina_Array *restack_objects __UNUSED__,
159 Eina_Array *delete_objects __UNUSED__,
160 Eina_Array *render_objects)
161{
162 unsigned int i;
163 Eina_List *l;
164 Evas_Object *proxy;
165
166 RD(" [--- PHASE 1 DIRECT\n");
167 for (i = 0; i < active_objects->count; i++)
168 {
169 Evas_Object *obj;
170
171 obj = eina_array_data_get(active_objects, i);
172 if (obj->changed)
173 {
174 /* Flag need redraw on proxy too */
175 evas_object_clip_recalc(obj);
176 if (obj->proxy.proxies)
177 {
178 EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy)
179 proxy->proxy.redraw = 1;
180 }
181 }
182 }
183 for (i = 0; i < render_objects->count; i++)
184 {
185 Evas_Object *obj;
186
187 obj = eina_array_data_get(render_objects, i);
188 RD(" OBJ [%p] changed %i\n", obj, obj->changed);
189 if (obj->changed)
190 {
191 /* Flag need redraw on proxy too */
192 evas_object_clip_recalc(obj);
193 obj->func->render_pre(obj);
194 if (obj->proxy.proxies)
195 {
196 obj->proxy.redraw = 1;
197 EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy)
198 {
199 proxy->func->render_pre(proxy);
200 _evas_render_prev_cur_clip_cache_add(e, proxy);
201 }
202 }
203 else if (obj->proxy.redraw)
204 {
205 _evas_render_prev_cur_clip_cache_add(e, obj);
206 }
207 if (obj->pre_render_done)
208 {
209 RD(" pre-render-done smart:%p|%p [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
210 obj->smart.smart,
211 evas_object_smart_members_get_direct(obj),
212 obj->cur.map, obj->cur.usemap,
213 obj->prev.map, obj->prev.usemap,
214 _evas_render_has_map(obj),
215 _evas_render_had_map(obj));
216 if ((obj->smart.smart) &&
217 (_evas_render_has_map(obj)))
218 {
219 RD(" has map + smart\n");
220 _evas_render_prev_cur_clip_cache_add(e, obj);
221 }
222 }
223 else if (_evas_render_had_map(obj))
224 {
225 RD(" no pre-render done\n");
226 _evas_render_prev_cur_clip_cache_add(e, obj);
227 }
228 }
229 else
230 {
231 if (obj->smart.smart)
232 {
233 // obj->func->render_pre(obj);
234 }
235 else if ((obj->rect_del) ||
236 (evas_object_is_opaque(obj) && evas_object_is_visible(obj)))
237 {
238 RD(" rect del\n");
239 _evas_render_cur_clip_cache_del(e, obj);
240 }
241 }
242 }
243 RD(" ---]\n");
244}
245
246static Eina_Bool
247_evas_render_phase1_object_process(Evas *e, Evas_Object *obj,
248 Eina_Array *active_objects,
249 Eina_Array *restack_objects,
250 Eina_Array *delete_objects,
251 Eina_Array *render_objects,
252 int restack, int map,
253 int *redraw_all
254#ifdef REND_DGB
255 , int level
256#endif
257 )
258{
259 Eina_Bool clean_them = EINA_FALSE;
260 Evas_Object *obj2;
261 int is_active;
262 Eina_Bool hmap;
263
264 obj->rect_del = 0;
265 obj->render_pre = 0;
266
267#ifndef EVAS_FRAME_QUEUING
268 /* because of clip objects - delete 2 cycles later */
269 if (obj->delete_me == 2)
270#else
271 if (obj->delete_me == evas_common_frameq_get_frameq_sz() + 2)
272#endif
273 eina_array_push(delete_objects, obj);
274 else if (obj->delete_me != 0) obj->delete_me++;
275 /* If the object will be removed, we should not cache anything during this run. */
276 if (obj->delete_me != 0) clean_them = EINA_TRUE;
277
278 /* build active object list */
279 evas_object_clip_recalc(obj);
280 is_active = evas_object_is_active(obj);
281 obj->is_active = is_active;
282
283 RDI(level);
284 RD(" [--- PROCESS [%p] '%s' active = %i, del = %i | %i %i %ix%i\n", obj, obj->type, is_active, obj->delete_me, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h);
285 if ((is_active) || (obj->delete_me != 0))
286 eina_array_push(active_objects, obj);
287
288#ifdef REND_DGB
289 if (!is_active)
290 {
291 RDI(level);
292 RD(" [%p] vis: %i, cache.clip.vis: %i cache.clip.a: %i [%p]\n", obj, obj->cur.visible, obj->cur.cache.clip.visible, obj->cur.cache.clip.a, obj->func->is_visible);
293 }
294#endif
295
296 map = _evas_render_has_map(obj);
297 hmap = _evas_render_had_map(obj);
298
299 if ((restack) && (!map))
300 {
301 if (!obj->changed)
302 {
303 eina_array_push(&e->pending_objects, obj);
304 obj->changed = 1;
305 }
306 obj->restack = 1;
307 clean_them = EINA_TRUE;
308 }
309
310 if (map)
311 {
312 RDI(level);
313 RD(" obj mapped\n");
314 if (obj->changed)
315 {
316 if (map != hmap)
317 {
318 *redraw_all = 1;
319 }
320 evas_object_clip_recalc(obj);
321 if ((obj->restack) &&
322 (is_active) && (!obj->clip.clipees) &&
323 ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
324 (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
325 {
326 eina_array_push(render_objects, obj);
327 _evas_render_prev_cur_clip_cache_add(e, obj);
328 obj->render_pre = 1;
329 }
330 else if ((is_active) && (!obj->clip.clipees) &&
331 ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
332 (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
333 {
334 eina_array_push(render_objects, obj);
335 _evas_render_prev_cur_clip_cache_add(e, obj);
336 obj->render_pre = 1;
337 }
338 }
339 return clean_them;
340 }
341 else if (_evas_render_had_map(obj))
342 {
343 RDI(level);
344 RD(" had map - restack objs\n");
345 // eina_array_push(restack_objects, obj);
346 _evas_render_prev_cur_clip_cache_add(e, obj);
347 if (obj->changed)
348 {
349 if (hmap)
350 {
351 if (!map)
352 {
353 if ((obj->cur.map) && (obj->cur.usemap)) map = 1;
354 }
355 }
356 if (map != hmap)
357 {
358 *redraw_all = 1;
359 }
360 }
361 }
362
363 /* handle normal rendering. this object knows how to handle maps */
364 if (obj->changed)
365 {
366 if (obj->smart.smart)
367 {
368 RDI(level);
369 RD(" changed + smart - render ok\n");
370 eina_array_push(render_objects, obj);
371 obj->render_pre = 1;
372 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
373 {
374 _evas_render_phase1_object_process(e, obj2,
375 active_objects,
376 restack_objects,
377 delete_objects,
378 render_objects,
379 obj->restack,
380 map,
381 redraw_all
382#ifdef REND_DGB
383 , level + 1
384#endif
385 );
386 }
387 }
388 else
389 {
390 if ((is_active) && (!obj->clip.clipees) &&
391 _evas_render_is_relevant(obj))
392 {
393 RDI(level);
394 RD(" relevant + active\n");
395 if (obj->restack)
396 eina_array_push(restack_objects, obj);
397 else
398 {
399 eina_array_push(render_objects, obj);
400 obj->render_pre = 1;
401 }
402 }
403 else
404 {
405 RDI(level);
406 RD(" skip - not smart, not active or clippees or not relevant\n");
407 }
408 }
409 }
410 else
411 {
412 RD(" not changed... [%i] -> (%i %i %p %i) [%i]\n",
413 evas_object_is_visible(obj),
414 obj->cur.visible, obj->cur.cache.clip.visible, obj->smart.smart, obj->cur.cache.clip.a,
415 evas_object_was_visible(obj));
416 if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
417 (_evas_render_can_render(obj) ||
418 (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
419 {
420 if (obj->smart.smart)
421 {
422 RDI(level);
423 RD(" smart + visible/was visible + not clip\n");
424 eina_array_push(render_objects, obj);
425 obj->render_pre = 1;
426 EINA_INLIST_FOREACH
427 (evas_object_smart_members_get_direct(obj), obj2)
428 {
429 _evas_render_phase1_object_process(e, obj2,
430 active_objects,
431 restack_objects,
432 delete_objects,
433 render_objects,
434 restack, map,
435 redraw_all
436#ifdef REND_DGB
437 , level + 1
438#endif
439 );
440 }
441 }
442 else
443 {
444 if (evas_object_is_opaque(obj) &&
445 evas_object_is_visible(obj))
446 {
447 RDI(level);
448 RD(" opaque + visible\n");
449 eina_array_push(render_objects, obj);
450 obj->rect_del = 1;
451 }
452 else if (evas_object_is_visible(obj))
453 {
454 RDI(level);
455 RD(" visible\n");
456 eina_array_push(render_objects, obj);
457 obj->render_pre = 1;
458 }
459 else
460 {
461 RDI(level);
462 RD(" skip\n");
463 }
464 }
465 }
466 /*
467 else if (obj->smart.smart)
468 {
469 RDI(level);
470 RD(" smart + mot visible/was visible\n");
471 eina_array_push(render_objects, obj);
472 obj->render_pre = 1;
473 EINA_INLIST_FOREACH
474 (evas_object_smart_members_get_direct(obj), obj2)
475 {
476 _evas_render_phase1_object_process(e, obj2,
477 active_objects,
478 restack_objects,
479 delete_objects,
480 render_objects,
481 restack, map,
482 redraw_all
483#ifdef REND_DGB
484, level + 1
485#endif
486);
487}
488}
489 */
490}
491if (!is_active) obj->restack = 0;
492RDI(level);
493RD(" ---]\n");
494return clean_them;
495}
496
497static Eina_Bool
498_evas_render_phase1_process(Evas *e,
499 Eina_Array *active_objects,
500 Eina_Array *restack_objects,
501 Eina_Array *delete_objects,
502 Eina_Array *render_objects,
503 int *redraw_all)
504{
505 Evas_Layer *lay;
506 Eina_Bool clean_them = EINA_FALSE;
507
508 RD(" [--- PHASE 1\n");
509 EINA_INLIST_FOREACH(e->layers, lay)
510 {
511 Evas_Object *obj;
512
513 EINA_INLIST_FOREACH(lay->objects, obj)
514 {
515 clean_them |= _evas_render_phase1_object_process
516 (e, obj, active_objects, restack_objects, delete_objects,
517 render_objects, 0, 0, redraw_all
518#ifdef REND_DGB
519 , 1
520#endif
521 );
522 }
523 }
524 RD(" ---]\n");
525 return clean_them;
526}
527
528static void
529_evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *e)
530{
531 unsigned int i;
532
533 for (i = 0; i < pending_objects->count; ++i)
534 {
535 Evas_Object *obj;
536 int is_active, ok = 0;
537
538 obj = eina_array_data_get(pending_objects, i);
539
540 if (!obj->layer) goto clean_stuff;
541
542 evas_object_clip_recalc(obj);
543 is_active = evas_object_is_active(obj);
544
545 if ((!is_active) && (!obj->is_active) && (!obj->render_pre) &&
546 (!obj->rect_del))
547 {
548 ok = 1;
549 goto clean_stuff;
550 }
551
552 if (obj->is_active == is_active)
553 {
554 if (obj->changed)
555 {
556 if (obj->smart.smart)
557 {
558 if (obj->render_pre || obj->rect_del) ok = 1;
559 }
560 else
561 if ((is_active) && (obj->restack) && (!obj->clip.clipees) &&
562 (_evas_render_can_render(obj) ||
563 (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
564 {
565 if (!(obj->render_pre || obj->rect_del)) ok = 1;
566 }
567 else
568 if (is_active && (!obj->clip.clipees) &&
569 (_evas_render_can_render(obj) ||
570 (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
571 {
572 if (obj->render_pre || obj->rect_del) ok = 1;
573 }
574 }
575 else
576 {
577 if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
578 (!obj->cur.have_clipees || (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))
579 && evas_object_is_opaque(obj) && evas_object_is_visible(obj))
580 {
581 if (obj->rect_del || obj->smart.smart) ok = 1;
582 }
583 }
584 }
585
586clean_stuff:
587 if (!ok)
588 {
589 eina_array_clean(&e->active_objects);
590 eina_array_clean(&e->render_objects);
591 eina_array_clean(&e->restack_objects);
592 eina_array_clean(&e->delete_objects);
593 e->invalidate = 1;
594 return ;
595 }
596 }
597}
598
599Eina_Bool
600pending_change(void *data, void *gdata __UNUSED__)
601{
602 Evas_Object *obj;
603
604 obj = data;
605 if (obj->delete_me) return EINA_FALSE;
606 if (obj->pre_render_done)
607 {
608 RD(" OBJ [%p] pending change %i -> 0, pre %i\n", obj, obj->changed, obj->pre_render_done);
609 obj->pre_render_done = 0;
610 //// FIXME: this wipes out changes
611 obj->changed = 0;
612 obj->changed_move_only = 0;
613 obj->changed_nomove = 0;
614 obj->changed_move = 0;
615 }
616 return obj->changed ? EINA_TRUE : EINA_FALSE;
617}
618/*
619 static void
620 unchange(Evas_Object *obj)
621 {
622 Evas_Object *obj2;
623
624 if (!obj->changed) return;
625 obj->changed = 0;
626 obj->changed_move_only = 0;
627 obj->changed_nomove = 0;
628 obj->changed_move = 0;
629 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
630 {
631 unchange(obj2);
632 }
633 }
634
635 static int
636 chlist(Evas_Object *obj, int i)
637 {
638 Evas_Object *obj2;
639 int j;
640 int ret = 0;
641
642 if (!obj->changed) return 0;
643 for (j = 0; j < i; j++) printf(" ");
644 printf("ch2 %p %s %i [%i %i %ix%i] v %i/%i [r%i] %p\n", obj,
645 obj->type,
646 obj->changed_move_only,
647 obj->cur.geometry.x,
648 obj->cur.geometry.y,
649 obj->cur.geometry.w,
650 obj->cur.geometry.h,
651 obj->cur.visible,
652 obj->prev.visible,
653 obj->restack,
654 obj->clip.clipees);
655 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
656 {
657 if (obj2->changed)
658 ret |= chlist(obj2, i + 1);
659 }
660 }
661 */
662static Eina_Bool
663_evas_render_can_use_overlay(Evas *e, Evas_Object *obj)
664{
665 Eina_Rectangle *r;
666 Evas_Object *tmp;
667 Eina_List *alphas = NULL;
668 Eina_List *opaques = NULL;
669 Evas_Object *video_parent = NULL;
670 Eina_Rectangle zone;
671 Evas_Coord xc1, yc1, xc2, yc2;
672 unsigned int i;
673 Eina_Bool nooverlay;
674
675 video_parent = _evas_object_image_video_parent_get(obj);
676
677 /* Check if any one is the stack make this object mapped */
678 tmp = obj;
679 while (tmp && !_evas_render_has_map(tmp))
680 tmp = tmp->smart.parent;
681
682 if (tmp && _evas_render_has_map(tmp)) return EINA_FALSE; /* we are mapped, we can't be an overlay */
683
684 if (!evas_object_is_visible(obj)) return EINA_FALSE; /* no need to update the overlay if it's not visible */
685
686 /* If any recoloring of the surface is needed, n overlay to */
687 if ((obj->cur.cache.clip.r != 255) ||
688 (obj->cur.cache.clip.g != 255) ||
689 (obj->cur.cache.clip.b != 255) ||
690 (obj->cur.cache.clip.a != 255))
691 return EINA_FALSE;
692
693 /* Check presence of transparent object on top of the video object */
694 EINA_RECTANGLE_SET(&zone,
695 obj->cur.cache.clip.x,
696 obj->cur.cache.clip.y,
697 obj->cur.cache.clip.w,
698 obj->cur.cache.clip.h);
699
700 for (i = e->active_objects.count - 1; i > 0; i--)
701 {
702 Eina_Rectangle self;
703 Eina_Rectangle *match;
704 Evas_Object *current;
705 Eina_List *l;
706 int xm1, ym1, xm2, ym2;
707
708 current = eina_array_data_get(&e->active_objects, i);
709
710 /* Did we find the video object in the stack ? */
711 if (current == video_parent || current == obj)
712 break;
713
714 EINA_RECTANGLE_SET(&self,
715 current->cur.cache.clip.x,
716 current->cur.cache.clip.y,
717 current->cur.cache.clip.w,
718 current->cur.cache.clip.h);
719
720 /* This doesn't cover the area of the video object, so don't bother with that object */
721 if (!eina_rectangles_intersect(&zone, &self))
722 continue ;
723
724 xc1 = current->cur.cache.clip.x;
725 yc1 = current->cur.cache.clip.y;
726 xc2 = current->cur.cache.clip.x + current->cur.cache.clip.w;
727 yc2 = current->cur.cache.clip.y + current->cur.cache.clip.h;
728
729 if (evas_object_is_visible(current) &&
730 (!current->clip.clipees) &&
731 (current->cur.visible) &&
732 (!current->delete_me) &&
733 (current->cur.cache.clip.visible) &&
734 (!current->smart.smart))
735 {
736 Eina_Bool included = EINA_FALSE;
737
738 if (evas_object_is_opaque(current) ||
739 ((current->func->has_opaque_rect) &&
740 (current->func->has_opaque_rect(current))))
741 {
742 /* The object is opaque */
743
744 /* Check if the opaque object is inside another opaque object */
745 EINA_LIST_FOREACH(opaques, l, match)
746 {
747 xm1 = match->x;
748 ym1 = match->y;
749 xm2 = match->x + match->w;
750 ym2 = match->y + match->h;
751
752 /* Both object are included */
753 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
754 {
755 included = EINA_TRUE;
756 break;
757 }
758 }
759
760 /* Not included yet */
761 if (!included)
762 {
763 Eina_List *ln;
764 Evas_Coord xn2, yn2;
765
766 r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y,
767 current->cur.cache.clip.w, current->cur.cache.clip.h);
768
769 opaques = eina_list_append(opaques, r);
770
771 xn2 = r->x + r->w;
772 yn2 = r->y + r->h;
773
774 /* Remove all the transparent object that are covered by the new opaque object */
775 EINA_LIST_FOREACH_SAFE(alphas, l, ln, match)
776 {
777 xm1 = match->x;
778 ym1 = match->y;
779 xm2 = match->x + match->w;
780 ym2 = match->y + match->h;
781
782 if (xm1 >= r->x && ym1 >= r->y && xm2 <= xn2 && ym2 <= yn2)
783 {
784 /* The new rectangle is over some transparent object,
785 so remove the transparent object */
786 alphas = eina_list_remove_list(alphas, l);
787 }
788 }
789 }
790 }
791 else
792 {
793 /* The object has some transparency */
794
795 /* Check if the transparent object is inside any other transparent object */
796 EINA_LIST_FOREACH(alphas, l, match)
797 {
798 xm1 = match->x;
799 ym1 = match->y;
800 xm2 = match->x + match->w;
801 ym2 = match->y + match->h;
802
803 /* Both object are included */
804 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
805 {
806 included = EINA_TRUE;
807 break;
808 }
809 }
810
811 /* If not check if it is inside any opaque one */
812 if (!included)
813 {
814 EINA_LIST_FOREACH(opaques, l, match)
815 {
816 xm1 = match->x;
817 ym1 = match->y;
818 xm2 = match->x + match->w;
819 ym2 = match->y + match->h;
820
821 /* Both object are included */
822 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
823 {
824 included = EINA_TRUE;
825 break;
826 }
827 }
828 }
829
830 /* No inclusion at all, so add it */
831 if (!included)
832 {
833 r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y,
834 current->cur.cache.clip.w, current->cur.cache.clip.h);
835
836 alphas = eina_list_append(alphas, r);
837 }
838 }
839 }
840 }
841
842 /* If there is any pending transparent object, then no overlay */
843 nooverlay = !!eina_list_count(alphas);
844
845 EINA_LIST_FREE(alphas, r)
846 eina_rectangle_free(r);
847 EINA_LIST_FREE(opaques, r)
848 eina_rectangle_free(r);
849
850 if (nooverlay)
851 return EINA_FALSE;
852
853 return EINA_TRUE;
854}
855
856Eina_Bool
857evas_render_mapped(Evas *e, Evas_Object *obj, void *context, void *surface,
858 int off_x, int off_y, int mapped,
859 int ecx, int ecy, int ecw, int ech
860#ifdef REND_DGB
861 , int level
862#endif
863 )
864{
865 void *ctx;
866 Evas_Object *obj2;
867 Eina_Bool clean_them = EINA_FALSE;
868
869 evas_object_clip_recalc(obj);
870 RDI(level);
871 RD(" { evas_render_mapped(%p, %p, %p, %p, %i, %i, %i, %i)\n", e, obj, context, surface, off_x, off_y, mapped, level);
872 if (mapped)
873 {
874 if ((!evas_object_is_visible(obj)) || (obj->clip.clipees) ||
875 (obj->cur.have_clipees))
876 {
877 RDI(level);
878 RD(" }\n");
879 return clean_them;
880 }
881 }
882 else if (!(((evas_object_is_active(obj) && (!obj->clip.clipees) &&
883 (_evas_render_can_render(obj))))
884 ))
885 {
886 RDI(level);
887 RD(" }\n");
888 return clean_them;
889 }
890
891 // set render_pre - for child objs that may not have gotten it.
892 obj->pre_render_done = 1;
893 RD(" Hasmap: %p (%d) %p %d -> %d\n",obj->func->can_map,
894 obj->func->can_map ? obj->func->can_map(obj): -1,
895 obj->cur.map, obj->cur.usemap,
896 _evas_render_has_map(obj));
897 if (_evas_render_has_map(obj))
898 {
899 const Evas_Map_Point *p, *p_end;
900 RGBA_Map_Point pts[4], *pt;
901 int sw, sh;
902 int changed = 0, rendered = 0;
903
904 clean_them = EINA_TRUE;
905
906 sw = obj->cur.geometry.w;
907 sh = obj->cur.geometry.h;
908 RDI(level);
909 RD(" mapped obj: %ix%i\n", sw, sh);
910 if ((sw <= 0) || (sh <= 0))
911 {
912 RDI(level);
913 RD(" }\n");
914 return clean_them;
915 }
916
917 pts[0].px = obj->cur.map->persp.px << FP;
918 pts[0].py = obj->cur.map->persp.py << FP;
919 pts[0].foc = obj->cur.map->persp.foc << FP;
920 pts[0].z0 = obj->cur.map->persp.z0 << FP;
921
922 p = obj->cur.map->points;
923 p_end = p + obj->cur.map->count;
924 pt = pts;
925 for (; p < p_end; p++, pt++)
926 {
927 pt->x = (lround(p->x) + off_x) * FP1;
928 pt->y = (lround(p->y) + off_y) * FP1;
929 pt->z = (lround(p->z) ) * FP1;
930 pt->fx = p->px;
931 pt->fy = p->py;
932 pt->fz = p->z;
933 pt->u = lround(p->u) * FP1;
934 pt->v = lround(p->v) * FP1;
935 if (pt->u < 0) pt->u = 0;
936 else if (pt->u > (sw * FP1)) pt->u = (sw * FP1);
937 if (pt->v < 0) pt->v = 0;
938 else if (pt->v > (sh * FP1)) pt->v = (sh * FP1);
939 pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b);
940 }
941 /* Copy last for software engine */
942 if (obj->cur.map->count & 0x1)
943 {
944 pts[obj->cur.map->count] = pts[obj->cur.map->count - 1];
945 }
946
947
948 if (obj->cur.map->surface)
949 {
950 if ((obj->cur.map->surface_w != sw) ||
951 (obj->cur.map->surface_h != sh))
952 {
953 RDI(level);
954 RD(" new surf: %ix%i\n", sw, sh);
955 obj->layer->evas->engine.func->image_map_surface_free
956 (e->engine.data.output, obj->cur.map->surface);
957 obj->cur.map->surface = NULL;
958 }
959 }
960 if (!obj->cur.map->surface)
961 {
962 obj->cur.map->surface_w = sw;
963 obj->cur.map->surface_h = sh;
964
965 obj->cur.map->surface =
966 obj->layer->evas->engine.func->image_map_surface_new
967 (e->engine.data.output, obj->cur.map->surface_w,
968 obj->cur.map->surface_h,
969 obj->cur.map->alpha);
970 RDI(level);
971 RD(" fisrt surf: %ix%i\n", sw, sh);
972 changed = 1;
973 }
974 if (obj->smart.smart)
975 {
976 Evas_Object *o2;
977
978 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), o2)
979 {
980 if (!evas_object_is_visible(o2) &&
981 !evas_object_was_visible(o2))
982 {
983 o2->changed = 0;
984 o2->changed_move_only = 0;
985 o2->changed_nomove = 0;
986 o2->changed_move = 0;
987 continue;
988 }
989 if (o2->changed)
990 {
991 // chlist(o2, 0);
992 changed = 1;
993 o2->changed = 0;
994 o2->changed_move_only = 0;
995 o2->changed_nomove = 0;
996 o2->changed_move = 0;
997 break;
998 }
999 }
1000 // unchange(obj);
1001 obj->changed = 0;
1002 obj->changed_move_only = 0;
1003 obj->changed_nomove = 0;
1004 obj->changed_move = 0;
1005 }
1006 else
1007 {
1008 if (obj->changed)
1009 {
1010 changed = 1;
1011 obj->changed = 0;
1012 obj->changed_move_only = 0;
1013 obj->changed_nomove = 0;
1014 obj->changed_move = 0;
1015 }
1016 }
1017
1018 // clear surface before re-render
1019 if ((changed) && (obj->cur.map->surface))
1020 {
1021 int off_x2, off_y2;
1022
1023 RDI(level);
1024 RD(" children redraw\n");
1025 // FIXME: calculate "changes" within map surface and only clear
1026 // and re-render those
1027 if (obj->cur.map->alpha)
1028 {
1029 ctx = e->engine.func->context_new(e->engine.data.output);
1030 e->engine.func->context_color_set
1031 (e->engine.data.output, ctx, 0, 0, 0, 0);
1032 e->engine.func->context_render_op_set
1033 (e->engine.data.output, ctx, EVAS_RENDER_COPY);
1034 e->engine.func->rectangle_draw(e->engine.data.output,
1035 ctx,
1036 obj->cur.map->surface,
1037 0, 0,
1038 obj->cur.map->surface_w,
1039 obj->cur.map->surface_h);
1040 e->engine.func->context_free(e->engine.data.output, ctx);
1041 }
1042 ctx = e->engine.func->context_new(e->engine.data.output);
1043 off_x2 = -obj->cur.geometry.x;
1044 off_y2 = -obj->cur.geometry.y;
1045 if (obj->smart.smart)
1046 {
1047 EINA_INLIST_FOREACH
1048 (evas_object_smart_members_get_direct(obj), obj2)
1049 {
1050 clean_them |= evas_render_mapped(e, obj2, ctx,
1051 obj->cur.map->surface,
1052 off_x2, off_y2, 1,
1053 ecx, ecy, ecw, ech
1054#ifdef REND_DGB
1055 , level + 1
1056#endif
1057 );
1058 }
1059 }
1060 else
1061 {
1062 int x = 0, y = 0, w = 0, h = 0;
1063
1064 w = obj->cur.map->surface_w;
1065 h = obj->cur.map->surface_h;
1066 RECTS_CLIP_TO_RECT(x, y, w, h,
1067 obj->cur.geometry.x + off_x2,
1068 obj->cur.geometry.y + off_y2,
1069 obj->cur.geometry.w,
1070 obj->cur.geometry.h);
1071
1072 e->engine.func->context_clip_set(e->engine.data.output,
1073 ctx, x, y, w, h);
1074 obj->func->render(obj, e->engine.data.output, ctx,
1075 obj->cur.map->surface, off_x2, off_y2);
1076 }
1077 e->engine.func->context_free(e->engine.data.output, ctx);
1078 rendered = 1;
1079 }
1080
1081 RDI(level);
1082 RD(" draw map\n");
1083
1084 if (rendered)
1085 {
1086 obj->cur.map->surface = e->engine.func->image_dirty_region
1087 (e->engine.data.output, obj->cur.map->surface,
1088 0, 0, obj->cur.map->surface_w, obj->cur.map->surface_h);
1089 }
1090 e->engine.func->context_clip_unset(e->engine.data.output,
1091 e->engine.data.context);
1092 if (obj->cur.map->surface)
1093 {
1094 if (obj->smart.smart)
1095 {
1096 if (obj->cur.clipper)
1097 {
1098 int x, y, w, h;
1099 Evas_Object *tobj;
1100
1101 obj->cur.cache.clip.dirty = 1;
1102 tobj = obj->cur.map_parent;
1103 obj->cur.map_parent = obj->cur.clipper->cur.map_parent;
1104 evas_object_clip_recalc(obj);
1105 obj->cur.map_parent = tobj;
1106 x = obj->cur.cache.clip.x;
1107 y = obj->cur.cache.clip.y;
1108 w = obj->cur.cache.clip.w;
1109 h = obj->cur.cache.clip.h;
1110 RECTS_CLIP_TO_RECT(x, y, w, h,
1111 obj->cur.clipper->cur.cache.clip.x,
1112 obj->cur.clipper->cur.cache.clip.y,
1113 obj->cur.clipper->cur.cache.clip.w,
1114 obj->cur.clipper->cur.cache.clip.h);
1115 e->engine.func->context_clip_set(e->engine.data.output,
1116 e->engine.data.context,
1117 x + off_x, y + off_y, w, h);
1118 }
1119 }
1120 else
1121 {
1122 if (obj->cur.clipper)
1123 {
1124 int x, y, w, h;
1125
1126 evas_object_clip_recalc(obj);
1127 x = obj->cur.cache.clip.x;
1128 y = obj->cur.cache.clip.y;
1129 w = obj->cur.cache.clip.w;
1130 h = obj->cur.cache.clip.h;
1131 RECTS_CLIP_TO_RECT(x, y, w, h,
1132 obj->cur.clipper->cur.cache.clip.x,
1133 obj->cur.clipper->cur.cache.clip.y,
1134 obj->cur.clipper->cur.cache.clip.w,
1135 obj->cur.clipper->cur.cache.clip.h);
1136 e->engine.func->context_clip_set(e->engine.data.output,
1137 e->engine.data.context,
1138 x + off_x, y + off_y, w, h);
1139 }
1140 }
1141 }
1142 if (surface == e->engine.data.output)
1143 e->engine.func->context_clip_clip(e->engine.data.output,
1144 e->engine.data.context,
1145 ecx, ecy, ecw, ech);
1146 if (obj->cur.cache.clip.visible)
1147 obj->layer->evas->engine.func->image_map_draw
1148 (e->engine.data.output, e->engine.data.context, surface,
1149 obj->cur.map->surface, obj->cur.map->count, pts,
1150 obj->cur.map->smooth, 0);
1151 // FIXME: needs to cache these maps and
1152 // keep them only rendering updates
1153 // obj->layer->evas->engine.func->image_map_surface_free
1154 // (e->engine.data.output, obj->cur.map->surface);
1155 // obj->cur.map->surface = NULL;
1156 }
1157 else
1158 {
1159 if (mapped)
1160 {
1161 RDI(level);
1162 RD(" draw child of mapped obj\n");
1163 ctx = e->engine.func->context_new(e->engine.data.output);
1164 if (obj->smart.smart)
1165 {
1166 EINA_INLIST_FOREACH
1167 (evas_object_smart_members_get_direct(obj), obj2)
1168 {
1169 clean_them |= evas_render_mapped(e, obj2, ctx,
1170 surface,
1171 off_x, off_y, 1,
1172 ecx, ecy, ecw, ech
1173#ifdef REND_DGB
1174 , level + 1
1175#endif
1176 );
1177 }
1178 }
1179 else
1180 {
1181 if (!obj->cur.map)
1182 {
1183 int x, y, w, h;
1184
1185 RDI(level);
1186
1187 x = obj->cur.cache.clip.x + off_x;
1188 y = obj->cur.cache.clip.y + off_y;
1189 w = obj->cur.cache.clip.w;
1190 h = obj->cur.cache.clip.h;
1191
1192 if (obj->cur.clipper)
1193 {
1194 if (_evas_render_has_map(obj))
1195 evas_object_clip_recalc(obj);
1196
1197 RD(" clipper: %i %i %ix%i\n",
1198 obj->cur.clipper->cur.cache.clip.x + off_x,
1199 obj->cur.clipper->cur.cache.clip.y + off_y,
1200 obj->cur.clipper->cur.cache.clip.w,
1201 obj->cur.clipper->cur.cache.clip.h);
1202
1203 RECTS_CLIP_TO_RECT(x, y, w, h,
1204 obj->cur.clipper->cur.cache.clip.x + off_x,
1205 obj->cur.clipper->cur.cache.clip.y + off_y,
1206 obj->cur.clipper->cur.cache.clip.w,
1207 obj->cur.clipper->cur.cache.clip.h);
1208 }
1209
1210 RD(" clip: %i %i %ix%i [%i %i %ix%i]\n",
1211 obj->cur.cache.clip.x + off_x,
1212 obj->cur.cache.clip.y + off_y,
1213 obj->cur.cache.clip.w,
1214 obj->cur.cache.clip.h,
1215 obj->cur.geometry.x + off_x,
1216 obj->cur.geometry.y + off_y,
1217 obj->cur.geometry.w,
1218 obj->cur.geometry.h);
1219 e->engine.func->context_clip_set(e->engine.data.output,
1220 ctx, x, y, w, h);
1221 }
1222 else
1223 {
1224 RDI(level);
1225 RD(" noclip\n");
1226 }
1227 obj->func->render(obj, e->engine.data.output, ctx,
1228 surface, off_x, off_y);
1229 /*
1230 obj->layer->evas->engine.func->context_color_set(e->engine.data.output,
1231 ctx,
1232 0, 30, 0, 30);
1233 obj->layer->evas->engine.func->rectangle_draw(e->engine.data.output,
1234 ctx,
1235 surface,
1236 0, 0, 9999, 9999);
1237 */
1238 }
1239 e->engine.func->context_free(e->engine.data.output, ctx);
1240 }
1241 else
1242 {
1243 if (obj->cur.clipper)
1244 {
1245 int x, y, w, h;
1246
1247 if (_evas_render_has_map(obj))
1248 evas_object_clip_recalc(obj);
1249 x = obj->cur.cache.clip.x;
1250 y = obj->cur.cache.clip.y;
1251 w = obj->cur.cache.clip.w;
1252 h = obj->cur.cache.clip.h;
1253 RECTS_CLIP_TO_RECT(x, y, w, h,
1254 obj->cur.clipper->cur.cache.clip.x,
1255 obj->cur.clipper->cur.cache.clip.y,
1256 obj->cur.clipper->cur.cache.clip.w,
1257 obj->cur.clipper->cur.cache.clip.h);
1258 e->engine.func->context_clip_set(e->engine.data.output,
1259 e->engine.data.context,
1260 x + off_x, y + off_y, w, h);
1261 e->engine.func->context_clip_clip(e->engine.data.output,
1262 e->engine.data.context,
1263 ecx, ecy, ecw, ech);
1264 }
1265
1266 RDI(level);
1267 RD(" draw normal obj\n");
1268 obj->func->render(obj, e->engine.data.output, context, surface,
1269 off_x, off_y);
1270 }
1271 }
1272 RDI(level);
1273 RD(" }\n");
1274
1275 return clean_them;
1276}
1277
1278static void
1279_evas_render_cutout_add(Evas *e, Evas_Object *obj, int off_x, int off_y)
1280{
1281 if (evas_object_is_opaque(obj))
1282 {
1283 Evas_Coord cox, coy, cow, coh;
1284
1285 cox = obj->cur.cache.clip.x;
1286 coy = obj->cur.cache.clip.y;
1287 cow = obj->cur.cache.clip.w;
1288 coh = obj->cur.cache.clip.h;
1289 if ((obj->cur.map) && (obj->cur.usemap))
1290 {
1291 Evas_Object *oo;
1292
1293 oo = obj;
1294 while (oo->cur.clipper)
1295 {
1296 if ((oo->cur.clipper->cur.map_parent
1297 != oo->cur.map_parent) &&
1298 (!((oo->cur.map) && (oo->cur.usemap))))
1299 break;
1300 RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
1301 oo->cur.geometry.x,
1302 oo->cur.geometry.y,
1303 oo->cur.geometry.w,
1304 oo->cur.geometry.h);
1305 oo = oo->cur.clipper;
1306 }
1307 }
1308 e->engine.func->context_cutout_add
1309 (e->engine.data.output, e->engine.data.context,
1310 cox + off_x, coy + off_y, cow, coh);
1311 }
1312 else
1313 {
1314 if (obj->func->get_opaque_rect)
1315 {
1316 Evas_Coord obx, oby, obw, obh;
1317
1318 obj->func->get_opaque_rect(obj, &obx, &oby, &obw, &obh);
1319 if ((obw > 0) && (obh > 0))
1320 {
1321 obx += off_x;
1322 oby += off_y;
1323 RECTS_CLIP_TO_RECT(obx, oby, obw, obh,
1324 obj->cur.cache.clip.x + off_x,
1325 obj->cur.cache.clip.y + off_y,
1326 obj->cur.cache.clip.w,
1327 obj->cur.cache.clip.h);
1328 e->engine.func->context_cutout_add
1329 (e->engine.data.output, e->engine.data.context,
1330 obx, oby, obw, obh);
1331 }
1332 }
1333 }
1334}
1335
1336static Eina_List *
1337evas_render_updates_internal(Evas *e,
1338 unsigned char make_updates,
1339 unsigned char do_draw)
1340{
1341 Evas_Object *obj;
1342 Eina_List *updates = NULL;
1343 Eina_List *ll;
1344 void *surface;
1345 Eina_Bool clean_them = EINA_FALSE;
1346 Eina_Bool alpha;
1347 Eina_Rectangle *r;
1348 int ux, uy, uw, uh;
1349 int cx, cy, cw, ch;
1350 unsigned int i, j;
1351 int haveup = 0;
1352 int redraw_all = 0;
1353
1354 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1355 return NULL;
1356 MAGIC_CHECK_END();
1357 if (!e->changed) return NULL;
1358
1359 evas_call_smarts_calculate(e);
1360
1361 RD("[--- RENDER EVAS (size: %ix%i)\n", e->viewport.w, e->viewport.h);
1362
1363 /* Check if the modified object mean recalculating every thing */
1364 if (!e->invalidate)
1365 _evas_render_check_pending_objects(&e->pending_objects, e);
1366
1367 /* phase 1. add extra updates for changed objects */
1368 if (e->invalidate || e->render_objects.count <= 0)
1369 clean_them = _evas_render_phase1_process(e,
1370 &e->active_objects,
1371 &e->restack_objects,
1372 &e->delete_objects,
1373 &e->render_objects,
1374 &redraw_all);
1375
1376 /* phase 1.5. check if the video should be inlined or stay in their overlay */
1377 alpha = e->engine.func->canvas_alpha_get(e->engine.data.output,
1378 e->engine.data.context);
1379
1380 EINA_LIST_FOREACH(e->video_objects, ll, obj)
1381 {
1382 /* we need the surface to be transparent to display the underlying overlay */
1383 if (alpha && _evas_render_can_use_overlay(e, obj))
1384 _evas_object_image_video_overlay_show(obj);
1385 else
1386 _evas_object_image_video_overlay_hide(obj);
1387 }
1388
1389
1390 /* phase 1.8. pre render for proxy */
1391 _evas_render_phase1_direct(e, &e->active_objects, &e->restack_objects,
1392 &e->delete_objects, &e->render_objects);
1393
1394 /* phase 2. force updates for restacks */
1395 for (i = 0; i < e->restack_objects.count; ++i)
1396 {
1397 obj = eina_array_data_get(&e->restack_objects, i);
1398 obj->func->render_pre(obj);
1399 _evas_render_prev_cur_clip_cache_add(e, obj);
1400 }
1401 eina_array_clean(&e->restack_objects);
1402 /* phase 3. add exposes */
1403 EINA_LIST_FREE(e->damages, r)
1404 {
1405 e->engine.func->output_redraws_rect_add(e->engine.data.output,
1406 r->x, r->y, r->w, r->h);
1407 eina_rectangle_free(r);
1408 }
1409 /* phase 4. output & viewport changes */
1410 if (e->viewport.changed)
1411 {
1412 e->engine.func->output_redraws_rect_add(e->engine.data.output,
1413 0, 0,
1414 e->output.w, e->output.h);
1415 }
1416 if (e->output.changed)
1417 {
1418 e->engine.func->output_resize(e->engine.data.output,
1419 e->output.w, e->output.h);
1420 e->engine.func->output_redraws_rect_add(e->engine.data.output,
1421 0, 0,
1422 e->output.w, e->output.h);
1423 }
1424 if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
1425 {
1426 ERR("viewport size != output size!");
1427 }
1428 if (redraw_all)
1429 {
1430 e->engine.func->output_redraws_rect_add(e->engine.data.output,
1431 0, 0,
1432 e->output.w, e->output.h);
1433 }
1434 /* phase 5. add obscures */
1435 EINA_LIST_FOREACH(e->obscures, ll, r)
1436 {
1437 e->engine.func->output_redraws_rect_del(e->engine.data.output,
1438 r->x, r->y, r->w, r->h);
1439 }
1440 /* build obscure objects list of active objects that obscure */
1441 for (i = 0; i < e->active_objects.count; ++i)
1442 {
1443 obj = eina_array_data_get(&e->active_objects, i);
1444 if (UNLIKELY((evas_object_is_opaque(obj) ||
1445 ((obj->func->has_opaque_rect) &&
1446 (obj->func->has_opaque_rect(obj)))) &&
1447 evas_object_is_visible(obj) &&
1448 (!obj->clip.clipees) &&
1449 (obj->cur.visible) &&
1450 (!obj->delete_me) &&
1451 (obj->cur.cache.clip.visible) &&
1452 (!obj->smart.smart)))
1453 /* obscuring_objects = eina_list_append(obscuring_objects, obj); */
1454 eina_array_push(&e->obscuring_objects, obj);
1455 }
1456
1457 /* save this list */
1458 /* obscuring_objects_orig = obscuring_objects; */
1459 /* obscuring_objects = NULL; */
1460 /* phase 6. go thru each update rect and render objects in it*/
1461 if (do_draw)
1462 {
1463 unsigned int offset = 0;
1464
1465 while ((surface =
1466 e->engine.func->output_redraws_next_update_get
1467 (e->engine.data.output,
1468 &ux, &uy, &uw, &uh,
1469 &cx, &cy, &cw, &ch)))
1470 {
1471 int off_x, off_y;
1472
1473 RD(" [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh);
1474 if (make_updates)
1475 {
1476 Eina_Rectangle *rect;
1477
1478 NEW_RECT(rect, ux, uy, uw, uh);
1479 if (rect)
1480 updates = eina_list_append(updates, rect);
1481 }
1482 haveup = 1;
1483 off_x = cx - ux;
1484 off_y = cy - uy;
1485 /* build obscuring objects list (in order from bottom to top) */
1486 for (i = 0; i < e->obscuring_objects.count; ++i)
1487 {
1488 obj = (Evas_Object *)eina_array_data_get
1489 (&e->obscuring_objects, i);
1490 if (evas_object_is_in_output_rect(obj, ux, uy, uw, uh))
1491 {
1492 eina_array_push(&e->temporary_objects, obj);
1493
1494 /* reset the background of the area if needed (using cutout and engine alpha flag to help) */
1495 if (alpha)
1496 _evas_render_cutout_add(e, obj, off_x, off_y);
1497 }
1498 }
1499 if (alpha)
1500 {
1501 e->engine.func->context_clip_set(e->engine.data.output,
1502 e->engine.data.context,
1503 ux + off_x, uy + off_y, uw, uh);
1504 e->engine.func->context_color_set(e->engine.data.output,
1505 e->engine.data.context,
1506 0, 0, 0, 0);
1507 e->engine.func->context_multiplier_unset
1508 (e->engine.data.output, e->engine.data.context);
1509 e->engine.func->context_render_op_set(e->engine.data.output,
1510 e->engine.data.context,
1511 EVAS_RENDER_COPY);
1512 e->engine.func->rectangle_draw(e->engine.data.output,
1513 e->engine.data.context,
1514 surface,
1515 cx, cy, cw, ch);
1516 e->engine.func->context_cutout_clear(e->engine.data.output,
1517 e->engine.data.context);
1518 e->engine.func->context_clip_unset(e->engine.data.output,
1519 e->engine.data.context);
1520 }
1521 /* render all object that intersect with rect */
1522 for (i = 0; i < e->active_objects.count; ++i)
1523 {
1524 obj = eina_array_data_get(&e->active_objects, i);
1525
1526 /* if it's in our outpout rect and it doesn't clip anything */
1527 RD(" OBJ: [%p] '%s' %i %i %ix%i\n", obj, obj->type, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h);
1528 if ((evas_object_is_in_output_rect(obj, ux, uy, uw, uh) ||
1529 (obj->smart.smart)) &&
1530 (!obj->clip.clipees) &&
1531 (obj->cur.visible) &&
1532 (!obj->delete_me) &&
1533 (obj->cur.cache.clip.visible) &&
1534 // (!obj->smart.smart) &&
1535 ((obj->cur.color.a > 0 || obj->cur.render_op != EVAS_RENDER_BLEND)))
1536 {
1537 int x, y, w, h;
1538
1539 RD(" DRAW (vis: %i, a: %i, clipees: %p\n", obj->cur.visible, obj->cur.color.a, obj->clip.clipees);
1540 if ((e->temporary_objects.count > offset) &&
1541 (eina_array_data_get(&e->temporary_objects, offset) == obj))
1542 offset++;
1543 x = cx; y = cy; w = cw; h = ch;
1544 if (((w > 0) && (h > 0)) || (obj->smart.smart))
1545 {
1546 if (!obj->smart.smart)
1547 {
1548 RECTS_CLIP_TO_RECT(x, y, w, h,
1549 obj->cur.cache.clip.x + off_x,
1550 obj->cur.cache.clip.y + off_y,
1551 obj->cur.cache.clip.w,
1552 obj->cur.cache.clip.h);
1553 }
1554 if (obj->cur.mask)
1555 e->engine.func->context_mask_set(e->engine.data.output,
1556 e->engine.data.context,
1557 obj->cur.mask->func->engine_data_get(obj->cur.mask),
1558 obj->cur.mask->cur.geometry.x + off_x,
1559 obj->cur.mask->cur.geometry.y + off_y,
1560 obj->cur.mask->cur.geometry.w,
1561 obj->cur.mask->cur.geometry.h);
1562 else
1563 e->engine.func->context_mask_unset(e->engine.data.output,
1564 e->engine.data.context);
1565 if (obj->cur.clipper)
1566 e->engine.func->context_clip_set(e->engine.data.output,
1567 e->engine.data.context,
1568 x, y, w, h);
1569 else
1570 e->engine.func->context_clip_unset(e->engine.data.output,
1571 e->engine.data.context);
1572#if 1 /* FIXME: this can slow things down... figure out optimum... coverage */
1573 for (j = offset; j < e->temporary_objects.count; ++j)
1574 {
1575 Evas_Object *obj2;
1576
1577 obj2 = (Evas_Object *)eina_array_data_get
1578 (&e->temporary_objects, j);
1579 _evas_render_cutout_add(e, obj2, off_x, off_y);
1580 }
1581#endif
1582 e->engine.func->context_clip_set(e->engine.data.output,
1583 e->engine.data.context,
1584 x, y, w, h);
1585 clean_them |= evas_render_mapped(e, obj, e->engine.data.context,
1586 surface, off_x, off_y, 0,
1587 cx, cy, cw, ch
1588#ifdef REND_DGB
1589 , 1
1590#endif
1591 );
1592 e->engine.func->context_cutout_clear(e->engine.data.output,
1593 e->engine.data.context);
1594 }
1595 }
1596 }
1597 /* punch rect out */
1598 e->engine.func->output_redraws_next_update_push(e->engine.data.output,
1599 surface,
1600 ux, uy, uw, uh);
1601 /* free obscuring objects list */
1602 eina_array_clean(&e->temporary_objects);
1603 RD(" ---]\n");
1604 }
1605 /* flush redraws */
1606 if (haveup)
1607 {
1608 evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
1609 e->engine.func->output_flush(e->engine.data.output);
1610 evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
1611 }
1612 }
1613 /* clear redraws */
1614 e->engine.func->output_redraws_clear(e->engine.data.output);
1615 /* and do a post render pass */
1616 for (i = 0; i < e->active_objects.count; ++i)
1617 {
1618 obj = eina_array_data_get(&e->active_objects, i);
1619 obj->pre_render_done = 0;
1620 RD(" OBJ [%p] post... %i %i\n", obj, obj->changed, do_draw);
1621 if ((obj->changed) && (do_draw))
1622 {
1623 RD(" OBJ [%p] post... func1\n", obj);
1624 obj->func->render_post(obj);
1625 obj->restack = 0;
1626 obj->changed = 0;
1627 obj->changed_move_only = 0;
1628 obj->changed_nomove = 0;
1629 obj->changed_move = 0;
1630 }
1631 else if ((obj->cur.map != obj->prev.map) ||
1632 (obj->cur.usemap != obj->prev.usemap))
1633 {
1634 RD(" OBJ [%p] post... func2\n", obj);
1635 obj->func->render_post(obj);
1636 obj->restack = 0;
1637 obj->changed = 0;
1638 obj->changed_move_only = 0;
1639 obj->changed_nomove = 0;
1640 obj->changed_move = 0;
1641 }
1642 /* moved to other pre-process phase 1
1643 if (obj->delete_me == 2)
1644 {
1645 delete_objects = eina_list_append(delete_objects, obj);
1646 }
1647 else if (obj->delete_me != 0) obj->delete_me++;
1648 */
1649 }
1650 /* free our obscuring object list */
1651 eina_array_clean(&e->obscuring_objects);
1652
1653 /* If some object are still marked as changed, do not remove
1654 them from the pending list. */
1655 eina_array_remove(&e->pending_objects, pending_change, NULL);
1656
1657 for (i = 0; i < e->render_objects.count; ++i)
1658 {
1659 obj = eina_array_data_get(&e->render_objects, i);
1660 obj->pre_render_done = 0;
1661 }
1662
1663 /* delete all objects flagged for deletion now */
1664 for (i = 0; i < e->delete_objects.count; ++i)
1665 {
1666 obj = eina_array_data_get(&e->delete_objects, i);
1667 evas_object_free(obj, 1);
1668 }
1669 eina_array_clean(&e->delete_objects);
1670
1671 e->changed = 0;
1672 e->viewport.changed = 0;
1673 e->output.changed = 0;
1674 e->invalidate = 0;
1675
1676 /* If their are some object to restack or some object to delete,
1677 * it's useless to keep the render object list around. */
1678 if (clean_them)
1679 {
1680 eina_array_clean(&e->active_objects);
1681 eina_array_clean(&e->render_objects);
1682 eina_array_clean(&e->restack_objects);
1683 eina_array_clean(&e->delete_objects);
1684 eina_array_clean(&e->obscuring_objects);
1685 e->invalidate = 1;
1686 }
1687
1688 evas_module_clean();
1689
1690 RD("---]\n");
1691
1692 return updates;
1693}
1694
1695EAPI void
1696evas_render_updates_free(Eina_List *updates)
1697{
1698 Eina_Rectangle *r;
1699
1700 EINA_LIST_FREE(updates, r)
1701 eina_rectangle_free(r);
1702}
1703
1704EAPI Eina_List *
1705evas_render_updates(Evas *e)
1706{
1707 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1708 return NULL;
1709 MAGIC_CHECK_END();
1710
1711#ifdef EVAS_FRAME_QUEUING
1712 evas_common_frameq_flush_ready ();
1713#endif
1714
1715 if (!e->changed) return NULL;
1716 return evas_render_updates_internal(e, 1, 1);
1717}
1718
1719EAPI void
1720evas_render(Evas *e)
1721{
1722 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1723 return;
1724 MAGIC_CHECK_END();
1725
1726#ifdef EVAS_FRAME_QUEUING
1727 evas_common_frameq_flush_ready ();
1728#endif
1729
1730 if (!e->changed) return;
1731 evas_render_updates_internal(e, 0, 1);
1732}
1733
1734EAPI void
1735evas_norender(Evas *e)
1736{
1737 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1738 return;
1739 MAGIC_CHECK_END();
1740
1741 // if (!e->changed) return;
1742 evas_render_updates_internal(e, 0, 0);
1743}
1744
1745EAPI void
1746evas_render_idle_flush(Evas *e)
1747{
1748 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1749 return;
1750 MAGIC_CHECK_END();
1751
1752 evas_fonts_zero_presure(e);
1753
1754 if ((e->engine.func) && (e->engine.func->output_idle_flush) &&
1755 (e->engine.data.output))
1756 e->engine.func->output_idle_flush(e->engine.data.output);
1757
1758 eina_array_flush(&e->delete_objects);
1759 eina_array_flush(&e->active_objects);
1760 eina_array_flush(&e->restack_objects);
1761 eina_array_flush(&e->render_objects);
1762 eina_array_flush(&e->clip_changes);
1763
1764 e->invalidate = 1;
1765}
1766
1767EAPI void
1768evas_sync(Evas *e)
1769{
1770#ifdef EVAS_FRAME_QUEUING
1771 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1772 return;
1773 MAGIC_CHECK_END();
1774
1775 evas_common_frameq_flush();
1776#else
1777 (void) e;
1778#endif
1779}
1780
1781static void
1782_evas_render_dump_map_surfaces(Evas_Object *obj)
1783{
1784 if ((obj->cur.map) && obj->cur.map->surface)
1785 {
1786 obj->layer->evas->engine.func->image_map_surface_free
1787 (obj->layer->evas->engine.data.output, obj->cur.map->surface);
1788 obj->cur.map->surface = NULL;
1789 }
1790
1791 if (obj->smart.smart)
1792 {
1793 Evas_Object *obj2;
1794
1795 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
1796 _evas_render_dump_map_surfaces(obj2);
1797 }
1798}
1799
1800EAPI void
1801evas_render_dump(Evas *e)
1802{
1803 Evas_Layer *lay;
1804
1805 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1806 return;
1807 MAGIC_CHECK_END();
1808
1809 EINA_INLIST_FOREACH(e->layers, lay)
1810 {
1811 Evas_Object *obj;
1812
1813 EINA_INLIST_FOREACH(lay->objects, obj)
1814 {
1815 if ((obj->type) && (!strcmp(obj->type, "image")))
1816 evas_object_inform_call_image_unloaded(obj);
1817 _evas_render_dump_map_surfaces(obj);
1818 }
1819 }
1820 if ((e->engine.func) && (e->engine.func->output_dump) &&
1821 (e->engine.data.output))
1822 e->engine.func->output_dump(e->engine.data.output);
1823}
1824
1825void
1826evas_render_invalidate(Evas *e)
1827{
1828 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1829 return;
1830 MAGIC_CHECK_END();
1831
1832 eina_array_clean(&e->active_objects);
1833 eina_array_clean(&e->render_objects);
1834
1835 eina_array_flush(&e->restack_objects);
1836 eina_array_flush(&e->delete_objects);
1837
1838 e->invalidate = 1;
1839}
1840
1841void
1842evas_render_object_recalc(Evas_Object *obj)
1843{
1844 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1845 return;
1846 MAGIC_CHECK_END();
1847
1848#ifndef EVAS_FRAME_QUEUING
1849 if ((!obj->changed) && (obj->delete_me < 2))
1850#else
1851 if ((!obj->changed))
1852#endif
1853 {
1854 Evas *e;
1855
1856 e = obj->layer->evas;
1857 if ((!e) || (e->cleanup)) return;
1858#ifdef EVAS_FRAME_QUEUING
1859 if (obj->delete_me >= evas_common_frameq_get_frameq_sz() + 2) return;
1860#endif
1861 eina_array_push(&e->pending_objects, obj);
1862 obj->changed = 1;
1863 }
1864}
1865
1866/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
diff --git a/libraries/evas/src/lib/canvas/evas_smart.c b/libraries/evas/src/lib/canvas/evas_smart.c
new file mode 100644
index 0000000..0cfba05
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_smart.c
@@ -0,0 +1,266 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4
5static void _evas_smart_class_callbacks_create(Evas_Smart *s);
6
7/* all public */
8
9EAPI void
10evas_smart_free(Evas_Smart *s)
11{
12 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
13 return;
14 MAGIC_CHECK_END();
15 s->delete_me = 1;
16 if (s->usage > 0) return;
17 if (s->class_allocated) free((void *)s->smart_class);
18 free(s->callbacks.array);
19 free(s);
20}
21
22EAPI Evas_Smart *
23evas_smart_class_new(const Evas_Smart_Class *sc)
24{
25 Evas_Smart *s;
26
27 if (!sc) return NULL;
28
29 /* api does not match abi! for now refuse as we only have 1 version */
30 if (sc->version != EVAS_SMART_CLASS_VERSION) return NULL;
31
32 s = evas_mem_calloc(sizeof(Evas_Smart));
33 if (!s) return NULL;
34
35 s->magic = MAGIC_SMART;
36
37 s->smart_class = sc;
38 _evas_smart_class_callbacks_create(s);
39
40 return s;
41}
42
43EAPI const Evas_Smart_Class *
44evas_smart_class_get(const Evas_Smart *s)
45{
46 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
47 return NULL;
48 MAGIC_CHECK_END();
49 return s->smart_class;
50}
51
52EAPI void *
53evas_smart_data_get(const Evas_Smart *s)
54{
55 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
56 return NULL;
57 MAGIC_CHECK_END();
58 return (void *)s->smart_class->data;
59}
60
61EAPI const Evas_Smart_Cb_Description **
62evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count)
63{
64 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
65 if (count) *count = 0;
66 return NULL;
67 MAGIC_CHECK_END();
68
69 if (count) *count = s->callbacks.size;
70 return s->callbacks.array;
71}
72
73EAPI const Evas_Smart_Cb_Description *
74evas_smart_callback_description_find(const Evas_Smart *s, const char *name)
75{
76 if (!name) return NULL;
77 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
78 return NULL;
79 MAGIC_CHECK_END();
80 return evas_smart_cb_description_find(&s->callbacks, name);
81}
82
83EAPI Eina_Bool
84evas_smart_class_inherit_full(Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size)
85{
86 unsigned int off;
87
88 /* api does not match abi! for now refuse as we only have 1 version */
89 if (parent_sc->version != EVAS_SMART_CLASS_VERSION) return EINA_FALSE;
90
91#define _CP(m) sc->m = parent_sc->m
92 _CP(add);
93 _CP(del);
94 _CP(move);
95 _CP(resize);
96 _CP(show);
97 _CP(hide);
98 _CP(color_set);
99 _CP(clip_set);
100 _CP(clip_unset);
101 _CP(calculate);
102 _CP(member_add);
103 _CP(member_del);
104#undef _CP
105
106 sc->parent = parent_sc;
107
108 off = sizeof(Evas_Smart_Class);
109 if (parent_sc_size == off) return EINA_TRUE;
110
111 memcpy(((char *)sc) + off, ((char *)parent_sc) + off, parent_sc_size - off);
112 return EINA_TRUE;
113}
114
115EAPI int
116evas_smart_usage_get(const Evas_Smart *s)
117{
118 MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART);
119 return 0;
120 MAGIC_CHECK_END();
121 return s->usage;
122}
123
124
125/* internal funcs */
126void
127evas_object_smart_use(Evas_Smart *s)
128{
129 s->usage++;
130}
131
132void
133evas_object_smart_unuse(Evas_Smart *s)
134{
135 s->usage--;
136 if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s);
137}
138
139Eina_Bool
140evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size)
141{
142 void *tmp;
143
144 if (size == a->size)
145 return EINA_TRUE;
146
147 if (size == EINA_FALSE)
148 {
149 free(a->array);
150 a->array = NULL;
151 a->size = 0;
152 return EINA_TRUE;
153 }
154
155 tmp = realloc(a->array, (size + 1) * sizeof(Evas_Smart_Cb_Description *));
156 if (tmp)
157 {
158 a->array = tmp;
159 a->size = size;
160 a->array[size] = NULL;
161 return EINA_TRUE;
162 }
163 else
164 {
165 ERR("realloc failed!");
166 return EINA_FALSE;
167 }
168}
169
170static int
171_evas_smart_cb_description_cmp_sort(const void *p1, const void *p2)
172{
173 const Evas_Smart_Cb_Description **a = (const Evas_Smart_Cb_Description **)p1;
174 const Evas_Smart_Cb_Description **b = (const Evas_Smart_Cb_Description **)p2;
175 return strcmp((*a)->name, (*b)->name);
176}
177
178void
179evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a)
180{
181 unsigned int i, j;
182
183 if (!a)
184 {
185 ERR("no array to fix!");
186 return;
187 }
188
189 qsort(a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
190 _evas_smart_cb_description_cmp_sort);
191
192 DBG("%u callbacks", a->size);
193 if (a->size)
194 DBG("%s [type=%s]", a->array[0]->name, a->array[0]->type);
195
196 for (i = 0, j = 1; j < a->size; j++)
197 {
198 const Evas_Smart_Cb_Description *cur, *prev;
199
200 cur = a->array[j];
201 prev = a->array[i];
202
203 DBG("%s [type=%s]", cur->name, cur->type);
204
205 if (strcmp(cur->name, prev->name) != 0)
206 {
207 i++;
208 if (i != j)
209 a->array[i] = a->array[j];
210 }
211 else
212 {
213 if (strcmp(cur->type, prev->type) == 0)
214 WRN("duplicated smart callback description"
215 " with name '%s' and type '%s'", cur->name, cur->type);
216 else
217 ERR("callback descriptions named '%s' differ"
218 " in type, keeping '%s', ignoring '%s'",
219 cur->name, prev->type, cur->type);
220 }
221 }
222
223 evas_smart_cb_descriptions_resize(a, i + 1);
224}
225
226static void
227_evas_smart_class_callbacks_create(Evas_Smart *s)
228{
229 const Evas_Smart_Class *sc;
230 unsigned int n = 0;
231
232 for (sc = s->smart_class; sc; sc = sc->parent)
233 {
234 const Evas_Smart_Cb_Description *d;
235 for (d = sc->callbacks; d && d->name; d++)
236 n++;
237 }
238
239 if (n == 0) return;
240 if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return;
241 for (n = 0, sc = s->smart_class; sc; sc = sc->parent)
242 {
243 const Evas_Smart_Cb_Description *d;
244 for (d = sc->callbacks; d && d->name; d++)
245 s->callbacks.array[n++] = d;
246 }
247 evas_smart_cb_descriptions_fix(&s->callbacks);
248}
249
250static int
251_evas_smart_cb_description_cmp_search(const void *p1, const void *p2)
252{
253 const char *name = p1;
254 const Evas_Smart_Cb_Description **v = (const Evas_Smart_Cb_Description **)p2;
255 /* speed up string shares searches (same pointers) */
256 if (name == (*v)->name) return 0;
257 return strcmp(name, (*v)->name);
258}
259
260const Evas_Smart_Cb_Description *
261evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name)
262{
263 if (!a->array) return NULL;
264 return bsearch(name, a->array, a->size, sizeof(Evas_Smart_Cb_Description *),
265 _evas_smart_cb_description_cmp_search);
266}
diff --git a/libraries/evas/src/lib/canvas/evas_stack.c b/libraries/evas/src/lib/canvas/evas_stack.c
new file mode 100644
index 0000000..a8dec0d
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_stack.c
@@ -0,0 +1,391 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4static Evas_Object *
5evas_object_above_get_internal(const Evas_Object *obj)
6{
7 if ((EINA_INLIST_GET(obj))->next)
8 return (Evas_Object *)((EINA_INLIST_GET(obj))->next);
9 else
10 {
11 if ((EINA_INLIST_GET(((Evas_Object*)(obj))->layer))->next)
12 {
13 Evas_Layer *l;
14
15 l = (Evas_Layer *)((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->next);
16 return l->objects;
17 }
18 }
19 return NULL;
20}
21
22static Evas_Object *
23evas_object_below_get_internal(const Evas_Object *obj)
24{
25 if ((EINA_INLIST_GET(obj))->prev)
26 return (Evas_Object *)((EINA_INLIST_GET(obj))->prev);
27 else
28 {
29 if ((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->prev)
30 {
31 Evas_Layer *l;
32
33 l = (Evas_Layer *)((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->prev);
34 return (Evas_Object *)((EINA_INLIST_GET((l->objects)))->last);
35 }
36 }
37 return NULL;
38}
39
40EAPI void
41evas_object_raise(Evas_Object *obj)
42{
43 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
44 return;
45 MAGIC_CHECK_END();
46 if (evas_object_intercept_call_raise(obj)) return;
47 if (!((EINA_INLIST_GET(obj))->next))
48 {
49 evas_object_inform_call_restack(obj);
50 return;
51 }
52 if (obj->smart.parent)
53 evas_object_smart_member_raise(obj);
54 else
55 {
56 if (obj->in_layer)
57 obj->layer->objects = (Evas_Object *)eina_inlist_demote(EINA_INLIST_GET(obj->layer->objects), EINA_INLIST_GET(obj));
58 }
59 if (obj->clip.clipees)
60 {
61 evas_object_inform_call_restack(obj);
62 return;
63 }
64 if (obj->layer) evas_render_invalidate(obj->layer->evas);
65 obj->restack = EINA_TRUE;
66 evas_object_change(obj);
67 evas_object_inform_call_restack(obj);
68 if (obj->layer->evas->events_frozen > 0) return;
69 if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj)))
70 {
71 if (!obj->smart.smart)
72 {
73 if (evas_object_is_in_output_rect(obj,
74 obj->layer->evas->pointer.x,
75 obj->layer->evas->pointer.y,
76 1, 1) && obj->cur.visible)
77 evas_event_feed_mouse_move(obj->layer->evas,
78 obj->layer->evas->pointer.x,
79 obj->layer->evas->pointer.y,
80 obj->layer->evas->last_timestamp,
81 NULL);
82 }
83 }
84}
85
86EAPI void
87evas_object_lower(Evas_Object *obj)
88{
89 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
90 return;
91 MAGIC_CHECK_END();
92 if (evas_object_intercept_call_lower(obj)) return;
93 if (!((EINA_INLIST_GET(obj))->prev))
94 {
95 evas_object_inform_call_restack(obj);
96 return;
97 }
98 if (obj->smart.parent)
99 evas_object_smart_member_lower(obj);
100 else
101 {
102 if (obj->in_layer)
103 obj->layer->objects = (Evas_Object *)eina_inlist_promote(EINA_INLIST_GET(obj->layer->objects),
104 EINA_INLIST_GET(obj));
105 }
106 if (obj->clip.clipees)
107 {
108 evas_object_inform_call_restack(obj);
109 return;
110 }
111 if (obj->layer) evas_render_invalidate(obj->layer->evas);
112 obj->restack = EINA_TRUE;
113 evas_object_change(obj);
114 evas_object_inform_call_restack(obj);
115 if (obj->layer->evas->events_frozen > 0) return;
116 if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj)))
117 {
118 if (!obj->smart.smart)
119 {
120 if (evas_object_is_in_output_rect(obj,
121 obj->layer->evas->pointer.x,
122 obj->layer->evas->pointer.y,
123 1, 1) && obj->cur.visible)
124 evas_event_feed_mouse_move(obj->layer->evas,
125 obj->layer->evas->pointer.x,
126 obj->layer->evas->pointer.y,
127 obj->layer->evas->last_timestamp,
128 NULL);
129 }
130 }
131}
132
133EAPI void
134evas_object_stack_above(Evas_Object *obj, Evas_Object *above)
135{
136 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
137 return;
138 MAGIC_CHECK_END();
139 MAGIC_CHECK(above, Evas_Object, MAGIC_OBJ);
140 return;
141 MAGIC_CHECK_END();
142 if (obj == above) return;
143 if (evas_object_intercept_call_stack_above(obj, above)) return;
144 if (!above)
145 {
146 evas_object_raise(obj);
147 return;
148 }
149 if ((EINA_INLIST_GET(obj))->prev == EINA_INLIST_GET(above))
150 {
151 evas_object_inform_call_restack(obj);
152 return;
153 }
154 if (obj->smart.parent)
155 {
156 if (obj->smart.parent != above->smart.parent)
157 {
158 ERR("BITCH! evas_object_stack_above(), %p not inside same smart as %p!", obj, above);
159 return;
160 }
161 evas_object_smart_member_stack_above(obj, above);
162 }
163 else
164 {
165 if (above->smart.parent)
166 {
167 ERR("BITCH! evas_object_stack_above(), %p stack above %p, but above has smart parent, obj does not", obj, above);
168 return;
169 }
170 if (obj->layer != above->layer)
171 {
172 ERR("BITCH! evas_object_stack_above(), %p stack above %p, not matching layers", obj, above);
173 return;
174 }
175 if (obj->in_layer)
176 {
177 obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects),
178 EINA_INLIST_GET(obj));
179 obj->layer->objects = (Evas_Object *)eina_inlist_append_relative(EINA_INLIST_GET(obj->layer->objects),
180 EINA_INLIST_GET(obj),
181 EINA_INLIST_GET(above));
182 }
183 }
184 if (obj->clip.clipees)
185 {
186 evas_object_inform_call_restack(obj);
187 return;
188 }
189 if (obj->layer) evas_render_invalidate(obj->layer->evas);
190 obj->restack = EINA_TRUE;
191 evas_object_change(obj);
192 evas_object_inform_call_restack(obj);
193 if (obj->layer->evas->events_frozen > 0) return;
194 if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj)))
195 {
196 if (!obj->smart.smart)
197 {
198 if (evas_object_is_in_output_rect(obj,
199 obj->layer->evas->pointer.x,
200 obj->layer->evas->pointer.y,
201 1, 1) && obj->cur.visible)
202 evas_event_feed_mouse_move(obj->layer->evas,
203 obj->layer->evas->pointer.x,
204 obj->layer->evas->pointer.y,
205 obj->layer->evas->last_timestamp,
206 NULL);
207 }
208 }
209}
210
211EAPI void
212evas_object_stack_below(Evas_Object *obj, Evas_Object *below)
213{
214 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
215 return;
216 MAGIC_CHECK_END();
217 MAGIC_CHECK(below, Evas_Object, MAGIC_OBJ);
218 return;
219 MAGIC_CHECK_END();
220 if (obj == below) return;
221 if (evas_object_intercept_call_stack_below(obj, below)) return;
222 if (!below)
223 {
224 evas_object_lower(obj);
225 return;
226 }
227 if ((EINA_INLIST_GET(obj))->next == EINA_INLIST_GET(below))
228 {
229 evas_object_inform_call_restack(obj);
230 return;
231 }
232 if (obj->smart.parent)
233 {
234 if (obj->smart.parent != below->smart.parent)
235 {
236 ERR("BITCH! evas_object_stack_below(), %p not inside same smart as %p!", obj, below);
237 return;
238 }
239 evas_object_smart_member_stack_below(obj, below);
240 }
241 else
242 {
243 if (below->smart.parent)
244 {
245 ERR("BITCH! evas_object_stack_below(), %p stack below %p, but below has smart parent, obj does not", obj, below);
246 return;
247 }
248 if (obj->layer != below->layer)
249 {
250 ERR("BITCH! evas_object_stack_below(), %p stack below %p, not matching layers", obj, below);
251 return;
252 }
253 if (obj->in_layer)
254 {
255 obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects),
256 EINA_INLIST_GET(obj));
257 obj->layer->objects = (Evas_Object *)eina_inlist_prepend_relative(EINA_INLIST_GET(obj->layer->objects),
258 EINA_INLIST_GET(obj),
259 EINA_INLIST_GET(below));
260 }
261 }
262 if (obj->clip.clipees)
263 {
264 evas_object_inform_call_restack(obj);
265 return;
266 }
267 if (obj->layer) evas_render_invalidate(obj->layer->evas);
268 obj->restack = EINA_TRUE;
269 evas_object_change(obj);
270 evas_object_inform_call_restack(obj);
271 if (obj->layer->evas->events_frozen > 0) return;
272 if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj)))
273 {
274 if (!obj->smart.smart)
275 {
276 if (evas_object_is_in_output_rect(obj,
277 obj->layer->evas->pointer.x,
278 obj->layer->evas->pointer.y,
279 1, 1) && obj->cur.visible)
280 evas_event_feed_mouse_move(obj->layer->evas,
281 obj->layer->evas->pointer.x,
282 obj->layer->evas->pointer.y,
283 obj->layer->evas->last_timestamp,
284 NULL);
285 }
286 }
287}
288
289EAPI Evas_Object *
290evas_object_above_get(const Evas_Object *obj)
291{
292 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
293 return NULL;
294 MAGIC_CHECK_END();
295 if (obj->smart.parent)
296 {
297 do
298 {
299 obj = (Evas_Object *)((EINA_INLIST_GET(obj))->next);
300 if ((obj) && (!obj->delete_me)) return (Evas_Object *)obj;
301 }
302 while (obj);
303 return NULL;
304 }
305 obj = evas_object_above_get_internal(obj);
306 while (obj)
307 {
308 if (!obj->delete_me) return (Evas_Object *)obj;
309 obj = evas_object_above_get_internal(obj);
310 }
311 return NULL;
312}
313
314EAPI Evas_Object *
315evas_object_below_get(const Evas_Object *obj)
316{
317 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
318 return NULL;
319 MAGIC_CHECK_END();
320 if (obj->smart.parent)
321 {
322 do
323 {
324 obj = (Evas_Object *)((EINA_INLIST_GET(obj))->prev);
325 if ((obj) && (!obj->delete_me)) return (Evas_Object *)obj;
326 }
327 while (obj);
328 return NULL;
329 }
330 obj = evas_object_below_get_internal(obj);
331 while (obj)
332 {
333 if (!obj->delete_me) return (Evas_Object *)obj;
334 obj = evas_object_below_get_internal(obj);
335 }
336 return NULL;
337}
338
339
340
341EAPI Evas_Object *
342evas_object_bottom_get(const Evas *e)
343{
344 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
345 return NULL;
346 MAGIC_CHECK_END();
347 if (e->layers)
348 {
349 Evas_Object *obj;
350
351 obj = e->layers->objects;
352 while (obj)
353 {
354 if (!obj->delete_me) return obj;
355 obj = evas_object_above_get_internal(obj);
356 }
357 }
358 return NULL;
359}
360
361EAPI Evas_Object *
362evas_object_top_get(const Evas *e)
363{
364 Evas_Object *obj = NULL;
365 Eina_Inlist *list;
366 Evas_Layer *layer;
367
368 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
369 return NULL;
370 MAGIC_CHECK_END();
371
372 list = EINA_INLIST_GET(e->layers);
373 if (!list) return NULL;
374
375 layer = (Evas_Layer *) list->last;
376 if (!layer) return NULL;
377
378 list = EINA_INLIST_GET(layer->objects);
379 if (!list) return NULL;
380
381 obj = (Evas_Object *) list->last;
382 if (!obj) return NULL;
383
384 while (obj)
385 {
386 if (!obj->delete_me) return obj;
387 obj = evas_object_below_get_internal(obj);
388 }
389
390 return obj;
391}
diff --git a/libraries/evas/src/lib/canvas/evas_stats.c b/libraries/evas/src/lib/canvas/evas_stats.c
new file mode 100644
index 0000000..cfb1a84
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_stats.c
@@ -0,0 +1,185 @@
1#include "evas_common.h"
2#include "evas_private.h"
3#include "evas_cs.h"
4
5EAPI Eina_Bool
6evas_cserve_want_get(void)
7{
8#ifdef EVAS_CSERVE
9 return evas_cserve_use_get();
10#endif
11 return 0;
12}
13
14EAPI Eina_Bool
15evas_cserve_connected_get(void)
16{
17#ifdef EVAS_CSERVE
18 return evas_cserve_have_get();
19#endif
20 return 0;
21}
22
23EAPI Eina_Bool
24evas_cserve_stats_get(Evas_Cserve_Stats *stats)
25{
26#ifdef EVAS_CSERVE
27 Op_Getstats_Reply st;
28
29 if (!evas_cserve_raw_stats_get(&st)) return 0;
30 if (!stats) return 1;
31 stats->saved_memory = st.saved_memory;
32 stats->wasted_memory = st.wasted_memory;
33 stats->saved_memory_peak = st.saved_memory_peak;
34 stats->wasted_memory_peak = st.wasted_memory_peak;
35 stats->saved_time_image_header_load = st.saved_time_image_header_load;
36 stats->saved_time_image_data_load = st.saved_time_image_data_load;
37 // may expand this in future
38 return 1;
39#else
40 (void) stats;
41 return 0;
42#endif
43}
44
45EAPI Eina_Bool
46evas_cserve_image_cache_contents_get(Evas_Cserve_Image_Cache *cache)
47{
48#ifdef EVAS_CSERVE
49 Op_Getinfo_Reply *info;
50 unsigned char *p;
51 int i, j;
52
53 if (!(info = evas_cserve_raw_info_get())) return 0;
54 if (!cache)
55 {
56 free(info);
57 return 1;
58 }
59 cache->active.mem_total = info->active.mem_total;
60 cache->active.count = info->active.count;
61 cache->cached.mem_total = info->cached.mem_total;
62 cache->cached.count = info->cached.count;
63 cache->images = NULL;
64 j = info->active.count + info->cached.count;
65 p = (unsigned char *)info;
66 p += sizeof(Op_Getinfo_Reply);
67 for (i = 0; i < j; i++)
68 {
69 Evas_Cserve_Image *im;
70 Op_Getinfo_Item it;
71 char *file, *key;
72
73 memcpy(&it, p, sizeof(Op_Getinfo_Item));
74 file = (char*) (p + sizeof(Op_Getinfo_Item));
75 key = file + strlen(file) + 1;
76 im = calloc(1, sizeof(Evas_Cserve_Image));
77 if (!im) continue;
78 if (file[0] != 0)
79 {
80 file = (char *)eina_stringshare_add(file);
81 if (!file)
82 {
83 free(im);
84 continue;
85 }
86 }
87 else
88 file = NULL;
89 if (key[0] != 0)
90 {
91 key = (char *)eina_stringshare_add(key);
92 if (!key)
93 {
94 if (file) eina_stringshare_del(file);
95 free(im);
96 continue;
97 }
98 }
99 else key = NULL;
100 cache->images = eina_list_append(cache->images, im);
101 im->file = file;
102 im->key = key;
103 im->w = it.w;
104 im->h = it.h;
105 im->cached_time = it.cached_time;
106 im->file_mod_time = it.file_mod_time;
107 im->file_checked_time = it.file_checked_time;
108 im->refcount = it.refcount;
109 im->data_refcount = it.data_refcount;
110 im->memory_footprint = it.memory_footprint;
111 im->head_load_time = it.head_load_time;
112 im->data_load_time = it.data_load_time;
113 im->active = it.active;
114 im->alpha = it.alpha;
115 im->data_loaded = it.data_loaded;
116 im->dead = it.dead;
117 im->useless = it.useless;
118 }
119 free(info);
120 return 1;
121#else
122 (void) cache;
123 return 0;
124#endif
125}
126
127EAPI void
128evas_cserve_image_cache_contents_clean(Evas_Cserve_Image_Cache *cache)
129{
130#ifdef EVAS_CSERVE
131 Evas_Cserve_Image *im;
132
133 EINA_LIST_FREE(cache->images, im)
134 {
135 if (im->file) eina_stringshare_del(im->file);
136 if (im->key) eina_stringshare_del(im->key);
137 free(im);
138 }
139#else
140 (void) cache;
141#endif
142}
143
144EAPI Eina_Bool
145evas_cserve_config_get(Evas_Cserve_Config *config)
146{
147#ifdef EVAS_CSERVE
148 Op_Getconfig_Reply conf;
149
150 if (!evas_cserve_raw_config_get(&conf)) return 0;
151 if (!config) return 1;
152 config->cache_max_usage = conf.cache_max_usage;
153 config->cache_item_timeout = conf.cache_item_timeout;
154 config->cache_item_timeout_check = conf.cache_item_timeout_check;
155 return 1;
156#else
157 (void) config;
158 return 0;
159#endif
160}
161
162EAPI Eina_Bool
163evas_cserve_config_set(const Evas_Cserve_Config *config)
164{
165#ifdef EVAS_CSERVE
166 Op_Setconfig conf;
167
168 if (!config) return 1;
169 conf.cache_max_usage = config->cache_max_usage;
170 conf.cache_item_timeout = config->cache_item_timeout;
171 conf.cache_item_timeout_check = config->cache_item_timeout_check;
172 return evas_cserve_raw_config_set(&conf);
173#else
174 (void) config;
175 return 0;
176#endif
177}
178
179EAPI void
180evas_cserve_disconnect(void)
181{
182#ifdef EVAS_CSERVE
183 evas_cserve_discon();
184#endif
185}
diff --git a/libraries/evas/src/lib/canvas/evas_touch_point.c b/libraries/evas/src/lib/canvas/evas_touch_point.c
new file mode 100644
index 0000000..bdea73f
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_touch_point.c
@@ -0,0 +1,110 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4void
5_evas_touch_point_append(Evas *e, int id, Evas_Coord x, Evas_Coord y)
6{
7 Evas_Coord_Touch_Point *point;
8
9 /* create new Evas_Coord_Touch_Point */
10 point = (Evas_Coord_Touch_Point *)calloc(1, sizeof(Evas_Coord_Touch_Point));
11 point->x = x;
12 point->y = y;
13 point->id = id;
14 point->state = EVAS_TOUCH_POINT_DOWN;
15 e->touch_points = eina_list_append(e->touch_points, point);
16}
17
18void
19_evas_touch_point_update(Evas *e, int id, Evas_Coord x, Evas_Coord y, Evas_Touch_Point_State state)
20{
21 Eina_List *l;
22 Evas_Coord_Touch_Point *point = NULL;
23
24 EINA_LIST_FOREACH(e->touch_points, l, point)
25 {
26 if (point->id == id)
27 {
28 point->x = x;
29 point->y = y;
30 point->state = state;
31 break;
32 }
33 }
34}
35
36void
37_evas_touch_point_remove(Evas *e, int id)
38{
39 Eina_List *l;
40 Evas_Coord_Touch_Point *point = NULL;
41
42 EINA_LIST_FOREACH(e->touch_points, l, point)
43 {
44 if (point->id == id)
45 {
46 e->touch_points = eina_list_remove(e->touch_points, point);
47 free(point);
48 break;
49 }
50 }
51}
52
53EAPI unsigned int
54evas_touch_point_list_count(Evas *e)
55{
56 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
57 return 0;
58 MAGIC_CHECK_END();
59 return eina_list_count(e->touch_points);
60}
61
62EAPI void
63evas_touch_point_list_nth_xy_get(Evas *e, unsigned int n, Evas_Coord *x, Evas_Coord *y)
64{
65 Evas_Coord_Touch_Point *point = NULL;
66
67 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
68 if (x) *x = 0;
69 if (y) *y = 0;
70 return;
71 MAGIC_CHECK_END();
72
73 point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n);
74 if (!point)
75 {
76 if (x) *x = 0;
77 if (y) *y = 0;
78 return;
79 }
80 if (x) *x = point->x;
81 if (y) *y = point->y;
82}
83
84EAPI int
85evas_touch_point_list_nth_id_get(Evas *e, unsigned int n)
86{
87 Evas_Coord_Touch_Point *point = NULL;
88
89 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
90 return -1;
91 MAGIC_CHECK_END();
92
93 point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n);
94 if (!point) return -1;
95 return point->id;
96}
97
98EAPI Evas_Touch_Point_State
99evas_touch_point_list_nth_state_get(Evas *e, unsigned int n)
100{
101 Evas_Coord_Touch_Point *point = NULL;
102
103 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
104 return EVAS_TOUCH_POINT_CANCEL;
105 MAGIC_CHECK_END();
106
107 point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n);
108 if (!point) return EVAS_TOUCH_POINT_CANCEL;
109 return point->state;
110}