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 <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpbase/gimpbase.h"
24 #include "libgimpcolor/gimpcolor.h"
25 #include "libgimpmath/gimpmath.h"
26 #include "libgimpwidgets/gimpwidgets.h"
27
28 #include "display-types.h"
29
30 #include "core/gimp-cairo.h"
31 #include "core/gimp-utils.h"
32 #include "core/gimpimage.h"
33
34 #include "gimpcanvas.h"
35 #include "gimpcanvas-style.h"
36 #include "gimpcanvaspath.h"
37 #include "gimpdisplay.h"
38 #include "gimpdisplayshell.h"
39 #include "gimpdisplayshell-draw.h"
40 #include "gimpdisplayshell-render.h"
41 #include "gimpdisplayshell-scale.h"
42 #include "gimpdisplayshell-transform.h"
43 #include "gimpdisplayxfer.h"
44
45 #ifdef GDK_WINDOWING_QUARTZ
46 #import <AppKit/AppKit.h>
47 #endif
48
49 /* #define GIMP_DISPLAY_RENDER_ENABLE_SCALING 1 */
50
51
52 /* public functions */
53
54 void
gimp_display_shell_draw_selection_out(GimpDisplayShell * shell,cairo_t * cr,GimpSegment * segs,gint n_segs)55 gimp_display_shell_draw_selection_out (GimpDisplayShell *shell,
56 cairo_t *cr,
57 GimpSegment *segs,
58 gint n_segs)
59 {
60 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
61 g_return_if_fail (cr != NULL);
62 g_return_if_fail (segs != NULL && n_segs > 0);
63
64 gimp_canvas_set_selection_out_style (shell->canvas, cr,
65 shell->offset_x, shell->offset_y);
66
67 gimp_cairo_segments (cr, segs, n_segs);
68 cairo_stroke (cr);
69 }
70
71 void
gimp_display_shell_draw_selection_in(GimpDisplayShell * shell,cairo_t * cr,cairo_pattern_t * mask,gint index)72 gimp_display_shell_draw_selection_in (GimpDisplayShell *shell,
73 cairo_t *cr,
74 cairo_pattern_t *mask,
75 gint index)
76 {
77 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
78 g_return_if_fail (cr != NULL);
79 g_return_if_fail (mask != NULL);
80
81 gimp_canvas_set_selection_in_style (shell->canvas, cr, index,
82 shell->offset_x, shell->offset_y);
83
84 cairo_mask (cr, mask);
85 }
86
87 void
gimp_display_shell_draw_checkerboard(GimpDisplayShell * shell,cairo_t * cr)88 gimp_display_shell_draw_checkerboard (GimpDisplayShell *shell,
89 cairo_t *cr)
90 {
91 GimpImage *image;
92
93 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
94 g_return_if_fail (cr != NULL);
95
96 image = gimp_display_get_image (shell->display);
97
98 if (G_UNLIKELY (! shell->checkerboard))
99 {
100 GimpCheckSize check_size;
101 GimpCheckType check_type;
102 guchar check_light;
103 guchar check_dark;
104 GimpRGB light;
105 GimpRGB dark;
106
107 g_object_get (shell->display->config,
108 "transparency-size", &check_size,
109 "transparency-type", &check_type,
110 NULL);
111
112 gimp_checks_get_shades (check_type, &check_light, &check_dark);
113 gimp_rgb_set_uchar (&light, check_light, check_light, check_light);
114 gimp_rgb_set_uchar (&dark, check_dark, check_dark, check_dark);
115
116 shell->checkerboard =
117 gimp_cairo_checkerboard_create (cr,
118 1 << (check_size + 2), &light, &dark);
119 }
120
121 cairo_translate (cr, - shell->offset_x, - shell->offset_y);
122
123 if (gimp_image_get_component_visible (image, GIMP_CHANNEL_ALPHA))
124 cairo_set_source (cr, shell->checkerboard);
125 else
126 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
127
128 cairo_paint (cr);
129 }
130
131 void
gimp_display_shell_draw_image(GimpDisplayShell * shell,cairo_t * cr,gint x,gint y,gint w,gint h)132 gimp_display_shell_draw_image (GimpDisplayShell *shell,
133 cairo_t *cr,
134 gint x,
135 gint y,
136 gint w,
137 gint h)
138 {
139 gdouble chunk_width;
140 gdouble chunk_height;
141 gdouble scale = 1.0;
142 gint n_rows;
143 gint n_cols;
144 gint r, c;
145
146 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
147 g_return_if_fail (gimp_display_get_image (shell->display));
148 g_return_if_fail (cr != NULL);
149
150 /* display the image in RENDER_BUF_WIDTH x RENDER_BUF_HEIGHT
151 * maximally-sized image-space chunks. adjust the screen-space
152 * chunk size as necessary, to accommodate for the display
153 * transform and window scale factor.
154 */
155 chunk_width = GIMP_DISPLAY_RENDER_BUF_WIDTH;
156 chunk_height = GIMP_DISPLAY_RENDER_BUF_HEIGHT;
157
158 #ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
159 /* if we had this future API, things would look pretty on hires (retina) */
160 scale *=
161 gdk_window_get_scale_factor (
162 gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
163 #elif defined(GDK_WINDOWING_QUARTZ)
164 /* gtk2/osx retina support */
165 if ([
166 [NSScreen mainScreen]
167 respondsToSelector: @selector(backingScaleFactor)
168 ]) {
169 for (NSScreen * screen in [NSScreen screens]) {
170 float s = [screen backingScaleFactor];
171 if (s > scale) scale = s;
172 }
173 }
174 #endif
175
176 scale = MIN (scale, GIMP_DISPLAY_RENDER_MAX_SCALE);
177 scale *= MAX (shell->scale_x, shell->scale_y);
178
179 if (scale != shell->scale_x)
180 chunk_width = (chunk_width - 1.0) * (shell->scale_x / scale);
181 if (scale != shell->scale_y)
182 chunk_height = (chunk_height - 1.0) * (shell->scale_y / scale);
183
184 if (shell->rotate_untransform)
185 {
186 gdouble a = shell->rotate_angle * G_PI / 180.0;
187
188 chunk_width = chunk_height = (MIN (chunk_width, chunk_height) - 1.0) /
189 (fabs (sin (a)) + fabs (cos (a)));
190 }
191
192 /* divide the painted area to evenly-sized chunks */
193 n_rows = ceil (h / floor (chunk_height));
194 n_cols = ceil (w / floor (chunk_width));
195
196 for (r = 0; r < n_rows; r++)
197 {
198 gint y1 = y + (2 * r * h + n_rows) / (2 * n_rows);
199 gint y2 = y + (2 * (r + 1) * h + n_rows) / (2 * n_rows);
200
201 for (c = 0; c < n_cols; c++)
202 {
203 gint x1 = x + (2 * c * w + n_cols) / (2 * n_cols);
204 gint x2 = x + (2 * (c + 1) * w + n_cols) / (2 * n_cols);
205 gdouble ix1, iy1;
206 gdouble ix2, iy2;
207 gint ix, iy;
208 gint iw, ih;
209
210 /* map chunk from screen space to scaled image space */
211 gimp_display_shell_untransform_bounds_with_scale (
212 shell, scale,
213 x1, y1, x2, y2,
214 &ix1, &iy1, &ix2, &iy2);
215
216 ix = floor (ix1);
217 iy = floor (iy1);
218 iw = ceil (ix2) - ix;
219 ih = ceil (iy2) - iy;
220
221 cairo_save (cr);
222
223 /* clip to chunk bounds, in screen space */
224 cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
225 cairo_clip (cr);
226
227 /* transform to scaled image space, and apply uneven scaling */
228 if (shell->rotate_transform)
229 cairo_transform (cr, shell->rotate_transform);
230 cairo_translate (cr, -shell->offset_x, -shell->offset_y);
231 cairo_scale (cr, shell->scale_x / scale, shell->scale_y / scale);
232
233 /* render image */
234 gimp_display_shell_render (shell, cr, ix, iy, iw, ih, scale);
235
236 cairo_restore (cr);
237
238 /* if the GIMP_BRICK_WALL environment variable is defined,
239 * show chunk bounds
240 */
241 {
242 static gint brick_wall = -1;
243
244 if (brick_wall < 0)
245 brick_wall = (g_getenv ("GIMP_BRICK_WALL") != NULL);
246
247 if (brick_wall)
248 {
249 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
250 cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
251 cairo_stroke (cr);
252 }
253 }
254 }
255 }
256 }
257