1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 2013 Daniel Sabo
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 #include <gegl.h>
20 #include <gdk-pixbuf/gdk-pixbuf.h>
21 
22 extern "C"
23 {
24 
25 #include "paint-types.h"
26 
27 #include "operations/layer-modes/gimp-layer-modes.h"
28 
29 #include "core/gimptempbuf.h"
30 
31 #include "operations/gimpoperationmaskcomponents.h"
32 
33 #include "operations/layer-modes/gimpoperationlayermode.h"
34 
35 #include "gimppaintcore-loops.h"
36 
37 } /* extern "C" */
38 
39 
40 #define PIXELS_PER_THREAD \
41   (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
42 
43 
44 /* In order to avoid iterating over the same region of the same buffers
45  * multiple times, when calling more than one of the paint-core loop functions
46  * (hereafter referred to as "algorithms") in succession, we provide a single
47  * function, gimp_paint_core_loops_process(), which can be used to perform
48  * multiple algorithms in a row.  This function takes a pointer to a
49  * GimpPaintCoreLoopsParams structure, providing the parameters for the
50  * algorithms, and a GimpPaintCoreLoopsAlgorithm bitset, which specifies the
51  * set of algorithms to run; currently, the algorithms are always run in a
52  * fixed order.  For convenience, we provide public functions for the
53  * individual algorithms, but they're merely wrappers around
54  * gimp_paint_core_loops_process().
55  *
56  * We use some C++ magic to statically generate specialized versions of
57  * gimp_paint_core_loops_process() for all possible combinations of algorithms,
58  * and, where relevant, formats and input parameters, and to dispatch to the
59  * correct version at runtime.
60  *
61  * To achieve this, each algorithm provides two components:
62  *
63  *   - The algorithm class template, which implements the algorithm, following
64  *     a common interface.  See the AlgorithmBase class for a description of
65  *     the interface.  Each algorithm class takes its base class as a template
66  *     parameter, which allows us to construct a class hierarchy corresponding
67  *     to a specific set of algorithms.  Some classes in the hierarchy are not
68  *     algorithms themselves, but are rather helpers, which provide some
69  *     functionality to the algorithms further down the hierarchy, such as
70  *     access to specific buffers.
71  *
72  *   - A dispatch function, which takes the input parameters, the requested set
73  *     of algorithms, the (type of) the current algorithm hierarchy, and a
74  *     visitor object.  The function calls the visitor with a (potentially)
75  *     modified hierarchy, depending on the input.  Ihe dispatch function for
76  *     an algorithm checks if the requested set of algorithms contains a
77  *     certain algorithm, adds the said algorithm to the hierarchy accordingly,
78  *     and calls the visitor with the new hierarchy.  See the AlgorithmDispatch
79  *     class, which provides a dispatch-function implementation which
80  *     algorithms can use instead of providing their own dispatch function.
81  *
82  *     Helper classes in the hierarchy may also provide dispatch functions,
83  *     which likewise modify the hierarchy based on the input parameters.  For
84  *     example, the dispatch_paint_mask() function adds a certain PaintMask
85  *     specialization to the hierarchy, depending on the format of the paint
86  *     mask buffer; this can be used to specialize algorithms based on the mask
87  *     format; an algorithm that depends on the paint mask may dispatch through
88  *     this function, before modifying the hierarchy itself.
89  *
90  * The dispatch() function is used to construct an algorithm hierarchy by
91  * dispatching through a list of functions.  gimp_paint_core_loops_process()
92  * calls dispatch() with the full list of algorithm dispatch functions,
93  * receiving in return the algorithm hierarchy matching the input.  It then
94  * uses the algorithm interface to perform the actual processing.
95  */
96 
97 
98 enum
99 {
100   ALGORITHM_PAINT_BUF              = 1u << 31,
101   ALGORITHM_PAINT_MASK             = 1u << 30,
102   ALGORITHM_STIPPLE                = 1u << 29,
103   ALGORITHM_COMP_MASK              = 1u << 28,
104   ALGORITHM_TEMP_COMP_MASK         = 1u << 27,
105   ALGORITHM_COMP_BUFFER            = 1u << 26,
106   ALGORITHM_TEMP_COMP_BUFFER       = 1u << 25,
107   ALGORITHM_CANVAS_BUFFER_ITERATOR = 1u << 24,
108   ALGORITHM_MASK_BUFFER_ITERATOR   = 1u << 23
109 };
110 
111 
112 template <class T>
113 struct identity
114 {
115   using type = T;
116 };
117 
118 
119 /* dispatch():
120  *
121  * Takes a list of dispatch function objects, and calls each of them, in order,
122  * with the same 'params' and 'algorithms' parameters, passing 'algorithm' as
123  * the input hierarchy to the first dispatch function, and passing the output
124  * hierarchy of the previous dispatch function as the input hierarchy for the
125  * next dispatch function.  Calls 'visitor' with the output hierarchy of the
126  * last dispatch function.
127  *
128  * Each algorithm hierarchy should provide a 'filter' static data member, and
129  * each dispatch function object should provide a 'mask' static data member.
130  * If the bitwise-AND of the current hierarchy's 'filter' member and the
131  * current dispatch function's 'mask' member is equal to 'mask', the dispatch
132  * function is skipped.  This can be used to make sure that a class appears
133  * only once in the hierarchy, even if its dispatch function is used multiple
134  * times, or to prevent an algorithm from being dispatched, if it cannot be
135  * used together with another algorithm.
136  */
137 
138 template <class Visitor,
139           class Algorithm>
140 static inline void
dispatch(Visitor visitor,const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms,identity<Algorithm> algorithm)141 dispatch (Visitor                         visitor,
142           const GimpPaintCoreLoopsParams *params,
143           GimpPaintCoreLoopsAlgorithm     algorithms,
144           identity<Algorithm>             algorithm)
145 {
146   visitor (algorithm);
147 }
148 
149 template <class Algorithm,
150           class Dispatch,
151           gboolean = (Algorithm::filter & Dispatch::mask) == Dispatch::mask>
152 struct dispatch_impl
153 {
154   template <class    Visitor,
155             class... DispatchRest>
156   static void
applydispatch_impl157   apply (Visitor                         visitor,
158          const GimpPaintCoreLoopsParams *params,
159          GimpPaintCoreLoopsAlgorithm     algorithms,
160          identity<Algorithm>             algorithm,
161          Dispatch                        disp,
162          DispatchRest...                 disp_rest)
163   {
164     disp (
165       [&] (auto algorithm)
166       {
167         dispatch (visitor, params, algorithms, algorithm, disp_rest...);
168       },
169       params, algorithms, algorithm);
170   }
171 };
172 
173 template <class Algorithm,
174           class Dispatch>
175 struct dispatch_impl<Algorithm, Dispatch, TRUE>
176 {
177   template <class    Visitor,
178             class... DispatchRest>
179   static void
applydispatch_impl180   apply (Visitor                         visitor,
181          const GimpPaintCoreLoopsParams *params,
182          GimpPaintCoreLoopsAlgorithm     algorithms,
183          identity<Algorithm>             algorithm,
184          Dispatch                        disp,
185          DispatchRest...                 disp_rest)
186   {
187     dispatch (visitor, params, algorithms, algorithm, disp_rest...);
188   }
189 };
190 
191 template <class    Visitor,
192           class    Algorithm,
193           class    Dispatch,
194           class... DispatchRest>
195 static inline void
dispatch(Visitor visitor,const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms,identity<Algorithm> algorithm,Dispatch disp,DispatchRest...disp_rest)196 dispatch (Visitor                         visitor,
197           const GimpPaintCoreLoopsParams *params,
198           GimpPaintCoreLoopsAlgorithm     algorithms,
199           identity<Algorithm>             algorithm,
200           Dispatch                        disp,
201           DispatchRest...                 disp_rest)
202 {
203   dispatch_impl<Algorithm, Dispatch>::apply (
204     visitor, params, algorithms, algorithm, disp, disp_rest...);
205 }
206 
207 
208 /* value_to_float():
209  *
210  * Converts a component value to float.
211  */
212 
213 static inline gfloat
value_to_float(guint8 value)214 value_to_float (guint8 value)
215 {
216   return value / 255.0f;
217 }
218 
219 static inline gfloat
value_to_float(gfloat value)220 value_to_float (gfloat value)
221 {
222   return value;
223 }
224 
225 template <class T>
226 static inline gfloat
227 value_to_float (T value) = delete;
228 
229 
230 /* AlgorithmBase:
231  *
232  * The base class of the algorithm hierarchy.
233  */
234 
235 struct AlgorithmBase
236 {
237   /* Used to filter-out dispatch functions; see the description of dispatch().
238    * Algorithms that redefine 'filter' should bitwise-OR their filter with that
239    * of their base class.
240    */
241   static constexpr guint          filter          = 0;
242 
243   /* The current maximal number of iterators used by the hierarchy.  Algorithms
244    * should redefine 'max_n_iterators' by adding the maximal number of
245    * iterators they use to this value.
246    */
247   static constexpr gint           max_n_iterators = 0;
248 
249   /* Non-static data members should be initialized in the constructor, and
250    * should not be further modified.
251    */
252   explicit
AlgorithmBaseAlgorithmBase253   AlgorithmBase (const GimpPaintCoreLoopsParams *params)
254   {
255   }
256 
257   /* Algorithms should store their dynamic state in the 'State' member class
258    * template.  This template will be instantiated with the most-derived type
259    * of the hierarchy, which allows an algorithm to depend on the properties of
260    * its descendants.  Algorithms that provide their own 'State' class should
261    * derive it from the 'State' class of their base class, passing 'Derived' as
262    * the template argument.
263    *
264    * Algorithms can be run in parallel on multiple threads.  In this case, each
265    * thread uses its own 'State' object, while the algorithm object itself is
266    * either shared, or is a copy of a shared algorithm object.  Either way, the
267    * algorithm object itself is immutable, while the state object is mutable.
268    */
269   template <class Derived>
270   struct State
271   {
272   };
273 
274   /* The 'init()' function is called once per state object before processing
275    * starts, and should initialize the state object, and, if necessary, the
276    * iterator.
277    *
278    * 'params' is the same parameter struct passed to the constructor.  'state'
279    * is the state object.  'iter' is the iterator; each distinct state object
280    * uses a distinct iterator; if the algorithm hierarchy doesn't use any
281    * iterator, 'iter' may be NULL.  'roi' is the full region to be processed.
282    * 'area' is the subregion to be processed by the current state object.
283    *
284    * An algorithm that overrides this function should call the 'init()'
285    * function of its base class first, using the same arguments.
286    */
287   template <class Derived>
288   void
initAlgorithmBase289   init (const GimpPaintCoreLoopsParams *params,
290         State<Derived>                 *state,
291         GeglBufferIterator             *iter,
292         const GeglRectangle            *roi,
293         const GeglRectangle            *area) const
294   {
295   }
296 
297   /* The 'init_step()' function is called once after each
298    * 'gegl_buffer_iterator_next()' call, and should perform any necessary
299    * initialization required before processing the current chunk.
300    *
301    * The parameters are the same as for 'init()', with the addition of 'rect',
302    * which is the area of the current chunk.
303    *
304    * An algorithm that overrides this function should call the 'init_step()'
305    * function of its base class first, using the same arguments.
306    */
307   template <class Derived>
308   void
init_stepAlgorithmBase309   init_step (const GimpPaintCoreLoopsParams *params,
310              State<Derived>                 *state,
311              GeglBufferIterator             *iter,
312              const GeglRectangle            *roi,
313              const GeglRectangle            *area,
314              const GeglRectangle            *rect) const
315   {
316   }
317 
318   /* The 'process_row()' function is called for each row in the current chunk,
319    * and should perform the actual processing.
320    *
321    * The parameters are the same as for 'init_step()', with the addition of
322    * 'y', which is the current row.
323    *
324    * An algorithm that overrides this function should call the 'process_row()'
325    * function of its base class first, using the same arguments.
326    */
327   template <class Derived>
328   void
process_rowAlgorithmBase329   process_row (const GimpPaintCoreLoopsParams *params,
330                State<Derived>                 *state,
331                GeglBufferIterator             *iter,
332                const GeglRectangle            *roi,
333                const GeglRectangle            *area,
334                const GeglRectangle            *rect,
335                gint                            y) const
336   {
337   }
338 
339   /* The 'finalize_step()' function is called once per chunk after its
340    * processing is done, and should finalize any chunk-specific resources of
341    * the state object.
342    *
343    * 'params' is the same parameter struct passed to the constructor.  'state'
344    * is the state object.
345    *
346    * An algorithm that overrides this function should call the
347    * 'finalize_step()' function of its base class after performing its own
348    * finalization, using the same arguments.
349    */
350   template <class Derived>
351   void
finalize_stepAlgorithmBase352   finalize_step (const GimpPaintCoreLoopsParams *params,
353                  State<Derived>                 *state) const
354   {
355   }
356 
357   /* The 'finalize()' function is called once per state object after processing
358    * is done, and should finalize the state object.
359    *
360    * 'params' is the same parameter struct passed to the constructor.  'state'
361    * is the state object.
362    *
363    * An algorithm that overrides this function should call the 'finalize()'
364    * function of its base class after performing its own finalization, using
365    * the same arguments.
366    */
367   template <class Derived>
368   void
finalizeAlgorithmBase369   finalize (const GimpPaintCoreLoopsParams *params,
370             State<Derived>                 *state) const
371   {
372   }
373 };
374 
375 
376 /* BasicDispatch:
377  *
378  * A class template implementing a simple dispatch function object, which adds
379  * an algorithm to the hierarchy unconditionally.  'AlgorithmTemplate' is the
380  * alogithm class template (usually a helper class, rather than an actual
381  * algorithm), 'Mask' is the dispatch function mask, as described in
382  * 'dispatch()', and 'Dependencies' is a list of (types of) dispatch functions
383  * the algorithm depends on.
384  *
385  * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
386  * dispatching through the list of dependencies, in order.
387  */
388 
389 template <template <class Base> class AlgorithmTemplate,
390           guint                       Mask,
391           class...                    Dependencies>
392 struct BasicDispatch
393 {
394   static constexpr guint mask = Mask;
395 
396   template <class Visitor,
397             class Algorithm>
398   void
operator ()BasicDispatch399   operator () (Visitor                         visitor,
400                const GimpPaintCoreLoopsParams *params,
401                GimpPaintCoreLoopsAlgorithm     algorithms,
402                identity<Algorithm>             algorithm) const
403   {
404     dispatch (
405       [&] (auto algorithm)
406       {
407         using NewAlgorithm = typename decltype (algorithm)::type;
408 
409         visitor (identity<AlgorithmTemplate<NewAlgorithm>> ());
410       },
411       params, algorithms, algorithm, Dependencies ()...);
412   }
413 };
414 
415 template <template <class Base> class AlgorithmTemplate,
416           guint                       Mask>
417 struct BasicDispatch<AlgorithmTemplate, Mask>
418 {
419   static constexpr guint mask = Mask;
420 
421   template <class Visitor,
422             class Algorithm>
423   void
operator ()BasicDispatch424   operator () (Visitor                         visitor,
425                const GimpPaintCoreLoopsParams *params,
426                GimpPaintCoreLoopsAlgorithm     algorithms,
427                identity<Algorithm>             algorithm) const
428   {
429     visitor (identity<AlgorithmTemplate<Algorithm>> ());
430   }
431 };
432 
433 
434 /* AlgorithmDispatch:
435  *
436  * A class template implementing a dispatch function suitable for dispatching
437  * algorithms.  'AlgorithmTemplate' is the algorithm class template, 'Mask' is
438  * the dispatch function mask, as described in 'dispatch()', and 'Dependencies'
439  * is a list of (types of) dispatch functions the algorithm depends on, used as
440  * explained below.
441  *
442  * 'AlgorithmDispatch' adds the algorithm to the hierarchy if it's included in
443  * the set of requested algorithms; specifically, if the bitwise-AND of the
444  * requested-algorithms bitset and of 'Mask' is equal to 'Mask'.
445  *
446  * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
447  * dispatching through the list of dependencies, in order.
448  */
449 
450 template <template <class Base> class AlgorithmTemplate,
451           guint                       Mask,
452           class...                    Dependencies>
453 struct AlgorithmDispatch
454 {
455   static constexpr guint mask = Mask;
456 
457   template <class Visitor,
458             class Algorithm>
459   void
operator ()AlgorithmDispatch460   operator () (Visitor                         visitor,
461                const GimpPaintCoreLoopsParams *params,
462                GimpPaintCoreLoopsAlgorithm     algorithms,
463                identity<Algorithm>             algorithm) const
464   {
465     if ((algorithms & mask) == mask)
466       {
467         dispatch (
468           [&] (auto algorithm)
469           {
470             using NewAlgorithm = typename decltype (algorithm)::type;
471 
472             visitor (identity<AlgorithmTemplate<NewAlgorithm>> ());
473           },
474           params, algorithms, algorithm, Dependencies ()...);
475       }
476     else
477       {
478         visitor (algorithm);
479       }
480   }
481 };
482 
483 
484 /* MandatoryAlgorithmDispatch:
485  *
486  * A class template implementing a dispatch function suitable for dispatching
487  * algorithms that must be included in all hierarchies.  'AlgorithmTemplate' is
488  * the algorithm class template, 'Mask' is the dispatch function mask, as
489  * described in 'dispatch()', and 'Dependencies' is a list of (types of)
490  * dispatch functions the algorithm depends on, used as explained below.
491  *
492  * 'MandatoryAlgorithmDispatch' verifies that the algorithm is included in the
493  * set of requested algorithms (specifically, that the bitwise-AND of the
494  * requested-algorithms bitset and of 'Mask' is equal to 'Mask'), and adds the
495  * it to the hierarchy unconditionally.
496  *
497  * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
498  * dispatching through the list of dependencies, in order.
499  */
500 
501 template <template <class Base> class AlgorithmTemplate,
502           guint                       Mask,
503           class...                    Dependencies>
504 struct MandatoryAlgorithmDispatch
505 {
506   static constexpr guint mask = Mask;
507 
508   template <class Visitor,
509             class Algorithm>
510   void
operator ()MandatoryAlgorithmDispatch511   operator () (Visitor                         visitor,
512                const GimpPaintCoreLoopsParams *params,
513                GimpPaintCoreLoopsAlgorithm     algorithms,
514                identity<Algorithm>             algorithm) const
515   {
516     g_return_if_fail ((algorithms & Mask) == Mask);
517 
518     BasicDispatch<AlgorithmTemplate, Mask, Dependencies...> () (visitor,
519                                                                 params,
520                                                                 algorithms,
521                                                                 algorithm);
522   }
523 };
524 
525 /* SuppressedAlgorithmDispatch:
526  *
527  * A class template implementing a placeholder dispatch function suitable for
528  * dispatching algorithms that are never included in any hierarchy.
529  * 'AlgorithmTemplate' is the algorithm class template, 'Mask' is the dispatch
530  * function mask, as described in 'dispatch()', and 'Dependencies' is a list of
531  * (types of) dispatch functions the algorithm depends on.  Note that
532  * 'AlgorithmTemplate' and 'Dependencies' are not actually used, and are merely
533  * included for exposition.
534  *
535  * 'SuppressedAlgorithmDispatch' verifies that the algorithm is not included in
536  * the set of requested algorithms (specifically, that the bitwise-AND of the
537  * requested-algorithms bitset and of 'Mask' is not equal to 'Mask'), and
538  * doesn't modify the hierarchy.
539  */
540 
541 template <template <class Base> class AlgorithmTemplate,
542           guint                       Mask,
543           class...                    Dependencies>
544 struct SuppressedAlgorithmDispatch
545 {
546   static constexpr guint mask = Mask;
547 
548   template <class Visitor,
549             class Algorithm>
550   void
operator ()SuppressedAlgorithmDispatch551   operator () (Visitor                         visitor,
552                const GimpPaintCoreLoopsParams *params,
553                GimpPaintCoreLoopsAlgorithm     algorithms,
554                identity<Algorithm>             algorithm) const
555   {
556     g_return_if_fail ((algorithms & Mask) != Mask);
557 
558     visitor (algorithm);
559   }
560 };
561 
562 
563 /* PaintBuf, dispatch_paint_buf():
564  *
565  * An algorithm helper class, providing access to the paint buffer.  Algorithms
566  * that use the paint buffer should specify 'dispatch_paint_buf()' as a
567  * dependency, and access 'PaintBuf' members through their base type/subobject.
568  */
569 
570 template <class Base>
571 struct PaintBuf : Base
572 {
573   /* Component type of the paint buffer. */
574   using paint_type = gfloat;
575 
576   static constexpr guint filter = Base::filter | ALGORITHM_PAINT_BUF;
577 
578   /* Paint buffer stride, in 'paint_type' elements. */
579   gint        paint_stride;
580   /* Pointer to the start of the paint buffer data. */
581   paint_type *paint_data;
582 
583   explicit
PaintBufPaintBuf584   PaintBuf (const GimpPaintCoreLoopsParams *params) :
585     Base (params)
586   {
587     paint_stride = gimp_temp_buf_get_width (params->paint_buf) * 4;
588     paint_data   = (paint_type *) gimp_temp_buf_get_data (params->paint_buf);
589   }
590 };
591 
592 static BasicDispatch<PaintBuf, ALGORITHM_PAINT_BUF> dispatch_paint_buf;
593 
594 
595 /* PaintMask, dispatch_paint_mask():
596  *
597  * An algorithm helper class, providing access to the paint mask.  Algorithms
598  * that use the paint mask should specify 'dispatch_paint_mask()' as a
599  * dependency, and access 'PaintMask' members through their base type/
600  * subobject.
601  */
602 
603 template <class Base,
604           class MaskType>
605 struct PaintMask : Base
606 {
607   /* Component type of the paint mask. */
608   using mask_type = MaskType;
609 
610   static constexpr guint filter = Base::filter | ALGORITHM_PAINT_MASK;
611 
612   /* Paint mask stride, in 'mask_type' elements. */
613   gint             mask_stride;
614   /* Pointer to the start of the paint mask data, taking the mask offset into
615    * account.
616    */
617   const mask_type *mask_data;
618 
619   explicit
PaintMaskPaintMask620   PaintMask (const GimpPaintCoreLoopsParams *params) :
621     Base (params)
622   {
623     mask_stride = gimp_temp_buf_get_width (params->paint_mask);
624     mask_data   =
625       (const mask_type *) gimp_temp_buf_get_data (params->paint_mask) +
626       params->paint_mask_offset_y * mask_stride                       +
627       params->paint_mask_offset_x;
628   }
629 };
630 
631 struct DispatchPaintMask
632 {
633   static constexpr guint mask = ALGORITHM_PAINT_MASK;
634 
635   template <class Visitor,
636             class Algorithm>
637   void
operator ()DispatchPaintMask638   operator () (Visitor                         visitor,
639                const GimpPaintCoreLoopsParams *params,
640                GimpPaintCoreLoopsAlgorithm     algorithms,
641                identity<Algorithm>             algorithm) const
642   {
643     const Babl *mask_format = gimp_temp_buf_get_format (params->paint_mask);
644 
645     if (mask_format == babl_format ("Y u8"))
646       visitor (identity<PaintMask<Algorithm, guint8>> ());
647     else if (mask_format == babl_format ("Y float"))
648       visitor (identity<PaintMask<Algorithm, gfloat>> ());
649     else
650       g_warning ("Mask format not supported: %s", babl_get_name (mask_format));
651   }
652 } static dispatch_paint_mask;
653 
654 
655 /* Stipple, dispatch_stipple():
656  *
657  * An algorithm helper class, providing access to the 'stipple' parameter.
658  * Algorithms that use the 'stipple' parameter should specify
659  * 'dispatch_stipple()' as a dependency, and access 'Stipple' members through
660  * their base type/subobject.
661  */
662 
663 template <class    Base,
664           gboolean StippleFlag>
665 struct Stipple : Base
666 {
667   static constexpr guint filter = Base::filter | ALGORITHM_STIPPLE;
668 
669   /* The value of the 'stipple' parameter, usable as a constant expression. */
670   static constexpr gboolean stipple = StippleFlag;
671 
672   using Base::Base;
673 };
674 
675 struct DispatchStipple
676 {
677   static constexpr guint mask = ALGORITHM_STIPPLE;
678 
679   template <class Visitor,
680             class Algorithm>
681   void
operator ()DispatchStipple682   operator () (Visitor                         visitor,
683                const GimpPaintCoreLoopsParams *params,
684                GimpPaintCoreLoopsAlgorithm     algorithms,
685                identity<Algorithm>             algorithm) const
686   {
687     if (params->stipple)
688       visitor (identity<Stipple<Algorithm, TRUE>> ());
689     else
690       visitor (identity<Stipple<Algorithm, FALSE>> ());
691   }
692 } static dispatch_stipple;
693 
694 
695 /* CompMask, dispatch_comp_mask(), has_comp_mask(), comp_mask_data():
696  *
697  * An algorithm helper class, providing access to the mask used for
698  * compositing.  When this class is part of the hierarchy, 'DoLayerBlend' uses
699  * this buffer as the mask, instead of the input parameters' 'mask_buffer'.
700  * Algorithms that use the compositing mask should specify
701  * 'dispatch_comp_mask()' as a dependency, and access 'CompMask' members
702  * through their base type/subobject.
703  *
704  * Note that 'CompMask' only provides *access* to the compositing mask, but
705  * doesn't provide its actual *storage*.  This is the responsibility of the
706  * algorithms that use 'CompMask'.  Algorithms that need temporary storage for
707  * the compositing mask can use 'TempCompMask'.
708  *
709  * The 'has_comp_mask()' constexpr function determines if a given algorithm
710  * hierarchy uses the compositing mask.
711  *
712  * The 'comp_mask_data()' function returns a pointer to the compositing mask
713  * data for the current row if the hierarchy uses the compositing mask, or NULL
714  * otherwise.
715  */
716 
717 template <class Base>
718 struct CompMask : Base
719 {
720   /* Component type of the compositing mask. */
721   using comp_mask_type = gfloat;
722 
723   static constexpr guint filter = Base::filter | ALGORITHM_COMP_MASK;
724 
725   using Base::Base;
726 
727   template <class Derived>
728   struct State : Base::template State<Derived>
729   {
730     /* Pointer to the compositing mask data for the current row. */
731     comp_mask_type *comp_mask_data;
732   };
733 };
734 
735 static BasicDispatch<CompMask, ALGORITHM_COMP_MASK> dispatch_comp_mask;
736 
737 template <class Base>
738 static constexpr gboolean
has_comp_mask(const CompMask<Base> * algorithm)739 has_comp_mask (const CompMask<Base> *algorithm)
740 {
741   return TRUE;
742 }
743 
744 static constexpr gboolean
has_comp_mask(const AlgorithmBase * algorithm)745 has_comp_mask (const AlgorithmBase *algorithm)
746 {
747   return FALSE;
748 }
749 
750 template <class Base,
751           class State>
752 static gfloat *
comp_mask_data(const CompMask<Base> * algorithm,State * state)753 comp_mask_data (const CompMask<Base> *algorithm,
754                 State                *state)
755 {
756   return state->comp_mask_data;
757 }
758 
759 template <class State>
760 static gfloat *
comp_mask_data(const AlgorithmBase * algorithm,State * state)761 comp_mask_data (const AlgorithmBase *algorithm,
762                 State               *state)
763 {
764   return NULL;
765 }
766 
767 
768 /* TempCompMask, dispatch_temp_comp_mask():
769  *
770  * An algorithm helper class, providing temporary storage for the compositing
771  * mask.  Algorithms that need a temporary compositing mask should specify
772  * 'dispatch_temp_comp_mask()' as a dependency, which itself includes
773  * 'dispatch_comp_mask()' as a dependency.
774  */
775 
776 template <class Base>
777 struct TempCompMask : Base
778 {
779   static constexpr guint filter = Base::filter | ALGORITHM_TEMP_COMP_MASK;
780 
781   using Base::Base;
782 
783   template <class Derived>
784   using State = typename Base::template State<Derived>;
785 
786   template <class Derived>
787   void
init_stepTempCompMask788   init_step (const GimpPaintCoreLoopsParams *params,
789              State<Derived>                 *state,
790              GeglBufferIterator             *iter,
791              const GeglRectangle            *roi,
792              const GeglRectangle            *area,
793              const GeglRectangle            *rect) const
794   {
795     Base::init_step (params, state, iter, roi, area, rect);
796 
797     state->comp_mask_data = gegl_scratch_new (gfloat, rect->width);
798   }
799 
800 
801   template <class Derived>
802   void
finalize_stepTempCompMask803   finalize_step (const GimpPaintCoreLoopsParams *params,
804                  State<Derived>                 *state) const
805   {
806     gegl_scratch_free (state->comp_mask_data);
807 
808     Base::finalize_step (params, state);
809   }
810 };
811 
812 static BasicDispatch<
813   TempCompMask,
814   ALGORITHM_TEMP_COMP_MASK,
815   decltype (dispatch_comp_mask)
816 > dispatch_temp_comp_mask;
817 
818 
819 /* CompBuffer, dispatch_comp_buffer(), has_comp_buffer(), comp_buffer_data():
820  *
821  * An algorithm helper class, providing access to the output buffer used for
822  * compositing.  When this class is part of the hierarchy, 'DoLayerBlend' uses
823  * this buffer as the output buffer, instead of the input parameters'
824  * 'dest_buffer'.  Algorithms that use the compositing buffer should specify
825  * 'dispatch_comp_buffer()' as a dependency, and access 'CompBuffer' members
826  * through their base type/subobject.
827  *
828  * Note that 'CompBuffer' only provides *access* to the compositing buffer, but
829  * doesn't provide its actual *storage*.  This is the responsibility of the
830  * algorithms that use 'CompBuffer'.  Algorithms that need temporary storage
831  * for the compositing buffer can use 'TempCompBuffer'.
832  *
833  * The 'has_comp_buffer()' constexpr function determines if a given algorithm
834  * hierarchy uses the compositing buffer.
835  *
836  * The 'comp_buffer_data()' function returns a pointer to the compositing
837  * buffer data for the current row if the hierarchy uses the compositing
838  * buffer, or NULL otherwise.
839  */
840 
841 template <class Base>
842 struct CompBuffer : Base
843 {
844   /* Component type of the compositing buffer. */
845   using comp_buffer_type = gfloat;
846 
847   static constexpr guint filter = Base::filter | ALGORITHM_COMP_BUFFER;
848 
849   using Base::Base;
850 
851   template <class Derived>
852   struct State : Base::template State<Derived>
853   {
854     /* Pointer to the compositing buffer data for the current row. */
855     comp_buffer_type *comp_buffer_data;
856   };
857 };
858 
859 static BasicDispatch<CompBuffer, ALGORITHM_COMP_BUFFER> dispatch_comp_buffer;
860 
861 template <class Base>
862 static constexpr gboolean
has_comp_buffer(const CompBuffer<Base> * algorithm)863 has_comp_buffer (const CompBuffer<Base> *algorithm)
864 {
865   return TRUE;
866 }
867 
868 static constexpr gboolean
has_comp_buffer(const AlgorithmBase * algorithm)869 has_comp_buffer (const AlgorithmBase *algorithm)
870 {
871   return FALSE;
872 }
873 
874 template <class Base,
875           class State>
876 static gfloat *
comp_buffer_data(const CompBuffer<Base> * algorithm,State * state)877 comp_buffer_data (const CompBuffer<Base> *algorithm,
878                   State                  *state)
879 {
880   return state->comp_buffer_data;
881 }
882 
883 template <class State>
884 static gfloat *
comp_buffer_data(const AlgorithmBase * algorithm,State * state)885 comp_buffer_data (const AlgorithmBase *algorithm,
886                   State               *state)
887 {
888   return NULL;
889 }
890 
891 
892 /* TempCompBuffer, dispatch_temp_comp_buffer():
893  *
894  * An algorithm helper class, providing temporary storage for the compositing
895  * buffer.  Algorithms that need a temporary compositing buffer should specify
896  * 'dispatch_temp_comp_buffer()' as a dependency, which itself includes
897  * 'dispatch_comp_buffer()' as a dependency.
898  */
899 
900 template <class Base>
901 struct TempCompBuffer : Base
902 {
903   static constexpr guint filter = Base::filter | ALGORITHM_TEMP_COMP_BUFFER;
904 
905   using Base::Base;
906 
907   template <class Derived>
908   using State = typename Base::template State<Derived>;
909 
910   template <class Derived>
911   void
init_stepTempCompBuffer912   init_step (const GimpPaintCoreLoopsParams *params,
913              State<Derived>                 *state,
914              GeglBufferIterator             *iter,
915              const GeglRectangle            *roi,
916              const GeglRectangle            *area,
917              const GeglRectangle            *rect) const
918   {
919     Base::init_step (params, state, iter, roi, area, rect);
920 
921     state->comp_buffer_data = gegl_scratch_new (gfloat, 4 * rect->width);
922   }
923 
924 
925   template <class Derived>
926   void
finalize_stepTempCompBuffer927   finalize_step (const GimpPaintCoreLoopsParams *params,
928                  State<Derived>                 *state) const
929   {
930     gegl_scratch_free (state->comp_buffer_data);
931 
932     Base::finalize_step (params, state);
933   }
934 };
935 
936 static BasicDispatch<
937   TempCompBuffer,
938   ALGORITHM_TEMP_COMP_BUFFER,
939   decltype (dispatch_comp_buffer)
940 > dispatch_temp_comp_buffer;
941 
942 
943 /* CanvasBufferIterator, DispatchCanvasBufferIterator:
944  *
945  * An algorithm helper class, providing iterator-access to the canvas buffer.
946  * Algorithms that iterate over the canvas buffer should specify
947  * 'DispatchCanvasBufferIterator<Access>' as a dependency, where 'Access' is
948  * the desired access mode to the canvas buffer, and access its members through
949  * their base type/subobject.
950  */
951 
952 template <class    Base,
953           guint    Access,
954           gboolean First>
955 struct CanvasBufferIterator;
956 
957 template <class Base,
958           guint Access>
959 static constexpr gboolean
canvas_buffer_iterator_is_first(CanvasBufferIterator<Base,Access,TRUE> * algorithm)960 canvas_buffer_iterator_is_first (CanvasBufferIterator<Base, Access, TRUE> *algorithm)
961 {
962   return FALSE;
963 }
964 
965 static constexpr gboolean
canvas_buffer_iterator_is_first(AlgorithmBase * algorithm)966 canvas_buffer_iterator_is_first (AlgorithmBase *algorithm)
967 {
968   return TRUE;
969 }
970 
971 template <class    Base,
972           guint    Access,
973           gboolean First = canvas_buffer_iterator_is_first ((Base *) NULL)>
974 struct CanvasBufferIterator : Base
975 {
976   /* The combined canvas-buffer access mode used by the hierarchy, up to, and
977    * including, the current class.
978    */
979   static constexpr GeglAccessMode canvas_buffer_access =
980     (GeglAccessMode) (Base::canvas_buffer_access | Access);
981 
982   using Base::Base;
983 };
984 
985 template <class Base,
986           guint Access>
987 struct CanvasBufferIterator<Base, Access, TRUE> : Base
988 {
989   /* The combined canvas-buffer access mode used by the hierarchy, up to, and
990    * including, the current class.
991    */
992   static constexpr GeglAccessMode canvas_buffer_access =
993     (GeglAccessMode) Access;
994 
995   static constexpr gint           max_n_iterators      =
996     Base::max_n_iterators + 1;
997 
998   using Base::Base;
999 
1000   template <class Derived>
1001   struct State : Base::template State<Derived>
1002   {
1003     gint canvas_buffer_iterator;
1004   };
1005 
1006   template <class Derived>
1007   void
initCanvasBufferIterator1008   init (const GimpPaintCoreLoopsParams *params,
1009         State<Derived>                 *state,
1010         GeglBufferIterator             *iter,
1011         const GeglRectangle            *roi,
1012         const GeglRectangle            *area) const
1013   {
1014     state->canvas_buffer_iterator = gegl_buffer_iterator_add (
1015       iter, params->canvas_buffer, area, 0, babl_format ("Y float"),
1016       Derived::canvas_buffer_access, GEGL_ABYSS_NONE);
1017 
1018     /* initialize the base class *after* initializing the iterator, to make
1019      * sure that canvas_buffer is the primary buffer of the iterator, if no
1020      * subclass added an iterator first.
1021      */
1022     Base::init (params, state, iter, roi, area);
1023   }
1024 };
1025 
1026 template <guint Access>
1027 struct DispatchCanvasBufferIteratorHelper
1028 {
1029   template <class Base>
1030   using algorithm_template = CanvasBufferIterator<Base, Access>;
1031 };
1032 
1033 template <guint Access>
1034 using DispatchCanvasBufferIterator = BasicDispatch<
1035   DispatchCanvasBufferIteratorHelper<Access>::template algorithm_template,
1036   ALGORITHM_CANVAS_BUFFER_ITERATOR
1037 >;
1038 
1039 
1040 /* MaskBufferIterator, mask_buffer_iterator_dispatch(),
1041  * has_mask_buffer_iterator():
1042  *
1043  * An algorithm helper class, providing read-only iterator-access to the mask
1044  * buffer.  Algorithms that iterate over the mask buffer should specify
1045  * 'dispatch_mask_buffer_iterator()' as a dependency, and access
1046  * 'MaskBufferIterator' members through their base type/subobject.
1047  *
1048  * The 'has_mask_buffer_iterator()' constexpr function determines if a given
1049  * algorithm hierarchy uses has a mask-buffer iterator.
1050  *
1051  * The 'mask_buffer_iterator()' function returns the index of the mask-buffer
1052  * iterator if the hierarchy has one, or -1 otherwise.
1053  */
1054 
1055 template <class Base>
1056 struct MaskBufferIterator : Base
1057 {
1058   static constexpr guint filter = Base::filter | ALGORITHM_MASK_BUFFER_ITERATOR;
1059 
1060   static constexpr gint max_n_iterators = Base::max_n_iterators + 1;
1061 
1062   using Base::Base;
1063 
1064   template <class Derived>
1065   struct State : Base::template State<Derived>
1066   {
1067     gint mask_buffer_iterator;
1068   };
1069 
1070   template <class Derived>
1071   void
initMaskBufferIterator1072   init (const GimpPaintCoreLoopsParams *params,
1073         State<Derived>                 *state,
1074         GeglBufferIterator             *iter,
1075         const GeglRectangle            *roi,
1076         const GeglRectangle            *area) const
1077   {
1078     Base::init (params, state, iter, roi, area);
1079 
1080     GeglRectangle mask_area = *area;
1081 
1082     mask_area.x -= params->mask_offset_x;
1083     mask_area.y -= params->mask_offset_y;
1084 
1085     state->mask_buffer_iterator = gegl_buffer_iterator_add (
1086       iter, params->mask_buffer, &mask_area, 0, babl_format ("Y float"),
1087       GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
1088   }
1089 };
1090 
1091 struct DispatchMaskBufferIterator
1092 {
1093   static constexpr guint mask = ALGORITHM_MASK_BUFFER_ITERATOR;
1094 
1095   template <class Visitor,
1096             class Algorithm>
1097   void
operator ()DispatchMaskBufferIterator1098   operator () (Visitor                         visitor,
1099                const GimpPaintCoreLoopsParams *params,
1100                GimpPaintCoreLoopsAlgorithm     algorithms,
1101                identity<Algorithm>             algorithm) const
1102   {
1103     if (params->mask_buffer)
1104       visitor (identity<MaskBufferIterator<Algorithm>> ());
1105     else
1106       visitor (algorithm);
1107   }
1108 } static dispatch_mask_buffer_iterator;
1109 
1110 template <class Base>
1111 static constexpr gboolean
has_mask_buffer_iterator(const MaskBufferIterator<Base> * algorithm)1112 has_mask_buffer_iterator (const MaskBufferIterator<Base> *algorithm)
1113 {
1114   return TRUE;
1115 }
1116 
1117 static constexpr gboolean
has_mask_buffer_iterator(const AlgorithmBase * algorithm)1118 has_mask_buffer_iterator (const AlgorithmBase *algorithm)
1119 {
1120   return FALSE;
1121 }
1122 
1123 template <class Base,
1124           class State>
1125 static gint
mask_buffer_iterator(const MaskBufferIterator<Base> * algorithm,State * state)1126 mask_buffer_iterator (const MaskBufferIterator<Base> *algorithm,
1127                       State                          *state)
1128 {
1129   return state->mask_buffer_iterator;
1130 }
1131 
1132 template <class State>
1133 static gint
mask_buffer_iterator(const AlgorithmBase * algorithm,State * state)1134 mask_buffer_iterator (const AlgorithmBase *algorithm,
1135                       State               *state)
1136 {
1137   return -1;
1138 }
1139 
1140 
1141 /* CombinePaintMaskToCanvasBufferToPaintBufAlpha,
1142  * dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha():
1143  *
1144  * An algorithm class, providing an optimized version combining both the
1145  * COMBINE_PAINT_MASK_TO_CANVAS_BUFFER and the CANVAS_BUFFER_TO_PAINT_BUF_ALPHA
1146  * algorithms.  Used instead of the individual implementations, when both
1147  * algorithms are requested.
1148  */
1149 
1150 template <class Base>
1151 struct CombinePaintMaskToCanvasBufferToPaintBufAlpha : Base
1152 {
1153   using mask_type = typename Base::mask_type;
1154 
1155   static constexpr guint filter =
1156     Base::filter                                                        |
1157     GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1158     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA    |
1159     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA       |
1160     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK          |
1161     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1162 
1163   using Base::Base;
1164 
1165   template <class Derived>
1166   struct State : Base::template State<Derived>
1167   {
1168     gfloat *canvas_pixel;
1169   };
1170 
1171   template <class Derived>
1172   void
init_stepCombinePaintMaskToCanvasBufferToPaintBufAlpha1173   init_step (const GimpPaintCoreLoopsParams *params,
1174              State<Derived>                 *state,
1175              GeglBufferIterator             *iter,
1176              const GeglRectangle            *roi,
1177              const GeglRectangle            *area,
1178              const GeglRectangle            *rect) const
1179   {
1180     Base::init_step (params, state, iter, roi, area, rect);
1181 
1182     state->canvas_pixel =
1183       (gfloat *) iter->items[state->canvas_buffer_iterator].data;
1184   }
1185 
1186   template <class Derived>
1187   void
process_rowCombinePaintMaskToCanvasBufferToPaintBufAlpha1188   process_row (const GimpPaintCoreLoopsParams *params,
1189                State<Derived>                 *state,
1190                GeglBufferIterator             *iter,
1191                const GeglRectangle            *roi,
1192                const GeglRectangle            *area,
1193                const GeglRectangle            *rect,
1194                gint                            y) const
1195   {
1196     Base::process_row (params, state, iter, roi, area, rect, y);
1197 
1198     gint             mask_offset  = (y       - roi->y) * this->mask_stride +
1199                                     (rect->x - roi->x);
1200     const mask_type *mask_pixel   = &this->mask_data[mask_offset];
1201     gint             paint_offset = (y       - roi->y) * this->paint_stride +
1202                                     (rect->x - roi->x) * 4;
1203     gfloat          *paint_pixel  = &this->paint_data[paint_offset];
1204     gint             x;
1205 
1206     for (x = 0; x < rect->width; x++)
1207       {
1208         if (Base::stipple)
1209           {
1210             state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0])  *
1211                                       value_to_float (*mask_pixel)    *
1212                                       params->paint_opacity;
1213           }
1214         else
1215           {
1216             if (params->paint_opacity > state->canvas_pixel[0])
1217               {
1218                 state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
1219                                            value_to_float (*mask_pixel)                    *
1220                                            params->paint_opacity;
1221               }
1222           }
1223 
1224         paint_pixel[3] *= state->canvas_pixel[0];
1225 
1226         mask_pixel          += 1;
1227         state->canvas_pixel += 1;
1228         paint_pixel         += 4;
1229       }
1230   }
1231 };
1232 
1233 static SuppressedAlgorithmDispatch<
1234   CombinePaintMaskToCanvasBufferToPaintBufAlpha,
1235   GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1236   GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
1237   decltype (dispatch_paint_buf),
1238   decltype (dispatch_paint_mask),
1239   decltype (dispatch_stipple),
1240   DispatchCanvasBufferIterator<GEGL_BUFFER_READWRITE>
1241 >
1242 dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha;
1243 
1244 
1245 /* CombinePaintMaskToCanvasBuffer,
1246  * dispatch_combine_paint_mask_to_canvas_buffer():
1247  *
1248  * An algorithm class, implementing the COMBINE_PAINT_MASK_TO_CANVAS_BUFFER
1249  * algorithm.
1250  */
1251 
1252 template <class Base>
1253 struct CombinePaintMaskToCanvasBuffer : Base
1254 {
1255   using mask_type = typename Base::mask_type;
1256 
1257   static constexpr guint filter =
1258     Base::filter                                                        |
1259     GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1260     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA    |
1261     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA       |
1262     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1263 
1264   using Base::Base;
1265 
1266   template <class Derived>
1267   struct State : Base::template State<Derived>
1268   {
1269     gfloat *canvas_pixel;
1270   };
1271 
1272   template <class Derived>
1273   void
init_stepCombinePaintMaskToCanvasBuffer1274   init_step (const GimpPaintCoreLoopsParams *params,
1275              State<Derived>                 *state,
1276              GeglBufferIterator             *iter,
1277              const GeglRectangle            *roi,
1278              const GeglRectangle            *area,
1279              const GeglRectangle            *rect) const
1280   {
1281     Base::init_step (params, state, iter, roi, area, rect);
1282 
1283     state->canvas_pixel =
1284       (gfloat *) iter->items[state->canvas_buffer_iterator].data;
1285   }
1286 
1287   template <class Derived>
1288   void
process_rowCombinePaintMaskToCanvasBuffer1289   process_row (const GimpPaintCoreLoopsParams *params,
1290                State<Derived>                 *state,
1291                GeglBufferIterator             *iter,
1292                const GeglRectangle            *roi,
1293                const GeglRectangle            *area,
1294                const GeglRectangle            *rect,
1295                gint                            y) const
1296   {
1297     Base::process_row (params, state, iter, roi, area, rect, y);
1298 
1299     gint             mask_offset = (y       - roi->y) * this->mask_stride +
1300                                    (rect->x - roi->x);
1301     const mask_type *mask_pixel  = &this->mask_data[mask_offset];
1302     gint             x;
1303 
1304     for (x = 0; x < rect->width; x++)
1305       {
1306         if (Base::stipple)
1307           {
1308             state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0]) *
1309                                       value_to_float (*mask_pixel)   *
1310                                       params->paint_opacity;
1311           }
1312         else
1313           {
1314             if (params->paint_opacity > state->canvas_pixel[0])
1315               {
1316                 state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
1317                                           value_to_float (*mask_pixel)                     *
1318                                           params->paint_opacity;
1319               }
1320           }
1321 
1322         mask_pixel          += 1;
1323         state->canvas_pixel += 1;
1324       }
1325   }
1326 };
1327 
1328 static AlgorithmDispatch<
1329   CombinePaintMaskToCanvasBuffer,
1330   GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER,
1331   decltype (dispatch_paint_mask),
1332   decltype (dispatch_stipple),
1333   DispatchCanvasBufferIterator<GEGL_BUFFER_READWRITE>
1334 >
1335 dispatch_combine_paint_mask_to_canvas_buffer;
1336 
1337 
1338 /* CanvasBufferToPaintBufAlpha, dispatch_canvas_buffer_to_paint_buf_alpha():
1339  *
1340  * An algorithm class, implementing the CANVAS_BUFFER_TO_PAINT_BUF_ALPHA
1341  * algorithm.
1342  */
1343 
1344 template <class Base>
1345 struct CanvasBufferToPaintBufAlpha : Base
1346 {
1347   static constexpr guint filter =
1348     Base::filter                                                     |
1349     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
1350     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA    |
1351     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK       |
1352     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1353 
1354   using Base::Base;
1355 
1356   template <class Derived>
1357   struct State : Base::template State<Derived>
1358   {
1359     const gfloat *canvas_pixel;
1360   };
1361 
1362   template <class Derived>
1363   void
init_stepCanvasBufferToPaintBufAlpha1364   init_step (const GimpPaintCoreLoopsParams *params,
1365              State<Derived>                 *state,
1366              GeglBufferIterator             *iter,
1367              const GeglRectangle            *roi,
1368              const GeglRectangle            *area,
1369              const GeglRectangle            *rect) const
1370   {
1371     Base::init_step (params, state, iter, roi, area, rect);
1372 
1373     state->canvas_pixel =
1374       (const gfloat *) iter->items[state->canvas_buffer_iterator].data;
1375   }
1376 
1377   template <class Derived>
1378   void
process_rowCanvasBufferToPaintBufAlpha1379   process_row (const GimpPaintCoreLoopsParams *params,
1380                State<Derived>                 *state,
1381                GeglBufferIterator             *iter,
1382                const GeglRectangle            *roi,
1383                const GeglRectangle            *area,
1384                const GeglRectangle            *rect,
1385                gint                            y) const
1386   {
1387     Base::process_row (params, state, iter, roi, area, rect, y);
1388 
1389     /* Copy the canvas buffer in rect to the paint buffer's alpha channel */
1390 
1391     gint    paint_offset = (y       - roi->y) * this->paint_stride +
1392                            (rect->x - roi->x) * 4;
1393     gfloat *paint_pixel  = &this->paint_data[paint_offset];
1394     gint    x;
1395 
1396     for (x = 0; x < rect->width; x++)
1397       {
1398         paint_pixel[3] *= *state->canvas_pixel;
1399 
1400         state->canvas_pixel += 1;
1401         paint_pixel         += 4;
1402       }
1403   }
1404 };
1405 
1406 static SuppressedAlgorithmDispatch<
1407   CanvasBufferToPaintBufAlpha,
1408   GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
1409   decltype (dispatch_paint_buf),
1410   DispatchCanvasBufferIterator<GEGL_BUFFER_READ>
1411 >
1412 dispatch_canvas_buffer_to_paint_buf_alpha;
1413 
1414 
1415 /* PaintMaskToPaintBufAlpha, dispatch_paint_mask_to_paint_buf_alpha():
1416  *
1417  * An algorithm class, implementing the PAINT_MASK_TO_PAINT_BUF_ALPHA
1418  * algorithm.
1419  */
1420 
1421 template <class Base>
1422 struct PaintMaskToPaintBufAlpha : Base
1423 {
1424   using mask_type = typename Base::mask_type;
1425 
1426   static constexpr guint filter =
1427     Base::filter |
1428     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
1429     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK    |
1430     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1431 
1432   explicit
PaintMaskToPaintBufAlphaPaintMaskToPaintBufAlpha1433   PaintMaskToPaintBufAlpha (const GimpPaintCoreLoopsParams *params) :
1434     Base (params)
1435   {
1436     /* Validate that the paint buffer is within the bounds of the paint mask */
1437     g_return_if_fail (gimp_temp_buf_get_width (params->paint_buf) <=
1438                       gimp_temp_buf_get_width (params->paint_mask) -
1439                       params->paint_mask_offset_x);
1440     g_return_if_fail (gimp_temp_buf_get_height (params->paint_buf) <=
1441                       gimp_temp_buf_get_height (params->paint_mask) -
1442                       params->paint_mask_offset_y);
1443   }
1444 
1445   template <class Derived>
1446   using State = typename Base::template State<Derived>;
1447 
1448   template <class Derived>
1449   void
process_rowPaintMaskToPaintBufAlpha1450   process_row (const GimpPaintCoreLoopsParams *params,
1451                State<Derived>                 *state,
1452                GeglBufferIterator             *iter,
1453                const GeglRectangle            *roi,
1454                const GeglRectangle            *area,
1455                const GeglRectangle            *rect,
1456                gint                            y) const
1457   {
1458     Base::process_row (params, state, iter, roi, area, rect, y);
1459 
1460     gint             paint_offset = (y       - roi->y) * this->paint_stride +
1461                                     (rect->x - roi->x) * 4;
1462     gfloat          *paint_pixel  = &this->paint_data[paint_offset];
1463     gint             mask_offset  = (y       - roi->y) * this->mask_stride +
1464                                     (rect->x - roi->x);
1465     const mask_type *mask_pixel   = &this->mask_data[mask_offset];
1466     gint             x;
1467 
1468     for (x = 0; x < rect->width; x++)
1469       {
1470         paint_pixel[3] *= value_to_float (*mask_pixel) * params->paint_opacity;
1471 
1472         mask_pixel  += 1;
1473         paint_pixel += 4;
1474       }
1475   }
1476 };
1477 
1478 static SuppressedAlgorithmDispatch<
1479   PaintMaskToPaintBufAlpha,
1480   GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA,
1481   decltype (dispatch_paint_buf),
1482   decltype (dispatch_paint_mask)
1483 >
1484 dispatch_paint_mask_to_paint_buf_alpha;
1485 
1486 
1487 /* CanvasBufferToCompMask, dispatch_canvas_buffer_to_comp_mask():
1488  *
1489  * An algorithm class, implementing the CANVAS_BUFFER_TO_COMP_MASK algorithm.
1490  */
1491 
1492 template <class    Base,
1493           gboolean Direct>
1494 struct CanvasBufferToCompMask : Base
1495 {
1496   using comp_mask_type = typename Base::comp_mask_type;
1497 
1498   static constexpr guint filter =
1499     Base::filter                                               |
1500     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1501     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1502 
1503   using Base::Base;
1504 
1505   template <class Derived>
1506   struct State : Base::template State<Derived>
1507   {
1508     const gfloat *canvas_pixel;
1509     const gfloat *mask_pixel;
1510   };
1511 
1512   template <class Derived>
1513   void
init_stepCanvasBufferToCompMask1514   init_step (const GimpPaintCoreLoopsParams *params,
1515              State<Derived>                 *state,
1516              GeglBufferIterator             *iter,
1517              const GeglRectangle            *roi,
1518              const GeglRectangle            *area,
1519              const GeglRectangle            *rect) const
1520   {
1521     Base::init_step (params, state, iter, roi, area, rect);
1522 
1523     state->canvas_pixel =
1524       (const gfloat *) iter->items[state->canvas_buffer_iterator].data;
1525     state->mask_pixel   =
1526       (const gfloat *) iter->items[state->mask_buffer_iterator].data;
1527   }
1528 
1529   template <class Derived>
1530   void
process_rowCanvasBufferToCompMask1531   process_row (const GimpPaintCoreLoopsParams *params,
1532                State<Derived>                 *state,
1533                GeglBufferIterator             *iter,
1534                const GeglRectangle            *roi,
1535                const GeglRectangle            *area,
1536                const GeglRectangle            *rect,
1537                gint                            y) const
1538   {
1539     Base::process_row (params, state, iter, roi, area, rect, y);
1540 
1541     comp_mask_type *comp_mask_pixel = state->comp_mask_data;
1542     gint            x;
1543 
1544     for (x = 0; x < rect->width; x++)
1545       {
1546         comp_mask_pixel[0] = state->canvas_pixel[0] * state->mask_pixel[0];
1547 
1548         comp_mask_pixel     += 1;
1549         state->canvas_pixel += 1;
1550         state->mask_pixel   += 1;
1551       }
1552   }
1553 };
1554 
1555 template <class Base>
1556 struct CanvasBufferToCompMask<Base, TRUE> : Base
1557 {
1558   static constexpr guint filter =
1559     Base::filter                                               |
1560     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1561     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1562 
1563   using Base::Base;
1564 
1565   template <class Derived>
1566   using State = typename Base::template State<Derived>;
1567 
1568   template <class Derived>
1569   void
init_stepCanvasBufferToCompMask1570   init_step (const GimpPaintCoreLoopsParams *params,
1571              State<Derived>                 *state,
1572              GeglBufferIterator             *iter,
1573              const GeglRectangle            *roi,
1574              const GeglRectangle            *area,
1575              const GeglRectangle            *rect) const
1576   {
1577     Base::init_step (params, state, iter, roi, area, rect);
1578 
1579     state->comp_mask_data =
1580       (gfloat *) iter->items[state->canvas_buffer_iterator].data - rect->width;
1581   }
1582 
1583   template <class Derived>
1584   void
process_rowCanvasBufferToCompMask1585   process_row (const GimpPaintCoreLoopsParams *params,
1586                State<Derived>                 *state,
1587                GeglBufferIterator             *iter,
1588                const GeglRectangle            *roi,
1589                const GeglRectangle            *area,
1590                const GeglRectangle            *rect,
1591                gint                            y) const
1592   {
1593     Base::process_row (params, state, iter, roi, area, rect, y);
1594 
1595     state->comp_mask_data += rect->width;
1596   }
1597 };
1598 
1599 struct DispatchCanvasBufferToCompMask
1600 {
1601   static constexpr guint mask =
1602     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
1603 
1604   template <class Base>
1605   using AlgorithmDirect   = CanvasBufferToCompMask<Base, TRUE>;
1606   template <class Base>
1607   using AlgorithmIndirect = CanvasBufferToCompMask<Base, FALSE>;
1608 
1609   using DispatchDirect    = BasicDispatch<
1610     AlgorithmDirect,
1611     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
1612     decltype (dispatch_comp_mask)
1613   >;
1614   using DispatchIndirect  = BasicDispatch<
1615     AlgorithmIndirect,
1616     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
1617     decltype (dispatch_temp_comp_mask)
1618   >;
1619 
1620   template <class Algorithm,
1621             gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
1622                                                (Algorithm *) NULL)>
1623   struct Dispatch : DispatchIndirect
1624   {
1625   };
1626 
1627   template <class Algorithm>
1628   struct Dispatch<Algorithm, FALSE> : DispatchDirect
1629   {
1630   };
1631 
1632   template <class Visitor,
1633             class Algorithm>
1634   void
operator ()DispatchCanvasBufferToCompMask1635   operator () (Visitor                         visitor,
1636                const GimpPaintCoreLoopsParams *params,
1637                GimpPaintCoreLoopsAlgorithm     algorithms,
1638                identity<Algorithm>             algorithm) const
1639   {
1640     if ((algorithms & mask) == mask)
1641       {
1642         dispatch (
1643           [&] (auto algorithm)
1644           {
1645             using NewAlgorithm = typename decltype (algorithm)::type;
1646 
1647             Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
1648           },
1649           params, algorithms, algorithm,
1650           DispatchCanvasBufferIterator<GEGL_BUFFER_READ> (),
1651           dispatch_mask_buffer_iterator);
1652       }
1653     else
1654       {
1655         visitor (algorithm);
1656       }
1657   }
1658 } static dispatch_canvas_buffer_to_comp_mask;
1659 
1660 
1661 /* PaintMaskToCompMask, dispatch_paint_mask_to_comp_mask():
1662  *
1663  * An algorithm class, implementing the PAINT_MASK_TO_COMP_MASK algorithm.
1664  */
1665 
1666 template <class    Base,
1667           gboolean Direct>
1668 struct PaintMaskToCompMask : Base
1669 {
1670   using mask_type      = typename Base::mask_type;
1671   using comp_mask_type = typename Base::comp_mask_type;
1672 
1673   static constexpr guint filter =
1674     Base::filter |
1675     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1676 
1677   using Base::Base;
1678 
1679   template <class Derived>
1680   struct State : Base::template State<Derived>
1681   {
1682     const gfloat *mask_pixel;
1683   };
1684 
1685   template <class Derived>
1686   void
init_stepPaintMaskToCompMask1687   init_step (const GimpPaintCoreLoopsParams *params,
1688              State<Derived>                 *state,
1689              GeglBufferIterator             *iter,
1690              const GeglRectangle            *roi,
1691              const GeglRectangle            *area,
1692              const GeglRectangle            *rect) const
1693   {
1694     Base::init_step (params, state, iter, roi, area, rect);
1695 
1696     if (has_mask_buffer_iterator (this))
1697       {
1698         state->mask_pixel =
1699           (const gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
1700       }
1701   }
1702 
1703   template <class Derived>
1704   void
process_rowPaintMaskToCompMask1705   process_row (const GimpPaintCoreLoopsParams *params,
1706                State<Derived>                 *state,
1707                GeglBufferIterator             *iter,
1708                const GeglRectangle            *roi,
1709                const GeglRectangle            *area,
1710                const GeglRectangle            *rect,
1711                gint                            y) const
1712   {
1713     Base::process_row (params, state, iter, roi, area, rect, y);
1714 
1715     gint             mask_offset = (y       - roi->y) * this->mask_stride +
1716                                    (rect->x - roi->x);
1717     const mask_type *mask_pixel  = &this->mask_data[mask_offset];
1718     comp_mask_type  *comp_mask_pixel = state->comp_mask_data;
1719     gint             x;
1720 
1721     if (has_mask_buffer_iterator (this))
1722       {
1723         for (x = 0; x < rect->width; x++)
1724           {
1725             comp_mask_pixel[0] = value_to_float (mask_pixel[0]) *
1726                                  state->mask_pixel[0]           *
1727                                  params->paint_opacity;
1728 
1729             comp_mask_pixel   += 1;
1730             mask_pixel        += 1;
1731             state->mask_pixel += 1;
1732           }
1733       }
1734     else
1735       {
1736         for (x = 0; x < rect->width; x++)
1737           {
1738             comp_mask_pixel[0] = value_to_float (mask_pixel[0]) *
1739                                  params->paint_opacity;
1740 
1741             comp_mask_pixel += 1;
1742             mask_pixel      += 1;
1743           }
1744       }
1745   }
1746 };
1747 
1748 template <class Base>
1749 struct PaintMaskToCompMask<Base, TRUE> : Base
1750 {
1751   using mask_type = typename Base::mask_type;
1752 
1753   static constexpr guint filter =
1754     Base::filter                                            |
1755     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK |
1756     GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
1757 
1758   using Base::Base;
1759 
1760   template <class Derived>
1761   using State = typename Base::template State<Derived>;
1762 
1763   template <class Derived>
1764   void
init_stepPaintMaskToCompMask1765   init_step (const GimpPaintCoreLoopsParams *params,
1766              State<Derived>                 *state,
1767              GeglBufferIterator             *iter,
1768              const GeglRectangle            *roi,
1769              const GeglRectangle            *area,
1770              const GeglRectangle            *rect) const
1771   {
1772     Base::init_step (params, state, iter, roi, area, rect);
1773 
1774     gint mask_offset = (rect->y - roi->y) * this->mask_stride +
1775                        (rect->x - roi->x);
1776 
1777     state->comp_mask_data = (mask_type *) &this->mask_data[mask_offset] -
1778                             this->mask_stride;
1779   }
1780 
1781   template <class Derived>
1782   void
process_rowPaintMaskToCompMask1783   process_row (const GimpPaintCoreLoopsParams *params,
1784                State<Derived>                 *state,
1785                GeglBufferIterator             *iter,
1786                const GeglRectangle            *roi,
1787                const GeglRectangle            *area,
1788                const GeglRectangle            *rect,
1789                gint                            y) const
1790   {
1791     Base::process_row (params, state, iter, roi, area, rect, y);
1792 
1793     state->comp_mask_data += this->mask_stride;
1794   }
1795 };
1796 
1797 struct DispatchPaintMaskToCompMask
1798 {
1799   static constexpr guint mask =
1800     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1801 
1802   template <class Base>
1803   using AlgorithmDirect   = PaintMaskToCompMask<Base, TRUE>;
1804   template <class Base>
1805   using AlgorithmIndirect = PaintMaskToCompMask<Base, FALSE>;
1806 
1807   using DispatchDirect    = BasicDispatch<
1808     AlgorithmDirect,
1809     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
1810     decltype (dispatch_comp_mask)
1811   >;
1812   using DispatchIndirect  = BasicDispatch<
1813     AlgorithmIndirect,
1814     GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
1815     decltype (dispatch_temp_comp_mask)
1816   >;
1817 
1818   template <class Algorithm,
1819             class MaskType                 = typename Algorithm::mask_type,
1820             gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
1821                                                (Algorithm *) NULL)>
1822   struct Dispatch : DispatchIndirect
1823   {
1824   };
1825 
1826   template <class Algorithm>
1827   struct Dispatch<Algorithm, gfloat, FALSE> : DispatchDirect
1828   {
1829   };
1830 
1831   template <class Visitor,
1832             class Algorithm>
1833   void
operator ()DispatchPaintMaskToCompMask1834   operator () (Visitor                         visitor,
1835                const GimpPaintCoreLoopsParams *params,
1836                GimpPaintCoreLoopsAlgorithm     algorithms,
1837                identity<Algorithm>             algorithm) const
1838   {
1839     if ((algorithms & mask) == mask)
1840       {
1841         dispatch (
1842           [&] (auto algorithm)
1843           {
1844             using NewAlgorithm = typename decltype (algorithm)::type;
1845 
1846             if (params->paint_opacity == GIMP_OPACITY_OPAQUE)
1847               Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
1848             else
1849               DispatchIndirect       () (visitor, params, algorithms, algorithm);
1850           },
1851           params, algorithms, algorithm,
1852           dispatch_paint_mask,
1853           dispatch_mask_buffer_iterator);
1854       }
1855     else
1856       {
1857         visitor (algorithm);
1858       }
1859   }
1860 } static dispatch_paint_mask_to_comp_mask;
1861 
1862 
1863 /* DoLayerBlend, dispatch_do_layer_blend():
1864  *
1865  * An algorithm class, implementing the DO_LAYER_BLEND algorithm.
1866  */
1867 
1868 template <class Base>
1869 struct DoLayerBlend : Base
1870 {
1871   static constexpr guint filter =
1872     Base::filter |
1873     GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
1874 
1875   static constexpr gint max_n_iterators = Base::max_n_iterators + 2;
1876 
1877   const Babl             *iterator_format;
1878   GimpOperationLayerMode  layer_mode;
1879 
1880   explicit
DoLayerBlendDoLayerBlend1881   DoLayerBlend (const GimpPaintCoreLoopsParams *params) :
1882     Base (params)
1883   {
1884     layer_mode.layer_mode      = params->paint_mode;
1885     layer_mode.opacity         = params->image_opacity;
1886     layer_mode.function        = gimp_layer_mode_get_function (params->paint_mode);
1887     layer_mode.blend_function  = gimp_layer_mode_get_blend_function (params->paint_mode);
1888     layer_mode.blend_space     = gimp_layer_mode_get_blend_space (params->paint_mode);
1889     layer_mode.composite_space = gimp_layer_mode_get_composite_space (params->paint_mode);
1890     layer_mode.composite_mode  = gimp_layer_mode_get_paint_composite_mode (params->paint_mode);
1891 
1892     iterator_format = gimp_layer_mode_get_format (params->paint_mode,
1893                                                   layer_mode.blend_space,
1894                                                   layer_mode.composite_space,
1895                                                   layer_mode.composite_mode,
1896                                                   gimp_temp_buf_get_format (params->paint_buf));
1897 
1898     g_return_if_fail (gimp_temp_buf_get_format (params->paint_buf) == iterator_format);
1899   }
1900 
1901   template <class Derived>
1902   struct State : Base::template State<Derived>
1903   {
1904     gint           iterator_base;
1905 
1906     GeglRectangle  process_roi;
1907 
1908     gfloat        *out_pixel;
1909     gfloat        *in_pixel;
1910     gfloat        *mask_pixel;
1911     gfloat        *paint_pixel;
1912   };
1913 
1914   template <class Derived>
1915   void
initDoLayerBlend1916   init (const GimpPaintCoreLoopsParams *params,
1917         State<Derived>                 *state,
1918         GeglBufferIterator             *iter,
1919         const GeglRectangle            *roi,
1920         const GeglRectangle            *area) const
1921   {
1922     state->iterator_base = gegl_buffer_iterator_add (iter, params->src_buffer,
1923                                                      area, 0, iterator_format,
1924                                                      GEGL_ACCESS_READ,
1925                                                      GEGL_ABYSS_NONE);
1926 
1927     if (! has_comp_buffer ((const Derived *) this))
1928       {
1929         gegl_buffer_iterator_add (iter, params->dest_buffer, area, 0,
1930                                   iterator_format,
1931                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
1932       }
1933 
1934     /* initialize the base class *after* initializing the iterator, to make
1935      * sure that src_buffer is the primary buffer of the iterator, if no
1936      * subclass added an iterator first.
1937      */
1938     Base::init (params, state, iter, roi, area);
1939   }
1940 
1941   template <class Derived>
1942   void
init_stepDoLayerBlend1943   init_step (const GimpPaintCoreLoopsParams *params,
1944              State<Derived>                 *state,
1945              GeglBufferIterator             *iter,
1946              const GeglRectangle            *roi,
1947              const GeglRectangle            *area,
1948              const GeglRectangle            *rect) const
1949   {
1950     Base::init_step (params, state, iter, roi, area, rect);
1951 
1952     state->in_pixel = (gfloat *) iter->items[state->iterator_base + 0].data;
1953 
1954     state->paint_pixel = this->paint_data                        +
1955                          (rect->y - roi->y) * this->paint_stride +
1956                          (rect->x - roi->x) * 4;
1957 
1958     if (! has_comp_mask (this) && has_mask_buffer_iterator (this))
1959       {
1960         state->mask_pixel =
1961           (gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
1962       }
1963 
1964     if (! has_comp_buffer ((const Derived *) this))
1965       state->out_pixel = (gfloat *) iter->items[state->iterator_base + 1].data;
1966 
1967     state->process_roi.x      = rect->x;
1968     state->process_roi.width  = rect->width;
1969     state->process_roi.height = 1;
1970   }
1971 
1972   template <class Derived>
1973   void
process_rowDoLayerBlend1974   process_row (const GimpPaintCoreLoopsParams *params,
1975                State<Derived>                 *state,
1976                GeglBufferIterator             *iter,
1977                const GeglRectangle            *roi,
1978                const GeglRectangle            *area,
1979                const GeglRectangle            *rect,
1980                gint                            y) const
1981   {
1982     Base::process_row (params, state, iter, roi, area, rect, y);
1983 
1984     gfloat *mask_pixel;
1985     gfloat *out_pixel;
1986 
1987     if (has_comp_mask (this))
1988       mask_pixel = comp_mask_data (this, state);
1989     else if (has_mask_buffer_iterator (this))
1990       mask_pixel = state->mask_pixel;
1991     else
1992       mask_pixel = NULL;
1993 
1994     if (! has_comp_buffer ((const Derived *) this))
1995       {
1996         out_pixel = state->out_pixel;
1997       }
1998     else
1999       {
2000         out_pixel = comp_buffer_data (
2001           (const Derived *) this,
2002           (typename Derived::template State<Derived> *) state);
2003       }
2004 
2005     state->process_roi.y = y;
2006 
2007     layer_mode.function ((GeglOperation*) &layer_mode,
2008                          state->in_pixel,
2009                          state->paint_pixel,
2010                          mask_pixel,
2011                          out_pixel,
2012                          rect->width,
2013                          &state->process_roi,
2014                          0);
2015 
2016     state->in_pixel     += rect->width * 4;
2017     state->paint_pixel  += this->paint_stride;
2018     if (! has_comp_mask (this) && has_mask_buffer_iterator (this))
2019       state->mask_pixel += rect->width;
2020     if (! has_comp_buffer ((const Derived *) this))
2021       state->out_pixel  += rect->width * 4;
2022   }
2023 };
2024 
2025 static MandatoryAlgorithmDispatch<
2026   DoLayerBlend,
2027   GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND,
2028   decltype (dispatch_paint_buf),
2029   decltype (dispatch_mask_buffer_iterator)
2030 >
2031 dispatch_do_layer_blend;
2032 
2033 
2034 /* MaskComponents, dispatch_mask_components():
2035  *
2036  * An algorithm class, implementing the MASK_COMPONENTS algorithm.
2037  */
2038 
2039 template <class Base>
2040 struct MaskComponents : Base
2041 {
2042   static constexpr guint filter =
2043     Base::filter |
2044     GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS;
2045 
2046   static constexpr gint max_n_iterators = Base::max_n_iterators + 1;
2047 
2048   const Babl *format;
2049   const Babl *comp_fish = NULL;
2050 
2051   explicit
MaskComponentsMaskComponents2052   MaskComponents (const GimpPaintCoreLoopsParams *params) :
2053     Base (params)
2054   {
2055     format = gimp_operation_mask_components_get_format (
2056       gegl_buffer_get_format (params->dest_buffer));
2057 
2058     if (format != this->iterator_format)
2059       comp_fish = babl_fish (this->iterator_format, format);
2060   }
2061 
2062   template <class Derived>
2063   struct State : Base::template State<Derived>
2064   {
2065     gint    dest_buffer_iterator;
2066 
2067     guint8 *dest_pixel;
2068     guint8 *comp_pixel;
2069   };
2070 
2071   template <class Derived>
2072   void
initMaskComponents2073   init (const GimpPaintCoreLoopsParams *params,
2074         State<Derived>                 *state,
2075         GeglBufferIterator             *iter,
2076         const GeglRectangle            *roi,
2077         const GeglRectangle            *area) const
2078   {
2079     state->dest_buffer_iterator = gegl_buffer_iterator_add (
2080       iter, params->dest_buffer, area, 0, format,
2081       GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
2082 
2083     /* initialize the base class *after* initializing the iterator, to make
2084      * sure that dest_buffer is the primary buffer of the iterator, if no
2085      * subclass added an iterator first.
2086      */
2087     Base::init (params, state, iter, roi, area);
2088   }
2089 
2090   template <class Derived>
2091   void
init_stepMaskComponents2092   init_step (const GimpPaintCoreLoopsParams *params,
2093              State<Derived>                 *state,
2094              GeglBufferIterator             *iter,
2095              const GeglRectangle            *roi,
2096              const GeglRectangle            *area,
2097              const GeglRectangle            *rect) const
2098   {
2099     Base::init_step (params, state, iter, roi, area, rect);
2100 
2101     state->dest_pixel =
2102       (guint8 *) iter->items[state->dest_buffer_iterator].data;
2103 
2104     if (comp_fish)
2105       {
2106         state->comp_pixel = (guint8 *) gegl_scratch_alloc (
2107           rect->width * babl_format_get_bytes_per_pixel (format));
2108       }
2109   }
2110 
2111   template <class Derived>
2112   void
process_rowMaskComponents2113   process_row (const GimpPaintCoreLoopsParams *params,
2114                State<Derived>                 *state,
2115                GeglBufferIterator             *iter,
2116                const GeglRectangle            *roi,
2117                const GeglRectangle            *area,
2118                const GeglRectangle            *rect,
2119                gint                            y) const
2120   {
2121     Base::process_row (params, state, iter, roi, area, rect, y);
2122 
2123     gpointer comp_pixel;
2124 
2125     if (comp_fish)
2126       {
2127         babl_process (comp_fish,
2128                       state->comp_buffer_data, state->comp_pixel,
2129                       rect->width);
2130 
2131         comp_pixel = state->comp_pixel;
2132       }
2133     else
2134       {
2135         comp_pixel = state->comp_buffer_data;
2136       }
2137 
2138     gimp_operation_mask_components_process (format,
2139                                             state->dest_pixel, comp_pixel,
2140                                             state->dest_pixel,
2141                                             rect->width, params->affect);
2142 
2143     state->dest_pixel += rect->width * babl_format_get_bytes_per_pixel (format);
2144   }
2145 
2146   template <class Derived>
2147   void
finalize_stepMaskComponents2148   finalize_step (const GimpPaintCoreLoopsParams *params,
2149                  State<Derived>                 *state) const
2150   {
2151     if (comp_fish)
2152       gegl_scratch_free (state->comp_pixel);
2153 
2154     Base::finalize_step (params, state);
2155   }
2156 };
2157 
2158 static AlgorithmDispatch<
2159   MaskComponents,
2160   GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS,
2161   decltype (dispatch_temp_comp_buffer)
2162 >
2163 dispatch_mask_components;
2164 
2165 
2166 /* gimp_paint_core_loops_process():
2167  *
2168  * Performs the set of algorithms requested in 'algorithms', specified as a
2169  * bitwise-OR of 'GimpPaintCoreLoopsAlgorithm' values, given the set of
2170  * parameters 'params'.
2171  *
2172  * Note that the order in which the algorithms are performed is currently
2173  * fixed, and follows their order of appearance in the
2174  * 'GimpPaintCoreLoopsAlgorithm' enum.
2175  */
2176 
2177 void
gimp_paint_core_loops_process(const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms)2178 gimp_paint_core_loops_process (const GimpPaintCoreLoopsParams *params,
2179                                GimpPaintCoreLoopsAlgorithm     algorithms)
2180 {
2181   GeglRectangle roi;
2182 
2183   if (params->paint_buf)
2184     {
2185       roi.x      = params->paint_buf_offset_x;
2186       roi.y      = params->paint_buf_offset_y;
2187       roi.width  = gimp_temp_buf_get_width  (params->paint_buf);
2188       roi.height = gimp_temp_buf_get_height (params->paint_buf);
2189     }
2190   else
2191     {
2192       roi.x      = params->paint_buf_offset_x;
2193       roi.y      = params->paint_buf_offset_y;
2194       roi.width  = gimp_temp_buf_get_width (params->paint_mask) -
2195                    params->paint_mask_offset_x;
2196       roi.height = gimp_temp_buf_get_height (params->paint_mask) -
2197                    params->paint_mask_offset_y;
2198     }
2199 
2200   dispatch (
2201     [&] (auto algorithm_type)
2202     {
2203       using Algorithm = typename decltype (algorithm_type)::type;
2204       using State     = typename Algorithm::template State<Algorithm>;
2205 
2206       Algorithm algorithm (params);
2207 
2208       gegl_parallel_distribute_area (
2209         &roi, PIXELS_PER_THREAD,
2210         [=] (const GeglRectangle *area)
2211         {
2212           State state;
2213           gint  y;
2214 
2215           if (Algorithm::max_n_iterators > 0)
2216             {
2217               GeglBufferIterator *iter;
2218 
2219               iter = gegl_buffer_iterator_empty_new (
2220                 Algorithm::max_n_iterators);
2221 
2222               algorithm.init (params, &state, iter, &roi, area);
2223 
2224               while (gegl_buffer_iterator_next (iter))
2225                 {
2226                   const GeglRectangle *rect = &iter->items[0].roi;
2227 
2228                   algorithm.init_step (params, &state, iter, &roi, area, rect);
2229 
2230                   for (y = 0; y < rect->height; y++)
2231                     {
2232                       algorithm.process_row (params, &state,
2233                                              iter, &roi, area, rect,
2234                                              rect->y + y);
2235                     }
2236 
2237                   algorithm.finalize_step (params, &state);
2238                 }
2239 
2240               algorithm.finalize (params, &state);
2241             }
2242           else
2243             {
2244               algorithm.init      (params, &state, NULL, &roi, area);
2245               algorithm.init_step (params, &state, NULL, &roi, area, area);
2246 
2247               for (y = 0; y < area->height; y++)
2248                 {
2249                   algorithm.process_row (params, &state,
2250                                          NULL, &roi, area, area,
2251                                          area->y + y);
2252                 }
2253 
2254               algorithm.finalize_step (params, &state);
2255               algorithm.finalize      (params, &state);
2256             }
2257         });
2258     },
2259     params, algorithms, identity<AlgorithmBase> (),
2260     dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha,
2261     dispatch_combine_paint_mask_to_canvas_buffer,
2262     dispatch_canvas_buffer_to_paint_buf_alpha,
2263     dispatch_paint_mask_to_paint_buf_alpha,
2264     dispatch_canvas_buffer_to_comp_mask,
2265     dispatch_paint_mask_to_comp_mask,
2266     dispatch_do_layer_blend,
2267     dispatch_mask_components);
2268 }
2269