summaryrefslogtreecommitdiffstats
path: root/app/operations/layer-modes
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
commit3c57dd931145d43f2b0aef96c4d178135956bf91 (patch)
tree3de698981e9f0cc2c4f9569b19a5f3595e741f6b /app/operations/layer-modes
parentInitial commit. (diff)
downloadgimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz
gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'app/operations/layer-modes')
-rw-r--r--app/operations/layer-modes/Makefile.am79
-rw-r--r--app/operations/layer-modes/Makefile.in1115
-rw-r--r--app/operations/layer-modes/gimp-layer-modes.c1522
-rw-r--r--app/operations/layer-modes/gimp-layer-modes.h73
-rw-r--r--app/operations/layer-modes/gimpoperationantierase.c188
-rw-r--r--app/operations/layer-modes/gimpoperationantierase.h53
-rw-r--r--app/operations/layer-modes/gimpoperationbehind.c236
-rw-r--r--app/operations/layer-modes/gimpoperationbehind.h53
-rw-r--r--app/operations/layer-modes/gimpoperationdissolve.c175
-rw-r--r--app/operations/layer-modes/gimpoperationdissolve.h53
-rw-r--r--app/operations/layer-modes/gimpoperationerase.c214
-rw-r--r--app/operations/layer-modes/gimpoperationerase.h53
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode-blend.c1215
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode-blend.h200
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c105
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode-composite.c434
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode-composite.h98
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode.c914
-rw-r--r--app/operations/layer-modes/gimpoperationlayermode.h89
-rw-r--r--app/operations/layer-modes/gimpoperationmerge.c243
-rw-r--r--app/operations/layer-modes/gimpoperationmerge.h54
-rw-r--r--app/operations/layer-modes/gimpoperationnormal-sse2.c264
-rw-r--r--app/operations/layer-modes/gimpoperationnormal-sse4.c260
-rw-r--r--app/operations/layer-modes/gimpoperationnormal.c266
-rw-r--r--app/operations/layer-modes/gimpoperationnormal.h91
-rw-r--r--app/operations/layer-modes/gimpoperationpassthrough.c55
-rw-r--r--app/operations/layer-modes/gimpoperationpassthrough.h54
-rw-r--r--app/operations/layer-modes/gimpoperationreplace.c347
-rw-r--r--app/operations/layer-modes/gimpoperationreplace.h53
-rw-r--r--app/operations/layer-modes/gimpoperationsplit.c213
-rw-r--r--app/operations/layer-modes/gimpoperationsplit.h54
31 files changed, 8823 insertions, 0 deletions
diff --git a/app/operations/layer-modes/Makefile.am b/app/operations/layer-modes/Makefile.am
new file mode 100644
index 0000000..24af8fe
--- /dev/null
+++ b/app/operations/layer-modes/Makefile.am
@@ -0,0 +1,79 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"Gimp-Layer-Modes\" \
+ -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 = \
+ libapplayermodes-generic.a \
+ libapplayermodes-sse2.a \
+ libapplayermodes-sse4.a \
+ libapplayermodes.a
+
+libapplayermodes_generic_a_sources = \
+ gimp-layer-modes.c \
+ gimp-layer-modes.h \
+ \
+ gimpoperationlayermode.c \
+ gimpoperationlayermode.h \
+ gimpoperationlayermode-blend.c \
+ gimpoperationlayermode-blend.h \
+ gimpoperationlayermode-composite.c \
+ gimpoperationlayermode-composite.h \
+ \
+ gimpoperationantierase.c \
+ gimpoperationantierase.h \
+ gimpoperationbehind.c \
+ gimpoperationbehind.h \
+ gimpoperationdissolve.c \
+ gimpoperationdissolve.h \
+ gimpoperationerase.c \
+ gimpoperationerase.h \
+ gimpoperationmerge.c \
+ gimpoperationmerge.h \
+ gimpoperationnormal.c \
+ gimpoperationnormal.h \
+ gimpoperationpassthrough.c \
+ gimpoperationpassthrough.h \
+ gimpoperationreplace.c \
+ gimpoperationreplace.h \
+ gimpoperationsplit.c \
+ gimpoperationsplit.h
+
+libapplayermodes_sse2_a_sources = \
+ gimpoperationlayermode-composite-sse2.c \
+ \
+ gimpoperationnormal-sse2.c
+
+libapplayermodes_sse4_a_sources = \
+ gimpoperationnormal-sse4.c
+
+
+libapplayermodes_generic_a_SOURCES = $(libapplayermodes_generic_a_sources)
+
+libapplayermodes_sse2_a_SOURCES = $(libapplayermodes_sse2_a_sources)
+
+libapplayermodes_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS)
+
+libapplayermodes_sse4_a_SOURCES = $(libapplayermodes_sse4_a_sources)
+
+libapplayermodes_sse4_a_CFLAGS = $(SSE4_1_EXTRA_CFLAGS)
+
+libapplayermodes_a_SOURCES =
+
+
+libapplayermodes.a: libapplayermodes-generic.a \
+ libapplayermodes-sse2.a \
+ libapplayermodes-sse4.a
+ $(AR) $(ARFLAGS) libapplayermodes.a \
+ $(libapplayermodes_generic_a_OBJECTS) \
+ $(libapplayermodes_sse2_a_OBJECTS) \
+ $(libapplayermodes_sse4_a_OBJECTS)
+ $(RANLIB) libapplayermodes.a
diff --git a/app/operations/layer-modes/Makefile.in b/app/operations/layer-modes/Makefile.in
new file mode 100644
index 0000000..ad8d4c1
--- /dev/null
+++ b/app/operations/layer-modes/Makefile.in
@@ -0,0 +1,1115 @@
+# 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/operations/layer-modes
+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 =
+libapplayermodes_generic_a_AR = $(AR) $(ARFLAGS)
+libapplayermodes_generic_a_LIBADD =
+am__objects_1 = gimp-layer-modes.$(OBJEXT) \
+ gimpoperationlayermode.$(OBJEXT) \
+ gimpoperationlayermode-blend.$(OBJEXT) \
+ gimpoperationlayermode-composite.$(OBJEXT) \
+ gimpoperationantierase.$(OBJEXT) gimpoperationbehind.$(OBJEXT) \
+ gimpoperationdissolve.$(OBJEXT) gimpoperationerase.$(OBJEXT) \
+ gimpoperationmerge.$(OBJEXT) gimpoperationnormal.$(OBJEXT) \
+ gimpoperationpassthrough.$(OBJEXT) \
+ gimpoperationreplace.$(OBJEXT) gimpoperationsplit.$(OBJEXT)
+am_libapplayermodes_generic_a_OBJECTS = $(am__objects_1)
+libapplayermodes_generic_a_OBJECTS = \
+ $(am_libapplayermodes_generic_a_OBJECTS)
+libapplayermodes_sse2_a_AR = $(AR) $(ARFLAGS)
+libapplayermodes_sse2_a_LIBADD =
+am__objects_2 = libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.$(OBJEXT) \
+ libapplayermodes_sse2_a-gimpoperationnormal-sse2.$(OBJEXT)
+am_libapplayermodes_sse2_a_OBJECTS = $(am__objects_2)
+libapplayermodes_sse2_a_OBJECTS = \
+ $(am_libapplayermodes_sse2_a_OBJECTS)
+libapplayermodes_sse4_a_AR = $(AR) $(ARFLAGS)
+libapplayermodes_sse4_a_LIBADD =
+am__objects_3 = \
+ libapplayermodes_sse4_a-gimpoperationnormal-sse4.$(OBJEXT)
+am_libapplayermodes_sse4_a_OBJECTS = $(am__objects_3)
+libapplayermodes_sse4_a_OBJECTS = \
+ $(am_libapplayermodes_sse4_a_OBJECTS)
+libapplayermodes_a_AR = $(AR) $(ARFLAGS)
+libapplayermodes_a_LIBADD =
+am_libapplayermodes_a_OBJECTS =
+libapplayermodes_a_OBJECTS = $(am_libapplayermodes_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-layer-modes.Po \
+ ./$(DEPDIR)/gimpoperationantierase.Po \
+ ./$(DEPDIR)/gimpoperationbehind.Po \
+ ./$(DEPDIR)/gimpoperationdissolve.Po \
+ ./$(DEPDIR)/gimpoperationerase.Po \
+ ./$(DEPDIR)/gimpoperationlayermode-blend.Po \
+ ./$(DEPDIR)/gimpoperationlayermode-composite.Po \
+ ./$(DEPDIR)/gimpoperationlayermode.Po \
+ ./$(DEPDIR)/gimpoperationmerge.Po \
+ ./$(DEPDIR)/gimpoperationnormal.Po \
+ ./$(DEPDIR)/gimpoperationpassthrough.Po \
+ ./$(DEPDIR)/gimpoperationreplace.Po \
+ ./$(DEPDIR)/gimpoperationsplit.Po \
+ ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po \
+ ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po \
+ ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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 =
+SOURCES = $(libapplayermodes_generic_a_SOURCES) \
+ $(libapplayermodes_sse2_a_SOURCES) \
+ $(libapplayermodes_sse4_a_SOURCES) \
+ $(libapplayermodes_a_SOURCES)
+DIST_SOURCES = $(libapplayermodes_generic_a_SOURCES) \
+ $(libapplayermodes_sse2_a_SOURCES) \
+ $(libapplayermodes_sse4_a_SOURCES) \
+ $(libapplayermodes_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-Layer-Modes\" \
+ -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 = \
+ libapplayermodes-generic.a \
+ libapplayermodes-sse2.a \
+ libapplayermodes-sse4.a \
+ libapplayermodes.a
+
+libapplayermodes_generic_a_sources = \
+ gimp-layer-modes.c \
+ gimp-layer-modes.h \
+ \
+ gimpoperationlayermode.c \
+ gimpoperationlayermode.h \
+ gimpoperationlayermode-blend.c \
+ gimpoperationlayermode-blend.h \
+ gimpoperationlayermode-composite.c \
+ gimpoperationlayermode-composite.h \
+ \
+ gimpoperationantierase.c \
+ gimpoperationantierase.h \
+ gimpoperationbehind.c \
+ gimpoperationbehind.h \
+ gimpoperationdissolve.c \
+ gimpoperationdissolve.h \
+ gimpoperationerase.c \
+ gimpoperationerase.h \
+ gimpoperationmerge.c \
+ gimpoperationmerge.h \
+ gimpoperationnormal.c \
+ gimpoperationnormal.h \
+ gimpoperationpassthrough.c \
+ gimpoperationpassthrough.h \
+ gimpoperationreplace.c \
+ gimpoperationreplace.h \
+ gimpoperationsplit.c \
+ gimpoperationsplit.h
+
+libapplayermodes_sse2_a_sources = \
+ gimpoperationlayermode-composite-sse2.c \
+ \
+ gimpoperationnormal-sse2.c
+
+libapplayermodes_sse4_a_sources = \
+ gimpoperationnormal-sse4.c
+
+libapplayermodes_generic_a_SOURCES = $(libapplayermodes_generic_a_sources)
+libapplayermodes_sse2_a_SOURCES = $(libapplayermodes_sse2_a_sources)
+libapplayermodes_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS)
+libapplayermodes_sse4_a_SOURCES = $(libapplayermodes_sse4_a_sources)
+libapplayermodes_sse4_a_CFLAGS = $(SSE4_1_EXTRA_CFLAGS)
+libapplayermodes_a_SOURCES =
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .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/operations/layer-modes/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu app/operations/layer-modes/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)
+
+libapplayermodes-generic.a: $(libapplayermodes_generic_a_OBJECTS) $(libapplayermodes_generic_a_DEPENDENCIES) $(EXTRA_libapplayermodes_generic_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libapplayermodes-generic.a
+ $(AM_V_AR)$(libapplayermodes_generic_a_AR) libapplayermodes-generic.a $(libapplayermodes_generic_a_OBJECTS) $(libapplayermodes_generic_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libapplayermodes-generic.a
+
+libapplayermodes-sse2.a: $(libapplayermodes_sse2_a_OBJECTS) $(libapplayermodes_sse2_a_DEPENDENCIES) $(EXTRA_libapplayermodes_sse2_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libapplayermodes-sse2.a
+ $(AM_V_AR)$(libapplayermodes_sse2_a_AR) libapplayermodes-sse2.a $(libapplayermodes_sse2_a_OBJECTS) $(libapplayermodes_sse2_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libapplayermodes-sse2.a
+
+libapplayermodes-sse4.a: $(libapplayermodes_sse4_a_OBJECTS) $(libapplayermodes_sse4_a_DEPENDENCIES) $(EXTRA_libapplayermodes_sse4_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libapplayermodes-sse4.a
+ $(AM_V_AR)$(libapplayermodes_sse4_a_AR) libapplayermodes-sse4.a $(libapplayermodes_sse4_a_OBJECTS) $(libapplayermodes_sse4_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libapplayermodes-sse4.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-layer-modes.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationantierase.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationbehind.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdissolve.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationerase.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode-blend.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode-composite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationmerge.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationnormal.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationpassthrough.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationreplace.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsplit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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 $@ $<
+
+libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o: gimpoperationlayermode-composite-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o `test -f 'gimpoperationlayermode-composite-sse2.c' || echo '$(srcdir)/'`gimpoperationlayermode-composite-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationlayermode-composite-sse2.c' object='libapplayermodes_sse2_a-gimpoperationlayermode-composite-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) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o `test -f 'gimpoperationlayermode-composite-sse2.c' || echo '$(srcdir)/'`gimpoperationlayermode-composite-sse2.c
+
+libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj: gimpoperationlayermode-composite-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj `if test -f 'gimpoperationlayermode-composite-sse2.c'; then $(CYGPATH_W) 'gimpoperationlayermode-composite-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationlayermode-composite-sse2.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationlayermode-composite-sse2.c' object='libapplayermodes_sse2_a-gimpoperationlayermode-composite-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) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj `if test -f 'gimpoperationlayermode-composite-sse2.c'; then $(CYGPATH_W) 'gimpoperationlayermode-composite-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationlayermode-composite-sse2.c'; fi`
+
+libapplayermodes_sse2_a-gimpoperationnormal-sse2.o: gimpoperationnormal-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationnormal-sse2.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.o `test -f 'gimpoperationnormal-sse2.c' || echo '$(srcdir)/'`gimpoperationnormal-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse2.c' object='libapplayermodes_sse2_a-gimpoperationnormal-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) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.o `test -f 'gimpoperationnormal-sse2.c' || echo '$(srcdir)/'`gimpoperationnormal-sse2.c
+
+libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj: gimpoperationnormal-sse2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj `if test -f 'gimpoperationnormal-sse2.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse2.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse2.c' object='libapplayermodes_sse2_a-gimpoperationnormal-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) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj `if test -f 'gimpoperationnormal-sse2.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse2.c'; fi`
+
+libapplayermodes_sse4_a-gimpoperationnormal-sse4.o: gimpoperationnormal-sse4.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse4_a-gimpoperationnormal-sse4.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.o `test -f 'gimpoperationnormal-sse4.c' || echo '$(srcdir)/'`gimpoperationnormal-sse4.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse4.c' object='libapplayermodes_sse4_a-gimpoperationnormal-sse4.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) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.o `test -f 'gimpoperationnormal-sse4.c' || echo '$(srcdir)/'`gimpoperationnormal-sse4.c
+
+libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj: gimpoperationnormal-sse4.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj `if test -f 'gimpoperationnormal-sse4.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse4.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse4.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse4.c' object='libapplayermodes_sse4_a-gimpoperationnormal-sse4.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) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj `if test -f 'gimpoperationnormal-sse4.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse4.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse4.c'; fi`
+
+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:
+
+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-layer-modes.Po
+ -rm -f ./$(DEPDIR)/gimpoperationantierase.Po
+ -rm -f ./$(DEPDIR)/gimpoperationbehind.Po
+ -rm -f ./$(DEPDIR)/gimpoperationdissolve.Po
+ -rm -f ./$(DEPDIR)/gimpoperationerase.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode-blend.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode-composite.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode.Po
+ -rm -f ./$(DEPDIR)/gimpoperationmerge.Po
+ -rm -f ./$(DEPDIR)/gimpoperationnormal.Po
+ -rm -f ./$(DEPDIR)/gimpoperationpassthrough.Po
+ -rm -f ./$(DEPDIR)/gimpoperationreplace.Po
+ -rm -f ./$(DEPDIR)/gimpoperationsplit.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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-layer-modes.Po
+ -rm -f ./$(DEPDIR)/gimpoperationantierase.Po
+ -rm -f ./$(DEPDIR)/gimpoperationbehind.Po
+ -rm -f ./$(DEPDIR)/gimpoperationdissolve.Po
+ -rm -f ./$(DEPDIR)/gimpoperationerase.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode-blend.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode-composite.Po
+ -rm -f ./$(DEPDIR)/gimpoperationlayermode.Po
+ -rm -f ./$(DEPDIR)/gimpoperationmerge.Po
+ -rm -f ./$(DEPDIR)/gimpoperationnormal.Po
+ -rm -f ./$(DEPDIR)/gimpoperationpassthrough.Po
+ -rm -f ./$(DEPDIR)/gimpoperationreplace.Po
+ -rm -f ./$(DEPDIR)/gimpoperationsplit.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po
+ -rm -f ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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
+
+
+libapplayermodes.a: libapplayermodes-generic.a \
+ libapplayermodes-sse2.a \
+ libapplayermodes-sse4.a
+ $(AR) $(ARFLAGS) libapplayermodes.a \
+ $(libapplayermodes_generic_a_OBJECTS) \
+ $(libapplayermodes_sse2_a_OBJECTS) \
+ $(libapplayermodes_sse4_a_OBJECTS)
+ $(RANLIB) libapplayermodes.a
+
+# 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/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
new file mode 100644
index 0000000..deb1f3d
--- /dev/null
+++ b/app/operations/layer-modes/gimp-layer-modes.c
@@ -0,0 +1,1522 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-layer-modes.c
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * Ø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 <glib-object.h>
+#include <gegl.h>
+
+#include "../operations-types.h"
+
+#include "gegl/gimp-babl.h"
+
+#include "gimpoperationlayermode.h"
+#include "gimpoperationlayermode-blend.h"
+
+#include "gimp-layer-modes.h"
+
+
+typedef struct _GimpLayerModeInfo GimpLayerModeInfo;
+
+struct _GimpLayerModeInfo
+{
+ GimpLayerMode layer_mode;
+ const gchar *op_name;
+ GimpLayerModeBlendFunc blend_function;
+ GimpLayerModeFlags flags;
+ GimpLayerModeContext context;
+ GimpLayerCompositeMode paint_composite_mode;
+ GimpLayerCompositeMode composite_mode;
+ GimpLayerColorSpace composite_space;
+ GimpLayerColorSpace blend_space;
+};
+
+
+/* static variables */
+
+static const GimpLayerModeInfo layer_mode_infos[] =
+{
+ { GIMP_LAYER_MODE_NORMAL_LEGACY,
+
+ .op_name = "gimp:normal",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DISSOLVE,
+
+ .op_name = "gimp:dissolve",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION
+ },
+
+ { GIMP_LAYER_MODE_BEHIND_LEGACY,
+
+ .op_name = "gimp:behind",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_PAINT |
+ GIMP_LAYER_MODE_CONTEXT_FILTER,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_MULTIPLY_LEGACY,
+
+ .op_name = "gimp:multiply-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_SCREEN_LEGACY,
+
+ .op_name = "gimp:screen-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_OVERLAY_LEGACY,
+
+ .op_name = "gimp:softlight-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
+
+ .op_name = "gimp:difference-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_ADDITION_LEGACY,
+
+ .op_name = "gimp:addition-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_SUBTRACT_LEGACY,
+
+ .op_name = "gimp:subtract-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
+
+ .op_name = "gimp:darken-only-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
+
+ .op_name = "gimp:lighten-only-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSV_HUE_LEGACY,
+
+ .op_name = "gimp:hsv-hue-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
+
+ .op_name = "gimp:hsv-saturation-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
+
+ .op_name = "gimp:hsl-color-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSV_VALUE_LEGACY,
+
+ .op_name = "gimp:hsv-value-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DIVIDE_LEGACY,
+
+ .op_name = "gimp:divide-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DODGE_LEGACY,
+
+ .op_name = "gimp:dodge-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_BURN_LEGACY,
+
+ .op_name = "gimp:burn-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
+
+ .op_name = "gimp:hardlight-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
+
+ .op_name = "gimp:softlight-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
+
+ .op_name = "gimp:grain-extract-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
+
+ .op_name = "gimp:grain-merge-legacy",
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_color_erase,
+ .flags = GIMP_LAYER_MODE_FLAG_LEGACY |
+ GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_SUBTRACTIVE,
+ .context = GIMP_LAYER_MODE_CONTEXT_PAINT |
+ GIMP_LAYER_MODE_CONTEXT_FILTER,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_OVERLAY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_overlay,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LCH_HUE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_lch_hue,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_LAB
+ },
+
+ { GIMP_LAYER_MODE_LCH_CHROMA,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_lch_chroma,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_LAB
+ },
+
+ { GIMP_LAYER_MODE_LCH_COLOR,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_lch_color,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_LAB
+ },
+
+ { GIMP_LAYER_MODE_LCH_LIGHTNESS,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_lch_lightness,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_LAB
+ },
+
+ { GIMP_LAYER_MODE_NORMAL,
+
+ .op_name = "gimp:normal",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_BEHIND,
+
+ .op_name = "gimp:behind",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_PAINT |
+ GIMP_LAYER_MODE_CONTEXT_FILTER,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_MULTIPLY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_multiply,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_SCREEN,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_screen,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DIFFERENCE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_difference,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_ADDITION,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_addition,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_SUBTRACT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_subtract,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_DARKEN_ONLY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_darken_only,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ /* no blend_space: reuse composite space, no conversion thus fewer copies */
+ },
+
+ { GIMP_LAYER_MODE_LIGHTEN_ONLY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_lighten_only,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ /* no blend_space: reuse composite space, no conversion thus fewer copies */
+ },
+
+ { GIMP_LAYER_MODE_HSV_HUE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hsv_hue,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSV_SATURATION,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hsv_saturation,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSL_COLOR,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hsl_color,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HSV_VALUE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hsv_value,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_DIVIDE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_divide,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_DODGE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_dodge,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_BURN,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_burn,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HARDLIGHT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hardlight,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_SOFTLIGHT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_softlight,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_GRAIN_EXTRACT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_grain_extract,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_GRAIN_MERGE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_grain_merge,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_VIVID_LIGHT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_vivid_light,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_PIN_LIGHT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_pin_light,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LINEAR_LIGHT,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_linear_light,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_HARD_MIX,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_hard_mix,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_EXCLUSION,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_exclusion,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LINEAR_BURN,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_linear_burn,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_luma_darken_only,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_luma_lighten_only,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL
+ },
+
+ { GIMP_LAYER_MODE_LUMINANCE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_luminance,
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_COLOR_ERASE,
+
+ .op_name = "gimp:layer-mode",
+ .blend_function = gimp_operation_layer_mode_blend_color_erase,
+ .flags = GIMP_LAYER_MODE_FLAG_SUBTRACTIVE,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_ERASE,
+
+ .op_name = "gimp:erase",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_SUBTRACTIVE |
+ GIMP_LAYER_MODE_FLAG_ALPHA_ONLY |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_MERGE,
+
+ .op_name = "gimp:merge",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_SPLIT,
+
+ .op_name = "gimp:split",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_SUBTRACTIVE |
+ GIMP_LAYER_MODE_FLAG_ALPHA_ONLY |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_ALL,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP
+ },
+
+ { GIMP_LAYER_MODE_PASS_THROUGH,
+
+ .op_name = "gimp:pass-through",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_GROUP,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_REPLACE,
+
+ .op_name = "gimp:replace",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_TRIVIAL,
+ .context = GIMP_LAYER_MODE_CONTEXT_FILTER,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ },
+
+ { GIMP_LAYER_MODE_ANTI_ERASE,
+
+ .op_name = "gimp:anti-erase",
+ .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
+ GIMP_LAYER_MODE_FLAG_ALPHA_ONLY,
+ .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION,
+ .composite_mode = GIMP_LAYER_COMPOSITE_UNION
+ }
+};
+
+static const GimpLayerMode layer_mode_group_default[] =
+{
+ GIMP_LAYER_MODE_PASS_THROUGH,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_REPLACE,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_NORMAL,
+ GIMP_LAYER_MODE_DISSOLVE,
+ GIMP_LAYER_MODE_BEHIND,
+ GIMP_LAYER_MODE_COLOR_ERASE,
+ GIMP_LAYER_MODE_ERASE,
+ GIMP_LAYER_MODE_ANTI_ERASE,
+ GIMP_LAYER_MODE_MERGE,
+ GIMP_LAYER_MODE_SPLIT,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_LIGHTEN_ONLY,
+ GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
+ GIMP_LAYER_MODE_SCREEN,
+ GIMP_LAYER_MODE_DODGE,
+ GIMP_LAYER_MODE_ADDITION,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_DARKEN_ONLY,
+ GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
+ GIMP_LAYER_MODE_MULTIPLY,
+ GIMP_LAYER_MODE_BURN,
+ GIMP_LAYER_MODE_LINEAR_BURN,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_OVERLAY,
+ GIMP_LAYER_MODE_SOFTLIGHT,
+ GIMP_LAYER_MODE_HARDLIGHT,
+ GIMP_LAYER_MODE_VIVID_LIGHT,
+ GIMP_LAYER_MODE_PIN_LIGHT,
+ GIMP_LAYER_MODE_LINEAR_LIGHT,
+ GIMP_LAYER_MODE_HARD_MIX,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_DIFFERENCE,
+ GIMP_LAYER_MODE_EXCLUSION,
+ GIMP_LAYER_MODE_SUBTRACT,
+ GIMP_LAYER_MODE_GRAIN_EXTRACT,
+ GIMP_LAYER_MODE_GRAIN_MERGE,
+ GIMP_LAYER_MODE_DIVIDE,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_HSV_HUE,
+ GIMP_LAYER_MODE_HSV_SATURATION,
+ GIMP_LAYER_MODE_HSL_COLOR,
+ GIMP_LAYER_MODE_HSV_VALUE,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_LCH_HUE,
+ GIMP_LAYER_MODE_LCH_CHROMA,
+ GIMP_LAYER_MODE_LCH_COLOR,
+ GIMP_LAYER_MODE_LCH_LIGHTNESS,
+ GIMP_LAYER_MODE_LUMINANCE
+};
+
+static const GimpLayerMode layer_mode_group_legacy[] =
+{
+ GIMP_LAYER_MODE_NORMAL_LEGACY,
+ GIMP_LAYER_MODE_DISSOLVE,
+ GIMP_LAYER_MODE_BEHIND_LEGACY,
+ GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
+ GIMP_LAYER_MODE_SCREEN_LEGACY,
+ GIMP_LAYER_MODE_DODGE_LEGACY,
+ GIMP_LAYER_MODE_ADDITION_LEGACY,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
+ GIMP_LAYER_MODE_MULTIPLY_LEGACY,
+ GIMP_LAYER_MODE_BURN_LEGACY,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_OVERLAY,
+ GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
+ GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
+ GIMP_LAYER_MODE_SUBTRACT_LEGACY,
+ GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
+ GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
+ GIMP_LAYER_MODE_DIVIDE_LEGACY,
+
+ GIMP_LAYER_MODE_SEPARATOR,
+
+ GIMP_LAYER_MODE_HSV_HUE_LEGACY,
+ GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
+ GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
+ GIMP_LAYER_MODE_HSV_VALUE_LEGACY
+};
+
+static const GimpLayerMode layer_mode_groups[][2] =
+{
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_NORMAL,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_NORMAL_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DISSOLVE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DISSOLVE
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_BEHIND,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_BEHIND_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_MULTIPLY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_MULTIPLY_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SCREEN,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SCREEN_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_OVERLAY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DIFFERENCE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DIFFERENCE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ADDITION,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_ADDITION_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SUBTRACT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SUBTRACT_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DARKEN_ONLY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LIGHTEN_ONLY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_HUE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_HUE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_SATURATION,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_SATURATION_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSL_COLOR,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSL_COLOR_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_VALUE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_VALUE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DIVIDE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DIVIDE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DODGE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DODGE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_BURN,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_BURN_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HARDLIGHT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HARDLIGHT_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SOFTLIGHT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_GRAIN_EXTRACT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_GRAIN_MERGE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_COLOR_ERASE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_VIVID_LIGHT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_PIN_LIGHT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LINEAR_LIGHT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HARD_MIX,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_EXCLUSION,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LINEAR_BURN,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMINANCE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ERASE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_MERGE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SPLIT,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_PASS_THROUGH,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1,
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_REPLACE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ },
+
+ { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ANTI_ERASE,
+ [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1
+ }
+};
+
+
+/* public functions */
+
+void
+gimp_layer_modes_init (void)
+{
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (layer_mode_infos); i++)
+ {
+ gimp_assert ((GimpLayerMode) i == layer_mode_infos[i].layer_mode);
+ }
+}
+
+static const GimpLayerModeInfo *
+gimp_layer_mode_info (GimpLayerMode mode)
+{
+ g_return_val_if_fail (mode >= 0 && mode < G_N_ELEMENTS (layer_mode_infos),
+ &layer_mode_infos[0]);
+
+ return &layer_mode_infos[mode];
+}
+
+gboolean
+gimp_layer_mode_is_legacy (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_LEGACY) != 0;
+}
+
+gboolean
+gimp_layer_mode_is_blend_space_mutable (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE) == 0;
+}
+
+gboolean
+gimp_layer_mode_is_composite_space_mutable (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE) == 0;
+}
+
+gboolean
+gimp_layer_mode_is_composite_mode_mutable (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE) == 0;
+}
+
+gboolean
+gimp_layer_mode_is_subtractive (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_SUBTRACTIVE) != 0;
+}
+
+gboolean
+gimp_layer_mode_is_alpha_only (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_ALPHA_ONLY) != 0;
+}
+
+gboolean
+gimp_layer_mode_is_trivial (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return FALSE;
+
+ return (info->flags & GIMP_LAYER_MODE_FLAG_TRIVIAL) != 0;
+}
+
+GimpLayerColorSpace
+gimp_layer_mode_get_blend_space (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return GIMP_LAYER_COLOR_SPACE_RGB_LINEAR;
+
+ return info->blend_space;
+}
+
+GimpLayerColorSpace
+gimp_layer_mode_get_composite_space (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return GIMP_LAYER_COLOR_SPACE_RGB_LINEAR;
+
+ return info->composite_space;
+}
+
+GimpLayerCompositeMode
+gimp_layer_mode_get_composite_mode (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return GIMP_LAYER_COMPOSITE_UNION;
+
+ return info->composite_mode;
+}
+
+GimpLayerCompositeMode
+gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return GIMP_LAYER_COMPOSITE_UNION;
+
+ return info->paint_composite_mode;
+}
+
+const gchar *
+gimp_layer_mode_get_operation (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return "gimp:layer-mode";
+
+ return info->op_name;
+}
+
+GimpLayerModeFunc
+gimp_layer_mode_get_function (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+ static GimpLayerModeFunc funcs[G_N_ELEMENTS (layer_mode_infos)];
+
+ if (! info)
+ info = layer_mode_infos;
+
+ mode = info - layer_mode_infos;
+
+ if (! funcs[mode])
+ {
+ GeglNode *node;
+ GeglOperation *operation;
+
+ node = gegl_node_new_child (NULL,
+ "operation", info->op_name,
+ NULL);
+
+ operation = gegl_node_get_gegl_operation (node);
+
+ funcs[mode] = GIMP_OPERATION_LAYER_MODE_GET_CLASS (operation)->process;
+
+ g_object_unref (node);
+ }
+
+ return funcs[mode];
+}
+
+GimpLayerModeBlendFunc
+gimp_layer_mode_get_blend_function (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return NULL;
+
+ return info->blend_function;
+}
+
+GimpLayerModeContext
+gimp_layer_mode_get_context (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return 0;
+
+ return info->context;
+}
+
+GimpLayerMode *
+gimp_layer_mode_get_context_array (GimpLayerMode mode,
+ GimpLayerModeContext context,
+ gint *n_modes)
+{
+ GimpLayerModeGroup group;
+ const GimpLayerMode *group_modes;
+ gint n_group_modes;
+ GimpLayerMode *array;
+ gint i;
+
+ group = gimp_layer_mode_get_group (mode);
+
+ group_modes = gimp_layer_mode_get_group_array (group, &n_group_modes);
+
+ array = g_new0 (GimpLayerMode, n_group_modes);
+ *n_modes = 0;
+
+ for (i = 0; i < n_group_modes; i++)
+ {
+ if (group_modes[i] != GIMP_LAYER_MODE_SEPARATOR &&
+ (gimp_layer_mode_get_context (group_modes[i]) & context))
+ {
+ array[*n_modes] = group_modes[i];
+ (*n_modes)++;
+ }
+ }
+
+ return array;
+}
+
+static gboolean
+is_mode_in_array (const GimpLayerMode *modes,
+ gint n_modes,
+ GimpLayerMode mode)
+{
+ gint i;
+
+ for (i = 0; i < n_modes; i++)
+ {
+ if (modes[i] == mode)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GimpLayerModeGroup
+gimp_layer_mode_get_group (GimpLayerMode mode)
+{
+ if (is_mode_in_array (layer_mode_group_default,
+ G_N_ELEMENTS (layer_mode_group_default), mode))
+ {
+ return GIMP_LAYER_MODE_GROUP_DEFAULT;
+ }
+ else if (is_mode_in_array (layer_mode_group_legacy,
+ G_N_ELEMENTS (layer_mode_group_legacy), mode))
+ {
+ return GIMP_LAYER_MODE_GROUP_LEGACY;
+ }
+
+ return GIMP_LAYER_MODE_GROUP_DEFAULT;
+}
+
+const GimpLayerMode *
+gimp_layer_mode_get_group_array (GimpLayerModeGroup group,
+ gint *n_modes)
+{
+ g_return_val_if_fail (n_modes != NULL, NULL);
+
+ switch (group)
+ {
+ case GIMP_LAYER_MODE_GROUP_DEFAULT:
+ *n_modes = G_N_ELEMENTS (layer_mode_group_default);
+ return layer_mode_group_default;
+
+ case GIMP_LAYER_MODE_GROUP_LEGACY:
+ *n_modes = G_N_ELEMENTS (layer_mode_group_legacy);
+ return layer_mode_group_legacy;
+
+ default:
+ g_return_val_if_reached (NULL);
+ }
+}
+
+gboolean
+gimp_layer_mode_get_for_group (GimpLayerMode old_mode,
+ GimpLayerModeGroup new_group,
+ GimpLayerMode *new_mode)
+{
+ gint i;
+
+ g_return_val_if_fail (new_mode != NULL, FALSE);
+
+ for (i = 0; i < G_N_ELEMENTS (layer_mode_groups); i++)
+ {
+ if (is_mode_in_array (layer_mode_groups[i], 2, old_mode))
+ {
+ *new_mode = layer_mode_groups[i][new_group];
+
+ if (*new_mode != -1)
+ return TRUE;
+
+ return FALSE;
+ }
+ }
+
+ *new_mode = -1;
+
+ return FALSE;
+}
+
+const Babl *
+gimp_layer_mode_get_format (GimpLayerMode mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode,
+ const Babl *preferred_format)
+{
+ GimpLayerCompositeRegion composite_region;
+
+ /* for now, all modes perform i/o in the composite space. */
+ (void) mode;
+ (void) blend_space;
+
+ 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);
+
+ composite_region = gimp_layer_mode_get_included_region (mode, composite_mode);
+
+ if (gimp_layer_mode_is_alpha_only (mode))
+ {
+ if (composite_region != GIMP_LAYER_COMPOSITE_REGION_UNION)
+ {
+ /* alpha-only layer modes don't combine colors in non-union composite
+ * modes, hence we can disregard the composite space.
+ */
+ composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
+ }
+ }
+ else if (gimp_layer_mode_is_trivial (mode))
+ {
+ if (! (composite_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION))
+ {
+ /* trivial layer modes don't combine colors when only the source
+ * region is included, hence we can disregard the composite space.
+ */
+ composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
+ }
+ }
+
+ switch (composite_space)
+ {
+ case GIMP_LAYER_COLOR_SPACE_AUTO:
+ /* compositing is color-space agnostic. return a format that has a fast
+ * conversion path to/from the preferred format.
+ */
+ if (! preferred_format || gimp_babl_format_get_linear (preferred_format))
+ return babl_format ("RGBA float");
+ else
+ return babl_format ("R'G'B'A float");
+
+ case GIMP_LAYER_COLOR_SPACE_RGB_LINEAR:
+ return babl_format ("RGBA float");
+
+ case GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL:
+ return babl_format ("R'G'B'A float");
+
+ case GIMP_LAYER_COLOR_SPACE_LAB:
+ return babl_format ("CIE Lab alpha float");
+ }
+
+ g_return_val_if_reached (babl_format ("RGBA float"));
+}
+
+GimpLayerCompositeRegion
+gimp_layer_mode_get_included_region (GimpLayerMode mode,
+ GimpLayerCompositeMode composite_mode)
+{
+ if (composite_mode == GIMP_LAYER_COMPOSITE_AUTO)
+ composite_mode = gimp_layer_mode_get_composite_mode (mode);
+
+ switch (composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ return GIMP_LAYER_COMPOSITE_REGION_UNION;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ return GIMP_LAYER_COMPOSITE_REGION_DESTINATION;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ return GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
+
+ default:
+ g_return_val_if_reached (GIMP_LAYER_COMPOSITE_REGION_INTERSECTION);
+ }
+}
diff --git a/app/operations/layer-modes/gimp-layer-modes.h b/app/operations/layer-modes/gimp-layer-modes.h
new file mode 100644
index 0000000..30c5e15
--- /dev/null
+++ b/app/operations/layer-modes/gimp-layer-modes.h
@@ -0,0 +1,73 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimp-layer-modes.h
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * Ø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_LAYER_MODES_H__
+#define __GIMP_LAYER_MODES_H__
+
+
+void gimp_layer_modes_init (void);
+
+gboolean gimp_layer_mode_is_legacy (GimpLayerMode mode);
+
+gboolean gimp_layer_mode_is_blend_space_mutable (GimpLayerMode mode);
+gboolean gimp_layer_mode_is_composite_space_mutable (GimpLayerMode mode);
+gboolean gimp_layer_mode_is_composite_mode_mutable (GimpLayerMode mode);
+
+gboolean gimp_layer_mode_is_subtractive (GimpLayerMode mode);
+gboolean gimp_layer_mode_is_alpha_only (GimpLayerMode mode);
+gboolean gimp_layer_mode_is_trivial (GimpLayerMode mode);
+
+GimpLayerColorSpace gimp_layer_mode_get_blend_space (GimpLayerMode mode);
+GimpLayerColorSpace gimp_layer_mode_get_composite_space (GimpLayerMode mode);
+GimpLayerCompositeMode gimp_layer_mode_get_composite_mode (GimpLayerMode mode);
+GimpLayerCompositeMode gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode);
+
+const gchar * gimp_layer_mode_get_operation (GimpLayerMode mode);
+
+GimpLayerModeFunc gimp_layer_mode_get_function (GimpLayerMode mode);
+GimpLayerModeBlendFunc gimp_layer_mode_get_blend_function (GimpLayerMode mode);
+
+GimpLayerModeContext gimp_layer_mode_get_context (GimpLayerMode mode);
+
+GimpLayerMode * gimp_layer_mode_get_context_array (GimpLayerMode mode,
+ GimpLayerModeContext context,
+ gint *n_modes);
+
+GimpLayerModeGroup gimp_layer_mode_get_group (GimpLayerMode mode);
+
+const GimpLayerMode * gimp_layer_mode_get_group_array (GimpLayerModeGroup group,
+ gint *n_modes);
+
+gboolean gimp_layer_mode_get_for_group (GimpLayerMode old_mode,
+ GimpLayerModeGroup new_group,
+ GimpLayerMode *new_mode);
+
+const Babl * gimp_layer_mode_get_format (GimpLayerMode mode,
+ GimpLayerColorSpace blend_space,
+ GimpLayerColorSpace composite_space,
+ GimpLayerCompositeMode composite_mode,
+ const Babl *preferred_format);
+
+GimpLayerCompositeRegion gimp_layer_mode_get_included_region (GimpLayerMode mode,
+ GimpLayerCompositeMode composite_mode);
+
+
+#endif /* __GIMP_LAYER_MODES_H__ */
diff --git a/app/operations/layer-modes/gimpoperationantierase.c b/app/operations/layer-modes/gimpoperationantierase.c
new file mode 100644
index 0000000..3fb2947
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationantierase.c
@@ -0,0 +1,188 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationantierase.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2012 Ville Sokk <ville.sokk@gmail.com>
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationantierase.h"
+
+
+
+static gboolean gimp_operation_anti_erase_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+static GimpLayerCompositeRegion gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode);
+
+
+G_DEFINE_TYPE (GimpOperationAntiErase, gimp_operation_anti_erase,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_anti_erase_class_init (GimpOperationAntiEraseClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:anti-erase",
+ "description", "GIMP anti erase mode operation",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_anti_erase_process;
+ layer_mode_class->get_affected_region = gimp_operation_anti_erase_get_affected_region;
+}
+
+static void
+gimp_operation_anti_erase_init (GimpOperationAntiErase *self)
+{
+}
+
+static gboolean
+gimp_operation_anti_erase_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat value = opacity;
+ gint b;
+
+ if (has_mask)
+ value *= *mask;
+
+ out[ALPHA] = in[ALPHA] + (1.0 - in[ALPHA]) * layer[ALPHA] * value;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ gint b;
+
+ out[ALPHA] = in[ALPHA];
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ in += 4;
+ out += 4;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat value = opacity;
+ gint b;
+
+ if (has_mask)
+ value *= *mask;
+
+ out[ALPHA] = layer[ALPHA] * value;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gfloat value = opacity;
+ gint b;
+
+ if (has_mask)
+ value *= *mask;
+
+ out[ALPHA] = in[ALPHA] * layer[ALPHA] * value;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+static GimpLayerCompositeRegion
+gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode)
+{
+ return GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+}
diff --git a/app/operations/layer-modes/gimpoperationantierase.h b/app/operations/layer-modes/gimpoperationantierase.h
new file mode 100644
index 0000000..0c5ddf8
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationantierase.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationantierase.h
+ * Copyright (C) 2008 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_OPERATION_ANTI_ERASE_H__
+#define __GIMP_OPERATION_ANTI_ERASE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_ANTI_ERASE (gimp_operation_anti_erase_get_type ())
+#define GIMP_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiErase))
+#define GIMP_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass))
+#define GIMP_IS_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE))
+#define GIMP_IS_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE))
+#define GIMP_OPERATION_ANTI_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass))
+
+
+typedef struct _GimpOperationAntiErase GimpOperationAntiErase;
+typedef struct _GimpOperationAntiEraseClass GimpOperationAntiEraseClass;
+
+struct _GimpOperationAntiErase
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationAntiEraseClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_anti_erase_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_ANTI_ERASE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationbehind.c b/app/operations/layer-modes/gimpoperationbehind.c
new file mode 100644
index 0000000..1dc2630
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationbehind.c
@@ -0,0 +1,236 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationbehind.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2012 Ville Sokk <ville.sokk@gmail.com>
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationbehind.h"
+
+
+
+static gboolean gimp_operation_behind_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+
+G_DEFINE_TYPE (GimpOperationBehind, gimp_operation_behind,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_behind_class_init (GimpOperationBehindClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:behind",
+ "description", "GIMP behind mode operation",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_behind_process;
+}
+
+static void
+gimp_operation_behind_init (GimpOperationBehind *self)
+{
+}
+
+static gboolean
+gimp_operation_behind_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat src1_alpha = in[ALPHA];
+ gfloat src2_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ src2_alpha *= *mask;
+
+ new_alpha = src2_alpha + (1.0 - src2_alpha) * src1_alpha;
+
+ if (new_alpha)
+ {
+ gfloat ratio = in[ALPHA] / new_alpha;
+ gfloat compl_ratio = 1.0f - ratio;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b] * ratio + layer[b] * compl_ratio;
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ gfloat src1_alpha = in[ALPHA];
+ gfloat new_alpha;
+ gint b;
+
+ new_alpha = src1_alpha;
+
+ if (new_alpha)
+ {
+ for (b = RED; b < ALPHA; b++)
+ out[b] = in[b];
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ out[b] = layer[b];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat src1_alpha = in[ALPHA];
+ gfloat src2_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ src2_alpha *= *mask;
+
+ new_alpha = src2_alpha;
+
+ if (new_alpha)
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b] + (in[b] - layer[b]) * src1_alpha;
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gfloat src1_alpha = in[ALPHA];
+ gfloat src2_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ src2_alpha *= *mask;
+
+ new_alpha = src1_alpha * src2_alpha;
+
+ if (new_alpha)
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationbehind.h b/app/operations/layer-modes/gimpoperationbehind.h
new file mode 100644
index 0000000..46b9ac4
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationbehind.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationbehind.h
+ * Copyright (C) 2008 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_OPERATION_BEHIND_H__
+#define __GIMP_OPERATION_BEHIND_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_BEHIND (gimp_operation_behind_get_type ())
+#define GIMP_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehind))
+#define GIMP_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass))
+#define GIMP_IS_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BEHIND))
+#define GIMP_IS_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BEHIND))
+#define GIMP_OPERATION_BEHIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass))
+
+
+typedef struct _GimpOperationBehind GimpOperationBehind;
+typedef struct _GimpOperationBehindClass GimpOperationBehindClass;
+
+struct _GimpOperationBehind
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationBehindClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_behind_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_BEHIND_H__ */
diff --git a/app/operations/layer-modes/gimpoperationdissolve.c b/app/operations/layer-modes/gimpoperationdissolve.c
new file mode 100644
index 0000000..fb4b1d0
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationdissolve.c
@@ -0,0 +1,175 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationdissolve.c
+ * Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com>
+ * 2012 Øyvind Kolås <pippin@gimp.org>
+ * 2003 Helvetix Victorinox
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationdissolve.h"
+
+
+#define RANDOM_TABLE_SIZE 4096
+
+
+static gboolean gimp_operation_dissolve_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *result,
+ gint level);
+static GimpLayerCompositeRegion gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode);
+
+
+G_DEFINE_TYPE (GimpOperationDissolve, gimp_operation_dissolve,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static gint32 random_table[RANDOM_TABLE_SIZE];
+
+
+static void
+gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+ GRand *gr;
+ gint i;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:dissolve",
+ "description", "GIMP dissolve mode operation",
+ "categories", "compositors",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_dissolve_process;
+ layer_mode_class->get_affected_region = gimp_operation_dissolve_get_affected_region;
+
+ /* generate a table of random seeds */
+ gr = g_rand_new_with_seed (314159265);
+ for (i = 0; i < RANDOM_TABLE_SIZE; i++)
+ random_table[i] = g_rand_int (gr);
+
+ g_rand_free (gr);
+}
+
+static void
+gimp_operation_dissolve_init (GimpOperationDissolve *self)
+{
+}
+
+static gboolean
+gimp_operation_dissolve_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *result,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+ gint x, y;
+
+ for (y = result->y; y < result->y + result->height; y++)
+ {
+ GRand *gr;
+
+ /* The offset can be negative. I could just abs() the result, but we
+ * probably prefer to use different indexes of the table when possible for
+ * nicer randomization, so let's cycle the modulo so that -1 is the last
+ * table index.
+ */
+ gr = g_rand_new_with_seed (random_table[((y % RANDOM_TABLE_SIZE) + RANDOM_TABLE_SIZE) % RANDOM_TABLE_SIZE]);
+
+ /* fast forward through the rows pseudo random sequence */
+ for (x = 0; x < result->x; x++)
+ g_rand_int (gr);
+
+ for (x = result->x; x < result->x + result->width; x++)
+ {
+ gfloat value = layer[ALPHA] * opacity * 255;
+
+ if (has_mask)
+ value *= *mask;
+
+ if (g_rand_int_range (gr, 0, 255) >= value)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
+ layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP)
+ {
+ out[3] = in[3];
+ }
+ else
+ {
+ out[3] = 0.0f;
+ }
+ }
+ else
+ {
+ out[0] = layer[0];
+ out[1] = layer[1];
+ out[2] = layer[2];
+
+ if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
+ layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER)
+ {
+ out[3] = 1.0f;
+ }
+ else
+ {
+ out[3] = in[3];
+ }
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+
+ g_rand_free (gr);
+ }
+
+ return TRUE;
+}
+
+static GimpLayerCompositeRegion
+gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode)
+{
+ return GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+}
diff --git a/app/operations/layer-modes/gimpoperationdissolve.h b/app/operations/layer-modes/gimpoperationdissolve.h
new file mode 100644
index 0000000..d448918
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationdissolve.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationdissolve.h
+ * Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com>
+ *
+ * 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_OPERATION_DISSOLVE_H__
+#define __GIMP_OPERATION_DISSOLVE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_DISSOLVE (gimp_operation_dissolve_get_type ())
+#define GIMP_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolve))
+#define GIMP_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass))
+#define GIMP_IS_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DISSOLVE))
+#define GIMP_IS_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DISSOLVE))
+#define GIMP_OPERATION_DISSOLVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass))
+
+
+typedef struct _GimpOperationDissolve GimpOperationDissolve;
+typedef struct _GimpOperationDissolveClass GimpOperationDissolveClass;
+
+struct _GimpOperationDissolveClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+struct _GimpOperationDissolve
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+
+GType gimp_operation_dissolve_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_DISSOLVE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationerase.c b/app/operations/layer-modes/gimpoperationerase.c
new file mode 100644
index 0000000..aae6eac
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationerase.c
@@ -0,0 +1,214 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationerase.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2012 Ville Sokk <ville.sokk@gmail.com>
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationerase.h"
+
+
+static gboolean gimp_operation_erase_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+
+G_DEFINE_TYPE (GimpOperationErase, gimp_operation_erase,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_erase_class_init (GimpOperationEraseClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:erase",
+ "description", "GIMP erase mode operation",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_erase_process;
+}
+
+static void
+gimp_operation_erase_init (GimpOperationErase *self)
+{
+}
+
+static gboolean
+gimp_operation_erase_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+ gfloat new_alpha;
+ gint b;
+
+ layer_alpha = layer[ALPHA] * opacity;
+
+ if (has_mask)
+ layer_alpha *= (*mask);
+
+ new_alpha = in[ALPHA] + layer_alpha - 2.0f * in[ALPHA] * layer_alpha;
+
+ if (new_alpha != 0.0f)
+ {
+ gfloat ratio;
+
+ ratio = (1.0f - in[ALPHA]) * layer_alpha / new_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = ratio * layer[b] + (1.0f - ratio) * in[b];
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask ++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+ gfloat new_alpha;
+ gint b;
+
+ layer_alpha = layer[ALPHA] * opacity;
+
+ if (has_mask)
+ layer_alpha *= (*mask);
+
+ new_alpha = (1.0f - layer_alpha) * in[ALPHA];
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask ++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+ gfloat new_alpha;
+ const gfloat *src;
+ gint b;
+
+ layer_alpha = layer[ALPHA] * opacity;
+
+ if (has_mask)
+ layer_alpha *= (*mask);
+
+ new_alpha = (1.0f - in[ALPHA]) * layer_alpha;
+
+ src = layer;
+
+ if (new_alpha == 0.0f)
+ src = in;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = src[b];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask ++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ out[ALPHA] = 0.0f;
+
+ in += 4;
+ out += 4;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationerase.h b/app/operations/layer-modes/gimpoperationerase.h
new file mode 100644
index 0000000..fec309b
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationerase.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationerase.h
+ * Copyright (C) 2008 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_OPERATION_ERASE_H__
+#define __GIMP_OPERATION_ERASE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_ERASE (gimp_operation_erase_get_type ())
+#define GIMP_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationErase))
+#define GIMP_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass))
+#define GIMP_IS_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ERASE))
+#define GIMP_IS_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ERASE))
+#define GIMP_OPERATION_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass))
+
+
+typedef struct _GimpOperationErase GimpOperationErase;
+typedef struct _GimpOperationEraseClass GimpOperationEraseClass;
+
+struct _GimpOperationErase
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationEraseClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_erase_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_ERASE_MODE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationlayermode-blend.c b/app/operations/layer-modes/gimpoperationlayermode-blend.c
new file mode 100644
index 0000000..e107462
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-blend.c
@@ -0,0 +1,1215 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode-blend.c
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * 2017 Øyvind Kolås <pippin@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpbase/gimpbase.h"
+#include "libgimpmath/gimpmath.h"
+
+#include "../operations-types.h"
+
+#include "gimpoperationlayermode-blend.h"
+
+
+#define EPSILON 1e-6f
+
+#define SAFE_DIV_MIN EPSILON
+#define SAFE_DIV_MAX (1.0f / SAFE_DIV_MIN)
+
+
+/* local function prototypes */
+
+static inline gfloat safe_div (gfloat a,
+ gfloat b);
+
+
+/* private functions */
+
+
+/* returns a / b, clamped to [-SAFE_DIV_MAX, SAFE_DIV_MAX].
+ * if -SAFE_DIV_MIN <= a <= SAFE_DIV_MIN, returns 0.
+ */
+static inline gfloat
+safe_div (gfloat a,
+ gfloat b)
+{
+ gfloat result = 0.0f;
+
+ if (fabsf (a) > SAFE_DIV_MIN)
+ {
+ result = a / b;
+ result = CLAMP (result, -SAFE_DIV_MAX, SAFE_DIV_MAX);
+ }
+
+ return result;
+}
+
+
+/* public functions */
+
+
+/* non-subtractive blending functions. these functions must set comp[ALPHA]
+ * to the same value as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are
+ * zero, the value of comp[RED..BLUE] is unconstrained (in particular, it may
+ * be NaN).
+ */
+
+
+void /* aka linear_dodge */
+gimp_operation_layer_mode_blend_addition (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] + layer[c];
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_burn (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = 1.0f - safe_div (1.0f - in[c], layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_darken_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = MIN (in[c], layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_difference (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = fabsf (in[c] - layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_divide (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = safe_div (in[c], layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_dodge (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = safe_div (in[c], 1.0f - layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_exclusion (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = 0.5f - 2.0f * (in[c] - 0.5f) * (layer[c] - 0.5f);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_grain_extract (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] - layer[c] + 0.5f;
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_grain_merge (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] + layer[c] - 0.5f;
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hard_mix (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] + layer[c] < 1.0f ? 0.0f : 1.0f;
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hardlight (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat val;
+
+ if (layer[c] > 0.5f)
+ {
+ val = (1.0f - in[c]) * (1.0f - (layer[c] - 0.5f) * 2.0f);
+ val = MIN (1.0f - val, 1.0f);
+ }
+ else
+ {
+ val = in[c] * (layer[c] * 2.0f);
+ val = MIN (val, 1.0f);
+ }
+
+ comp[c] = val;
+ }
+ }
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hsl_color (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat dest_min, dest_max, dest_l;
+ gfloat src_min, src_max, src_l;
+
+ dest_min = MIN (in[0], in[1]);
+ dest_min = MIN (dest_min, in[2]);
+ dest_max = MAX (in[0], in[1]);
+ dest_max = MAX (dest_max, in[2]);
+ dest_l = (dest_min + dest_max) / 2.0f;
+
+ src_min = MIN (layer[0], layer[1]);
+ src_min = MIN (src_min, layer[2]);
+ src_max = MAX (layer[0], layer[1]);
+ src_max = MAX (src_max, layer[2]);
+ src_l = (src_min + src_max) / 2.0f;
+
+ if (fabs (src_l) > EPSILON && fabs (1.0 - src_l) > EPSILON)
+ {
+ gboolean dest_high;
+ gboolean src_high;
+ gfloat ratio;
+ gfloat offset;
+ gint c;
+
+ dest_high = dest_l > 0.5f;
+ src_high = src_l > 0.5f;
+
+ dest_l = MIN (dest_l, 1.0f - dest_l);
+ src_l = MIN (src_l, 1.0f - src_l);
+
+ ratio = dest_l / src_l;
+
+ offset = 0.0f;
+ if (dest_high) offset += 1.0f - 2.0f * dest_l;
+ if (src_high) offset += 2.0f * dest_l - ratio;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = layer[c] * ratio + offset;
+ }
+ else
+ {
+ comp[RED] = dest_l;
+ comp[GREEN] = dest_l;
+ comp[BLUE] = dest_l;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hsv_hue (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat src_min, src_max, src_delta;
+ gfloat dest_min, dest_max, dest_delta, dest_s;
+
+ src_min = MIN (layer[0], layer[1]);
+ src_min = MIN (src_min, layer[2]);
+ src_max = MAX (layer[0], layer[1]);
+ src_max = MAX (src_max, layer[2]);
+ src_delta = src_max - src_min;
+
+ if (src_delta > EPSILON)
+ {
+ gfloat ratio;
+ gfloat offset;
+ gint c;
+
+ dest_min = MIN (in[0], in[1]);
+ dest_min = MIN (dest_min, in[2]);
+ dest_max = MAX (in[0], in[1]);
+ dest_max = MAX (dest_max, in[2]);
+ dest_delta = dest_max - dest_min;
+ dest_s = dest_max ? dest_delta / dest_max : 0.0f;
+
+ ratio = dest_s * dest_max / src_delta;
+ offset = dest_max - src_max * ratio;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = layer[c] * ratio + offset;
+ }
+ else
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c];
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat src_min, src_max, src_delta, src_s;
+ gfloat dest_min, dest_max, dest_delta;
+
+ dest_min = MIN (in[0], in[1]);
+ dest_min = MIN (dest_min, in[2]);
+ dest_max = MAX (in[0], in[1]);
+ dest_max = MAX (dest_max, in[2]);
+ dest_delta = dest_max - dest_min;
+
+ if (dest_delta > EPSILON)
+ {
+ gfloat ratio;
+ gfloat offset;
+ gint c;
+
+ src_min = MIN (layer[0], layer[1]);
+ src_min = MIN (src_min, layer[2]);
+ src_max = MAX (layer[0], layer[1]);
+ src_max = MAX (src_max, layer[2]);
+ src_delta = src_max - src_min;
+ src_s = src_max ? src_delta / src_max : 0.0f;
+
+ ratio = src_s * dest_max / dest_delta;
+ offset = (1.0f - ratio) * dest_max;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] * ratio + offset;
+ }
+ else
+ {
+ comp[RED] = dest_max;
+ comp[GREEN] = dest_max;
+ comp[BLUE] = dest_max;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_hsv_value (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat dest_v;
+ gfloat src_v;
+
+ dest_v = MAX (in[0], in[1]);
+ dest_v = MAX (dest_v, in[2]);
+
+ src_v = MAX (layer[0], layer[1]);
+ src_v = MAX (src_v, layer[2]);
+
+ if (fabs (dest_v) > EPSILON)
+ {
+ gfloat ratio = src_v / dest_v;
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] * ratio;
+ }
+ else
+ {
+ comp[RED] = src_v;
+ comp[GREEN] = src_v;
+ comp[BLUE] = src_v;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_lch_chroma (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat A1 = in[1];
+ gfloat B1 = in[2];
+ gfloat c1 = hypotf (A1, B1);
+
+ if (c1 > EPSILON)
+ {
+ gfloat A2 = layer[1];
+ gfloat B2 = layer[2];
+ gfloat c2 = hypotf (A2, B2);
+ gfloat A = c2 * A1 / c1;
+ gfloat B = c2 * B1 / c1;
+
+ comp[0] = in[0];
+ comp[1] = A;
+ comp[2] = B;
+ }
+ else
+ {
+ comp[0] = in[0];
+ comp[1] = in[1];
+ comp[2] = in[2];
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_lch_color (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ comp[0] = in[0];
+ comp[1] = layer[1];
+ comp[2] = layer[2];
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_lch_hue (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat A2 = layer[1];
+ gfloat B2 = layer[2];
+ gfloat c2 = hypotf (A2, B2);
+
+ if (c2 > EPSILON)
+ {
+ gfloat A1 = in[1];
+ gfloat B1 = in[2];
+ gfloat c1 = hypotf (A1, B1);
+ gfloat A = c1 * A2 / c2;
+ gfloat B = c1 * B2 / c2;
+
+ comp[0] = in[0];
+ comp[1] = A;
+ comp[2] = B;
+ }
+ else
+ {
+ comp[0] = in[0];
+ comp[1] = in[1];
+ comp[2] = in[2];
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_lch_lightness (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ comp[0] = layer[0];
+ comp[1] = in[1];
+ comp[2] = in[2];
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_lighten_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = MAX (in[c], layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_linear_burn (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] + layer[c] - 1.0f;
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+/* added according to:
+ http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */
+void
+gimp_operation_layer_mode_blend_linear_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat val;
+
+ if (layer[c] <= 0.5f)
+ val = in[c] + 2.0f * layer[c] - 1.0f;
+ else
+ val = in[c] + 2.0f * (layer[c] - 0.5f);
+
+ comp[c] = val;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat dest_luminance;
+ gfloat src_luminance;
+ gint c;
+
+ dest_luminance = GIMP_RGB_LUMINANCE (in[0], in[1], in[2]);
+ src_luminance = GIMP_RGB_LUMINANCE (layer[0], layer[1], layer[2]);
+
+ if (dest_luminance <= src_luminance)
+ {
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c];
+ }
+ else
+ {
+ for (c = 0; c < 3; c++)
+ comp[c] = layer[c];
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gfloat dest_luminance;
+ gfloat src_luminance;
+ gint c;
+
+ dest_luminance = GIMP_RGB_LUMINANCE (in[0], in[1], in[2]);
+ src_luminance = GIMP_RGB_LUMINANCE (layer[0], layer[1], layer[2]);
+
+ if (dest_luminance >= src_luminance)
+ {
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c];
+ }
+ else
+ {
+ for (c = 0; c < 3; c++)
+ comp[c] = layer[c];
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_luminance (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ static const Babl *fish;
+ gfloat *scratch;
+ gfloat *in_Y;
+ gfloat *layer_Y;
+
+ if (! fish)
+ fish = babl_fish ("RGBA float", "Y float");
+
+ scratch = gegl_scratch_new (gfloat, 2 * samples);
+
+ in_Y = scratch;
+ layer_Y = scratch + samples;
+
+ babl_process (fish, in, in_Y, samples);
+ babl_process (fish, layer, layer_Y, samples);
+
+ while (samples--)
+ {
+ if (layer[ALPHA] != 0.0f && in[ALPHA] != 0.0f)
+ {
+ gfloat ratio = safe_div (layer_Y[0], in_Y[0]);
+ gint c;
+
+ for (c = 0; c < 3; c ++)
+ comp[c] = in[c] * ratio;
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ in += 4;
+ layer += 4;
+ in_Y ++;
+ layer_Y ++;
+ }
+
+ gegl_scratch_free (scratch);
+}
+
+void
+gimp_operation_layer_mode_blend_multiply (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] * layer[c];
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_overlay (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat val;
+
+ if (in[c] < 0.5f)
+ val = 2.0f * in[c] * layer[c];
+ else
+ val = 1.0f - 2.0f * (1.0f - layer[c]) * (1.0f - in[c]);
+
+ comp[c] = val;
+ }
+ }
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+/* added according to:
+ http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */
+void
+gimp_operation_layer_mode_blend_pin_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat val;
+
+ if (layer[c] > 0.5f)
+ val = MAX(in[c], 2.0f * (layer[c] - 0.5f));
+ else
+ val = MIN(in[c], 2.0f * layer[c]);
+
+ comp[c] = val;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_screen (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]);
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_softlight (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat multiply = in[c] * layer[c];
+ gfloat screen = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]);
+ gfloat val = (1.0f - in[c]) * multiply + in[c] * screen;
+
+ comp[c] = val;
+ }
+ }
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+void
+gimp_operation_layer_mode_blend_subtract (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = in[c] - layer[c];
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+/* added according to:
+ http://www.simplefilter.de/en/basics/mixmods.html */
+void
+gimp_operation_layer_mode_blend_vivid_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat val;
+
+ if (layer[c] <= 0.5f)
+ {
+ val = 1.0f - safe_div (1.0f - in[c], 2.0f * layer[c]);
+ val = MAX (val, 0.0f);
+ }
+ else
+ {
+ val = safe_div (in[c], 2.0f * (1.0f - layer[c]));
+ val = MIN (val, 1.0f);
+ }
+
+ comp[c] = val;
+ }
+ }
+
+ comp[ALPHA] = layer[ALPHA];
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
+
+
+/* subtractive blending functions. these functions must set comp[ALPHA] to
+ * the modified alpha of the overlapping content, as a fraction of the
+ * original overlapping content (i.e., an alpha of 1.0 specifies that no
+ * content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value
+ * of comp[RED..BLUE] is unconstrained (in particular, it may be NaN).
+ */
+
+
+void
+gimp_operation_layer_mode_blend_color_erase (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples)
+{
+ while (samples--)
+ {
+ if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+ {
+ const gfloat *color = in;
+ const gfloat *bgcolor = layer;
+ gfloat alpha;
+ gint c;
+
+ alpha = 0.0f;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat col = CLAMP (color[c], 0.0f, 1.0f);
+ gfloat bgcol = CLAMP (bgcolor[c], 0.0f, 1.0f);
+
+ if (fabs (col - bgcol) > EPSILON)
+ {
+ gfloat a;
+
+ if (col > bgcol)
+ a = (col - bgcol) / (1.0f - bgcol);
+ else
+ a = (bgcol - col) / bgcol;
+
+ alpha = MAX (alpha, a);
+ }
+ }
+
+ if (alpha > EPSILON)
+ {
+ gfloat alpha_inv = 1.0f / alpha;
+
+ for (c = 0; c < 3; c++)
+ comp[c] = (color[c] - bgcolor[c]) * alpha_inv + bgcolor[c];
+ }
+ else
+ {
+ comp[RED] = comp[GREEN] = comp[BLUE] = 0.0f;
+ }
+
+ comp[ALPHA] = alpha;
+ }
+ else
+ comp[ALPHA] = 0.0f;
+
+ comp += 4;
+ layer += 4;
+ in += 4;
+ }
+}
diff --git a/app/operations/layer-modes/gimpoperationlayermode-blend.h b/app/operations/layer-modes/gimpoperationlayermode-blend.h
new file mode 100644
index 0000000..3a8f995
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-blend.h
@@ -0,0 +1,200 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode-blend.h
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * 2017 Øyvind Kolås <pippin@gimp.org>
+ * 2017 Ell
+ *
+ * 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; withcomp 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_OPERATION_LAYER_MODE_BLEND_H__
+#define __GIMP_OPERATION_LAYER_MODE_BLEND_H__
+
+
+/* nonsubtractive blend functions */
+
+void gimp_operation_layer_mode_blend_addition (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_burn (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_darken_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_difference (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_divide (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_dodge (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_exclusion (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_grain_extract (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_grain_merge (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hard_mix (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hardlight (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hsl_color (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hsv_hue (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_hsv_value (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_lch_chroma (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_lch_color (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_lch_hue (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_lch_lightness (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_lighten_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_linear_burn (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_linear_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_luminance (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_multiply (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_overlay (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_pin_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_screen (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_softlight (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_subtract (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+void gimp_operation_layer_mode_blend_vivid_light (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+
+
+/* subtractive blend functions */
+
+void gimp_operation_layer_mode_blend_color_erase (GeglOperation *operation,
+ const gfloat *in,
+ const gfloat *layer,
+ gfloat *comp,
+ gint samples);
+
+
+#endif /* __GIMP_OPERATION_LAYER_MODE_BLEND_H__ */
diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c b/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c
new file mode 100644
index 0000000..2630751
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c
@@ -0,0 +1,105 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode-composite-sse2.c
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * 2017 Øyvind Kolås <pippin@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationlayermode-composite.h"
+
+
+#if COMPILE_SSE2_INTRINISICS
+
+/* SSE2 */
+#include <emmintrin.h>
+
+
+/* non-subtractive compositing functions. these functions expect comp[ALPHA]
+ * to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
+ * the value of comp[RED..BLUE] is unconstrained (in particular, it may be
+ * NaN).
+ */
+
+
+void
+gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ if ((((uintptr_t)in) | /* alignment check */
+ ((uintptr_t)comp) |
+ ((uintptr_t)out) ) & 0x0F)
+ {
+ gimp_operation_layer_mode_composite_clip_to_backdrop (in, layer, comp,
+ mask, opacity, out,
+ samples);
+ }
+ else
+ {
+ const __v4sf *v_in = (const __v4sf*) in;
+ const __v4sf *v_comp = (const __v4sf*) comp;
+ __v4sf *v_out = (__v4sf*) out;
+ const __v4sf v_one = _mm_set1_ps (1.0f);
+ const __v4sf v_opacity = _mm_set1_ps (opacity);
+
+ while (samples--)
+ {
+ __v4sf alpha, rgba_in, rgba_comp;
+
+ rgba_in = *v_in ++;
+ rgba_comp = *v_comp++;
+
+ alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_comp,_MM_SHUFFLE(3,3,3,3)) * v_opacity;
+
+ if (mask)
+ {
+ alpha = alpha * _mm_set1_ps (*mask++);
+ }
+
+ if (rgba_in[ALPHA] != 0.0f && _mm_ucomineq_ss (alpha, _mm_setzero_ps ()))
+ {
+ __v4sf out_pixel, out_pixel_rbaa, out_alpha;
+
+ out_alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_in,_MM_SHUFFLE(3,3,3,3));
+ out_pixel = rgba_comp * alpha + rgba_in * (v_one - alpha);
+ out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
+ out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
+
+ *v_out++ = out_pixel;
+ }
+ else
+ {
+ *v_out ++ = rgba_in;
+ }
+ }
+ }
+}
+
+#endif /* COMPILE_SSE2_INTRINISICS */
diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite.c b/app/operations/layer-modes/gimpoperationlayermode-composite.c
new file mode 100644
index 0000000..4275818
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-composite.c
@@ -0,0 +1,434 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode-composite.c
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * 2017 Øyvind Kolås <pippin@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationlayermode-composite.h"
+
+
+/* non-subtractive compositing functions. these functions expect comp[ALPHA]
+ * to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
+ * the value of comp[RED..BLUE] is unconstrained (in particular, it may be
+ * NaN).
+ */
+
+
+void
+gimp_operation_layer_mode_composite_union (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat new_alpha;
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ new_alpha = layer_alpha + (1.0f - layer_alpha) * in_alpha;
+
+ if (layer_alpha == 0.0f || new_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else if (in_alpha == 0.0f)
+ {
+ out[RED] = layer[RED];
+ out[GREEN] = layer[GREEN];
+ out[BLUE] = layer[BLUE];
+ }
+ else
+ {
+ gfloat ratio = layer_alpha / new_alpha;
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = ratio * (in_alpha * (comp[b] - layer[b]) + layer[b] - in[b]) + in[b];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat layer_alpha = comp[ALPHA] * opacity;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ if (in[ALPHA] == 0.0f || layer_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = comp[b] * layer_alpha + in[b] * (1.0f - layer_alpha);
+ }
+
+ out[ALPHA] = in[ALPHA];
+
+ in += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ if (layer_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else if (in[ALPHA] == 0.0f)
+ {
+ out[RED] = layer[RED];
+ out[GREEN] = layer[GREEN];
+ out[BLUE] = layer[BLUE];
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = comp[b] * in[ALPHA] + layer[b] * (1.0f - in[ALPHA]);
+ }
+
+ out[ALPHA] = layer_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_intersection (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat new_alpha = in[ALPHA] * comp[ALPHA] * opacity;
+
+ if (mask)
+ new_alpha *= *mask;
+
+ if (new_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ out[RED] = comp[RED];
+ out[GREEN] = comp[GREEN];
+ out[BLUE] = comp[BLUE];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+/* subtractive compositing functions. these functions expect comp[ALPHA] to
+ * specify the modified alpha of the overlapping content, as a fraction of the
+ * original overlapping content (i.e., an alpha of 1.0 specifies that no
+ * content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value
+ * of comp[RED..BLUE] is unconstrained (in particular, it may be NaN).
+ */
+
+void
+gimp_operation_layer_mode_composite_union_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat comp_alpha = comp[ALPHA];
+ gfloat new_alpha;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ new_alpha = in_alpha + layer_alpha -
+ (2.0f - comp_alpha) * in_alpha * layer_alpha;
+
+ if (layer_alpha == 0.0f || new_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else if (in_alpha == 0.0f)
+ {
+ out[RED] = layer[RED];
+ out[GREEN] = layer[GREEN];
+ out[BLUE] = layer[BLUE];
+ }
+ else
+ {
+ gfloat ratio = in_alpha / new_alpha;
+ gfloat layer_coeff = 1.0f / in_alpha - 1.0f;
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = ratio * (layer_alpha * (comp_alpha * comp[b] + layer_coeff * layer[b] - in[b]) + in[b]);
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat comp_alpha = comp[ALPHA];
+ gfloat new_alpha;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ comp_alpha *= layer_alpha;
+
+ new_alpha = 1.0f - layer_alpha + comp_alpha;
+
+ if (in[ALPHA] == 0.0f || comp_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gfloat ratio = comp_alpha / new_alpha;
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = comp[b] * ratio + in[b] * (1.0f - ratio);
+ }
+
+ new_alpha *= in[ALPHA];
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat comp_alpha = comp[ALPHA];
+ gfloat new_alpha;
+
+ if (mask)
+ layer_alpha *= *mask;
+
+ comp_alpha *= in_alpha;
+
+ new_alpha = 1.0f - in_alpha + comp_alpha;
+
+ if (layer_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else if (in_alpha == 0.0f)
+ {
+ out[RED] = layer[RED];
+ out[GREEN] = layer[GREEN];
+ out[BLUE] = layer[BLUE];
+ }
+ else
+ {
+ gfloat ratio = comp_alpha / new_alpha;
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = comp[b] * ratio + layer[b] * (1.0f - ratio);
+ }
+
+ new_alpha *= layer_alpha;
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
+
+void
+gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples)
+{
+ while (samples--)
+ {
+ gfloat new_alpha = in[ALPHA] * layer[ALPHA] * comp[ALPHA] * opacity;
+
+ if (mask)
+ new_alpha *= *mask;
+
+ if (new_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ out[RED] = comp[RED];
+ out[GREEN] = comp[GREEN];
+ out[BLUE] = comp[BLUE];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ comp += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+}
diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite.h b/app/operations/layer-modes/gimpoperationlayermode-composite.h
new file mode 100644
index 0000000..f9ec2a5
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-composite.h
@@ -0,0 +1,98 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode-composite.h
+ * Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
+ * 2017 Øyvind Kolås <pippin@gimp.org>
+ * 2017 Ell
+ *
+ * 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_OPERATION_LAYER_MODE_COMPOSITE_H__
+#define __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__
+
+
+void gimp_operation_layer_mode_composite_union (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_intersection (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+
+void gimp_operation_layer_mode_composite_union_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+void gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+
+#if COMPILE_SSE2_INTRINISICS
+
+void gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ gfloat opacity,
+ gfloat *out,
+ gint samples);
+
+#endif /* COMPILE_SSE2_INTRINISICS */
+
+
+#endif /* __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationlayermode.c b/app/operations/layer-modes/gimpoperationlayermode.c
new file mode 100644
index 0000000..db74ed5
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode.c
@@ -0,0 +1,914 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.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-plugin.h>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "../operations-types.h"
+
+#include "gimp-layer-modes.h"
+#include "gimpoperationlayermode.h"
+#include "gimpoperationlayermode-composite.h"
+
+
+/* the maximum number of samples to process in one go. used to limit
+ * the size of the buffers we allocate on the stack.
+ */
+#define GIMP_COMPOSITE_BLEND_MAX_SAMPLES ((1 << 18) /* 256 KiB */ / \
+ 16 /* bytes per pixel */ / \
+ 2 /* max number of buffers */)
+
+/* number of consecutive unblended samples (whose source or destination alpha
+ * is zero) above which to split the blending process, in order to avoid
+ * performing too many unnecessary conversions.
+ */
+#define GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD 32
+
+
+enum
+{
+ PROP_0,
+ PROP_LAYER_MODE,
+ PROP_OPACITY,
+ PROP_BLEND_SPACE,
+ PROP_COMPOSITE_SPACE,
+ PROP_COMPOSITE_MODE
+};
+
+
+typedef void (* CompositeFunc) (const gfloat *in,
+ const gfloat *layer,
+ const gfloat *comp,
+ const gfloat *mask,
+ float opacity,
+ gfloat *out,
+ gint samples);
+
+
+static void gimp_operation_layer_mode_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_operation_layer_mode_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_operation_layer_mode_prepare (GeglOperation *operation);
+static GeglRectangle gimp_operation_layer_mode_get_bounding_box (GeglOperation *operation);
+static gboolean gimp_operation_layer_mode_parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level);
+
+static gboolean gimp_operation_layer_mode_process (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+static gboolean gimp_operation_layer_mode_real_parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level);
+static gboolean gimp_operation_layer_mode_real_process (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+static gboolean process_last_node (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+
+G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode,
+ GEGL_TYPE_OPERATION_POINT_COMPOSER3)
+
+#define parent_class gimp_operation_layer_mode_parent_class
+
+
+static const Babl *gimp_layer_color_space_fish[3 /* from */][3 /* to */];
+
+static CompositeFunc composite_union = gimp_operation_layer_mode_composite_union;
+static CompositeFunc composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop;
+static CompositeFunc composite_clip_to_layer = gimp_operation_layer_mode_composite_clip_to_layer;
+static CompositeFunc composite_intersection = gimp_operation_layer_mode_composite_intersection;
+
+static CompositeFunc composite_union_sub = gimp_operation_layer_mode_composite_union_sub;
+static CompositeFunc composite_clip_to_backdrop_sub = gimp_operation_layer_mode_composite_clip_to_backdrop_sub;
+static CompositeFunc composite_clip_to_layer_sub = gimp_operation_layer_mode_composite_clip_to_layer_sub;
+static CompositeFunc composite_intersection_sub = gimp_operation_layer_mode_composite_intersection_sub;
+
+
+static void
+gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GeglOperationPointComposer3Class *point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:layer-mode", NULL);
+
+ object_class->set_property = gimp_operation_layer_mode_set_property;
+ object_class->get_property = gimp_operation_layer_mode_get_property;
+
+ operation_class->prepare = gimp_operation_layer_mode_prepare;
+ operation_class->get_bounding_box = gimp_operation_layer_mode_get_bounding_box;
+ operation_class->process = gimp_operation_layer_mode_parent_process;
+
+ point_composer3_class->process = gimp_operation_layer_mode_process;
+
+ klass->parent_process = gimp_operation_layer_mode_real_parent_process;
+ klass->process = gimp_operation_layer_mode_real_process;
+ klass->get_affected_region = NULL;
+
+ g_object_class_install_property (object_class, PROP_LAYER_MODE,
+ g_param_spec_enum ("layer-mode",
+ NULL, NULL,
+ GIMP_TYPE_LAYER_MODE,
+ GIMP_LAYER_MODE_NORMAL,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_OPACITY,
+ g_param_spec_double ("opacity",
+ NULL, NULL,
+ 0.0, 1.0, 1.0,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_BLEND_SPACE,
+ g_param_spec_enum ("blend-space",
+ NULL, NULL,
+ GIMP_TYPE_LAYER_COLOR_SPACE,
+ GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+
+ g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE,
+ g_param_spec_enum ("composite-space",
+ NULL, NULL,
+ GIMP_TYPE_LAYER_COLOR_SPACE,
+ GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_COMPOSITE_MODE,
+ g_param_spec_enum ("composite-mode",
+ NULL, NULL,
+ GIMP_TYPE_LAYER_COMPOSITE_MODE,
+ GIMP_LAYER_COMPOSITE_UNION,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
+ babl_fish ("RGBA float", "R'G'B'A float");
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] =
+ babl_fish ("RGBA float", "CIE Lab alpha float");
+
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
+ babl_fish ("R'G'B'A float", "RGBA float");
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] =
+ babl_fish ("R'G'B'A float", "CIE Lab alpha float");
+
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
+ babl_fish ("CIE Lab alpha float", "RGBA float");
+ gimp_layer_color_space_fish
+ /* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1]
+ /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
+ babl_fish ("CIE Lab alpha float", "R'G'B'A float");
+
+#if COMPILE_SSE2_INTRINISICS
+ if (gimp_cpu_accel_get_support () & GIMP_CPU_ACCEL_X86_SSE2)
+ composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop_sse2;
+#endif
+}
+
+static void
+gimp_operation_layer_mode_init (GimpOperationLayerMode *self)
+{
+}
+
+static void
+gimp_operation_layer_mode_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object);
+
+ switch (property_id)
+ {
+ case PROP_LAYER_MODE:
+ self->layer_mode = g_value_get_enum (value);
+ break;
+
+ case PROP_OPACITY:
+ self->prop_opacity = g_value_get_double (value);
+ break;
+
+ case PROP_BLEND_SPACE:
+ self->blend_space = g_value_get_enum (value);
+ break;
+
+ case PROP_COMPOSITE_SPACE:
+ self->composite_space = g_value_get_enum (value);
+ break;
+
+ case PROP_COMPOSITE_MODE:
+ self->prop_composite_mode = g_value_get_enum (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_operation_layer_mode_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object);
+
+ switch (property_id)
+ {
+ case PROP_LAYER_MODE:
+ g_value_set_enum (value, self->layer_mode);
+ break;
+
+ case PROP_OPACITY:
+ g_value_set_double (value, self->prop_opacity);
+ break;
+
+ case PROP_BLEND_SPACE:
+ g_value_set_enum (value, self->blend_space);
+ break;
+
+ case PROP_COMPOSITE_SPACE:
+ g_value_set_enum (value, self->composite_space);
+ break;
+
+ case PROP_COMPOSITE_MODE:
+ g_value_set_enum (value, self->prop_composite_mode);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_operation_layer_mode_prepare (GeglOperation *operation)
+{
+ GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (operation);
+ const GeglRectangle *input_extent;
+ const GeglRectangle *mask_extent;
+ const Babl *preferred_format;
+ const Babl *format;
+
+ self->composite_mode = self->prop_composite_mode;
+
+ if (self->composite_mode == GIMP_LAYER_COMPOSITE_AUTO)
+ {
+ self->composite_mode =
+ gimp_layer_mode_get_composite_mode (self->layer_mode);
+
+ g_warn_if_fail (self->composite_mode != GIMP_LAYER_COMPOSITE_AUTO);
+ }
+
+ self->function = gimp_layer_mode_get_function (self->layer_mode);
+ self->blend_function = gimp_layer_mode_get_blend_function (self->layer_mode);
+
+ input_extent = gegl_operation_source_get_bounding_box (operation, "input");
+ mask_extent = gegl_operation_source_get_bounding_box (operation, "aux2");
+
+ /* if the input pad has data, work as usual. */
+ if (input_extent && ! gegl_rectangle_is_empty (input_extent))
+ {
+ self->is_last_node = FALSE;
+
+ preferred_format = gegl_operation_get_source_format (operation, "input");
+ }
+ /* otherwise, we're the last node (corresponding to the bottom layer).
+ * in this case, we render the layer (as if) using UNION mode.
+ */
+ else
+ {
+ self->is_last_node = TRUE;
+
+ /* if the layer mode doesn't affect the source, use a shortcut
+ * function that only applies the opacity/mask to the layer.
+ */
+ if (! (gimp_operation_layer_mode_get_affected_region (self) &
+ GIMP_LAYER_COMPOSITE_REGION_SOURCE))
+ {
+ self->function = process_last_node;
+ }
+ /* otherwise, use the original process function, but force the
+ * composite mode to UNION.
+ */
+ else
+ {
+ self->composite_mode = GIMP_LAYER_COMPOSITE_UNION;
+ }
+
+ preferred_format = gegl_operation_get_source_format (operation, "aux");
+ }
+
+ self->has_mask = mask_extent && ! gegl_rectangle_is_empty (mask_extent);
+
+ format = gimp_layer_mode_get_format (self->layer_mode,
+ self->blend_space,
+ self->composite_space,
+ self->composite_mode,
+ preferred_format);
+
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
+ gegl_operation_set_format (operation, "aux", format);
+ gegl_operation_set_format (operation, "aux2", babl_format ("Y float"));
+}
+
+static GeglRectangle
+gimp_operation_layer_mode_get_bounding_box (GeglOperation *op)
+{
+ GimpOperationLayerMode *self = (gpointer) op;
+ GeglRectangle *in_rect;
+ GeglRectangle *aux_rect;
+ GeglRectangle *aux2_rect;
+ GeglRectangle src_rect = {};
+ GeglRectangle dst_rect = {};
+ GeglRectangle result;
+ GimpLayerCompositeRegion included_region;
+
+ in_rect = gegl_operation_source_get_bounding_box (op, "input");
+ aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
+ aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
+
+ if (in_rect)
+ dst_rect = *in_rect;
+
+ if (aux_rect)
+ {
+ src_rect = *aux_rect;
+
+ if (aux2_rect)
+ gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
+ }
+
+ if (self->is_last_node)
+ {
+ included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+ }
+ else
+ {
+ included_region = gimp_layer_mode_get_included_region (self->layer_mode,
+ self->composite_mode);
+ }
+
+ if (self->prop_opacity == 0.0)
+ included_region &= ~GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+
+ gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
+
+ if (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)
+ gegl_rectangle_bounding_box (&result, &result, &src_rect);
+
+ if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)
+ gegl_rectangle_bounding_box (&result, &result, &dst_rect);
+
+ return result;
+}
+
+static gboolean
+gimp_operation_layer_mode_parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
+
+ point->opacity = point->prop_opacity;
+
+ /* if we have a mask, but it's not included in the output, pretend the
+ * opacity is 0, so that we don't composite 'aux' over 'input' as if there
+ * was no mask.
+ */
+ if (point->has_mask)
+ {
+ GObject *mask;
+ gboolean has_mask;
+
+ /* get the raw value. this does not increase the reference count. */
+ mask = gegl_operation_context_get_object (context, "aux2");
+
+ /* disregard 'mask' if it's not included in the roi. */
+ has_mask =
+ mask &&
+ gegl_rectangle_intersect (NULL,
+ gegl_buffer_get_extent (GEGL_BUFFER (mask)),
+ result);
+
+ if (! has_mask)
+ point->opacity = 0.0;
+ }
+
+ return GIMP_OPERATION_LAYER_MODE_GET_CLASS (point)->parent_process (
+ operation, context, output_prop, result, level);
+}
+
+static gboolean
+gimp_operation_layer_mode_process (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ return ((GimpOperationLayerMode *) operation)->function (
+ operation, in, layer, mask, out, samples, roi, level);
+}
+
+static gboolean
+gimp_operation_layer_mode_real_parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
+ GObject *input;
+ GObject *aux;
+ gboolean has_input;
+ gboolean has_aux;
+ GimpLayerCompositeRegion included_region;
+
+ /* get the raw values. this does not increase the reference count. */
+ input = gegl_operation_context_get_object (context, "input");
+ aux = gegl_operation_context_get_object (context, "aux");
+
+ /* disregard 'input' if it's not included in the roi. */
+ has_input =
+ input &&
+ gegl_rectangle_intersect (NULL,
+ gegl_buffer_get_extent (GEGL_BUFFER (input)),
+ result);
+
+ /* disregard 'aux' if it's not included in the roi, or if it's fully
+ * transparent.
+ */
+ has_aux =
+ aux &&
+ point->opacity != 0.0 &&
+ gegl_rectangle_intersect (NULL,
+ gegl_buffer_get_extent (GEGL_BUFFER (aux)),
+ result);
+
+ if (point->is_last_node)
+ {
+ included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+ }
+ else
+ {
+ included_region = gimp_layer_mode_get_included_region (point->layer_mode,
+ point->composite_mode);
+ }
+
+ /* if there's no 'input' ... */
+ if (! has_input)
+ {
+ /* ... and there's 'aux', and the composite mode includes it (or we're
+ * the last node) ...
+ */
+ if (has_aux && (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE))
+ {
+ GimpLayerCompositeRegion affected_region;
+
+ affected_region =
+ gimp_operation_layer_mode_get_affected_region (point);
+
+ /* ... and the op doesn't otherwise affect 'aux', or changes its
+ * alpha ...
+ */
+ if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE) &&
+ point->opacity == 1.0 &&
+ ! gegl_operation_context_get_object (context, "aux2"))
+ {
+ /* pass 'aux' directly as output; */
+ gegl_operation_context_set_object (context, "output", aux);
+ return TRUE;
+ }
+
+ /* otherwise, if the op affects 'aux', or changes its alpha, process
+ * it even though there's no 'input';
+ */
+ }
+ /* otherwise, there's no 'aux', or the composite mode doesn't include it,
+ * and so ...
+ */
+ else
+ {
+ /* ... the output is empty. */
+ gegl_operation_context_set_object (context, "output", NULL);
+ return TRUE;
+ }
+ }
+ /* otherwise, if there's 'input' but no 'aux' ... */
+ else if (! has_aux)
+ {
+ /* ... and the composite mode includes 'input' ... */
+ if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)
+ {
+ GimpLayerCompositeRegion affected_region;
+
+ affected_region =
+ gimp_operation_layer_mode_get_affected_region (point);
+
+ /* ... and the op doesn't otherwise affect 'input' ... */
+ if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION))
+ {
+ /* pass 'input' directly as output; */
+ gegl_operation_context_set_object (context, "output", input);
+ return TRUE;
+ }
+
+ /* otherwise, if the op affects 'input', process it even though
+ * there's no 'aux';
+ */
+ }
+
+ /* otherwise, the output is fully transparent, but we process it anyway
+ * to maintain the 'input' color values.
+ */
+ }
+
+ /* FIXME: we don't actually handle the case where one of the inputs
+ * is NULL -- it'll just segfault. 'input' is not expected to be NULL,
+ * but 'aux' might be, currently.
+ */
+ if (! input || ! aux)
+ {
+ GObject *empty = G_OBJECT (gegl_buffer_new (NULL, NULL));
+
+ if (! input) gegl_operation_context_set_object (context, "input", empty);
+ if (! aux) gegl_operation_context_set_object (context, "aux", empty);
+
+ if (! input && ! aux)
+ gegl_object_set_has_forked (G_OBJECT (empty));
+
+ g_object_unref (empty);
+ }
+
+ /* chain up, which will create the needed buffers for our actual
+ * process function
+ */
+ return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
+ output_prop, result,
+ level);
+}
+
+static gboolean
+gimp_operation_layer_mode_real_process (GeglOperation *operation,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) operation;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ GimpLayerColorSpace blend_space = layer_mode->blend_space;
+ GimpLayerColorSpace composite_space = layer_mode->composite_space;
+ GimpLayerCompositeMode composite_mode = layer_mode->composite_mode;
+ GimpLayerModeBlendFunc blend_function = layer_mode->blend_function;
+ gboolean composite_needs_in_color;
+ gfloat *blend_in;
+ gfloat *blend_layer;
+ gfloat *blend_out;
+ const Babl *composite_to_blend_fish = NULL;
+ const Babl *blend_to_composite_fish = NULL;
+
+ /* make sure we don't process more than GIMP_COMPOSITE_BLEND_MAX_SAMPLES
+ * at a time, so that we don't overflow the stack if we allocate buffers
+ * on it. note that this has to be done with a nested function call,
+ * because alloca'd buffers remain for the duration of the stack frame.
+ */
+ while (samples > GIMP_COMPOSITE_BLEND_MAX_SAMPLES)
+ {
+ gimp_operation_layer_mode_real_process (operation,
+ in, layer, mask, out,
+ GIMP_COMPOSITE_BLEND_MAX_SAMPLES,
+ roi, level);
+
+ in += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
+ layer += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
+ if (mask)
+ mask += GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
+ out += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
+
+ samples -= GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
+ }
+
+ composite_needs_in_color =
+ composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
+ composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP;
+
+ blend_in = in;
+ blend_layer = layer;
+ blend_out = out;
+
+ if (blend_space != GIMP_LAYER_COLOR_SPACE_AUTO)
+ {
+ gimp_assert (composite_space >= 1 && composite_space < 4);
+ gimp_assert (blend_space >= 1 && blend_space < 4);
+
+ composite_to_blend_fish = gimp_layer_color_space_fish [composite_space - 1]
+ [blend_space - 1];
+
+ blend_to_composite_fish = gimp_layer_color_space_fish [blend_space - 1]
+ [composite_space - 1];
+ }
+
+ /* if we need to convert the samples between the composite and blend
+ * spaces...
+ */
+ if (composite_to_blend_fish)
+ {
+ gint i;
+ gint end;
+
+ if (in != out || composite_needs_in_color)
+ {
+ /* don't convert input in-place if we're not doing in-place output,
+ * or if we're going to need the original input for compositing.
+ */
+ blend_in = g_alloca (sizeof (gfloat) * 4 * samples);
+ }
+ blend_layer = g_alloca (sizeof (gfloat) * 4 * samples);
+
+ if (in == out) /* in-place detected, avoid clobbering since we need to
+ read 'in' for the compositing stage */
+ {
+ if (blend_layer != layer)
+ blend_out = blend_layer;
+ else
+ blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
+ }
+
+ /* samples whose the source or destination alpha is zero are not blended,
+ * and therefore do not need to be converted. while it's generally
+ * desirable to perform conversion and blending in bulk, when we have
+ * more than a certain number of consecutive unblended samples, the cost
+ * of converting them outweighs the cost of splitting the process around
+ * them to avoid the conversion.
+ */
+
+ i = ALPHA;
+ end = 4 * samples + ALPHA;
+
+ while (TRUE)
+ {
+ gint first;
+ gint last;
+ gint count;
+
+ /* skip any unblended samples. the color values of `blend_out` for
+ * these samples are unconstrained, in particular, they may be NaN,
+ * but the alpha values should generally be finite, and specifically
+ * 0 when the source alpha is 0.
+ */
+ while (i < end && (in[i] == 0.0f || layer[i] == 0.0f))
+ {
+ blend_out[i] = 0.0f;
+ i += 4;
+ }
+
+ /* stop if there are no more samples */
+ if (i == end)
+ break;
+
+ /* otherwise, keep scanning the samples until we find
+ * GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD consecutive unblended
+ * samples.
+ */
+
+ first = i;
+ i += 4;
+ last = i;
+
+ while (i < end && i - last < 4 * GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD)
+ {
+ gboolean blended;
+
+ blended = (in[i] != 0.0f && layer[i] != 0.0f);
+
+ i += 4;
+ if (blended)
+ last = i;
+ }
+
+ /* convert and blend the samples in the range [first, last) */
+
+ count = (last - first) / 4;
+ first -= ALPHA;
+
+ babl_process (composite_to_blend_fish,
+ in + first, blend_in + first, count);
+ babl_process (composite_to_blend_fish,
+ layer + first, blend_layer + first, count);
+
+ blend_function (operation, blend_in + first, blend_layer + first,
+ blend_out + first, count);
+
+ babl_process (blend_to_composite_fish,
+ blend_out + first, blend_out + first, count);
+
+ /* make sure the alpha values of `blend_out` are valid for the
+ * trailing unblended samples.
+ */
+ for (; last < i; last += 4)
+ blend_out[last] = 0.0f;
+ }
+ }
+ else
+ {
+ /* if both blending and compositing use the same color space, things are
+ * much simpler.
+ */
+
+ if (in == out) /* in-place detected, avoid clobbering since we need to
+ read 'in' for the compositing stage */
+ {
+ blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
+ }
+
+ blend_function (operation, blend_in, blend_layer, blend_out, samples);
+ }
+
+ if (! gimp_layer_mode_is_subtractive (layer_mode->layer_mode))
+ {
+ switch (composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ composite_union (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ composite_clip_to_backdrop (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ composite_clip_to_layer (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ composite_intersection (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+ }
+ }
+ else
+ {
+ switch (composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ composite_union_sub (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ composite_clip_to_backdrop_sub (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ composite_clip_to_layer_sub (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ composite_intersection_sub (in, layer, blend_out, mask, opacity,
+ out, samples);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+process_last_node (GeglOperation *operation,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = GIMP_OPERATION_LAYER_MODE (operation)->opacity;
+
+ while (samples--)
+ {
+ memcpy (out, layer, 3 * sizeof (gfloat));
+
+ out[ALPHA] = layer[ALPHA] * opacity;
+ if (mask)
+ out[ALPHA] *= *mask++;
+
+ layer += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
+
+/* public functions */
+
+
+GimpLayerCompositeRegion
+gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode)
+{
+ GimpOperationLayerModeClass *klass;
+
+ g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode),
+ GIMP_LAYER_COMPOSITE_REGION_INTERSECTION);
+
+ klass = GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode);
+
+ if (klass->get_affected_region)
+ return klass->get_affected_region (layer_mode);
+
+ return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
+}
diff --git a/app/operations/layer-modes/gimpoperationlayermode.h b/app/operations/layer-modes/gimpoperationlayermode.h
new file mode 100644
index 0000000..a2a5463
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode.h
@@ -0,0 +1,89 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationlayermode.h
+ * Copyright (C) 2008 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_OPERATION_LAYER_MODE_H__
+#define __GIMP_OPERATION_LAYER_MODE_H__
+
+
+#include <gegl-plugin.h>
+
+
+#define GIMP_TYPE_OPERATION_LAYER_MODE (gimp_operation_layer_mode_get_type ())
+#define GIMP_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerMode))
+#define GIMP_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass))
+#define GIMP_IS_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_LAYER_MODE))
+#define GIMP_IS_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_LAYER_MODE))
+#define GIMP_OPERATION_LAYER_MODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass))
+
+
+typedef struct _GimpOperationLayerModeClass GimpOperationLayerModeClass;
+
+struct _GimpOperationLayerMode
+{
+ GeglOperationPointComposer3 parent_instance;
+
+ GimpLayerMode layer_mode;
+ gdouble opacity;
+ GimpLayerColorSpace blend_space;
+ GimpLayerColorSpace composite_space;
+ GimpLayerCompositeMode composite_mode;
+
+ gdouble prop_opacity;
+ GimpLayerCompositeMode prop_composite_mode;
+
+ GimpLayerModeFunc function;
+ GimpLayerModeBlendFunc blend_function;
+ gboolean is_last_node;
+ gboolean has_mask;
+};
+
+struct _GimpOperationLayerModeClass
+{
+ GeglOperationPointComposer3Class parent_class;
+
+ /* virtual functions */
+ gboolean (* parent_process) (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level);
+ gboolean (* process) (GeglOperation *operation,
+ void *in,
+ void *aux,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+ /* Returns the composite region (any combination of the layer and the
+ * backdrop) that the layer mode affects. Most modes only affect the
+ * overlapping region, and don't need to override this function.
+ */
+ GimpLayerCompositeRegion (* get_affected_region) (GimpOperationLayerMode *layer_mode);
+};
+
+
+GType gimp_operation_layer_mode_get_type (void) G_GNUC_CONST;
+
+GimpLayerCompositeRegion gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode);
+
+
+#endif /* __GIMP_OPERATION_LAYER_MODE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationmerge.c b/app/operations/layer-modes/gimpoperationmerge.c
new file mode 100644
index 0000000..e1b25ca
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationmerge.c
@@ -0,0 +1,243 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationmerge.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationmerge.h"
+
+
+static gboolean gimp_operation_merge_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+
+G_DEFINE_TYPE (GimpOperationMerge, gimp_operation_merge,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_merge_class_init (GimpOperationMergeClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:merge",
+ "description", "GIMP merge mode operation",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_merge_process;
+}
+
+static void
+gimp_operation_merge_init (GimpOperationMerge *self)
+{
+}
+
+static gboolean
+gimp_operation_merge_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ in_alpha = MIN (in_alpha, 1.0f - layer_alpha);
+ new_alpha = in_alpha + layer_alpha;
+
+ if (new_alpha)
+ {
+ gfloat ratio = layer_alpha / new_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b] + (layer[b] - in[b]) * ratio;
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ layer_alpha -= 1.0f - in_alpha;
+
+ if (layer_alpha > 0.0f)
+ {
+ gfloat ratio = layer_alpha / in_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b] + (layer[b] - in[b]) * ratio;
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = in_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ if (layer_alpha != 0.0f)
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = layer_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ layer_alpha -= 1.0f - in_alpha;
+ layer_alpha = MAX (layer_alpha, 0.0f);
+
+ if (layer_alpha != 0.0f)
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = layer_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationmerge.h b/app/operations/layer-modes/gimpoperationmerge.h
new file mode 100644
index 0000000..01afde1
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationmerge.h
@@ -0,0 +1,54 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationmerge.h
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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_OPERATION_MERGE_H__
+#define __GIMP_OPERATION_MERGE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_MERGE (gimp_operation_merge_get_type ())
+#define GIMP_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMerge))
+#define GIMP_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass))
+#define GIMP_IS_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MERGE))
+#define GIMP_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_MERGE))
+#define GIMP_OPERATION_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass))
+
+
+typedef struct _GimpOperationMerge GimpOperationMerge;
+typedef struct _GimpOperationMergeClass GimpOperationMergeClass;
+
+struct _GimpOperationMerge
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationMergeClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_merge_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_MERGE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationnormal-sse2.c b/app/operations/layer-modes/gimpoperationnormal-sse2.c
new file mode 100644
index 0000000..73e42ed
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationnormal-sse2.c
@@ -0,0 +1,264 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationnormal-sse2.c
+ * Copyright (C) 2013 Daniel Sabo
+ *
+ * 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-plugin.h>
+
+#include "operations/operations-types.h"
+
+#include "gimpoperationnormal.h"
+
+
+#if COMPILE_SSE2_INTRINISICS
+
+/* SSE2 */
+#include <emmintrin.h>
+
+
+gboolean
+gimp_operation_normal_process_sse2 (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ /* check alignment */
+ if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
+ {
+ return gimp_operation_normal_process (op,
+ in_p, layer_p, mask_p, out_p,
+ samples, roi, level);
+ }
+ else
+ {
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat opacity = layer_mode->opacity;
+ gfloat *mask = mask_p;
+ const __v4sf *v_in = (const __v4sf*) in_p;
+ const __v4sf *v_layer = (const __v4sf*) layer_p;
+ __v4sf *v_out = ( __v4sf*) out_p;
+
+ const __v4sf one = _mm_set1_ps (1.0f);
+ const __v4sf v_opacity = _mm_set1_ps (opacity);
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ __v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa;
+
+ /* expand alpha */
+ dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ /* a_term = dst_a * (1.0 - src_a) */
+ a_term = dst_alpha * (one - alpha);
+
+ /* out(color) = src * src_a + dst * a_term */
+ out_pixel = rgba_layer * alpha + rgba_in * a_term;
+
+ /* out(alpha) = 1.0 * src_a + 1.0 * a_term */
+ out_alpha = alpha + a_term;
+
+ /* un-premultiply */
+ out_pixel = out_pixel / out_alpha;
+
+ /* swap in the real alpha */
+ out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
+ out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
+
+ *v_out++ = out_pixel;
+ }
+ else
+ {
+ *v_out++ = rgba_in;
+ }
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ __v4sf dst_alpha, out_pixel, out_pixel_rbaa;
+
+ /* expand alpha */
+ dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ /* out(color) = dst * (1 - src_a) + src * src_a */
+ out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
+
+ /* swap in the real alpha */
+ out_pixel_rbaa = _mm_shuffle_ps (out_pixel, dst_alpha, _MM_SHUFFLE (3, 3, 2, 0));
+ out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
+
+ *v_out++ = out_pixel;
+ }
+ else
+ {
+ *v_out++ = rgba_in;
+ }
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+ __v4sf out_pixel, out_pixel_rbaa;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ /* out(color) = src */
+ out_pixel = rgba_layer;
+ }
+ else
+ {
+ out_pixel = rgba_in;
+ }
+
+ /* swap in the real alpha */
+ out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
+ out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
+
+ *v_out++ = out_pixel;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+ __v4sf out_pixel, out_pixel_rbaa;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ /* multiply the alpha by in's alpha */
+ alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ /* out(color) = src */
+ out_pixel = rgba_layer;
+ }
+ else
+ {
+ out_pixel = rgba_in;
+ }
+
+ /* swap in the real alpha */
+ out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
+ out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
+
+ *v_out++ = out_pixel;
+ }
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+#endif /* COMPILE_SSE2_INTRINISICS */
diff --git a/app/operations/layer-modes/gimpoperationnormal-sse4.c b/app/operations/layer-modes/gimpoperationnormal-sse4.c
new file mode 100644
index 0000000..ba621a2
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationnormal-sse4.c
@@ -0,0 +1,260 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationnormalmode-sse2.c
+ * Copyright (C) 2013 Daniel Sabo
+ *
+ * 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-plugin.h>
+
+#include "operations/operations-types.h"
+
+#include "gimpoperationnormal.h"
+
+
+#if COMPILE_SSE4_1_INTRINISICS
+
+/* SSE4 */
+#include <smmintrin.h>
+
+
+gboolean
+gimp_operation_normal_process_sse4 (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ /* check alignment */
+ if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
+ {
+ return gimp_operation_normal_process (op,
+ in_p, layer_p, mask_p, out_p,
+ samples, roi, level);
+ }
+ else
+ {
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat opacity = layer_mode->opacity;
+ gfloat *mask = mask_p;
+ const __v4sf *v_in = (const __v4sf*) in_p;
+ const __v4sf *v_layer = (const __v4sf*) layer_p;
+ __v4sf *v_out = ( __v4sf*) out_p;
+
+ const __v4sf one = _mm_set1_ps (1.0f);
+ const __v4sf v_opacity = _mm_set1_ps (opacity);
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ __v4sf dst_alpha, a_term, out_pixel, out_alpha;
+
+ /* expand alpha */
+ dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ /* a_term = dst_a * (1.0 - src_a) */
+ a_term = dst_alpha * (one - alpha);
+
+ /* out(color) = src * src_a + dst * a_term */
+ out_pixel = rgba_layer * alpha + rgba_in * a_term;
+
+ /* out(alpha) = 1.0 * src_a + 1.0 * a_term */
+ out_alpha = alpha + a_term;
+
+ /* un-premultiply */
+ out_pixel = out_pixel / out_alpha;
+
+ /* swap in the real alpha */
+ out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08);
+
+ *v_out++ = out_pixel;
+ }
+ else
+ {
+ *v_out++ = rgba_in;
+ }
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ __v4sf dst_alpha, out_pixel;
+
+ /* expand alpha */
+ dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ /* out(color) = dst * (1 - src_a) + src * src_a */
+ out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
+
+ /* swap in the real alpha */
+ out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08);
+
+ *v_out++ = out_pixel;
+ }
+ else
+ {
+ *v_out++ = rgba_in;
+ }
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+ __v4sf out_pixel;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ /* out(color) = src */
+ out_pixel = rgba_layer;
+ }
+ else
+ {
+ out_pixel = rgba_in;
+ }
+
+ /* swap in the real alpha */
+ out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
+
+ *v_out++ = out_pixel;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ __v4sf rgba_in, rgba_layer, alpha;
+ __v4sf out_pixel;
+
+ rgba_in = *v_in++;
+ rgba_layer = *v_layer++;
+
+ /* expand alpha */
+ alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (mask)
+ {
+ __v4sf mask_alpha;
+
+ /* multiply layer's alpha by the mask */
+ mask_alpha = _mm_set1_ps (*mask++);
+ alpha = alpha * mask_alpha;
+ }
+
+ alpha = alpha * v_opacity;
+
+ /* multiply the alpha by in's alpha */
+ alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
+ _MM_SHUFFLE (3, 3, 3, 3));
+
+ if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
+ {
+ /* out(color) = src */
+ out_pixel = rgba_layer;
+ }
+ else
+ {
+ out_pixel = rgba_in;
+ }
+
+ /* swap in the real alpha */
+ out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
+
+ *v_out++ = out_pixel;
+ }
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+#endif /* COMPILE_SSE4_1_INTRINISICS */
diff --git a/app/operations/layer-modes/gimpoperationnormal.c b/app/operations/layer-modes/gimpoperationnormal.c
new file mode 100644
index 0000000..9bd8705
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationnormal.c
@@ -0,0 +1,266 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationnormalmode.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 <gio/gio.h>
+#include <gegl-plugin.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "../operations-types.h"
+
+#include "gimpoperationnormal.h"
+
+
+G_DEFINE_TYPE (GimpOperationNormal, gimp_operation_normal,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
+"<gegl>"
+"<node operation='gimp:normal'>"
+" <node operation='gegl:load'>"
+" <params>"
+" <param name='path'>blending-test-B.png</param>"
+" </params>"
+" </node>"
+"</node>"
+"<node operation='gegl:load'>"
+" <params>"
+" <param name='path'>blending-test-A.png</param>"
+" </params>"
+"</node>"
+"</gegl>";
+
+
+static void
+gimp_operation_normal_class_init (GimpOperationNormalClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:normal",
+ "description", "GIMP normal mode operation",
+ "reference-image", "normal-mode.png",
+ "reference-composition", reference_xml,
+ NULL);
+
+ layer_mode_class->process = gimp_operation_normal_process;
+
+#if COMPILE_SSE2_INTRINISICS
+ if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE2)
+ layer_mode_class->process = gimp_operation_normal_process_sse2;
+#endif /* COMPILE_SSE2_INTRINISICS */
+
+#if COMPILE_SSE4_1_INTRINISICS
+ if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE4_1)
+ layer_mode_class->process = gimp_operation_normal_process_sse4;
+#endif /* COMPILE_SSE4_1_INTRINISICS */
+}
+
+static void
+gimp_operation_normal_init (GimpOperationNormal *self)
+{
+}
+
+gboolean
+gimp_operation_normal_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+
+ layer_alpha = layer[ALPHA] * opacity;
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA];
+
+ if (out[ALPHA])
+ {
+ gfloat layer_weight = layer_alpha / out[ALPHA];
+ gfloat in_weight = 1.0f - layer_weight;
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b] * layer_weight + in[b] * in_weight;
+ }
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+
+ layer_alpha = layer[ALPHA] * opacity;
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ out[ALPHA] = in[ALPHA];
+
+ if (out[ALPHA])
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b] + (layer[b] - in[b]) * layer_alpha;
+ }
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+
+ layer_alpha = layer[ALPHA] * opacity;
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ out[ALPHA] = layer_alpha;
+
+ if (out[ALPHA])
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gfloat layer_alpha;
+
+ layer_alpha = layer[ALPHA] * opacity;
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ out[ALPHA] = in[ALPHA] * layer_alpha;
+
+ if (out[ALPHA])
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+ else
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationnormal.h b/app/operations/layer-modes/gimpoperationnormal.h
new file mode 100644
index 0000000..6fa1b36
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationnormal.h
@@ -0,0 +1,91 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationnormal.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_OPERATION_NORMAL_H__
+#define __GIMP_OPERATION_NORMAL_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_NORMAL (gimp_operation_normal_get_type ())
+#define GIMP_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormal))
+#define GIMP_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass))
+#define GIMP_IS_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_NORMAL))
+#define GIMP_IS_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_NORMAL))
+#define GIMP_OPERATION_NORMAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass))
+
+
+typedef struct _GimpOperationNormal GimpOperationNormal;
+typedef struct _GimpOperationNormalClass GimpOperationNormalClass;
+
+struct _GimpOperationNormal
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationNormalClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_normal_get_type (void) G_GNUC_CONST;
+
+
+/* protected */
+
+gboolean gimp_operation_normal_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+#if COMPILE_SSE2_INTRINISICS
+
+gboolean gimp_operation_normal_process_sse2 (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+#endif /* COMPILE_SSE2_INTRINISICS */
+
+#if COMPILE_SSE4_1_INTRINISICS
+
+gboolean gimp_operation_normal_process_sse4 (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+#endif /* COMPILE_SSE4_1_INTRINISICS */
+
+
+#endif /* __GIMP_OPERATION_NORMAL_H__ */
diff --git a/app/operations/layer-modes/gimpoperationpassthrough.c b/app/operations/layer-modes/gimpoperationpassthrough.c
new file mode 100644
index 0000000..bc7d328
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationpassthrough.c
@@ -0,0 +1,55 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationpassthrough.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationpassthrough.h"
+
+
+G_DEFINE_TYPE (GimpOperationPassThrough, gimp_operation_pass_through,
+ GIMP_TYPE_OPERATION_REPLACE)
+
+
+static void
+gimp_operation_pass_through_class_init (GimpOperationPassThroughClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:pass-through",
+ "description", "GIMP pass through mode operation",
+ NULL);
+
+ /* don't use REPLACE mode's specialized get_affected_region(); PASS_THROUGH
+ * behaves like an ordinary layer mode here.
+ */
+ layer_mode_class->get_affected_region = NULL;
+}
+
+static void
+gimp_operation_pass_through_init (GimpOperationPassThrough *self)
+{
+}
diff --git a/app/operations/layer-modes/gimpoperationpassthrough.h b/app/operations/layer-modes/gimpoperationpassthrough.h
new file mode 100644
index 0000000..5a5b838
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationpassthrough.h
@@ -0,0 +1,54 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationpassthrough.h
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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_OPERATION_PASS_THROUGH_H__
+#define __GIMP_OPERATION_PASS_THROUGH_H__
+
+
+#include "gimpoperationreplace.h"
+
+
+#define GIMP_TYPE_OPERATION_PASS_THROUGH (gimp_operation_pass_through_get_type ())
+#define GIMP_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThrough))
+#define GIMP_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass))
+#define GIMP_IS_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH))
+#define GIMP_IS_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH))
+#define GIMP_OPERATION_PASS_THROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass))
+
+
+typedef struct _GimpOperationPassThrough GimpOperationPassThrough;
+typedef struct _GimpOperationPassThroughClass GimpOperationPassThroughClass;
+
+struct _GimpOperationPassThrough
+{
+ GimpOperationReplace parent_instance;
+};
+
+struct _GimpOperationPassThroughClass
+{
+ GimpOperationReplaceClass parent_class;
+};
+
+
+GType gimp_operation_pass_through_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_PASS_THROUGH_H__ */
diff --git a/app/operations/layer-modes/gimpoperationreplace.c b/app/operations/layer-modes/gimpoperationreplace.c
new file mode 100644
index 0000000..ed1ac19
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationreplace.c
@@ -0,0 +1,347 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationreplace.c
+ * Copyright (C) 2008 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimp-layer-modes.h"
+#include "gimpoperationreplace.h"
+
+
+static GeglRectangle gimp_operation_replace_get_bounding_box (GeglOperation *op);
+
+static gboolean gimp_operation_replace_parent_process (GeglOperation *op,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level);
+static gboolean gimp_operation_replace_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+static GimpLayerCompositeRegion gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode);
+
+
+G_DEFINE_TYPE (GimpOperationReplace, gimp_operation_replace,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+#define parent_class gimp_operation_replace_parent_class
+
+
+static void
+gimp_operation_replace_class_init (GimpOperationReplaceClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:replace",
+ "description", "GIMP replace mode operation",
+ NULL);
+
+ operation_class->get_bounding_box = gimp_operation_replace_get_bounding_box;
+
+ layer_mode_class->parent_process = gimp_operation_replace_parent_process;
+ layer_mode_class->process = gimp_operation_replace_process;
+ layer_mode_class->get_affected_region = gimp_operation_replace_get_affected_region;
+}
+
+static void
+gimp_operation_replace_init (GimpOperationReplace *self)
+{
+}
+
+static GeglRectangle
+gimp_operation_replace_get_bounding_box (GeglOperation *op)
+{
+ GimpOperationLayerMode *self = (gpointer) op;
+ GeglRectangle *in_rect;
+ GeglRectangle *aux_rect;
+ GeglRectangle *aux2_rect;
+ GeglRectangle src_rect = {};
+ GeglRectangle dst_rect = {};
+ GeglRectangle result;
+ GimpLayerCompositeRegion included_region;
+
+ in_rect = gegl_operation_source_get_bounding_box (op, "input");
+ aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
+ aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
+
+ if (in_rect)
+ dst_rect = *in_rect;
+
+ if (aux_rect)
+ {
+ src_rect = *aux_rect;
+
+ if (aux2_rect)
+ gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
+ }
+
+ if (self->is_last_node)
+ {
+ included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+ }
+ else
+ {
+ included_region = gimp_layer_mode_get_included_region (self->layer_mode,
+ self->composite_mode);
+ }
+
+ if (self->prop_opacity == 0.0)
+ included_region &= ~GIMP_LAYER_COMPOSITE_REGION_SOURCE;
+ else if (self->prop_opacity == 1.0 && ! aux2_rect)
+ included_region &= ~GIMP_LAYER_COMPOSITE_REGION_DESTINATION;
+
+ gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
+
+ if (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)
+ gegl_rectangle_bounding_box (&result, &result, &src_rect);
+
+ if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)
+ gegl_rectangle_bounding_box (&result, &result, &dst_rect);
+
+ return result;
+}
+
+static gboolean
+gimp_operation_replace_parent_process (GeglOperation *op,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ GimpLayerCompositeRegion included_region;
+
+ included_region = gimp_layer_mode_get_included_region
+ (layer_mode->layer_mode, layer_mode->composite_mode);
+
+ /* if the layer's opacity is 100%, it has no mask, and its composite mode
+ * contains "aux" (the latter should always be the case in practice,
+ * currently,) we can just pass "aux" directly as output.
+ */
+ if (layer_mode->opacity == 1.0 &&
+ ! gegl_operation_context_get_object (context, "aux2") &&
+ (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE))
+ {
+ GObject *aux;
+
+ aux = gegl_operation_context_get_object (context, "aux");
+
+ gegl_operation_context_set_object (context, "output", aux);
+
+ return TRUE;
+ }
+ /* the opposite case, where the opacity is 0%, is handled by
+ * GimpOperationLayerMode.
+ */
+ else if (layer_mode->opacity == 0.0)
+ {
+ }
+ /* if both buffers are included in the result, and if both of them have the
+ * same content -- i.e., if they share the same storage, same alignment, and
+ * same abyss (or if the abyss is irrelevant) -- we can just pass either of
+ * them directly as output.
+ */
+ else if (included_region == GIMP_LAYER_COMPOSITE_REGION_UNION)
+ {
+ GObject *input;
+ GObject *aux;
+
+ input = gegl_operation_context_get_object (context, "input");
+ aux = gegl_operation_context_get_object (context, "aux");
+
+ if (input && aux &&
+ gegl_buffer_share_storage (GEGL_BUFFER (input), GEGL_BUFFER (aux)))
+ {
+ gint input_shift_x;
+ gint input_shift_y;
+ gint aux_shift_x;
+ gint aux_shift_y;
+
+ g_object_get (input,
+ "shift-x", &input_shift_x,
+ "shift-y", &input_shift_y,
+ NULL);
+ g_object_get (aux,
+ "shift-x", &aux_shift_x,
+ "shift-y", &aux_shift_y,
+ NULL);
+
+ if (input_shift_x == aux_shift_x && input_shift_y == aux_shift_y)
+ {
+ const GeglRectangle *input_abyss;
+ const GeglRectangle *aux_abyss;
+
+ input_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (input));
+ aux_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (aux));
+
+ if (gegl_rectangle_equal (input_abyss, aux_abyss) ||
+ (gegl_rectangle_contains (input_abyss, result) &&
+ gegl_rectangle_contains (aux_abyss, result)))
+ {
+ gegl_operation_context_set_object (context, "output", input);
+
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return GIMP_OPERATION_LAYER_MODE_CLASS (parent_class)->parent_process (
+ op, context, output_prop, result, level);
+}
+
+static gboolean
+gimp_operation_replace_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat opacity_value = opacity;
+ gfloat new_alpha;
+ gfloat ratio;
+ gint b;
+
+ if (has_mask)
+ opacity_value *= *mask;
+
+ new_alpha = (layer[ALPHA] - in[ALPHA]) * opacity_value + in[ALPHA];
+
+ ratio = opacity_value;
+
+ if (new_alpha)
+ ratio *= layer[ALPHA] / new_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = (layer[b] - in[b]) * ratio + in[b];
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ while (samples--)
+ {
+ gfloat opacity_value = opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ opacity_value *= *mask;
+
+ new_alpha = in[ALPHA] * (1.0f - opacity_value);
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = in[b];
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat opacity_value = opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ opacity_value *= *mask;
+
+ new_alpha = layer[ALPHA] * opacity_value;
+
+ for (b = RED; b < ALPHA; b++)
+ out[b] = layer[b];
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ memset (out, 0, 4 * samples * sizeof (gfloat));
+ break;
+ }
+
+ return TRUE;
+}
+
+static GimpLayerCompositeRegion
+gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode)
+{
+ GimpLayerCompositeRegion affected_region = GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
+
+ if (layer_mode->prop_opacity != 0.0)
+ affected_region |= GIMP_LAYER_COMPOSITE_REGION_DESTINATION;
+
+ /* if opacity != 1.0, or we have a mask, then we also affect SOURCE, but this
+ * is considered the case anyway, so no need for special handling.
+ */
+
+ return affected_region;
+}
diff --git a/app/operations/layer-modes/gimpoperationreplace.h b/app/operations/layer-modes/gimpoperationreplace.h
new file mode 100644
index 0000000..f8d7b0c
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationreplace.h
@@ -0,0 +1,53 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationreplace.h
+ * Copyright (C) 2008 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_OPERATION_REPLACE_H__
+#define __GIMP_OPERATION_REPLACE_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_REPLACE (gimp_operation_replace_get_type ())
+#define GIMP_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplace))
+#define GIMP_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass))
+#define GIMP_IS_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_REPLACE))
+#define GIMP_IS_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_REPLACE))
+#define GIMP_OPERATION_REPLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass))
+
+
+typedef struct _GimpOperationReplace GimpOperationReplace;
+typedef struct _GimpOperationReplaceClass GimpOperationReplaceClass;
+
+struct _GimpOperationReplace
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationReplaceClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_replace_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_REPLACE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationsplit.c b/app/operations/layer-modes/gimpoperationsplit.c
new file mode 100644
index 0000000..fe83d3f
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationsplit.c
@@ -0,0 +1,213 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationsplit.c
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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-plugin.h>
+
+#include "../operations-types.h"
+
+#include "gimpoperationsplit.h"
+
+
+static gboolean gimp_operation_split_process (GeglOperation *op,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
+
+G_DEFINE_TYPE (GimpOperationSplit, gimp_operation_split,
+ GIMP_TYPE_OPERATION_LAYER_MODE)
+
+
+static void
+gimp_operation_split_class_init (GimpOperationSplitClass *klass)
+{
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+ GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gimp:split",
+ "description", "GIMP split mode operation",
+ NULL);
+
+ layer_mode_class->process = gimp_operation_split_process;
+}
+
+static void
+gimp_operation_split_init (GimpOperationSplit *self)
+{
+}
+
+static gboolean
+gimp_operation_split_process (GeglOperation *op,
+ void *in_p,
+ void *layer_p,
+ void *mask_p,
+ void *out_p,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *layer_mode = (gpointer) op;
+ gfloat *in = in_p;
+ gfloat *out = out_p;
+ gfloat *layer = layer_p;
+ gfloat *mask = mask_p;
+ gfloat opacity = layer_mode->opacity;
+ const gboolean has_mask = mask != NULL;
+
+ switch (layer_mode->composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_UNION:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ if (layer_alpha <= in_alpha)
+ {
+ new_alpha = in_alpha - layer_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+ else
+ {
+ new_alpha = layer_alpha - in_alpha;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
+ case GIMP_LAYER_COMPOSITE_AUTO:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ new_alpha = MAX (in_alpha - layer_alpha, 0.0f);
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
+ while (samples--)
+ {
+ gfloat in_alpha = in[ALPHA];
+ gfloat layer_alpha = layer[ALPHA] * opacity;
+ gfloat new_alpha;
+ gint b;
+
+ if (has_mask)
+ layer_alpha *= *mask;
+
+ new_alpha = MAX (layer_alpha - in_alpha, 0.0f);
+
+ if (new_alpha != 0.0f)
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = layer[b];
+ }
+ }
+ else
+ {
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+ }
+
+ out[ALPHA] = new_alpha;
+
+ in += 4;
+ layer += 4;
+ out += 4;
+
+ if (has_mask)
+ mask++;
+ }
+ break;
+
+ case GIMP_LAYER_COMPOSITE_INTERSECTION:
+ while (samples--)
+ {
+ gint b;
+
+ for (b = RED; b < ALPHA; b++)
+ {
+ out[b] = in[b];
+ }
+
+ out[ALPHA] = 0.0f;
+
+ in += 4;
+ out += 4;
+ }
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/operations/layer-modes/gimpoperationsplit.h b/app/operations/layer-modes/gimpoperationsplit.h
new file mode 100644
index 0000000..e1dbbe9
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationsplit.h
@@ -0,0 +1,54 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpoperationsplit.h
+ * Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
+ * 2017 Ell
+ *
+ * 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_OPERATION_SPLIT_H__
+#define __GIMP_OPERATION_SPLIT_H__
+
+
+#include "gimpoperationlayermode.h"
+
+
+#define GIMP_TYPE_OPERATION_SPLIT (gimp_operation_split_get_type ())
+#define GIMP_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplit))
+#define GIMP_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
+#define GIMP_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SPLIT))
+#define GIMP_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SPLIT))
+#define GIMP_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
+
+
+typedef struct _GimpOperationSplit GimpOperationSplit;
+typedef struct _GimpOperationSplitClass GimpOperationSplitClass;
+
+struct _GimpOperationSplit
+{
+ GimpOperationLayerMode parent_instance;
+};
+
+struct _GimpOperationSplitClass
+{
+ GimpOperationLayerModeClass parent_class;
+};
+
+
+GType gimp_operation_split_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_SPLIT_H__ */