From fab81faa86e35700608f00bd03590890f2b96c69 Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Sat, 20 Sep 2008 02:03:22 +0000 Subject: [PATCH] tim horton's quartz engine for evas. SVN revision: 36107 --- legacy/evas/AUTHORS | 1 + legacy/evas/Makefile.am | 7 +- legacy/evas/configure.in | 36 + legacy/evas/evas-quartz.pc.in | 3 + legacy/evas/evas.spec.in | 19 + legacy/evas/src/modules/engines/Makefile.am | 3 +- .../engines/gl_common/evas_gl_common.h | 11 +- .../engines/quartz/Evas_Engine_Quartz.h | 22 + .../src/modules/engines/quartz/Makefile.am | 28 + legacy/evas/src/modules/engines/quartz/README | 32 + .../src/modules/engines/quartz/evas_engine.c | 1512 +++++++++++++++++ .../src/modules/engines/quartz/evas_engine.h | 71 + .../engines/quartz/evas_quartz_private.h | 109 ++ 13 files changed, 1849 insertions(+), 5 deletions(-) create mode 100644 legacy/evas/evas-quartz.pc.in create mode 100644 legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h create mode 100644 legacy/evas/src/modules/engines/quartz/Makefile.am create mode 100644 legacy/evas/src/modules/engines/quartz/README create mode 100644 legacy/evas/src/modules/engines/quartz/evas_engine.c create mode 100644 legacy/evas/src/modules/engines/quartz/evas_engine.h create mode 100644 legacy/evas/src/modules/engines/quartz/evas_quartz_private.h diff --git a/legacy/evas/AUTHORS b/legacy/evas/AUTHORS index a93633aa56..6d53c4a1b7 100644 --- a/legacy/evas/AUTHORS +++ b/legacy/evas/AUTHORS @@ -13,3 +13,4 @@ Jorge Luis Zapata Muga Cedric Bail Gustavo Sverzut Barbieri Vincent Torri +Tim Horton diff --git a/legacy/evas/Makefile.am b/legacy/evas/Makefile.am index 8015a3e580..5e8259df9b 100644 --- a/legacy/evas/Makefile.am +++ b/legacy/evas/Makefile.am @@ -27,6 +27,7 @@ evas-fb.pc \ evas-glitz-x11.pc \ evas-opengl-x11.pc \ evas-opengl-glew.pc \ +evas-quartz.pc \ evas-software-buffer.pc \ evas-software-qtopia.pc \ evas-software-x11.pc \ @@ -112,6 +113,10 @@ if BUILD_ENGINE_GL_X11 popenglx11 = evas-opengl-x11.pc endif +if BUILD_ENGINE_QUARTZ +pquartz = evas-quartz.pc +endif + if BUILD_ENGINE_GL_GLEW popenglglew = evas-opengl-glew.pc endif @@ -151,6 +156,6 @@ endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ evas.pc $(psoftwarex11) $(psoftwarexcb) $(pdirectfb) $(pfb) \ - $(psoftwarebuffer) $(psoftwareqtopia) $(popenglx11) $(pcairox11) \ + $(psoftwarebuffer) $(psoftwareqtopia) $(popenglx11) $(pquartz) $(pcairox11) \ $(pxrenderx11) $(pxrenderxcb) $(pglitzx11) $(psoftwareddraw) $(psoftwaresdl) \ $(psoftware16x11) $(pdirect3d) $(psoftware16ddraw) $(psoftware16wince) $(popenglglew) diff --git a/legacy/evas/configure.in b/legacy/evas/configure.in index 60781a89f5..8984fd7bd7 100644 --- a/legacy/evas/configure.in +++ b/legacy/evas/configure.in @@ -595,6 +595,36 @@ if test "x$want_evas_gl_x11" = "xyes"; then fi AM_CONDITIONAL(BUILD_ENGINE_GL_X11, test "x$have_evas_gl_x11" = "xyes") +####################################### +## Check if we should build the quartz engine +## FIXME: someone more experienced with Autotools-on-OSX: how do Frameworks work with AC_CHECK_HEADERS? +## I want this to detect Cocoa/Cocoa.h, but it's not in the normal include path. +want_evas_quartz="no"; +have_evas_quartz="no"; + +AC_MSG_CHECKING(whether quartz backend is to be built) +AC_ARG_ENABLE(quartz, + AC_HELP_STRING([--enable-quartz], [enable the Quartz display engine]), + [ want_evas_quartz=$enableval ] +) +AC_MSG_RESULT($want_evas_quartz) + +if test "x$want_evas_quartz" = "xyes"; then + AC_PATH_X + AC_PATH_XTRA + AC_CHECK_HEADERS(/System/Library/Frameworks/Cocoa.framework/Headers/Cocoa.h, + [ + have_evas_quartz="yes" + ], + [ + if test "x$want_evas_quartz" = "xyes" -a "x$use_strict" = "xyes" ; then + AC_MSG_ERROR([Quartz not found (strict dependencies checking)]) + fi + ] + ) +fi +AM_CONDITIONAL(BUILD_ENGINE_QUARTZ, test "x$have_evas_quartz" = "xyes") + ####################################### ## Check if we should build the gl_glew engine want_evas_gl_glew="no"; @@ -1684,6 +1714,9 @@ AC_SUBST(x_libs) AC_SUBST(gl_cflags) AC_SUBST(gl_libs) +AC_SUBST(quartz_cflags) +AC_SUBST(quartz_libs) + AC_SUBST(qt_cflags) AC_SUBST(qt_libs) AC_SUBST(qt_moc) @@ -1715,6 +1748,7 @@ evas-fb.pc evas-glitz-x11.pc evas-opengl-glew.pc evas-opengl-x11.pc +evas-quartz.pc evas-software-buffer.pc evas-software-qtopia.pc evas-software-x11.pc @@ -1760,6 +1794,7 @@ src/modules/engines/directfb/Makefile src/modules/engines/gl_common/Makefile src/modules/engines/gl_glew/Makefile src/modules/engines/gl_x11/Makefile +src/modules/engines/quartz/Makefile src/modules/engines/cairo_common/Makefile src/modules/engines/cairo_x11/Makefile src/modules/engines/xrender_x11/Makefile @@ -1814,6 +1849,7 @@ echo " Software XCB...............: $have_evas_software_xcb" echo " XRender XCB................: $have_evas_xrender_xcb" echo " Software DirectDraw........: $have_evas_software_ddraw" echo " Direct3d...................: $have_evas_direct3d" +echo " Quartz.....................: $have_evas_quartz" echo " OpenGL Glew................: $have_evas_gl_glew" echo " Software SDL...............: $have_evas_sdl (primitive: $sdl_primitive)" echo " Software Framebuffer.......: $have_evas_fb" diff --git a/legacy/evas/evas-quartz.pc.in b/legacy/evas/evas-quartz.pc.in new file mode 100644 index 0000000000..dccd3933a5 --- /dev/null +++ b/legacy/evas/evas-quartz.pc.in @@ -0,0 +1,3 @@ +Name: evas-quartz +Description: Evas Quartz engine +Version: @VERSION@ diff --git a/legacy/evas/evas.spec.in b/legacy/evas/evas.spec.in index 828cbb5484..11a3270353 100644 --- a/legacy/evas/evas.spec.in +++ b/legacy/evas/evas.spec.in @@ -19,6 +19,7 @@ %bcond_with module_saver_edb %bcond_with module_engine_directfb %bcond_with module_engine_gl_x11 +%bcond_with module_engine_quartz %bcond_with module_engine_software_qtopia %bcond_with module_engine_software_sdl %bcond_with module_engine_software_xcb @@ -67,6 +68,7 @@ %define ac_with_module_engine_fb --%{?with_module_engine_fb:en}%{!?with_module_engine_fb:dis}able-fb %define ac_with_module_engine_xrender_x11 --%{?with_module_engine_xrender_x11:en}%{!?with_module_engine_xrender_x11:dis}able-xrender-x11 %define ac_with_module_engine_gl_x11 --%{?with_module_engine_gl_x11:en}%{!?with_module_engine_gl_x11:dis}able-gl-x11 +%define ac_with_module_engine_quartz --%{?with_module_engine_quartz:en}%{!?with_module_engine_quartz:dis}able-quartz %define ac_with_module_engine_directfb --%{?with_module_engine_directfb:en}%{!?with_module_engine_directfb:dis}able-directfb %define ac_with_module_engine_software_qtopia --%{?with_module_engine_software_qtopia:en}%{!?with_module_engine_software_qtopia:dis}able-software-qtopia %define ac_with_module_engine_software_sdl --%{?with_module_engine_software_sdl:en}%{!?with_module_engine_software_sdl:dis}able-sdl @@ -287,6 +289,16 @@ Requires: evas OpenGL under X11 rendering engine module for Evas %endif +%if %{with module_engine_quartz} +%package module_engine_quartz +Summary: Quartz rendering engine module for Evas +Group: System Environment/Libraries +#BuildSuggests: +Requires: evas +%description module_engine_quartz +Quartz rendering engine module for Evas +%endif + %if %{with module_engine_directfb} %package module_engine_directfb Summary: Directfb rendering engine module for Evas @@ -366,6 +378,7 @@ Xrender XCB X11 rendering engine module for Evas %{?ac_with_module_engine_fb} \ %{?ac_with_module_engine_xrender_x11} \ %{?ac_with_module_engine_gl_x11} \ + %{?ac_with_module_engine_quartz} \ %{?ac_with_module_engine_directfb} \ %{?ac_with_module_engine_software_qtopia} \ %{?ac_with_module_engine_software_sdl} \ @@ -519,6 +532,12 @@ test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT %{_libdir}/evas/modules/engines/gl_x11/*/module.so %endif +%if %{with module_engine_quartz} +%files module_engine_quartz +%defattr(-, root, root) +%{_libdir}/evas/modules/engines/quartz/*/module.so +%endif + %if %{with module_engine_directfb} %files module_engine_directfb %defattr(-, root, root) diff --git a/legacy/evas/src/modules/engines/Makefile.am b/legacy/evas/src/modules/engines/Makefile.am index 59df875794..b2c61164ad 100644 --- a/legacy/evas/src/modules/engines/Makefile.am +++ b/legacy/evas/src/modules/engines/Makefile.am @@ -24,5 +24,6 @@ software_16_x11 \ direct3d \ software_16_ddraw \ software_16_wince \ -software_16_sdl +software_16_sdl \ +quartz diff --git a/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h b/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h index 0af1d35466..8910588c5d 100644 --- a/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h +++ b/legacy/evas/src/modules/engines/gl_common/evas_gl_common.h @@ -20,13 +20,18 @@ #include #include +#ifdef BUILD_ENGINE_GL_QUARTZ +#include +#include +#else +#include +#include +#endif /* BUILD_ENGINE_GL_QUARTZ */ + #ifdef BUILD_ENGINE_GL_GLEW #include #endif /* BUILD_ENGINE_GL_GLEW */ -#include -#include - typedef struct _Evas_GL_Context Evas_GL_Context; typedef struct _Evas_GL_Texture Evas_GL_Texture; typedef struct _Evas_GL_Image Evas_GL_Image; diff --git a/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h b/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h new file mode 100644 index 0000000000..abca92276e --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h @@ -0,0 +1,22 @@ +#ifndef _EVAS_ENGINE_QUARTZ_H +#define _EVAS_ENGINE_QUARTZ_H + +#include + +typedef struct _Evas_Engine_Info_Quartz Evas_Engine_Info_Quartz; + +struct _Evas_Engine_Info_Quartz +{ + /* PRIVATE - don't mess with this baby or evas will poke its tongue out */ + /* at you and make nasty noises */ + Evas_Engine_Info magic; + + /* engine specific data & parameters it needs to set up */ + struct { + CGContextRef context; + } info; +}; + +#endif + + diff --git a/legacy/evas/src/modules/engines/quartz/Makefile.am b/legacy/evas/src/modules/engines/quartz/Makefile.am new file mode 100644 index 0000000000..24ba355d4e --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/Makefile.am @@ -0,0 +1,28 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = -I. -I$(top_srcdir)/src/lib -I$(top_srcdir)/src/lib/include @quartz_cflags@ @FREETYPE_CFLAGS@ + +if BUILD_ENGINE_QUARTZ + +pkgdir = $(libdir)/evas/modules/engines/quartz/$(MODULE_ARCH) + +pkg_LTLIBRARIES = module.la + +module_la_SOURCES = \ +evas_engine.h \ +evas_engine.c + +module_la_LIBADD = @quartz_libs@ $(top_builddir)/src/lib/libevas.la +module_la_LDFLAGS = -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static +module_la_DEPENDENCIES = $(top_builddir)/config.h + +include_HEADERS = Evas_Engine_Quartz.h + +endif + +EXTRA_DIST = \ +evas_engine.h \ +evas_engine.c \ +Evas_Engine_Quartz.h diff --git a/legacy/evas/src/modules/engines/quartz/README b/legacy/evas/src/modules/engines/quartz/README new file mode 100644 index 0000000000..eb12dc6f08 --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/README @@ -0,0 +1,32 @@ +================ +==INSTALLATION== +================ + +Here's what I had to do to get Evas_Quartz working on a fresh install of Mac OS X Leopard (Evas_Quartz is currently not versions prior to 10.5): + +1) Install all system software updates. + +2) Install the XCode developer tools (this includes GCC). + +3) Install macports. + +4) Put /opt/local/bin in your path, permanently. (I put it in front of everything else, because the newer versions of autotools provided by ports are required to build evas) + +5) With macports, install the following: m4, autoconf, automake, libtool, pkgconfig, zlib, libpng, jpeg, freetype, tiff. + +6) Check out a version of Evas that includes Evas_Quartz (from CVS). + +7) Set up your environment. You need to, at the very least, set: + CFLAGS=-I/opt/local/include + LDFLAGS=-L/opt/local/lib + +8) Build and install eet. + +9) Build and install evas. Make sure to use --enable-quartz when configuring! + +============== +==KNOWN BUGS== +============== + +**** A few different types of gradients don't currently draw. +** Textbox drawing is a little bit off (because of hardcoded constants that shouldn't exist). \ No newline at end of file diff --git a/legacy/evas/src/modules/engines/quartz/evas_engine.c b/legacy/evas/src/modules/engines/quartz/evas_engine.c new file mode 100644 index 0000000000..e5271af021 --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/evas_engine.c @@ -0,0 +1,1512 @@ +/* + * vim:ts=3:sw=3:sts=3:expandtab + */ +#include + +#include "evas_common.h" +#include "evas_private.h" +#include "evas_engine.h" +#include "Evas_Engine_Quartz.h" +#include "evas_quartz_private.h" + +static Evas_Func func; + +typedef struct _Render_Engine Render_Engine; + +struct _Render_Engine +{ + CGContextRef ctx; + int w, h; + + struct + { + int redraw : 1; + int x1, y1, x2, y2; + } draw; +}; + +static inline void +flip_pixels(int *y, int *h, void *re) +{ + // We need to flip the Y axis, because Quartz uses a coordinate system + // with the origin in the bottom left, while Evas uses a top left origin. + + (*y) = ((Evas_Quartz_Context *)re)->h - (*y); + + if (h && y) (*y) -= *h; +} + +static void * +eng_info(Evas *e) +{ + Evas_Engine_Info_Quartz *info; + + info = calloc(1, sizeof(Evas_Engine_Info_Quartz)); + if (!info) return NULL; + + info->magic.magic = rand(); + + return info; +} + +static void +eng_info_free(Evas *e, void *info) +{ + free((Evas_Engine_Info_Quartz *)info); +} + +static void +eng_setup(Evas *e, void *in) +{ + Render_Engine *re; + Evas_Engine_Info_Quartz *info = (Evas_Engine_Info_Quartz *)in; + + if (!e->engine.data.output) + e->engine.data.output = eng_output_setup(info->info.context, e->output.w, e->output.h); + if (!e->engine.data.output) return; + + if (!e->engine.data.context) + e->engine.data.context = e->engine.func->context_new(e->engine.data.output); + + ((Evas_Quartz_Context *)e->engine.data.context)->w = e->output.w; + ((Evas_Quartz_Context *)e->engine.data.context)->h = e->output.h; +} + +#pragma mark Output Setup + +static void * +eng_output_setup(CGContextRef context, int w, int h) +{ + Render_Engine *re = calloc(1, sizeof(Render_Engine)); + if (!re) return NULL; + + re->ctx = context; + re->w = w; + re->h = h; + + evas_common_cpu_init(); + + evas_common_blend_init(); + evas_common_image_init(); + evas_common_convert_init(); + evas_common_scale_init(); + evas_common_rectangle_init(); + evas_common_gradient_init(); + evas_common_polygon_init(); + evas_common_line_init(); + evas_common_font_init(); + evas_common_draw_init(); + evas_common_tilebuf_init(); + + return re; +} + +static void +eng_output_free(void *data) +{ + Render_Engine *re = (Render_Engine *)data; + + free(re); + + evas_common_font_shutdown(); + evas_common_image_shutdown(); +} + +static void +eng_output_resize(void *data, int w, int h) +{ + Render_Engine *re = (Render_Engine *)data; + + re->w = w; + re->h = h; +} + +static void +eng_output_redraws_rect_add(void *data, int x, int y, int w, int h) +{ + Render_Engine *re = (Render_Engine *)data; + + if (!re->draw.redraw) + { + re->draw.x1 = x; + re->draw.y1 = y; + re->draw.x2 = x + w; + re->draw.y2 = y + h; + } + else + { + if (x < re->draw.x1) re->draw.x1 = x; + if (y < re->draw.y1) re->draw.y1 = y; + if ((x + w - 1) > re->draw.x2) re->draw.x2 = x + w - 1; + if ((y + h - 1) > re->draw.y2) re->draw.y2 = y + h - 1; + } + + re->draw.redraw = 1; +} + +static void +eng_output_redraws_rect_del(void *data, int x, int y, int w, int h) +{ + // FIXME: Implement this? +} + +static void +eng_output_redraws_clear(void *data) +{ + Render_Engine *re = (Render_Engine *)data; + + re->draw.redraw = 0; +} + +static void * +eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch) +{ + Render_Engine *re = (Render_Engine *)data; + + if (!re->draw.redraw) return NULL; + + if (x) *x = re->draw.x1; + if (y) *y = re->draw.y1; + if (w) *w = re->draw.x2 - re->draw.x1 + 1; + if (h) *h = re->draw.y2 - re->draw.y1 + 1; + if (cx) *cx = re->draw.x1; + if (cy) *cy = re->draw.y1; + if (cw) *cw = re->draw.x2 - re->draw.x1 + 1; + if (ch) *ch = re->draw.y2 - re->draw.y1 + 1; + + return re; +} + +static void +eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctx = (Evas_Quartz_Context *)(re->ctx); + re->draw.redraw = 0; + + flip_pixels(&y, &h, ctx); + + CGContextClearRect(re->ctx, CGRectMake(x, y, w, h)); +} + +static void +eng_output_flush(void *data) +{ + // By default, Apple coalesces calls to CGContextFlush, but this actually + // blocks if called more than 60 times per second, which is a waste of time. + // + // http://developer.apple.com/technotes/tn2005/tn2133.html + + CGContextFlush(((Render_Engine *)data)->ctx); +} + +#pragma mark Context Manipulation + +static void * +eng_context_new(void *data) +{ + Evas_Quartz_Context *ctxt = calloc(1, sizeof(Evas_Quartz_Context)); + if (!ctxt) return NULL; + + return ctxt; +} + +static void +eng_context_free(void *data, void *context) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + if (re->ctx) CGContextRelease(re->ctx); + free(ctxt); +} + +static void +eng_context_clip_set(void *data, void *context, int x, int y, int w, int h) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + flip_pixels(&y, &h, ctxt); + + CGContextResetClip(re->ctx); + CGContextClipToRect(re->ctx, CGRectMake(0, 0, re->w, re->h)); // don't draw over the title bar + CGContextClipToRect(re->ctx, CGRectMake(x, y, w, h)); + + ctxt->clipped = 1; +} + +static void +eng_context_clip_unset(void *data, void *context) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + CGContextResetClip(re->ctx); + + ctxt->clipped = 0; +} + +static int +eng_context_clip_get(void *data, void *context, int *x, int *y, int *w, int *h) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + CGRect clip = CGContextGetClipBoundingBox(re->ctx); + if (x) *x = clip.origin.x; + if (y) *y = clip.origin.y; + if (w) *w = clip.size.width; + if (h) *h = clip.size.height; + + return ctxt->clipped; +} + +static void +eng_context_color_set(void *data, void *context, int r, int g, int b, int a) +{ + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + ctxt->col.r = (double)r / 255.0; + ctxt->col.g = (double)g / 255.0; + ctxt->col.b = (double)b / 255.0; + ctxt->col.a = (double)a / 255.0; +} + +static int +eng_context_color_get(void *data, void *context, int *r, int *g, int *b, int *a) +{ + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + if (r) *r = ctxt->col.r * 255; + if (g) *g = ctxt->col.g * 255; + if (b) *b = ctxt->col.b * 255; + if (a) *a = ctxt->col.a * 255; + return 1; +} + +static void +eng_context_multiplier_set(void *data, void *context, int r, int g, int b, int a) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + ctxt->mul.r = (double)r / 255.0; + ctxt->mul.g = (double)g / 255.0; + ctxt->mul.b = (double)b / 255.0; + ctxt->mul.a = (double)a / 255.0; + ctxt->mul.set = 1; + + CGContextSetAlpha(re->ctx, ctxt->mul.a); +} + +static void +eng_context_multiplier_unset(void *data, void *context) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + ctxt->mul.set = 0; + CGContextSetAlpha(re->ctx, 1.0); +} + +static int +eng_context_multiplier_get(void *data, void *context, int *r, int *g, int *b, int *a) +{ + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + if (r) *r = ctxt->mul.r * 255; + if (g) *g = ctxt->mul.g * 255; + if (b) *b = ctxt->mul.b * 255; + if (a) *a = ctxt->mul.a * 255; + return ctxt->mul.set; +} + +static void +eng_context_cutout_add(void *data, void *context, int x, int y, int w, int h) +{ + // FIXME: This doesn't seem to be implemented anywhere. What does it do? +} + +static void +eng_context_cutout_clear(void *data, void *context) +{ + // FIXME: This doesn't seem to be implemented anywhere. What does it do? +} + +static void +eng_context_anti_alias_set(void *data, void *context, unsigned char aa) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + ctxt->aa = aa; + + CGContextSetAllowsAntialiasing(re->ctx, (bool)aa); + CGContextSetShouldAntialias(re->ctx, (bool)aa); + CGContextSetInterpolationQuality(re->ctx, kCGInterpolationLow); // is it OK to assume low quality? +} + +static unsigned char +eng_context_anti_alias_get(void *data, void *context) +{ + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + return ctxt->aa; +} + +#pragma mark Rectangle Drawing + +static void +eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + double r, g, b, a; + + flip_pixels(&y, &h, ctxt); + + r = ctxt->col.r; + g = ctxt->col.g; + b = ctxt->col.b; + a = ctxt->col.a; + + if (ctxt->mul.set) + { + r *= ctxt->mul.r; + g *= ctxt->mul.g; + b *= ctxt->mul.b; + a *= ctxt->mul.a; + } + + CGContextSetRGBFillColor(re->ctx, r, g, b, a); + CGContextFillRect(re->ctx, CGRectMake(x, y, w, h)); +} + +#pragma mark Line Drawing + +static void +eng_line_draw(void *data, void *context, void *surface, int x1, int y1, int x2, int y2) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + double r, g, b, a; + + flip_pixels(&y1, NULL, ctxt); + flip_pixels(&y2, NULL, ctxt); + + r = ctxt->col.r; + g = ctxt->col.g; + b = ctxt->col.b; + a = ctxt->col.a; + + if (ctxt->mul.set) + { + r *= ctxt->mul.r; + g *= ctxt->mul.g; + b *= ctxt->mul.b; + a *= ctxt->mul.a; + } + + CGContextSetRGBStrokeColor(re->ctx, r, g, b, a); + CGContextBeginPath(re->ctx); + CGContextMoveToPoint(re->ctx, x1, y1); + CGContextAddLineToPoint(re->ctx, x2, y2); + CGContextStrokePath(re->ctx); +} + +#pragma mark Polygon Manipulation & Drawing + +static void * +eng_polygon_point_add(void *data, void *context, void *polygon, int x, int y) +{ + Evas_Quartz_Polygon *poly; + Evas_Quartz_Polygon_Point *pt; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + + flip_pixels(&y, NULL, ctxt); + + poly = (Evas_Quartz_Polygon *)polygon; + if (!poly) poly = calloc(1, sizeof(Evas_Quartz_Polygon)); + if (!poly) return NULL; + + pt = calloc(1, sizeof(Evas_Quartz_Polygon_Point)); + if (pt) + { + pt->x = x; + pt->y = y; + poly->points = evas_list_append(poly->points, pt); + } + return poly; +} + +static void * +eng_polygon_points_clear(void *data, void *context, void *polygon) +{ + Evas_Quartz_Polygon *poly; + + poly = (Evas_Quartz_Polygon *)polygon; + if (!poly) return NULL; + + while (poly->points) + { + free(poly->points->data); + poly->points = evas_list_remove_list(poly->points, poly->points); + } + free(poly); + + return NULL; +} + +static void +eng_polygon_draw(void *data, void *context, void *surface, void *polygon) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + Evas_Quartz_Polygon *poly = (Evas_Quartz_Polygon *)polygon; + Evas_Quartz_Polygon_Point *pt; + + double r, g, b, a; + + CGContextBeginPath(re->ctx); + + pt = poly->points->data; + if (pt) + { + Evas_List *l; + CGContextMoveToPoint(re->ctx, pt->x, pt->y); + for (l = poly->points->next; l; l = l->next) + { + pt = l->data; + CGContextAddLineToPoint(re->ctx, pt->x, pt->y); + } + } + + r = ctxt->col.r; + g = ctxt->col.g; + b = ctxt->col.b; + a = ctxt->col.a; + + if (ctxt->mul.set) + { + r *= ctxt->mul.r; + g *= ctxt->mul.g; + b *= ctxt->mul.b; + a *= ctxt->mul.a; + } + + CGContextSetRGBFillColor(re->ctx, r, g, b, a); + CGContextFillPath(re->ctx); +} + +#pragma mark Gradient Manipulation & Drawing + +static void * +eng_gradient_new(void *data) +{ + Evas_Quartz_Gradient *gradient = calloc(1, sizeof(Evas_Quartz_Gradient)); + if (!gradient) return NULL; + + gradient->grad = evas_common_gradient_new(); + if (!(gradient->grad)) + { + free(gradient); + return NULL; + } + + gradient->changed = 1; + gradient->buf = NULL; + + return gradient; +} + +static void +eng_gradient_free(void *data, void *gradient) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + if (gr->grad) evas_common_gradient_free(gr->grad); + if (gr->im) eng_image_free(data, gr->im); + if (gr->buf) free(gr->buf); + free(gr); +} + +static void +eng_gradient_color_stop_add(void *data, void *gradient, int r, int g, int b, int a, int delta) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_color_stop_add(gr->grad, r, g, b, a, delta); + gr->changed = 1; +} + +static void +eng_gradient_alpha_stop_add(void *data, void *gradient, int a, int delta) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_alpha_stop_add(gr->grad, a, delta); + gr->changed = 1; +} + +static void +eng_gradient_color_data_set(void *data, void *gradient, void *map, int len, int has_alpha) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_color_data_set(gr->grad, map, len, has_alpha); + gr->changed = 1; +} + +static void +eng_gradient_alpha_data_set(void *data, void *gradient, void *alpha_map, int len) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_alpha_data_set(gr->grad, alpha_map, len); + gr->changed = 1; +} + +static void +eng_gradient_clear(void *data, void *gradient) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_clear(gr->grad); + gr->changed = 1; +} + +static void +eng_gradient_fill_set(void *data, void *gradient, int x, int y, int w, int h) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_fill_set(gr->grad, x, y, w, h); + gr->changed = 1; +} + +static void +eng_gradient_fill_angle_set(void *data, void *gradient, double angle) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_fill_angle_set(gr->grad, angle); + gr->changed = 1; +} + +static void +eng_gradient_fill_spread_set(void *data, void *gradient, int spread) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_fill_spread_set(gr->grad, spread); + gr->changed = 1; +} + +static void +eng_gradient_angle_set(void *data, void *gradient, double angle) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_map_angle_set(gr->grad, angle); + gr->changed = 1; +} + +static void +eng_gradient_offset_set(void *data, void *gradient, float offset) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_map_offset_set(gr->grad, offset); + gr->changed = 1; +} + +static void +eng_gradient_direction_set(void *data, void *gradient, int direction) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_map_direction_set(gr->grad, direction); + gr->changed = 1; +} + +static void +eng_gradient_type_set(void *data, void *gradient, char *name, char *params) +{ + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + if (!gr) return; + evas_common_gradient_type_set(gr->grad, name, params); + gr->changed = 1; +} + +static int +eng_gradient_is_opaque(void *data, void *context, void *gradient, int x, int y, int w, int h) +{ + RGBA_Draw_Context *dc = (RGBA_Draw_Context *)context; + RGBA_Gradient *grad; + if (!gradient) return 0; + + grad = ((Evas_Quartz_Gradient *)gradient)->grad; + + if (!grad || !grad->type.geometer) return 0; + + return !(grad->type.geometer->has_alpha(grad, dc->render_op) | + grad->type.geometer->has_mask(grad, dc->render_op)); +} + +static int +eng_gradient_is_visible(void *data, void *context, void *gradient, int x, int y, int w, int h) +{ + if (!gradient) return 0; + return 1; +} + +static void +eng_gradient_render_pre(void *data, void *context, void *gradient) +{ + int len; + RGBA_Gradient *grad; + + if (!context || !gradient) return; + grad = ((Evas_Quartz_Gradient *)gradient)->grad; + if (!grad || !grad->type.geometer) return; + grad->type.geometer->geom_set(grad); + len = grad->type.geometer->get_map_len(grad); + evas_common_gradient_map(context, grad, len); + ((Evas_Quartz_Gradient *)gradient)->changed = 1; +} + +static void +eng_gradient_render_post(void *data, void *gradient) +{ +} + +static void +eng_gradient_draw(void *data, void *context, void *surface, void *gradient, int x, int y, int w, int h) +{ + RGBA_Draw_Context *dc = (RGBA_Draw_Context *)context; + Evas_Quartz_Gradient *gr = (Evas_Quartz_Gradient *)gradient; + + printf("#Gradient#\n"); + printf("Fill: %i %i %i %i\n", gr->grad->fill.x, gr->grad->fill.y, gr->grad->fill.w, gr->grad->fill.h); + printf("Type: %s %s\n", gr->grad->type.name, gr->grad->type.params); + printf("XYWH: %i %i %i %i\n", x, y, w, h); + printf("Geom: %p %p\n", gr->grad->type.geometer, gr->grad->type.geometer->get_fill_func); + printf("Map: len: %d angle: %f direction: %d offset: %f\n", gr->grad->map.len, gr->grad->map.angle, gr->grad->map.direction, gr->grad->map.offset); + printf("Color: nstops: %d len: %d\n", gr->grad->color.nstops, gr->grad->color.len); + printf("Alpha: nstops: %d len: %d\n", gr->grad->alpha.nstops, gr->grad->alpha.len); + printf("\n"); + + if ((gr->sw != w) || (gr->sh != h)) + gr->changed = 1; + + if ((gr->changed) || (!gr->im)) + { + if (gr->buf && ((gr->sw != w) || (gr->sh != h))) + { + free(gr->buf); + gr->buf = NULL; + } + + if (!gr->buf) + gr->buf = calloc(w * h, 4); + + eng_image_free(data, gr->im); + gr->im = eng_image_new_from_data(data, w, h, gr->buf, 1, EVAS_COLORSPACE_ARGB8888); + dc->render_op = _EVAS_RENDER_FILL; + evas_common_gradient_draw((RGBA_Image *) &gr->im->im->cache_entry, dc, 0, 0, w, h, gr->grad); + evas_common_cpu_end_opt(); + gr->sw = w; + gr->sh = h; + gr->changed = 0; + } + + eng_image_draw(data, context, NULL, gr->im, 0, 0, 0, 0, x, y, w, h, 0); +} + +#pragma mark Image Manipulation & Drawing + +static void * +eng_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo) +{ + Evas_Quartz_Image *im = calloc(1, sizeof(Evas_Quartz_Image)); + + // FIXME: set error before returning without a new image... + // I can't figure out what to set it to, even trying to follow through the core code. + // Also, none of the other engines set it. + + if (error) *error = 0; + if (!im) return NULL; + + im->im = (RGBA_Image *)evas_common_load_image_from_file(file, key, lo); + if (!im->im) + { + free(im); + return NULL; + } + im->references = 1; + return im; +} + +static void * +eng_image_new_from_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace) +{ + Evas_Quartz_Image *im = calloc(1, sizeof(Evas_Quartz_Image)); + + if (!im) return NULL; + + im->im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(), w, h, image_data, alpha, cspace); + im->references = 1; + + if (!im->im) + { + free(im); + return NULL; + } + + return im; +} + +static void * +eng_image_new_from_copied_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace) +{ + Evas_Quartz_Image *im = calloc(1, sizeof(Evas_Quartz_Image)); + + if (!im) return NULL; + + im->im = (RGBA_Image *)evas_cache_image_copied_data(evas_common_image_cache_get(), w, h, image_data, alpha, cspace); + im->references = 1; + + if (!im->im) + { + free(im); + return NULL; + } + + return im; +} + +static void +eng_image_free(void *data, void *image) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if (!im) return; + + if (--im->references > 0) return; + + if (im->cgim) CGImageRelease(im->cgim); + if (im->im) evas_cache_image_drop(&im->im->cache_entry); + free(im); +} + +static void * +eng_image_size_set(void *data, void *image, int w, int h) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + Evas_Quartz_Image *im_old; + + if (!im) return NULL; + im_old = image; + if ((eng_image_colorspace_get(data, image) == EVAS_COLORSPACE_YCBCR422P601_PL) || + (eng_image_colorspace_get(data, image) == EVAS_COLORSPACE_YCBCR422P709_PL)) + w &= ~0x1; + + if ((im_old) && (im_old->im->cache_entry.w == w) && (im_old->im->cache_entry.h == h)) + return image; + + if ((w <= 0) || (h <= 0)) + { + eng_image_free(data, im_old); + return NULL; + } + + if (im_old) + { + im = eng_image_new_from_data(data, w, h, im_old->im->image.data, eng_image_alpha_get(data, im_old), eng_image_colorspace_get(data, im_old)); + eng_image_free(data, im_old); + } + else + im = eng_image_new_from_data(data, w, h, NULL, true, EVAS_COLORSPACE_ARGB8888); + return im; +} + +static void +eng_image_size_get(void *data, void *image, int *w, int *h) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if (!image) + { + if (w) *w = 0; + if (h) *h = 0; + } + else + { + if (w) *w = im->im->cache_entry.w; + if (h) *h = im->im->cache_entry.h; + } +} + +static void * +eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if ((im) && (im->im)) + return evas_cache_image_dirty(&im->im->cache_entry, x, y, w, h); +} + +static void * +eng_image_alpha_set(void *data, void *image, int has_alpha) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if ((!im) || (!im->im)) return NULL; + + if (im->im->cache_entry.space != EVAS_COLORSPACE_ARGB8888) + { + im->im->cache_entry.flags.alpha = 0; + } + else + { + im->im = (RGBA_Image *)evas_cache_image_alone(&im->im->cache_entry); + evas_common_image_colorspace_dirty(im->im); + im->im->cache_entry.flags.alpha = has_alpha ? 1 : 0; + } + + return im; +} + +static int +eng_image_alpha_get(void *data, void *image) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *) image; + + if (!im->im) return 0; + + return (int)(im->im->cache_entry.flags.alpha); +} + +static char * +eng_image_comment_get(void *data, void *image, char *key) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if ((!im) || (!im->im)) + return NULL; + else + return im->im->info.comment; +} + +static char * +eng_image_format_get(void *data, void *image) +{ + // these are unimplemented for now, until core features are finished + + return NULL; +} + +static void +eng_image_colorspace_set(void *data, void *image, int cspace) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if (!im) + return; + else + evas_cache_image_colorspace(&im->im->cache_entry, cspace); +} + +static int +eng_image_colorspace_get(void *data, void *image) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if (!im) + return EVAS_COLORSPACE_ARGB8888; + else + return im->im->cache_entry.space; +} + +static void +eng_image_native_set(void *data, void *image, void *native) +{ + // these are unimplemented for now, until core features are finished +} + +static void * +eng_image_native_get(void *data, void *image) +{ + // these are unimplemented for now, until core features are finished + return NULL; +} + +static void * +eng_image_data_put(void *data, void *image, DATA32 *image_data) +{ + // FIXME: one last leak somewhere in this function + + Evas_Quartz_Image *im_old = (Evas_Quartz_Image *)image; + + if (!im_old) return NULL; + + if (im_old->cgim) + { + CGImageRelease(im_old->cgim); + im_old->cgim = NULL; + } + + switch (im_old->im->cache_entry.space) + { + case EVAS_COLORSPACE_ARGB8888: + image = eng_image_new_from_data(data, im_old->im->cache_entry.w, im_old->im->cache_entry.h, image_data, 1, EVAS_COLORSPACE_ARGB8888); + eng_image_free(data, im_old); + break; + case EVAS_COLORSPACE_YCBCR422P709_PL: + case EVAS_COLORSPACE_YCBCR422P601_PL: + if (image_data != im_old->im->cs.data) + { + if (im_old->im->cs.data) + if (!im_old->im->cs.no_free) + free(im_old->im->cs.data); + + im_old->im->cs.data = image_data; + evas_common_image_colorspace_dirty(im_old->im); + } + break; + } + + if (!image) return NULL; + + return image; +} + +static void * +eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data) +{ + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + + if ((!im) || (!im->im)) + { + *image_data = NULL; + return NULL; + } + + switch (im->im->cache_entry.space) + { + case EVAS_COLORSPACE_ARGB8888: + if (to_write) + { + CGImageRelease(im->cgim); + im->cgim = NULL; + + if (im->references > 1) + { + Evas_Quartz_Image *im_new; + im_new = eng_image_new_from_copied_data(data, + im->im->cache_entry.w, + im->im->cache_entry.h, + im->im->image.data, + eng_image_alpha_get(data, image), + eng_image_colorspace_get(data, image)); + + if (!im_new) + { + if (image_data) *image_data = NULL; + return im; + } + + eng_image_free(data, im); + im = im_new; + } + else + { + im->im = (RGBA_Image *)evas_cache_image_dirty(&im->im->cache_entry, + 0, 0, + im->im->cache_entry.w, im->im->cache_entry.h); + im->references++; + } + } + + evas_cache_image_load_data(&im->im->cache_entry); + + if (image_data) *image_data = im->im->image.data; + break; + case EVAS_COLORSPACE_YCBCR422P709_PL: + case EVAS_COLORSPACE_YCBCR422P601_PL: + if (image_data) *image_data = im->im->cs.data; + im->references++; + break; + default: + abort(); // this seems ... incredibly unreasonable, but GL does it... + break; + } + + return im; +} + +static void +eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + Evas_Quartz_Image *im = (Evas_Quartz_Image *)image; + flip_pixels(&dst_y, &dst_h, ctxt); + + if ((!im) || (!im->im)) return; + + if (!im->cgim) + { + CGColorSpaceRef colorspace; + CGDataProviderRef provider; + evas_cache_image_load_data(&im->im->cache_entry); + evas_common_image_colorspace_normalize((RGBA_Image *)(&im->im->cache_entry)); + + if (!im->im->image.data) return; + + colorspace = CGColorSpaceCreateDeviceRGB(); + provider = CGDataProviderCreateWithData(NULL, + im->im->image.data, + im->im->cache_entry.w * im->im->cache_entry.h * sizeof(DATA32), + NULL); + im->cgim = CGImageCreate(im->im->cache_entry.w, + im->im->cache_entry.h, + 8, + 8 * 4, + 4 * im->im->cache_entry.w, + colorspace, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + provider, + NULL, + smooth, + kCGRenderingIntentDefault); + + CGDataProviderRelease(provider); + CGColorSpaceRelease(colorspace); + + if (!im->cgim) return; + } + + CGImageRef subImage = NULL; + + if (src_x != 0 || src_y != 0 || src_w != 0 || src_h != 0) + { + subImage = CGImageCreateWithImageInRect(im->cgim, CGRectMake(src_x,src_y,src_w,src_h)); + if (!subImage) return; + + CGContextDrawImage(re->ctx, CGRectMake(dst_x, dst_y, dst_w, dst_h), subImage); + CGImageRelease(subImage); + } + else + CGContextDrawImage(re->ctx, CGRectMake(dst_x, dst_y, dst_w, dst_h), im->cgim); +} + +#pragma mark Text Manipulation & Drawing + +static Evas_Quartz_Font * +quartz_font_from_ats(ATSFontContainerRef container, int size) +{ + ItemCount count; + ATSFontRef *fonts; + CTFontRef font; + CFStringRef keys[1]; + CFTypeRef values[1]; + CFDictionaryRef attr; + Evas_Quartz_Font *loaded_font; + + ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0, NULL, &count); + fonts = calloc(count, sizeof(ATSFontRef)); + if (!fonts) return NULL; + ATSFontFindFromContainer(container, kATSOptionFlagsDefault, count, fonts, NULL); + + font = CTFontCreateWithPlatformFont(fonts[0], size, NULL, NULL); + + loaded_font = calloc(1, sizeof(Evas_Quartz_Font)); + if (!font || !loaded_font) return NULL; + + keys[0] = kCTFontAttributeName; + values[0] = font; + attr = CFDictionaryCreate(NULL, + (const void **)&keys, + (const void **)&values, + sizeof(keys) / sizeof(keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + loaded_font->font = font; + loaded_font->attr = attr; + loaded_font->size = size; + + free(fonts); + + return loaded_font; +} + +static void * +eng_font_add(void *data, void *font, const char *name, int size) +{ + // FIXME: what is this function supposed to do? + // if I delete it, we eventually crash when it gets run + + return (char *)name; +} + +static void * +eng_font_load(void *data, const char *name, int size) +{ + FSRef fontFile; + ATSFontContainerRef container; + + FSPathMakeRef((unsigned char *)name, &fontFile, NULL); + ATSFontActivateFromFileReference(&fontFile, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &container); + + return quartz_font_from_ats(container, size);; +} + +static void * +eng_font_memory_load(void *data, char *name, int size, const void *fdata, int fdata_size) +{ + ATSFontContainerRef container; + + ATSFontActivateFromMemory((void *)fdata, fdata_size, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &container); + + return quartz_font_from_ats(container, size); +} + +static void +eng_font_free(void *data, void *font) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + CFRelease(loaded_font->font); + CFRelease(loaded_font->attr); + free(loaded_font); +} + +static int +eng_font_ascent_get(void *data, void *font) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + return CTFontGetAscent(loaded_font->font); +} + +static int +eng_font_descent_get(void *data, void *font) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + return CTFontGetDescent(loaded_font->font); +} + +static int +eng_font_max_ascent_get(void *data, void *font) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + return CTFontGetAscent(loaded_font->font); +} + +static int +eng_font_max_descent_get(void *data, void *font) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + return CTFontGetDescent(loaded_font->font); +} + +static void +eng_font_string_size_get(void *data, void *font, const char *text, int *w, int *h) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + CFStringRef string = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); + CFAttributedStringRef attrString = CFAttributedStringCreate(NULL, string, loaded_font->attr); + CTLineRef line = CTLineCreateWithAttributedString(attrString); + CGContextSetTextMatrix(re->ctx, CGAffineTransformIdentity); + CGContextSetTextPosition(re->ctx, 0, CTFontGetDescent(loaded_font->font)); + CGRect bounds = CTLineGetImageBounds(line, re->ctx); + + // Descenders on characters seem to leave origin at typographic origin, instead of image origin. + // Evas expects text to be treated like an image, so we have to offset by the typographic origin. + + if (w) (*w) = ceil(bounds.size.width + bounds.origin.x); + if (h) (*h) = ceil(bounds.size.height + bounds.origin.y); + + CFRelease(attrString); + CFRelease(string); + CFRelease(line); +} + +static int +eng_font_inset_get(void *data, void *font, const char *text) +{ + return 0; +} + +static int +eng_font_h_advance_get(void *data, void *font, const char *text) +{ + int w; + + eng_font_string_size_get(data, font, text, &w, NULL); + + return w + 2; // FIXME: shouldn't need a constant here. from where do we get word spacing? + // it seems we lose the space between differently-styled text in a text block. Why? +} + +static int +eng_font_v_advance_get(void *data, void *font, const char *text) +{ + int h; + + eng_font_string_size_get(data, font, text, NULL, &h); + + return h; +} + +static int +eng_font_char_coords_get(void *data, void *font, const char *text, int pos, int *cx, int *cy, int *cw, int *ch) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + CFStringRef string = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); + CFAttributedStringRef attrString = CFAttributedStringCreate(NULL, string, loaded_font->attr); + CTLineRef line = CTLineCreateWithAttributedString(attrString); + + float offset = CTLineGetOffsetForStringIndex(line, pos, NULL); + if (cx) *cx = offset; + if (cy) *cy = loaded_font->size; + + CFRelease(attrString); + CFRelease(string); + CFRelease(line); + + return 1; +} + +static int +eng_font_char_at_coords_get(void *data, void *font, const char *text, int x, int y, int *cx, int *cy, int *cw, int *ch) +{ + // Return the index of the character at the given point, also lookup it's origin x, y, w, and h. + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + + CFStringRef string = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); + CFAttributedStringRef attrString = CFAttributedStringCreate(NULL, string, loaded_font->attr); + CTLineRef line = CTLineCreateWithAttributedString(attrString); + + int stringIndex = (int) CTLineGetStringIndexForPosition(line, CGPointMake(x, y)); + + // In order to get the character's size and position, look up the position of this character and the next one + eng_font_char_coords_get(data, font, text, stringIndex, cx, cy, NULL, NULL); + eng_font_char_coords_get(data, font, text, stringIndex + 1, cw, NULL, NULL, NULL); + + if (cw && cx) *cw -= *cx; + if (ch) *ch = loaded_font->size; + + CFRelease(attrString); + CFRelease(string); + CFRelease(line); + + return stringIndex; +} + +static void +eng_font_hinting_set(void *data, void *font, int hinting) +{ + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + loaded_font->hint = hinting; +} + +static int +eng_font_hinting_can_hint(void *data, int hinting) +{ + return 1; +} + +static void +eng_font_draw(void *data, void *context, void *surface, void *font, int x, int y, int w, int h, int ow, int oh, const char *text) +{ + Render_Engine *re = (Render_Engine *)data; + Evas_Quartz_Context *ctxt = (Evas_Quartz_Context *)context; + Evas_Quartz_Font *loaded_font = (Evas_Quartz_Font *)font; + double r, g, b, a; + CGFloat colors[4]; + CGColorSpaceRef colorspace; + CGColorRef color; + CFStringRef keys[2]; + CFTypeRef values[2]; + CFDictionaryRef attr; + CFStringRef string; + CFAttributedStringRef attrString; + CTLineRef line; + + flip_pixels(&y, &h, ctxt); + + // FIXME: I know this should never happen, but the next line is magic. + // It's also... broken. It /works/, but ... for example, subtracting 1 shouldn't need to happen. + // The text drawing is a mess, but this is the closest I've gotten yet... + + y += floor(CTFontGetAscent(loaded_font->font) - (CTFontGetXHeight(loaded_font->font) + CTFontGetDescent(loaded_font->font))) - 1; + + CGContextSetShouldSmoothFonts(re->ctx, (bool)(loaded_font->hint)); + + r = ctxt->col.r; + g = ctxt->col.g; + b = ctxt->col.b; + a = ctxt->col.a; + + if (ctxt->mul.set) + { + r *= ctxt->mul.r; + g *= ctxt->mul.g; + b *= ctxt->mul.b; + a *= ctxt->mul.a; + } + + colors[0] = r; + colors[1] = g; + colors[2] = b; + colors[3] = a; + + // Create an attributed string + colorspace = CGColorSpaceCreateDeviceRGB(); + color = CGColorCreate(colorspace, colors); + + keys[0] = kCTFontAttributeName; + values[0] = loaded_font->font; + keys[1] = kCTForegroundColorAttributeName; + values[1] = color; + + attr = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + string = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); + attrString = CFAttributedStringCreate(NULL, string, attr); + + // Draw the string + line = CTLineCreateWithAttributedString(attrString); + CGContextSetTextMatrix(re->ctx, CGAffineTransformIdentity); + CGContextSetTextPosition(re->ctx, x, y + h); + CTLineDraw(line, re->ctx); + + // Clean up + CGColorSpaceRelease(colorspace); + CFRelease(attr); + CFRelease(string); + CFRelease(attrString); + CFRelease(line); + CGColorRelease(color); +} + +#pragma mark Module Function Export + +EAPI int +module_open(Evas_Module *em) +{ + if (!em) return 0; + if (!_evas_module_engine_inherit(&func, "software_generic")) return 0; + #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_) + ORD(context_anti_alias_get); + ORD(context_anti_alias_set); + ORD(context_clip_get); + ORD(context_clip_set); + ORD(context_clip_unset); + ORD(context_color_get); + ORD(context_color_set); + ORD(context_cutout_add); + ORD(context_cutout_clear); + ORD(context_free); + ORD(context_multiplier_get); + ORD(context_multiplier_set); + ORD(context_multiplier_unset); + ORD(context_new); + ORD(font_add); + ORD(font_ascent_get); + ORD(font_char_at_coords_get); + ORD(font_char_coords_get); + ORD(font_descent_get); + ORD(font_draw); + ORD(font_free); + ORD(font_hinting_can_hint); + ORD(font_hinting_set); + ORD(font_h_advance_get); + ORD(font_inset_get); + ORD(font_load); + ORD(font_max_ascent_get); + ORD(font_max_descent_get); + ORD(font_memory_load); + ORD(font_string_size_get); + ORD(font_v_advance_get); + ORD(gradient_new); + ORD(gradient_free); + ORD(gradient_color_stop_add); + ORD(gradient_alpha_stop_add); + ORD(gradient_color_data_set); + ORD(gradient_alpha_data_set); + ORD(gradient_clear); + ORD(gradient_fill_set); + ORD(gradient_fill_angle_set); + ORD(gradient_fill_spread_set); + ORD(gradient_angle_set); + ORD(gradient_offset_set); + ORD(gradient_direction_set); + ORD(gradient_type_set); + ORD(gradient_is_opaque); + ORD(gradient_is_visible); + ORD(gradient_render_pre); + ORD(gradient_render_post); + ORD(gradient_draw); + ORD(image_alpha_get); + ORD(image_alpha_set); + ORD(image_colorspace_get); + ORD(image_colorspace_set); + ORD(image_comment_get); + ORD(image_data_get); + ORD(image_data_put); + ORD(image_dirty_region); + ORD(image_draw); + ORD(image_format_get); + ORD(image_free); + ORD(image_load); + ORD(image_native_get); + ORD(image_native_set); + ORD(image_new_from_copied_data); + ORD(image_new_from_data); + ORD(image_size_get); + ORD(image_size_set); + ORD(info); + ORD(info_free); + ORD(line_draw); + ORD(output_flush); + ORD(output_free); + ORD(output_redraws_clear); + ORD(output_redraws_next_update_get); + ORD(output_redraws_next_update_push); + ORD(output_redraws_rect_add); + ORD(output_redraws_rect_del); + ORD(output_resize); + ORD(polygon_draw); + ORD(polygon_points_clear); + ORD(polygon_point_add); + ORD(rectangle_draw); + ORD(setup); + + /* now advertise out our api */ + em->functions = (void *)(&func); + return 1; +} + +EAPI void +module_close(void) +{ + +} + +EAPI Evas_Module_Api evas_modapi = +{ + EVAS_MODULE_API_VERSION, + EVAS_MODULE_TYPE_ENGINE, + "quartz", + "none" +}; diff --git a/legacy/evas/src/modules/engines/quartz/evas_engine.h b/legacy/evas/src/modules/engines/quartz/evas_engine.h new file mode 100644 index 0000000000..94b2b05f97 --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/evas_engine.h @@ -0,0 +1,71 @@ +#ifndef EVAS_ENGINE_H +#define EVAS_ENGINE_H + +#include + +typedef struct _Evas_Quartz_Context Evas_Quartz_Context; + +struct _Evas_Quartz_Context +{ + int w, h; + + struct + { + double r, g, b, a; + } col; + + struct + { + double r, g, b, a; + int set : 1; + } mul; + + unsigned char aa, clipped; +}; + +typedef struct _Evas_Quartz_Polygon Evas_Quartz_Polygon; + +struct _Evas_Quartz_Polygon +{ + Evas_List *points; +}; + +typedef struct _Evas_Quartz_Polygon_Point Evas_Quartz_Polygon_Point; + +struct _Evas_Quartz_Polygon_Point +{ + int x, y; +}; + +typedef struct _Evas_Quartz_Image Evas_Quartz_Image; + +struct _Evas_Quartz_Image +{ + RGBA_Image *im; + CGImageRef cgim; + + int references; +}; + +typedef struct _Evas_Quartz_Font Evas_Quartz_Font; + +struct _Evas_Quartz_Font +{ + CTFontRef font; + CFDictionaryRef attr; + int hint; + int size; +}; + +typedef struct _Evas_Quartz_Gradient Evas_Quartz_Gradient; + +struct _Evas_Quartz_Gradient +{ + DATA32 *buf; + RGBA_Gradient *grad; + Evas_Quartz_Image *im; + unsigned char changed : 1; + int sw, sh; +}; + +#endif diff --git a/legacy/evas/src/modules/engines/quartz/evas_quartz_private.h b/legacy/evas/src/modules/engines/quartz/evas_quartz_private.h new file mode 100644 index 0000000000..cf49519b1f --- /dev/null +++ b/legacy/evas/src/modules/engines/quartz/evas_quartz_private.h @@ -0,0 +1,109 @@ +#ifndef _EVAS_QUARTZ_PRIVATE_H_ +#define _EVAS_QUARTZ_PRIVATE_H_ + +#include "evas_engine.h" + +CG_EXTERN void CGContextResetClip (CGContextRef); // undocumented CoreGraphics function to clear clip rect/* + +static inline void flip_pixels(int *y, int *h, void *re); + +static void *eng_info(Evas *e); +static void eng_info_free(Evas *e, void *info); + +static void *eng_output_setup(CGContextRef context, int w, int h); +static void eng_setup(Evas *e, void *in); + +static void eng_output_free(void *data); +static void eng_output_resize(void *data, int w, int h); +static void eng_output_redraws_rect_add(void *data, int x, int y, int w, int h); +static void eng_output_redraws_rect_del(void *data, int x, int y, int w, int h); +static void eng_output_redraws_clear(void *data); +static void *eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch); +static void eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h); +static void eng_output_flush(void *data); + +static void *eng_context_new(void *data); +static void eng_context_free(void *data, void *context); +static void eng_context_clip_set(void *data, void *context, int x, int y, int w, int h); +static void eng_context_clip_unset(void *data, void *context); +static int eng_context_clip_get(void *data, void *context, int *x, int *y, int *w, int *h); +static void eng_context_color_set(void *data, void *context, int r, int g, int b, int a); +static int eng_context_color_get(void *data, void *context, int *r, int *g, int *b, int *a); +static void eng_context_multiplier_set(void *data, void *context, int r, int g, int b, int a); +static void eng_context_multiplier_unset(void *data, void *context); +static int eng_context_multiplier_get(void *data, void *context, int *r, int *g, int *b, int *a); +static void eng_context_cutout_add(void *data, void *context, int x, int y, int w, int h); +static void eng_context_cutout_clear(void *data, void *context); +static void eng_context_anti_alias_set(void *data, void *context, unsigned char aa); +static unsigned char eng_context_anti_alias_get(void *data, void *context); + +static void eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h); + +static void eng_line_draw(void *data, void *context, void *surface, int x1, int y1, int x2, int y2); + +static void *eng_polygon_point_add(void *data, void *context, void *polygon, int x, int y); +static void *eng_polygon_points_clear(void *data, void *context, void *polygon); +static void eng_polygon_draw(void *data, void *context, void *surface, void *polygon); + +static void *eng_gradient_new(void *data); +static void eng_gradient_free(void *data, void *gradient); +static void eng_gradient_color_stop_add(void *data, void *gradient, int r, int g, int b, int a, int delta); +static void eng_gradient_alpha_stop_add(void *data, void *gradient, int a, int delta); +static void eng_gradient_color_data_set(void *data, void *gradient, void *map, int len, int has_alpha); +static void eng_gradient_alpha_data_set(void *data, void *gradient, void *alpha_map, int len); +static void eng_gradient_clear(void *data, void *gradient); +static void eng_gradient_fill_set(void *data, void *gradient, int x, int y, int w, int h); +static void eng_gradient_fill_angle_set(void *data, void *gradient, double angle); +static void eng_gradient_fill_spread_set(void *data, void *gradient, int spread); +static void eng_gradient_angle_set(void *data, void *gradient, double angle); +static void eng_gradient_offset_set(void *data, void *gradient, float offset); +static void eng_gradient_direction_set(void *data, void *gradient, int direction); +static void eng_gradient_type_set(void *data, void *gradient, char *name, char *params); +static int eng_gradient_is_opaque(void *data, void *context, void *gradient, int x, int y, int w, int h); +static int eng_gradient_is_visible(void *data, void *context, void *gradient, int x, int y, int w, int h); +static void eng_gradient_render_pre(void *data, void *context, void *gradient); +static void eng_gradient_render_post(void *data, void *gradient); +static void eng_gradient_draw(void *data, void *context, void *surface, void *gradient, int x, int y, int w, int h); +static void *eng_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo); + +static void *eng_image_new_from_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace); +static void *eng_image_new_from_copied_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace); +static void eng_image_free(void *data, void *image); +static void eng_image_size_get(void *data, void *image, int *w, int *h); +static void *eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h); +static void *eng_image_alpha_set(void *data, void *image, int has_alpha); +static int eng_image_alpha_get(void *data, void *image); +static char *eng_image_comment_get(void *data, void *image, char *key); +static char *eng_image_format_get(void *data, void *image); +static void eng_image_colorspace_set(void *data, void *image, int cspace); +static int eng_image_colorspace_get(void *data, void *image); +static void eng_image_native_set(void *data, void *image, void *native); +static void *eng_image_native_get(void *data, void *image); +static void *eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data); +static void *eng_image_data_put(void *data, void *image, DATA32 *image_data); +static void *eng_image_size_set(void *data, void *image, int w, int h); +static void eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth); + +static void *eng_font_add(void *data, void *font, const char *name, int size); +static Evas_Quartz_Font *quartz_font_from_ats(ATSFontContainerRef container, int size); +static void *eng_font_load(void *data, const char *name, int size); +static void *eng_font_memory_load(void *data, char *name, int size, const void *fdata, int fdata_size); +static void eng_font_free(void *data, void *font); +static int eng_font_ascent_get(void *data, void *font); +static int eng_font_descent_get(void *data, void *font); +static int eng_font_max_ascent_get(void *data, void *font); +static int eng_font_max_descent_get(void *data, void *font); +static void eng_font_string_size_get(void *data, void *font, const char *text, int *w, int *h); +static int eng_font_inset_get(void *data, void *font, const char *text); +static int eng_font_h_advance_get(void *data, void *font, const char *text); +static int eng_font_v_advance_get(void *data, void *font, const char *text); +static int eng_font_char_coords_get(void *data, void *font, const char *text, int pos, int *cx, int *cy, int *cw, int *ch); +static int eng_font_char_at_coords_get(void *data, void *font, const char *text, int x, int y, int *cx, int *cy, int *cw, int *ch); +static void eng_font_draw(void *data, void *context, void *surface, void *font, int x, int y, int w, int h, int ow, int oh, const char *text); +static void eng_font_hinting_set(void *data, void *font, int hinting); +static int eng_font_hinting_can_hint(void *data, int hinting); + +EAPI int module_open(Evas_Module *em); +EAPI void module_close(void); + +#endif /* _EVAS_QUARTZ_PRIVATE_H_ */