[gimp] app: layer mode code shuffling



commit 71bbd88e00ccfd5b27c17c1fa3c1c9fe9ced3797
Author: Ell <ell_se yahoo com>
Date:   Thu Aug 17 10:26:49 2017 -0400

    app: layer mode code shuffling
    
    Commit 3635cf04ab69bafb76d7583da804f580f2d5fbf3 moved the special
    handling of bottom-layer compositing to GimpOperationLayerMode.
    This required giving the op more control over the process()
    function of its subclasses.  As a temporary workaround, the commit
    bypassed the subclasses entirely, using "gimp:layer-mode" for all
    modes.  This is the reckoning :)
    
    Add a process() virtual function to GimpOperationLayerMode, which
    its subclasses should override instead of
    GeglOperationPointComposer3's process() functions.  Reinstate the
    subclasses (by returning the correct op in
    gimp_layer_mode_get_oepration()), and have them override this
    function.
    
    Improve the way gimp_operation_layer_mode_process() dispatches to
    the actual process function, to slightly lower its overhead and
    fix some thread-safety issues.
    
    Remove the "function" field of the layer-mode info array, and have
    gimp_layer_mode_get_function() return the
    GimpOperationLayerMode::process() function of the corresponding
    op's class (caching the result, to keep it cheap.)  This reduces
    redundancy, allows us to make the ops' process() functions private,
    and simplifies SSE dispatching (only used by NORMAL mode,
    currently.)
    
    Move the blend and composite functions of the non-specialized
    layer modes to gimpoperationlayermode-{blend,composite}.[hc],
    respectively, to improve code organization.
    
    Move the SSE2 composite functions to a separate file, so that they
    can be built as part of libapplayermodes_sse2, allowing
    libapplayermodes to be built without SSE2 compiler flags.  This
    allows building GIMP with SSE acceleration enabled, while running
    the resulting binary on a target with no SSE accelration.
    
    Add a "blend_function" field to the layer-mode info array, and use
    it to specify the blend function for the non-specialized modes.
    This replaces the separate switch() statement that we used
    previously.
    
    Remove the "affected_region" field of the layer-mode info array.
    We don't need it anymore, since we can go back to using
    GimpOperationLayerMode's virtual get_affected_region() function.
    
    Last but not least, a bunch of code cleanups and consistency
    adjustments.

 app/Makefile.am                                    |    2 +-
 app/config/Makefile.am                             |    2 +-
 .../gimpoperationadditionlegacy.c                  |   21 +-
 .../gimpoperationadditionlegacy.h                  |   11 +-
 .../layer-modes-legacy/gimpoperationburnlegacy.c   |   22 +-
 .../layer-modes-legacy/gimpoperationburnlegacy.h   |   11 +-
 .../gimpoperationdarkenonlylegacy.c                |   21 +-
 .../gimpoperationdarkenonlylegacy.h                |   11 +-
 .../gimpoperationdifferencelegacy.c                |   21 +-
 .../gimpoperationdifferencelegacy.h                |   11 +-
 .../layer-modes-legacy/gimpoperationdividelegacy.c |   21 +-
 .../layer-modes-legacy/gimpoperationdividelegacy.h |   11 +-
 .../layer-modes-legacy/gimpoperationdodgelegacy.c  |   21 +-
 .../layer-modes-legacy/gimpoperationdodgelegacy.h  |   11 +-
 .../gimpoperationgrainextractlegacy.c              |   21 +-
 .../gimpoperationgrainextractlegacy.h              |   11 +-
 .../gimpoperationgrainmergelegacy.c                |   21 +-
 .../gimpoperationgrainmergelegacy.h                |   11 +-
 .../gimpoperationhardlightlegacy.c                 |   21 +-
 .../gimpoperationhardlightlegacy.h                 |   11 +-
 .../gimpoperationhslcolorlegacy.c                  |   21 +-
 .../gimpoperationhslcolorlegacy.h                  |   11 +-
 .../layer-modes-legacy/gimpoperationhsvhuelegacy.c |   21 +-
 .../layer-modes-legacy/gimpoperationhsvhuelegacy.h |   11 +-
 .../gimpoperationhsvsaturationlegacy.c             |   21 +-
 .../gimpoperationhsvsaturationlegacy.h             |   11 +-
 .../gimpoperationhsvvaluelegacy.c                  |   21 +-
 .../gimpoperationhsvvaluelegacy.h                  |   11 +-
 .../gimpoperationlightenonlylegacy.c               |   21 +-
 .../gimpoperationlightenonlylegacy.h               |   11 +-
 .../gimpoperationmultiplylegacy.c                  |   21 +-
 .../gimpoperationmultiplylegacy.h                  |   11 +-
 .../layer-modes-legacy/gimpoperationscreenlegacy.c |   21 +-
 .../layer-modes-legacy/gimpoperationscreenlegacy.h |   11 +-
 .../gimpoperationsoftlightlegacy.c                 |   21 +-
 .../gimpoperationsoftlightlegacy.h                 |   11 +-
 .../gimpoperationsubtractlegacy.c                  |   21 +-
 .../gimpoperationsubtractlegacy.h                  |   11 +-
 app/operations/layer-modes/Makefile.am             |   45 +-
 app/operations/layer-modes/gimp-layer-modes.c      |  192 +-
 app/operations/layer-modes/gimp-layer-modes.h      |    3 +-
 .../layer-modes/gimpoperationantierase.c           |   27 +-
 .../layer-modes/gimpoperationantierase.h           |   11 +-
 app/operations/layer-modes/gimpoperationbehind.c   |   24 +-
 app/operations/layer-modes/gimpoperationbehind.h   |    9 -
 app/operations/layer-modes/gimpoperationdissolve.c |   38 +-
 app/operations/layer-modes/gimpoperationdissolve.h |   11 +-
 app/operations/layer-modes/gimpoperationerase.c    |   23 +-
 app/operations/layer-modes/gimpoperationerase.h    |   11 +-
 .../layer-modes/gimpoperationlayermode-blend.c     | 1168 +++++++++++
 .../layer-modes/gimpoperationlayermode-blend.h     |  167 ++
 .../gimpoperationlayermode-composite-sse2.c        |  105 +
 .../layer-modes/gimpoperationlayermode-composite.c |  434 ++++
 .../layer-modes/gimpoperationlayermode-composite.h |   98 +
 .../layer-modes/gimpoperationlayermode.c           | 2162 ++------------------
 .../layer-modes/gimpoperationlayermode.h           |   49 +-
 app/operations/layer-modes/gimpoperationmerge.c    |   23 +-
 app/operations/layer-modes/gimpoperationmerge.h    |   11 +-
 .../layer-modes/gimpoperationnormal-sse2.c         |   79 +-
 .../layer-modes/gimpoperationnormal-sse4.c         |   80 +-
 app/operations/layer-modes/gimpoperationnormal.c   |   43 +-
 app/operations/layer-modes/gimpoperationnormal.h   |   76 +-
 app/operations/layer-modes/gimpoperationreplace.c  |   26 +-
 app/operations/layer-modes/gimpoperationreplace.h  |   11 +-
 app/operations/layer-modes/gimpoperationsplit.c    |   23 +-
 app/operations/layer-modes/gimpoperationsplit.h    |   11 +-
 app/operations/operations-types.h                  |   26 +-
 app/paint/gimppaintcore-loops.c                    |   54 +-
 app/tests/Makefile.am                              |    2 +-
 69 files changed, 2828 insertions(+), 2795 deletions(-)
---
diff --git a/app/Makefile.am b/app/Makefile.am
index ad8f776..97807cb 100644
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -147,9 +147,9 @@ gimpconsoleldadd = \
        file/libappfile.a                                       \
        text/libapptext.a                                       \
        paint/libapppaint.a                                     \
+       operations/libappoperations.a                           \
        operations/layer-modes/libapplayermodes.a               \
        operations/layer-modes-legacy/libapplayermodeslegacy.a  \
-       operations/libappoperations.a                           \
        gegl/libappgegl.a                                       \
        config/libappconfig.a                                   \
        $(libgimpconfig)                                        \
diff --git a/app/config/Makefile.am b/app/config/Makefile.am
index 97bc714..13d9221 100644
--- a/app/config/Makefile.am
+++ b/app/config/Makefile.am
@@ -103,9 +103,9 @@ test_config_LDADD = \
        ../text/libapptext.a                                            \
        ../paint/libapppaint.a                                          \
        ../gegl/libappgegl.a                                            \
+       ../operations/libappoperations.a                                \
        ../operations/layer-modes/libapplayermodes.a                    \
        ../operations/layer-modes-legacy/libapplayermodeslegacy.a       \
-       ../operations/libappoperations.a                                \
        libappconfig.a                                                  \
        ../gimp-debug.o                                                 \
        ../gimp-log.o                                                   \
diff --git a/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c
index 3279028..e42b315 100644
--- a/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationadditionlegacy.h"
 
 
+static gboolean   gimp_operation_addition_legacy_process (GeglOperation       *op,
+                                                          void                *in,
+                                                          void                *layer,
+                                                          void                *mask,
+                                                          void                *out,
+                                                          glong                samples,
+                                                          const GeglRectangle *roi,
+                                                          gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationAdditionLegacy, gimp_operation_addition_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationAdditionLegacy, gimp_operation_addition_legacy,
 static void
 gimp_operation_addition_legacy_class_init (GimpOperationAdditionLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:addition-legacy",
                                  "description", "GIMP addition mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_addition_legacy_process;
+  layer_mode_class->process = gimp_operation_addition_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_addition_legacy_init (GimpOperationAdditionLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_addition_legacy_process (GeglOperation       *op,
                                         void                *in_p,
                                         void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h
index 730a5dc..7049567 100644
--- a/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationAdditionLegacyClass
 };
 
 
-GType    gimp_operation_addition_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_addition_legacy_process  (GeglOperation       *op,
-                                                  void                *in,
-                                                  void                *layer,
-                                                  void                *mask,
-                                                  void                *out,
-                                                  glong                samples,
-                                                  const GeglRectangle *roi,
-                                                  gint                 level);
+GType   gimp_operation_addition_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_ADDITION_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c
index a00a131..531f097 100644
--- a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c
@@ -27,6 +27,17 @@
 
 #include "gimpoperationburnlegacy.h"
 
+
+static gboolean   gimp_operation_burn_legacy_process (GeglOperation       *op,
+                                                      void                *in,
+                                                      void                *layer,
+                                                      void                *mask,
+                                                      void                *out,
+                                                      glong                samples,
+                                                      const GeglRectangle *roi,
+                                                      gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationBurnLegacy, gimp_operation_burn_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -34,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationBurnLegacy, gimp_operation_burn_legacy,
 static void
 gimp_operation_burn_legacy_class_init (GimpOperationBurnLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:burn-legacy",
                                  "description", "GIMP burn mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_burn_legacy_process;
+  layer_mode_class->process = gimp_operation_burn_legacy_process;
 }
 
 static void
@@ -53,7 +61,7 @@ gimp_operation_burn_legacy_init (GimpOperationBurnLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_burn_legacy_process (GeglOperation       *op,
                                     void                *in_p,
                                     void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h
index 5e350d9..669e784 100644
--- a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationBurnLegacyClass
 };
 
 
-GType    gimp_operation_burn_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_burn_legacy_process  (GeglOperation       *op,
-                                              void                *in,
-                                              void                *layer,
-                                              void                *mask,
-                                              void                *out,
-                                              glong                samples,
-                                              const GeglRectangle *roi,
-                                              gint                 level);
+GType   gimp_operation_burn_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_BURN_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c
index a35abbd..74c770c 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationdarkenonlylegacy.h"
 
 
+static gboolean   gimp_operation_darken_only_legacy_process (GeglOperation       *op,
+                                                             void                *in,
+                                                             void                *layer,
+                                                             void                *mask,
+                                                             void                *out,
+                                                             glong                samples,
+                                                             const GeglRectangle *roi,
+                                                             gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationDarkenOnlyLegacy, gimp_operation_darken_only_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationDarkenOnlyLegacy, gimp_operation_darken_only_legacy,
 static void
 gimp_operation_darken_only_legacy_class_init (GimpOperationDarkenOnlyLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:darken-only-legacy",
                                  "description", "GIMP darken only mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_darken_only_legacy_process;
+  layer_mode_class->process = gimp_operation_darken_only_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_darken_only_legacy_init (GimpOperationDarkenOnlyLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_darken_only_legacy_process (GeglOperation       *op,
                                            void                *in_p,
                                            void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h
index 5f416b3..f72a151 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationDarkenOnlyLegacyClass
 };
 
 
-GType    gimp_operation_darken_only_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_darken_only_legacy_process  (GeglOperation       *op,
-                                                     void                *in,
-                                                     void                *layer,
-                                                     void                *mask,
-                                                     void                *out,
-                                                     glong                samples,
-                                                     const GeglRectangle *roi,
-                                                     gint                 level);
+GType   gimp_operation_darken_only_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_DARKEN_ONLY_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c
index 1fa5ffa..0ff29ed 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationdifferencelegacy.h"
 
 
+static gboolean   gimp_operation_difference_legacy_process (GeglOperation       *op,
+                                                            void                *in,
+                                                            void                *layer,
+                                                            void                *mask,
+                                                            void                *out,
+                                                            glong                samples,
+                                                            const GeglRectangle *roi,
+                                                            gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationDifferenceLegacy, gimp_operation_difference_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationDifferenceLegacy, gimp_operation_difference_legacy,
 static void
 gimp_operation_difference_legacy_class_init (GimpOperationDifferenceLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:difference-legacy",
                                  "description", "GIMP difference mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_difference_legacy_process;
+  layer_mode_class->process = gimp_operation_difference_legacy_process;
 }
 
 static void
@@ -55,7 +62,7 @@ gimp_operation_difference_legacy_init (GimpOperationDifferenceLegacy *self)
 }
 
 
-gboolean
+static gboolean
 gimp_operation_difference_legacy_process (GeglOperation       *op,
                                           void                *in_p,
                                           void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h
index 727a623..312aebb 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationDifferenceLegacyClass
 };
 
 
-GType    gimp_operation_difference_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_difference_legacy_process  (GeglOperation       *op,
-                                                    void                *in,
-                                                    void                *layer,
-                                                    void                *mask,
-                                                    void                *out,
-                                                    glong                samples,
-                                                    const GeglRectangle *roi,
-                                                    gint                 level);
+GType   gimp_operation_difference_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_DIFFERENCE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c
index 48564a7..50afd3a 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationdividelegacy.h"
 
 
+static gboolean   gimp_operation_divide_legacy_process (GeglOperation       *op,
+                                                        void                *in,
+                                                        void                *layer,
+                                                        void                *mask,
+                                                        void                *out,
+                                                        glong                samples,
+                                                        const GeglRectangle *roi,
+                                                        gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationDivideLegacy, gimp_operation_divide_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationDivideLegacy, gimp_operation_divide_legacy,
 static void
 gimp_operation_divide_legacy_class_init (GimpOperationDivideLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:divide-legacy",
                                  "description", "GIMP divide mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_divide_legacy_process;
+  layer_mode_class->process = gimp_operation_divide_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_divide_legacy_init (GimpOperationDivideLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_divide_legacy_process (GeglOperation       *op,
                                       void                *in_p,
                                       void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h
index cd5589d..3fadfc9 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationDivideLegacyClass
 };
 
 
-GType    gimp_operation_divide_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_divide_legacy_process  (GeglOperation       *op,
-                                                void                *in,
-                                                void                *layer,
-                                                void                *mask,
-                                                void                *out,
-                                                glong                samples,
-                                                const GeglRectangle *roi,
-                                                gint                 level);
+GType   gimp_operation_divide_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_DIVIDE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c
index 01b25f2..d94c518 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationdodgelegacy.h"
 
 
+static gboolean   gimp_operation_dodge_legacy_process (GeglOperation       *op,
+                                                       void                *in,
+                                                       void                *layer,
+                                                       void                *mask,
+                                                       void                *out,
+                                                       glong                samples,
+                                                       const GeglRectangle *roi,
+                                                       gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationDodgeLegacy, gimp_operation_dodge_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationDodgeLegacy, gimp_operation_dodge_legacy,
 static void
 gimp_operation_dodge_legacy_class_init (GimpOperationDodgeLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:dodge-legacy",
                                  "description", "GIMP dodge mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_dodge_legacy_process;
+  layer_mode_class->process = gimp_operation_dodge_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_dodge_legacy_init (GimpOperationDodgeLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_dodge_legacy_process (GeglOperation       *op,
                                      void                *in_p,
                                      void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h
index 2eafabd..2013fd0 100644
--- a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationDodgeLegacyClass
 };
 
 
-GType    gimp_operation_dodge_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_dodge_legacy_process  (GeglOperation       *op,
-                                               void                *in,
-                                               void                *layer,
-                                               void                *mask,
-                                               void                *out,
-                                               glong                samples,
-                                               const GeglRectangle *roi,
-                                               gint                 level);
+GType   gimp_operation_dodge_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_DODGE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c
index 802fde2..1646c0d 100644
--- a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationgrainextractlegacy.h"
 
 
+static gboolean   gimp_operation_grain_extract_legacy_process (GeglOperation       *op,
+                                                               void                *in,
+                                                               void                *layer,
+                                                               void                *mask,
+                                                               void                *out,
+                                                               glong                samples,
+                                                               const GeglRectangle *roi,
+                                                               gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationGrainExtractLegacy, gimp_operation_grain_extract_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationGrainExtractLegacy, gimp_operation_grain_extract_leg
 static void
 gimp_operation_grain_extract_legacy_class_init (GimpOperationGrainExtractLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:grain-extract-legacy",
                                  "description", "GIMP grain extract mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_grain_extract_legacy_process;
+  layer_mode_class->process = gimp_operation_grain_extract_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_grain_extract_legacy_init (GimpOperationGrainExtractLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_grain_extract_legacy_process (GeglOperation       *op,
                                              void                *in_p,
                                              void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h
index 7c86455..e6acc28 100644
--- a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationGrainExtractLegacyClass
 };
 
 
-GType    gimp_operation_grain_extract_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_grain_extract_legacy_process  (GeglOperation       *op,
-                                                       void                *in,
-                                                       void                *layer,
-                                                       void                *mask,
-                                                       void                *out,
-                                                       glong                samples,
-                                                       const GeglRectangle *roi,
-                                                       gint                 level);
+GType   gimp_operation_grain_extract_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c
index a5e0117..fddd93d 100644
--- a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationgrainmergelegacy.h"
 
 
+static gboolean   gimp_operation_grain_merge_legacy_process (GeglOperation       *op,
+                                                             void                *in,
+                                                             void                *layer,
+                                                             void                *mask,
+                                                             void                *out,
+                                                             glong                samples,
+                                                             const GeglRectangle *roi,
+                                                             gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationGrainMergeLegacy, gimp_operation_grain_merge_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationGrainMergeLegacy, gimp_operation_grain_merge_legacy,
 static void
 gimp_operation_grain_merge_legacy_class_init (GimpOperationGrainMergeLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:grain-merge-legacy",
                                  "description", "GIMP grain merge mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_grain_merge_legacy_process;
+  layer_mode_class->process = gimp_operation_grain_merge_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_grain_merge_legacy_init (GimpOperationGrainMergeLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_grain_merge_legacy_process (GeglOperation       *op,
                                            void                *in_p,
                                            void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h
index 579f545..7aeacf2 100644
--- a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationGrainMergeLegacyClass
 };
 
 
-GType    gimp_operation_grain_merge_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_grain_merge_legacy_process  (GeglOperation       *op,
-                                                     void                *in,
-                                                     void                *layer,
-                                                     void                *mask,
-                                                     void                *out,
-                                                     glong                samples,
-                                                     const GeglRectangle *roi,
-                                                     gint                 level);
+GType   gimp_operation_grain_merge_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_GRAIN_MERGE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c
index acc7798..96a3233 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationhardlightlegacy.h"
 
 
+static gboolean   gimp_operation_hardlight_legacy_process (GeglOperation       *op,
+                                                           void                *in,
+                                                           void                *layer,
+                                                           void                *mask,
+                                                           void                *out,
+                                                           glong                samples,
+                                                           const GeglRectangle *roi,
+                                                           gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationHardlightLegacy, gimp_operation_hardlight_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationHardlightLegacy, gimp_operation_hardlight_legacy,
 static void
 gimp_operation_hardlight_legacy_class_init (GimpOperationHardlightLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:hardlight-legacy",
                                  "description", "GIMP hardlight mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_hardlight_legacy_process;
+  layer_mode_class->process = gimp_operation_hardlight_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_hardlight_legacy_init (GimpOperationHardlightLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_hardlight_legacy_process (GeglOperation       *op,
                                          void                *in_p,
                                          void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h
index 1a82e95..ebcbe8b 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationHardlightLegacyClass
 };
 
 
-GType    gimp_operation_hardlight_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_hardlight_legacy_process  (GeglOperation       *op,
-                                                   void                *in,
-                                                   void                *layer,
-                                                   void                *mask,
-                                                   void                *out,
-                                                   glong                samples,
-                                                   const GeglRectangle *roi,
-                                                   gint                 level);
+GType   gimp_operation_hardlight_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_HARDLIGHT_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c
index b4c2dfe..fa4afe9 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c
@@ -32,6 +32,16 @@
 #include "gimpoperationhslcolorlegacy.h"
 
 
+static gboolean   gimp_operation_hsl_color_legacy_process (GeglOperation       *op,
+                                                           void                *in,
+                                                           void                *layer,
+                                                           void                *mask,
+                                                           void                *out,
+                                                           glong                samples,
+                                                           const GeglRectangle *roi,
+                                                           gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationHslColorLegacy, gimp_operation_hsl_color_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -39,18 +49,15 @@ G_DEFINE_TYPE (GimpOperationHslColorLegacy, gimp_operation_hsl_color_legacy,
 static void
 gimp_operation_hsl_color_legacy_class_init (GimpOperationHslColorLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:hsl-color-legacy",
                                  "description", "GIMP color mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_hsl_color_legacy_process;
+  layer_mode_class->process = gimp_operation_hsl_color_legacy_process;
 }
 
 static void
@@ -58,7 +65,7 @@ gimp_operation_hsl_color_legacy_init (GimpOperationHslColorLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_hsl_color_legacy_process (GeglOperation       *op,
                                          void                *in_p,
                                          void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h
index 182d007..34ce586 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationHslColorLegacyClass
 };
 
 
-GType    gimp_operation_hsl_color_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_hsl_color_legacy_process  (GeglOperation       *op,
-                                                   void                *in,
-                                                   void                *layer,
-                                                   void                *mask,
-                                                   void                *out,
-                                                   glong                samples,
-                                                   const GeglRectangle *roi,
-                                                   gint                 level);
+GType   gimp_operation_hsl_color_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_HSL_COLOR_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c
index 863ee39..1141ba8 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c
@@ -32,6 +32,16 @@
 #include "gimpoperationhsvhuelegacy.h"
 
 
+static gboolean   gimp_operation_hsv_hue_legacy_process (GeglOperation       *op,
+                                                         void                *in,
+                                                         void                *layer,
+                                                         void                *mask,
+                                                         void                *out,
+                                                         glong                samples,
+                                                         const GeglRectangle *roi,
+                                                         gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationHsvHueLegacy, gimp_operation_hsv_hue_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -39,18 +49,15 @@ G_DEFINE_TYPE (GimpOperationHsvHueLegacy, gimp_operation_hsv_hue_legacy,
 static void
 gimp_operation_hsv_hue_legacy_class_init (GimpOperationHsvHueLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:hsv-hue-legacy",
                                  "description", "GIMP hue mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_hsv_hue_legacy_process;
+  layer_mode_class->process = gimp_operation_hsv_hue_legacy_process;
 }
 
 static void
@@ -58,7 +65,7 @@ gimp_operation_hsv_hue_legacy_init (GimpOperationHsvHueLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_hsv_hue_legacy_process (GeglOperation       *op,
                                        void                *in_p,
                                        void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h
index 8f353b4..5686da5 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationHsvHueLegacyClass
 };
 
 
-GType    gimp_operation_hsv_hue_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_hsv_hue_legacy_process  (GeglOperation       *op,
-                                                 void                *in,
-                                                 void                *layer,
-                                                 void                *mask,
-                                                 void                *out,
-                                                 glong                samples,
-                                                 const GeglRectangle *roi,
-                                                 gint                 level);
+GType   gimp_operation_hsv_hue_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_HSV_HUE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c
index 9d8d18c..81d85a2 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c
@@ -32,6 +32,16 @@
 #include "gimpoperationhsvsaturationlegacy.h"
 
 
+static gboolean   gimp_operation_hsv_saturation_legacy_process (GeglOperation       *op,
+                                                                void                *in,
+                                                                void                *layer,
+                                                                void                *mask,
+                                                                void                *out,
+                                                                glong                samples,
+                                                                const GeglRectangle *roi,
+                                                                gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationHsvSaturationLegacy, gimp_operation_hsv_saturation_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -39,18 +49,15 @@ G_DEFINE_TYPE (GimpOperationHsvSaturationLegacy, gimp_operation_hsv_saturation_l
 static void
 gimp_operation_hsv_saturation_legacy_class_init (GimpOperationHsvSaturationLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:hsv-saturation-legacy",
                                  "description", "GIMP saturation mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_hsv_saturation_legacy_process;
+  layer_mode_class->process = gimp_operation_hsv_saturation_legacy_process;
 }
 
 static void
@@ -58,7 +65,7 @@ gimp_operation_hsv_saturation_legacy_init (GimpOperationHsvSaturationLegacy *sel
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_hsv_saturation_legacy_process (GeglOperation       *op,
                                               void                *in_p,
                                               void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h
index 71cc96e..d0127a4 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationHsvSaturationLegacyClass
 };
 
 
-GType    gimp_operation_hsv_saturation_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_hsv_saturation_legacy_process  (GeglOperation       *op,
-                                                        void                *in,
-                                                        void                *layer,
-                                                        void                *mask,
-                                                        void                *out,
-                                                        glong                samples,
-                                                        const GeglRectangle *roi,
-                                                        gint                 level);
+GType   gimp_operation_hsv_saturation_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_HSV_SATURATION_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c
index 5091dfa..3659a89 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c
@@ -32,6 +32,16 @@
 #include "gimpoperationhsvvaluelegacy.h"
 
 
+static gboolean   gimp_operation_hsv_value_legacy_process (GeglOperation       *op,
+                                                           void                *in,
+                                                           void                *layer,
+                                                           void                *mask,
+                                                           void                *out,
+                                                           glong                samples,
+                                                           const GeglRectangle *roi,
+                                                           gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationHsvValueLegacy, gimp_operation_hsv_value_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -39,18 +49,15 @@ G_DEFINE_TYPE (GimpOperationHsvValueLegacy, gimp_operation_hsv_value_legacy,
 static void
 gimp_operation_hsv_value_legacy_class_init (GimpOperationHsvValueLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:hsv-value-legacy",
                                  "description", "GIMP value mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_hsv_value_legacy_process;
+  layer_mode_class->process = gimp_operation_hsv_value_legacy_process;
 }
 
 static void
@@ -58,7 +65,7 @@ gimp_operation_hsv_value_legacy_init (GimpOperationHsvValueLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_hsv_value_legacy_process (GeglOperation       *op,
                                          void                *in_p,
                                          void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h
index 439c22f..bf119cf 100644
--- a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationHsvValueLegacyClass
 };
 
 
-GType    gimp_operation_hsv_value_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_hsv_value_legacy_process  (GeglOperation       *op,
-                                                   void                *in,
-                                                   void                *layer,
-                                                   void                *mask,
-                                                   void                *out,
-                                                   glong                samples,
-                                                   const GeglRectangle *roi,
-                                                   gint                 level);
+GType   gimp_operation_hsv_value_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_HSV_VALUE_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c
index a696aca..88a1a31 100644
--- a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationlightenonlylegacy.h"
 
 
+static gboolean   gimp_operation_lighten_only_legacy_process (GeglOperation       *op,
+                                                              void                *in,
+                                                              void                *layer,
+                                                              void                *mask,
+                                                              void                *out,
+                                                              glong                samples,
+                                                              const GeglRectangle *roi,
+                                                              gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationLightenOnlyLegacy, gimp_operation_lighten_only_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationLightenOnlyLegacy, gimp_operation_lighten_only_legac
 static void
 gimp_operation_lighten_only_legacy_class_init (GimpOperationLightenOnlyLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:lighten-only-legacy",
                                  "description", "GIMP lighten only legacy operation",
                                  NULL);
 
-  point_class->process = gimp_operation_lighten_only_legacy_process;
+  layer_mode_class->process = gimp_operation_lighten_only_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_lighten_only_legacy_init (GimpOperationLightenOnlyLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_lighten_only_legacy_process (GeglOperation       *op,
                                             void                *in_p,
                                             void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h
index d9570af..124de63 100644
--- a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationLightenOnlyLegacyClass
 };
 
 
-GType    gimp_operation_lighten_only_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_lighten_only_legacy_process  (GeglOperation       *op,
-                                                      void                *in,
-                                                      void                *layer,
-                                                      void                *mask,
-                                                      void                *out,
-                                                      glong                samples,
-                                                      const GeglRectangle *roi,
-                                                      gint                 level);
+GType   gimp_operation_lighten_only_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c
index 74e59a0..b6bcdcf 100644
--- a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationmultiplylegacy.h"
 
 
+static gboolean   gimp_operation_multiply_legacy_process (GeglOperation       *op,
+                                                          void                *in,
+                                                          void                *layer,
+                                                          void                *mask,
+                                                          void                *out,
+                                                          glong                samples,
+                                                          const GeglRectangle *roi,
+                                                          gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationMultiplyLegacy, gimp_operation_multiply_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationMultiplyLegacy, gimp_operation_multiply_legacy,
 static void
 gimp_operation_multiply_legacy_class_init (GimpOperationMultiplyLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:multiply-legacy",
                                  "description", "GIMP multiply legacy operation",
                                  NULL);
 
-  point_class->process = gimp_operation_multiply_legacy_process;
+  layer_mode_class->process = gimp_operation_multiply_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_multiply_legacy_init (GimpOperationMultiplyLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_multiply_legacy_process (GeglOperation       *op,
                                         void                *in_p,
                                         void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h
index 70779a5..7a47726 100644
--- a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationMultiplyLegacyClass
 };
 
 
-GType    gimp_operation_multiply_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_multiply_legacy_process  (GeglOperation       *op,
-                                                  void                *in,
-                                                  void                *layer,
-                                                  void                *mask,
-                                                  void                *out,
-                                                  glong                samples,
-                                                  const GeglRectangle *roi,
-                                                  gint                 level);
+GType   gimp_operation_multiply_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_MULTIPLY_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c
index e8ed506..205ac8e 100644
--- a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationscreenlegacy.h"
 
 
+static gboolean   gimp_operation_screen_legacy_process (GeglOperation       *op,
+                                                        void                *in,
+                                                        void                *layer,
+                                                        void                *mask,
+                                                        void                *out,
+                                                        glong                samples,
+                                                        const GeglRectangle *roi,
+                                                        gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationScreenLegacy, gimp_operation_screen_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationScreenLegacy, gimp_operation_screen_legacy,
 static void
 gimp_operation_screen_legacy_class_init (GimpOperationScreenLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:screen-legacy",
                                  "description", "GIMP screen mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_screen_legacy_process;
+  layer_mode_class->process = gimp_operation_screen_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_screen_legacy_init (GimpOperationScreenLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_screen_legacy_process (GeglOperation       *op,
                                       void                *in_p,
                                       void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h
index f8d0830..976a015 100644
--- a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationScreenLegacyClass
 };
 
 
-GType    gimp_operation_screen_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_screen_legacy_process  (GeglOperation       *op,
-                                                void                *in,
-                                                void                *layer,
-                                                void                *mask,
-                                                void                *out,
-                                                glong                samples,
-                                                const GeglRectangle *roi,
-                                                gint                 level);
+GType   gimp_operation_screen_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_SCREEN_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c
index 4a65354..22eda93 100644
--- a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationsoftlightlegacy.h"
 
 
+static gboolean   gimp_operation_softlight_legacy_process (GeglOperation       *op,
+                                                           void                *in,
+                                                           void                *layer,
+                                                           void                *mask,
+                                                           void                *out,
+                                                           glong                samples,
+                                                           const GeglRectangle *roi,
+                                                           gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationSoftlightLegacy, gimp_operation_softlight_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -52,11 +62,8 @@ static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
 static void
 gimp_operation_softlight_legacy_class_init (GimpOperationSoftlightLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:softlight-legacy",
@@ -65,7 +72,7 @@ gimp_operation_softlight_legacy_class_init (GimpOperationSoftlightLegacyClass *k
                                  "reference-composition", reference_xml,
                                  NULL);
 
-  point_class->process = gimp_operation_softlight_legacy_process;
+  layer_mode_class->process = gimp_operation_softlight_legacy_process;
 }
 
 static void
@@ -73,7 +80,7 @@ gimp_operation_softlight_legacy_init (GimpOperationSoftlightLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_softlight_legacy_process (GeglOperation       *op,
                                          void                *in_p,
                                          void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h
index 77516bb..687ade2 100644
--- a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationSoftlightLegacyClass
 };
 
 
-GType    gimp_operation_softlight_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_softlight_legacy_process  (GeglOperation       *op,
-                                                   void                *in,
-                                                   void                *layer,
-                                                   void                *mask,
-                                                   void                *out,
-                                                   glong                samples,
-                                                   const GeglRectangle *roi,
-                                                   gint                 level);
+GType   gimp_operation_softlight_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_SOFTLIGHT_LEGACY_H__ */
diff --git a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c 
b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c
index 5e11adf..32505b1 100644
--- a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c
+++ b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c
@@ -28,6 +28,16 @@
 #include "gimpoperationsubtractlegacy.h"
 
 
+static gboolean   gimp_operation_subtract_legacy_process (GeglOperation       *op,
+                                                          void                *in,
+                                                          void                *layer,
+                                                          void                *mask,
+                                                          void                *out,
+                                                          glong                samples,
+                                                          const GeglRectangle *roi,
+                                                          gint                 level);
+
+
 G_DEFINE_TYPE (GimpOperationSubtractLegacy, gimp_operation_subtract_legacy,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationSubtractLegacy, gimp_operation_subtract_legacy,
 static void
 gimp_operation_subtract_legacy_class_init (GimpOperationSubtractLegacyClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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:subtract-legacy",
                                  "description", "GIMP subtract mode operation",
                                  NULL);
 
-  point_class->process = gimp_operation_subtract_legacy_process;
+  layer_mode_class->process = gimp_operation_subtract_legacy_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_subtract_legacy_init (GimpOperationSubtractLegacy *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_subtract_legacy_process (GeglOperation       *op,
                                         void                *in_p,
                                         void                *layer_p,
diff --git a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h 
b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h
index ba1021b..9223e82 100644
--- a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h
+++ b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h
@@ -47,16 +47,7 @@ struct _GimpOperationSubtractLegacyClass
 };
 
 
-GType    gimp_operation_subtract_legacy_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_subtract_legacy_process  (GeglOperation       *op,
-                                                  void                *in,
-                                                  void                *layer,
-                                                  void                *mask,
-                                                  void                *out,
-                                                  glong                samples,
-                                                  const GeglRectangle *roi,
-                                                  gint                 level);
+GType   gimp_operation_subtract_legacy_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_SUBTRACT_LEGACY_H__ */
diff --git a/app/operations/layer-modes/Makefile.am b/app/operations/layer-modes/Makefile.am
index f7bedd2..9bd64b9 100644
--- a/app/operations/layer-modes/Makefile.am
+++ b/app/operations/layer-modes/Makefile.am
@@ -9,7 +9,6 @@ AM_CPPFLAGS = \
        $(CAIRO_CFLAGS)                         \
        $(GEGL_CFLAGS)                          \
        $(GDK_PIXBUF_CFLAGS)                    \
-       $(SSE2_EXTRA_CFLAGS)            \
        -I$(includedir)
 
 noinst_LIBRARIES = \
@@ -19,30 +18,36 @@ noinst_LIBRARIES = \
        libapplayermodes.a
 
 libapplayermodes_generic_a_sources = \
-       gimp-layer-modes.c              \
-       gimp-layer-modes.h              \
+       gimp-layer-modes.c                      \
+       gimp-layer-modes.h                      \
        \
-       gimpoperationlayermode.c        \
-       gimpoperationlayermode.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           \
-       gimpoperationreplace.c          \
-       gimpoperationreplace.h          \
-       gimpoperationsplit.c            \
+       gimpoperationantierase.c                \
+       gimpoperationantierase.h                \
+       gimpoperationbehind.c                   \
+       gimpoperationbehind.h                   \
+       gimpoperationdissolve.c                 \
+       gimpoperationdissolve.h                 \
+       gimpoperationerase.c                    \
+       gimpoperationerase.h                    \
+       gimpoperationmerge.c                    \
+       gimpoperationmerge.h                    \
+       gimpoperationnormal.c                   \
+       gimpoperationnormal.h                   \
+       gimpoperationreplace.c                  \
+       gimpoperationreplace.h                  \
+       gimpoperationsplit.c                    \
        gimpoperationsplit.h
 
 libapplayermodes_sse2_a_sources = \
+       gimpoperationlayermode-composite-sse2.c \
+       \
        gimpoperationnormal-sse2.c
 
 libapplayermodes_sse4_a_sources = \
diff --git a/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
index efaee4d..1e7eade 100644
--- a/app/operations/layer-modes/gimp-layer-modes.c
+++ b/app/operations/layer-modes/gimp-layer-modes.c
@@ -25,33 +25,8 @@
 
 #include "../operations-types.h"
 
-#include "operations/layer-modes-legacy/gimpoperationadditionlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationburnlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationdifferencelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationdividelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationdodgelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationhardlightlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationmultiplylegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationscreenlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h"
-#include "operations/layer-modes-legacy/gimpoperationsubtractlegacy.h"
-
-#include "gimpoperationantierase.h"
-#include "gimpoperationbehind.h"
-#include "gimpoperationdissolve.h"
-#include "gimpoperationerase.h"
-#include "gimpoperationmerge.h"
-#include "gimpoperationnormal.h"
-#include "gimpoperationreplace.h"
-#include "gimpoperationsplit.h"
+#include "gimpoperationlayermode.h"
+#include "gimpoperationlayermode-blend.h"
 
 #include "gimp-layer-modes.h"
 
@@ -62,14 +37,13 @@ struct _GimpLayerModeInfo
 {
   GimpLayerMode             layer_mode;
   const gchar              *op_name;
-  GimpLayerModeFunc         function;
+  GimpLayerModeBlendFunc    blend_function;
   GimpLayerModeFlags        flags;
   GimpLayerModeContext      context;
   GimpLayerCompositeMode    paint_composite_mode;
   GimpLayerCompositeMode    composite_mode;
   GimpLayerColorSpace       composite_space;
   GimpLayerColorSpace       blend_space;
-  GimpLayerCompositeRegion  affected_region;
 };
 
 
@@ -80,7 +54,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_NORMAL_LEGACY,
 
     .op_name              = "gimp:normal",
-    .function             = gimp_operation_normal_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -94,19 +67,16 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DISSOLVE,
 
     .op_name              = "gimp:dissolve",
-    .function             = gimp_operation_dissolve_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
-    .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER,
-    .affected_region      = GIMP_LAYER_COMPOSITE_REGION_SOURCE
+    .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER
   },
 
   { GIMP_LAYER_MODE_BEHIND_LEGACY,
 
     .op_name              = "gimp:behind",
-    .function             = gimp_operation_behind_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -121,7 +91,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_MULTIPLY_LEGACY,
 
     .op_name              = "gimp:multiply-legacy",
-    .function             = gimp_operation_multiply_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -136,7 +105,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SCREEN_LEGACY,
 
     .op_name              = "gimp:screen-legacy",
-    .function             = gimp_operation_screen_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -151,7 +119,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_OVERLAY_LEGACY,
 
     .op_name              = "gimp:softlight-legacy",
-    .function             = gimp_operation_softlight_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -166,7 +133,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
 
     .op_name              = "gimp:difference-legacy",
-    .function             = gimp_operation_difference_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -181,7 +147,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_ADDITION_LEGACY,
 
     .op_name              = "gimp:addition-legacy",
-    .function             = gimp_operation_addition_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -196,7 +161,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SUBTRACT_LEGACY,
 
     .op_name              = "gimp:subtract-legacy",
-    .function             = gimp_operation_subtract_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -211,7 +175,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
 
     .op_name              = "gimp:darken-only-legacy",
-    .function             = gimp_operation_darken_only_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -226,7 +189,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
 
     .op_name              = "gimp:lighten-only-legacy",
-    .function             = gimp_operation_lighten_only_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -241,7 +203,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_HUE_LEGACY,
 
     .op_name              = "gimp:hsv-hue-legacy",
-    .function             = gimp_operation_hsv_hue_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -256,7 +217,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
 
     .op_name              = "gimp:hsv-saturation-legacy",
-    .function             = gimp_operation_hsv_saturation_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -271,7 +231,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
 
     .op_name              = "gimp:hsl-color-legacy",
-    .function             = gimp_operation_hsl_color_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -286,7 +245,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_VALUE_LEGACY,
 
     .op_name              = "gimp:hsv-value-legacy",
-    .function             = gimp_operation_hsv_value_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -301,7 +259,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DIVIDE_LEGACY,
 
     .op_name              = "gimp:divide-legacy",
-    .function             = gimp_operation_divide_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -316,7 +273,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DODGE_LEGACY,
 
     .op_name              = "gimp:dodge-legacy",
-    .function             = gimp_operation_dodge_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -331,7 +287,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_BURN_LEGACY,
 
     .op_name              = "gimp:burn-legacy",
-    .function             = gimp_operation_burn_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -346,7 +301,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
 
     .op_name              = "gimp:hardlight-legacy",
-    .function             = gimp_operation_hardlight_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -361,7 +315,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
 
     .op_name              = "gimp:softlight-legacy",
-    .function             = gimp_operation_softlight_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -376,7 +329,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
 
     .op_name              = "gimp:grain-extract-legacy",
-    .function             = gimp_operation_grain_extract_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -391,7 +343,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
 
     .op_name              = "gimp:grain-merge-legacy",
-    .function             = gimp_operation_grain_merge_legacy_process,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -406,7 +357,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
     .flags                = GIMP_LAYER_MODE_FLAG_LEGACY                    |
                             GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
@@ -422,7 +372,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_OVERLAY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_overlay,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -433,7 +383,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LCH_HUE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -445,7 +395,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LCH_CHROMA,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -457,7 +407,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LCH_COLOR,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -469,7 +419,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LCH_LIGHTNESS,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -481,7 +431,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_NORMAL,
 
     .op_name              = "gimp:normal",
-    .function             = gimp_operation_normal_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
@@ -492,7 +441,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_BEHIND,
 
     .op_name              = "gimp:behind",
-    .function             = gimp_operation_behind_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_PAINT |
                             GIMP_LAYER_MODE_CONTEXT_FADE,
@@ -504,7 +452,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_MULTIPLY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_multiply,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -515,7 +463,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SCREEN,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_screen,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -526,7 +474,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DIFFERENCE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_difference,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -537,7 +485,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_ADDITION,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_addition,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -548,7 +496,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SUBTRACT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_subtract,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -559,7 +507,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DARKEN_ONLY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -571,7 +519,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LIGHTEN_ONLY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -583,7 +531,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_HUE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -595,7 +543,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_SATURATION,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -607,7 +555,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSL_COLOR,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -619,7 +567,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HSV_VALUE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -631,7 +579,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DIVIDE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_divide,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -642,7 +590,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_DODGE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_dodge,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -653,7 +601,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_BURN,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_burn,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -664,7 +612,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HARDLIGHT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_hardlight,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -675,7 +623,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SOFTLIGHT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_softlight,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -686,7 +634,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_GRAIN_EXTRACT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_grain_extract,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -697,7 +645,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_GRAIN_MERGE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_grain_merge,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -708,7 +656,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_VIVID_LIGHT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_vivid_light,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -719,7 +667,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_PIN_LIGHT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_pin_light,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -730,7 +678,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LINEAR_LIGHT,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_linear_light,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -741,7 +689,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_HARD_MIX,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_hard_mix,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -752,7 +700,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_EXCLUSION,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_exclusion,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -763,7 +711,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LINEAR_BURN,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_linear_burn,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -774,7 +722,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_luma_darken_only,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -785,7 +733,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .blend_function       = gimp_operation_layer_mode_blend_luma_lighten_only,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_ATOP,
@@ -796,7 +744,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_LUMINANCE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_OVER,
@@ -808,7 +756,7 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_COLOR_ERASE,
 
     .op_name              = "gimp:layer-mode",
-    .function             = gimp_operation_layer_mode_process_pixels,
+    .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_SRC_ATOP,
@@ -820,7 +768,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_ERASE,
 
     .op_name              = "gimp:erase",
-    .function             = gimp_operation_erase_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
                             GIMP_LAYER_MODE_FLAG_SUBTRACTIVE,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
@@ -832,7 +779,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_MERGE,
 
     .op_name              = "gimp:merge",
-    .function             = gimp_operation_merge_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_ALL,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
@@ -843,7 +789,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_SPLIT,
 
     .op_name              = "gimp:split",
-    .function             = gimp_operation_split_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE     |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE |
                             GIMP_LAYER_MODE_FLAG_SUBTRACTIVE,
@@ -855,7 +800,6 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_PASS_THROUGH,
 
     .op_name              = "gimp:replace",
-    .function             = gimp_operation_replace_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_GROUP,
@@ -866,25 +810,21 @@ static const GimpLayerModeInfo layer_mode_infos[] =
   { GIMP_LAYER_MODE_REPLACE,
 
     .op_name              = "gimp:replace",
-    .function             = gimp_operation_replace_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_FADE,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
     .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER,
-    .composite_space      = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
-    .affected_region      = GIMP_LAYER_COMPOSITE_REGION_DESTINATION
+    .composite_space      = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
   },
 
   { GIMP_LAYER_MODE_ANTI_ERASE,
 
     .op_name              = "gimp:anti-erase",
-    .function             = gimp_operation_anti_erase_process,
     .flags                = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE |
                             GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE,
     .context              = GIMP_LAYER_MODE_CONTEXT_FADE,
     .paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
-    .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER,
-    .affected_region      = GIMP_LAYER_COMPOSITE_REGION_SOURCE
+    .composite_mode       = GIMP_LAYER_COMPOSITE_SRC_OVER
   }
 };
 
@@ -1172,7 +1112,7 @@ gimp_layer_modes_init (void)
 static const GimpLayerModeInfo *
 gimp_layer_mode_info (GimpLayerMode mode)
 {
-  g_return_val_if_fail (mode < G_N_ELEMENTS (layer_mode_infos),
+  g_return_val_if_fail (mode >= 0 && mode < G_N_ELEMENTS (layer_mode_infos),
                         &layer_mode_infos[0]);
 
   return &layer_mode_infos[mode];
@@ -1280,18 +1220,53 @@ gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode)
 const gchar *
 gimp_layer_mode_get_operation (GimpLayerMode mode)
 {
-  return "gimp:layer-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 gimp_operation_layer_mode_process_pixels;
+    return NULL;
 
-  return info->function;
+  return info->blend_function;
 }
 
 GimpLayerModeContext
@@ -1460,17 +1435,6 @@ gimp_layer_mode_get_format (GimpLayerMode        mode,
 }
 
 GimpLayerCompositeRegion
-gimp_layer_mode_get_affected_region (GimpLayerMode mode)
-{
-  const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
-
-  if (! info)
-    return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
-
-  return info->affected_region;
-}
-
-GimpLayerCompositeRegion
 gimp_layer_mode_get_included_region (GimpLayerMode          mode,
                                      GimpLayerCompositeMode composite_mode)
 {
diff --git a/app/operations/layer-modes/gimp-layer-modes.h b/app/operations/layer-modes/gimp-layer-modes.h
index a8463cd..ef80605 100644
--- a/app/operations/layer-modes/gimp-layer-modes.h
+++ b/app/operations/layer-modes/gimp-layer-modes.h
@@ -41,6 +41,7 @@ GimpLayerCompositeMode     gimp_layer_mode_get_paint_composite_mode   (GimpLayer
 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);
 
@@ -62,8 +63,6 @@ const Babl               * gimp_layer_mode_get_format                 (GimpLayer
                                                                        GimpLayerColorSpace     blend_space,
                                                                        const Babl             
*preferred_format);
 
-GimpLayerCompositeRegion   gimp_layer_mode_get_affected_region        (GimpLayerMode           mode);
-
 GimpLayerCompositeRegion   gimp_layer_mode_get_included_region        (GimpLayerMode           mode,
                                                                        GimpLayerCompositeMode  
composite_mode);
 
diff --git a/app/operations/layer-modes/gimpoperationantierase.c 
b/app/operations/layer-modes/gimpoperationantierase.c
index 572b800..b7a2d2d 100644
--- a/app/operations/layer-modes/gimpoperationantierase.c
+++ b/app/operations/layer-modes/gimpoperationantierase.c
@@ -28,7 +28,16 @@
 #include "gimpoperationantierase.h"
 
 
-static GimpLayerCompositeRegion gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode 
*layer_mode);
+
+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,
@@ -38,21 +47,15 @@ G_DEFINE_TYPE (GimpOperationAntiErase, gimp_operation_anti_erase,
 static void
 gimp_operation_anti_erase_class_init (GimpOperationAntiEraseClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-  GimpOperationLayerModeClass      *layer_mode_class;
-
-  operation_class  = GEGL_OPERATION_CLASS (klass);
-  point_class      = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
-  layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (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);
 
-  point_class->process = gimp_operation_anti_erase_process;
-
+  layer_mode_class->process             = gimp_operation_anti_erase_process;
   layer_mode_class->get_affected_region = gimp_operation_anti_erase_get_affected_region;
 }
 
@@ -61,7 +64,7 @@ gimp_operation_anti_erase_init (GimpOperationAntiErase *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_anti_erase_process (GeglOperation       *op,
                                    void                *in_p,
                                    void                *layer_p,
@@ -79,7 +82,7 @@ gimp_operation_anti_erase_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
     case GIMP_LAYER_COMPOSITE_AUTO:
diff --git a/app/operations/layer-modes/gimpoperationantierase.h 
b/app/operations/layer-modes/gimpoperationantierase.h
index 8e275fe..010dc94 100644
--- a/app/operations/layer-modes/gimpoperationantierase.h
+++ b/app/operations/layer-modes/gimpoperationantierase.h
@@ -47,16 +47,7 @@ struct _GimpOperationAntiEraseClass
 };
 
 
-GType    gimp_operation_anti_erase_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_anti_erase_process  (GeglOperation       *op,
-                                             void                *in,
-                                             void                *layer,
-                                             void                *mask,
-                                             void                *out,
-                                             glong                samples,
-                                             const GeglRectangle *roi,
-                                             gint                 level);
+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
index 8ecb61a..82f0faf 100644
--- a/app/operations/layer-modes/gimpoperationbehind.c
+++ b/app/operations/layer-modes/gimpoperationbehind.c
@@ -28,6 +28,17 @@
 #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)
 
@@ -35,18 +46,15 @@ G_DEFINE_TYPE (GimpOperationBehind, gimp_operation_behind,
 static void
 gimp_operation_behind_class_init (GimpOperationBehindClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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);
 
-  point_class->process = gimp_operation_behind_process;
+  layer_mode_class->process = gimp_operation_behind_process;
 }
 
 static void
@@ -54,7 +62,7 @@ gimp_operation_behind_init (GimpOperationBehind *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_behind_process (GeglOperation       *op,
                                void                *in_p,
                                void                *layer_p,
@@ -72,7 +80,7 @@ gimp_operation_behind_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
     case GIMP_LAYER_COMPOSITE_AUTO:
diff --git a/app/operations/layer-modes/gimpoperationbehind.h 
b/app/operations/layer-modes/gimpoperationbehind.h
index 17b4f64..d72e679 100644
--- a/app/operations/layer-modes/gimpoperationbehind.h
+++ b/app/operations/layer-modes/gimpoperationbehind.h
@@ -49,14 +49,5 @@ struct _GimpOperationBehindClass
 
 GType    gimp_operation_behind_get_type (void) G_GNUC_CONST;
 
-gboolean gimp_operation_behind_process  (GeglOperation       *op,
-                                         void                *in,
-                                         void                *layer,
-                                         void                *mask,
-                                         void                *out,
-                                         glong                samples,
-                                         const GeglRectangle *roi,
-                                         gint                 level);
-
 
 #endif /* __GIMP_OPERATION_BEHIND_H__ */
diff --git a/app/operations/layer-modes/gimpoperationdissolve.c 
b/app/operations/layer-modes/gimpoperationdissolve.c
index 993c821..4d7b2f4 100644
--- a/app/operations/layer-modes/gimpoperationdissolve.c
+++ b/app/operations/layer-modes/gimpoperationdissolve.c
@@ -32,7 +32,15 @@
 #define RANDOM_TABLE_SIZE 4096
 
 
-static GimpLayerCompositeRegion gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode 
*layer_mode);
+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,
@@ -45,15 +53,10 @@ static gint32 random_table[RANDOM_TABLE_SIZE];
 static void
 gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_composer_class;
-  GimpOperationLayerModeClass      *layer_mode_class;
-  GRand                            *gr;
-  gint                              i;
-
-  operation_class      = GEGL_OPERATION_CLASS (klass);
-  point_composer_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
-  layer_mode_class     = GIMP_OPERATION_LAYER_MODE_CLASS (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",
@@ -61,8 +64,7 @@ gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
                                  "categories",  "compositors",
                                  NULL);
 
-  point_composer_class->process = gimp_operation_dissolve_process;
-
+  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 */
@@ -78,7 +80,7 @@ gimp_operation_dissolve_init (GimpOperationDissolve *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_dissolve_process (GeglOperation       *op,
                                  void                *in_p,
                                  void                *layer_p,
@@ -118,8 +120,8 @@ gimp_operation_dissolve_process (GeglOperation       *op,
               out[1] = in[1];
               out[2] = in[2];
 
-              if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
-                  layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_SRC_ATOP)
+              if (layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
+                  layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_SRC_ATOP)
                 {
                   out[3] = in[3];
                 }
@@ -134,8 +136,8 @@ gimp_operation_dissolve_process (GeglOperation       *op,
               out[1] = layer[1];
               out[2] = layer[2];
 
-              if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
-                  layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_DST_ATOP)
+              if (layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
+                  layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_DST_ATOP)
                 {
                   out[3] = 1.0f;
                 }
@@ -159,7 +161,7 @@ gimp_operation_dissolve_process (GeglOperation       *op,
   return TRUE;
 }
 
-GimpLayerCompositeRegion
+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
index 8b89ca1..7dea99a 100644
--- a/app/operations/layer-modes/gimpoperationdissolve.h
+++ b/app/operations/layer-modes/gimpoperationdissolve.h
@@ -47,16 +47,7 @@ struct _GimpOperationDissolve
 };
 
 
-GType    gimp_operation_dissolve_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_dissolve_process  (GeglOperation       *op,
-                                           void                *in,
-                                           void                *layer,
-                                           void                *mask,
-                                           void                *out,
-                                           glong                samples,
-                                           const GeglRectangle *result,
-                                           gint                 level);
+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
index 1cc1ba8..ff0aa37 100644
--- a/app/operations/layer-modes/gimpoperationerase.c
+++ b/app/operations/layer-modes/gimpoperationerase.c
@@ -28,6 +28,16 @@
 #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)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationErase, gimp_operation_erase,
 static void
 gimp_operation_erase_class_init (GimpOperationEraseClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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);
 
-  point_class->process = gimp_operation_erase_process;
+  layer_mode_class->process = gimp_operation_erase_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_erase_init (GimpOperationErase *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_erase_process (GeglOperation       *op,
                               void                *in_p,
                               void                *layer_p,
@@ -72,7 +79,7 @@ gimp_operation_erase_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
       while (samples--)
diff --git a/app/operations/layer-modes/gimpoperationerase.h b/app/operations/layer-modes/gimpoperationerase.h
index 0d15ab1..5f9bb4d 100644
--- a/app/operations/layer-modes/gimpoperationerase.h
+++ b/app/operations/layer-modes/gimpoperationerase.h
@@ -47,16 +47,7 @@ struct _GimpOperationEraseClass
 };
 
 
-GType    gimp_operation_erase_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_erase_process  (GeglOperation       *op,
-                                        void                *in,
-                                        void                *layer,
-                                        void                *mask,
-                                        void                *out,
-                                        glong                samples,
-                                        const GeglRectangle *roi,
-                                        gint                 level);
+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..dd01115
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-blend.c
@@ -0,0 +1,1168 @@
+/* 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 <http://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"
+
+
+/*  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 (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 (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 = 1.0f - (1.0f - in[c]) / layer[c];
+
+              /* The CLAMP macro is deliberately inlined and written
+               * to map comp == NAN (0 / 0) -> 1
+               */
+              comp[c] = val < 0 ? 0.0f : val < 1.0f ? val : 1.0f;
+            }
+        }
+
+      comp[ALPHA] = layer[ALPHA];
+
+      comp  += 4;
+      layer += 4;
+      in    += 4;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_darken_only (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 (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];
+
+              if (comp[c] < 0)
+                comp[c] = -comp[c];
+            }
+        }
+
+      comp[ALPHA] = layer[ALPHA];
+
+      comp  += 4;
+      layer += 4;
+      in    += 4;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_divide (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 = in[c] / layer[c];
+
+              /* make infinities(or NaN) correspond to a high number,
+               * to get more predictable math, ideally higher than 5.0
+               * but it seems like some babl conversions might be
+               * acting up then
+               */
+              if (!(val > -42949672.0f && val < 5.0f))
+                val = 5.0f;
+
+              comp[c] = val;
+            }
+        }
+
+      comp[ALPHA] = layer[ALPHA];
+
+      comp  += 4;
+      layer += 4;
+      in    += 4;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_dodge (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 = in[c] / (1.0f - layer[c]);
+
+              val = MIN (val, 1.0f);
+
+              comp[c] = val;
+            }
+        }
+
+      comp[ALPHA] = layer[ALPHA];
+
+      comp  += 4;
+      layer += 4;
+      in    += 4;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_exclusion (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 (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 (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 (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 (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 (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 (src_l != 0.0f && src_l != 1.0f)
+            {
+              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 (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 != 0.0f)
+            {
+              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 (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 != 0.0f)
+            {
+              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 (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 (dest_v != 0.0f)
+            {
+              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 (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 != 0.0f)
+            {
+              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 (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 (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 > 0.1f)
+            {
+              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 (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 (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 (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 (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.0 * layer[c] - 1.0f;
+                }
+              else
+                {
+                  val = in[c] + 2.0 * (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 (const gfloat *in,
+                                                  const gfloat *layer,
+                                                  gfloat       *comp,
+                                                  gint          samples)
+{
+  while (samples--)
+    {
+      if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+        {
+          gint c;
+          gfloat dest_luminance =
+             GIMP_RGB_LUMINANCE(in[0], in[1], in[2]);
+          gfloat 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 (const gfloat *in,
+                                                   const gfloat *layer,
+                                                   gfloat       *comp,
+                                                   gint          samples)
+{
+  while (samples--)
+    {
+      if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f)
+        {
+          gint c;
+          gfloat dest_luminance =
+             GIMP_RGB_LUMINANCE(in[0], in[1], in[2]);
+          gfloat 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 (const gfloat *in,
+                                           const gfloat *layer,
+                                           gfloat       *comp,
+                                           gint          samples)
+{
+  gfloat layer_Y[samples], *layer_Y_p;
+  gfloat in_Y[samples], *in_Y_p;
+
+  babl_process (babl_fish ("RGBA gfloat", "Y gfloat"), layer, layer_Y, samples);
+  babl_process (babl_fish ("RGBA gfloat", "Y gfloat"), in, in_Y, samples);
+
+  layer_Y_p = &layer_Y[0];
+  in_Y_p = &in_Y[0];
+
+  while (samples--)
+    {
+      if (layer[ALPHA] != 0.0f && in[ALPHA] != 0.0f)
+        {
+          gfloat ratio = layer_Y_p[0] / MAX(in_Y_p[0], 0.0000000000000000001);
+          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_p    ++;
+      layer_Y_p ++;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_multiply (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 (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 (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 * (layer[c] - 0.5));
+                }
+              else
+                {
+                  val = MIN(in[c], 2 * layer[c]);
+                }
+              comp[c] = val;
+            }
+        }
+
+      comp[ALPHA] = layer[ALPHA];
+
+      comp  += 4;
+      layer += 4;
+      in    += 4;
+    }
+}
+
+void
+gimp_operation_layer_mode_blend_screen (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 (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 (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 (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 - (1.0f - in[c]) / (2.0f * (layer[c]));
+                }
+              else
+                {
+                  val = 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 (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 (col != bgcol)
+                {
+                  gfloat a;
+
+                  if (col > bgcol)
+                    a = (col - bgcol) / (1.0f - bgcol);
+                  else
+                    a = (bgcol - col) / bgcol;
+
+                  alpha = MAX (alpha, a);
+                }
+            }
+
+          if (alpha > 0.0f)
+            {
+              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..40e8513
--- /dev/null
+++ b/app/operations/layer-modes/gimpoperationlayermode-blend.h
@@ -0,0 +1,167 @@
+/* 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 <http://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          (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_burn              (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_darken_only       (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_difference        (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_divide            (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_dodge             (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_exclusion         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_grain_extract     (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_grain_merge       (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hard_mix          (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hardlight         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hsl_color         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hsv_hue           (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hsv_saturation    (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_hsv_value         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_lch_chroma        (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_lch_color         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_lch_hue           (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_lch_lightness     (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_lighten_only      (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_linear_burn       (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_linear_light      (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_luma_darken_only  (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_luma_lighten_only (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_luminance         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_multiply          (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_overlay           (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_pin_light         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_screen            (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_softlight         (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_subtract          (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+void gimp_operation_layer_mode_blend_vivid_light       (const gfloat *in,
+                                                        const gfloat *layer,
+                                                        gfloat       *comp,
+                                                        gint          samples);
+
+
+/*  subtractive blend functions  */
+
+void gimp_operation_layer_mode_blend_color_erase       (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..8f55078
--- /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 <http://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_src_atop_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_src_atop (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..a4f3bad
--- /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 <http://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_src_over (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_src_atop (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_dst_atop (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_src_in (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_src_over_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_src_atop_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_dst_atop_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_src_in_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..a6f9823
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__
+#define __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__
+
+
+void gimp_operation_layer_mode_composite_src_over      (const gfloat        *in,
+                                                        const gfloat        *layer,
+                                                        const gfloat        *comp,
+                                                        const gfloat        *mask,
+                                                        gfloat               opacity,
+                                                        gfloat              *out,
+                                                        gint                 samples);
+void gimp_operation_layer_mode_composite_src_atop      (const gfloat        *in,
+                                                        const gfloat        *layer,
+                                                        const gfloat        *comp,
+                                                        const gfloat        *mask,
+                                                        gfloat               opacity,
+                                                        gfloat              *out,
+                                                        gint                 samples);
+void gimp_operation_layer_mode_composite_dst_atop      (const gfloat        *in,
+                                                        const gfloat        *layer,
+                                                        const gfloat        *comp,
+                                                        const gfloat        *mask,
+                                                        gfloat               opacity,
+                                                        gfloat              *out,
+                                                        gint                 samples);
+void gimp_operation_layer_mode_composite_src_in        (const gfloat        *in,
+                                                        const gfloat        *layer,
+                                                        const gfloat        *comp,
+                                                        const gfloat        *mask,
+                                                        gfloat               opacity,
+                                                        gfloat              *out,
+                                                        gint                 samples);
+
+void gimp_operation_layer_mode_composite_src_over_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_src_atop_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_dst_atop_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_src_in_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_src_atop_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
index 513705f..68d4eb6 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.c
+++ b/app/operations/layer-modes/gimpoperationlayermode.c
@@ -25,14 +25,13 @@
 #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 "gimp-layer-modes.h"
 #include "gimpoperationlayermode.h"
+#include "gimpoperationlayermode-composite.h"
 
 
 /* the maximum number of samples to process in one go.  used to limit
@@ -59,120 +58,58 @@ enum
   PROP_COMPOSITE_MODE
 };
 
-typedef void (* CompositeFunc) (gfloat *in,
-                                gfloat *layer,
-                                gfloat *comp,
-                                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 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 GimpLayerCompositeRegion
-    gimp_operation_layer_mode_real_get_affected_region (GimpOperationLayerMode *layer_mode);
-
-static inline void composite_func_src_atop_core     (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_dst_atop_core     (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_src_in_core       (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_src_over_core     (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-
-static inline void composite_func_src_atop_sub_core (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_dst_atop_sub_core (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_src_in_sub_core   (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-static inline void composite_func_src_over_sub_core (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-
-#if COMPILE_SSE2_INTRINISICS
-static inline void composite_func_src_atop_sse2     (gfloat *in,
-                                                     gfloat *layer,
-                                                     gfloat *comp,
-                                                     gfloat *mask,
-                                                     gfloat  opacity,
-                                                     gfloat *out,
-                                                     gint    samples);
-#endif
 
-static gboolean process_layer_only (GeglOperation       *operation,
-                                    void                *in,
-                                    void                *layer,
-                                    void                *mask,
-                                    void                *out,
-                                    glong                samples,
-                                    const GeglRectangle *roi,
-                                    gint                 level);
+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 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_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,
@@ -183,39 +120,37 @@ G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode,
 
 static const Babl *gimp_layer_color_space_fish[3 /* from */][3 /* to */];
 
-static CompositeFunc composite_func_src_atop     = composite_func_src_atop_core;
-static CompositeFunc composite_func_dst_atop     = composite_func_dst_atop_core;
-static CompositeFunc composite_func_src_in       = composite_func_src_in_core;
-static CompositeFunc composite_func_src_over     = composite_func_src_over_core;
+static CompositeFunc composite_src_over     = gimp_operation_layer_mode_composite_src_over;
+static CompositeFunc composite_src_atop     = gimp_operation_layer_mode_composite_src_atop;
+static CompositeFunc composite_dst_atop     = gimp_operation_layer_mode_composite_dst_atop;
+static CompositeFunc composite_src_in       = gimp_operation_layer_mode_composite_src_in;
 
-static CompositeFunc composite_func_src_atop_sub = composite_func_src_atop_sub_core;
-static CompositeFunc composite_func_dst_atop_sub = composite_func_dst_atop_sub_core;
-static CompositeFunc composite_func_src_in_sub   = composite_func_src_in_sub_core;
-static CompositeFunc composite_func_src_over_sub = composite_func_src_over_sub_core;
+static CompositeFunc composite_src_over_sub = gimp_operation_layer_mode_composite_src_over_sub;
+static CompositeFunc composite_src_atop_sub = gimp_operation_layer_mode_composite_src_atop_sub;
+static CompositeFunc composite_dst_atop_sub = gimp_operation_layer_mode_composite_dst_atop_sub;
+static CompositeFunc composite_src_in_sub   = gimp_operation_layer_mode_composite_src_in_sub;
 
 
 static void
 gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
 {
-  GObjectClass                     *object_class;
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_composer3_class;
-
-  object_class          = G_OBJECT_CLASS (klass);
-  operation_class       = GEGL_OPERATION_CLASS (klass);
-  point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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;
+  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->process       = gimp_operation_layer_mode_parent_process;
+
   point_composer3_class->process = gimp_operation_layer_mode_process;
 
-  klass->get_affected_region     = gimp_operation_layer_mode_real_get_affected_region;
+  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",
@@ -286,7 +221,7 @@ gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
 
 #if COMPILE_SSE2_INTRINISICS
   if (gimp_cpu_accel_get_support () & GIMP_CPU_ACCEL_X86_SSE2)
-    composite_func_src_atop = composite_func_src_atop_sse2;
+    composite_src_atop = gimp_operation_layer_mode_composite_src_atop_sse2;
 #endif
 }
 
@@ -375,7 +310,10 @@ gimp_operation_layer_mode_prepare (GeglOperation *operation)
   const Babl             *preferred_format;
   const Babl             *format;
 
-  self->func = gimp_layer_mode_get_function (self->layer_mode);
+  self->real_composite_mode = self->composite_mode;
+
+  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");
 
@@ -396,9 +334,18 @@ gimp_operation_layer_mode_prepare (GeglOperation *operation)
       /* if the layer mode doesn't affect the source, use a shortcut
        * function that only applies the opacity/mask to the layer.
        */
-      if (! (gimp_layer_mode_get_affected_region (self->layer_mode) &
+      if (! (gimp_operation_layer_mode_get_affected_region (self) &
              GIMP_LAYER_COMPOSITE_REGION_SOURCE))
-        self->func = process_layer_only;
+        {
+          self->function = process_last_node;
+        }
+      /* otherwise, use the original process function, but force the
+       * composite mode to SRC_OVER.
+       */
+      else
+        {
+          self->real_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER;
+        }
 
       preferred_format = gegl_operation_get_source_format (operation, "aux");
     }
@@ -470,13 +417,13 @@ gimp_operation_layer_mode_parent_process (GeglOperation        *operation,
           GimpLayerCompositeRegion affected_region;
 
           affected_region =
-            gimp_layer_mode_get_affected_region (point->layer_mode);
+            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                        &&
+              point->opacity == 1.0                                    &&
               ! gegl_operation_context_get_object (context, "aux2"))
             {
               /* pass 'aux' directly as output; */
@@ -507,7 +454,7 @@ gimp_operation_layer_mode_parent_process (GeglOperation        *operation,
           GimpLayerCompositeRegion affected_region;
 
           affected_region =
-            gimp_layer_mode_get_affected_region (point->layer_mode);
+            gimp_operation_layer_mode_get_affected_region (point);
 
           /* ... and the op doesn't otherwise affect 'input' ... */
           if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION))
@@ -562,603 +509,36 @@ gimp_operation_layer_mode_process (GeglOperation       *operation,
                                    const GeglRectangle *roi,
                                    gint                 level)
 {
-  GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
-
-  /* if we're not the last node, or we're using the opacity/mask shortcut
-   * function, forward directly to the real process function.
-   */
-  if (! point->is_last_node || point->func == process_layer_only)
-    {
-      return point->func (operation, in, layer, mask, out, samples, roi, level);
-    }
-  /* otherwise, switch the composite mode temporarily to src-over, before
-   * handing processing over to the real process function.
-   */
-  else
-    {
-      GimpLayerCompositeMode composite_mode = point->composite_mode;
-      gboolean               result;
-
-      point->composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER;
-
-      result = point->func (operation, in, layer, mask, out, samples, roi, level);
-
-      point->composite_mode = composite_mode;
-
-      return result;
-    }
-}
-
-static GimpLayerCompositeRegion
-gimp_operation_layer_mode_real_get_affected_region (GimpOperationLayerMode *layer_mode)
-{
-  /* most modes only affect the overlapping regions. */
-  return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
-}
-
-
-/* public functions */
-
-GimpLayerCompositeRegion
-gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode)
-{
-  g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode),
-                        GIMP_LAYER_COMPOSITE_REGION_INTERSECTION);
-
-  return GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode)->get_affected_region (layer_mode);
-}
-
-
-/* compositing and blending functions */
-
-static inline GimpBlendFunc gimp_layer_mode_get_blend_fun (GimpLayerMode mode);
-
-static inline void gimp_composite_blend (GimpOperationLayerMode *layer_mode,
-                                         gfloat                 *in,
-                                         gfloat                 *layer,
-                                         gfloat                 *mask,
-                                         gfloat                 *out,
-                                         glong                   samples,
-                                         GimpBlendFunc           blend_func);
-
-
-gboolean
-gimp_operation_layer_mode_process_pixels (GeglOperation       *operation,
-                                          void                *in,
-                                          void                *layer,
-                                          void                *mask,
-                                          void                *out,
-                                          glong                samples,
-                                          const GeglRectangle *roi,
-                                          gint                 level)
-{
-  GimpOperationLayerMode *layer_mode = (gpointer) operation;
-
-  gimp_composite_blend (layer_mode, in, layer, mask, out, samples,
-                        gimp_layer_mode_get_blend_fun (layer_mode->layer_mode));
-
-  return TRUE;
+  return ((GimpOperationLayerMode *) operation)->function (
+    operation, in, layer, mask, out, samples, roi, level);
 }
 
 static gboolean
-process_layer_only (GeglOperation       *operation,
-                    void                *in_buf,
-                    void                *layer_buf,
-                    void                *mask_buf,
-                    void                *out_buf,
-                    glong                samples,
-                    const GeglRectangle *roi,
-                    gint                 level)
-{
-  gfloat *out    = out_buf;
-  gfloat *layer  = layer_buf;
-  gfloat *mask   = mask_buf;
-  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;
-}
-
-
-/*  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).
- */
-
-static inline void
-composite_func_src_atop_core (gfloat *in,
-                              gfloat *layer,
-                              gfloat *comp,
-                              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++;
-    }
-}
-
-static inline void
-composite_func_src_over_core (gfloat *in,
-                              gfloat *layer,
-                              gfloat *comp,
-                              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++;
-    }
-}
-
-static inline void
-composite_func_dst_atop_core (gfloat *in,
-                              gfloat *layer,
-                              gfloat *comp,
-                              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++;
-    }
-}
-
-static inline void
-composite_func_src_in_core (gfloat *in,
-                            gfloat *layer,
-                            gfloat *comp,
-                            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).
- */
-
-static inline void
-composite_func_src_atop_sub_core (gfloat *in,
-                                  gfloat *layer,
-                                  gfloat *comp,
-                                  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++;
-    }
-}
-
-static inline void
-composite_func_src_over_sub_core (gfloat *in,
-                                  gfloat *layer,
-                                  gfloat *comp,
-                                  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++;
-    }
-}
-
-static inline void
-composite_func_dst_atop_sub_core (gfloat *in,
-                                  gfloat *layer,
-                                  gfloat *comp,
-                                  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++;
-    }
-}
-
-static inline void
-composite_func_src_in_sub_core (gfloat *in,
-                                gfloat *layer,
-                                gfloat *comp,
-                                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++;
-    }
-}
-
-#if COMPILE_SSE2_INTRINISICS
-
-#include <emmintrin.h>
-
-static inline void
-composite_func_src_atop_sse2 (gfloat *in,
-                              gfloat *layer,
-                              gfloat *comp,
-                              gfloat *mask,
-                              gfloat  opacity,
-                              gfloat *out,
-                              gint    samples)
-{
-  if ((((uintptr_t)in)   | /* alignment check */
-       ((uintptr_t)comp) |
-       ((uintptr_t)out)   ) & 0x0F)
-    {
-      return composite_func_src_atop_core (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
-
-static inline void
-gimp_composite_blend (GimpOperationLayerMode *layer_mode,
-                      gfloat                 *in,
-                      gfloat                 *layer,
-                      gfloat                 *mask,
-                      gfloat                 *out,
-                      glong                   samples,
-                      GimpBlendFunc           blend_func)
-{
-  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;
-
-  gfloat *blend_in;
-  gfloat *blend_layer;
-  gfloat *blend_out;
-
-  gboolean composite_needs_in_color =
-    composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
-    composite_mode == GIMP_LAYER_COMPOSITE_SRC_ATOP;
-
-  const Babl *composite_to_blend_fish = NULL;
-  const Babl *blend_to_composite_fish = NULL;
+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->real_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
@@ -1167,10 +547,10 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
    */
   while (samples > GIMP_COMPOSITE_BLEND_MAX_SAMPLES)
     {
-      gimp_composite_blend (layer_mode,
-                            in, layer, mask, out,
-                            GIMP_COMPOSITE_BLEND_MAX_SAMPLES,
-                            blend_func);
+      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;
@@ -1181,6 +561,10 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
       samples -= GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
     }
 
+  composite_needs_in_color =
+    composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
+    composite_mode == GIMP_LAYER_COMPOSITE_SRC_ATOP;
+
   blend_in    = in;
   blend_layer = layer;
   blend_out   = out;
@@ -1285,8 +669,8 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
           babl_process (composite_to_blend_fish,
                         layer + first, blend_layer + first, count);
 
-          blend_func (blend_in + first, blend_layer + first,
-                      blend_out + first, count);
+          blend_function (blend_in + first, blend_layer + first,
+                          blend_out + first, count);
 
           babl_process (blend_to_composite_fish,
                         blend_out + first, blend_out + first, count);
@@ -1310,7 +694,7 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
           blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
         }
 
-      blend_func (blend_in, blend_layer, blend_out, samples);
+      blend_function (blend_in, blend_layer, blend_out, samples);
     }
 
   if (! gimp_layer_mode_is_subtractive (layer_mode->layer_mode))
@@ -1319,27 +703,23 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
         {
         case GIMP_LAYER_COMPOSITE_SRC_ATOP:
         default:
-          composite_func_src_atop (in, layer, blend_out,
-                                   mask, opacity,
-                                   out, samples);
+          composite_src_atop (in, layer, blend_out, mask, opacity,
+                              out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_SRC_OVER:
-          composite_func_src_over (in, layer, blend_out,
-                                   mask, opacity,
-                                   out, samples);
+          composite_src_over (in, layer, blend_out, mask, opacity,
+                              out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_DST_ATOP:
-          composite_func_dst_atop (in, layer, blend_out,
-                                   mask, opacity,
-                                   out, samples);
+          composite_dst_atop (in, layer, blend_out, mask, opacity,
+                              out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_SRC_IN:
-          composite_func_src_in (in, layer, blend_out,
-                                 mask, opacity,
-                                 out, samples);
+          composite_src_in (in, layer, blend_out, mask, opacity,
+                            out, samples);
           break;
         }
     }
@@ -1349,1276 +729,76 @@ gimp_composite_blend (GimpOperationLayerMode *layer_mode,
         {
         case GIMP_LAYER_COMPOSITE_SRC_ATOP:
         default:
-          composite_func_src_atop_sub (in, layer, blend_out,
-                                       mask, opacity,
-                                       out, samples);
+          composite_src_atop_sub (in, layer, blend_out, mask, opacity,
+                                  out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_SRC_OVER:
-          composite_func_src_over_sub (in, layer, blend_out,
-                                       mask, opacity,
-                                       out, samples);
+          composite_src_over_sub (in, layer, blend_out, mask, opacity,
+                                  out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_DST_ATOP:
-          composite_func_dst_atop_sub (in, layer, blend_out,
-                                       mask, opacity,
-                                       out, samples);
+          composite_dst_atop_sub (in, layer, blend_out, mask, opacity,
+                                  out, samples);
           break;
 
         case GIMP_LAYER_COMPOSITE_SRC_IN:
-          composite_func_src_in_sub (in, layer, blend_out,
-                                     mask, opacity,
-                                     out, samples);
+          composite_src_in_sub (in, layer, blend_out, mask, opacity,
+                                out, samples);
           break;
         }
     }
-}
-
-static inline void
-blendfun_screen (const float *dest,
-                 const float *src,
-                 float       *out,
-                 int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
 
-          for (c = 0; c < 3; c++)
-            out[c] = 1.0f - (1.0f - dest[c])   * (1.0f - src[c]);
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void /* aka linear_dodge */
-blendfun_addition (const float *dest,
-                   const float *src,
-                   float       *out,
-                   int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] + src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_linear_burn (const float *dest,
-                      const float *src,
-                      float       *out,
-                      int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] + src[c] - 1.0f;
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_subtract (const float *dest,
-                   const float *src,
-                   float       *out,
-                   int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] - src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_multiply (const float *dest,
-                   const float *src,
-                   float       *out,
-                   int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] * src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_normal (const float *dest,
-                 const float *src,
-                 float       *out,
-                 int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_burn (const float *dest,
-               const float *src,
-               float       *out,
-               int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp = 1.0f - (1.0f - dest[c]) / src[c];
-
-              /* The CLAMP macro is deliberately inlined and written
-               * to map comp == NAN (0 / 0) -> 1
-               */
-              out[c] = comp < 0 ? 0.0f : comp < 1.0f ? comp : 1.0f;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_darken_only (const float *dest,
-                      const float *src,
-                      float       *out,
-                      int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = MIN (dest[c], src[c]);
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_luminance_lighten_only (const float *dest,
-                                 const float *src,
-                                 float       *out,
-                                 int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-          float dest_luminance =
-             GIMP_RGB_LUMINANCE(dest[0], dest[1], dest[2]);
-          float src_luminance =
-             GIMP_RGB_LUMINANCE(src[0], src[1], src[2]);
-
-          if (dest_luminance >= src_luminance)
-            for (c = 0; c < 3; c++)
-              out[c] = dest[c];
-          else
-            for (c = 0; c < 3; c++)
-              out[c] = src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_luminance_darken_only (const float *dest,
-                                const float *src,
-                                float       *out,
-                                int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-          float dest_luminance =
-             GIMP_RGB_LUMINANCE(dest[0], dest[1], dest[2]);
-          float src_luminance =
-             GIMP_RGB_LUMINANCE(src[0], src[1], src[2]);
-
-          if (dest_luminance <= src_luminance)
-            for (c = 0; c < 3; c++)
-              out[c] = dest[c];
-          else
-            for (c = 0; c < 3; c++)
-              out[c] = src[c];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_lighten_only (const float *dest,
-                       const float *src,
-                       float       *out,
-                       int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = MAX (dest[c], src[c]);
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_difference (const float *dest,
-                     const float *src,
-                     float       *out,
-                     int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              out[c] = dest[c] - src[c];
-
-              if (out[c] < 0)
-                out[c] = -out[c];
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_divide (const float *dest,
-                 const float *src,
-                 float       *out,
-                 int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp = dest[c] / src[c];
-
-              /* make infinities(or NaN) correspond to a high number,
-               * to get more predictable math, ideally higher than 5.0
-               * but it seems like some babl conversions might be
-               * acting up then
-               */
-              if (!(comp > -42949672.0f && comp < 5.0f))
-                comp = 5.0f;
-
-              out[c] = comp;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_dodge (const float *dest,
-                const float *src,
-                float       *out,
-                int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp = dest[c] / (1.0f - src[c]);
-
-              comp = MIN (comp, 1.0f);
-
-              out[c] = comp;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_grain_extract (const float *dest,
-                        const float *src,
-                        float       *out,
-                        int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] - src[c] + 0.5f;
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_grain_merge (const float *dest,
-                      const float *src,
-                      float       *out,
-                      int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            out[c] = dest[c] + src[c] - 0.5f;
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hardlight (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp;
-
-              if (src[c] > 0.5f)
-                {
-                  comp = (1.0f - dest[c]) * (1.0f - (src[c] - 0.5f) * 2.0f);
-                  comp = MIN (1 - comp, 1);
-                }
-              else
-                {
-                  comp = dest[c] * (src[c] * 2.0f);
-                  comp = MIN (comp, 1.0f);
-                }
-
-              out[c] = comp;
-            }
-        }
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_softlight (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat multiply = dest[c] * src[c];
-              gfloat screen   = 1.0f - (1.0f - dest[c]) * (1.0f - src[c]);
-              gfloat comp     = (1.0f - dest[c]) * multiply + dest[c] * screen;
-
-              out[c] = comp;
-            }
-        }
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_overlay (const float *dest,
-                  const float *src,
-                  float       *out,
-                  int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp;
-
-              if (dest[c] < 0.5f)
-                {
-                  comp = 2.0f * dest[c] * src[c];
-                }
-              else
-                {
-                  comp = 1.0f - 2.0f * (1.0f - src[c]) * (1.0f - dest[c]);
-                }
-
-              out[c] = comp;
-            }
-        }
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hsl_color (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat dest_min, dest_max, dest_l;
-          gfloat src_min,  src_max,  src_l;
-
-          dest_min = MIN (dest[0],  dest[1]);
-          dest_min = MIN (dest_min, dest[2]);
-          dest_max = MAX (dest[0],  dest[1]);
-          dest_max = MAX (dest_max, dest[2]);
-          dest_l   = (dest_min + dest_max) / 2.0f;
-
-          src_min  = MIN (src[0],  src[1]);
-          src_min  = MIN (src_min, src[2]);
-          src_max  = MAX (src[0],  src[1]);
-          src_max  = MAX (src_max, src[2]);
-          src_l    = (src_min + src_max) / 2.0f;
-
-          if (src_l != 0.0f && src_l != 1.0f)
-            {
-              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++)
-                out[c] = src[c] * ratio + offset;
-            }
-          else
-            {
-              out[RED]   = dest_l;
-              out[GREEN] = dest_l;
-              out[BLUE]  = dest_l;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hsv_hue (const float *dest,
-                  const float *src,
-                  float       *out,
-                  int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat src_min,  src_max,  src_delta;
-          gfloat dest_min, dest_max, dest_delta, dest_s;
-
-          src_min   = MIN (src[0], src[1]);
-          src_min   = MIN (src_min, src[2]);
-          src_max   = MAX (src[0], src[1]);
-          src_max   = MAX (src_max, src[2]);
-          src_delta = src_max - src_min;
-
-          if (src_delta != 0.0f)
-            {
-              gfloat ratio;
-              gfloat offset;
-              gint   c;
-
-              dest_min   = MIN (dest[0], dest[1]);
-              dest_min   = MIN (dest_min, dest[2]);
-              dest_max   = MAX (dest[0], dest[1]);
-              dest_max   = MAX (dest_max, dest[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++)
-                out[c] = src[c] * ratio + offset;
-            }
-          else
-            {
-              gint c;
-
-              for (c = 0; c < 3; c++)
-                out[c] = dest[c];
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hsv_saturation (const float *dest,
-                         const float *src,
-                         float       *out,
-                         int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat src_min,  src_max,  src_delta, src_s;
-          gfloat dest_min, dest_max, dest_delta;
-
-          dest_min   = MIN (dest[0], dest[1]);
-          dest_min   = MIN (dest_min, dest[2]);
-          dest_max   = MAX (dest[0], dest[1]);
-          dest_max   = MAX (dest_max, dest[2]);
-          dest_delta = dest_max - dest_min;
-
-          if (dest_delta != 0.0f)
-            {
-              gfloat ratio;
-              gfloat offset;
-              gint   c;
-
-              src_min   = MIN (src[0], src[1]);
-              src_min   = MIN (src_min, src[2]);
-              src_max   = MAX (src[0], src[1]);
-              src_max   = MAX (src_max, src[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++)
-                out[c] = dest[c] * ratio + offset;
-            }
-          else
-            {
-              out[RED]   = dest_max;
-              out[GREEN] = dest_max;
-              out[BLUE]  = dest_max;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hsv_value (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat dest_v;
-          gfloat src_v;
-
-          dest_v = MAX (dest[0], dest[1]);
-          dest_v = MAX (dest_v, dest[2]);
-
-          src_v  = MAX (src[0], src[1]);
-          src_v  = MAX (src_v, src[2]);
-
-          if (dest_v != 0.0f)
-            {
-              gfloat ratio = src_v / dest_v;
-              gint   c;
-
-              for (c = 0; c < 3; c++)
-                out[c] = dest[c] * ratio;
-            }
-          else
-            {
-              out[RED]   = src_v;
-              out[GREEN] = src_v;
-              out[BLUE]  = src_v;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_lch_chroma (const float *dest,
-                     const float *src,
-                     float       *out,
-                     int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat A1 = dest[1];
-          gfloat B1 = dest[2];
-          gfloat c1 = hypotf (A1, B1);
-
-          if (c1 != 0.0f)
-            {
-              gfloat A2 = src[1];
-              gfloat B2 = src[2];
-              gfloat c2 = hypotf (A2, B2);
-              gfloat A  = c2 * A1 / c1;
-              gfloat B  = c2 * B1 / c1;
-
-              out[0] = dest[0];
-              out[1] = A;
-              out[2] = B;
-            }
-          else
-            {
-              out[0] = dest[0];
-              out[1] = dest[1];
-              out[2] = dest[2];
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_lch_color (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          out[0] = dest[0];
-          out[1] = src[1];
-          out[2] = src[2];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-  }
-}
-
-static inline void
-blendfun_lch_hue (const float *dest,
-                  const float *src,
-                  float       *out,
-                  int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gfloat A2 = src[1];
-          gfloat B2 = src[2];
-          gfloat c2 = hypotf (A2, B2);
-
-          if (c2 > 0.1f)
-            {
-              gfloat A1 = dest[1];
-              gfloat B1 = dest[2];
-              gfloat c1 = hypotf (A1, B1);
-              gfloat A  = c1 * A2 / c2;
-              gfloat B  = c1 * B2 / c2;
-
-              out[0] = dest[0];
-              out[1] = A;
-              out[2] = B;
-            }
-          else
-            {
-              out[0] = dest[0];
-              out[1] = dest[1];
-              out[2] = dest[2];
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_lch_lightness (const float *dest,
-                        const float *src,
-                        float       *out,
-                        int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          out[0] = src[0];
-          out[1] = dest[1];
-          out[2] = dest[2];
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
+  return TRUE;
 }
 
-static inline void
-blendfun_luminance (const float *dest,//*in,
-                    const float *src,//*layer,
-                    float       *out,
-                    int          samples)
+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 layer_Y[samples], *layer;
-  gfloat in_Y[samples], *in;
-
-  babl_process (babl_fish ("RGBA float", "Y float"), src, layer_Y, samples);
-  babl_process (babl_fish ("RGBA float", "Y float"), dest, in_Y, samples);
-
-  layer = &layer_Y[0];
-  in = &in_Y[0];
+  gfloat *out     = out_p;
+  gfloat *layer   = layer_p;
+  gfloat *mask    = mask_p;
+  gfloat  opacity = GIMP_OPERATION_LAYER_MODE (operation)->opacity;
 
   while (samples--)
     {
-      if (src[ALPHA] != 0.0f && dest[ALPHA] != 0.0f)
-        {
-          gfloat ratio = layer[0] / MAX(in[0], 0.0000000000000000001);
-          int c;
-          for (c = 0; c < 3; c ++)
-            out[c] = dest[c] * ratio;
-        }
+      memcpy (out, layer, 3 * sizeof (gfloat));
 
-      out[ALPHA] = src[ALPHA];
+      out[ALPHA] = layer[ALPHA] * opacity;
+      if (mask)
+        out[ALPHA] *= *mask++;
 
+      layer += 4;
       out   += 4;
-      dest  += 4;
-      src   += 4;
-      in    ++;
-      layer ++;
-    }
-}
-
-static inline void
-blendfun_copy (const float *dest,
-               const float *src,
-               float       *out,
-               int          samples)
-{
-  while (samples--)
-    {
-      gint c;
-
-      for (c = 0; c < 4; c++)
-        out[c] = src[c];
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-/* added according to:
-    http://www.simplefilter.de/en/basics/mixmods.html */
-static inline void
-blendfun_vivid_light (const float *dest,
-                      const float *src,
-                      float       *out,
-                      int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp;
-
-              if (src[c] <= 0.5f)
-                {
-                  comp = 1.0f - (1.0f - dest[c]) / (2.0f * (src[c]));
-                }
-              else
-                {
-                  comp = dest[c] / (2.0f * (1.0f - src[c]));
-                }
-              comp = MIN (comp, 1.0f);
-
-              out[c] = comp;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-
-/* added according to:
-    http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */
-static inline void
-blendfun_linear_light (const float *dest,
-                       const float *src,
-                       float       *out,
-                       int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp;
-
-              if (src[c] <= 0.5f)
-                {
-                  comp = dest[c] + 2.0 * src[c] - 1.0f;
-                }
-              else
-                {
-                  comp = dest[c] + 2.0 * (src[c] - 0.5f);
-                }
-              out[c] = comp;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
     }
-}
-
-
-/* added according to:
-    http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */
-static inline void
-blendfun_pin_light (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              gfloat comp;
-
-              if (src[c] > 0.5f)
-                {
-                  comp = MAX(dest[c], 2 * (src[c] - 0.5));
-                }
-              else
-                {
-                  comp = MIN(dest[c], 2 * src[c]);
-                }
-              out[c] = comp;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
-
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_hard_mix (const float *dest,
-                   const float *src,
-                   float       *out,
-                   int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
-
-          for (c = 0; c < 3; c++)
-            {
-              out[c] = dest[c] + src[c] < 1.0f ? 0.0f : 1.0f;
-            }
-        }
-
-      out[ALPHA] = src[ALPHA];
 
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
+  return TRUE;
 }
 
-static inline void
-blendfun_exclusion (const float *dest,
-                    const float *src,
-                    float       *out,
-                    int          samples)
-{
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          gint c;
 
-          for (c = 0; c < 3; c++)
-            {
-              out[c] = 0.5f - 2.0f * (dest[c] - 0.5f) * (src[c] - 0.5f);
-            }
-        }
+/*  public functions  */
 
-      out[ALPHA] = src[ALPHA];
 
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
-
-static inline void
-blendfun_color_erase (const float *dest,
-                      const float *src,
-                      float       *out,
-                      int          samples)
+GimpLayerCompositeRegion
+gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode)
 {
-  while (samples--)
-    {
-      if (dest[ALPHA] != 0.0f && src[ALPHA] != 0.0f)
-        {
-          const float *color   = dest;
-          const float *bgcolor = src;
-          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 (col != bgcol)
-                {
-                  gfloat a;
+  GimpOperationLayerModeClass *klass;
 
-                  if (col > bgcol)
-                    a = (col - bgcol) / (1.0f - bgcol);
-                  else
-                    a = (bgcol - col) / bgcol;
-
-                  alpha = MAX (alpha, a);
-                }
-            }
-
-          if (alpha > 0.0f)
-            {
-              gfloat alpha_inv = 1.0f / alpha;
-
-              for (c = 0; c < 3; c++)
-                out[c] = (color[c] - bgcolor[c]) * alpha_inv + bgcolor[c];
-            }
-          else
-            {
-              out[RED] = out[GREEN] = out[BLUE] = 0.0f;
-            }
-
-          out[ALPHA] = alpha;
-        }
-      else
-        out[ALPHA] = 0.0f;
+  g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode),
+                        GIMP_LAYER_COMPOSITE_REGION_INTERSECTION);
 
-      out  += 4;
-      src  += 4;
-      dest += 4;
-    }
-}
+  klass = GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode);
 
-static inline void
-blendfun_dummy (const float *dest,
-                const float *src,
-                float       *out,
-                int          samples)
-{
-}
+  if (klass->get_affected_region)
+    return klass->get_affected_region (layer_mode);
 
-static inline GimpBlendFunc
-gimp_layer_mode_get_blend_fun (GimpLayerMode mode)
-{
-  switch (mode)
-    {
-    case GIMP_LAYER_MODE_SCREEN:         return blendfun_screen;
-    case GIMP_LAYER_MODE_ADDITION:       return blendfun_addition;
-    case GIMP_LAYER_MODE_SUBTRACT:       return blendfun_subtract;
-    case GIMP_LAYER_MODE_MULTIPLY:       return blendfun_multiply;
-    case GIMP_LAYER_MODE_NORMAL_LEGACY:
-    case GIMP_LAYER_MODE_NORMAL:         return blendfun_normal;
-    case GIMP_LAYER_MODE_BURN:           return blendfun_burn;
-    case GIMP_LAYER_MODE_GRAIN_MERGE:    return blendfun_grain_merge;
-    case GIMP_LAYER_MODE_GRAIN_EXTRACT:  return blendfun_grain_extract;
-    case GIMP_LAYER_MODE_DODGE:          return blendfun_dodge;
-    case GIMP_LAYER_MODE_OVERLAY:        return blendfun_overlay;
-    case GIMP_LAYER_MODE_HSL_COLOR:      return blendfun_hsl_color;
-    case GIMP_LAYER_MODE_HSV_HUE:        return blendfun_hsv_hue;
-    case GIMP_LAYER_MODE_HSV_SATURATION: return blendfun_hsv_saturation;
-    case GIMP_LAYER_MODE_HSV_VALUE:      return blendfun_hsv_value;
-    case GIMP_LAYER_MODE_LCH_CHROMA:     return blendfun_lch_chroma;
-    case GIMP_LAYER_MODE_LCH_COLOR:      return blendfun_lch_color;
-    case GIMP_LAYER_MODE_LCH_HUE:        return blendfun_lch_hue;
-    case GIMP_LAYER_MODE_LCH_LIGHTNESS:  return blendfun_lch_lightness;
-    case GIMP_LAYER_MODE_LUMINANCE:      return blendfun_luminance;
-    case GIMP_LAYER_MODE_HARDLIGHT:      return blendfun_hardlight;
-    case GIMP_LAYER_MODE_SOFTLIGHT:      return blendfun_softlight;
-    case GIMP_LAYER_MODE_DIVIDE:         return blendfun_divide;
-    case GIMP_LAYER_MODE_DIFFERENCE:     return blendfun_difference;
-    case GIMP_LAYER_MODE_DARKEN_ONLY:    return blendfun_darken_only;
-    case GIMP_LAYER_MODE_LIGHTEN_ONLY:   return blendfun_lighten_only;
-    case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:  return blendfun_luminance_darken_only;
-    case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY: return blendfun_luminance_lighten_only;
-    case GIMP_LAYER_MODE_VIVID_LIGHT:    return blendfun_vivid_light;
-    case GIMP_LAYER_MODE_PIN_LIGHT:      return blendfun_pin_light;
-    case GIMP_LAYER_MODE_LINEAR_LIGHT:   return blendfun_linear_light;
-    case GIMP_LAYER_MODE_HARD_MIX:       return blendfun_hard_mix;
-    case GIMP_LAYER_MODE_EXCLUSION:      return blendfun_exclusion;
-    case GIMP_LAYER_MODE_LINEAR_BURN:    return blendfun_linear_burn;
-    case GIMP_LAYER_MODE_COLOR_ERASE_LEGACY:
-    case GIMP_LAYER_MODE_COLOR_ERASE:    return blendfun_color_erase;
-
-    case GIMP_LAYER_MODE_DISSOLVE:
-    case GIMP_LAYER_MODE_BEHIND_LEGACY:
-    case GIMP_LAYER_MODE_BEHIND:
-    case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
-    case GIMP_LAYER_MODE_SCREEN_LEGACY:
-    case GIMP_LAYER_MODE_OVERLAY_LEGACY:
-    case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
-    case GIMP_LAYER_MODE_ADDITION_LEGACY:
-    case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
-    case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
-    case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
-    case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
-    case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
-    case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
-    case GIMP_LAYER_MODE_HSV_VALUE_LEGACY:
-    case GIMP_LAYER_MODE_DIVIDE_LEGACY:
-    case GIMP_LAYER_MODE_DODGE_LEGACY:
-    case GIMP_LAYER_MODE_BURN_LEGACY:
-    case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
-    case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY:
-    case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY:
-    case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
-    case GIMP_LAYER_MODE_ERASE:
-    case GIMP_LAYER_MODE_MERGE:
-    case GIMP_LAYER_MODE_SPLIT:
-    case GIMP_LAYER_MODE_PASS_THROUGH:
-    case GIMP_LAYER_MODE_REPLACE:
-    case GIMP_LAYER_MODE_ANTI_ERASE:
-    case GIMP_LAYER_MODE_SEPARATOR: /* to stop GCC from complaining :P */
-      return blendfun_dummy;
-    }
-
-  return blendfun_dummy;
+  return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
 }
diff --git a/app/operations/layer-modes/gimpoperationlayermode.h 
b/app/operations/layer-modes/gimpoperationlayermode.h
index c2b044f..0e8426c 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.h
+++ b/app/operations/layer-modes/gimpoperationlayermode.h
@@ -35,20 +35,6 @@
 
 typedef struct _GimpOperationLayerModeClass GimpOperationLayerModeClass;
 
-struct _GimpOperationLayerModeClass
-{
-  GeglOperationPointComposer3Class  parent_class;
-
-  /*  virtual functions  */
-
-  /* Returns the composite region (any combination of the layer and the
-   * backdrop) that the layer mode affects.  Most modes only affect the
-   * overlapping region, which is what the function returns by default.
-   */
-  GimpLayerCompositeRegion (* get_affected_region) (GimpOperationLayerMode *layer_mode);
-};
-
-
 struct _GimpOperationLayerMode
 {
   GeglOperationPointComposer3  parent_instance;
@@ -58,23 +44,38 @@ struct _GimpOperationLayerMode
   GimpLayerColorSpace          blend_space;
   GimpLayerColorSpace          composite_space;
   GimpLayerCompositeMode       composite_mode;
-  GimpLayerModeFunc            func;
+
+  GimpLayerCompositeMode       real_composite_mode;
+  GimpLayerModeFunc            function;
+  GimpLayerModeBlendFunc       blend_function;
   gboolean                     is_last_node;
 };
 
+struct _GimpOperationLayerModeClass
+{
+  GeglOperationPointComposer3Class  parent_class;
+
+  /*  virtual functions  */
+  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);
 
-gboolean
-gimp_operation_layer_mode_process_pixels (GeglOperation       *operation,
-                                          void                *in,
-                                          void                *layer,
-                                          void                *mask,
-                                          void                *out,
-                                          glong                samples,
-                                          const GeglRectangle *roi,
-                                          gint                 level);
 
 #endif /* __GIMP_OPERATION_LAYER_MODE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationmerge.c b/app/operations/layer-modes/gimpoperationmerge.c
index d13e231..736d114 100644
--- a/app/operations/layer-modes/gimpoperationmerge.c
+++ b/app/operations/layer-modes/gimpoperationmerge.c
@@ -28,6 +28,16 @@
 #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)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationMerge, gimp_operation_merge,
 static void
 gimp_operation_merge_class_init (GimpOperationMergeClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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);
 
-  point_class->process = gimp_operation_merge_process;
+  layer_mode_class->process = gimp_operation_merge_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_merge_init (GimpOperationMerge *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_merge_process (GeglOperation       *op,
                               void                *in_p,
                               void                *layer_p,
@@ -72,7 +79,7 @@ gimp_operation_merge_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
     case GIMP_LAYER_COMPOSITE_AUTO:
diff --git a/app/operations/layer-modes/gimpoperationmerge.h b/app/operations/layer-modes/gimpoperationmerge.h
index 8734e8c..8393398 100644
--- a/app/operations/layer-modes/gimpoperationmerge.h
+++ b/app/operations/layer-modes/gimpoperationmerge.h
@@ -48,16 +48,7 @@ struct _GimpOperationMergeClass
 };
 
 
-GType    gimp_operation_merge_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_merge_process  (GeglOperation       *op,
-                                        void                *in,
-                                        void                *layer,
-                                        void                *mask,
-                                        void                *out,
-                                        glong                samples,
-                                        const GeglRectangle *roi,
-                                        gint                 level);
+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
index b4396be..60bd847 100644
--- a/app/operations/layer-modes/gimpoperationnormal-sse2.c
+++ b/app/operations/layer-modes/gimpoperationnormal-sse2.c
@@ -32,55 +32,56 @@
 /* SSE2 */
 #include <emmintrin.h>
 
+
 gboolean
-gimp_operation_normal_process_sse2 (GeglOperation       *operation,
-                                    void                *in,
-                                    void                *aux,
+gimp_operation_normal_process_sse2 (GeglOperation       *op,
+                                    void                *in_p,
+                                    void                *layer_p,
                                     void                *mask_p,
-                                    void                *out,
+                                    void                *out_p,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
   /* check alignment */
-  if ((((uintptr_t)in) | ((uintptr_t)aux) | ((uintptr_t)out)) & 0x0F)
+  if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
     {
-      return gimp_operation_normal_process_core (operation, in, aux, mask_p, out,
-                                                 samples,
-                                                 roi, level);
+      return gimp_operation_normal_process (op,
+                                            in_p, layer_p, mask_p, out_p,
+                                            samples, roi, level);
     }
   else
     {
-      GimpOperationLayerMode *layer_mode    = (GimpOperationLayerMode *) operation;
-      gfloat                  opacity       = layer_mode->opacity;
-      gfloat                 *mask          = mask_p;
-      const                   __v4sf *v_in  = (const __v4sf*) in;
-      const                   __v4sf *v_aux = (const __v4sf*) aux;
-                              __v4sf *v_out = (      __v4sf*) out;
+      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)
+      switch (layer_mode->real_composite_mode)
         {
         case GIMP_LAYER_COMPOSITE_SRC_OVER:
         case GIMP_LAYER_COMPOSITE_AUTO:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -99,7 +100,7 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
                   a_term = dst_alpha * (one - alpha);
 
                   /* out(color) = src * src_a + dst * a_term */
-                  out_pixel = rgba_aux * alpha + rgba_in * 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;
@@ -123,20 +124,20 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_SRC_ATOP:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -152,7 +153,7 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
                                                          _MM_SHUFFLE (3, 3, 3, 3));
 
                   /* out(color) = dst * (1 - src_a) + src * src_a */
-                  out_pixel = rgba_in + (rgba_aux - rgba_in) * alpha;
+                  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));
@@ -170,21 +171,21 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_DST_ATOP:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
               __v4sf out_pixel, out_pixel_rbaa;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -194,7 +195,7 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
               if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
                 {
                   /* out(color) = src */
-                  out_pixel = rgba_aux;
+                  out_pixel = rgba_layer;
                 }
               else
                 {
@@ -212,21 +213,21 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_SRC_IN:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
               __v4sf out_pixel, out_pixel_rbaa;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -240,7 +241,7 @@ gimp_operation_normal_process_sse2 (GeglOperation       *operation,
               if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
                 {
                   /* out(color) = src */
-                  out_pixel = rgba_aux;
+                  out_pixel = rgba_layer;
                 }
               else
                 {
diff --git a/app/operations/layer-modes/gimpoperationnormal-sse4.c 
b/app/operations/layer-modes/gimpoperationnormal-sse4.c
index 72825cf..c52763b 100644
--- a/app/operations/layer-modes/gimpoperationnormal-sse4.c
+++ b/app/operations/layer-modes/gimpoperationnormal-sse4.c
@@ -32,56 +32,56 @@
 /* SSE4 */
 #include <smmintrin.h>
 
+
 gboolean
-gimp_operation_normal_process_sse4 (GeglOperation       *operation,
-                                    void                *in,
-                                    void                *aux,
+gimp_operation_normal_process_sse4 (GeglOperation       *op,
+                                    void                *in_p,
+                                    void                *layer_p,
                                     void                *mask_p,
-                                    void                *out,
+                                    void                *out_p,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
   /* check alignment */
-  if ((((uintptr_t)in) | ((uintptr_t)aux) | ((uintptr_t)out)) & 0x0F)
+  if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
     {
-      return gimp_operation_normal_process_core (operation,
-                                                 in, aux, mask_p, out,
-                                                 samples,
-                                                 roi, level);
+      return gimp_operation_normal_process (op,
+                                            in_p, layer_p, mask_p, out_p,
+                                            samples, roi, level);
     }
   else
     {
-      GimpOperationLayerMode *layer_mode    = (GimpOperationLayerMode *) operation;
-      gfloat                  opacity       = layer_mode->opacity;
-      gfloat                 *mask          = mask_p;
-      const                   __v4sf *v_in  = (const __v4sf*) in;
-      const                   __v4sf *v_aux = (const __v4sf*) aux;
-                              __v4sf *v_out = (      __v4sf*) out;
+      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)
+      switch (layer_mode->real_composite_mode)
         {
         case GIMP_LAYER_COMPOSITE_SRC_OVER:
         case GIMP_LAYER_COMPOSITE_AUTO:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -100,7 +100,7 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
                   a_term = dst_alpha * (one - alpha);
 
                   /* out(color) = src * src_a + dst * a_term */
-                  out_pixel = rgba_aux * alpha + rgba_in * 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;
@@ -123,20 +123,20 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_SRC_ATOP:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -152,7 +152,7 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
                                                          _MM_SHUFFLE (3, 3, 3, 3));
 
                   /* out(color) = dst * (1 - src_a) + src * src_a */
-                  out_pixel = rgba_in + (rgba_aux - rgba_in) * alpha;
+                  out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
 
                   /* swap in the real alpha */
                   out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08);
@@ -169,21 +169,21 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_DST_ATOP:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
               __v4sf out_pixel;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -193,7 +193,7 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
               if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
                 {
                   /* out(color) = src */
-                  out_pixel = rgba_aux;
+                  out_pixel = rgba_layer;
                 }
               else
                 {
@@ -210,21 +210,21 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
         case GIMP_LAYER_COMPOSITE_SRC_IN:
           while (samples--)
             {
-              __v4sf rgba_in, rgba_aux, alpha;
+              __v4sf rgba_in, rgba_layer, alpha;
               __v4sf out_pixel;
 
-              rgba_in  = *v_in++;
-              rgba_aux = *v_aux++;
+              rgba_in    = *v_in++;
+              rgba_layer = *v_layer++;
 
               /* expand alpha */
-              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_aux,
+              alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
                                                  _MM_SHUFFLE (3, 3, 3, 3));
 
               if (mask)
                 {
                   __v4sf mask_alpha;
 
-                  /* multiply aux's alpha by the mask */
+                  /* multiply layer's alpha by the mask */
                   mask_alpha = _mm_set1_ps (*mask++);
                   alpha = alpha * mask_alpha;
                 }
@@ -238,7 +238,7 @@ gimp_operation_normal_process_sse4 (GeglOperation       *operation,
               if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
                 {
                   /* out(color) = src */
-                  out_pixel = rgba_aux;
+                  out_pixel = rgba_layer;
                 }
               else
                 {
diff --git a/app/operations/layer-modes/gimpoperationnormal.c 
b/app/operations/layer-modes/gimpoperationnormal.c
index 30870a7..4caea70 100644
--- a/app/operations/layer-modes/gimpoperationnormal.c
+++ b/app/operations/layer-modes/gimpoperationnormal.c
@@ -33,8 +33,6 @@
 G_DEFINE_TYPE (GimpOperationNormal, gimp_operation_normal,
                GIMP_TYPE_OPERATION_LAYER_MODE)
 
-#define parent_class gimp_operation_normal_parent_class
-
 
 static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
 "<gegl>"
@@ -52,17 +50,12 @@ static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
 "</node>"
 "</gegl>";
 
-static GimpLayerModeFunc _gimp_operation_normal_process = NULL;
-
 
 static void
 gimp_operation_normal_class_init (GimpOperationNormalClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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",
@@ -71,19 +64,17 @@ gimp_operation_normal_class_init (GimpOperationNormalClass *klass)
                                  "reference-composition", reference_xml,
                                  NULL);
 
-  _gimp_operation_normal_process = gimp_operation_normal_process_core;
+  layer_mode_class->process = gimp_operation_normal_process;
 
 #if COMPILE_SSE2_INTRINISICS
   if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE2)
-    _gimp_operation_normal_process = gimp_operation_normal_process_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)
-    _gimp_operation_normal_process = gimp_operation_normal_process_sse4;
+    layer_mode_class->process = gimp_operation_normal_process_sse4;
 #endif /* COMPILE_SSE4_1_INTRINISICS */
-
-  point_class->process         = gimp_operation_normal_process;
 }
 
 static void
@@ -93,28 +84,14 @@ gimp_operation_normal_init (GimpOperationNormal *self)
 
 gboolean
 gimp_operation_normal_process (GeglOperation       *op,
-                               void                *in,
-                               void                *aux,
-                               void                *mask,
-                               void                *out,
+                               void                *in_p,
+                               void                *layer_p,
+                               void                *mask_p,
+                               void                *out_p,
                                glong                samples,
                                const GeglRectangle *roi,
                                gint                 level)
 {
-  return _gimp_operation_normal_process (op, in, aux, mask, out,
-                                         samples, roi, level);
-}
-
-gboolean
-gimp_operation_normal_process_core (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;
@@ -123,7 +100,7 @@ gimp_operation_normal_process_core (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
     case GIMP_LAYER_COMPOSITE_AUTO:
diff --git a/app/operations/layer-modes/gimpoperationnormal.h 
b/app/operations/layer-modes/gimpoperationnormal.h
index ccd014c..4d24fb8 100644
--- a/app/operations/layer-modes/gimpoperationnormal.h
+++ b/app/operations/layer-modes/gimpoperationnormal.h
@@ -47,43 +47,45 @@ struct _GimpOperationNormalClass
 };
 
 
-GType    gimp_operation_normal_get_type     (void) G_GNUC_CONST;
-
-gboolean gimp_operation_normal_process      (GeglOperation       *op,
-                                             void                *in,
-                                             void                *aux,
-                                             void                *mask,
-                                             void                *out,
-                                             glong                samples,
-                                             const GeglRectangle *roi,
-                                             gint                 level);
-
-gboolean gimp_operation_normal_process_core (GeglOperation       *op,
-                                             void                *in,
-                                             void                *aux,
-                                             void                *mask,
-                                             void                *out,
-                                             glong                samples,
-                                             const GeglRectangle *roi,
-                                             gint                 level);
-
-gboolean gimp_operation_normal_process_sse2 (GeglOperation       *op,
-                                             void                *in,
-                                             void                *aux,
-                                             void                *mask,
-                                             void                *out,
-                                             glong                samples,
-                                             const GeglRectangle *roi,
-                                             gint                 level);
-
-gboolean gimp_operation_normal_process_sse4 (GeglOperation       *op,
-                                             void                *in,
-                                             void                *aux,
-                                             void                *mask,
-                                             void                *out,
-                                             glong                samples,
-                                             const GeglRectangle *roi,
-                                             gint                 level);
+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/gimpoperationreplace.c 
b/app/operations/layer-modes/gimpoperationreplace.c
index f82eac5..db7e4ce 100644
--- a/app/operations/layer-modes/gimpoperationreplace.c
+++ b/app/operations/layer-modes/gimpoperationreplace.c
@@ -27,7 +27,15 @@
 #include "gimpoperationreplace.h"
 
 
-static GimpLayerCompositeRegion gimp_operation_replace_get_affected_region (GimpOperationLayerMode 
*layer_mode);
+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,
@@ -37,21 +45,15 @@ G_DEFINE_TYPE (GimpOperationReplace, gimp_operation_replace,
 static void
 gimp_operation_replace_class_init (GimpOperationReplaceClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-  GimpOperationLayerModeClass      *layer_mode_class;
-
-  operation_class  = GEGL_OPERATION_CLASS (klass);
-  point_class      = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
-  layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (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);
 
-  point_class->process = gimp_operation_replace_process;
-
+  layer_mode_class->process             = gimp_operation_replace_process;
   layer_mode_class->get_affected_region = gimp_operation_replace_get_affected_region;
 }
 
@@ -60,7 +62,7 @@ gimp_operation_replace_init (GimpOperationReplace *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_replace_process (GeglOperation       *op,
                                 void                *in_p,
                                 void                *layer_p,
@@ -78,7 +80,7 @@ gimp_operation_replace_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
     case GIMP_LAYER_COMPOSITE_AUTO:
diff --git a/app/operations/layer-modes/gimpoperationreplace.h 
b/app/operations/layer-modes/gimpoperationreplace.h
index 37d30fa..0615a3b 100644
--- a/app/operations/layer-modes/gimpoperationreplace.h
+++ b/app/operations/layer-modes/gimpoperationreplace.h
@@ -47,16 +47,7 @@ struct _GimpOperationReplaceClass
 };
 
 
-GType    gimp_operation_replace_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_replace_process  (GeglOperation       *op,
-                                          void                *in,
-                                          void                *layer,
-                                          void                *mask,
-                                          void                *out,
-                                          glong                samples,
-                                          const GeglRectangle *roi,
-                                          gint                 level);
+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
index 3a22374..22f7f1a 100644
--- a/app/operations/layer-modes/gimpoperationsplit.c
+++ b/app/operations/layer-modes/gimpoperationsplit.c
@@ -28,6 +28,16 @@
 #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)
 
@@ -35,18 +45,15 @@ G_DEFINE_TYPE (GimpOperationSplit, gimp_operation_split,
 static void
 gimp_operation_split_class_init (GimpOperationSplitClass *klass)
 {
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_class;
-
-  operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (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);
 
-  point_class->process = gimp_operation_split_process;
+  layer_mode_class->process = gimp_operation_split_process;
 }
 
 static void
@@ -54,7 +61,7 @@ gimp_operation_split_init (GimpOperationSplit *self)
 {
 }
 
-gboolean
+static gboolean
 gimp_operation_split_process (GeglOperation       *op,
                               void                *in_p,
                               void                *layer_p,
@@ -72,7 +79,7 @@ gimp_operation_split_process (GeglOperation       *op,
   gfloat                  opacity    = layer_mode->opacity;
   const gboolean          has_mask   = mask != NULL;
 
-  switch (layer_mode->composite_mode)
+  switch (layer_mode->real_composite_mode)
     {
     case GIMP_LAYER_COMPOSITE_SRC_OVER:
       while (samples--)
diff --git a/app/operations/layer-modes/gimpoperationsplit.h b/app/operations/layer-modes/gimpoperationsplit.h
index 377297f..bb82130 100644
--- a/app/operations/layer-modes/gimpoperationsplit.h
+++ b/app/operations/layer-modes/gimpoperationsplit.h
@@ -48,16 +48,7 @@ struct _GimpOperationSplitClass
 };
 
 
-GType    gimp_operation_split_get_type (void) G_GNUC_CONST;
-
-gboolean gimp_operation_split_process  (GeglOperation       *op,
-                                        void                *in,
-                                        void                *layer,
-                                        void                *mask,
-                                        void                *out,
-                                        glong                samples,
-                                        const GeglRectangle *roi,
-                                        gint                 level);
+GType   gimp_operation_split_get_type (void) G_GNUC_CONST;
 
 
 #endif /* __GIMP_OPERATION_SPLIT_H__ */
diff --git a/app/operations/operations-types.h b/app/operations/operations-types.h
index b1ca7b7..911873e 100644
--- a/app/operations/operations-types.h
+++ b/app/operations/operations-types.h
@@ -55,19 +55,19 @@ typedef struct _GimpCagePoint                   GimpCagePoint;
 
 /*  functions  */
 
-typedef gboolean (* GimpLayerModeFunc) (GeglOperation          *operation,
-                                        void                   *in,
-                                        void                   *aux,
-                                        void                   *mask,
-                                        void                   *out,
-                                        glong                   samples,
-                                        const GeglRectangle    *roi,
-                                        gint                    level);
-
-typedef  void    (* GimpBlendFunc)     (const float            *dest,
-                                        const float            *src,
-                                        float                  *out,
-                                        gint                    samples);
+typedef gboolean (* GimpLayerModeFunc)      (GeglOperation          *operation,
+                                             void                   *in,
+                                             void                   *aux,
+                                             void                   *mask,
+                                             void                   *out,
+                                             glong                   samples,
+                                             const GeglRectangle    *roi,
+                                             gint                    level);
+
+typedef  void    (* GimpLayerModeBlendFunc) (const gfloat           *in,
+                                             const gfloat           *layer,
+                                             gfloat                 *out,
+                                             gint                    samples);
 
 
 #endif /* __OPERATIONS_TYPES_H__ */
diff --git a/app/paint/gimppaintcore-loops.c b/app/paint/gimppaintcore-loops.c
index b8e2eb7..9551b97 100644
--- a/app/paint/gimppaintcore-loops.c
+++ b/app/paint/gimppaintcore-loops.c
@@ -305,21 +305,23 @@ do_layer_blend (GeglBuffer    *src_buffer,
   GeglBufferIterator     *iter;
   guint                   paint_stride;
   gfloat                 *paint_data;
-  GimpLayerModeFunc       apply_func;
-  GimpLayerColorSpace     blend_space;
-  GimpLayerColorSpace     composite_space;
-  GimpLayerCompositeMode  composite_mode;
+  GimpOperationLayerMode  layer_mode;
 
   paint_stride = gimp_temp_buf_get_width (paint_buf);
   paint_data   = (gfloat *) gimp_temp_buf_get_data (paint_buf);
 
-  apply_func      = gimp_layer_mode_get_function (paint_mode);
-  blend_space     = gimp_layer_mode_get_blend_space (paint_mode);
-  composite_space = gimp_layer_mode_get_composite_space (paint_mode);
-  composite_mode  = gimp_layer_mode_get_paint_composite_mode (paint_mode);
+  layer_mode.layer_mode          = paint_mode;
+  layer_mode.opacity             = opacity;
+  layer_mode.function            = gimp_layer_mode_get_function (paint_mode);
+  layer_mode.blend_function      = gimp_layer_mode_get_blend_function (paint_mode);
+  layer_mode.blend_space         = gimp_layer_mode_get_blend_space (paint_mode);
+  layer_mode.composite_space     = gimp_layer_mode_get_composite_space (paint_mode);
+  layer_mode.composite_mode      = gimp_layer_mode_get_paint_composite_mode (paint_mode);
+  layer_mode.real_composite_mode = layer_mode.composite_mode;
 
   iterator_format = gimp_layer_mode_get_format (paint_mode,
-                                                composite_space, blend_space,
+                                                layer_mode.composite_space,
+                                                layer_mode.blend_space,
                                                 gegl_buffer_get_format (src_buffer));
 
   roi.x = x_offset;
@@ -351,21 +353,14 @@ do_layer_blend (GeglBuffer    *src_buffer,
 
   while (gegl_buffer_iterator_next (iter))
     {
-      GimpOperationLayerMode  layer_data;
-      gfloat                 *out_pixel   = (gfloat *) iter->data[0];
-      gfloat                 *in_pixel    = (gfloat *) iter->data[1];
-      gfloat                 *mask_pixel  = NULL;
-      gfloat                 *paint_pixel;
-      gint                    iy;
+      gfloat *out_pixel  = (gfloat *) iter->data[0];
+      gfloat *in_pixel   = (gfloat *) iter->data[1];
+      gfloat *mask_pixel = NULL;
+      gfloat *paint_pixel;
+      gint    iy;
 
       paint_pixel = paint_data + ((iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x) * 4;
 
-      layer_data.layer_mode      = paint_mode;
-      layer_data.opacity         = opacity;
-      layer_data.blend_space     = blend_space;
-      layer_data.composite_space = composite_space;
-      layer_data.composite_mode  = composite_mode;
-
       if (mask_buffer)
         mask_pixel  = (gfloat *)iter->data[2];
 
@@ -373,19 +368,18 @@ do_layer_blend (GeglBuffer    *src_buffer,
       process_roi.width  = iter->roi[0].width;
       process_roi.height = 1;
 
-
       for (iy = 0; iy < iter->roi[0].height; iy++)
         {
           process_roi.y = iter->roi[0].y + iy;
 
-          (*apply_func) ((GeglOperation*)&layer_data,
-                         in_pixel,
-                         paint_pixel,
-                         mask_pixel,
-                         out_pixel,
-                         iter->roi[0].width,
-                         &process_roi,
-                         0);
+          layer_mode.function ((GeglOperation*) &layer_mode,
+                               in_pixel,
+                               paint_pixel,
+                               mask_pixel,
+                               out_pixel,
+                               iter->roi[0].width,
+                               &process_roi,
+                               0);
 
           in_pixel    += iter->roi[0].width * 4;
           out_pixel   += iter->roi[0].width * 4;
diff --git a/app/tests/Makefile.am b/app/tests/Makefile.am
index 9254bd3..547a3fa 100644
--- a/app/tests/Makefile.am
+++ b/app/tests/Makefile.am
@@ -103,9 +103,9 @@ LDADD = \
        ../config/libappconfig.a                                        \
        ../libapp.a                                                     \
        ../gegl/libappgegl.a                                            \
+       ../operations/libappoperations.a                                \
        ../operations/layer-modes/libapplayermodes.a                    \
        ../operations/layer-modes-legacy/libapplayermodeslegacy.a       \
-       ../operations/libappoperations.a                                \
        libgimpapptestutils.a                                           \
        $(libgimpwidgets)                                               \
        $(libgimpconfig)                                                \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]