1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright � 2013 Samsung Research America - Silicon Valley
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Mozilla Foundation.
34 * Henry Song <henry.song@samsung.com>
37 #define _GNU_SOURCE /* required for RTLD_DEFAULT */
39 #include "cairo-pattern-private.h"
40 #include "cairo-quartz-private.h"
41 #include "cairo-quartz.h"
42 #include <Accelerate/Accelerate.h>
44 #define CAIRO_QUARTZ_MAX_SCALE 4
47 _cairo_quartz_pattern_create_gaussian_matrix (const cairo_pattern_t *pattern,
50 int *shrink_x, int *shrink_y)
52 double x_sigma, y_sigma;
53 double x_sigma_sq, y_sigma_sq;
60 int x_radius, y_radius;
62 int x_factor, y_factor;
63 cairo_rectangle_int_t extents;
68 max_factor = CAIRO_QUARTZ_MAX_SCALE;;
69 max_sigma = CAIRO_MAX_SIGMA;
71 width = CAIRO_MIN_SHRINK_SIZE;
72 height = CAIRO_MIN_SHRINK_SIZE;
74 if (_cairo_surface_get_extents (((cairo_surface_pattern_t *)pattern)->surface, &extents)) {
75 width = extents.width;
76 height = extents.height;
79 x_factor = y_factor = 1;
80 x_sigma = pattern->x_sigma;
81 y_sigma = pattern->y_sigma;
84 if (x_sigma == 0.0 && y_sigma == 0.0) {
91 while (x_sigma >= max_sigma) {
92 if (width <= CAIRO_MIN_SHRINK_SIZE || x_factor >= max_factor)
104 while (y_sigma >= max_sigma) {
105 if (height <= CAIRO_MIN_SHRINK_SIZE || y_factor >= max_factor)
115 * f(x, y) = exp (-((x-x0)^2/(2*x_sigma^2)+(y-y0)^2/(2*y_sigma*2)))
117 x_radius = x_sigma * 2;
118 y_radius = y_sigma * 2;
122 n = (2 * i_row + 1) * (2 * i_col + 1);
124 x_sigma_sq = 2 * x_sigma * x_sigma;
125 y_sigma_sq = 2 * y_sigma * y_sigma;
127 buffer = _cairo_malloc_ab (n, sizeof (double));
130 i_buffer = _cairo_malloc_ab (n, sizeof (i_buffer));
138 for (y = -i_row; y <= i_row; y++) {
139 for (x = -i_col; x <= i_col; x++) {
151 buffer[i] = exp (-(u1 + v1));
152 i_buffer[i] = ceil (buffer[i] - 0.5);
160 *row = i_row * 2 + 1;
161 *col = i_col * 2 + 1;
162 *shrink_x = x_factor;
163 *shrink_y = y_factor;
168 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
170 _cairo_quartz_get_image_context (CGImageRef image)
174 CGContextRef context;
175 CGColorSpaceRef color_space;
176 CGBitmapInfo bitmap_info;
184 width = CGImageGetWidth (image);
185 height = CGImageGetHeight (image);
186 bytes_per_row = CGImageGetBytesPerRow (image);
188 color_space = CGImageGetColorSpace (image);
189 buffer = malloc (sizeof (char) * bytes_per_row * height);
193 bitmap_info = CGImageGetBitmapInfo (image);
195 /* create output image bitmap context */
196 context = CGBitmapContextCreate (buffer, width, height,
197 CGImageGetBitsPerComponent (image),
207 size = CGRectMake (0, 0, width, height);
209 CGContextDrawImage (context, size, image);
215 static cairo_int_status_t
216 _cairo_quartz_resize_image (CGImageRef src, double x_resize_factor,
217 double y_resize_factor, CGImageRef *out)
222 CGContextRef out_bitmap_context;
223 CGColorSpaceRef color_space;
224 CGBitmapInfo bitmap_info;
230 return CAIRO_INT_STATUS_UNSUPPORTED;
232 if (x_resize_factor <= 0.0 ||
233 y_resize_factor <= 0.0)
234 return CAIRO_INT_STATUS_UNSUPPORTED;
236 width = CGImageGetWidth (src) * x_resize_factor;
237 height = CGImageGetHeight (src) * y_resize_factor;
238 bytes_per_pixel = CGImageGetBytesPerRow (src) / CGImageGetWidth (src);
240 color_space = CGImageGetColorSpace (src);
241 bytes_per_row = bytes_per_pixel * width;
242 buffer = malloc (sizeof (char) * bytes_per_row * height);
244 return CAIRO_INT_STATUS_NO_MEMORY;
246 bitmap_info = CGImageGetBitmapInfo (src);
248 /* create output image bitmap context */
249 out_bitmap_context = CGBitmapContextCreate (buffer, width, height,
250 CGImageGetBitsPerComponent (src),
255 size = CGRectMake (0, 0, width, height);
257 CGContextDrawImage (out_bitmap_context, size, src);
259 *out = CGBitmapContextCreateImage (out_bitmap_context);
262 CGContextRelease (out_bitmap_context);
265 return CAIRO_INT_STATUS_SUCCESS;
268 static cairo_int_status_t
269 _cairo_quartz_convolve_pass (vImage_Buffer *src,
270 const int16_t *kernel,
271 int kernel_width, int kernel_height,
272 const int32_t divisor,
273 unsigned char *edge_fill,
278 dst->data = malloc (src->rowBytes * src->height);
280 return CAIRO_INT_STATUS_NO_MEMORY;
282 dst->width = src->width;
283 dst->height = src->height;
284 dst->rowBytes = src->rowBytes;
286 /* we always use background color beyond edge */
287 error = vImageConvolve_ARGB8888 (src, dst, NULL, /* no temp buffer */
289 kernel, kernel_width, kernel_height,
294 if (error != kvImageNoError)
295 return CAIRO_INT_STATUS_UNSUPPORTED;
297 return CAIRO_INT_STATUS_SUCCESS;
301 _cairo_quartz_gaussian_filter (const cairo_pattern_t *src,
302 const CGImageRef image,
303 CGImageRef *out_image)
305 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
307 vImage_Buffer src_buffer, dst_buffer;
308 int16_t *kernel = NULL;
313 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
314 CGContextRef image_ctx;
316 CGDataProviderRef image_provider;
317 CFDataRef image_data_ref;
319 CGImageRef resized_image;
320 CGImageRef resized_out_image;
323 CGColorSpaceRef color_space;
324 CGBitmapInfo bitmap_info;
327 unsigned char edge_color[4] = {0, 0, 0, 0};
329 if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
330 ! src->convolution_matrix) {
331 *out_image = CGImageRetain (image);
332 return CAIRO_INT_STATUS_SUCCESS;
335 /* re-compute scaling */
336 kernel = _cairo_quartz_pattern_create_gaussian_matrix ((cairo_pattern_t *)src,
343 return CAIRO_INT_STATUS_NO_MEMORY;
346 if (shrink_factor_x == 1 &&
347 shrink_factor_y == 1)
348 resized_image = CGImageRetain (image);
350 status = _cairo_quartz_resize_image (image,
351 1.0 / src->shrink_factor_x,
352 1.0 / src->shrink_factor_y,
354 if (unlikely (status)) {
361 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
362 image_ctx = _cairo_quartz_get_image_context (resized_image);
366 return CAIRO_INT_STATUS_NO_MEMORY;
369 image_provider = CGImageGetDataProvider (resized_image);
370 image_data_ref = CGDataProviderCopyData (image_provider);
373 src_buffer.width = CGImageGetWidth (resized_image);
374 src_buffer.height = CGImageGetHeight (resized_image);
375 src_buffer.rowBytes = CGImageGetBytesPerRow (resized_image);
377 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
378 src_buffer.data = CGBitmapContextGetData (image_ctx);
379 if (! src_buffer.data) {
381 CGContextRelease (image_ctx);
383 return CAIRO_INT_STATUS_NO_MEMORY;
386 src_buffer.data = (void *) CFDataGetBytePtr (image_data_ref);
389 dst_buffer.data = NULL;
391 status = _cairo_quartz_convolve_pass (&src_buffer,
398 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
399 CGContextRelease (image_ctx);
400 free (src_buffer.data);
402 CFRelease (image_data_ref);
406 CGImageRelease (resized_image);
408 if (unlikely (status)) {
410 free (dst_buffer.data);
415 /* create resized_out_image from blur */
416 color_space = CGImageGetColorSpace (resized_image);
417 bitmap_info = CGImageGetBitmapInfo (resized_image);
419 ctx = CGBitmapContextCreate (dst_buffer.data,
422 CGImageGetBitsPerComponent (resized_image),
427 resized_out_image = CGBitmapContextCreateImage (ctx);
429 CGContextRelease (ctx);
430 free (dst_buffer.data);
432 /* scale back from resized_out_image to out_image */
433 if (shrink_factor_x == 1 &&
434 shrink_factor_y == 1) {
435 *out_image = resized_out_image;
436 return CAIRO_INT_STATUS_SUCCESS;
439 status = _cairo_quartz_resize_image (resized_out_image,
440 src->shrink_factor_x,
441 src->shrink_factor_y,
443 if (unlikely (status)) {
444 CGImageRelease (resized_out_image);
448 CGImageRelease (resized_out_image);