blob: 502f4b88e3ae4a3948bfe2af1eb62dde164f6902 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050023#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050027#include <math.h>
28#include <cairo.h>
29#include "cairo-util.h"
30
Kristian Høgsberg27d38662011-10-20 13:11:12 -040031#include <jpeglib.h>
32
Kristian Høgsberg87330262008-11-17 22:23:55 -050033#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
34
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050035void
Benjamin Franzke47eb8f42011-10-07 09:08:56 +020036surface_flush_device(cairo_surface_t *surface)
37{
38 cairo_device_t *device;
39
40 device = cairo_surface_get_device(surface);
41 if (device)
42 cairo_device_flush(device);
43}
44
45void
Kristian Høgsberg10bdd292008-11-08 23:27:27 -050046blur_surface(cairo_surface_t *surface, int margin)
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050047{
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050048 int32_t width, height, stride, x, y, z, w;
49 uint8_t *src, *dst;
50 uint32_t *s, *d, a, p;
Kristian Høgsberg87330262008-11-17 22:23:55 -050051 int i, j, k, size, half;
Kristian Høgsberg49e868c2010-06-15 16:18:58 -040052 uint32_t kernel[49];
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050053 double f;
54
Kristian Høgsberg87330262008-11-17 22:23:55 -050055 size = ARRAY_LENGTH(kernel);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050056 width = cairo_image_surface_get_width(surface);
57 height = cairo_image_surface_get_height(surface);
58 stride = cairo_image_surface_get_stride(surface);
59 src = cairo_image_surface_get_data(surface);
60
Kristian Høgsberg5fc96ff2009-09-12 15:58:48 -040061 dst = malloc(height * stride);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050062
63 half = size / 2;
Kristian Høgsberg0cd8f6e2011-01-21 22:19:40 -050064 a = 0;
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050065 for (i = 0; i < size; i++) {
66 f = (i - half);
Kristian Høgsberg49e868c2010-06-15 16:18:58 -040067 kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000;
Kristian Høgsberg0cd8f6e2011-01-21 22:19:40 -050068 a += kernel[i];
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050069 }
70
71 for (i = 0; i < height; i++) {
72 s = (uint32_t *) (src + i * stride);
73 d = (uint32_t *) (dst + i * stride);
74 for (j = 0; j < width; j++) {
Kristian Høgsberg87330262008-11-17 22:23:55 -050075 if (margin < j && j < width - margin) {
76 d[j] = s[j];
Kristian Høgsberg10bdd292008-11-08 23:27:27 -050077 continue;
Kristian Høgsberg87330262008-11-17 22:23:55 -050078 }
79
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -050080 x = 0;
81 y = 0;
82 z = 0;
83 w = 0;
84 for (k = 0; k < size; k++) {
85 if (j - half + k < 0 || j - half + k >= width)
86 continue;
87 p = s[j - half + k];
88
89 x += (p >> 24) * kernel[k];
90 y += ((p >> 16) & 0xff) * kernel[k];
91 z += ((p >> 8) & 0xff) * kernel[k];
92 w += (p & 0xff) * kernel[k];
93 }
94 d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
95 }
96 }
97
98 for (i = 0; i < height; i++) {
99 s = (uint32_t *) (dst + i * stride);
100 d = (uint32_t *) (src + i * stride);
101 for (j = 0; j < width; j++) {
Kristian Høgsberg87330262008-11-17 22:23:55 -0500102 if (margin <= i && i < height - margin) {
103 d[j] = s[j];
Kristian Høgsberg10bdd292008-11-08 23:27:27 -0500104 continue;
Kristian Høgsberg87330262008-11-17 22:23:55 -0500105 }
106
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500107 x = 0;
108 y = 0;
109 z = 0;
110 w = 0;
111 for (k = 0; k < size; k++) {
112 if (i - half + k < 0 || i - half + k >= height)
113 continue;
114 s = (uint32_t *) (dst + (i - half + k) * stride);
115 p = s[j];
116
117 x += (p >> 24) * kernel[k];
118 y += ((p >> 16) & 0xff) * kernel[k];
119 z += ((p >> 8) & 0xff) * kernel[k];
120 w += (p & 0xff) * kernel[k];
121 }
122 d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
123 }
124 }
125
Kristian Høgsberg5fc96ff2009-09-12 15:58:48 -0400126 free(dst);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400127 cairo_surface_mark_dirty(surface);
128}
129
130void
131tile_mask(cairo_t *cr, cairo_surface_t *surface,
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400132 int x, int y, int width, int height, int margin, int top_margin)
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400133{
134 cairo_pattern_t *pattern;
135 cairo_matrix_t matrix;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400136 int i, fx, fy, vmargin;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400137
138 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
139 pattern = cairo_pattern_create_for_surface (surface);
140
141 for (i = 0; i < 4; i++) {
142 fx = i & 1;
143 fy = i >> 1;
144
145 cairo_matrix_init_translate(&matrix,
146 -x + fx * (128 - width),
147 -y + fy * (128 - height));
148 cairo_pattern_set_matrix(pattern, &matrix);
149
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400150 if (fy)
151 vmargin = margin;
152 else
153 vmargin = top_margin;
154
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400155 cairo_reset_clip(cr);
156 cairo_rectangle(cr,
157 x + fx * (width - margin),
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400158 y + fy * (height - vmargin),
159 margin, vmargin);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400160 cairo_clip (cr);
161 cairo_mask(cr, pattern);
162 }
163
164 /* Top strecth */
165 cairo_matrix_init_translate(&matrix, 64, 0);
166 cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
167 cairo_matrix_translate(&matrix, -x - width / 2, -y);
168 cairo_pattern_set_matrix(pattern, &matrix);
169 cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
170
171 cairo_reset_clip(cr);
172 cairo_rectangle(cr,
173 x + margin,
174 y,
175 width - 2 * margin, margin);
176 cairo_clip (cr);
177 cairo_mask(cr, pattern);
178
179 /* Bottom strecth */
180 cairo_matrix_translate(&matrix, 0, -height + 128);
181 cairo_pattern_set_matrix(pattern, &matrix);
182
183 cairo_reset_clip(cr);
184 cairo_rectangle(cr, x + margin, y + height - margin,
185 width - 2 * margin, margin);
186 cairo_clip (cr);
187 cairo_mask(cr, pattern);
188
189 /* Left strecth */
190 cairo_matrix_init_translate(&matrix, 0, 64);
191 cairo_matrix_scale(&matrix, 1, 64.0 / (height - 2 * margin));
192 cairo_matrix_translate(&matrix, -x, -y - height / 2);
193 cairo_pattern_set_matrix(pattern, &matrix);
194 cairo_reset_clip(cr);
195 cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
196 cairo_clip (cr);
197 cairo_mask(cr, pattern);
198
199 /* Right strecth */
200 cairo_matrix_translate(&matrix, -width + 128, 0);
201 cairo_pattern_set_matrix(pattern, &matrix);
202 cairo_rectangle(cr, x + width - margin, y + margin,
203 margin, height - 2 * margin);
204 cairo_reset_clip(cr);
205 cairo_clip (cr);
206 cairo_mask(cr, pattern);
207
208 cairo_pattern_destroy(pattern);
209 cairo_reset_clip(cr);
210}
211
212void
213tile_source(cairo_t *cr, cairo_surface_t *surface,
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400214 int x, int y, int width, int height, int margin, int top_margin)
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400215{
216 cairo_pattern_t *pattern;
217 cairo_matrix_t matrix;
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400218 int i, fx, fy, vmargin;
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400219
220 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
221 pattern = cairo_pattern_create_for_surface (surface);
222 cairo_set_source(cr, pattern);
223 cairo_pattern_destroy(pattern);
224
225 for (i = 0; i < 4; i++) {
226 fx = i & 1;
227 fy = i >> 1;
228
229 cairo_matrix_init_translate(&matrix,
230 -x + fx * (128 - width),
231 -y + fy * (128 - height));
232 cairo_pattern_set_matrix(pattern, &matrix);
233
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400234 if (fy)
235 vmargin = margin;
236 else
237 vmargin = top_margin;
238
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400239 cairo_rectangle(cr,
240 x + fx * (width - margin),
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400241 y + fy * (height - vmargin),
242 margin, vmargin);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400243 cairo_fill(cr);
244 }
245
246 /* Top strecth */
247 cairo_matrix_init_translate(&matrix, 64, 0);
248 cairo_matrix_scale(&matrix, 64.0 / (width - 2 * margin), 1);
249 cairo_matrix_translate(&matrix, -x - width / 2, -y);
250 cairo_pattern_set_matrix(pattern, &matrix);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400251 cairo_rectangle(cr, x + margin, y, width - 2 * margin, top_margin);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400252 cairo_fill(cr);
253
254 /* Bottom strecth */
255 cairo_matrix_translate(&matrix, 0, -height + 128);
256 cairo_pattern_set_matrix(pattern, &matrix);
257 cairo_rectangle(cr, x + margin, y + height - margin,
258 width - 2 * margin, margin);
259 cairo_fill(cr);
260
261 /* Left strecth */
262 cairo_matrix_init_translate(&matrix, 0, 64);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400263 cairo_matrix_scale(&matrix, 1, 64.0 / (height - margin - top_margin));
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400264 cairo_matrix_translate(&matrix, -x, -y - height / 2);
265 cairo_pattern_set_matrix(pattern, &matrix);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400266 cairo_rectangle(cr, x, y + top_margin,
267 margin, height - margin - top_margin);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400268 cairo_fill(cr);
269
270 /* Right strecth */
271 cairo_matrix_translate(&matrix, -width + 128, 0);
272 cairo_pattern_set_matrix(pattern, &matrix);
Kristian Høgsberg9a686242010-08-18 15:28:04 -0400273 cairo_rectangle(cr, x + width - margin, y + top_margin,
274 margin, height - margin - top_margin);
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400275 cairo_fill(cr);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500276}
Kristian Høgsberg1e164b92011-09-13 14:47:46 -0400277
278void
279rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
280{
281 cairo_move_to(cr, x0, y0 + radius);
282 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
283 cairo_line_to(cr, x1 - radius, y0);
284 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
285 cairo_line_to(cr, x1, y1 - radius);
286 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
287 cairo_line_to(cr, x0 + radius, y1);
288 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
289 cairo_close_path(cr);
290}
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400291
292cairo_surface_t *
293load_jpeg(const char *filename)
294{
295 struct jpeg_decompress_struct cinfo;
296 struct jpeg_error_mgr jerr;
297 FILE *fp;
298 int stride, i;
299 JSAMPLE *data, *rows[4];
300
301 cinfo.err = jpeg_std_error(&jerr);
302 jpeg_create_decompress(&cinfo);
303
304 fp = fopen(filename, "rb");
305 if (fp == NULL) {
306 fprintf(stderr, "can't open %s\n", filename);
307 return NULL;
308 }
309 jpeg_stdio_src(&cinfo, fp);
310
311 jpeg_read_header(&cinfo, TRUE);
312
313 cinfo.out_color_space = JCS_EXT_BGRX;
314 jpeg_start_decompress(&cinfo);
315
316 stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
317 cinfo.output_width);
318 data = malloc(stride * cinfo.output_height);
319 if (data == NULL) {
320 fprintf(stderr, "couldn't allocate image data\n");
321 return NULL;
322 }
323
324 while (cinfo.output_scanline < cinfo.output_height) {
325 for (i = 0; i < ARRAY_LENGTH(rows); i++, p += stride)
326 rows[i] = data + (cinfo.output_scanline + i) * stride;
327
328 jpeg_read_scanlines(&cinfo, rows, ARRAY_LENGTH(rows));
329 }
330
331 jpeg_finish_decompress(&cinfo);
332
333 fclose(fp);
334
335 jpeg_destroy_decompress(&cinfo);
336
337 return cairo_image_surface_create_for_data (data,
338 CAIRO_FORMAT_RGB24,
339 cinfo.output_width,
340 cinfo.output_height,
341 stride);
342}