1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
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 
20 #include <cairo.h>
21 #include <gdk-pixbuf/gdk-pixbuf.h>
22 #include <gegl.h>
23 
24 #include "libgimpbase/gimpbase.h"
25 
26 #include "core-types.h"
27 
28 #include "gegl/gimpapplicator.h"
29 
30 #include "gimp.h"
31 #include "gimpchannel.h"
32 #include "gimpchunkiterator.h"
33 #include "gimpdrawable-combine.h"
34 #include "gimpimage.h"
35 
36 
37 void
gimp_drawable_real_apply_buffer(GimpDrawable * drawable,GeglBuffer * buffer,const GeglRectangle * buffer_region,gboolean push_undo,const gchar * undo_desc,gdouble opacity,GimpLayerMode mode,GimpLayerColorSpace blend_space,GimpLayerColorSpace composite_space,GimpLayerCompositeMode composite_mode,GeglBuffer * base_buffer,gint base_x,gint base_y)38 gimp_drawable_real_apply_buffer (GimpDrawable           *drawable,
39                                  GeglBuffer             *buffer,
40                                  const GeglRectangle    *buffer_region,
41                                  gboolean                push_undo,
42                                  const gchar            *undo_desc,
43                                  gdouble                 opacity,
44                                  GimpLayerMode           mode,
45                                  GimpLayerColorSpace     blend_space,
46                                  GimpLayerColorSpace     composite_space,
47                                  GimpLayerCompositeMode  composite_mode,
48                                  GeglBuffer             *base_buffer,
49                                  gint                    base_x,
50                                  gint                    base_y)
51 {
52   GimpItem          *item  = GIMP_ITEM (drawable);
53   GimpImage         *image = gimp_item_get_image (item);
54   GimpChannel       *mask  = gimp_image_get_mask (image);
55   GimpApplicator    *applicator;
56   GimpChunkIterator *iter;
57   gint               x, y, width, height;
58   gint               offset_x, offset_y;
59 
60   /*  don't apply the mask to itself and don't apply an empty mask  */
61   if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
62     mask = NULL;
63 
64   if (! base_buffer)
65     base_buffer = gimp_drawable_get_buffer (drawable);
66 
67   /*  get the layer offsets  */
68   gimp_item_get_offset (item, &offset_x, &offset_y);
69 
70   /*  make sure the image application coordinates are within drawable bounds  */
71   if (! gimp_rectangle_intersect (base_x, base_y,
72                                   buffer_region->width, buffer_region->height,
73                                   0, 0,
74                                   gimp_item_get_width  (item),
75                                   gimp_item_get_height (item),
76                                   &x, &y, &width, &height))
77     {
78       return;
79     }
80 
81   if (mask)
82     {
83       GimpItem *mask_item = GIMP_ITEM (mask);
84 
85       /*  make sure coordinates are in mask bounds ...
86        *  we need to add the layer offset to transform coords
87        *  into the mask coordinate system
88        */
89       if (! gimp_rectangle_intersect (x, y, width, height,
90                                       -offset_x, -offset_y,
91                                       gimp_item_get_width  (mask_item),
92                                       gimp_item_get_height (mask_item),
93                                       &x, &y, &width, &height))
94         {
95           return;
96         }
97     }
98 
99   if (push_undo)
100     {
101       gimp_drawable_push_undo (drawable, undo_desc,
102                                NULL, x, y, width, height);
103     }
104 
105   applicator = gimp_applicator_new (NULL);
106 
107   if (mask)
108     {
109       GeglBuffer *mask_buffer;
110 
111       mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
112 
113       gimp_applicator_set_mask_buffer (applicator, mask_buffer);
114       gimp_applicator_set_mask_offset (applicator, -offset_x, -offset_y);
115     }
116 
117   gimp_applicator_set_src_buffer (applicator, base_buffer);
118   gimp_applicator_set_dest_buffer (applicator,
119                                    gimp_drawable_get_buffer (drawable));
120 
121   gimp_applicator_set_apply_buffer (applicator, buffer);
122   gimp_applicator_set_apply_offset (applicator,
123                                     base_x - buffer_region->x,
124                                     base_y - buffer_region->y);
125 
126   gimp_applicator_set_opacity (applicator, opacity);
127   gimp_applicator_set_mode (applicator, mode,
128                             blend_space, composite_space, composite_mode);
129   gimp_applicator_set_affect (applicator,
130                               gimp_drawable_get_active_mask (drawable));
131 
132   iter = gimp_chunk_iterator_new (cairo_region_create_rectangle (
133     &(cairo_rectangle_int_t) {x, y, width, height}));
134 
135   while (gimp_chunk_iterator_next (iter))
136     {
137       GeglRectangle rect;
138 
139       while (gimp_chunk_iterator_get_rect (iter, &rect))
140         gimp_applicator_blit (applicator, &rect);
141     }
142 
143   g_object_unref (applicator);
144 }
145