summaryrefslogtreecommitdiffstats
path: root/app/gegl
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--app/gegl/Makefile.am99
-rw-r--r--app/gegl/Makefile.in1116
-rw-r--r--app/gegl/gimp-babl-compat.c93
-rw-r--r--app/gegl/gimp-babl-compat.h31
-rw-r--r--app/gegl/gimp-babl.c1415
-rw-r--r--app/gegl/gimp-babl.h62
-rw-r--r--app/gegl/gimp-gegl-apply-operation.c827
-rw-r--r--app/gegl/gimp-gegl-apply-operation.h172
-rw-r--r--app/gegl/gimp-gegl-enums.c43
-rw-r--r--app/gegl/gimp-gegl-enums.h35
-rw-r--r--app/gegl/gimp-gegl-loops-sse2.c127
-rw-r--r--app/gegl/gimp-gegl-loops-sse2.h40
-rw-r--r--app/gegl/gimp-gegl-loops.cc1089
-rw-r--r--app/gegl/gimp-gegl-loops.h109
-rw-r--r--app/gegl/gimp-gegl-mask-combine.cc653
-rw-r--r--app/gegl/gimp-gegl-mask-combine.h51
-rw-r--r--app/gegl/gimp-gegl-mask.c253
-rw-r--r--app/gegl/gimp-gegl-mask.h30
-rw-r--r--app/gegl/gimp-gegl-nodes.c260
-rw-r--r--app/gegl/gimp-gegl-nodes.h52
-rw-r--r--app/gegl/gimp-gegl-tile-compat.c79
-rw-r--r--app/gegl/gimp-gegl-tile-compat.h36
-rw-r--r--app/gegl/gimp-gegl-types.h34
-rw-r--r--app/gegl/gimp-gegl-utils.c348
-rw-r--r--app/gegl/gimp-gegl-utils.h60
-rw-r--r--app/gegl/gimp-gegl.c171
-rw-r--r--app/gegl/gimp-gegl.h29
-rw-r--r--app/gegl/gimpapplicator.c652
-rw-r--r--app/gegl/gimpapplicator.h146
-rw-r--r--app/gegl/gimptilehandlervalidate.c766
-rw-r--r--app/gegl/gimptilehandlervalidate.h112
31 files changed, 8990 insertions, 0 deletions
diff --git a/app/gegl/Makefile.am b/app/gegl/Makefile.am
new file mode 100644
index 0000000..e402056
--- /dev/null
+++ b/app/gegl/Makefile.am
@@ -0,0 +1,99 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"Gimp-GEGL\" \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ -I$(top_builddir)/app \
+ -I$(top_srcdir)/app \
+ $(CAIRO_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ $(GDK_PIXBUF_CFLAGS) \
+ -I$(includedir)
+
+noinst_LIBRARIES = \
+ libappgegl-generic.a \
+ libappgegl-sse2.a \
+ libappgegl.a
+
+libappgegl_generic_a_sources = \
+ gimp-gegl-enums.h \
+ gimp-gegl-types.h \
+ gimp-babl.c \
+ gimp-babl.h \
+ gimp-babl-compat.c \
+ gimp-babl-compat.h \
+ gimp-gegl.c \
+ gimp-gegl.h \
+ gimp-gegl-apply-operation.c \
+ gimp-gegl-apply-operation.h \
+ gimp-gegl-loops.cc \
+ gimp-gegl-loops.h \
+ gimp-gegl-mask.c \
+ gimp-gegl-mask.h \
+ gimp-gegl-mask-combine.cc \
+ gimp-gegl-mask-combine.h \
+ gimp-gegl-nodes.c \
+ gimp-gegl-nodes.h \
+ gimp-gegl-tile-compat.c \
+ gimp-gegl-tile-compat.h \
+ gimp-gegl-utils.c \
+ gimp-gegl-utils.h \
+ gimpapplicator.c \
+ gimpapplicator.h \
+ gimptilehandlervalidate.c \
+ gimptilehandlervalidate.h
+
+libappgegl_generic_a_built_sources = gimp-gegl-enums.c
+
+libappgegl_sse2_a_sources = \
+ gimp-gegl-loops-sse2.c \
+ gimp-gegl-loops-sse2.h
+
+libappgegl_generic_a_SOURCES = $(libappgegl_generic_a_built_sources) $(libappgegl_generic_a_sources)
+
+libappgegl_sse2_a_SOURCES = $(libappgegl_sse2_a_sources)
+
+libappgegl_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS)
+
+libappgegl_a_SOURCES =
+
+
+libappgegl.a: libappgegl-generic.a \
+ libappgegl-sse2.a
+ $(AR) $(ARFLAGS) libappgegl.a \
+ $(libappgegl_generic_a_OBJECTS) \
+ $(libappgegl_sse2_a_OBJECTS)
+ $(RANLIB) libappgegl.a
+
+
+#
+# rules to generate built sources
+#
+# setup autogeneration dependencies
+gen_sources = xgen-ggec
+CLEANFILES = $(gen_sources)
+
+xgen-ggec: $(srcdir)/gimp-gegl-enums.h $(GIMP_MKENUMS) Makefile.am
+ $(AM_V_GEN) $(GIMP_MKENUMS) \
+ --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"core/core-enums.h\"\n#include \"gimp-gegl-enums.h\"\n#include \"gimp-intl.h\"" \
+ --fprod "\n/* enumerations from \"@basename@\" */" \
+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n };\n" \
+ --dhead " static const Gimp@Type@Desc descs[] =\n {" \
+ --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \
+ --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \
+ $< > $@
+
+# copy the generated enum file back to the source directory only if it's
+# changed; otherwise, only update its timestamp, so that the recipe isn't
+# executed again on the next build, however, allow this to (harmlessly) fail,
+# to support building from a read-only source tree.
+$(srcdir)/gimp-gegl-enums.c: xgen-ggec
+ $(AM_V_GEN) if ! cmp -s $< $@; then \
+ cp $< $@; \
+ else \
+ touch $@ 2> /dev/null \
+ || true; \
+ fi
diff --git a/app/gegl/Makefile.in b/app/gegl/Makefile.in
new file mode 100644
index 0000000..1e9d24b
--- /dev/null
+++ b/app/gegl/Makefile.in
@@ -0,0 +1,1116 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = app/gegl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libappgegl_generic_a_AR = $(AR) $(ARFLAGS)
+libappgegl_generic_a_LIBADD =
+am__objects_1 = gimp-gegl-enums.$(OBJEXT)
+am__objects_2 = gimp-babl.$(OBJEXT) gimp-babl-compat.$(OBJEXT) \
+ gimp-gegl.$(OBJEXT) gimp-gegl-apply-operation.$(OBJEXT) \
+ gimp-gegl-loops.$(OBJEXT) gimp-gegl-mask.$(OBJEXT) \
+ gimp-gegl-mask-combine.$(OBJEXT) gimp-gegl-nodes.$(OBJEXT) \
+ gimp-gegl-tile-compat.$(OBJEXT) gimp-gegl-utils.$(OBJEXT) \
+ gimpapplicator.$(OBJEXT) gimptilehandlervalidate.$(OBJEXT)
+am_libappgegl_generic_a_OBJECTS = $(am__objects_1) $(am__objects_2)
+libappgegl_generic_a_OBJECTS = $(am_libappgegl_generic_a_OBJECTS)
+libappgegl_sse2_a_AR = $(AR) $(ARFLAGS)
+libappgegl_sse2_a_LIBADD =
+am__objects_3 = libappgegl_sse2_a-gimp-gegl-loops-sse2.$(OBJEXT)
+am_libappgegl_sse2_a_OBJECTS = $(am__objects_3)
+libappgegl_sse2_a_OBJECTS = $(am_libappgegl_sse2_a_OBJECTS)
+libappgegl_a_AR = $(AR) $(ARFLAGS)
+libappgegl_a_LIBADD =
+am_libappgegl_a_OBJECTS =
+libappgegl_a_OBJECTS = $(am_libappgegl_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/gimp-babl-compat.Po \
+ ./$(DEPDIR)/gimp-babl.Po \
+ ./$(DEPDIR)/gimp-gegl-apply-operation.Po \
+ ./$(DEPDIR)/gimp-gegl-enums.Po ./$(DEPDIR)/gimp-gegl-loops.Po \
+ ./$(DEPDIR)/gimp-gegl-mask-combine.Po \
+ ./$(DEPDIR)/gimp-gegl-mask.Po ./$(DEPDIR)/gimp-gegl-nodes.Po \
+ ./$(DEPDIR)/gimp-gegl-tile-compat.Po \
+ ./$(DEPDIR)/gimp-gegl-utils.Po ./$(DEPDIR)/gimp-gegl.Po \
+ ./$(DEPDIR)/gimpapplicator.Po \
+ ./$(DEPDIR)/gimptilehandlervalidate.Po \
+ ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po
+am__mv = mv -f
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(libappgegl_generic_a_SOURCES) $(libappgegl_sse2_a_SOURCES) \
+ $(libappgegl_a_SOURCES)
+DIST_SOURCES = $(libappgegl_generic_a_SOURCES) \
+ $(libappgegl_sse2_a_SOURCES) $(libappgegl_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"Gimp-GEGL\" \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ -I$(top_builddir)/app \
+ -I$(top_srcdir)/app \
+ $(CAIRO_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ $(GDK_PIXBUF_CFLAGS) \
+ -I$(includedir)
+
+noinst_LIBRARIES = \
+ libappgegl-generic.a \
+ libappgegl-sse2.a \
+ libappgegl.a
+
+libappgegl_generic_a_sources = \
+ gimp-gegl-enums.h \
+ gimp-gegl-types.h \
+ gimp-babl.c \
+ gimp-babl.h \
+ gimp-babl-compat.c \
+ gimp-babl-compat.h \
+ gimp-gegl.c \
+ gimp-gegl.h \
+ gimp-gegl-apply-operation.c \
+ gimp-gegl-apply-operation.h \
+ gimp-gegl-loops.cc \
+ gimp-gegl-loops.h \
+ gimp-gegl-mask.c \
+ gimp-gegl-mask.h \
+ gimp-gegl-mask-combine.cc \
+ gimp-gegl-mask-combine.h \
+ gimp-gegl-nodes.c \
+ gimp-gegl-nodes.h \
+ gimp-gegl-tile-compat.c \
+ gimp-gegl-tile-compat.h \
+ gimp-gegl-utils.c \
+ gimp-gegl-utils.h \
+ gimpapplicator.c \
+ gimpapplicator.h \
+ gimptilehandlervalidate.c \
+ gimptilehandlervalidate.h
+
+libappgegl_generic_a_built_sources = gimp-gegl-enums.c
+libappgegl_sse2_a_sources = \
+ gimp-gegl-loops-sse2.c \
+ gimp-gegl-loops-sse2.h
+
+libappgegl_generic_a_SOURCES = $(libappgegl_generic_a_built_sources) $(libappgegl_generic_a_sources)
+libappgegl_sse2_a_SOURCES = $(libappgegl_sse2_a_sources)
+libappgegl_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS)
+libappgegl_a_SOURCES =
+
+#
+# rules to generate built sources
+#
+# setup autogeneration dependencies
+gen_sources = xgen-ggec
+CLEANFILES = $(gen_sources)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu app/gegl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu app/gegl/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libappgegl-generic.a: $(libappgegl_generic_a_OBJECTS) $(libappgegl_generic_a_DEPENDENCIES) $(EXTRA_libappgegl_generic_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libappgegl-generic.a
+ $(AM_V_AR)$(libappgegl_generic_a_AR) libappgegl-generic.a $(libappgegl_generic_a_OBJECTS) $(libappgegl_generic_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libappgegl-generic.a
+
+libappgegl-sse2.a: $(libappgegl_sse2_a_OBJECTS) $(libappgegl_sse2_a_DEPENDENCIES) $(EXTRA_libappgegl_sse2_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libappgegl-sse2.a
+ $(AM_V_AR)$(libappgegl_sse2_a_AR) libappgegl-sse2.a $(libappgegl_sse2_a_OBJECTS) $(libappgegl_sse2_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libappgegl-sse2.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-babl-compat.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-babl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-apply-operation.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-enums.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-loops.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-mask-combine.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-mask.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-nodes.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-tile-compat.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpapplicator.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptilehandlervalidate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libappgegl_sse2_a-gimp-gegl-loops-sse2.o: gimp-gegl-loops-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -MT libappgegl_sse2_a-gimp-gegl-loops-sse2.o -MD -MP -MF $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.o `test -f 'gimp-gegl-loops-sse2.c' || echo '$(srcdir)/'`gimp-gegl-loops-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimp-gegl-loops-sse2.c' object='libappgegl_sse2_a-gimp-gegl-loops-sse2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.o `test -f 'gimp-gegl-loops-sse2.c' || echo '$(srcdir)/'`gimp-gegl-loops-sse2.c
+
+libappgegl_sse2_a-gimp-gegl-loops-sse2.obj: gimp-gegl-loops-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -MT libappgegl_sse2_a-gimp-gegl-loops-sse2.obj -MD -MP -MF $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.obj `if test -f 'gimp-gegl-loops-sse2.c'; then $(CYGPATH_W) 'gimp-gegl-loops-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimp-gegl-loops-sse2.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimp-gegl-loops-sse2.c' object='libappgegl_sse2_a-gimp-gegl-loops-sse2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.obj `if test -f 'gimp-gegl-loops-sse2.c'; then $(CYGPATH_W) 'gimp-gegl-loops-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimp-gegl-loops-sse2.c'; fi`
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/gimp-babl-compat.Po
+ -rm -f ./$(DEPDIR)/gimp-babl.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-apply-operation.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-enums.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-loops.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-mask-combine.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-mask.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-nodes.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-tile-compat.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-utils.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl.Po
+ -rm -f ./$(DEPDIR)/gimpapplicator.Po
+ -rm -f ./$(DEPDIR)/gimptilehandlervalidate.Po
+ -rm -f ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/gimp-babl-compat.Po
+ -rm -f ./$(DEPDIR)/gimp-babl.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-apply-operation.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-enums.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-loops.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-mask-combine.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-mask.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-nodes.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-tile-compat.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl-utils.Po
+ -rm -f ./$(DEPDIR)/gimp-gegl.Po
+ -rm -f ./$(DEPDIR)/gimpapplicator.Po
+ -rm -f ./$(DEPDIR)/gimptilehandlervalidate.Po
+ -rm -f ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+libappgegl.a: libappgegl-generic.a \
+ libappgegl-sse2.a
+ $(AR) $(ARFLAGS) libappgegl.a \
+ $(libappgegl_generic_a_OBJECTS) \
+ $(libappgegl_sse2_a_OBJECTS)
+ $(RANLIB) libappgegl.a
+
+xgen-ggec: $(srcdir)/gimp-gegl-enums.h $(GIMP_MKENUMS) Makefile.am
+ $(AM_V_GEN) $(GIMP_MKENUMS) \
+ --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"core/core-enums.h\"\n#include \"gimp-gegl-enums.h\"\n#include \"gimp-intl.h\"" \
+ --fprod "\n/* enumerations from \"@basename@\" */" \
+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n };\n" \
+ --dhead " static const Gimp@Type@Desc descs[] =\n {" \
+ --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \
+ --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \
+ $< > $@
+
+# copy the generated enum file back to the source directory only if it's
+# changed; otherwise, only update its timestamp, so that the recipe isn't
+# executed again on the next build, however, allow this to (harmlessly) fail,
+# to support building from a read-only source tree.
+$(srcdir)/gimp-gegl-enums.c: xgen-ggec
+ $(AM_V_GEN) if ! cmp -s $< $@; then \
+ cp $< $@; \
+ else \
+ touch $@ 2> /dev/null \
+ || true; \
+ fi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/app/gegl/gimp-babl-compat.c b/app/gegl/gimp-babl-compat.c
new file mode 100644
index 0000000..b077f86
--- /dev/null
+++ b/app/gegl/gimp-babl-compat.c
@@ -0,0 +1,93 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-babl-compat.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-babl.h"
+#include "gimp-babl-compat.h"
+
+
+GimpImageType
+gimp_babl_format_get_image_type (const Babl *format)
+{
+ const Babl *model;
+
+ g_return_val_if_fail (format != NULL, -1);
+
+ model = babl_format_get_model (format);
+
+ if (model == babl_model ("Y") ||
+ model == babl_model ("Y'"))
+ {
+ return GIMP_GRAY_IMAGE;
+ }
+ else if (model == babl_model ("YA") ||
+ model == babl_model ("Y'A"))
+ {
+ return GIMP_GRAYA_IMAGE;
+ }
+ else if (model == babl_model ("RGB") ||
+ model == babl_model ("R'G'B'"))
+ {
+ return GIMP_RGB_IMAGE;
+ }
+ else if (model == babl_model ("RGBA") ||
+ model == babl_model ("R'G'B'A"))
+ {
+ return GIMP_RGBA_IMAGE;
+ }
+ else if (babl_format_is_palette (format))
+ {
+ if (babl_format_has_alpha (format))
+ return GIMP_INDEXEDA_IMAGE;
+ else
+ return GIMP_INDEXED_IMAGE;
+ }
+
+ g_return_val_if_reached (-1);
+}
+
+const Babl *
+gimp_babl_compat_u8_format (const Babl *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ /* indexed images only exist in u8, return the same format */
+ if (babl_format_is_palette (format))
+ return format;
+
+ return gimp_babl_format (gimp_babl_format_get_base_type (format),
+ GIMP_PRECISION_U8_GAMMA,
+ babl_format_has_alpha (format));
+}
+
+const Babl *
+gimp_babl_compat_u8_mask_format (const Babl *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return gimp_babl_format (gimp_babl_format_get_base_type (format),
+ GIMP_PRECISION_U8_LINEAR,
+ FALSE);
+}
diff --git a/app/gegl/gimp-babl-compat.h b/app/gegl/gimp-babl-compat.h
new file mode 100644
index 0000000..778bf3e
--- /dev/null
+++ b/app/gegl/gimp-babl-compat.h
@@ -0,0 +1,31 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-babl-compat.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_BABL_COMPAT_H__
+#define __GIMP_BABL_COMPAT_H__
+
+
+GimpImageType gimp_babl_format_get_image_type (const Babl *format);
+
+const Babl * gimp_babl_compat_u8_format (const Babl *format);
+const Babl * gimp_babl_compat_u8_mask_format (const Babl *format);
+
+
+#endif /* __GIMP_BABL_COMPAT_H__ */
diff --git a/app/gegl/gimp-babl.c b/app/gegl/gimp-babl.c
new file mode 100644
index 0000000..b2dc20a
--- /dev/null
+++ b/app/gegl/gimp-babl.c
@@ -0,0 +1,1415 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-babl.c
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpcolor/gimpcolor.h"
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-babl.h"
+
+#include "gimp-intl.h"
+
+
+void
+gimp_babl_init (void)
+{
+ babl_format_new ("name", "R u8",
+ babl_model ("RGBA"),
+ babl_type ("u8"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' u8",
+ babl_model ("R'G'B'A"),
+ babl_type ("u8"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G u8",
+ babl_model ("RGBA"),
+ babl_type ("u8"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' u8",
+ babl_model ("R'G'B'A"),
+ babl_type ("u8"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B u8",
+ babl_model ("RGBA"),
+ babl_type ("u8"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' u8",
+ babl_model ("R'G'B'A"),
+ babl_type ("u8"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A u8",
+ babl_model ("RGBA"),
+ babl_type ("u8"),
+ babl_component ("A"),
+ NULL);
+
+ babl_format_new ("name", "R u16",
+ babl_model ("RGBA"),
+ babl_type ("u16"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' u16",
+ babl_model ("R'G'B'A"),
+ babl_type ("u16"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G u16",
+ babl_model ("RGBA"),
+ babl_type ("u16"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' u16",
+ babl_model ("R'G'B'A"),
+ babl_type ("u16"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B u16",
+ babl_model ("RGBA"),
+ babl_type ("u16"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' u16",
+ babl_model ("R'G'B'A"),
+ babl_type ("u16"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A u16",
+ babl_model ("RGBA"),
+ babl_type ("u16"),
+ babl_component ("A"),
+ NULL);
+
+ babl_format_new ("name", "R u32",
+ babl_model ("RGBA"),
+ babl_type ("u32"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' u32",
+ babl_model ("R'G'B'A"),
+ babl_type ("u32"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G u32",
+ babl_model ("RGBA"),
+ babl_type ("u32"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' u32",
+ babl_model ("R'G'B'A"),
+ babl_type ("u32"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B u32",
+ babl_model ("RGBA"),
+ babl_type ("u32"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' u32",
+ babl_model ("R'G'B'A"),
+ babl_type ("u32"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A u32",
+ babl_model ("RGBA"),
+ babl_type ("u32"),
+ babl_component ("A"),
+ NULL);
+
+ babl_format_new ("name", "R half",
+ babl_model ("RGBA"),
+ babl_type ("half"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' half",
+ babl_model ("R'G'B'A"),
+ babl_type ("half"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G half",
+ babl_model ("RGBA"),
+ babl_type ("half"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' half",
+ babl_model ("R'G'B'A"),
+ babl_type ("half"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B half",
+ babl_model ("RGBA"),
+ babl_type ("half"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' half",
+ babl_model ("R'G'B'A"),
+ babl_type ("half"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A half",
+ babl_model ("RGBA"),
+ babl_type ("half"),
+ babl_component ("A"),
+ NULL);
+
+ babl_format_new ("name", "R float",
+ babl_model ("RGBA"),
+ babl_type ("float"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' float",
+ babl_model ("R'G'B'A"),
+ babl_type ("float"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G float",
+ babl_model ("RGBA"),
+ babl_type ("float"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' float",
+ babl_model ("R'G'B'A"),
+ babl_type ("float"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B float",
+ babl_model ("RGBA"),
+ babl_type ("float"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' float",
+ babl_model ("R'G'B'A"),
+ babl_type ("float"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A float",
+ babl_model ("RGBA"),
+ babl_type ("float"),
+ babl_component ("A"),
+ NULL);
+
+ babl_format_new ("name", "R double",
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("R"),
+ NULL);
+ babl_format_new ("name", "R' double",
+ babl_model ("R'G'B'A"),
+ babl_type ("double"),
+ babl_component ("R'"),
+ NULL);
+ babl_format_new ("name", "G double",
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("G"),
+ NULL);
+ babl_format_new ("name", "G' double",
+ babl_model ("R'G'B'A"),
+ babl_type ("double"),
+ babl_component ("G'"),
+ NULL);
+ babl_format_new ("name", "B double",
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("B"),
+ NULL);
+ babl_format_new ("name", "B' double",
+ babl_model ("R'G'B'A"),
+ babl_type ("double"),
+ babl_component ("B'"),
+ NULL);
+ babl_format_new ("name", "A double",
+ babl_model ("RGBA"),
+ babl_type ("double"),
+ babl_component ("A"),
+ NULL);
+}
+
+void
+gimp_babl_init_fishes (GimpInitStatusFunc status_callback)
+{
+ /* create a bunch of fishes - to decrease the initial lazy
+ * initialization cost for some interactions
+ */
+ static const struct
+ {
+ const gchar *from_format;
+ const gchar *to_format;
+ }
+ fishes[] =
+ {
+ { "Y' u8", "RaGaBaA float" },
+ { "Y u8", "RaGaBaA float" },
+ { "R'G'B'A u8", "RaGaBaA float" },
+ { "R'G'B'A float", "R'G'B'A u8" },
+ { "R'G'B'A float", "R'G'B' u8" },
+ { "R'G'B'A u8", "RGBA float" },
+ { "RGBA float", "R'G'B'A u8" },
+ { "RGBA float", "R'G'B'A u8" },
+ { "RGBA float", "R'G'B'A float" },
+ { "Y' u8", "R'G'B' u8" },
+ { "Y u8", "Y float" },
+ { "R'G'B' u8", "cairo-RGB24" },
+ { "R'G'B' u8", "R'G'B'A float" },
+ { "R'G'B' u8", "R'G'B'A u8" },
+ { "R'G'B'A u8", "R'G'B'A float" },
+ { "R'G'B'A u8", "cairo-ARGB32" },
+ { "R'G'B'A double", "RGBA float" },
+ { "R'G'B'A float", "RGBA double" },
+ { "R'G'B' u8", "RGB float" },
+ { "RGB float", "R'G'B'A float" },
+ { "R'G'B' u8", "RGBA float" },
+ { "RaGaBaA float", "R'G'B'A float" },
+ { "RaGaBaA float", "RGBA float" },
+ { "RGBA float", "RaGaBaA float" },
+ { "R'G'B' u8", "RaGaBaA float" },
+ { "cairo-ARGB32", "R'G'B'A u8" }
+ };
+
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (fishes); i++)
+ {
+ status_callback (NULL, NULL,
+ (gdouble) (i + 1) /
+ (gdouble) G_N_ELEMENTS (fishes) * 0.8);
+
+ babl_fish (babl_format (fishes[i].from_format),
+ babl_format (fishes[i].to_format));
+ }
+}
+
+static const struct
+{
+ const gchar *name;
+ const gchar *description;
+}
+babl_descriptions[] =
+{
+ { "RGB u8", N_("RGB") },
+ { "R'G'B' u8", N_("RGB") },
+ { "RGB u16", N_("RGB") },
+ { "R'G'B' u16", N_("RGB") },
+ { "RGB u32", N_("RGB") },
+ { "R'G'B' u32", N_("RGB") },
+ { "RGB half", N_("RGB") },
+ { "R'G'B' half", N_("RGB") },
+ { "RGB float", N_("RGB") },
+ { "R'G'B' float", N_("RGB") },
+ { "RGB double", N_("RGB") },
+ { "R'G'B' double", N_("RGB") },
+
+ { "RGBA u8", N_("RGB-alpha") },
+ { "R'G'B'A u8", N_("RGB-alpha") },
+ { "RGBA u16", N_("RGB-alpha") },
+ { "R'G'B'A u16", N_("RGB-alpha") },
+ { "RGBA u32", N_("RGB-alpha") },
+ { "R'G'B'A u32", N_("RGB-alpha") },
+ { "RGBA half", N_("RGB-alpha") },
+ { "R'G'B'A half", N_("RGB-alpha") },
+ { "RGBA float", N_("RGB-alpha") },
+ { "R'G'B'A float", N_("RGB-alpha") },
+ { "RGBA double", N_("RGB-alpha") },
+ { "R'G'B'A double", N_("RGB-alpha") },
+
+ { "Y u8", N_("Grayscale") },
+ { "Y' u8", N_("Grayscale") },
+ { "Y u16", N_("Grayscale") },
+ { "Y' u16", N_("Grayscale") },
+ { "Y u32", N_("Grayscale") },
+ { "Y' u32", N_("Grayscale") },
+ { "Y half", N_("Grayscale") },
+ { "Y' half", N_("Grayscale") },
+ { "Y float", N_("Grayscale") },
+ { "Y' float", N_("Grayscale") },
+ { "Y double", N_("Grayscale") },
+ { "Y' double", N_("Grayscale") },
+
+ { "YA u8", N_("Grayscale-alpha") },
+ { "Y'A u8", N_("Grayscale-alpha") },
+ { "YA u16", N_("Grayscale-alpha") },
+ { "Y'A u16", N_("Grayscale-alpha") },
+ { "YA u32", N_("Grayscale-alpha") },
+ { "Y'A u32", N_("Grayscale-alpha") },
+ { "YA half", N_("Grayscale-alpha") },
+ { "Y'A half", N_("Grayscale-alpha") },
+ { "YA float", N_("Grayscale-alpha") },
+ { "Y'A float", N_("Grayscale-alpha") },
+ { "YA double", N_("Grayscale-alpha") },
+ { "Y'A double", N_("Grayscale-alpha") },
+
+ { "R u8", N_("Red component") },
+ { "R' u8", N_("Red component") },
+ { "R u16", N_("Red component") },
+ { "R' u16", N_("Red component") },
+ { "R u32", N_("Red component") },
+ { "R' u32", N_("Red component") },
+ { "R half", N_("Red component") },
+ { "R' half", N_("Red component") },
+ { "R float", N_("Red component") },
+ { "R' float", N_("Red component") },
+ { "R double", N_("Red component") },
+ { "R' double", N_("Red component") },
+
+ { "G u8", N_("Green component") },
+ { "G' u8", N_("Green component") },
+ { "G u16", N_("Green component") },
+ { "G' u16", N_("Green component") },
+ { "G u32", N_("Green component") },
+ { "G' u32", N_("Green component") },
+ { "G half", N_("Green component") },
+ { "G' half", N_("Green component") },
+ { "G float", N_("Green component") },
+ { "G' float", N_("Green component") },
+ { "G double", N_("Green component") },
+ { "G' double", N_("Green component") },
+
+ { "B u8", N_("Blue component") },
+ { "B' u8", N_("Blue component") },
+ { "B u16", N_("Blue component") },
+ { "B' u16", N_("Blue component") },
+ { "B u32", N_("Blue component") },
+ { "B' u32", N_("Blue component") },
+ { "B half", N_("Blue component") },
+ { "B' half", N_("Blue component") },
+ { "B float", N_("Blue component") },
+ { "B' float", N_("Blue component") },
+ { "B double", N_("Blue component") },
+ { "B' double", N_("Blue component") },
+
+ { "A u8", N_("Alpha component") },
+ { "A u16", N_("Alpha component") },
+ { "A u32", N_("Alpha component") },
+ { "A half", N_("Alpha component") },
+ { "A float", N_("Alpha component") },
+ { "A double", N_("Alpha component") }
+};
+
+static GHashTable *babl_description_hash = NULL;
+
+const gchar *
+gimp_babl_format_get_description (const Babl *babl)
+{
+ const gchar *description;
+
+ g_return_val_if_fail (babl != NULL, NULL);
+
+ if (G_UNLIKELY (! babl_description_hash))
+ {
+ gint i;
+
+ babl_description_hash = g_hash_table_new (g_str_hash,
+ g_str_equal);
+
+ for (i = 0; i < G_N_ELEMENTS (babl_descriptions); i++)
+ g_hash_table_insert (babl_description_hash,
+ (gpointer) babl_descriptions[i].name,
+ gettext (babl_descriptions[i].description));
+ }
+
+ if (babl_format_is_palette (babl))
+ {
+ if (babl_format_has_alpha (babl))
+ return _("Indexed-alpha");
+ else
+ return _("Indexed");
+ }
+
+ description = g_hash_table_lookup (babl_description_hash,
+ babl_get_name (babl));
+
+ if (description)
+ return description;
+
+ return g_strconcat ("ERROR: unknown Babl format ",
+ babl_get_name (babl), NULL);
+}
+
+GimpColorProfile *
+gimp_babl_format_get_color_profile (const Babl *format)
+{
+ static GimpColorProfile *srgb_profile = NULL;
+ static GimpColorProfile *linear_rgb_profile = NULL;
+ static GimpColorProfile *gray_profile = NULL;
+ static GimpColorProfile *linear_gray_profile = NULL;
+
+ g_return_val_if_fail (format != NULL, NULL);
+
+ if (gimp_babl_format_get_base_type (format) == GIMP_GRAY)
+ {
+ if (gimp_babl_format_get_linear (format))
+ {
+ if (! linear_gray_profile)
+ {
+ linear_gray_profile = gimp_color_profile_new_d65_gray_linear ();
+ g_object_add_weak_pointer (G_OBJECT (linear_gray_profile),
+ (gpointer) &linear_gray_profile);
+ }
+
+ return linear_gray_profile;
+ }
+ else
+ {
+ if (! gray_profile)
+ {
+ gray_profile = gimp_color_profile_new_d65_gray_srgb_trc ();
+ g_object_add_weak_pointer (G_OBJECT (gray_profile),
+ (gpointer) &gray_profile);
+ }
+
+ return gray_profile;
+ }
+ }
+ else
+ {
+ if (gimp_babl_format_get_linear (format))
+ {
+ if (! linear_rgb_profile)
+ {
+ linear_rgb_profile = gimp_color_profile_new_rgb_srgb_linear ();
+ g_object_add_weak_pointer (G_OBJECT (linear_rgb_profile),
+ (gpointer) &linear_rgb_profile);
+ }
+
+ return linear_rgb_profile;
+ }
+ else
+ {
+ if (! srgb_profile)
+ {
+ srgb_profile = gimp_color_profile_new_rgb_srgb ();
+ g_object_add_weak_pointer (G_OBJECT (srgb_profile),
+ (gpointer) &srgb_profile);
+ }
+
+ return srgb_profile;
+ }
+ }
+}
+
+GimpImageBaseType
+gimp_babl_format_get_base_type (const Babl *format)
+{
+ const Babl *model;
+
+ g_return_val_if_fail (format != NULL, -1);
+
+ model = babl_format_get_model (format);
+
+ if (model == babl_model ("Y") ||
+ model == babl_model ("Y'") ||
+ model == babl_model ("YA") ||
+ model == babl_model ("Y'A"))
+ {
+ return GIMP_GRAY;
+ }
+ else if (model == babl_model ("RGB") ||
+ model == babl_model ("R'G'B'") ||
+ model == babl_model ("RGBA") ||
+ model == babl_model ("R'G'B'A") ||
+ model == babl_model ("RaGaBaA") ||
+ model == babl_model ("R'aG'aB'aA"))
+ {
+ return GIMP_RGB;
+ }
+ else if (babl_format_is_palette (format))
+ {
+ return GIMP_INDEXED;
+ }
+
+ g_return_val_if_reached (-1);
+}
+
+GimpComponentType
+gimp_babl_format_get_component_type (const Babl *format)
+{
+ const Babl *type;
+
+ g_return_val_if_fail (format != NULL, -1);
+
+ type = babl_format_get_type (format, 0);
+
+ if (type == babl_type ("u8"))
+ return GIMP_COMPONENT_TYPE_U8;
+ else if (type == babl_type ("u16"))
+ return GIMP_COMPONENT_TYPE_U16;
+ else if (type == babl_type ("u32"))
+ return GIMP_COMPONENT_TYPE_U32;
+ else if (type == babl_type ("half"))
+ return GIMP_COMPONENT_TYPE_HALF;
+ else if (type == babl_type ("float"))
+ return GIMP_COMPONENT_TYPE_FLOAT;
+ else if (type == babl_type ("double"))
+ return GIMP_COMPONENT_TYPE_DOUBLE;
+
+ g_return_val_if_reached (-1);
+}
+
+GimpPrecision
+gimp_babl_format_get_precision (const Babl *format)
+{
+ const Babl *type;
+
+ g_return_val_if_fail (format != NULL, -1);
+
+ type = babl_format_get_type (format, 0);
+
+ if (gimp_babl_format_get_linear (format))
+ {
+ if (type == babl_type ("u8"))
+ return GIMP_PRECISION_U8_LINEAR;
+ else if (type == babl_type ("u16"))
+ return GIMP_PRECISION_U16_LINEAR;
+ else if (type == babl_type ("u32"))
+ return GIMP_PRECISION_U32_LINEAR;
+ else if (type == babl_type ("half"))
+ return GIMP_PRECISION_HALF_LINEAR;
+ else if (type == babl_type ("float"))
+ return GIMP_PRECISION_FLOAT_LINEAR;
+ else if (type == babl_type ("double"))
+ return GIMP_PRECISION_DOUBLE_LINEAR;
+ }
+ else
+ {
+ if (type == babl_type ("u8"))
+ return GIMP_PRECISION_U8_GAMMA;
+ else if (type == babl_type ("u16"))
+ return GIMP_PRECISION_U16_GAMMA;
+ else if (type == babl_type ("u32"))
+ return GIMP_PRECISION_U32_GAMMA;
+ else if (type == babl_type ("half"))
+ return GIMP_PRECISION_HALF_GAMMA;
+ else if (type == babl_type ("float"))
+ return GIMP_PRECISION_FLOAT_GAMMA;
+ else if (type == babl_type ("double"))
+ return GIMP_PRECISION_DOUBLE_GAMMA;
+ }
+
+ g_return_val_if_reached (-1);
+}
+
+gboolean
+gimp_babl_format_get_linear (const Babl *format)
+{
+ const Babl *model;
+
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ model = babl_format_get_model (format);
+
+ if (model == babl_model ("Y") ||
+ model == babl_model ("YA") ||
+ model == babl_model ("RGB") ||
+ model == babl_model ("RGBA") ||
+ model == babl_model ("RaGaBaA"))
+ {
+ return TRUE;
+ }
+ else if (model == babl_model ("Y'") ||
+ model == babl_model ("Y'A") ||
+ model == babl_model ("R'G'B'") ||
+ model == babl_model ("R'G'B'A") ||
+ model == babl_model ("R'aG'aB'aA"))
+ {
+ return FALSE;
+ }
+ else if (babl_format_is_palette (format))
+ {
+ return FALSE;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+GimpComponentType
+gimp_babl_component_type (GimpPrecision precision)
+{
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ case GIMP_PRECISION_U8_GAMMA:
+ return GIMP_COMPONENT_TYPE_U8;
+
+ case GIMP_PRECISION_U16_LINEAR:
+ case GIMP_PRECISION_U16_GAMMA:
+ return GIMP_COMPONENT_TYPE_U16;
+
+ case GIMP_PRECISION_U32_LINEAR:
+ case GIMP_PRECISION_U32_GAMMA:
+ return GIMP_COMPONENT_TYPE_U32;
+
+ case GIMP_PRECISION_HALF_LINEAR:
+ case GIMP_PRECISION_HALF_GAMMA:
+ return GIMP_COMPONENT_TYPE_HALF;
+
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ return GIMP_COMPONENT_TYPE_FLOAT;
+
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ return GIMP_COMPONENT_TYPE_DOUBLE;
+ }
+
+ g_return_val_if_reached (-1);
+}
+
+gboolean
+gimp_babl_linear (GimpPrecision precision)
+{
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ case GIMP_PRECISION_U16_LINEAR:
+ case GIMP_PRECISION_U32_LINEAR:
+ case GIMP_PRECISION_HALF_LINEAR:
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ return TRUE;
+
+ case GIMP_PRECISION_U8_GAMMA:
+ case GIMP_PRECISION_U16_GAMMA:
+ case GIMP_PRECISION_U32_GAMMA:
+ case GIMP_PRECISION_HALF_GAMMA:
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ return FALSE;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+GimpPrecision
+gimp_babl_precision (GimpComponentType component,
+ gboolean linear)
+{
+ switch (component)
+ {
+ case GIMP_COMPONENT_TYPE_U8:
+ if (linear)
+ return GIMP_PRECISION_U8_LINEAR;
+ else
+ return GIMP_PRECISION_U8_GAMMA;
+
+ case GIMP_COMPONENT_TYPE_U16:
+ if (linear)
+ return GIMP_PRECISION_U16_LINEAR;
+ else
+ return GIMP_PRECISION_U16_GAMMA;
+
+ case GIMP_COMPONENT_TYPE_U32:
+ if (linear)
+ return GIMP_PRECISION_U32_LINEAR;
+ else
+ return GIMP_PRECISION_U32_GAMMA;
+
+ case GIMP_COMPONENT_TYPE_HALF:
+ if (linear)
+ return GIMP_PRECISION_HALF_LINEAR;
+ else
+ return GIMP_PRECISION_HALF_GAMMA;
+
+ case GIMP_COMPONENT_TYPE_FLOAT:
+ if (linear)
+ return GIMP_PRECISION_FLOAT_LINEAR;
+ else
+ return GIMP_PRECISION_FLOAT_GAMMA;
+
+ case GIMP_COMPONENT_TYPE_DOUBLE:
+ if (linear)
+ return GIMP_PRECISION_DOUBLE_LINEAR;
+ else
+ return GIMP_PRECISION_DOUBLE_GAMMA;
+
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (-1);
+}
+
+gboolean
+gimp_babl_is_valid (GimpImageBaseType base_type,
+ GimpPrecision precision)
+{
+ switch (base_type)
+ {
+ case GIMP_RGB:
+ case GIMP_GRAY:
+ return TRUE;
+
+ case GIMP_INDEXED:
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_GAMMA:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+GimpComponentType
+gimp_babl_is_bounded (GimpPrecision precision)
+{
+ switch (gimp_babl_component_type (precision))
+ {
+ case GIMP_COMPONENT_TYPE_U8:
+ case GIMP_COMPONENT_TYPE_U16:
+ case GIMP_COMPONENT_TYPE_U32:
+ return TRUE;
+
+ case GIMP_COMPONENT_TYPE_HALF:
+ case GIMP_COMPONENT_TYPE_FLOAT:
+ case GIMP_COMPONENT_TYPE_DOUBLE:
+ return FALSE;
+ }
+
+ g_return_val_if_reached (FALSE);
+}
+
+const Babl *
+gimp_babl_format (GimpImageBaseType base_type,
+ GimpPrecision precision,
+ gboolean with_alpha)
+{
+ switch (base_type)
+ {
+ case GIMP_RGB:
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA u8");
+ else
+ return babl_format ("RGB u8");
+
+ case GIMP_PRECISION_U8_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A u8");
+ else
+ return babl_format ("R'G'B' u8");
+
+ case GIMP_PRECISION_U16_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA u16");
+ else
+ return babl_format ("RGB u16");
+
+ case GIMP_PRECISION_U16_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A u16");
+ else
+ return babl_format ("R'G'B' u16");
+
+ case GIMP_PRECISION_U32_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA u32");
+ else
+ return babl_format ("RGB u32");
+
+ case GIMP_PRECISION_U32_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A u32");
+ else
+ return babl_format ("R'G'B' u32");
+
+ case GIMP_PRECISION_HALF_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA half");
+ else
+ return babl_format ("RGB half");
+
+ case GIMP_PRECISION_HALF_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A half");
+ else
+ return babl_format ("R'G'B' half");
+
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA float");
+ else
+ return babl_format ("RGB float");
+
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A float");
+ else
+ return babl_format ("R'G'B' float");
+
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ if (with_alpha)
+ return babl_format ("RGBA double");
+ else
+ return babl_format ("RGB double");
+
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ if (with_alpha)
+ return babl_format ("R'G'B'A double");
+ else
+ return babl_format ("R'G'B' double");
+
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_GRAY:
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA u8");
+ else
+ return babl_format ("Y u8");
+
+ case GIMP_PRECISION_U8_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A u8");
+ else
+ return babl_format ("Y' u8");
+
+ case GIMP_PRECISION_U16_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA u16");
+ else
+ return babl_format ("Y u16");
+
+ case GIMP_PRECISION_U16_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A u16");
+ else
+ return babl_format ("Y' u16");
+
+ case GIMP_PRECISION_U32_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA u32");
+ else
+ return babl_format ("Y u32");
+
+ case GIMP_PRECISION_U32_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A u32");
+ else
+ return babl_format ("Y' u32");
+
+ case GIMP_PRECISION_HALF_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA half");
+ else
+ return babl_format ("Y half");
+
+ case GIMP_PRECISION_HALF_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A half");
+ else
+ return babl_format ("Y' half");
+
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA float");
+ else
+ return babl_format ("Y float");
+
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A float");
+ else
+ return babl_format ("Y' float");
+
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ if (with_alpha)
+ return babl_format ("YA double");
+ else
+ return babl_format ("Y double");
+
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ if (with_alpha)
+ return babl_format ("Y'A double");
+ else
+ return babl_format ("Y' double");
+
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_INDEXED:
+ /* need to use the image's api for this */
+ break;
+ }
+
+ g_return_val_if_reached (NULL);
+}
+
+const Babl *
+gimp_babl_mask_format (GimpPrecision precision)
+{
+ switch (gimp_babl_component_type (precision))
+ {
+ case GIMP_COMPONENT_TYPE_U8: return babl_format ("Y u8");
+ case GIMP_COMPONENT_TYPE_U16: return babl_format ("Y u16");
+ case GIMP_COMPONENT_TYPE_U32: return babl_format ("Y u32");
+ case GIMP_COMPONENT_TYPE_HALF: return babl_format ("Y half");
+ case GIMP_COMPONENT_TYPE_FLOAT: return babl_format ("Y float");
+ case GIMP_COMPONENT_TYPE_DOUBLE: return babl_format ("Y double");
+ }
+
+ g_return_val_if_reached (NULL);
+}
+
+const Babl *
+gimp_babl_component_format (GimpImageBaseType base_type,
+ GimpPrecision precision,
+ gint index)
+{
+ switch (base_type)
+ {
+ case GIMP_RGB:
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R u8");
+ case 1: return babl_format ("G u8");
+ case 2: return babl_format ("B u8");
+ case 3: return babl_format ("A u8");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U8_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' u8");
+ case 1: return babl_format ("G' u8");
+ case 2: return babl_format ("B' u8");
+ case 3: return babl_format ("A u8");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U16_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R u16");
+ case 1: return babl_format ("G u16");
+ case 2: return babl_format ("B u16");
+ case 3: return babl_format ("A u16");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U16_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' u16");
+ case 1: return babl_format ("G' u16");
+ case 2: return babl_format ("B' u16");
+ case 3: return babl_format ("A u16");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U32_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R u32");
+ case 1: return babl_format ("G u32");
+ case 2: return babl_format ("B u32");
+ case 3: return babl_format ("A u32");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U32_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' u32");
+ case 1: return babl_format ("G' u32");
+ case 2: return babl_format ("B' u32");
+ case 3: return babl_format ("A u32");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_HALF_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R half");
+ case 1: return babl_format ("G half");
+ case 2: return babl_format ("B half");
+ case 3: return babl_format ("A half");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_HALF_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' half");
+ case 1: return babl_format ("G' half");
+ case 2: return babl_format ("B' half");
+ case 3: return babl_format ("A half");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R float");
+ case 1: return babl_format ("G float");
+ case 2: return babl_format ("B float");
+ case 3: return babl_format ("A float");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' float");
+ case 1: return babl_format ("G' float");
+ case 2: return babl_format ("B' float");
+ case 3: return babl_format ("A float");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("R double");
+ case 1: return babl_format ("G double");
+ case 2: return babl_format ("B double");
+ case 3: return babl_format ("A double");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("R' double");
+ case 1: return babl_format ("G' double");
+ case 2: return babl_format ("B' double");
+ case 3: return babl_format ("A double");
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_GRAY:
+ switch (precision)
+ {
+ case GIMP_PRECISION_U8_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y u8");
+ case 1: return babl_format ("A u8");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U8_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' u8");
+ case 1: return babl_format ("A u8");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U16_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y u16");
+ case 1: return babl_format ("A u16");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U16_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' u16");
+ case 1: return babl_format ("A u16");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U32_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y u32");
+ case 1: return babl_format ("A u32");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_U32_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' u32");
+ case 1: return babl_format ("A u32");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_HALF_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y half");
+ case 1: return babl_format ("A half");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_HALF_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' half");
+ case 1: return babl_format ("A half");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_FLOAT_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y float");
+ case 1: return babl_format ("A float");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_FLOAT_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' float");
+ case 1: return babl_format ("A float");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_DOUBLE_LINEAR:
+ switch (index)
+ {
+ case 0: return babl_format ("Y double");
+ case 1: return babl_format ("A double");
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_PRECISION_DOUBLE_GAMMA:
+ switch (index)
+ {
+ case 0: return babl_format ("Y' double");
+ case 1: return babl_format ("A double");
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case GIMP_INDEXED:
+ /* need to use the image's api for this */
+ break;
+ }
+
+ g_return_val_if_reached (NULL);
+}
+
+const Babl *
+gimp_babl_format_change_component_type (const Babl *format,
+ GimpComponentType component)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return gimp_babl_format (gimp_babl_format_get_base_type (format),
+ gimp_babl_precision (
+ component,
+ gimp_babl_format_get_linear (format)),
+ babl_format_has_alpha (format));
+}
+
+const Babl *
+gimp_babl_format_change_linear (const Babl *format,
+ gboolean linear)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return gimp_babl_format (gimp_babl_format_get_base_type (format),
+ gimp_babl_precision (
+ gimp_babl_format_get_component_type (format),
+ linear),
+ babl_format_has_alpha (format));
+}
+
+gchar **
+gimp_babl_print_pixel (const Babl *format,
+ gpointer pixel)
+{
+ GimpPrecision precision;
+ gint n_components;
+ guchar tmp_pixel[32];
+ gchar **strings;
+
+ g_return_val_if_fail (format != NULL, NULL);
+ g_return_val_if_fail (pixel != NULL, NULL);
+
+ precision = gimp_babl_format_get_precision (format);
+
+ if (babl_format_is_palette (format))
+ {
+ const Babl *f = gimp_babl_format (GIMP_RGB, precision,
+ babl_format_has_alpha (format));
+
+ babl_process (babl_fish (format, f), pixel, tmp_pixel, 1);
+
+ format = f;
+ pixel = tmp_pixel;
+ }
+
+ n_components = babl_format_get_n_components (format);
+
+ strings = g_new0 (gchar *, n_components + 1);
+
+ switch (gimp_babl_format_get_component_type (format))
+ {
+ case GIMP_COMPONENT_TYPE_U8:
+ {
+ guchar *color = pixel;
+ gint i;
+
+ for (i = 0; i < n_components; i++)
+ strings[i] = g_strdup_printf ("%d", color[i]);
+ }
+ break;
+
+ case GIMP_COMPONENT_TYPE_U16:
+ {
+ guint16 *color = pixel;
+ gint i;
+
+ for (i = 0; i < n_components; i++)
+ strings[i] = g_strdup_printf ("%u", color[i]);
+ }
+ break;
+
+ case GIMP_COMPONENT_TYPE_U32:
+ {
+ guint32 *color = pixel;
+ gint i;
+
+ for (i = 0; i < n_components; i++)
+ strings[i] = g_strdup_printf ("%u", color[i]);
+ }
+ break;
+
+ case GIMP_COMPONENT_TYPE_HALF:
+ {
+ GimpPrecision p;
+ const Babl *f;
+
+ p = gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
+ gimp_babl_format_get_linear (format));
+
+ f = gimp_babl_format (gimp_babl_format_get_base_type (format),
+ p,
+ babl_format_has_alpha (format));
+
+ babl_process (babl_fish (format, f), pixel, tmp_pixel, 1);
+
+ pixel = tmp_pixel;
+ }
+ /* fall through */
+
+ case GIMP_COMPONENT_TYPE_FLOAT:
+ {
+ gfloat *color = pixel;
+ gint i;
+
+ for (i = 0; i < n_components; i++)
+ strings[i] = g_strdup_printf ("%0.6f", color[i]);
+ }
+ break;
+
+ case GIMP_COMPONENT_TYPE_DOUBLE:
+ {
+ gdouble *color = pixel;
+ gint i;
+
+ for (i = 0; i < n_components; i++)
+ strings[i] = g_strdup_printf ("%0.6f", color[i]);
+ }
+ break;
+ }
+
+ return strings;
+}
diff --git a/app/gegl/gimp-babl.h b/app/gegl/gimp-babl.h
new file mode 100644
index 0000000..3062e02
--- /dev/null
+++ b/app/gegl/gimp-babl.h
@@ -0,0 +1,62 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-babl.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_BABL_H__
+#define __GIMP_BABL_H__
+
+
+void gimp_babl_init (void);
+void gimp_babl_init_fishes (GimpInitStatusFunc status_callback);
+
+const gchar * gimp_babl_format_get_description (const Babl *format);
+GimpColorProfile * gimp_babl_format_get_color_profile (const Babl *format);
+
+GimpImageBaseType gimp_babl_format_get_base_type (const Babl *format);
+GimpComponentType gimp_babl_format_get_component_type (const Babl *format);
+GimpPrecision gimp_babl_format_get_precision (const Babl *format);
+gboolean gimp_babl_format_get_linear (const Babl *format);
+
+GimpComponentType gimp_babl_component_type (GimpPrecision precision);
+gboolean gimp_babl_linear (GimpPrecision precision);
+GimpPrecision gimp_babl_precision (GimpComponentType component,
+ gboolean linear);
+
+gboolean gimp_babl_is_valid (GimpImageBaseType base_type,
+ GimpPrecision precision);
+GimpComponentType gimp_babl_is_bounded (GimpPrecision precision);
+
+const Babl * gimp_babl_format (GimpImageBaseType base_type,
+ GimpPrecision precision,
+ gboolean with_alpha);
+const Babl * gimp_babl_mask_format (GimpPrecision precision);
+const Babl * gimp_babl_component_format (GimpImageBaseType base_type,
+ GimpPrecision precision,
+ gint index);
+
+const Babl * gimp_babl_format_change_component_type (const Babl *format,
+ GimpComponentType component);
+const Babl * gimp_babl_format_change_linear (const Babl *format,
+ gboolean linear);
+
+gchar ** gimp_babl_print_pixel (const Babl *format,
+ gpointer pixel);
+
+
+#endif /* __GIMP_BABL_H__ */
diff --git a/app/gegl/gimp-gegl-apply-operation.c b/app/gegl/gimp-gegl-apply-operation.c
new file mode 100644
index 0000000..d76b3b1
--- /dev/null
+++ b/app/gegl/gimp-gegl-apply-operation.c
@@ -0,0 +1,827 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-apply-operation.c
+ * Copyright (C) 2012 Øyvind Kolås <pippin@gimp.org>
+ * Sven Neumann <sven@gimp.org>
+ * Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "core/gimp-transform-utils.h"
+#include "core/gimp-utils.h"
+#include "core/gimpchunkiterator.h"
+#include "core/gimpprogress.h"
+
+#include "gimp-gegl-apply-operation.h"
+#include "gimp-gegl-loops.h"
+#include "gimp-gegl-nodes.h"
+#include "gimp-gegl-utils.h"
+
+
+/* iteration interval when applying an operation interactively
+ * (with progress indication)
+ */
+#define APPLY_OPERATION_INTERACTIVE_INTERVAL (1.0 / 8.0) /* seconds */
+
+/* iteration interval when applying an operation non-interactively
+ * (without progress indication)
+ */
+#define APPLY_OPERATION_NON_INTERACTIVE_INTERVAL 1.0 /* seconds */
+
+
+void
+gimp_gegl_apply_operation (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglNode *operation,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gboolean crop_input)
+{
+ gimp_gegl_apply_cached_operation (src_buffer,
+ progress, undo_desc,
+ operation,
+ src_buffer != NULL,
+ dest_buffer,
+ dest_rect,
+ crop_input,
+ NULL, NULL, 0,
+ FALSE);
+}
+
+static void
+gimp_gegl_apply_operation_cancel (GimpProgress *progress,
+ gboolean *cancel)
+{
+ *cancel = TRUE;
+}
+
+gboolean
+gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglNode *operation,
+ gboolean connect_src_buffer,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gboolean crop_input,
+ GeglBuffer *cache,
+ const GeglRectangle *valid_rects,
+ gint n_valid_rects,
+ gboolean cancelable)
+{
+ GeglNode *gegl;
+ GeglNode *effect;
+ GeglNode *dest_node;
+ GeglNode *underlying_operation;
+ GeglNode *operation_src_node = NULL;
+ GeglBuffer *result_buffer;
+ GimpChunkIterator *iter;
+ cairo_region_t *region;
+ gboolean progress_started = FALSE;
+ gboolean cancel = FALSE;
+ gint64 all_pixels;
+ gint64 done_pixels;
+
+ g_return_val_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer), FALSE);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
+ g_return_val_if_fail (GEGL_IS_NODE (operation), FALSE);
+ g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), FALSE);
+ g_return_val_if_fail (cache == NULL || GEGL_IS_BUFFER (cache), FALSE);
+ g_return_val_if_fail (valid_rects == NULL || cache != NULL, FALSE);
+ g_return_val_if_fail (valid_rects == NULL || n_valid_rects != 0, FALSE);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ if (progress)
+ {
+ if (gimp_progress_is_active (progress))
+ {
+ if (undo_desc)
+ gimp_progress_set_text_literal (progress, undo_desc);
+
+ progress_started = FALSE;
+ cancelable = FALSE;
+ }
+ else
+ {
+ gimp_progress_start (progress, cancelable, "%s", undo_desc);
+
+ if (cancelable)
+ g_signal_connect (progress, "cancel",
+ G_CALLBACK (gimp_gegl_apply_operation_cancel),
+ &cancel);
+
+ progress_started = TRUE;
+ }
+ }
+ else
+ {
+ cancelable = FALSE;
+ }
+
+ gegl_buffer_freeze_changed (dest_buffer);
+
+ underlying_operation = gimp_gegl_node_get_underlying_operation (operation);
+
+ result_buffer = dest_buffer;
+
+ if (result_buffer == src_buffer &&
+ ! (gimp_gegl_node_is_point_operation (underlying_operation) ||
+ gimp_gegl_node_is_source_operation (underlying_operation)))
+ {
+ /* Write the result to a temporary buffer, instead of directly to
+ * dest_buffer, since reading and writing the same buffer doesn't
+ * generally work with non-point ops when working in chunks.
+ *
+ * See bug #701875.
+ */
+
+ if (cache)
+ {
+ /* If we have a cache, use it directly as the temporary result
+ * buffer, and skip copying the cached results to result_buffer
+ * below. Instead, the cached results are copied together with the
+ * newly rendered results in a single step at the end of processing.
+ */
+
+ g_warn_if_fail (cache != dest_buffer);
+
+ result_buffer = g_object_ref (cache);
+
+ cache = NULL;
+ }
+ else
+ {
+ result_buffer = gegl_buffer_new (
+ dest_rect, gegl_buffer_get_format (dest_buffer));
+ }
+ }
+
+ all_pixels = (gint64) dest_rect->width * (gint64) dest_rect->height;
+ done_pixels = 0;
+
+ region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) dest_rect);
+
+ if (n_valid_rects > 0)
+ {
+ gint i;
+
+ for (i = 0; i < n_valid_rects; i++)
+ {
+ GeglRectangle valid_rect;
+
+ if (! gegl_rectangle_intersect (&valid_rect,
+ &valid_rects[i], dest_rect))
+ {
+ continue;
+ }
+
+ if (cache)
+ {
+ gimp_gegl_buffer_copy (
+ cache, &valid_rect, GEGL_ABYSS_NONE,
+ result_buffer, &valid_rect);
+ }
+
+ cairo_region_subtract_rectangle (region,
+ (cairo_rectangle_int_t *)
+ &valid_rect);
+
+ done_pixels += (gint64) valid_rect.width * (gint64) valid_rect.height;
+
+ if (progress)
+ {
+ gimp_progress_set_value (progress,
+ (gdouble) done_pixels /
+ (gdouble) all_pixels);
+ }
+ }
+ }
+
+ gegl = gegl_node_new ();
+
+ if (! gegl_node_get_parent (operation))
+ gegl_node_add_child (gegl, operation);
+
+ effect = operation;
+
+ if (connect_src_buffer || crop_input)
+ {
+ GeglNode *src_node;
+
+ operation_src_node = gegl_node_get_producer (operation, "input", NULL);
+
+ src_node = operation_src_node;
+
+ if (connect_src_buffer)
+ {
+ src_node = gegl_node_new_child (gegl,
+ "operation", "gegl:buffer-source",
+ "buffer", src_buffer,
+ NULL);
+ }
+
+ if (crop_input)
+ {
+ GeglNode *crop_node;
+
+ crop_node = gegl_node_new_child (gegl,
+ "operation", "gegl:crop",
+ "x", (gdouble) dest_rect->x,
+ "y", (gdouble) dest_rect->y,
+ "width", (gdouble) dest_rect->width,
+ "height", (gdouble) dest_rect->height,
+ NULL);
+
+ gegl_node_connect_to (src_node, "output",
+ crop_node, "input");
+
+ src_node = crop_node;
+ }
+
+ if (! gegl_node_has_pad (operation, "input"))
+ {
+ effect = gegl_node_new_child (gegl,
+ "operation", "gimp:normal",
+ NULL);
+
+ gegl_node_connect_to (operation, "output",
+ effect, "aux");
+ }
+
+ gegl_node_connect_to (src_node, "output",
+ effect, "input");
+ }
+
+ dest_node = gegl_node_new_child (gegl,
+ "operation", "gegl:write-buffer",
+ "buffer", result_buffer,
+ NULL);
+
+ gegl_node_connect_to (effect, "output",
+ dest_node, "input");
+
+ iter = gimp_chunk_iterator_new (region);
+
+ if (progress &&
+ /* avoid the interactive iteration interval for area filters (or meta ops
+ * that potentially involve area filters), since their processing speed
+ * tends to be sensitive to the chunk size.
+ */
+ ! gimp_gegl_node_is_area_filter_operation (underlying_operation))
+ {
+ /* we use a shorter iteration interval for interactive use (when there's
+ * progress indication), to stay responsive.
+ */
+ gimp_chunk_iterator_set_interval (
+ iter,
+ APPLY_OPERATION_INTERACTIVE_INTERVAL);
+ }
+ else
+ {
+ /* we use a longer iteration interval for non-interactive use (when
+ * there's no progress indication), or when applying an area filter (see
+ * above), as this generally allows for faster processing. we don't
+ * avoid chunking altogether, since *some* chunking is still desirable to
+ * reduce the space needed for intermediate results.
+ */
+ gimp_chunk_iterator_set_interval (
+ iter,
+ APPLY_OPERATION_NON_INTERACTIVE_INTERVAL);
+ }
+
+ while (gimp_chunk_iterator_next (iter))
+ {
+ GeglRectangle render_rect;
+
+ if (cancelable)
+ {
+ while (! cancel && g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+
+ if (cancel)
+ break;
+ }
+
+ while (gimp_chunk_iterator_get_rect (iter, &render_rect))
+ {
+ gegl_node_blit (dest_node, 1.0, &render_rect, NULL, NULL, 0,
+ GEGL_BLIT_DEFAULT);
+
+ done_pixels += (gint64) render_rect.width *
+ (gint64) render_rect.height;
+ }
+
+ if (progress)
+ {
+ gimp_progress_set_value (progress,
+ (gdouble) done_pixels /
+ (gdouble) all_pixels);
+ }
+ }
+
+ if (result_buffer != dest_buffer)
+ {
+ if (! cancel)
+ gimp_gegl_buffer_copy (result_buffer, dest_rect, GEGL_ABYSS_NONE,
+ dest_buffer, dest_rect);
+
+ g_object_unref (result_buffer);
+ }
+
+ gegl_buffer_thaw_changed (dest_buffer);
+
+ g_object_unref (gegl);
+
+ if (operation_src_node)
+ {
+ gegl_node_connect_to (operation_src_node, "output",
+ operation, "input");
+ }
+
+ if (progress_started)
+ {
+ gimp_progress_end (progress);
+
+ if (cancelable)
+ g_signal_handlers_disconnect_by_func (progress,
+ gimp_gegl_apply_operation_cancel,
+ &cancel);
+ }
+
+ return ! cancel;
+}
+
+void
+gimp_gegl_apply_dither (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gint levels,
+ gint dither_type)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ levels = CLAMP (levels, 2, 65536);
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:dither",
+ "red-levels", levels,
+ "green-levels", levels,
+ "blue-levels", levels,
+ "alpha-bits", levels,
+ "dither-method", dither_type,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_flatten (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GimpRGB *background,
+ GimpLayerColorSpace composite_space)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+ g_return_if_fail (background != NULL);
+
+ node = gimp_gegl_create_flatten_node (background, composite_space);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_feather (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble radius_x,
+ gdouble radius_y,
+ gboolean edge_lock)
+{
+ GaussianBlurAbyssPolicy abyss_policy;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ if (edge_lock)
+ abyss_policy = GAUSSIAN_BLUR_ABYSS_CLAMP;
+ else
+ abyss_policy = GAUSSIAN_BLUR_ABYSS_NONE;
+
+ /* 3.5 is completely magic and picked to visually match the old
+ * gaussian_blur_region() on a crappy laptop display
+ */
+ gimp_gegl_apply_gaussian_blur (src_buffer,
+ progress, undo_desc,
+ dest_buffer, dest_rect,
+ radius_x / 3.5,
+ radius_y / 3.5,
+ abyss_policy);
+}
+
+void
+gimp_gegl_apply_border (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y,
+ GimpChannelBorderStyle style,
+ gboolean edge_lock)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ switch (style)
+ {
+ case GIMP_CHANNEL_BORDER_STYLE_HARD:
+ case GIMP_CHANNEL_BORDER_STYLE_FEATHERED:
+ {
+ gboolean feather = style == GIMP_CHANNEL_BORDER_STYLE_FEATHERED;
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gimp:border",
+ "radius-x", radius_x,
+ "radius-y", radius_y,
+ "feather", feather,
+ "edge-lock", edge_lock,
+ NULL);
+ }
+ break;
+
+ case GIMP_CHANNEL_BORDER_STYLE_SMOOTH:
+ {
+ GeglNode *input, *output;
+ GeglNode *grow, *shrink, *subtract;
+
+ node = gegl_node_new ();
+
+ input = gegl_node_get_input_proxy (node, "input");
+ output = gegl_node_get_output_proxy (node, "output");
+
+ /* Duplicate special-case behavior of "gimp:border". */
+ if (radius_x == 1 && radius_y == 1)
+ {
+ grow = gegl_node_new_child (node,
+ "operation", "gegl:nop",
+ NULL);
+ shrink = gegl_node_new_child (node,
+ "operation", "gimp:shrink",
+ "radius-x", 1,
+ "radius-y", 1,
+ "edge-lock", edge_lock,
+ NULL);
+ }
+ else
+ {
+ grow = gegl_node_new_child (node,
+ "operation", "gimp:grow",
+ "radius-x", radius_x,
+ "radius-y", radius_y,
+ NULL);
+ shrink = gegl_node_new_child (node,
+ "operation", "gimp:shrink",
+ "radius-x", radius_x + 1,
+ "radius-y", radius_y + 1,
+ "edge-lock", edge_lock,
+ NULL);
+ }
+
+ subtract = gegl_node_new_child (node,
+ "operation", "gegl:subtract",
+ NULL);
+
+ gegl_node_link_many (input, grow, subtract, output, NULL);
+ gegl_node_link (input, shrink);
+ gegl_node_connect_to (shrink, "output", subtract, "aux");
+ }
+ break;
+
+ default:
+ gimp_assert_not_reached ();
+ }
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, dest_rect, TRUE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_grow (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gimp:grow",
+ "radius-x", radius_x,
+ "radius-y", radius_y,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, dest_rect, TRUE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_shrink (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y,
+ gboolean edge_lock)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gimp:shrink",
+ "radius-x", radius_x,
+ "radius-y", radius_y,
+ "edge-lock", edge_lock,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, dest_rect, TRUE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_flood (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gimp:flood",
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, dest_rect, TRUE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_gaussian_blur (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble std_dev_x,
+ gdouble std_dev_y,
+ GaussianBlurAbyssPolicy abyss_policy)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:gaussian-blur",
+ "std-dev-x", std_dev_x,
+ "std-dev-y", std_dev_y,
+ "abyss-policy", abyss_policy,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, dest_rect, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_invert_gamma (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:invert-gamma",
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_invert_linear (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:invert-linear",
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_opacity (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GeglBuffer *mask,
+ gint mask_offset_x,
+ gint mask_offset_y,
+ gdouble opacity)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+ g_return_if_fail (mask == NULL || GEGL_IS_BUFFER (mask));
+
+ node = gimp_gegl_create_apply_opacity_node (mask,
+ mask_offset_x,
+ mask_offset_y,
+ opacity);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_scale (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GimpInterpolationType interpolation_type,
+ gdouble x,
+ gdouble y)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:scale-ratio",
+ "origin-x", 0.0,
+ "origin-y", 0.0,
+ "sampler", interpolation_type,
+ "abyss-policy", GEGL_ABYSS_CLAMP,
+ "x", x,
+ "y", y,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_set_alpha (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gdouble value)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gimp:set-alpha",
+ "value", value,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_threshold (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gdouble value)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:threshold",
+ "value", value,
+ NULL);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
+
+void
+gimp_gegl_apply_transform (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GimpInterpolationType interpolation_type,
+ GimpMatrix3 *transform)
+{
+ GeglNode *node;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:transform",
+ "near-z", GIMP_TRANSFORM_NEAR_Z,
+ "sampler", interpolation_type,
+ NULL);
+
+ gimp_gegl_node_set_matrix (node, transform);
+
+ gimp_gegl_apply_operation (src_buffer, progress, undo_desc,
+ node, dest_buffer, NULL, FALSE);
+ g_object_unref (node);
+}
diff --git a/app/gegl/gimp-gegl-apply-operation.h b/app/gegl/gimp-gegl-apply-operation.h
new file mode 100644
index 0000000..3b19ee0
--- /dev/null
+++ b/app/gegl/gimp-gegl-apply-operation.h
@@ -0,0 +1,172 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-apply-operation.h
+ * Copyright (C) 2012 Øyvind Kolås <pippin@gimp.org>
+ * Sven Neumann <sven@gimp.org>
+ * Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_APPLY_OPERATION_H__
+#define __GIMP_GEGL_APPLY_OPERATION_H__
+
+
+/* generic functions, also used by the specific ones below */
+
+void gimp_gegl_apply_operation (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglNode *operation,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gboolean crop_input);
+
+gboolean gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglNode *operation,
+ gboolean connect_src_buffer,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gboolean crop_input,
+ GeglBuffer *cache,
+ const GeglRectangle *valid_rects,
+ gint n_valid_rects,
+ gboolean cancellable);
+
+
+/* apply specific operations */
+
+void gimp_gegl_apply_dither (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gint levels,
+ gint dither_type);
+
+void gimp_gegl_apply_flatten (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GimpRGB *background,
+ GimpLayerColorSpace composite_space);
+
+void gimp_gegl_apply_feather (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble radius_x,
+ gdouble radius_y,
+ gboolean edge_lock);
+
+void gimp_gegl_apply_border (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y,
+ GimpChannelBorderStyle style,
+ gboolean edge_lock);
+
+void gimp_gegl_apply_grow (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y);
+
+void gimp_gegl_apply_shrink (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gint radius_x,
+ gint radius_y,
+ gboolean edge_lock);
+
+void gimp_gegl_apply_flood (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect);
+
+/* UGLY: private enum of gegl:gaussian-blur */
+typedef enum
+{
+ GAUSSIAN_BLUR_ABYSS_NONE,
+ GAUSSIAN_BLUR_ABYSS_CLAMP
+} GaussianBlurAbyssPolicy;
+
+void gimp_gegl_apply_gaussian_blur (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble std_dev_x,
+ gdouble std_dev_y,
+ GaussianBlurAbyssPolicy abyss_policy);
+
+void gimp_gegl_apply_invert_gamma (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer);
+
+void gimp_gegl_apply_invert_linear (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer);
+
+void gimp_gegl_apply_opacity (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GeglBuffer *mask,
+ gint mask_offset_x,
+ gint mask_offset_y,
+ gdouble opacity);
+
+void gimp_gegl_apply_scale (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GimpInterpolationType interpolation_type,
+ gdouble x,
+ gdouble y);
+
+void gimp_gegl_apply_set_alpha (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gdouble value);
+
+void gimp_gegl_apply_threshold (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ gdouble value);
+
+void gimp_gegl_apply_transform (GeglBuffer *src_buffer,
+ GimpProgress *progress,
+ const gchar *undo_desc,
+ GeglBuffer *dest_buffer,
+ GimpInterpolationType interpolation_type,
+ GimpMatrix3 *transform);
+
+
+#endif /* __GIMP_GEGL_APPLY_OPERATION_H__ */
diff --git a/app/gegl/gimp-gegl-enums.c b/app/gegl/gimp-gegl-enums.c
new file mode 100644
index 0000000..de9c7b5
--- /dev/null
+++ b/app/gegl/gimp-gegl-enums.c
@@ -0,0 +1,43 @@
+
+/* Generated data (by gimp-mkenums) */
+
+#include "config.h"
+#include <gio/gio.h>
+#include "libgimpbase/gimpbase.h"
+#include "core/core-enums.h"
+#include "gimp-gegl-enums.h"
+#include "gimp-intl.h"
+
+/* enumerations from "gimp-gegl-enums.h" */
+GType
+gimp_cage_mode_get_type (void)
+{
+ static const GEnumValue values[] =
+ {
+ { GIMP_CAGE_MODE_CAGE_CHANGE, "GIMP_CAGE_MODE_CAGE_CHANGE", "cage-change" },
+ { GIMP_CAGE_MODE_DEFORM, "GIMP_CAGE_MODE_DEFORM", "deform" },
+ { 0, NULL, NULL }
+ };
+
+ static const GimpEnumDesc descs[] =
+ {
+ { GIMP_CAGE_MODE_CAGE_CHANGE, NC_("cage-mode", "Create or adjust the cage"), NULL },
+ { GIMP_CAGE_MODE_DEFORM, NC_("cage-mode", "Deform the cage\nto deform the image"), NULL },
+ { 0, NULL, NULL }
+ };
+
+ static GType type = 0;
+
+ if (G_UNLIKELY (! type))
+ {
+ type = g_enum_register_static ("GimpCageMode", values);
+ gimp_type_set_translation_context (type, "cage-mode");
+ gimp_enum_set_value_descriptions (type, descs);
+ }
+
+ return type;
+}
+
+
+/* Generated data ends here */
+
diff --git a/app/gegl/gimp-gegl-enums.h b/app/gegl/gimp-gegl-enums.h
new file mode 100644
index 0000000..022c93a
--- /dev/null
+++ b/app/gegl/gimp-gegl-enums.h
@@ -0,0 +1,35 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-enums.h
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_ENUMS_H__
+#define __GIMP_GEGL_ENUMS_H__
+
+
+#define GIMP_TYPE_CAGE_MODE (gimp_cage_mode_get_type ())
+
+GType gimp_cage_mode_get_type (void) G_GNUC_CONST;
+
+typedef enum
+{
+ GIMP_CAGE_MODE_CAGE_CHANGE, /*< desc="Create or adjust the cage" >*/
+ GIMP_CAGE_MODE_DEFORM /*< desc="Deform the cage\nto deform the image" >*/
+} GimpCageMode;
+
+
+#endif /* __GIMP_GEGL_ENUMS_H__ */
diff --git a/app/gegl/gimp-gegl-loops-sse2.c b/app/gegl/gimp-gegl-loops-sse2.c
new file mode 100644
index 0000000..b9bf3ae
--- /dev/null
+++ b/app/gegl/gimp-gegl-loops-sse2.c
@@ -0,0 +1,127 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-loops-sse2.c
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-gegl-loops-sse2.h"
+
+
+#if COMPILE_SSE2_INTRINISICS
+
+#include <emmintrin.h>
+
+
+/* helper function of gimp_gegl_smudge_with_paint_process_sse2()
+ * src and dest can be the same address
+ */
+static inline void
+gimp_gegl_smudge_with_paint_blend_sse2 (const gfloat *src1,
+ gfloat src1_rate,
+ const gfloat *src2,
+ gfloat src2_rate,
+ gfloat *dest,
+ gboolean no_erasing_src2)
+{
+ /* 2017/4/13 shark0r : According to my test, SSE decreases about 25%
+ * execution time
+ */
+
+ __m128 v_src1 = _mm_loadu_ps (src1);
+ __m128 v_src2 = _mm_loadu_ps (src2);
+ __m128 *v_dest = (__v4sf *) dest;
+
+ gfloat orginal_src2_alpha;
+ gfloat src1_alpha;
+ gfloat src2_alpha;
+ gfloat result_alpha;
+
+ orginal_src2_alpha = v_src2[3];
+ src1_alpha = src1_rate * v_src1[3];
+ src2_alpha = src2_rate * orginal_src2_alpha;
+ result_alpha = src1_alpha + src2_alpha;
+
+ if (result_alpha == 0)
+ {
+ *v_dest = _mm_set1_ps (0);
+ return;
+ }
+
+ *v_dest = (v_src1 * _mm_set1_ps (src1_alpha) +
+ v_src2 * _mm_set1_ps (src2_alpha)) /
+ _mm_set1_ps (result_alpha);
+
+ if (no_erasing_src2)
+ {
+ result_alpha = MAX (result_alpha, orginal_src2_alpha);
+ }
+
+ dest[3] = result_alpha;
+}
+
+/* helper function of gimp_gegl_smudge_with_paint()
+ *
+ * note that it's the caller's responsibility to verify that the buffers are
+ * properly aligned
+ */
+void
+gimp_gegl_smudge_with_paint_process_sse2 (gfloat *accum,
+ const gfloat *canvas,
+ gfloat *paint,
+ gint count,
+ const gfloat *brush_color,
+ gfloat brush_a,
+ gboolean no_erasing,
+ gfloat flow,
+ gfloat rate)
+{
+ while (count--)
+ {
+ /* blend accum_buffer and canvas_buffer to accum_buffer */
+ gimp_gegl_smudge_with_paint_blend_sse2 (accum, rate, canvas, 1 - rate,
+ accum, no_erasing);
+
+ /* blend accum_buffer and brush color/pixmap to paint_buffer */
+ if (brush_a == 0) /* pure smudge */
+ {
+ memcpy (paint, accum, sizeof (gfloat) * 4);
+ }
+ else
+ {
+ const gfloat *src1 = brush_color ? brush_color : paint;
+
+ gimp_gegl_smudge_with_paint_blend_sse2 (src1, flow, accum, 1 - flow,
+ paint, no_erasing);
+ }
+
+ accum += 4;
+ canvas += 4;
+ paint += 4;
+ }
+}
+
+#endif /* COMPILE_SSE2_INTRINISICS */
diff --git a/app/gegl/gimp-gegl-loops-sse2.h b/app/gegl/gimp-gegl-loops-sse2.h
new file mode 100644
index 0000000..fc8100c
--- /dev/null
+++ b/app/gegl/gimp-gegl-loops-sse2.h
@@ -0,0 +1,40 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-loops-sse2.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_LOOPS_SSE2_H__
+#define __GIMP_GEGL_LOOPS_SSE2_H__
+
+
+#if COMPILE_SSE2_INTRINISICS
+
+void gimp_gegl_smudge_with_paint_process_sse2 (gfloat *accum,
+ const gfloat *canvas,
+ gfloat *paint,
+ gint count,
+ const gfloat *brush_color,
+ gfloat brush_a,
+ gboolean no_erasing,
+ gfloat flow,
+ gfloat rate);
+
+#endif /* COMPILE_SSE2_INTRINISICS */
+
+
+#endif /* __GIMP_GEGL_LOOPS_SSE2_H__ */
diff --git a/app/gegl/gimp-gegl-loops.cc b/app/gegl/gimp-gegl-loops.cc
new file mode 100644
index 0000000..4564bcd
--- /dev/null
+++ b/app/gegl/gimp-gegl-loops.cc
@@ -0,0 +1,1089 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-loops.c
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+#include <gegl-buffer-backend.h>
+
+extern "C"
+{
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-babl.h"
+#include "gimp-gegl-loops.h"
+#include "gimp-gegl-loops-sse2.h"
+
+#include "core/gimp-atomic.h"
+#include "core/gimp-utils.h"
+#include "core/gimpprogress.h"
+
+
+#define PIXELS_PER_THREAD \
+ (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
+
+#define SHIFTED_AREA(dest, src) \
+ const GeglRectangle dest##_area_ = { \
+ src##_area->x + (dest##_rect->x - src##_rect->x), \
+ src##_area->y + (dest##_rect->y - src##_rect->y), \
+ src##_area->width, src##_area->height \
+ }; \
+ const GeglRectangle * const dest##_area = &dest##_area_
+
+
+void
+gimp_gegl_buffer_copy (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglAbyssPolicy abyss_policy,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect)
+{
+ GeglRectangle real_dest_rect;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ if (! src_rect)
+ src_rect = gegl_buffer_get_extent (src_buffer);
+
+ if (! dest_rect)
+ dest_rect = src_rect;
+
+ real_dest_rect = *dest_rect;
+ real_dest_rect.width = src_rect->width;
+ real_dest_rect.height = src_rect->height;
+
+ dest_rect = &real_dest_rect;
+
+ if (gegl_buffer_get_format (src_buffer) ==
+ gegl_buffer_get_format (dest_buffer))
+ {
+ gboolean skip_abyss = FALSE;
+ GeglRectangle src_abyss;
+ GeglRectangle dest_abyss;
+
+ if (abyss_policy == GEGL_ABYSS_NONE)
+ {
+ src_abyss = *gegl_buffer_get_abyss (src_buffer);
+ dest_abyss = *gegl_buffer_get_abyss (dest_buffer);
+
+ skip_abyss = ! (gegl_rectangle_contains (&src_abyss, src_rect) &&
+ gegl_rectangle_contains (&dest_abyss, dest_rect));
+ }
+
+ if (skip_abyss)
+ {
+ if (src_buffer < dest_buffer)
+ {
+ gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer));
+ gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer));
+ }
+ else
+ {
+ gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer));
+ gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer));
+ }
+
+ gegl_buffer_set_abyss (src_buffer, src_rect);
+ gegl_buffer_set_abyss (dest_buffer, dest_rect);
+ }
+
+ gegl_buffer_copy (src_buffer, src_rect, abyss_policy,
+ dest_buffer, dest_rect);
+
+ if (skip_abyss)
+ {
+ gegl_buffer_set_abyss (src_buffer, &src_abyss);
+ gegl_buffer_set_abyss (dest_buffer, &dest_abyss);
+
+ gegl_tile_handler_unlock (GEGL_TILE_HANDLER (src_buffer));
+ gegl_tile_handler_unlock (GEGL_TILE_HANDLER (dest_buffer));
+ }
+ }
+ else
+ {
+ gegl_parallel_distribute_area (
+ src_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *src_area)
+ {
+ SHIFTED_AREA (dest, src);
+
+ gegl_buffer_copy (src_buffer, src_area, abyss_policy,
+ dest_buffer, dest_area);
+ });
+ }
+}
+
+void
+gimp_gegl_clear (GeglBuffer *buffer,
+ const GeglRectangle *rect)
+{
+ const Babl *format;
+ gint bpp;
+ gint n_components;
+ gint bpc;
+ gint alpha_offset;
+
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+
+ if (! rect)
+ rect = gegl_buffer_get_extent (buffer);
+
+ format = gegl_buffer_get_format (buffer);
+
+ if (! babl_format_has_alpha (format))
+ return;
+
+ bpp = babl_format_get_bytes_per_pixel (format);
+ n_components = babl_format_get_n_components (format);
+ bpc = bpp / n_components;
+ alpha_offset = (n_components - 1) * bpc;
+
+ gegl_parallel_distribute_area (
+ rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *area)
+ {
+ GeglBufferIterator *iter;
+
+ iter = gegl_buffer_iterator_new (buffer, area, 0, format,
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE,
+ 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ guint8 *data = (guint8 *) iter->items[0].data;
+ gint i;
+
+ data += alpha_offset;
+
+ for (i = 0; i < iter->length; i++)
+ {
+ memset (data, 0, bpc);
+
+ data += bpp;
+ }
+ }
+ });
+}
+
+void
+gimp_gegl_convolve (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ const gfloat *kernel,
+ gint kernel_size,
+ gdouble divisor,
+ GimpConvolutionType mode,
+ gboolean alpha_weighting)
+{
+ gfloat *src;
+ gint src_rowstride;
+
+ const Babl *src_format;
+ const Babl *dest_format;
+ gint src_components;
+ gint dest_components;
+ gfloat offset;
+
+ if (! src_rect)
+ src_rect = gegl_buffer_get_extent (src_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ src_format = gegl_buffer_get_format (src_buffer);
+
+ if (babl_format_is_palette (src_format))
+ src_format = gimp_babl_format (GIMP_RGB,
+ GIMP_PRECISION_FLOAT_LINEAR,
+ babl_format_has_alpha (src_format));
+ else
+ src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format),
+ GIMP_PRECISION_FLOAT_LINEAR,
+ babl_format_has_alpha (src_format));
+
+ dest_format = gegl_buffer_get_format (dest_buffer);
+
+ if (babl_format_is_palette (dest_format))
+ dest_format = gimp_babl_format (GIMP_RGB,
+ GIMP_PRECISION_FLOAT_LINEAR,
+ babl_format_has_alpha (dest_format));
+ else
+ dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format),
+ GIMP_PRECISION_FLOAT_LINEAR,
+ babl_format_has_alpha (dest_format));
+
+ src_components = babl_format_get_n_components (src_format);
+ dest_components = babl_format_get_n_components (dest_format);
+
+ /* Get source pixel data */
+ src_rowstride = src_components * src_rect->width;
+ src = g_new (gfloat, src_rowstride * src_rect->height);
+ gegl_buffer_get (src_buffer, src_rect, 1.0, src_format, src,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ /* If the mode is NEGATIVE_CONVOL, the offset should be 0.5 */
+ if (mode == GIMP_NEGATIVE_CONVOL)
+ {
+ offset = 0.5;
+ mode = GIMP_NORMAL_CONVOL;
+ }
+ else
+ {
+ offset = 0.0;
+ }
+
+ gegl_parallel_distribute_area (
+ dest_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *dest_area)
+ {
+ const gint components = src_components;
+ const gint a_component = components - 1;
+ const gint margin = kernel_size / 2;
+ GeglBufferIterator *dest_iter;
+
+ /* Set up dest iterator */
+ dest_iter = gegl_buffer_iterator_new (dest_buffer, dest_area, 0, dest_format,
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
+
+ while (gegl_buffer_iterator_next (dest_iter))
+ {
+ /* Convolve the src image using the convolution kernel, writing
+ * to dest Convolve is not tile-enabled--use accordingly
+ */
+ gfloat *dest = (gfloat *) dest_iter->items[0].data;
+ const gint x1 = 0;
+ const gint y1 = 0;
+ const gint x2 = src_rect->width - 1;
+ const gint y2 = src_rect->height - 1;
+ const gint dest_x1 = dest_iter->items[0].roi.x;
+ const gint dest_y1 = dest_iter->items[0].roi.y;
+ const gint dest_x2 = dest_iter->items[0].roi.x + dest_iter->items[0].roi.width;
+ const gint dest_y2 = dest_iter->items[0].roi.y + dest_iter->items[0].roi.height;
+ gint x, y;
+
+ for (y = dest_y1; y < dest_y2; y++)
+ {
+ gfloat *d = dest;
+
+ if (alpha_weighting)
+ {
+ for (x = dest_x1; x < dest_x2; x++)
+ {
+ const gfloat *m = kernel;
+ gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 };
+ gdouble weighted_divisor = 0.0;
+ gint i, j, b;
+
+ for (j = y - margin; j <= y + margin; j++)
+ {
+ for (i = x - margin; i <= x + margin; i++, m++)
+ {
+ gint xx = CLAMP (i, x1, x2);
+ gint yy = CLAMP (j, y1, y2);
+ const gfloat *s = src + yy * src_rowstride + xx * components;
+ const gfloat a = s[a_component];
+
+ if (a)
+ {
+ gdouble mult_alpha = *m * a;
+
+ weighted_divisor += mult_alpha;
+
+ for (b = 0; b < a_component; b++)
+ total[b] += mult_alpha * s[b];
+
+ total[a_component] += mult_alpha;
+ }
+ }
+ }
+
+ if (weighted_divisor == 0.0)
+ weighted_divisor = divisor;
+
+ for (b = 0; b < a_component; b++)
+ total[b] /= weighted_divisor;
+
+ total[a_component] /= divisor;
+
+ for (b = 0; b < components; b++)
+ {
+ total[b] += offset;
+
+ if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
+ total[b] = - total[b];
+
+ *d++ = CLAMP (total[b], 0.0, 1.0);
+ }
+ }
+ }
+ else
+ {
+ for (x = dest_x1; x < dest_x2; x++)
+ {
+ const gfloat *m = kernel;
+ gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 };
+ gint i, j, b;
+
+ for (j = y - margin; j <= y + margin; j++)
+ {
+ for (i = x - margin; i <= x + margin; i++, m++)
+ {
+ gint xx = CLAMP (i, x1, x2);
+ gint yy = CLAMP (j, y1, y2);
+ const gfloat *s = src + yy * src_rowstride + xx * components;
+
+ for (b = 0; b < components; b++)
+ total[b] += *m * s[b];
+ }
+ }
+
+ for (b = 0; b < components; b++)
+ {
+ total[b] = total[b] / divisor + offset;
+
+ if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
+ total[b] = - total[b];
+
+ *d++ = CLAMP (total[b], 0.0, 1.0);
+ }
+ }
+ }
+
+ dest += dest_iter->items[0].roi.width * dest_components;
+ }
+ }
+ });
+
+ g_free (src);
+}
+
+static inline gfloat
+odd_powf (gfloat x,
+ gfloat y)
+{
+ if (x >= 0.0f)
+ return powf ( x, y);
+ else
+ return -powf (-x, y);
+}
+
+void
+gimp_gegl_dodgeburn (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble exposure,
+ GimpDodgeBurnType type,
+ GimpTransferMode mode)
+{
+ if (type == GIMP_DODGE_BURN_TYPE_BURN)
+ exposure = -exposure;
+
+ if (! src_rect)
+ src_rect = gegl_buffer_get_extent (src_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ gegl_parallel_distribute_area (
+ src_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *src_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (dest, src);
+
+ iter = gegl_buffer_iterator_new (src_buffer, src_area, 0,
+ babl_format ("R'G'B'A float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
+ babl_format ("R'G'B'A float"),
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
+
+ switch (mode)
+ {
+ gfloat factor;
+
+ case GIMP_TRANSFER_HIGHLIGHTS:
+ factor = 1.0 + exposure * (0.333333);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *src = (gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ *dest++ = *src++ * factor;
+ *dest++ = *src++ * factor;
+ *dest++ = *src++ * factor;
+
+ *dest++ = *src++;
+ }
+ }
+ break;
+
+ case GIMP_TRANSFER_MIDTONES:
+ if (exposure < 0)
+ factor = 1.0 - exposure * (0.333333);
+ else
+ factor = 1.0 / (1.0 + exposure);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *src = (gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ *dest++ = odd_powf (*src++, factor);
+ *dest++ = odd_powf (*src++, factor);
+ *dest++ = odd_powf (*src++, factor);
+
+ *dest++ = *src++;
+ }
+ }
+ break;
+
+ case GIMP_TRANSFER_SHADOWS:
+ if (exposure >= 0)
+ factor = 0.333333 * exposure;
+ else
+ factor = -0.333333 * exposure;
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *src = (gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ if (exposure >= 0)
+ {
+ gfloat s;
+
+ s = *src++; *dest++ = factor + s - factor * s;
+ s = *src++; *dest++ = factor + s - factor * s;
+ s = *src++; *dest++ = factor + s - factor * s;
+ }
+ else
+ {
+ gfloat s;
+
+ s = *src++;
+ if (s < factor)
+ *dest++ = 0;
+ else /* factor <= value <=1 */
+ *dest++ = (s - factor) / (1.0 - factor);
+
+ s = *src++;
+ if (s < factor)
+ *dest++ = 0;
+ else /* factor <= value <=1 */
+ *dest++ = (s - factor) / (1.0 - factor);
+
+ s = *src++;
+ if (s < factor)
+ *dest++ = 0;
+ else /* factor <= value <=1 */
+ *dest++ = (s - factor) / (1.0 - factor);
+ }
+
+ *dest++ = *src++;
+ }
+ }
+ break;
+ }
+ });
+}
+
+/* helper function of gimp_gegl_smudge_with_paint_process()
+ src and dest can be the same address
+ */
+static inline void
+gimp_gegl_smudge_with_paint_blend (const gfloat *src1,
+ gfloat src1_rate,
+ const gfloat *src2,
+ gfloat src2_rate,
+ gfloat *dest,
+ gboolean no_erasing_src2)
+{
+ gfloat orginal_src2_alpha;
+ gfloat src1_alpha;
+ gfloat src2_alpha;
+ gfloat result_alpha;
+ gint b;
+
+ orginal_src2_alpha = src2[3];
+ src1_alpha = src1_rate * src1[3];
+ src2_alpha = src2_rate * orginal_src2_alpha;
+ result_alpha = src1_alpha + src2_alpha;
+
+ if (result_alpha == 0)
+ {
+ memset (dest, 0, sizeof (gfloat) * 4);
+ return;
+ }
+
+ for (b = 0; b < 3; b++)
+ dest[b] = (src1[b] * src1_alpha + src2[b] * src2_alpha) / result_alpha;
+
+ if (no_erasing_src2)
+ {
+ result_alpha = MAX (result_alpha, orginal_src2_alpha);
+ }
+
+ dest[3] = result_alpha;
+}
+
+/* helper function of gimp_gegl_smudge_with_paint() */
+static void
+gimp_gegl_smudge_with_paint_process (gfloat *accum,
+ const gfloat *canvas,
+ gfloat *paint,
+ gint count,
+ const gfloat *brush_color,
+ gfloat brush_a,
+ gboolean no_erasing,
+ gfloat flow,
+ gfloat rate)
+{
+ while (count--)
+ {
+ /* blend accum_buffer and canvas_buffer to accum_buffer */
+ gimp_gegl_smudge_with_paint_blend (accum, rate, canvas, 1 - rate,
+ accum, no_erasing);
+
+ /* blend accum_buffer and brush color/pixmap to paint_buffer */
+ if (brush_a == 0) /* pure smudge */
+ {
+ memcpy (paint, accum, sizeof (gfloat) * 4);
+ }
+ else
+ {
+ const gfloat *src1 = brush_color ? brush_color : paint;
+
+ gimp_gegl_smudge_with_paint_blend (src1, flow, accum, 1 - flow,
+ paint, no_erasing);
+ }
+
+ accum += 4;
+ canvas += 4;
+ paint += 4;
+ }
+}
+
+/* smudge painting calculation. Currently only smudge tool uses this function
+ * Accum = rate*Accum + (1-rate)*Canvas
+ * if brush_color!=NULL
+ * Paint = flow*brushColor + (1-flow)*Accum
+ * else
+ * Paint = flow*Paint + (1-flow)*Accum
+ */
+void
+gimp_gegl_smudge_with_paint (GeglBuffer *accum_buffer,
+ const GeglRectangle *accum_rect,
+ GeglBuffer *canvas_buffer,
+ const GeglRectangle *canvas_rect,
+ const GimpRGB *brush_color,
+ GeglBuffer *paint_buffer,
+ gboolean no_erasing,
+ gdouble flow,
+ gdouble rate)
+{
+ gfloat brush_color_float[4];
+ gfloat brush_a = flow;
+ GeglAccessMode paint_buffer_access_mode = (brush_color ?
+ GEGL_ACCESS_WRITE :
+ GEGL_ACCESS_READWRITE);
+#if COMPILE_SSE2_INTRINISICS
+ gboolean sse2 = (gimp_cpu_accel_get_support () &
+ GIMP_CPU_ACCEL_X86_SSE2);
+#endif
+
+ if (! accum_rect)
+ accum_rect = gegl_buffer_get_extent (accum_buffer);
+
+ if (! canvas_rect)
+ canvas_rect = gegl_buffer_get_extent (canvas_buffer);
+
+ /* convert brush color from double to float */
+ if (brush_color)
+ {
+ const gdouble *brush_color_ptr = &brush_color->r;
+ gint b;
+
+ for (b = 0; b < 4; b++)
+ brush_color_float[b] = brush_color_ptr[b];
+
+ brush_a *= brush_color_ptr[3];
+ }
+
+ gegl_parallel_distribute_area (
+ accum_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *accum_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (canvas, accum);
+
+ iter = gegl_buffer_iterator_new (accum_buffer, accum_area, 0,
+ babl_format ("RGBA float"),
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 3);
+
+ gegl_buffer_iterator_add (iter, canvas_buffer, canvas_area, 0,
+ babl_format ("RGBA float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ gegl_buffer_iterator_add (iter, paint_buffer,
+ GEGL_RECTANGLE (accum_area->x - accum_rect->x,
+ accum_area->y - accum_rect->y,
+ 0, 0),
+ 0,
+ babl_format ("RGBA float"),
+ paint_buffer_access_mode, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *accum = (gfloat *) iter->items[0].data;
+ const gfloat *canvas = (const gfloat *) iter->items[1].data;
+ gfloat *paint = (gfloat *) iter->items[2].data;
+ gint count = iter->length;
+
+#if COMPILE_SSE2_INTRINISICS
+ if (sse2 && ((guintptr) accum |
+ (guintptr) canvas |
+ (guintptr) (brush_color ? brush_color_float : paint) |
+ (guintptr) paint) % 16 == 0)
+ {
+ gimp_gegl_smudge_with_paint_process_sse2 (accum, canvas, paint, count,
+ brush_color ? brush_color_float :
+ NULL,
+ brush_a,
+ no_erasing, flow, rate);
+ }
+ else
+#endif
+ {
+ gimp_gegl_smudge_with_paint_process (accum, canvas, paint, count,
+ brush_color ? brush_color_float :
+ NULL,
+ brush_a,
+ no_erasing, flow, rate);
+ }
+ }
+ });
+}
+
+void
+gimp_gegl_apply_mask (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity)
+{
+ if (! mask_rect)
+ mask_rect = gegl_buffer_get_extent (mask_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ gegl_parallel_distribute_area (
+ mask_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *mask_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (dest, mask);
+
+ iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
+ babl_format ("RGBA float"),
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const gfloat *mask = (const gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ dest[3] *= *mask * opacity;
+
+ mask += 1;
+ dest += 4;
+ }
+ }
+ });
+}
+
+void
+gimp_gegl_combine_mask (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity)
+{
+ if (! mask_rect)
+ mask_rect = gegl_buffer_get_extent (mask_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ gegl_parallel_distribute_area (
+ mask_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *mask_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (dest, mask);
+
+ iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const gfloat *mask = (const gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ *dest *= *mask * opacity;
+
+ mask += 1;
+ dest += 1;
+ }
+ }
+ });
+}
+
+void
+gimp_gegl_combine_mask_weird (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity,
+ gboolean stipple)
+{
+ if (! mask_rect)
+ mask_rect = gegl_buffer_get_extent (mask_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ gegl_parallel_distribute_area (
+ mask_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *mask_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (dest, mask);
+
+ iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const gfloat *mask = (const gfloat *) iter->items[0].data;
+ gfloat *dest = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ if (stipple)
+ {
+ while (count--)
+ {
+ dest[0] += (1.0 - dest[0]) * *mask * opacity;
+
+ mask += 1;
+ dest += 1;
+ }
+ }
+ else
+ {
+ while (count--)
+ {
+ if (opacity > dest[0])
+ dest[0] += (opacity - dest[0]) * *mask * opacity;
+
+ mask += 1;
+ dest += 1;
+ }
+ }
+ }
+ });
+}
+
+void
+gimp_gegl_index_to_mask (GeglBuffer *indexed_buffer,
+ const GeglRectangle *indexed_rect,
+ const Babl *indexed_format,
+ GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ gint index)
+{
+ if (! indexed_rect)
+ indexed_rect = gegl_buffer_get_extent (indexed_buffer);
+
+ if (! mask_rect)
+ mask_rect = gegl_buffer_get_extent (mask_buffer);
+
+ gegl_parallel_distribute_area (
+ indexed_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *indexed_area)
+ {
+ GeglBufferIterator *iter;
+
+ SHIFTED_AREA (mask, indexed);
+
+ iter = gegl_buffer_iterator_new (indexed_buffer, indexed_area, 0,
+ indexed_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, mask_buffer, mask_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const guchar *indexed = (const guchar *) iter->items[0].data;
+ gfloat *mask = (gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ if (*indexed == index)
+ *mask = 1.0;
+ else
+ *mask = 0.0;
+
+ indexed++;
+ mask++;
+ }
+ }
+ });
+}
+
+static void
+gimp_gegl_convert_color_profile_progress (GimpProgress *progress,
+ gdouble value)
+{
+ if (gegl_is_main_thread ())
+ gimp_progress_set_value (progress, value);
+}
+
+void
+gimp_gegl_convert_color_profile (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GimpColorProfile *src_profile,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ GimpColorProfile *dest_profile,
+ GimpColorRenderingIntent intent,
+ gboolean bpc,
+ GimpProgress *progress)
+{
+ GimpColorTransform *transform;
+ guint flags = 0;
+ const Babl *src_format;
+ const Babl *dest_format;
+
+ src_format = gegl_buffer_get_format (src_buffer);
+ dest_format = gegl_buffer_get_format (dest_buffer);
+
+ if (bpc)
+ flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION;
+
+ flags |= GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE;
+
+ transform = gimp_color_transform_new (src_profile, src_format,
+ dest_profile, dest_format,
+ intent,
+ (GimpColorTransformFlags) flags);
+
+ if (! src_rect)
+ src_rect = gegl_buffer_get_extent (src_buffer);
+
+ if (! dest_rect)
+ dest_rect = gegl_buffer_get_extent (dest_buffer);
+
+ if (transform)
+ {
+ if (progress)
+ {
+ g_signal_connect_swapped (
+ transform, "progress",
+ G_CALLBACK (gimp_gegl_convert_color_profile_progress),
+ progress);
+ }
+
+ GIMP_TIMER_START ();
+
+ gegl_parallel_distribute_area (
+ src_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *src_area)
+ {
+ SHIFTED_AREA (dest, src);
+
+ gimp_color_transform_process_buffer (transform,
+ src_buffer, src_area,
+ dest_buffer, dest_area);
+ });
+
+ GIMP_TIMER_END ("converting buffer");
+
+ g_object_unref (transform);
+ }
+ else
+ {
+ gimp_gegl_buffer_copy (src_buffer, src_rect, GEGL_ABYSS_NONE,
+ dest_buffer, dest_rect);
+
+ if (progress)
+ gimp_progress_set_value (progress, 1.0);
+ }
+}
+
+void
+gimp_gegl_average_color (GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ gboolean clip_to_buffer,
+ GeglAbyssPolicy abyss_policy,
+ const Babl *format,
+ gpointer color)
+{
+ typedef struct
+ {
+ gfloat color[4];
+ gint n;
+ } Sum;
+
+ const Babl *average_format = babl_format ("RaGaBaA float");
+ GeglRectangle roi;
+ GSList * volatile sums = NULL;
+ GSList *list;
+ Sum average = {};
+ gint c;
+
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+ g_return_if_fail (color != NULL);
+
+ if (! rect)
+ rect = gegl_buffer_get_extent (buffer);
+
+ if (! format)
+ format = gegl_buffer_get_format (buffer);
+
+ if (clip_to_buffer)
+ gegl_rectangle_intersect (&roi, rect, gegl_buffer_get_extent (buffer));
+ else
+ roi = *rect;
+
+ gegl_parallel_distribute_area (
+ &roi, PIXELS_PER_THREAD,
+ [&] (const GeglRectangle *area)
+ {
+ Sum *sum;
+ GeglBufferIterator *iter;
+ gfloat color[4] = {};
+ gint n = 0;
+
+ iter = gegl_buffer_iterator_new (buffer, area, 0, average_format,
+ GEGL_BUFFER_READ, abyss_policy, 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const gfloat *p = (const gfloat *) iter->items[0].data;
+ gint i;
+
+ for (i = 0; i < iter->length; i++)
+ {
+ gint c;
+
+ for (c = 0; c < 4; c++)
+ color[c] += p[c];
+
+ p += 4;
+ }
+
+ n += iter->length;
+ }
+
+ sum = g_slice_new (Sum);
+
+ memcpy (sum->color, color, sizeof (color));
+ sum->n = n;
+
+ gimp_atomic_slist_push_head (&sums, sum);
+ });
+
+ for (list = sums; list; list = g_slist_next (list))
+ {
+ Sum *sum = (Sum *) list->data;
+
+ for (c = 0; c < 4; c++)
+ average.color[c] += sum->color[c];
+
+ average.n += sum->n;
+
+ g_slice_free (Sum, sum);
+ }
+
+ g_slist_free (sums);
+
+ if (average.n > 0)
+ {
+ for (c = 0; c < 4; c++)
+ average.color[c] /= average.n;
+ }
+
+ babl_process (babl_fish (average_format, format), average.color, color, 1);
+}
+
+} /* extern "C" */
diff --git a/app/gegl/gimp-gegl-loops.h b/app/gegl/gimp-gegl-loops.h
new file mode 100644
index 0000000..872c2b4
--- /dev/null
+++ b/app/gegl/gimp-gegl-loops.h
@@ -0,0 +1,109 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-loops.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_LOOPS_H__
+#define __GIMP_GEGL_LOOPS_H__
+
+
+void gimp_gegl_buffer_copy (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglAbyssPolicy abyss_policy,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect);
+
+void gimp_gegl_clear (GeglBuffer *buffer,
+ const GeglRectangle *rect);
+
+/* this is a pretty stupid port of concolve_region() that only works
+ * on a linear source buffer
+ */
+void gimp_gegl_convolve (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ const gfloat *kernel,
+ gint kernel_size,
+ gdouble divisor,
+ GimpConvolutionType mode,
+ gboolean alpha_weighting);
+
+void gimp_gegl_dodgeburn (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble exposure,
+ GimpDodgeBurnType type,
+ GimpTransferMode mode);
+
+void gimp_gegl_smudge_with_paint (GeglBuffer *accum_buffer,
+ const GeglRectangle *accum_rect,
+ GeglBuffer *canvas_buffer,
+ const GeglRectangle *canvas_rect,
+ const GimpRGB *brush_color,
+ GeglBuffer *paint_buffer,
+ gboolean no_erasing,
+ gdouble flow,
+ gdouble rate);
+
+void gimp_gegl_apply_mask (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity);
+
+void gimp_gegl_combine_mask (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity);
+
+void gimp_gegl_combine_mask_weird (GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ gdouble opacity,
+ gboolean stipple);
+
+void gimp_gegl_index_to_mask (GeglBuffer *indexed_buffer,
+ const GeglRectangle *indexed_rect,
+ const Babl *indexed_format,
+ GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect,
+ gint index);
+
+void gimp_gegl_convert_color_profile (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GimpColorProfile *src_profile,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ GimpColorProfile *dest_profile,
+ GimpColorRenderingIntent intent,
+ gboolean bpc,
+ GimpProgress *progress);
+
+void gimp_gegl_average_color (GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ gboolean clip_to_buffer,
+ GeglAbyssPolicy abyss_policy,
+ const Babl *format,
+ gpointer color);
+
+
+#endif /* __GIMP_GEGL_LOOPS_H__ */
diff --git a/app/gegl/gimp-gegl-mask-combine.cc b/app/gegl/gimp-gegl-mask-combine.cc
new file mode 100644
index 0000000..0e61c0e
--- /dev/null
+++ b/app/gegl/gimp-gegl-mask-combine.cc
@@ -0,0 +1,653 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpmath/gimpmath.h"
+
+extern "C"
+{
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-babl.h"
+#include "gimp-gegl-loops.h"
+#include "gimp-gegl-mask-combine.h"
+
+
+#define EPSILON 1e-6
+
+#define PIXELS_PER_THREAD \
+ (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
+
+
+gboolean
+gimp_gegl_mask_combine_rect (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h)
+{
+ GeglRectangle rect;
+ gfloat value;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE);
+
+ if (! gegl_rectangle_intersect (&rect,
+ GEGL_RECTANGLE (x, y, w, h),
+ gegl_buffer_get_abyss (mask)))
+ {
+ return FALSE;
+ }
+
+ switch (op)
+ {
+ case GIMP_CHANNEL_OP_REPLACE:
+ case GIMP_CHANNEL_OP_ADD:
+ value = 1.0f;
+ break;
+
+ case GIMP_CHANNEL_OP_SUBTRACT:
+ value = 0.0f;
+ break;
+
+ case GIMP_CHANNEL_OP_INTERSECT:
+ return TRUE;
+ }
+
+ gegl_buffer_set_color_from_pixel (mask, &rect, &value,
+ babl_format ("Y float"));
+
+ return TRUE;
+}
+
+gboolean
+gimp_gegl_mask_combine_ellipse (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h,
+ gboolean antialias)
+{
+ return gimp_gegl_mask_combine_ellipse_rect (mask, op, x, y, w, h,
+ w / 2.0, h / 2.0, antialias);
+}
+
+gboolean
+gimp_gegl_mask_combine_ellipse_rect (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h,
+ gdouble rx,
+ gdouble ry,
+ gboolean antialias)
+{
+ GeglRectangle rect;
+ const Babl *format;
+ gint bpp;
+ gfloat one_f = 1.0f;
+ gpointer one;
+ gdouble cx;
+ gdouble cy;
+ gint left;
+ gint right;
+ gint top;
+ gint bottom;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE);
+
+ if (rx <= EPSILON || ry <= EPSILON)
+ return gimp_gegl_mask_combine_rect (mask, op, x, y, w, h);
+
+ left = x;
+ right = x + w;
+ top = y;
+ bottom = y + h;
+
+ cx = (left + right) / 2.0;
+ cy = (top + bottom) / 2.0;
+
+ rx = MIN (rx, w / 2.0);
+ ry = MIN (ry, h / 2.0);
+
+ if (! gegl_rectangle_intersect (&rect,
+ GEGL_RECTANGLE (x, y, w, h),
+ gegl_buffer_get_abyss (mask)))
+ {
+ return FALSE;
+ }
+
+ format = gegl_buffer_get_format (mask);
+
+ if (antialias)
+ {
+ format = gimp_babl_format_change_component_type (
+ format, GIMP_COMPONENT_TYPE_FLOAT);
+ }
+
+ bpp = babl_format_get_bytes_per_pixel (format);
+ one = g_alloca (bpp);
+
+ babl_process (babl_fish ("Y float", format), &one_f, one, 1);
+
+ /* coordinate-system transforms. (x, y) coordinates are in the image
+ * coordinate-system, and (u, v) coordinates are in a coordinate-system
+ * aligned with the center of one of the elliptic corners, with the positive
+ * directions pointing away from the rectangle. when converting from (x, y)
+ * to (u, v), we use the closest elliptic corner.
+ */
+ auto x_to_u = [=] (gdouble x)
+ {
+ if (x < cx)
+ return (left + rx) - x;
+ else
+ return x - (right - rx);
+ };
+
+ auto y_to_v = [=] (gdouble y)
+ {
+ if (y < cy)
+ return (top + ry) - y;
+ else
+ return y - (bottom - ry);
+ };
+
+ auto u_to_x_left = [=] (gdouble u)
+ {
+ return (left + rx) - u;
+ };
+
+ auto u_to_x_right = [=] (gdouble u)
+ {
+ return (right - rx) + u;
+ };
+
+ /* intersection of a horizontal line with the ellipse */
+ auto v_to_u = [=] (gdouble v)
+ {
+ if (v > 0.0)
+ return sqrt (MAX (SQR (rx) - SQR (rx * v / ry), 0.0));
+ else
+ return rx;
+ };
+
+ /* intersection of a vertical line with the ellipse */
+ auto u_to_v = [=] (gdouble u)
+ {
+ if (u > 0.0)
+ return sqrt (MAX (SQR (ry) - SQR (ry * u / rx), 0.0));
+ else
+ return ry;
+ };
+
+ /* signed, normalized distance of a point from the ellipse's circumference.
+ * the sign of the result determines if the point is inside (positive) or
+ * outside (negative) the ellipse. the result is normalized to the cross-
+ * section length of a pixel, in the direction of the closest point along the
+ * ellipse.
+ *
+ * we use the following method to approximate the distance: pass horizontal
+ * and vertical lines at the given point, P, and find their (positive) points
+ * of intersection with the ellipse, A and B. the segment AB is an
+ * approximation of the corresponding elliptic arc (see bug #147836). find
+ * the closest point, C, to P, along the segment AB. find the (positive)
+ * point of intersection, Q, of the line PC and the ellipse. Q is an
+ * approximation for the closest point to P along the ellipse, and the
+ * approximated distance is the distance from P to Q.
+ */
+ auto ellipse_distance = [=] (gdouble u,
+ gdouble v)
+ {
+ gdouble du;
+ gdouble dv;
+ gdouble t;
+ gdouble a, b, c;
+ gdouble d;
+
+ u = MAX (u, 0.0);
+ v = MAX (v, 0.0);
+
+ du = v_to_u (v) - u;
+ dv = u_to_v (u) - v;
+
+ t = SQR (du) / (SQR (du) + SQR (dv));
+
+ du *= 1.0 - t;
+ dv *= t;
+
+ v *= rx / ry;
+ dv *= rx / ry;
+
+ a = SQR (du) + SQR (dv);
+ b = u * du + v * dv;
+ c = SQR (u) + SQR (v) - SQR (rx);
+
+ if (a <= EPSILON)
+ return 0.0;
+
+ if (c < 0.0)
+ t = (-b + sqrt (MAX (SQR (b) - a * c, 0.0))) / a;
+ else
+ t = (-b - sqrt (MAX (SQR (b) - a * c, 0.0))) / a;
+
+ dv *= ry / rx;
+
+ d = sqrt (SQR (du * t) + SQR (dv * t));
+
+ if (c > 0.0)
+ d = -d;
+
+ d /= sqrt (SQR (MIN (du / dv, dv / du)) + 1.0);
+
+ return d;
+ };
+
+ /* anti-aliased value of a pixel */
+ auto pixel_value = [=] (gint x,
+ gint y)
+ {
+ gdouble u = x_to_u (x + 0.5);
+ gdouble v = y_to_v (y + 0.5);
+ gdouble d = ellipse_distance (u, v);
+
+ /* use the distance of the pixel's center from the ellipse to approximate
+ * the coverage
+ */
+ d = CLAMP (0.5 + d, 0.0, 1.0);
+
+ /* we're at the horizontal boundary of an elliptic corner */
+ if (u < 0.5)
+ d = d * (0.5 + u) + (0.5 - u);
+
+ /* we're at the vertical boundary of an elliptic corner */
+ if (v < 0.5)
+ d = d * (0.5 + v) + (0.5 - v);
+
+ /* opposite horizontal corners intersect the pixel */
+ if (x == (right - 1) - (x - left))
+ d = 2.0 * d - 1.0;
+
+ /* opposite vertical corners intersect the pixel */
+ if (y == (bottom - 1) - (y - top))
+ d = 2.0 * d - 1.0;
+
+ return d;
+ };
+
+ auto ellipse_range = [=] (gdouble y,
+ gdouble *x0,
+ gdouble *x1)
+ {
+ gdouble u = v_to_u (y_to_v (y));
+
+ *x0 = u_to_x_left (u);
+ *x1 = u_to_x_right (u);
+ };
+
+ auto fill0 = [=] (gpointer dest,
+ gint n)
+ {
+ switch (op)
+ {
+ case GIMP_CHANNEL_OP_REPLACE:
+ case GIMP_CHANNEL_OP_INTERSECT:
+ memset (dest, 0, bpp * n);
+ break;
+
+ case GIMP_CHANNEL_OP_ADD:
+ case GIMP_CHANNEL_OP_SUBTRACT:
+ break;
+ }
+
+ return (gpointer) ((guint8 *) dest + bpp * n);
+ };
+
+ auto fill1 = [=] (gpointer dest,
+ gint n)
+ {
+ switch (op)
+ {
+ case GIMP_CHANNEL_OP_REPLACE:
+ case GIMP_CHANNEL_OP_ADD:
+ gegl_memset_pattern (dest, one, bpp, n);
+ break;
+
+ case GIMP_CHANNEL_OP_SUBTRACT:
+ memset (dest, 0, bpp * n);
+ break;
+
+ case GIMP_CHANNEL_OP_INTERSECT:
+ break;
+ }
+
+ return (gpointer) ((guint8 *) dest + bpp * n);
+ };
+
+ auto set = [=] (gpointer dest,
+ gfloat value)
+ {
+ gfloat *p = (gfloat *) dest;
+
+ switch (op)
+ {
+ case GIMP_CHANNEL_OP_REPLACE:
+ *p = value;
+ break;
+
+ case GIMP_CHANNEL_OP_ADD:
+ *p = MIN (*p + value, 1.0);
+ break;
+
+ case GIMP_CHANNEL_OP_SUBTRACT:
+ *p = MAX (*p - value, 0.0);
+ break;
+
+ case GIMP_CHANNEL_OP_INTERSECT:
+ *p = MIN (*p, value);
+ break;
+ }
+
+ return (gpointer) (p + 1);
+ };
+
+ gegl_parallel_distribute_area (
+ &rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *area)
+ {
+ GeglBufferIterator *iter;
+
+ iter = gegl_buffer_iterator_new (
+ mask, area, 0, format,
+ op == GIMP_CHANNEL_OP_REPLACE ? GEGL_ACCESS_WRITE :
+ GEGL_ACCESS_READWRITE,
+ GEGL_ABYSS_NONE, 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const GeglRectangle *roi = &iter->items[0].roi;
+ gpointer d = iter->items[0].data;
+ gdouble tx0, ty0;
+ gdouble tx1, ty1;
+ gdouble x0;
+ gdouble x1;
+ gint y;
+
+ /* tile bounds */
+ tx0 = roi->x;
+ ty0 = roi->y;
+
+ tx1 = roi->x + roi->width;
+ ty1 = roi->y + roi->height;
+
+ if (! antialias)
+ {
+ tx0 += 0.5;
+ ty0 += 0.5;
+
+ tx1 -= 0.5;
+ ty1 -= 0.5;
+ }
+
+ /* if the tile is fully inside/outside the ellipse, fill it with 1/0,
+ * respectively, and skip the rest.
+ */
+ ellipse_range (ty0, &x0, &x1);
+
+ if (tx0 >= x0 && tx1 <= x1)
+ {
+ ellipse_range (ty1, &x0, &x1);
+
+ if (tx0 >= x0 && tx1 <= x1)
+ {
+ fill1 (d, iter->length);
+
+ continue;
+ }
+ }
+ else if (tx1 < x0 || tx0 > x1)
+ {
+ ellipse_range (ty1, &x0, &x1);
+
+ if (tx1 < x0 || tx0 > x1)
+ {
+ if ((ty0 - cy) * (ty1 - cy) >= 0.0)
+ {
+ fill0 (d, iter->length);
+
+ continue;
+ }
+ }
+ }
+
+ for (y = roi->y; y < roi->y + roi->height; y++)
+ {
+ gint a, b;
+
+ if (antialias)
+ {
+ gdouble v = y_to_v (y + 0.5);
+ gdouble u0 = v_to_u (v - 0.5);
+ gdouble u1 = v_to_u (v + 0.5);
+ gint x;
+
+ a = floor (u_to_x_left (u0)) - roi->x;
+ a = CLAMP (a, 0, roi->width);
+
+ b = ceil (u_to_x_left (u1)) - roi->x;
+ b = CLAMP (b, a, roi->width);
+
+ d = fill0 (d, a);
+
+ for (x = roi->x + a; x < roi->x + b; x++)
+ d = set (d, pixel_value (x, y));
+
+ a = floor (u_to_x_right (u1)) - roi->x;
+ a = CLAMP (a, b, roi->width);
+
+ d = fill1 (d, a - b);
+
+ b = ceil (u_to_x_right (u0)) - roi->x;
+ b = CLAMP (b, a, roi->width);
+
+ for (x = roi->x + a; x < roi->x + b; x++)
+ d = set (d, pixel_value (x, y));
+
+ d = fill0 (d, roi->width - b);
+ }
+ else
+ {
+ ellipse_range (y + 0.5, &x0, &x1);
+
+ a = ceil (x0 - 0.5) - roi->x;
+ a = CLAMP (a, 0, roi->width);
+
+ b = floor (x1 + 0.5) - roi->x;
+ b = CLAMP (b, 0, roi->width);
+
+ d = fill0 (d, a);
+ d = fill1 (d, b - a);
+ d = fill0 (d, roi->width - b);
+ }
+ }
+ }
+ });
+
+ return TRUE;
+}
+
+gboolean
+gimp_gegl_mask_combine_buffer (GeglBuffer *mask,
+ GeglBuffer *add_on,
+ GimpChannelOps op,
+ gint off_x,
+ gint off_y)
+{
+ GeglRectangle mask_rect;
+ GeglRectangle add_on_rect;
+ const Babl *mask_format;
+ const Babl *add_on_format;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE);
+ g_return_val_if_fail (GEGL_IS_BUFFER (add_on), FALSE);
+
+ if (! gegl_rectangle_intersect (&mask_rect,
+ GEGL_RECTANGLE (
+ off_x + gegl_buffer_get_x (add_on),
+ off_y + gegl_buffer_get_y (add_on),
+ gegl_buffer_get_width (add_on),
+ gegl_buffer_get_height (add_on)),
+ gegl_buffer_get_abyss (mask)))
+ {
+ return FALSE;
+ }
+
+ add_on_rect = mask_rect;
+ add_on_rect.x -= off_x;
+ add_on_rect.y -= off_y;
+
+ mask_format = gegl_buffer_get_format (mask);
+ add_on_format = gegl_buffer_get_format (add_on);
+
+ if (op == GIMP_CHANNEL_OP_REPLACE &&
+ (gimp_babl_is_bounded (gimp_babl_format_get_precision (add_on_format)) ||
+ gimp_babl_is_bounded (gimp_babl_format_get_precision (mask_format))))
+ {
+ /* See below: this additional hack is only needed for the
+ * gimp-channel-combine-masks procedure, it's the only place that
+ * allows to combine arbitrary channels with each other.
+ */
+ gegl_buffer_set_format (
+ add_on,
+ gimp_babl_format_change_linear (
+ add_on_format, gimp_babl_format_get_linear (mask_format)));
+
+ gimp_gegl_buffer_copy (add_on, &add_on_rect, GEGL_ABYSS_NONE,
+ mask, &mask_rect);
+
+ gegl_buffer_set_format (add_on, NULL);
+
+ return TRUE;
+ }
+
+ /* This is a hack: all selections/layer masks/channels are always
+ * linear except for channels in 8-bit images. We don't want these
+ * "Y' u8" to be converted to "Y float" because that would cause a
+ * gamma canversion and give unexpected results for
+ * "add/subtract/etc channel from selection". Instead, use all
+ * channel values "as-is", which makes no differce except in the
+ * 8-bit case where we need it.
+ *
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=791519
+ */
+ mask_format = gimp_babl_format_change_component_type (
+ mask_format, GIMP_COMPONENT_TYPE_FLOAT);
+
+ add_on_format = gimp_babl_format_change_component_type (
+ add_on_format, GIMP_COMPONENT_TYPE_FLOAT);
+
+ gegl_parallel_distribute_area (
+ &mask_rect, PIXELS_PER_THREAD,
+ [=] (const GeglRectangle *mask_area)
+ {
+ GeglBufferIterator *iter;
+ GeglRectangle add_on_area;
+
+ add_on_area = *mask_area;
+ add_on_area.x -= off_x;
+ add_on_area.y -= off_y;
+
+ iter = gegl_buffer_iterator_new (mask, mask_area, 0,
+ mask_format,
+ op == GIMP_CHANNEL_OP_REPLACE ?
+ GEGL_ACCESS_WRITE :
+ GEGL_ACCESS_READWRITE,
+ GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, add_on, &add_on_area, 0,
+ add_on_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ auto process = [=] (auto value)
+ {
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gfloat *mask_data = (gfloat *) iter->items[0].data;
+ const gfloat *add_on_data = (const gfloat *) iter->items[1].data;
+ gint count = iter->length;
+
+ while (count--)
+ {
+ const gfloat val = value (mask_data, add_on_data);
+
+ *mask_data = CLAMP (val, 0.0f, 1.0f);
+
+ add_on_data++;
+ mask_data++;
+ }
+ }
+ };
+
+ switch (op)
+ {
+ case GIMP_CHANNEL_OP_REPLACE:
+ process ([] (const gfloat *mask,
+ const gfloat *add_on)
+ {
+ return *add_on;
+ });
+ break;
+
+ case GIMP_CHANNEL_OP_ADD:
+ process ([] (const gfloat *mask,
+ const gfloat *add_on)
+ {
+ return *mask + *add_on;
+ });
+ break;
+
+ case GIMP_CHANNEL_OP_SUBTRACT:
+ process ([] (const gfloat *mask,
+ const gfloat *add_on)
+ {
+ return *mask - *add_on;
+ });
+ break;
+
+ case GIMP_CHANNEL_OP_INTERSECT:
+ process ([] (const gfloat *mask,
+ const gfloat *add_on)
+ {
+ return MIN (*mask, *add_on);
+ });
+ break;
+ }
+ });
+
+ return TRUE;
+}
+
+} /* extern "C" */
diff --git a/app/gegl/gimp-gegl-mask-combine.h b/app/gegl/gimp-gegl-mask-combine.h
new file mode 100644
index 0000000..d8e0fa2
--- /dev/null
+++ b/app/gegl/gimp-gegl-mask-combine.h
@@ -0,0 +1,51 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_MASK_COMBINE_H__
+#define __GIMP_GEGL_MASK_COMBINE_H__
+
+
+gboolean gimp_gegl_mask_combine_rect (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h);
+gboolean gimp_gegl_mask_combine_ellipse (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h,
+ gboolean antialias);
+gboolean gimp_gegl_mask_combine_ellipse_rect (GeglBuffer *mask,
+ GimpChannelOps op,
+ gint x,
+ gint y,
+ gint w,
+ gint h,
+ gdouble rx,
+ gdouble ry,
+ gboolean antialias);
+gboolean gimp_gegl_mask_combine_buffer (GeglBuffer *mask,
+ GeglBuffer *add_on,
+ GimpChannelOps op,
+ gint off_x,
+ gint off_y);
+
+
+#endif /* __GIMP_GEGL_MASK_COMBINE_H__ */
diff --git a/app/gegl/gimp-gegl-mask.c b/app/gegl/gimp-gegl-mask.c
new file mode 100644
index 0000000..325289c
--- /dev/null
+++ b/app/gegl/gimp-gegl-mask.c
@@ -0,0 +1,253 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "gegl/gimp-gegl-mask.h"
+
+
+gboolean
+gimp_gegl_mask_bounds (GeglBuffer *buffer,
+ gint *x1,
+ gint *y1,
+ gint *x2,
+ gint *y2)
+{
+ GeglBufferIterator *iter;
+ const GeglRectangle *extent;
+ const GeglRectangle *roi;
+ const Babl *format;
+ gint bpp;
+ gint tx1, tx2, ty1, ty2;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (x1 != NULL, FALSE);
+ g_return_val_if_fail (y1 != NULL, FALSE);
+ g_return_val_if_fail (x2 != NULL, FALSE);
+ g_return_val_if_fail (y2 != NULL, FALSE);
+
+ extent = gegl_buffer_get_extent (buffer);
+
+ /* go through and calculate the bounds */
+ tx1 = extent->x + extent->width;
+ ty1 = extent->y + extent->height;
+ tx2 = extent->x;
+ ty2 = extent->y;
+
+ format = gegl_buffer_get_format (buffer);
+ bpp = babl_format_get_bytes_per_pixel (format);
+
+ iter = gegl_buffer_iterator_new (buffer, NULL, 0, format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
+ roi = &iter->items[0].roi;
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const guint8 *data_u8 = iter->items[0].data;
+ gint ex = roi->x + roi->width;
+ gint ey = roi->y + roi->height;
+
+ /* only check the pixels if this tile is not fully within the
+ * currently computed bounds
+ */
+ if (roi->x < tx1 || ex > tx2 ||
+ roi->y < ty1 || ey > ty2)
+ {
+ /* Check upper left and lower right corners to see if we can
+ * avoid checking the rest of the pixels in this tile
+ */
+ if (! gegl_memeq_zero (data_u8, bpp) &&
+ ! gegl_memeq_zero (data_u8 + (iter->length - 1) * bpp, bpp))
+ {
+ /* "ex/ey - 1" because the internal variables are the
+ * right/bottom pixel of the mask's contents, not one
+ * right/below it like the return values.
+ */
+
+ if (roi->x < tx1) tx1 = roi->x;
+ if (ex > tx2) tx2 = ex - 1;
+
+ if (roi->y < ty1) ty1 = roi->y;
+ if (ey > ty2) ty2 = ey - 1;
+ }
+ else
+ {
+ #define FIND_BOUNDS(bpp, type) \
+ G_STMT_START \
+ { \
+ const type *data; \
+ gint y; \
+ \
+ if ((guintptr) data_u8 % bpp) \
+ goto generic; \
+ \
+ data = (const type *) data_u8; \
+ \
+ for (y = roi->y; y < ey; y++) \
+ { \
+ gint x1; \
+ \
+ for (x1 = 0; x1 < roi->width; x1++) \
+ { \
+ if (data[x1]) \
+ { \
+ gint x2; \
+ gint x2_end = MAX (x1, tx2 - roi->x); \
+ \
+ for (x2 = roi->width - 1; x2 > x2_end; x2--) \
+ { \
+ if (data[x2]) \
+ break; \
+ } \
+ \
+ x1 += roi->x; \
+ x2 += roi->x; \
+ \
+ if (x1 < tx1) tx1 = x1; \
+ if (x2 > tx2) tx2 = x2; \
+ \
+ if (y < ty1) ty1 = y; \
+ if (y > ty2) ty2 = y; \
+ \
+ break; \
+ } \
+ } \
+ \
+ data += roi->width; \
+ } \
+ } \
+ G_STMT_END
+
+ switch (bpp)
+ {
+ case 1:
+ FIND_BOUNDS (1, guint8);
+ break;
+
+ case 2:
+ FIND_BOUNDS (2, guint16);
+ break;
+
+ case 4:
+ FIND_BOUNDS (4, guint32);
+ break;
+
+ case 8:
+ FIND_BOUNDS (8, guint64);
+ break;
+
+ default:
+ generic:
+ {
+ const guint8 *data = data_u8;
+ gint y;
+
+ for (y = roi->y; y < ey; y++)
+ {
+ gint x1;
+
+ for (x1 = 0; x1 < roi->width; x1++)
+ {
+ if (! gegl_memeq_zero (data + x1 * bpp, bpp))
+ {
+ gint x2;
+ gint x2_end = MAX (x1, tx2 - roi->x);
+
+ for (x2 = roi->width - 1; x2 > x2_end; x2--)
+ {
+ if (! gegl_memeq_zero (data + x2 * bpp,
+ bpp))
+ {
+ break;
+ }
+ }
+
+ x1 += roi->x;
+ x2 += roi->x;
+
+ if (x1 < tx1) tx1 = x1;
+ if (x2 > tx2) tx2 = x2;
+
+ if (y < ty1) ty1 = y;
+ if (y > ty2) ty2 = y;
+ }
+ }
+
+ data += roi->width * bpp;
+ }
+ }
+ break;
+ }
+
+ #undef FIND_BOUNDS
+ }
+ }
+ }
+
+ tx2 = CLAMP (tx2 + 1, 0, gegl_buffer_get_width (buffer));
+ ty2 = CLAMP (ty2 + 1, 0, gegl_buffer_get_height (buffer));
+
+ if (tx1 == gegl_buffer_get_width (buffer) &&
+ ty1 == gegl_buffer_get_height (buffer))
+ {
+ *x1 = 0;
+ *y1 = 0;
+ *x2 = gegl_buffer_get_width (buffer);
+ *y2 = gegl_buffer_get_height (buffer);
+
+ return FALSE;
+ }
+
+ *x1 = tx1;
+ *y1 = ty1;
+ *x2 = tx2;
+ *y2 = ty2;
+
+ return TRUE;
+}
+
+gboolean
+gimp_gegl_mask_is_empty (GeglBuffer *buffer)
+{
+ GeglBufferIterator *iter;
+ const Babl *format;
+ gint bpp;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
+
+ format = gegl_buffer_get_format (buffer);
+ bpp = babl_format_get_bytes_per_pixel (format);
+
+ iter = gegl_buffer_iterator_new (buffer, NULL, 0, format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ if (! gegl_memeq_zero (iter->items[0].data, bpp * iter->length))
+ {
+ gegl_buffer_iterator_stop (iter);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/app/gegl/gimp-gegl-mask.h b/app/gegl/gimp-gegl-mask.h
new file mode 100644
index 0000000..e14d838
--- /dev/null
+++ b/app/gegl/gimp-gegl-mask.h
@@ -0,0 +1,30 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_MASK_H__
+#define __GIMP_GEGL_MASK_H__
+
+
+gboolean gimp_gegl_mask_bounds (GeglBuffer *buffer,
+ gint *x1,
+ gint *y1,
+ gint *x2,
+ gint *y2);
+gboolean gimp_gegl_mask_is_empty (GeglBuffer *buffer);
+
+
+#endif /* __GIMP_GEGL_MASK_H__ */
diff --git a/app/gegl/gimp-gegl-nodes.c b/app/gegl/gimp-gegl-nodes.c
new file mode 100644
index 0000000..5067da2
--- /dev/null
+++ b/app/gegl/gimp-gegl-nodes.c
@@ -0,0 +1,260 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-nodes.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "operations/layer-modes/gimp-layer-modes.h"
+
+#include "gimp-gegl-nodes.h"
+#include "gimp-gegl-utils.h"
+
+
+GeglNode *
+gimp_gegl_create_flatten_node (const GimpRGB *background,
+ GimpLayerColorSpace composite_space)
+{
+ GeglNode *node;
+ GeglNode *input;
+ GeglNode *output;
+ GeglNode *color;
+ GeglNode *mode;
+ GeglColor *c;
+
+ g_return_val_if_fail (background != NULL, NULL);
+ g_return_val_if_fail (composite_space == GIMP_LAYER_COLOR_SPACE_RGB_LINEAR ||
+ composite_space == GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ NULL);
+
+ node = gegl_node_new ();
+
+ input = gegl_node_get_input_proxy (node, "input");
+ output = gegl_node_get_output_proxy (node, "output");
+
+ c = gimp_gegl_color_new (background);
+ color = gegl_node_new_child (node,
+ "operation", "gegl:color",
+ "value", c,
+ "format", gimp_layer_mode_get_format (
+ GIMP_LAYER_MODE_NORMAL,
+ GIMP_LAYER_COLOR_SPACE_AUTO,
+ composite_space,
+ GIMP_LAYER_COMPOSITE_AUTO,
+ NULL),
+ NULL);
+ g_object_unref (c);
+
+ gimp_gegl_node_set_underlying_operation (node, color);
+
+ mode = gegl_node_new_child (node,
+ "operation", "gimp:normal",
+ NULL);
+ gimp_gegl_mode_node_set_mode (mode,
+ GIMP_LAYER_MODE_NORMAL,
+ GIMP_LAYER_COLOR_SPACE_AUTO,
+ composite_space,
+ GIMP_LAYER_COMPOSITE_AUTO);
+
+ gegl_node_connect_to (input, "output",
+ mode, "aux");
+ gegl_node_connect_to (color, "output",
+ mode, "input");
+ gegl_node_connect_to (mode, "output",
+ output, "input");
+
+ return node;
+}
+
+GeglNode *
+gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
+ gint mask_offset_x,
+ gint mask_offset_y,
+ gdouble opacity)
+{
+ GeglNode *node;
+ GeglNode *input;
+ GeglNode *output;
+ GeglNode *opacity_node;
+ GeglNode *mask_source;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (mask), NULL);
+
+ node = gegl_node_new ();
+
+ input = gegl_node_get_input_proxy (node, "input");
+ output = gegl_node_get_output_proxy (node, "output");
+
+ opacity_node = gegl_node_new_child (node,
+ "operation", "gegl:opacity",
+ "value", opacity,
+ NULL);
+
+ gimp_gegl_node_set_underlying_operation (node, opacity_node);
+
+ mask_source = gimp_gegl_add_buffer_source (node, mask,
+ mask_offset_x,
+ mask_offset_y);
+
+ gegl_node_connect_to (input, "output",
+ opacity_node, "input");
+ gegl_node_connect_to (mask_source, "output",
+ opacity_node, "aux");
+ gegl_node_connect_to (opacity_node, "output",
+ output, "input");
+
+ return node;
+}
+
+GeglNode *
+gimp_gegl_create_transform_node (const GimpMatrix3 *matrix)
+{
+ GeglNode *node;
+
+ g_return_val_if_fail (matrix != NULL, NULL);
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:transform",
+ NULL);
+
+ gimp_gegl_node_set_matrix (node, matrix);
+
+ return node;
+}
+
+GeglNode *
+gimp_gegl_add_buffer_source (GeglNode *parent,
+ GeglBuffer *buffer,
+ gint offset_x,
+ gint offset_y)
+{
+ GeglNode *buffer_source;
+
+ g_return_val_if_fail (GEGL_IS_NODE (parent), NULL);
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
+
+ buffer_source = gegl_node_new_child (parent,
+ "operation", "gegl:buffer-source",
+ "buffer", buffer,
+ NULL);
+
+ if (offset_x != 0 || offset_y != 0)
+ {
+ GeglNode *translate =
+ gegl_node_new_child (parent,
+ "operation", "gegl:translate",
+ "x", (gdouble) offset_x,
+ "y", (gdouble) offset_y,
+ NULL);
+
+ gegl_node_connect_to (buffer_source, "output",
+ translate, "input");
+
+ buffer_source = translate;
+ }
+
+ return buffer_source;
+}
+
+void
+gimp_gegl_mode_node_set_mode (GeglNode *node,
+ GimpLayerMode mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode)
+{
+ gdouble opacity;
+
+ g_return_if_fail (GEGL_IS_NODE (node));
+
+ if (blend_space == GIMP_LAYER_COLOR_SPACE_AUTO)
+ blend_space = gimp_layer_mode_get_blend_space (mode);
+
+ if (composite_space == GIMP_LAYER_COLOR_SPACE_AUTO)
+ composite_space = gimp_layer_mode_get_composite_space (mode);
+
+ if (composite_mode == GIMP_LAYER_COMPOSITE_AUTO)
+ composite_mode = gimp_layer_mode_get_composite_mode (mode);
+
+ gegl_node_get (node,
+ "opacity", &opacity,
+ NULL);
+
+ /* setting the operation creates a new instance, so we have to set
+ * all its properties
+ */
+ gegl_node_set (node,
+ "operation", gimp_layer_mode_get_operation (mode),
+ "layer-mode", mode,
+ "opacity", opacity,
+ "blend-space", blend_space,
+ "composite-space", composite_space,
+ "composite-mode", composite_mode,
+ NULL);
+}
+
+void
+gimp_gegl_mode_node_set_opacity (GeglNode *node,
+ gdouble opacity)
+{
+ g_return_if_fail (GEGL_IS_NODE (node));
+
+ gegl_node_set (node,
+ "opacity", opacity,
+ NULL);
+}
+
+void
+gimp_gegl_node_set_matrix (GeglNode *node,
+ const GimpMatrix3 *matrix)
+{
+ gchar *matrix_string;
+
+ g_return_if_fail (GEGL_IS_NODE (node));
+ g_return_if_fail (matrix != NULL);
+
+ matrix_string = gegl_matrix3_to_string ((GeglMatrix3 *) matrix);
+
+ gegl_node_set (node,
+ "transform", matrix_string,
+ NULL);
+
+ g_free (matrix_string);
+}
+
+void
+gimp_gegl_node_set_color (GeglNode *node,
+ const GimpRGB *color)
+{
+ GeglColor *gegl_color;
+
+ g_return_if_fail (GEGL_IS_NODE (node));
+ g_return_if_fail (color != NULL);
+
+ gegl_color = gimp_gegl_color_new (color);
+
+ gegl_node_set (node,
+ "value", gegl_color,
+ NULL);
+
+ g_object_unref (gegl_color);
+}
diff --git a/app/gegl/gimp-gegl-nodes.h b/app/gegl/gimp-gegl-nodes.h
new file mode 100644
index 0000000..0f627ff
--- /dev/null
+++ b/app/gegl/gimp-gegl-nodes.h
@@ -0,0 +1,52 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-nodes.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_NODES_H__
+#define __GIMP_GEGL_NODES_H__
+
+
+GeglNode * gimp_gegl_create_flatten_node (const GimpRGB *background,
+ GimpLayerColorSpace composite_space);
+GeglNode * gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
+ gint mask_offset_x,
+ gint mask_offset_y,
+ gdouble opacity);
+GeglNode * gimp_gegl_create_transform_node (const GimpMatrix3 *matrix);
+
+GeglNode * gimp_gegl_add_buffer_source (GeglNode *parent,
+ GeglBuffer *buffer,
+ gint offset_x,
+ gint offset_y);
+
+void gimp_gegl_mode_node_set_mode (GeglNode *node,
+ GimpLayerMode mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode);
+void gimp_gegl_mode_node_set_opacity (GeglNode *node,
+ gdouble opacity);
+
+void gimp_gegl_node_set_matrix (GeglNode *node,
+ const GimpMatrix3 *matrix);
+void gimp_gegl_node_set_color (GeglNode *node,
+ const GimpRGB *color);
+
+
+#endif /* __GIMP_GEGL_NODES_H__ */
diff --git a/app/gegl/gimp-gegl-tile-compat.c b/app/gegl/gimp-gegl-tile-compat.c
new file mode 100644
index 0000000..54d917c
--- /dev/null
+++ b/app/gegl/gimp-gegl-tile-compat.c
@@ -0,0 +1,79 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-tile-compat.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-gegl-tile-compat.h"
+
+
+gint
+gimp_gegl_buffer_get_n_tile_rows (GeglBuffer *buffer,
+ gint tile_height)
+{
+ return (gegl_buffer_get_height (buffer) + tile_height - 1) / tile_height;
+}
+
+gint
+gimp_gegl_buffer_get_n_tile_cols (GeglBuffer *buffer,
+ gint tile_width)
+{
+ return (gegl_buffer_get_width (buffer) + tile_width - 1) / tile_width;
+}
+
+gboolean
+gimp_gegl_buffer_get_tile_rect (GeglBuffer *buffer,
+ gint tile_width,
+ gint tile_height,
+ gint tile_num,
+ GeglRectangle *rect)
+{
+ gint n_tile_rows;
+ gint n_tile_columns;
+ gint tile_row;
+ gint tile_column;
+
+ n_tile_rows = gimp_gegl_buffer_get_n_tile_rows (buffer, tile_height);
+ n_tile_columns = gimp_gegl_buffer_get_n_tile_cols (buffer, tile_width);
+
+ if (tile_num > n_tile_rows * n_tile_columns - 1)
+ return FALSE;
+
+ tile_row = tile_num / n_tile_columns;
+ tile_column = tile_num % n_tile_columns;
+
+ rect->x = tile_column * tile_width;
+ rect->y = tile_row * tile_height;
+
+ if (tile_column == n_tile_columns - 1)
+ rect->width = gegl_buffer_get_width (buffer) - rect->x;
+ else
+ rect->width = tile_width;
+
+ if (tile_row == n_tile_rows - 1)
+ rect->height = gegl_buffer_get_height (buffer) - rect->y;
+ else
+ rect->height = tile_height;
+
+ return TRUE;
+}
diff --git a/app/gegl/gimp-gegl-tile-compat.h b/app/gegl/gimp-gegl-tile-compat.h
new file mode 100644
index 0000000..e35f288
--- /dev/null
+++ b/app/gegl/gimp-gegl-tile-compat.h
@@ -0,0 +1,36 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-tile-compat.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_TILE_COMPAT_H__
+#define __GIMP_GEGL_TILE_COMPAT_H__
+
+
+gint gimp_gegl_buffer_get_n_tile_rows (GeglBuffer *buffer,
+ gint tile_height);
+gint gimp_gegl_buffer_get_n_tile_cols (GeglBuffer *buffer,
+ gint tile_width);
+gboolean gimp_gegl_buffer_get_tile_rect (GeglBuffer *buffer,
+ gint tile_width,
+ gint tile_height,
+ gint tile_num,
+ GeglRectangle *rect);
+
+
+#endif /* __GIMP_GEGL_TILE_COMPAT_H__ */
diff --git a/app/gegl/gimp-gegl-types.h b/app/gegl/gimp-gegl-types.h
new file mode 100644
index 0000000..ecea87e
--- /dev/null
+++ b/app/gegl/gimp-gegl-types.h
@@ -0,0 +1,34 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-types.h
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_TYPES_H__
+#define __GIMP_GEGL_TYPES_H__
+
+
+#include "core/core-types.h"
+
+#include "gegl/gimp-gegl-enums.h"
+
+#include "operations/operations-types.h"
+
+
+typedef struct _GimpApplicator GimpApplicator;
+
+
+#endif /* __GIMP_GEGL_TYPES_H__ */
diff --git a/app/gegl/gimp-gegl-utils.c b/app/gegl/gimp-gegl-utils.c
new file mode 100644
index 0000000..efc3a1e
--- /dev/null
+++ b/app/gegl/gimp-gegl-utils.c
@@ -0,0 +1,348 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-utils.h
+ * Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gegl-plugin.h>
+
+#include "gimp-gegl-types.h"
+
+#include "core/gimpprogress.h"
+
+#include "gimp-gegl-loops.h"
+#include "gimp-gegl-utils.h"
+
+
+GType
+gimp_gegl_get_op_enum_type (const gchar *operation,
+ const gchar *property)
+{
+ GeglNode *node;
+ GObject *op;
+ GParamSpec *pspec;
+
+ g_return_val_if_fail (operation != NULL, G_TYPE_NONE);
+ g_return_val_if_fail (property != NULL, G_TYPE_NONE);
+
+ node = g_object_new (GEGL_TYPE_NODE,
+ "operation", operation,
+ NULL);
+ g_object_get (node, "gegl-operation", &op, NULL);
+ g_object_unref (node);
+
+ g_return_val_if_fail (op != NULL, G_TYPE_NONE);
+
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (op), property);
+
+ g_return_val_if_fail (G_IS_PARAM_SPEC_ENUM (pspec), G_TYPE_NONE);
+
+ g_object_unref (op);
+
+ return G_TYPE_FROM_CLASS (G_PARAM_SPEC_ENUM (pspec)->enum_class);
+}
+
+GeglColor *
+gimp_gegl_color_new (const GimpRGB *rgb)
+{
+ GeglColor *color;
+
+ g_return_val_if_fail (rgb != NULL, NULL);
+
+ color = gegl_color_new (NULL);
+ gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb);
+
+ return color;
+}
+
+static void
+gimp_gegl_progress_callback (GObject *object,
+ gdouble value,
+ GimpProgress *progress)
+{
+ if (value == 0.0)
+ {
+ const gchar *text = g_object_get_data (object, "gimp-progress-text");
+
+ if (gimp_progress_is_active (progress))
+ gimp_progress_set_text (progress, "%s", text);
+ else
+ gimp_progress_start (progress, FALSE, "%s", text);
+ }
+ else
+ {
+ gimp_progress_set_value (progress, value);
+
+ if (value == 1.0)
+ gimp_progress_end (progress);
+ }
+}
+
+void
+gimp_gegl_progress_connect (GeglNode *node,
+ GimpProgress *progress,
+ const gchar *text)
+{
+ g_return_if_fail (GEGL_IS_NODE (node));
+ g_return_if_fail (GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (text != NULL);
+
+ g_signal_connect (node, "progress",
+ G_CALLBACK (gimp_gegl_progress_callback),
+ progress);
+
+ g_object_set_data_full (G_OBJECT (node),
+ "gimp-progress-text", g_strdup (text),
+ (GDestroyNotify) g_free);
+}
+
+gboolean
+gimp_gegl_node_is_source_operation (GeglNode *node)
+{
+ GeglOperation *operation;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
+
+ operation = gegl_node_get_gegl_operation (node);
+
+ if (! operation)
+ return FALSE;
+
+ return GEGL_IS_OPERATION_SOURCE (operation);
+}
+
+gboolean
+gimp_gegl_node_is_point_operation (GeglNode *node)
+{
+ GeglOperation *operation;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
+
+ operation = gegl_node_get_gegl_operation (node);
+
+ if (! operation)
+ return FALSE;
+
+ return GEGL_IS_OPERATION_POINT_RENDER (operation) ||
+ GEGL_IS_OPERATION_POINT_FILTER (operation) ||
+ GEGL_IS_OPERATION_POINT_COMPOSER (operation) ||
+ GEGL_IS_OPERATION_POINT_COMPOSER3 (operation);
+}
+
+gboolean
+gimp_gegl_node_is_area_filter_operation (GeglNode *node)
+{
+ GeglOperation *operation;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
+
+ operation = gegl_node_get_gegl_operation (node);
+
+ if (! operation)
+ return FALSE;
+
+ return GEGL_IS_OPERATION_AREA_FILTER (operation) ||
+ /* be conservative and return TRUE for meta ops, since they may
+ * involve an area op
+ */
+ GEGL_IS_OPERATION_META (operation);
+}
+
+const gchar *
+gimp_gegl_node_get_key (GeglNode *node,
+ const gchar *key)
+{
+ const gchar *operation_name;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
+
+ operation_name = gegl_node_get_operation (node);
+
+ if (operation_name)
+ return gegl_operation_get_key (operation_name, key);
+ else
+ return NULL;
+}
+
+gboolean
+gimp_gegl_node_has_key (GeglNode *node,
+ const gchar *key)
+{
+ return gimp_gegl_node_get_key (node, key) != NULL;
+}
+
+const Babl *
+gimp_gegl_node_get_format (GeglNode *node,
+ const gchar *pad_name)
+{
+ GeglOperation *op;
+ const Babl *format = NULL;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
+ g_return_val_if_fail (pad_name != NULL, NULL);
+
+ g_object_get (node, "gegl-operation", &op, NULL);
+
+ if (op)
+ {
+ format = gegl_operation_get_format (op, pad_name);
+
+ g_object_unref (op);
+ }
+
+ if (! format)
+ format = babl_format ("RGBA float");
+
+ return format;
+}
+
+void
+gimp_gegl_node_set_underlying_operation (GeglNode *node,
+ GeglNode *operation)
+{
+ g_return_if_fail (GEGL_IS_NODE (node));
+ g_return_if_fail (operation == NULL || GEGL_IS_NODE (operation));
+
+ g_object_set_data (G_OBJECT (node),
+ "gimp-gegl-node-underlying-operation", operation);
+}
+
+GeglNode *
+gimp_gegl_node_get_underlying_operation (GeglNode *node)
+{
+ GeglNode *operation;
+
+ g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
+
+ operation = g_object_get_data (G_OBJECT (node),
+ "gimp-gegl-node-underlying-operation");
+
+ if (operation)
+ return gimp_gegl_node_get_underlying_operation (operation);
+ else
+ return node;
+}
+
+gboolean
+gimp_gegl_param_spec_has_key (GParamSpec *pspec,
+ const gchar *key,
+ const gchar *value)
+{
+ const gchar *v = gegl_param_spec_get_property_key (pspec, key);
+
+ if (v && ! strcmp (v, value))
+ return TRUE;
+
+ return FALSE;
+}
+
+GeglBuffer *
+gimp_gegl_buffer_dup (GeglBuffer *buffer)
+{
+ GeglBuffer *new_buffer;
+ const GeglRectangle *extent;
+ const GeglRectangle *abyss;
+ GeglRectangle rect;
+ gint shift_x;
+ gint shift_y;
+ gint tile_width;
+ gint tile_height;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
+
+ extent = gegl_buffer_get_extent (buffer);
+ abyss = gegl_buffer_get_abyss (buffer);
+
+ g_object_get (buffer,
+ "shift-x", &shift_x,
+ "shift-y", &shift_y,
+ "tile-width", &tile_width,
+ "tile-height", &tile_height,
+ NULL);
+
+ new_buffer = g_object_new (GEGL_TYPE_BUFFER,
+ "format", gegl_buffer_get_format (buffer),
+ "x", extent->x,
+ "y", extent->y,
+ "width", extent->width,
+ "height", extent->height,
+ "abyss-x", abyss->x,
+ "abyss-y", abyss->y,
+ "abyss-width", abyss->width,
+ "abyss-height", abyss->height,
+ "shift-x", shift_x,
+ "shift-y", shift_y,
+ "tile-width", tile_width,
+ "tile-height", tile_height,
+ NULL);
+
+ gegl_rectangle_align_to_buffer (&rect, extent, buffer,
+ GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+
+ gimp_gegl_buffer_copy (buffer, &rect, GEGL_ABYSS_NONE,
+ new_buffer, &rect);
+
+ return new_buffer;
+}
+
+gboolean
+gimp_gegl_buffer_set_extent (GeglBuffer *buffer,
+ const GeglRectangle *extent)
+{
+ GeglRectangle aligned_old_extent;
+ GeglRectangle aligned_extent;
+ GeglRectangle old_extent_rem;
+ GeglRectangle diff_rects[4];
+ gint n_diff_rects;
+ gint i;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (extent != NULL, FALSE);
+
+ gegl_rectangle_align_to_buffer (&aligned_old_extent,
+ gegl_buffer_get_extent (buffer), buffer,
+ GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+ gegl_rectangle_align_to_buffer (&aligned_extent,
+ extent, buffer,
+ GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+
+ n_diff_rects = gegl_rectangle_subtract (diff_rects,
+ &aligned_old_extent,
+ &aligned_extent);
+
+ for (i = 0; i < n_diff_rects; i++)
+ gegl_buffer_clear (buffer, &diff_rects[i]);
+
+ if (gegl_rectangle_intersect (&old_extent_rem,
+ gegl_buffer_get_extent (buffer),
+ &aligned_extent))
+ {
+ n_diff_rects = gegl_rectangle_subtract (diff_rects,
+ &old_extent_rem,
+ extent);
+
+ for (i = 0; i < n_diff_rects; i++)
+ gegl_buffer_clear (buffer, &diff_rects[i]);
+ }
+
+ return gegl_buffer_set_extent (buffer, extent);
+}
diff --git a/app/gegl/gimp-gegl-utils.h b/app/gegl/gimp-gegl-utils.h
new file mode 100644
index 0000000..cee725f
--- /dev/null
+++ b/app/gegl/gimp-gegl-utils.h
@@ -0,0 +1,60 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl-utils.h
+ * Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_UTILS_H__
+#define __GIMP_GEGL_UTILS_H__
+
+
+GType gimp_gegl_get_op_enum_type (const gchar *operation,
+ const gchar *property);
+
+GeglColor * gimp_gegl_color_new (const GimpRGB *rgb);
+
+void gimp_gegl_progress_connect (GeglNode *node,
+ GimpProgress *progress,
+ const gchar *text);
+
+gboolean gimp_gegl_node_is_source_operation (GeglNode *node);
+gboolean gimp_gegl_node_is_point_operation (GeglNode *node);
+gboolean gimp_gegl_node_is_area_filter_operation (GeglNode *node);
+
+const gchar * gimp_gegl_node_get_key (GeglNode *node,
+ const gchar *key);
+gboolean gimp_gegl_node_has_key (GeglNode *node,
+ const gchar *key);
+
+const Babl * gimp_gegl_node_get_format (GeglNode *node,
+ const gchar *pad_name);
+
+void gimp_gegl_node_set_underlying_operation (GeglNode *node,
+ GeglNode *operation);
+GeglNode * gimp_gegl_node_get_underlying_operation (GeglNode *node);
+
+gboolean gimp_gegl_param_spec_has_key (GParamSpec *pspec,
+ const gchar *key,
+ const gchar *value);
+
+GeglBuffer * gimp_gegl_buffer_dup (GeglBuffer *buffer);
+
+gboolean gimp_gegl_buffer_set_extent (GeglBuffer *buffer,
+ const GeglRectangle *extent);
+
+
+#endif /* __GIMP_GEGL_UTILS_H__ */
diff --git a/app/gegl/gimp-gegl.c b/app/gegl/gimp-gegl.c
new file mode 100644
index 0000000..64046b6
--- /dev/null
+++ b/app/gegl/gimp-gegl.c
@@ -0,0 +1,171 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl.c
+ * Copyright (C) 2007 Øyvind Kolås <pippin@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "libgimpconfig/gimpconfig.h"
+
+#include "gimp-gegl-types.h"
+
+#include "config/gimpgeglconfig.h"
+
+#include "operations/gimp-operations.h"
+
+#include "core/gimp.h"
+#include "core/gimp-parallel.h"
+
+#include "gimp-babl.h"
+#include "gimp-gegl.h"
+
+#include <operation/gegl-operation.h>
+
+
+static void gimp_gegl_notify_temp_path (GimpGeglConfig *config);
+static void gimp_gegl_notify_swap_path (GimpGeglConfig *config);
+static void gimp_gegl_notify_swap_compression (GimpGeglConfig *config);
+static void gimp_gegl_notify_tile_cache_size (GimpGeglConfig *config);
+static void gimp_gegl_notify_num_processors (GimpGeglConfig *config);
+static void gimp_gegl_notify_use_opencl (GimpGeglConfig *config);
+
+
+/* public functions */
+
+void
+gimp_gegl_init (Gimp *gimp)
+{
+ GimpGeglConfig *config;
+
+ g_return_if_fail (GIMP_IS_GIMP (gimp));
+
+ config = GIMP_GEGL_CONFIG (gimp->config);
+
+ /* make sure temp and swap directories exist */
+ gimp_gegl_notify_temp_path (config);
+ gimp_gegl_notify_swap_path (config);
+
+ g_object_set (gegl_config (),
+ "swap-compression", config->swap_compression,
+ "tile-cache-size", (guint64) config->tile_cache_size,
+ "threads", config->num_processors,
+ "use-opencl", config->use_opencl,
+ NULL);
+
+ gimp_parallel_init (gimp);
+
+ g_signal_connect (config, "notify::temp-path",
+ G_CALLBACK (gimp_gegl_notify_temp_path),
+ NULL);
+ g_signal_connect (config, "notify::swap-path",
+ G_CALLBACK (gimp_gegl_notify_swap_path),
+ NULL);
+ g_signal_connect (config, "notify::swap-compression",
+ G_CALLBACK (gimp_gegl_notify_swap_compression),
+ NULL);
+ g_signal_connect (config, "notify::num-processors",
+ G_CALLBACK (gimp_gegl_notify_num_processors),
+ NULL);
+ g_signal_connect (config, "notify::tile-cache-size",
+ G_CALLBACK (gimp_gegl_notify_tile_cache_size),
+ NULL);
+ g_signal_connect (config, "notify::num-processors",
+ G_CALLBACK (gimp_gegl_notify_num_processors),
+ NULL);
+ g_signal_connect (config, "notify::use-opencl",
+ G_CALLBACK (gimp_gegl_notify_use_opencl),
+ NULL);
+
+ gimp_babl_init ();
+
+ gimp_operations_init (gimp);
+}
+
+void
+gimp_gegl_exit (Gimp *gimp)
+{
+ g_return_if_fail (GIMP_IS_GIMP (gimp));
+
+ gimp_parallel_exit (gimp);
+}
+
+
+/* private functions */
+
+static void
+gimp_gegl_notify_temp_path (GimpGeglConfig *config)
+{
+ GFile *file = gimp_file_new_for_config_path (config->temp_path, NULL);
+
+ if (! g_file_query_exists (file, NULL))
+ g_file_make_directory_with_parents (file, NULL, NULL);
+
+ g_object_unref (file);
+}
+
+static void
+gimp_gegl_notify_swap_path (GimpGeglConfig *config)
+{
+ GFile *file = gimp_file_new_for_config_path (config->swap_path, NULL);
+ gchar *path = g_file_get_path (file);
+
+ if (! g_file_query_exists (file, NULL))
+ g_file_make_directory_with_parents (file, NULL, NULL);
+
+ g_object_set (gegl_config (),
+ "swap", path,
+ NULL);
+
+ g_free (path);
+ g_object_unref (file);
+}
+
+static void
+gimp_gegl_notify_swap_compression (GimpGeglConfig *config)
+{
+ g_object_set (gegl_config (),
+ "swap-compression", config->swap_compression,
+ NULL);
+}
+
+static void
+gimp_gegl_notify_tile_cache_size (GimpGeglConfig *config)
+{
+ g_object_set (gegl_config (),
+ "tile-cache-size", (guint64) config->tile_cache_size,
+ NULL);
+}
+
+static void
+gimp_gegl_notify_num_processors (GimpGeglConfig *config)
+{
+ g_object_set (gegl_config (),
+ "threads", config->num_processors,
+ NULL);
+}
+
+static void
+gimp_gegl_notify_use_opencl (GimpGeglConfig *config)
+{
+ g_object_set (gegl_config (),
+ "use-opencl", config->use_opencl,
+ NULL);
+}
diff --git a/app/gegl/gimp-gegl.h b/app/gegl/gimp-gegl.h
new file mode 100644
index 0000000..a8e12c2
--- /dev/null
+++ b/app/gegl/gimp-gegl.h
@@ -0,0 +1,29 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-gegl.h
+ * Copyright (C) 2007 Øyvind Kolås <pippin@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_GEGL_H__
+#define __GIMP_GEGL_H__
+
+
+void gimp_gegl_init (Gimp *gimp);
+void gimp_gegl_exit (Gimp *gimp);
+
+
+#endif /* __GIMP_GEGL_H__ */
diff --git a/app/gegl/gimpapplicator.c b/app/gegl/gimpapplicator.c
new file mode 100644
index 0000000..ac8c2db
--- /dev/null
+++ b/app/gegl/gimpapplicator.c
@@ -0,0 +1,652 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpapplicator.c
+ * Copyright (C) 2012-2013 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "gimp-gegl-nodes.h"
+#include "gimpapplicator.h"
+
+
+static void gimp_applicator_finalize (GObject *object);
+static void gimp_applicator_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_applicator_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+G_DEFINE_TYPE (GimpApplicator, gimp_applicator, G_TYPE_OBJECT)
+
+#define parent_class gimp_applicator_parent_class
+
+
+static void
+gimp_applicator_class_init (GimpApplicatorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_applicator_finalize;
+ object_class->set_property = gimp_applicator_set_property;
+ object_class->get_property = gimp_applicator_get_property;
+}
+
+static void
+gimp_applicator_init (GimpApplicator *applicator)
+{
+ applicator->active = TRUE;
+ applicator->opacity = 1.0;
+ applicator->paint_mode = GIMP_LAYER_MODE_NORMAL;
+ applicator->blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
+ applicator->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
+ applicator->composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
+ applicator->affect = GIMP_COMPONENT_MASK_ALL;
+}
+
+static void
+gimp_applicator_finalize (GObject *object)
+{
+ GimpApplicator *applicator = GIMP_APPLICATOR (object);
+
+ g_clear_object (&applicator->node);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_applicator_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_applicator_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+GimpApplicator *
+gimp_applicator_new (GeglNode *parent)
+{
+ GimpApplicator *applicator;
+
+ g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL);
+
+ applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL);
+
+ if (parent)
+ applicator->node = g_object_ref (parent);
+ else
+ applicator->node = gegl_node_new ();
+
+ applicator->input_node =
+ gegl_node_get_input_proxy (applicator->node, "input");
+
+ applicator->aux_node =
+ gegl_node_get_input_proxy (applicator->node, "aux");
+
+ applicator->output_node =
+ gegl_node_get_output_proxy (applicator->node, "output");
+
+ applicator->mode_node = gegl_node_new_child (applicator->node,
+ "operation", "gimp:normal",
+ NULL);
+
+ gimp_gegl_mode_node_set_mode (applicator->mode_node,
+ applicator->paint_mode,
+ applicator->blend_space,
+ applicator->composite_space,
+ applicator->composite_mode);
+ gimp_gegl_mode_node_set_opacity (applicator->mode_node,
+ applicator->opacity);
+
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->mode_node, "input");
+
+ applicator->apply_offset_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:translate",
+ NULL);
+
+ gegl_node_link_many (applicator->aux_node,
+ applicator->apply_offset_node,
+ NULL);
+
+ gegl_node_connect_to (applicator->apply_offset_node, "output",
+ applicator->mode_node, "aux");
+
+ applicator->mask_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:buffer-source",
+ NULL);
+
+ applicator->mask_offset_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:translate",
+ NULL);
+
+ gegl_node_connect_to (applicator->mask_node, "output",
+ applicator->mask_offset_node, "input");
+ /* don't connect the the mask offset node to mode's aux2 yet */
+
+ applicator->affect_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gimp:mask-components",
+ "mask", applicator->affect,
+ NULL);
+
+ applicator->convert_format_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:nop",
+ NULL);
+
+ applicator->cache_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:nop",
+ NULL);
+
+ applicator->crop_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:nop",
+ NULL);
+
+ gegl_node_link_many (applicator->input_node,
+ applicator->affect_node,
+ applicator->convert_format_node,
+ applicator->cache_node,
+ applicator->crop_node,
+ applicator->output_node,
+ NULL);
+
+ gegl_node_connect_to (applicator->mode_node, "output",
+ applicator->affect_node, "aux");
+
+ return applicator;
+}
+
+void
+gimp_applicator_set_active (GimpApplicator *applicator,
+ gboolean active)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (active != applicator->active)
+ {
+ applicator->active = active;
+
+ if (active)
+ gegl_node_link (applicator->crop_node, applicator->output_node);
+ else
+ gegl_node_link (applicator->input_node, applicator->output_node);
+ }
+}
+
+void
+gimp_applicator_set_src_buffer (GimpApplicator *applicator,
+ GeglBuffer *src_buffer)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+ g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer));
+
+ if (src_buffer == applicator->src_buffer)
+ return;
+
+ if (src_buffer)
+ {
+ if (! applicator->src_node)
+ {
+ applicator->src_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:buffer-source",
+ "buffer", src_buffer,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->src_node,
+ "buffer", src_buffer,
+ NULL);
+ }
+
+ if (! applicator->src_buffer)
+ gegl_node_link (applicator->src_node, applicator->input_node);
+ }
+ else if (applicator->src_buffer)
+ {
+ gegl_node_disconnect (applicator->input_node, "input");
+
+ gegl_node_set (applicator->src_node,
+ "buffer", NULL,
+ NULL);
+ }
+
+ applicator->src_buffer = src_buffer;
+}
+
+void
+gimp_applicator_set_dest_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+ g_return_if_fail (dest_buffer == NULL || GEGL_IS_BUFFER (dest_buffer));
+
+ if (dest_buffer == applicator->dest_buffer)
+ return;
+
+ if (dest_buffer)
+ {
+ if (! applicator->dest_node)
+ {
+ applicator->dest_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:write-buffer",
+ "buffer", dest_buffer,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->dest_node,
+ "buffer", dest_buffer,
+ NULL);
+ }
+
+ if (! applicator->dest_buffer)
+ gegl_node_link (applicator->affect_node, applicator->dest_node);
+ }
+ else if (applicator->dest_buffer)
+ {
+ gegl_node_disconnect (applicator->dest_node, "input");
+
+ gegl_node_set (applicator->dest_node,
+ "buffer", NULL,
+ NULL);
+ }
+
+ applicator->dest_buffer = dest_buffer;
+}
+
+void
+gimp_applicator_set_mask_buffer (GimpApplicator *applicator,
+ GeglBuffer *mask_buffer)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+ g_return_if_fail (mask_buffer == NULL || GEGL_IS_BUFFER (mask_buffer));
+
+ if (applicator->mask_buffer == mask_buffer)
+ return;
+
+ gegl_node_set (applicator->mask_node,
+ "buffer", mask_buffer,
+ NULL);
+
+ if (mask_buffer)
+ {
+ gegl_node_connect_to (applicator->mask_offset_node, "output",
+ applicator->mode_node, "aux2");
+ }
+ else
+ {
+ gegl_node_disconnect (applicator->mode_node, "aux2");
+ }
+
+ applicator->mask_buffer = mask_buffer;
+}
+
+void
+gimp_applicator_set_mask_offset (GimpApplicator *applicator,
+ gint mask_offset_x,
+ gint mask_offset_y)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->mask_offset_x != mask_offset_x ||
+ applicator->mask_offset_y != mask_offset_y)
+ {
+ applicator->mask_offset_x = mask_offset_x;
+ applicator->mask_offset_y = mask_offset_y;
+
+ gegl_node_set (applicator->mask_offset_node,
+ "x", (gdouble) mask_offset_x,
+ "y", (gdouble) mask_offset_y,
+ NULL);
+ }
+}
+
+void
+gimp_applicator_set_apply_buffer (GimpApplicator *applicator,
+ GeglBuffer *apply_buffer)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+ g_return_if_fail (apply_buffer == NULL || GEGL_IS_BUFFER (apply_buffer));
+
+ if (apply_buffer == applicator->apply_buffer)
+ return;
+
+ if (apply_buffer)
+ {
+ if (! applicator->apply_src_node)
+ {
+ applicator->apply_src_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:buffer-source",
+ "buffer", apply_buffer,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->apply_src_node,
+ "buffer", apply_buffer,
+ NULL);
+ }
+
+ if (! applicator->apply_buffer)
+ {
+ gegl_node_connect_to (applicator->apply_src_node, "output",
+ applicator->apply_offset_node, "input");
+ }
+ }
+ else if (applicator->apply_buffer)
+ {
+ gegl_node_connect_to (applicator->aux_node, "output",
+ applicator->apply_offset_node, "input");
+ }
+
+ applicator->apply_buffer = apply_buffer;
+}
+
+void
+gimp_applicator_set_apply_offset (GimpApplicator *applicator,
+ gint apply_offset_x,
+ gint apply_offset_y)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->apply_offset_x != apply_offset_x ||
+ applicator->apply_offset_y != apply_offset_y)
+ {
+ applicator->apply_offset_x = apply_offset_x;
+ applicator->apply_offset_y = apply_offset_y;
+
+ gegl_node_set (applicator->apply_offset_node,
+ "x", (gdouble) apply_offset_x,
+ "y", (gdouble) apply_offset_y,
+ NULL);
+ }
+}
+
+void
+gimp_applicator_set_opacity (GimpApplicator *applicator,
+ gdouble opacity)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->opacity != opacity)
+ {
+ applicator->opacity = opacity;
+
+ gimp_gegl_mode_node_set_opacity (applicator->mode_node,
+ opacity);
+ }
+}
+
+void
+gimp_applicator_set_mode (GimpApplicator *applicator,
+ GimpLayerMode paint_mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->paint_mode != paint_mode ||
+ applicator->blend_space != blend_space ||
+ applicator->composite_space != composite_space ||
+ applicator->composite_mode != composite_mode)
+ {
+ applicator->paint_mode = paint_mode;
+ applicator->blend_space = blend_space;
+ applicator->composite_space = composite_space;
+ applicator->composite_mode = composite_mode;
+
+ gimp_gegl_mode_node_set_mode (applicator->mode_node,
+ paint_mode, blend_space,
+ composite_space, composite_mode);
+ }
+}
+
+void
+gimp_applicator_set_affect (GimpApplicator *applicator,
+ GimpComponentMask affect)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->affect != affect)
+ {
+ applicator->affect = affect;
+
+ gegl_node_set (applicator->affect_node,
+ "mask", affect,
+ NULL);
+ }
+}
+
+void
+gimp_applicator_set_output_format (GimpApplicator *applicator,
+ const Babl *format)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->output_format != format)
+ {
+ if (format)
+ {
+ if (! applicator->output_format)
+ {
+ gegl_node_set (applicator->convert_format_node,
+ "operation", "gegl:convert-format",
+ "format", format,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->convert_format_node,
+ "format", format,
+ NULL);
+ }
+ }
+ else
+ {
+ gegl_node_set (applicator->convert_format_node,
+ "operation", "gegl:nop",
+ NULL);
+ }
+
+ applicator->output_format = format;
+ }
+}
+
+const Babl *
+gimp_applicator_get_output_format (GimpApplicator *applicator)
+{
+ g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL);
+
+ return applicator->output_format;
+}
+
+void
+gimp_applicator_set_cache (GimpApplicator *applicator,
+ gboolean enable)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->cache_enabled != enable)
+ {
+ if (enable)
+ {
+ gegl_node_set (applicator->cache_node,
+ "operation", "gegl:cache",
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->cache_node,
+ "operation", "gegl:nop",
+ NULL);
+ }
+
+ applicator->cache_enabled = enable;
+ }
+}
+
+gboolean
+gimp_applicator_get_cache (GimpApplicator *applicator)
+{
+ g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), FALSE);
+
+ return applicator->cache_enabled;
+}
+
+gboolean gegl_buffer_list_valid_rectangles (GeglBuffer *buffer,
+ GeglRectangle **rectangles,
+ gint *n_rectangles);
+
+GeglBuffer *
+gimp_applicator_get_cache_buffer (GimpApplicator *applicator,
+ GeglRectangle **rectangles,
+ gint *n_rectangles)
+{
+ g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL);
+ g_return_val_if_fail (rectangles != NULL, NULL);
+ g_return_val_if_fail (n_rectangles != NULL, NULL);
+
+ if (applicator->cache_enabled)
+ {
+ GeglBuffer *cache;
+
+ gegl_node_get (applicator->cache_node,
+ "cache", &cache,
+ NULL);
+
+ if (cache)
+ {
+ if (gegl_buffer_list_valid_rectangles (cache,
+ rectangles, n_rectangles))
+ {
+ return cache;
+ }
+
+ g_object_unref (cache);
+ }
+ }
+
+ return NULL;
+}
+
+void
+gimp_applicator_set_crop (GimpApplicator *applicator,
+ const GeglRectangle *rect)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ if (applicator->crop_enabled != (rect != NULL) ||
+ (rect && ! gegl_rectangle_equal (&applicator->crop_rect, rect)))
+ {
+ if (rect)
+ {
+ if (! applicator->crop_enabled)
+ {
+ gegl_node_set (applicator->crop_node,
+ "operation", "gimp:compose-crop",
+ "x", rect->x,
+ "y", rect->y,
+ "width", rect->width,
+ "height", rect->height,
+ NULL);
+
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->crop_node, "aux");
+ }
+ else
+ {
+ gegl_node_set (applicator->crop_node,
+ "x", rect->x,
+ "y", rect->y,
+ "width", rect->width,
+ "height", rect->height,
+ NULL);
+ }
+
+ applicator->crop_enabled = TRUE;
+ applicator->crop_rect = *rect;
+ }
+ else
+ {
+ gegl_node_disconnect (applicator->crop_node, "aux");
+ gegl_node_set (applicator->crop_node,
+ "operation", "gegl:nop",
+ NULL);
+
+ applicator->crop_enabled = FALSE;
+ }
+ }
+}
+
+const GeglRectangle *
+gimp_applicator_get_crop (GimpApplicator *applicator)
+{
+ g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL);
+
+ if (applicator->crop_enabled)
+ return &applicator->crop_rect;
+
+ return NULL;
+}
+
+void
+gimp_applicator_blit (GimpApplicator *applicator,
+ const GeglRectangle *rect)
+{
+ g_return_if_fail (GIMP_IS_APPLICATOR (applicator));
+
+ gegl_node_blit (applicator->dest_node, 1.0, rect,
+ NULL, NULL, 0, GEGL_BLIT_DEFAULT);
+}
diff --git a/app/gegl/gimpapplicator.h b/app/gegl/gimpapplicator.h
new file mode 100644
index 0000000..e2919c2
--- /dev/null
+++ b/app/gegl/gimpapplicator.h
@@ -0,0 +1,146 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpapplicator.h
+ * Copyright (C) 2012-2013 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_APPLICATOR_H__
+#define __GIMP_APPLICATOR_H__
+
+
+#define GIMP_TYPE_APPLICATOR (gimp_applicator_get_type ())
+#define GIMP_APPLICATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_APPLICATOR, GimpApplicator))
+#define GIMP_APPLICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_APPLICATOR, GimpApplicatorClass))
+#define GIMP_IS_APPLICATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_APPLICATOR))
+#define GIMP_IS_APPLICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_APPLICATOR))
+#define GIMP_APPLICATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_APPLICATOR, GimpApplicatorClass))
+
+
+typedef struct _GimpApplicatorClass GimpApplicatorClass;
+
+struct _GimpApplicator
+{
+ GObject parent_instance;
+
+ GeglNode *node;
+ GeglNode *input_node;
+ GeglNode *aux_node;
+ GeglNode *output_node;
+
+ gboolean active;
+
+ GeglBuffer *apply_buffer;
+ GeglNode *apply_src_node;
+
+ gint apply_offset_x;
+ gint apply_offset_y;
+ GeglNode *apply_offset_node;
+
+ gdouble opacity;
+ GimpLayerMode paint_mode;
+ GimpLayerColorSpace blend_space;
+ GimpLayerColorSpace composite_space;
+ GimpLayerCompositeMode composite_mode;
+ GeglNode *mode_node;
+
+ GimpComponentMask affect;
+ GeglNode *affect_node;
+
+ const Babl *output_format;
+ GeglNode *convert_format_node;
+
+ gboolean cache_enabled;
+ GeglNode *cache_node;
+
+ gboolean crop_enabled;
+ GeglRectangle crop_rect;
+ GeglNode *crop_node;
+
+ GeglBuffer *src_buffer;
+ GeglNode *src_node;
+
+ GeglBuffer *dest_buffer;
+ GeglNode *dest_node;
+
+ GeglBuffer *mask_buffer;
+ GeglNode *mask_node;
+
+ gint mask_offset_x;
+ gint mask_offset_y;
+ GeglNode *mask_offset_node;
+};
+
+struct _GimpApplicatorClass
+{
+ GObjectClass parent_class;
+};
+
+
+GType gimp_applicator_get_type (void) G_GNUC_CONST;
+
+GimpApplicator * gimp_applicator_new (GeglNode *parent);
+
+void gimp_applicator_set_active (GimpApplicator *applicator,
+ gboolean active);
+
+void gimp_applicator_set_src_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer);
+void gimp_applicator_set_dest_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer);
+
+void gimp_applicator_set_mask_buffer (GimpApplicator *applicator,
+ GeglBuffer *mask_buffer);
+void gimp_applicator_set_mask_offset (GimpApplicator *applicator,
+ gint mask_offset_x,
+ gint mask_offset_y);
+
+void gimp_applicator_set_apply_buffer (GimpApplicator *applicator,
+ GeglBuffer *apply_buffer);
+void gimp_applicator_set_apply_offset (GimpApplicator *applicator,
+ gint apply_offset_x,
+ gint apply_offset_y);
+
+void gimp_applicator_set_opacity (GimpApplicator *applicator,
+ gdouble opacity);
+void gimp_applicator_set_mode (GimpApplicator *applicator,
+ GimpLayerMode paint_mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode);
+void gimp_applicator_set_affect (GimpApplicator *applicator,
+ GimpComponentMask affect);
+
+void gimp_applicator_set_output_format (GimpApplicator *applicator,
+ const Babl *format);
+const Babl * gimp_applicator_get_output_format (GimpApplicator *applicator);
+
+void gimp_applicator_set_cache (GimpApplicator *applicator,
+ gboolean enable);
+gboolean gimp_applicator_get_cache (GimpApplicator *applicator);
+GeglBuffer * gimp_applicator_get_cache_buffer (GimpApplicator *applicator,
+ GeglRectangle **rectangles,
+ gint *n_rectangles);
+
+void gimp_applicator_set_crop (GimpApplicator *applicator,
+ const GeglRectangle *rect);
+const GeglRectangle * gimp_applicator_get_crop (GimpApplicator *applicator);
+
+void gimp_applicator_blit (GimpApplicator *applicator,
+ const GeglRectangle *rect);
+
+
+#endif /* __GIMP_APPLICATOR_H__ */
diff --git a/app/gegl/gimptilehandlervalidate.c b/app/gegl/gimptilehandlervalidate.c
new file mode 100644
index 0000000..01915d5
--- /dev/null
+++ b/app/gegl/gimptilehandlervalidate.c
@@ -0,0 +1,766 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gegl.h>
+
+#include "gimp-gegl-types.h"
+
+#include "core/gimpchunkiterator.h"
+#include "core/gimpmarshal.h"
+
+#include "gimp-gegl-loops.h"
+#include "gimp-gegl-utils.h"
+#include "gimptilehandlervalidate.h"
+
+
+enum
+{
+ INVALIDATED,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_FORMAT,
+ PROP_TILE_WIDTH,
+ PROP_TILE_HEIGHT,
+ PROP_WHOLE_TILE
+};
+
+
+static void gimp_tile_handler_validate_finalize (GObject *object);
+static void gimp_tile_handler_validate_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_tile_handler_validate_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_tile_handler_validate_real_begin_validate (GimpTileHandlerValidate *validate);
+static void gimp_tile_handler_validate_real_end_validate (GimpTileHandlerValidate *validate);
+static void gimp_tile_handler_validate_real_validate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint dest_stride);
+static void gimp_tile_handler_validate_real_validate_buffer (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ GeglBuffer *buffer);
+
+static gpointer gimp_tile_handler_validate_command (GeglTileSource *source,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+
+
+G_DEFINE_TYPE (GimpTileHandlerValidate, gimp_tile_handler_validate,
+ GEGL_TYPE_TILE_HANDLER)
+
+#define parent_class gimp_tile_handler_validate_parent_class
+
+static guint gimp_tile_handler_validate_signals[LAST_SIGNAL];
+
+
+static void
+gimp_tile_handler_validate_class_init (GimpTileHandlerValidateClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ gimp_tile_handler_validate_signals[INVALIDATED] =
+ g_signal_new ("invalidated",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpTileHandlerValidateClass, invalidated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ GEGL_TYPE_RECTANGLE);
+
+ object_class->finalize = gimp_tile_handler_validate_finalize;
+ object_class->set_property = gimp_tile_handler_validate_set_property;
+ object_class->get_property = gimp_tile_handler_validate_get_property;
+
+ klass->begin_validate = gimp_tile_handler_validate_real_begin_validate;
+ klass->end_validate = gimp_tile_handler_validate_real_end_validate;
+ klass->validate = gimp_tile_handler_validate_real_validate;
+ klass->validate_buffer = gimp_tile_handler_validate_real_validate_buffer;
+
+ g_object_class_install_property (object_class, PROP_FORMAT,
+ g_param_spec_pointer ("format", NULL, NULL,
+ GIMP_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_TILE_WIDTH,
+ g_param_spec_int ("tile-width", NULL, NULL,
+ 1, G_MAXINT, 1,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_TILE_HEIGHT,
+ g_param_spec_int ("tile-height", NULL, NULL,
+ 1, G_MAXINT, 1,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_WHOLE_TILE,
+ g_param_spec_boolean ("whole-tile", NULL, NULL,
+ FALSE,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_tile_handler_validate_init (GimpTileHandlerValidate *validate)
+{
+ GeglTileSource *source = GEGL_TILE_SOURCE (validate);
+
+ source->command = gimp_tile_handler_validate_command;
+
+ validate->dirty_region = cairo_region_create ();
+}
+
+static void
+gimp_tile_handler_validate_finalize (GObject *object)
+{
+ GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object);
+
+ g_clear_object (&validate->graph);
+ g_clear_pointer (&validate->dirty_region, cairo_region_destroy);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_tile_handler_validate_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object);
+
+ switch (property_id)
+ {
+ case PROP_FORMAT:
+ validate->format = g_value_get_pointer (value);
+ break;
+ case PROP_TILE_WIDTH:
+ validate->tile_width = g_value_get_int (value);
+ break;
+ case PROP_TILE_HEIGHT:
+ validate->tile_height = g_value_get_int (value);
+ break;
+ case PROP_WHOLE_TILE:
+ validate->whole_tile = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_tile_handler_validate_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object);
+
+ switch (property_id)
+ {
+ case PROP_FORMAT:
+ g_value_set_pointer (value, (gpointer) validate->format);
+ break;
+ case PROP_TILE_WIDTH:
+ g_value_set_int (value, validate->tile_width);
+ break;
+ case PROP_TILE_HEIGHT:
+ g_value_set_int (value, validate->tile_height);
+ break;
+ case PROP_WHOLE_TILE:
+ g_value_set_boolean (value, validate->whole_tile);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_tile_handler_validate_real_begin_validate (GimpTileHandlerValidate *validate)
+{
+ validate->suspend_validate++;
+}
+
+static void
+gimp_tile_handler_validate_real_end_validate (GimpTileHandlerValidate *validate)
+{
+ validate->suspend_validate--;
+}
+
+static void
+gimp_tile_handler_validate_real_validate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint dest_stride)
+{
+#if 0
+ g_printerr ("validating at %d %d %d %d\n",
+ rect.x,
+ rect.y,
+ rect.width,
+ rect.height);
+#endif
+
+ gegl_node_blit (validate->graph, 1.0, rect, format,
+ dest_buf, dest_stride,
+ GEGL_BLIT_DEFAULT);
+}
+
+static void
+gimp_tile_handler_validate_real_validate_buffer (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ GeglBuffer *buffer)
+{
+ GimpTileHandlerValidateClass *klass;
+
+ klass = GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate);
+
+ if (klass->validate == gimp_tile_handler_validate_real_validate)
+ {
+ gegl_node_blit_buffer (validate->graph, buffer, rect, 0,
+ GEGL_ABYSS_NONE);
+ }
+ else
+ {
+ const Babl *format = gegl_buffer_get_format (buffer);
+ gpointer data;
+ gint stride;
+
+ data = gegl_buffer_linear_open (buffer, rect, &stride, format);
+
+ klass->validate (validate, rect, format, data, stride);
+
+ gegl_buffer_linear_close (buffer, data);
+ }
+}
+
+static GeglTile *
+gimp_tile_handler_validate_validate_tile (GeglTileSource *source,
+ gint x,
+ gint y)
+{
+ GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (source);
+ GeglTile *tile;
+ cairo_rectangle_int_t tile_rect;
+ cairo_region_overlap_t overlap;
+
+ if (validate->suspend_validate ||
+ cairo_region_is_empty (validate->dirty_region))
+ {
+ return gegl_tile_handler_source_command (source,
+ GEGL_TILE_GET, x, y, 0, NULL);
+ }
+
+ tile_rect.x = x * validate->tile_width;
+ tile_rect.y = y * validate->tile_height;
+ tile_rect.width = validate->tile_width;
+ tile_rect.height = validate->tile_height;
+
+ overlap = cairo_region_contains_rectangle (validate->dirty_region,
+ &tile_rect);
+
+ if (overlap == CAIRO_REGION_OVERLAP_OUT)
+ {
+ return gegl_tile_handler_source_command (source,
+ GEGL_TILE_GET, x, y, 0, NULL);
+ }
+
+ if (overlap == CAIRO_REGION_OVERLAP_IN || validate->whole_tile)
+ {
+ gint tile_bpp;
+ gint tile_stride;
+
+ cairo_region_subtract_rectangle (validate->dirty_region, &tile_rect);
+
+ tile_bpp = babl_format_get_bytes_per_pixel (validate->format);
+ tile_stride = tile_bpp * validate->tile_width;
+
+ tile = gegl_tile_handler_get_source_tile (GEGL_TILE_HANDLER (source),
+ x, y, 0, FALSE);
+
+ gimp_tile_handler_validate_begin_validate (validate);
+
+ gegl_tile_lock (tile);
+
+ GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->validate
+ (validate,
+ GEGL_RECTANGLE (tile_rect.x,
+ tile_rect.y,
+ tile_rect.width,
+ tile_rect.height),
+ validate->format,
+ gegl_tile_get_data (tile),
+ tile_stride);
+
+ gegl_tile_unlock (tile);
+
+ gimp_tile_handler_validate_end_validate (validate);
+ }
+ else
+ {
+ cairo_region_t *tile_region;
+ gint tile_bpp;
+ gint tile_stride;
+ gint n_rects;
+ gint i;
+
+ tile_region = cairo_region_copy (validate->dirty_region);
+ cairo_region_intersect_rectangle (tile_region, &tile_rect);
+
+ cairo_region_subtract_rectangle (validate->dirty_region, &tile_rect);
+
+ tile_bpp = babl_format_get_bytes_per_pixel (validate->format);
+ tile_stride = tile_bpp * validate->tile_width;
+
+ tile = gegl_tile_handler_source_command (source,
+ GEGL_TILE_GET, x, y, 0, NULL);
+
+ if (! tile)
+ {
+ tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (source),
+ x, y, 0);
+
+ memset (gegl_tile_get_data (tile),
+ 0, tile_stride * validate->tile_height);
+ }
+
+ gimp_tile_handler_validate_begin_validate (validate);
+
+ gegl_tile_lock (tile);
+
+ n_rects = cairo_region_num_rectangles (tile_region);
+
+#if 0
+ g_printerr ("%d chunks\n", n_rects);
+#endif
+
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t blit_rect;
+ gint tile_x;
+ gint tile_y;
+
+ cairo_region_get_rectangle (tile_region, i, &blit_rect);
+
+ tile_x = blit_rect.x % validate->tile_width;
+ if (tile_x < 0) tile_x += validate->tile_width;
+
+ tile_y = blit_rect.y % validate->tile_height;
+ if (tile_y < 0) tile_y += validate->tile_height;
+
+ GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->validate
+ (validate,
+ GEGL_RECTANGLE (blit_rect.x,
+ blit_rect.y,
+ blit_rect.width,
+ blit_rect.height),
+ validate->format,
+ gegl_tile_get_data (tile) +
+ tile_y * tile_stride +
+ tile_x * tile_bpp,
+ tile_stride);
+ }
+
+ gegl_tile_unlock (tile);
+
+ gimp_tile_handler_validate_end_validate (validate);
+
+ cairo_region_destroy (tile_region);
+ }
+
+ return tile;
+}
+
+static gpointer
+gimp_tile_handler_validate_command (GeglTileSource *source,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ if (command == GEGL_TILE_GET && z == 0)
+ return gimp_tile_handler_validate_validate_tile (source, x, y);
+
+ return gegl_tile_handler_source_command (source, command, x, y, z, data);
+}
+
+
+/* public functions */
+
+GeglTileHandler *
+gimp_tile_handler_validate_new (GeglNode *graph)
+{
+ GimpTileHandlerValidate *validate;
+
+ g_return_val_if_fail (GEGL_IS_NODE (graph), NULL);
+
+ validate = g_object_new (GIMP_TYPE_TILE_HANDLER_VALIDATE, NULL);
+
+ validate->graph = g_object_ref (graph);
+
+ return GEGL_TILE_HANDLER (validate);
+}
+
+void
+gimp_tile_handler_validate_assign (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+ g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) == NULL);
+
+ gegl_buffer_add_handler (buffer, validate);
+
+ g_object_get (buffer,
+ "format", &validate->format,
+ "tile-width", &validate->tile_width,
+ "tile-height", &validate->tile_height,
+ NULL);
+
+ g_object_set_data (G_OBJECT (buffer),
+ "gimp-tile-handler-validate", validate);
+}
+
+void
+gimp_tile_handler_validate_unassign (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+ g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) == validate);
+
+ g_object_set_data (G_OBJECT (buffer),
+ "gimp-tile-handler-validate", NULL);
+
+ gegl_buffer_remove_handler (buffer, validate);
+}
+
+GimpTileHandlerValidate *
+gimp_tile_handler_validate_get_assigned (GeglBuffer *buffer)
+{
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
+
+ return g_object_get_data (G_OBJECT (buffer),
+ "gimp-tile-handler-validate");
+}
+
+void
+gimp_tile_handler_validate_invalidate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (rect != NULL);
+
+ cairo_region_union_rectangle (validate->dirty_region,
+ (cairo_rectangle_int_t *) rect);
+
+ gegl_tile_handler_damage_rect (GEGL_TILE_HANDLER (validate), rect);
+
+ g_signal_emit (validate, gimp_tile_handler_validate_signals[INVALIDATED],
+ 0, rect, NULL);
+}
+
+void
+gimp_tile_handler_validate_undo_invalidate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (rect != NULL);
+
+ cairo_region_subtract_rectangle (validate->dirty_region,
+ (cairo_rectangle_int_t *) rect);
+}
+
+void
+gimp_tile_handler_validate_begin_validate (GimpTileHandlerValidate *validate)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+
+ if (validate->validating++ == 0)
+ GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->begin_validate (validate);
+}
+
+void
+gimp_tile_handler_validate_end_validate (GimpTileHandlerValidate *validate)
+{
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (validate->validating > 0);
+
+ if (--validate->validating == 0)
+ GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->end_validate (validate);
+}
+
+void
+gimp_tile_handler_validate_validate (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ gboolean intersect,
+ gboolean chunked)
+{
+ GimpTileHandlerValidateClass *klass;
+ cairo_region_t *region = NULL;
+
+ g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate));
+ g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) ==
+ validate);
+
+ klass = GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate);
+
+ if (! rect)
+ rect = gegl_buffer_get_extent (buffer);
+
+ if (intersect)
+ {
+ region = cairo_region_copy (validate->dirty_region);
+
+ cairo_region_intersect_rectangle (region,
+ (const cairo_rectangle_int_t *) rect);
+ }
+ else if (chunked)
+ {
+ region = cairo_region_create_rectangle (
+ (const cairo_rectangle_int_t *) rect);
+ }
+
+ if (region)
+ {
+ if (! cairo_region_is_empty (region))
+ {
+ gimp_tile_handler_validate_begin_validate (validate);
+
+ if (chunked)
+ {
+ GimpChunkIterator *iter;
+
+ iter = gimp_chunk_iterator_new (region);
+ region = NULL;
+
+ while (gimp_chunk_iterator_next (iter))
+ {
+ GeglRectangle blit_rect;
+
+ while (gimp_chunk_iterator_get_rect (iter, &blit_rect))
+ klass->validate_buffer (validate, &blit_rect, buffer);
+ }
+ }
+ else
+ {
+ gint n_rects;
+ gint i;
+
+ n_rects = cairo_region_num_rectangles (region);
+
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t blit_rect;
+
+ cairo_region_get_rectangle (region, i, &blit_rect);
+
+ klass->validate_buffer (validate,
+ (const GeglRectangle *) &blit_rect,
+ buffer);
+ }
+ }
+
+ gimp_tile_handler_validate_end_validate (validate);
+
+ cairo_region_subtract_rectangle (
+ validate->dirty_region,
+ (const cairo_rectangle_int_t *) rect);
+ }
+
+ g_clear_pointer (&region, cairo_region_destroy);
+ }
+ else
+ {
+ gimp_tile_handler_validate_begin_validate (validate);
+
+ klass->validate_buffer (validate, rect, buffer);
+
+ gimp_tile_handler_validate_end_validate (validate);
+
+ cairo_region_subtract_rectangle (
+ validate->dirty_region,
+ (const cairo_rectangle_int_t *) rect);
+ }
+}
+
+gboolean
+gimp_tile_handler_validate_buffer_set_extent (GeglBuffer *buffer,
+ const GeglRectangle *extent)
+{
+ GimpTileHandlerValidate *validate;
+
+ g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (extent != NULL, FALSE);
+
+ validate = gimp_tile_handler_validate_get_assigned (buffer);
+
+ g_return_val_if_fail (validate != NULL, FALSE);
+
+ validate->suspend_validate++;
+
+ if (gimp_gegl_buffer_set_extent (buffer, extent))
+ {
+ validate->suspend_validate--;
+
+ cairo_region_intersect_rectangle (validate->dirty_region,
+ (const cairo_rectangle_int_t *) extent);
+
+ return TRUE;
+ }
+
+ validate->suspend_validate--;
+
+ return FALSE;
+}
+
+void
+gimp_tile_handler_validate_buffer_copy (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dst_buffer,
+ const GeglRectangle *dst_rect)
+{
+ GimpTileHandlerValidate *src_validate;
+ GimpTileHandlerValidate *dst_validate;
+ GeglRectangle real_src_rect;
+ GeglRectangle real_dst_rect;
+
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (GEGL_IS_BUFFER (dst_buffer));
+ g_return_if_fail (src_rect != dst_rect);
+
+ src_validate = gimp_tile_handler_validate_get_assigned (src_buffer);
+ dst_validate = gimp_tile_handler_validate_get_assigned (dst_buffer);
+
+ g_return_if_fail (dst_validate != NULL);
+
+ if (! src_rect)
+ src_rect = gegl_buffer_get_extent (src_buffer);
+
+ if (! dst_rect)
+ dst_rect = src_rect;
+
+ real_src_rect = *src_rect;
+
+ gegl_rectangle_intersect (&real_dst_rect,
+ dst_rect, gegl_buffer_get_extent (dst_buffer));
+
+ real_src_rect.x += real_dst_rect.x - dst_rect->x;
+ real_src_rect.y += real_dst_rect.y - dst_rect->y;
+ real_src_rect.width -= real_dst_rect.x - dst_rect->x;
+ real_src_rect.height -= real_dst_rect.y - dst_rect->y;
+
+ real_src_rect.width = CLAMP (real_src_rect.width, 0, real_dst_rect.width);
+ real_src_rect.height = CLAMP (real_src_rect.height, 0, real_dst_rect.height);
+
+ /* temporarily remove the source buffer's validate handler, so that
+ * gegl_buffer_copy() can use fast tile copying, using the TILE_COPY command.
+ * currently, gegl only uses TILE_COPY when the source buffer has no user-
+ * provided tile handlers.
+ */
+ if (src_validate)
+ {
+ g_object_ref (src_validate);
+
+ gimp_tile_handler_validate_unassign (src_validate, src_buffer);
+ }
+
+ dst_validate->suspend_validate++;
+
+ gimp_gegl_buffer_copy (src_buffer, &real_src_rect, GEGL_ABYSS_NONE,
+ dst_buffer, &real_dst_rect);
+
+ dst_validate->suspend_validate--;
+
+ if (src_validate)
+ {
+ gimp_tile_handler_validate_assign (src_validate, src_buffer);
+
+ g_object_unref (src_validate);
+ }
+
+ cairo_region_subtract_rectangle (dst_validate->dirty_region,
+ (cairo_rectangle_int_t *) &real_dst_rect);
+
+ if (src_validate)
+ {
+ if (real_src_rect.x == real_dst_rect.x &&
+ real_src_rect.y == real_dst_rect.y &&
+ gegl_rectangle_equal (&real_src_rect,
+ gegl_buffer_get_extent (src_buffer)))
+ {
+ cairo_region_union (dst_validate->dirty_region,
+ src_validate->dirty_region);
+ }
+ else if (cairo_region_contains_rectangle (
+ src_validate->dirty_region,
+ (cairo_rectangle_int_t *) &real_src_rect) !=
+ CAIRO_REGION_OVERLAP_OUT)
+ {
+ cairo_region_t *region;
+
+ region = cairo_region_copy (src_validate->dirty_region);
+
+ if (! gegl_rectangle_equal (&real_src_rect,
+ gegl_buffer_get_extent (src_buffer)))
+ {
+ cairo_region_intersect_rectangle (
+ region, (cairo_rectangle_int_t *) &real_src_rect);
+ }
+
+ cairo_region_translate (region,
+ real_dst_rect.x - real_src_rect.x,
+ real_dst_rect.y - real_src_rect.y);
+
+ if (cairo_region_is_empty (dst_validate->dirty_region))
+ {
+ cairo_region_destroy (dst_validate->dirty_region);
+
+ dst_validate->dirty_region = region;
+ }
+ else
+ {
+ cairo_region_union (dst_validate->dirty_region, region);
+
+ cairo_region_destroy (region);
+ }
+ }
+ }
+}
diff --git a/app/gegl/gimptilehandlervalidate.h b/app/gegl/gimptilehandlervalidate.h
new file mode 100644
index 0000000..998430f
--- /dev/null
+++ b/app/gegl/gimptilehandlervalidate.h
@@ -0,0 +1,112 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_TILE_HANDLER_VALIDATE_H__
+#define __GIMP_TILE_HANDLER_VALIDATE_H__
+
+#include <gegl-buffer-backend.h>
+
+/***
+ * GimpTileHandlerValidate is a GeglTileHandler that renders the
+ * projection.
+ */
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_TILE_HANDLER_VALIDATE (gimp_tile_handler_validate_get_type ())
+#define GIMP_TILE_HANDLER_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidate))
+#define GIMP_TILE_HANDLER_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidateClass))
+#define GIMP_IS_TILE_HANDLER_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE))
+#define GIMP_IS_TILE_HANDLER_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TILE_HANDLER_VALIDATE))
+#define GIMP_TILE_HANDLER_VALIDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidateClass))
+
+
+typedef struct _GimpTileHandlerValidate GimpTileHandlerValidate;
+typedef struct _GimpTileHandlerValidateClass GimpTileHandlerValidateClass;
+
+struct _GimpTileHandlerValidate
+{
+ GeglTileHandler parent_instance;
+
+ GeglNode *graph;
+ cairo_region_t *dirty_region;
+ const Babl *format;
+ gint tile_width;
+ gint tile_height;
+ gboolean whole_tile;
+ gint validating;
+ gint suspend_validate;
+};
+
+struct _GimpTileHandlerValidateClass
+{
+ GeglTileHandlerClass parent_class;
+
+ /* signals */
+ void (* invalidated) (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect);
+
+ /* virtual functions */
+ void (* begin_validate) (GimpTileHandlerValidate *validate);
+ void (* end_validate) (GimpTileHandlerValidate *validate);
+ void (* validate) (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint dest_stride);
+ void (* validate_buffer) (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect,
+ GeglBuffer *buffer);
+};
+
+
+GType gimp_tile_handler_validate_get_type (void) G_GNUC_CONST;
+
+GeglTileHandler * gimp_tile_handler_validate_new (GeglNode *graph);
+
+void gimp_tile_handler_validate_assign (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer);
+void gimp_tile_handler_validate_unassign (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer);
+GimpTileHandlerValidate * gimp_tile_handler_validate_get_assigned (GeglBuffer *buffer);
+
+void gimp_tile_handler_validate_invalidate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect);
+void gimp_tile_handler_validate_undo_invalidate (GimpTileHandlerValidate *validate,
+ const GeglRectangle *rect);
+
+void gimp_tile_handler_validate_begin_validate (GimpTileHandlerValidate *validate);
+void gimp_tile_handler_validate_end_validate (GimpTileHandlerValidate *validate);
+
+void gimp_tile_handler_validate_validate (GimpTileHandlerValidate *validate,
+ GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ gboolean intersect,
+ gboolean chunked);
+
+gboolean gimp_tile_handler_validate_buffer_set_extent (GeglBuffer *buffer,
+ const GeglRectangle *extent);
+
+void gimp_tile_handler_validate_buffer_copy (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dst_buffer,
+ const GeglRectangle *dst_rect);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_TILE_HANDLER_VALIDATE_H__ */