1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2005 Red Hat, Inc
4 * Copyright © 2007 Adrian Johnson
5 * Copyright © 2009 Chris Wilson
6 * Copyright © 2013 Samsung Research America, Silicon Valley
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is Red Hat, Inc.
36 * Henry Song <henry.song@samsung.com
40 #include "cairo-surface-private.h"
41 #include "cairo-clip-inline.h"
42 #include "cairo-error-private.h"
43 #include "cairo-pattern-private.h"
44 #include "cairo-surface-shadow-private.h"
45 #include "cairo-surface-scale-translate-private.h"
46 #include "cairo-path-fixed-private.h"
47 #include "cairo-list-inline.h"
48 #include "cairo-device-private.h"
49 #include "cairo-image-surface-private.h"
51 #define MAX_SHADOW_SIZE 1024
53 typedef struct _cairo_shadow_cache_list {
57 } cairo_shadow_cache_list_t;
60 _cairo_stroke_style_hash (unsigned long hash,
61 const cairo_stroke_style_t *style)
63 hash = _cairo_hash_bytes (hash, style, sizeof (cairo_stroke_style_t));
64 if (style->num_dashes)
65 hash = _cairo_hash_bytes (hash, style->dash, sizeof (double) * style->num_dashes);
70 _cairo_matrix_hash (unsigned long hash, const cairo_matrix_t *matrix)
72 return _cairo_hash_bytes (hash, matrix, sizeof (cairo_matrix_t));
76 _cairo_path_fixed_rel_hash (unsigned long hash, const cairo_path_fixed_t *path)
78 const cairo_path_buf_t *buf;
80 cairo_path_fixed_t path_copy;
81 cairo_status_t status;
85 status = _cairo_path_fixed_init_copy (&path_copy, path);
86 if (unlikely (status))
89 dx = path_copy.buf.points[0].x;
90 dy = path_copy.buf.points[0].y;
92 cairo_path_foreach_buf_start (buf, &path_copy) {
93 for (i = 0; i < buf->num_points; i++) {
94 buf->points[i].x -= dx;
95 buf->points[i].y -= dy;
97 } cairo_path_foreach_buf_end (buf, &path_copy);
100 cairo_path_foreach_buf_start (buf, &path_copy) {
101 hash = _cairo_hash_bytes (hash, buf->op,
102 buf->num_ops * sizeof (buf->op[0]));
103 count += buf->num_ops;
104 } cairo_path_foreach_buf_end (buf, &path_copy);
105 hash = _cairo_hash_bytes (hash, &count, sizeof (count));
108 cairo_path_foreach_buf_start (buf, &path_copy) {
109 hash = _cairo_hash_bytes (hash, buf->points,
110 buf->num_points * sizeof (buf->points[0]));
111 count += buf->num_points;
112 } cairo_path_foreach_buf_end (buf, &path_copy);
113 hash = _cairo_hash_bytes (hash, &count, sizeof (count));
115 _cairo_path_fixed_fini (&path_copy);
121 _cairo_shadow_hash (unsigned long hash, const cairo_shadow_t *shadow)
123 return _cairo_hash_bytes (hash, shadow, sizeof (cairo_shadow_t) - sizeof (cairo_bool_t));
127 _cairo_shadow_hash_for_paint (const cairo_pattern_t *source,
128 const cairo_shadow_t *shadow)
130 unsigned long hash = _CAIRO_HASH_INIT_VALUE;
131 cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
133 hash = _cairo_pattern_hash_with_hash (hash, source, use_color);
134 return _cairo_shadow_hash (hash, shadow);
138 _cairo_shadow_hash_for_mask (const cairo_pattern_t *source,
139 const cairo_pattern_t *mask,
140 const cairo_shadow_t *shadow)
142 unsigned long hash = _CAIRO_HASH_INIT_VALUE;
143 cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
145 hash = _cairo_pattern_hash_with_hash (hash, source, use_color);
146 hash = _cairo_pattern_hash_with_hash (hash, mask, use_color);
147 return _cairo_shadow_hash (hash, shadow);
151 _cairo_shadow_hash_for_fill (const cairo_pattern_t *source,
152 const cairo_path_fixed_t *path,
153 cairo_fill_rule_t fill_rule,
154 const cairo_shadow_t *shadow)
156 unsigned long hash = _CAIRO_HASH_INIT_VALUE;
157 /* FIXME: for OVER operator, we don't need to hash the source
158 * color, for other operators, we might */
159 cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
162 hash = _cairo_pattern_hash_with_hash (hash, source, use_color);
163 hash = _cairo_path_fixed_rel_hash (hash, path);
164 hash = _cairo_hash_bytes (hash, &fill_rule, sizeof (cairo_fill_rule_t));
165 return _cairo_shadow_hash (hash, shadow);
169 _cairo_shadow_hash_for_stroke (const cairo_pattern_t *source,
170 const cairo_path_fixed_t *path,
171 const cairo_stroke_style_t*stroke_style,
172 const cairo_matrix_t *ctm,
173 const cairo_shadow_t *shadow)
175 unsigned long hash = _CAIRO_HASH_INIT_VALUE;
177 /* FIXME: for OVER operator, we don't need to hash the source
178 * color, for other operators, we might */
179 cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
182 hash = _cairo_pattern_hash_with_hash (hash, source, use_color);
183 hash = _cairo_path_fixed_rel_hash (hash, path);
184 hash = _cairo_stroke_style_hash (hash, stroke_style);
185 hash = _cairo_matrix_hash (hash, ctm);
186 return _cairo_shadow_hash (hash, shadow);
190 _cairo_shadow_cache_init (cairo_shadow_cache_t *shadow_cache,
191 cairo_surface_t *cache_surface,
198 cairo_list_init (&shadow_cache->link);
199 shadow_cache->surface = cairo_surface_reference (cache_surface);
200 shadow_cache->size = size;
201 shadow_cache->hash = hash;
202 shadow_cache->x_blur = x_blur;
203 shadow_cache->y_blur = y_blur;
204 shadow_cache->scale = scale;
208 _cairo_shadow_cache_destroy (cairo_shadow_cache_t *shadow_cache)
210 cairo_list_del (&shadow_cache->link);
211 cairo_surface_destroy (shadow_cache->surface);
216 _cairo_shadow_cache_list_shrink_to_accomodate (cairo_shadow_cache_list_t *shadow_caches,
217 unsigned long additional)
219 cairo_shadow_cache_t *shadow_cache;
221 while (*(shadow_caches->size) + additional > MAX_SHADOW_CACHE_SIZE) {
222 shadow_cache = cairo_list_last_entry (shadow_caches->caches,
223 cairo_shadow_cache_t,
225 *(shadow_caches->size) -= shadow_cache->size;
226 _cairo_shadow_cache_destroy (shadow_cache);
230 static cairo_shadow_cache_t *
231 _cairo_shadow_cache_list_find (cairo_shadow_cache_list_t *shadow_caches,
234 cairo_shadow_cache_t *shadow_cache;
236 cairo_list_foreach_entry (shadow_cache,
237 cairo_shadow_cache_t,
238 shadow_caches->caches, link)
239 if (shadow_cache->hash == hash) {
247 _calculate_shadow_extents_scale (cairo_rectangle_int_t *extents,
248 int shadow_width, int shadow_height)
250 double x_scale = (double)extents->width / (double)shadow_width;
251 double y_scale = (double)extents->height / (double)shadow_height;
253 return MIN (1.0, MIN (x_scale, y_scale));
257 _cairo_shadow_cache_list_init (cairo_shadow_cache_list_t *shadow_cache_list,
258 cairo_surface_t *target)
260 cairo_status_t status;
261 cairo_device_t *device = NULL;
264 device = target->device;
266 if (device != NULL) {
267 shadow_cache_list->caches = &device->shadow_caches;
268 shadow_cache_list->size = &device->shadow_caches_size;
269 shadow_cache_list->locked = FALSE;
271 else if (target != NULL &&
273 target->backend->has_shadow_cache &&
274 target->backend->has_shadow_cache (target)) {
275 status = target->backend->shadow_cache_acquire (target);
276 shadow_cache_list->locked = TRUE;
278 if (status == CAIRO_STATUS_SUCCESS) {
279 shadow_cache_list->caches = target->backend->get_shadow_cache (target);
280 if (shadow_cache_list->caches) {
281 shadow_cache_list->size = target->backend->get_shadow_cache_size (target);
287 static cairo_surface_t*
288 _cairo_ensure_shadow_surface (cairo_surface_t *target,
289 cairo_rectangle_int_t *shadow_surface_extents,
290 int x_blur, int y_blur,
291 int shadow_width, int shadow_height)
293 int width_out, height_out;
294 cairo_content_t content;
295 cairo_surface_t *shadow_surface;
296 cairo_bool_t has_blur = ! (x_blur == 0 && y_blur == 0);
298 if (target->backend->get_shadow_surface)
299 shadow_surface = target->backend->get_shadow_surface (target,
307 width_out = MIN (shadow_width, MAX_SHADOW_SIZE) * 0.5;
308 height_out = MIN (shadow_width, MAX_SHADOW_SIZE) * 0.5;
311 width_out = MIN (shadow_width, MAX_SHADOW_SIZE);
312 height_out = MIN (shadow_width, MAX_SHADOW_SIZE);
315 content = cairo_surface_get_content (target);
316 if (content == CAIRO_CONTENT_COLOR)
317 content = CAIRO_CONTENT_COLOR_ALPHA;
318 shadow_surface = cairo_surface_create_similar (target,
322 _cairo_surface_release_device_reference (shadow_surface);
325 shadow_surface_extents->x = 0;
326 shadow_surface_extents->y = 0;
327 shadow_surface_extents->width = width_out;
328 shadow_surface_extents->height = height_out;
330 return shadow_surface;
333 /* A collection of routines to draw shadow*/
336 _cairo_surface_shadow_paint (cairo_surface_t *target,
338 const cairo_pattern_t *source,
339 const cairo_clip_t *clip,
340 const cairo_shadow_t *shadow)
342 cairo_status_t status;
343 cairo_pattern_union_t shadow_source;
344 cairo_rectangle_t shadow_extents;
345 cairo_pattern_t *shadow_pattern = NULL;
346 cairo_pattern_t *color_pattern = NULL;
347 cairo_surface_t *shadow_surface = NULL;
348 cairo_rectangle_int_t shadow_surface_extents;
350 int shadow_width, shadow_height;
352 cairo_shadow_t shadow_copy = *shadow;
356 double x_offset = shadow->x_offset;
357 double y_offset = shadow->y_offset;
358 cairo_content_t content;
360 unsigned long hash = 0;
361 cairo_shadow_cache_t *shadow_cache = NULL;
362 cairo_device_t *device = target->device;
364 cairo_surface_t *cache_surface = NULL;
365 cairo_bool_t bounded;
366 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
367 cairo_shadow_type_t shadow_type = source->shadow.type;
368 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
369 source->shadow.y_blur == 0.0);
371 cairo_shadow_cache_list_t shadow_cache_list;
373 if (shadow->type != CAIRO_SHADOW_DROP)
374 return CAIRO_STATUS_SUCCESS;
376 if (shadow->color.alpha == 0.0)
377 return CAIRO_STATUS_SUCCESS;
379 if (shadow->x_blur <= 0.0 && shadow->y_blur <= 0.0 &&
380 shadow->x_offset == 0.0 && shadow->y_offset == 0.0)
381 return CAIRO_STATUS_SUCCESS;
383 if (_cairo_clip_is_all_clipped (clip))
384 return CAIRO_STATUS_SUCCESS;
386 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
387 if (shadow_cache_list.caches != NULL) {
388 hash = _cairo_shadow_hash_for_paint (source, shadow);
389 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
392 if (shadow_cache != NULL) {
393 /* paint the shadow surface to target */
394 x_blur = shadow_cache->x_blur;
395 y_blur = shadow_cache->y_blur;
397 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
398 shadow_copy.color.green,
399 shadow_copy.color.blue,
402 status = _cairo_surface_paint_get_offset_extents (target,
410 if (unlikely (status))
413 if (shadow_extents.width == 0 || shadow_extents.height == 0)
416 x_offset = shadow_extents.x - x_blur;
417 y_offset = shadow_extents.y - y_blur;
419 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
420 cairo_matrix_translate (&m, -x_offset, -y_offset);
422 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
423 cairo_pattern_set_matrix (shadow_pattern, &m);
425 status = _cairo_surface_mask (target, op, color_pattern,
426 shadow_pattern, clip);
427 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
431 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
432 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
434 x_blur = ceil (shadow_copy.x_blur);
435 y_blur = ceil (shadow_copy.y_blur);
437 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
438 shadow_copy.color.green,
439 shadow_copy.color.blue,
440 shadow_copy.color.alpha);
442 status = _cairo_surface_paint_get_offset_extents (target,
449 if (unlikely (status))
452 if (shadow_extents.width == 0 && shadow_extents.height == 0)
455 x_offset = shadow_extents.x - x_blur;
456 y_offset = shadow_extents.y - y_blur;
458 shadow_width = ceil (shadow_extents.width + x_blur * 2);
459 shadow_height = ceil (shadow_extents.height + y_blur * 2);
461 shadow_surface = _cairo_ensure_shadow_surface (target,
462 &shadow_surface_extents,
464 shadow_width, shadow_height);
465 if (! shadow_surface || unlikely (shadow_surface->status))
468 if ((device || shadow_cache_list.locked) &&
469 shadow->enable_cache && bounded && has_blur) {
470 content = cairo_surface_get_content (target);
471 if (content == CAIRO_CONTENT_COLOR)
472 content = CAIRO_CONTENT_COLOR_ALPHA;
474 cache_surface = cairo_surface_create_similar (target, content,
475 shadow_surface_extents.width,
476 shadow_surface_extents.height);
477 if (unlikely (cache_surface->status))
481 _cairo_surface_release_device_reference (cache_surface);
484 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
487 cairo_matrix_init_scale (&m, scale, scale);
488 cairo_matrix_translate (&m, -x_offset, -y_offset);
490 /* paint with offset and scale */
491 status = _cairo_surface_scale_translate_paint (shadow_surface,
498 if (unlikely (status))
501 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
502 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
503 cairo_pattern_set_sigma (shadow_pattern,
504 shadow_copy.x_blur * scale * 0.5,
505 shadow_copy.y_blur * scale * 0.5);
507 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
508 if (unlikely (status))
511 if ((shadow_cache_list.locked ||device) &&
512 shadow->enable_cache && bounded && has_blur) {
513 status = _cairo_surface_mask (cache_surface, CAIRO_OPERATOR_OVER,
514 color_pattern, shadow_pattern, NULL);
515 if (unlikely (status))
518 cairo_pattern_destroy (shadow_pattern);
520 size = shadow_surface_extents.width * shadow_surface_extents.height;
521 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
524 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
525 _cairo_shadow_cache_init (shadow_cache,
533 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
534 *shadow_cache_list.size += size;
536 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
537 cairo_pattern_set_matrix (shadow_pattern, &m);
539 cairo_pattern_destroy (color_pattern);
540 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
541 shadow_copy.color.green,
542 shadow_copy.color.blue,
546 cairo_pattern_set_matrix (shadow_pattern, &m);
548 status = _cairo_surface_mask (target, op,
549 color_pattern, shadow_pattern, clip);
552 cairo_pattern_destroy (color_pattern);
555 cairo_pattern_destroy (shadow_pattern);
557 cairo_surface_destroy (shadow_surface);
558 cairo_surface_destroy (cache_surface);
560 if (shadow_cache_list.locked)
561 target->backend->shadow_cache_release (target);
563 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
564 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
569 _cairo_surface_shadow_mask (cairo_surface_t *target,
571 const cairo_pattern_t *source,
572 const cairo_pattern_t *mask,
573 const cairo_clip_t *clip,
574 const cairo_shadow_t *shadow)
576 cairo_status_t status;
577 cairo_pattern_union_t shadow_source;
578 cairo_pattern_union_t shadow_mask;
579 cairo_rectangle_t shadow_extents;
580 cairo_pattern_t *shadow_pattern = NULL;
581 cairo_pattern_t *color_pattern = NULL;
582 cairo_surface_t *shadow_surface = NULL;
583 cairo_rectangle_int_t shadow_surface_extents;
584 cairo_content_t content;
586 int shadow_width, shadow_height;
588 cairo_shadow_t shadow_copy = *shadow;
592 double x_offset = shadow->x_offset;
593 double y_offset = shadow->y_offset;
595 unsigned long hash = 0;
596 cairo_shadow_cache_t *shadow_cache = NULL;
597 cairo_device_t *device = target->device;
599 cairo_surface_t *cache_surface = NULL;
600 cairo_bool_t bounded;
601 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
602 cairo_shadow_type_t shadow_type = source->shadow.type;
603 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
604 source->shadow.y_blur == 0.0);
606 cairo_shadow_cache_list_t shadow_cache_list;
608 if (shadow->type != CAIRO_SHADOW_DROP)
609 return CAIRO_STATUS_SUCCESS;
611 if (shadow->color.alpha == 0.0)
612 return CAIRO_STATUS_SUCCESS;
614 if (shadow->x_blur <= 0.0 && shadow->y_blur <= 0.0 &&
615 shadow->x_offset == 0.0 && shadow->y_offset == 0.0)
616 return CAIRO_STATUS_SUCCESS;
618 if (_cairo_clip_is_all_clipped (clip))
619 return CAIRO_STATUS_SUCCESS;
621 if (shadow->x_blur == 0.0 && shadow->y_blur == 0.0) {
622 status = _cairo_surface_mask_get_offset_extents (target,
632 if (unlikely (status)) {
636 cairo_matrix_init_identity (&m);
637 cairo_matrix_translate (&m, -x_offset, -y_offset);
639 /* stroke to target with offset */
640 shadow_source.base.shadow.type = CAIRO_SHADOW_NONE;
641 shadow_source.base.shadow.draw_shadow_only = FALSE;
642 status = _cairo_surface_scale_translate_mask (target,
650 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
651 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
655 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
656 if (shadow_cache_list.caches != NULL) {
657 hash = _cairo_shadow_hash_for_mask (source, mask, shadow);
658 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
661 if (shadow_cache != NULL) {
662 /* paint the shadow surface to target */
663 x_blur = shadow_cache->x_blur;
664 y_blur = shadow_cache->y_blur;
666 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
667 shadow_copy.color.green,
668 shadow_copy.color.blue,
671 status = _cairo_surface_mask_get_offset_extents (target,
681 if (unlikely (status))
684 if (shadow_extents.width == 0 || shadow_extents.height == 0)
687 x_offset = shadow_extents.x - x_blur;
688 y_offset = shadow_extents.y - y_blur;
690 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
691 cairo_matrix_translate (&m, -x_offset, -y_offset);
693 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
694 cairo_pattern_set_matrix (shadow_pattern, &m);
696 status = _cairo_surface_mask (target, op, color_pattern,
697 shadow_pattern, clip);
698 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
702 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
703 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
705 x_blur = ceil (shadow_copy.x_blur);
706 y_blur = ceil (shadow_copy.y_blur);
708 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
709 shadow_copy.color.green,
710 shadow_copy.color.blue,
711 shadow_copy.color.alpha);
713 status = _cairo_surface_mask_get_offset_extents (target,
722 if (unlikely (status))
725 if (shadow_extents.width == 0 && shadow_extents.height == 0)
728 x_offset = shadow_extents.x - x_blur;
729 y_offset = shadow_extents.y - y_blur;
731 shadow_width = ceil (shadow_extents.width + x_blur * 2);
732 shadow_height = ceil (shadow_extents.height + y_blur * 2);
734 shadow_surface = _cairo_ensure_shadow_surface (target,
735 &shadow_surface_extents,
737 shadow_width, shadow_height);
738 if (! shadow_surface || unlikely (shadow_surface->status))
741 if ((shadow_cache_list.locked || device) &&
742 shadow->enable_cache && bounded && has_blur) {
743 content = cairo_surface_get_content (target);
744 if (content == CAIRO_CONTENT_COLOR)
745 content = CAIRO_CONTENT_COLOR_ALPHA;
747 cache_surface = cairo_surface_create_similar (target, content,
748 shadow_surface_extents.width,
749 shadow_surface_extents.height);
750 if (unlikely (cache_surface->status))
754 _cairo_surface_release_device_reference (cache_surface);
757 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
760 cairo_matrix_init_scale (&m, scale, scale);
761 cairo_matrix_translate (&m, -x_offset, -y_offset);
763 /* paint with offset and scale */
764 status = _cairo_surface_scale_translate_mask (shadow_surface,
771 if (unlikely (status))
774 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
775 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
776 cairo_pattern_set_sigma (shadow_pattern,
777 shadow_copy.x_blur * scale * 0.5,
778 shadow_copy.y_blur * scale * 0.5);
780 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
781 if (unlikely (status))
784 if ((shadow_cache_list.locked || device) &&
785 shadow->enable_cache && bounded && has_blur) {
786 status = _cairo_surface_mask (cache_surface, CAIRO_OPERATOR_OVER,
787 color_pattern, shadow_pattern, NULL);
788 if (unlikely (status))
791 cairo_pattern_destroy (shadow_pattern);
793 size = shadow_surface_extents.width * shadow_surface_extents.height;
794 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
797 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
798 _cairo_shadow_cache_init (shadow_cache,
806 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
807 *shadow_cache_list.size += size;
809 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
810 cairo_pattern_set_matrix (shadow_pattern, &m);
812 cairo_pattern_destroy (color_pattern);
813 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
814 shadow_copy.color.green,
815 shadow_copy.color.blue,
819 cairo_pattern_set_matrix (shadow_pattern, &m);
821 status = _cairo_surface_mask (target, op,
822 color_pattern, shadow_pattern, clip);
825 cairo_pattern_destroy (color_pattern);
828 cairo_pattern_destroy (shadow_pattern);
830 cairo_surface_destroy (shadow_surface);
831 cairo_surface_destroy (cache_surface);
833 if (shadow_cache_list.locked)
834 target->backend->shadow_cache_release (target);
836 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
837 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
841 static cairo_status_t
842 _cairo_surface_inset_shadow_stroke (cairo_surface_t *target,
844 const cairo_pattern_t *source,
845 const cairo_path_fixed_t *path,
846 const cairo_stroke_style_t*stroke_style,
847 const cairo_matrix_t *ctm,
848 const cairo_matrix_t *ctm_inverse,
850 cairo_antialias_t antialias,
851 const cairo_clip_t *clip,
852 const cairo_shadow_t *shadow)
854 cairo_status_t status;
855 cairo_pattern_union_t shadow_source;
856 cairo_path_fixed_t shadow_path;
857 cairo_rectangle_t shadow_extents;
858 cairo_pattern_t *shadow_pattern = NULL;
859 cairo_pattern_t *color_pattern = NULL;
860 cairo_surface_t *shadow_surface = NULL;
861 cairo_rectangle_int_t extents;
862 cairo_rectangle_int_t shadow_surface_extents;
863 cairo_matrix_t shadow_ctm, shadow_ctm_inverse;
864 cairo_content_t content;
866 int shadow_width, shadow_height;
868 cairo_shadow_t shadow_copy = *shadow;
869 cairo_color_t bg_color;
873 double x_offset = shadow->x_offset;
874 double y_offset = shadow->y_offset;
875 unsigned long hash = 0;
876 cairo_shadow_cache_t *shadow_cache = NULL;
877 cairo_device_t *device = target->device;
879 cairo_surface_t *cache_surface = NULL;
880 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
881 cairo_shadow_type_t shadow_type = source->shadow.type;
882 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
883 source->shadow.y_blur == 0.0);
884 double line_width = stroke_style->line_width;
886 cairo_shadow_cache_list_t shadow_cache_list;
888 if (shadow->color.alpha == 0.0)
889 return CAIRO_STATUS_SUCCESS;
891 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
892 if (shadow_cache_list.caches != NULL) {
893 hash = _cairo_shadow_hash_for_stroke (source, path, stroke_style, ctm, shadow);
894 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
897 if (shadow_cache != NULL) {
898 /* paint the shadow surface to target */
899 x_blur = shadow_cache->x_blur;
900 y_blur = shadow_cache->y_blur;
902 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
903 shadow_copy.color.green,
904 shadow_copy.color.blue,
907 status = _cairo_surface_stroke_get_offset_extents (target,
921 if (unlikely (status))
924 if (shadow_extents.width == 0 || shadow_extents.height == 0)
927 x_offset = shadow_extents.x - x_blur;
928 y_offset = shadow_extents.y - y_blur;
930 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
931 cairo_matrix_translate (&m, -x_offset, -y_offset);
933 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
934 cairo_pattern_set_matrix (shadow_pattern, &m);
936 status = _cairo_surface_stroke (target, op, shadow_pattern,
938 ctm, ctm_inverse, tolerance,
940 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
944 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
945 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
947 x_blur = ceil (shadow_copy.x_blur);
948 y_blur = ceil (shadow_copy.y_blur);
950 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
951 shadow_copy.color.green,
952 shadow_copy.color.blue,
953 shadow_copy.color.alpha);
955 status = _cairo_surface_stroke_get_offset_extents (target,
968 if (unlikely (status))
971 if (shadow_extents.width == 0 || shadow_extents.height == 0)
974 x_offset = shadow_extents.x - x_blur;
975 y_offset = shadow_extents.y - y_blur;
977 shadow_width = ceil (shadow_extents.width + x_blur * 2);
978 shadow_height = ceil (shadow_extents.height + y_blur * 2);
980 shadow_surface = _cairo_ensure_shadow_surface (target,
981 &shadow_surface_extents,
983 shadow_width, shadow_height);
984 if (! shadow_surface || unlikely (shadow_surface->status))
987 _cairo_surface_get_extents (shadow_surface, &extents);
989 if ((shadow_cache_list.locked || device) &&
990 shadow->enable_cache && has_blur) {
991 content = cairo_surface_get_content (target);
992 if (content == CAIRO_CONTENT_COLOR)
993 content = CAIRO_CONTENT_COLOR_ALPHA;
995 cache_surface = cairo_surface_create_similar (target, content,
996 shadow_surface_extents.width,
997 shadow_surface_extents.height);
998 if (unlikely (cache_surface->status))
1002 _cairo_surface_release_device_reference (cache_surface);
1005 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1008 if (line_width * scale <= 1.0)
1009 ((cairo_stroke_style_t *)stroke_style)->line_width = line_width / scale;
1010 cairo_matrix_init_scale (&m, scale, scale);
1011 cairo_matrix_translate (&m, -x_offset, -y_offset);
1013 _cairo_color_init_rgba (&bg_color,
1014 shadow_copy.color.red,
1015 shadow_copy.color.green,
1016 shadow_copy.color.blue,
1017 shadow_copy.color.alpha);
1019 /* paint with offset and scale */
1020 status = _cairo_surface_scale_translate_stroke (shadow_surface,
1023 CAIRO_OPERATOR_CLEAR,
1024 &shadow_source.base,
1028 &shadow_ctm_inverse,
1033 if (unlikely (status))
1036 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
1037 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
1038 cairo_pattern_set_sigma (shadow_pattern,
1039 shadow_copy.x_blur * scale * 0.5,
1040 shadow_copy.y_blur * scale * 0.5);
1042 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern,
1043 line_width * scale);
1044 if (unlikely (status))
1047 /* blur to mask surface */
1048 cairo_matrix_init_scale (&m, scale, scale);
1049 cairo_matrix_translate (&m, -x_offset, -y_offset);
1051 if ((shadow_cache_list.locked || device) &&
1052 shadow->enable_cache && has_blur) {
1053 status = _cairo_surface_paint (cache_surface, CAIRO_OPERATOR_OVER,
1054 shadow_pattern, NULL);
1055 if (unlikely (status))
1058 cairo_pattern_destroy (shadow_pattern);
1060 size = shadow_surface_extents.width * shadow_surface_extents.height;
1061 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1064 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1065 _cairo_shadow_cache_init (shadow_cache,
1073 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1074 *shadow_cache_list.size += size;
1076 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1077 cairo_pattern_set_matrix (shadow_pattern, &m);
1079 status = _cairo_surface_stroke (target, op, shadow_pattern,
1080 path, stroke_style, ctm,
1081 ctm_inverse, tolerance,
1086 cairo_pattern_set_matrix (shadow_pattern, &m);
1087 status = _cairo_surface_stroke (target, op, shadow_pattern,
1090 tolerance, antialias, clip);
1094 _cairo_path_fixed_fini (&shadow_path);
1095 cairo_pattern_destroy (color_pattern);
1098 cairo_pattern_destroy (shadow_pattern);
1100 cairo_surface_destroy (shadow_surface);
1101 cairo_surface_destroy (cache_surface);
1103 if (shadow_cache_list.locked)
1104 target->backend->shadow_cache_release (target);
1106 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1107 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1108 ((cairo_stroke_style_t *)stroke_style)->line_width = line_width;
1113 _cairo_surface_shadow_stroke (cairo_surface_t *target,
1114 cairo_operator_t op,
1115 const cairo_pattern_t *source,
1116 const cairo_path_fixed_t *path,
1117 const cairo_stroke_style_t*stroke_style,
1118 const cairo_matrix_t *ctm,
1119 const cairo_matrix_t *ctm_inverse,
1121 cairo_antialias_t antialias,
1122 const cairo_clip_t *clip,
1123 const cairo_shadow_t *shadow)
1125 cairo_status_t status;
1126 cairo_pattern_union_t shadow_source;
1127 cairo_path_fixed_t shadow_path;
1128 cairo_rectangle_t shadow_extents;
1129 cairo_pattern_t *shadow_pattern = NULL;
1130 cairo_pattern_t *color_pattern = NULL;
1131 cairo_surface_t *shadow_surface = NULL;
1132 cairo_rectangle_int_t shadow_surface_extents;
1133 cairo_matrix_t shadow_ctm, shadow_ctm_inverse;
1134 cairo_content_t content;
1135 cairo_color_t bg_color;
1137 int shadow_width, shadow_height;
1139 cairo_shadow_t shadow_copy = *shadow;
1143 double x_offset = shadow->x_offset;
1144 double y_offset = shadow->y_offset;
1145 unsigned long hash = 0;
1146 cairo_shadow_cache_t *shadow_cache = NULL;
1147 cairo_device_t *device = target->device;
1149 cairo_surface_t *cache_surface = NULL;
1150 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
1151 cairo_shadow_type_t shadow_type = source->shadow.type;
1152 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
1153 source->shadow.y_blur == 0.0);
1154 double line_width = stroke_style->line_width;
1156 cairo_shadow_cache_list_t shadow_cache_list;
1158 if (shadow->type == CAIRO_SHADOW_NONE)
1159 return CAIRO_STATUS_SUCCESS;
1161 if (shadow->color.alpha == 0.0)
1162 return CAIRO_STATUS_SUCCESS;
1164 if (shadow->x_blur <= 0.0 && shadow->y_blur <= 0.0 &&
1165 shadow->x_offset == 0.0 && shadow->y_offset == 0.0)
1166 return CAIRO_STATUS_SUCCESS;
1168 if (_cairo_clip_is_all_clipped (clip))
1169 return CAIRO_STATUS_SUCCESS;
1171 if (shadow->type == CAIRO_SHADOW_INSET)
1172 return _cairo_surface_inset_shadow_stroke (target, op, source,
1175 tolerance, antialias,
1178 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
1179 if (shadow_cache_list.caches != NULL) {
1180 hash = _cairo_shadow_hash_for_stroke (source, path, stroke_style, ctm, shadow);
1181 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
1184 if (shadow_cache != NULL) {
1185 /* paint the shadow surface to target */
1186 x_blur = shadow_cache->x_blur;
1187 y_blur = shadow_cache->y_blur;
1189 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1190 shadow_copy.color.green,
1191 shadow_copy.color.blue,
1194 status = _cairo_surface_stroke_get_offset_extents (target,
1203 &shadow_source.base,
1206 &shadow_ctm_inverse,
1208 if (unlikely (status))
1211 if (shadow_extents.width == 0 || shadow_extents.height == 0)
1214 x_offset = shadow_extents.x - x_blur;
1215 y_offset = shadow_extents.y - y_blur;
1217 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1218 cairo_matrix_translate (&m, -x_offset, -y_offset);
1220 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1221 cairo_pattern_set_matrix (shadow_pattern, &m);
1223 status = _cairo_surface_mask (target, op, color_pattern,
1224 shadow_pattern, clip);
1225 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1229 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1230 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1232 x_blur = ceil (shadow_copy.x_blur);
1233 y_blur = ceil (shadow_copy.y_blur);
1235 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1236 shadow_copy.color.green,
1237 shadow_copy.color.blue,
1238 shadow_copy.color.alpha);
1240 status = _cairo_surface_stroke_get_offset_extents (target,
1248 &shadow_source.base,
1251 &shadow_ctm_inverse,
1253 if (unlikely (status))
1256 if (shadow_extents.width == 0 || shadow_extents.height == 0)
1259 x_offset = shadow_extents.x - x_blur;
1260 y_offset = shadow_extents.y - y_blur;
1262 shadow_width = ceil (shadow_extents.width + x_blur * 2);
1263 shadow_height = ceil (shadow_extents.height + y_blur * 2);
1265 shadow_surface = _cairo_ensure_shadow_surface (target,
1266 &shadow_surface_extents,
1268 shadow_width, shadow_height);
1269 if (! shadow_surface || unlikely (shadow_surface->status))
1272 if ((shadow_cache_list.locked || device) &&
1273 shadow->enable_cache && has_blur) {
1274 content = cairo_surface_get_content (target);
1275 if (content == CAIRO_CONTENT_COLOR)
1276 content = CAIRO_CONTENT_COLOR_ALPHA;
1278 cache_surface = cairo_surface_create_similar (target, content,
1279 shadow_surface_extents.width,
1280 shadow_surface_extents.height);
1281 if (unlikely (cache_surface->status))
1285 _cairo_surface_release_device_reference (cache_surface);
1288 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1292 if (line_width * scale <= 1.0)
1293 ((cairo_stroke_style_t *)stroke_style)->line_width = line_width / scale;
1295 cairo_matrix_init_scale (&m, scale, scale);
1296 cairo_matrix_translate (&m, -x_offset, -y_offset);
1298 /* paint with offset and scale */
1299 _cairo_color_init_rgba (&bg_color, 0, 0, 0, 0);
1300 status = _cairo_surface_scale_translate_stroke (shadow_surface,
1303 CAIRO_OPERATOR_OVER,
1304 &shadow_source.base,
1308 &shadow_ctm_inverse,
1313 if (unlikely (status))
1316 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
1317 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
1318 cairo_pattern_set_sigma (shadow_pattern,
1319 shadow_copy.x_blur * scale * 0.5,
1320 shadow_copy.y_blur * scale * 0.5);
1322 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern,
1323 line_width * scale);
1324 if (unlikely (status))
1327 if ((shadow_cache_list.locked || device) &&
1328 shadow->enable_cache && has_blur) {
1329 status = _cairo_surface_mask (cache_surface, CAIRO_OPERATOR_OVER,
1330 color_pattern, shadow_pattern, NULL);
1331 if (unlikely (status))
1334 cairo_pattern_destroy (shadow_pattern);
1336 size = shadow_surface_extents.width * shadow_surface_extents.height;
1337 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1340 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1341 _cairo_shadow_cache_init (shadow_cache,
1349 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1350 *shadow_cache_list.size += size;
1352 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1353 cairo_pattern_set_matrix (shadow_pattern, &m);
1355 cairo_pattern_destroy (color_pattern);
1356 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1357 shadow_copy.color.green,
1358 shadow_copy.color.blue,
1362 cairo_pattern_set_matrix (shadow_pattern, &m);
1364 status = _cairo_surface_mask (target, op,
1365 color_pattern, shadow_pattern, clip);
1368 _cairo_path_fixed_fini (&shadow_path);
1369 cairo_pattern_destroy (color_pattern);
1372 cairo_pattern_destroy (shadow_pattern);
1374 cairo_surface_destroy (shadow_surface);
1375 cairo_surface_destroy (cache_surface);
1377 if (shadow_cache_list.locked)
1378 target->backend->shadow_cache_release (target);
1380 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1381 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1382 ((cairo_stroke_style_t *)stroke_style)->line_width = line_width;
1386 static cairo_status_t
1387 _cairo_surface_inset_shadow_fill (cairo_surface_t *target,
1388 cairo_operator_t op,
1389 const cairo_pattern_t*source,
1390 const cairo_path_fixed_t *path,
1391 cairo_fill_rule_t fill_rule,
1393 cairo_antialias_t antialias,
1394 const cairo_clip_t *clip,
1395 const cairo_shadow_t *shadow)
1397 cairo_status_t status;
1398 cairo_pattern_union_t shadow_source;
1399 cairo_path_fixed_t shadow_path;
1400 cairo_rectangle_t shadow_extents;
1401 cairo_pattern_t *shadow_pattern = NULL;
1402 cairo_pattern_t *color_pattern = NULL;
1403 cairo_surface_t *shadow_surface = NULL;
1404 cairo_surface_t *cache_surface = NULL;
1405 cairo_rectangle_int_t shadow_surface_extents;
1406 cairo_rectangle_int_t extents;
1407 cairo_content_t content;
1409 int shadow_width, shadow_height;
1411 cairo_shadow_t shadow_copy = *shadow;
1415 double x_offset = shadow->x_offset;
1416 double y_offset = shadow->y_offset;
1417 unsigned long hash = 0;
1418 cairo_shadow_cache_t *shadow_cache = NULL;
1419 cairo_device_t *device = target->device;
1421 cairo_color_t bg_color;
1422 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
1423 cairo_shadow_type_t shadow_type = source->shadow.type;
1424 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
1425 source->shadow.y_blur == 0.0);
1427 cairo_shadow_cache_list_t shadow_cache_list;
1429 if (shadow->color.alpha == 0.0)
1430 return CAIRO_STATUS_SUCCESS;
1432 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
1433 if (shadow_cache_list.caches != NULL) {
1434 hash = _cairo_shadow_hash_for_fill (source, path, fill_rule, shadow);
1435 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
1438 if (shadow_cache != NULL) {
1439 /* paint the shadow surface to target */
1440 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1441 shadow_copy.color.green,
1442 shadow_copy.color.blue,
1444 x_blur = shadow_cache->x_blur;
1445 y_blur = shadow_cache->y_blur;
1447 status = _cairo_surface_fill_get_offset_extents (target,
1455 &shadow_source.base,
1458 if (unlikely (status))
1461 if (shadow_extents.width == 0 || shadow_extents.height == 0)
1464 x_offset = shadow_extents.x - x_blur;
1465 y_offset = shadow_extents.y - y_blur;
1467 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1468 cairo_matrix_translate (&m, -x_offset, -y_offset);
1470 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1471 cairo_pattern_set_matrix (shadow_pattern, &m);
1473 if (! shadow->path_is_fill_with_spread)
1474 status = _cairo_surface_fill (target, op, shadow_pattern,
1475 path, fill_rule, tolerance,
1478 status = _cairo_surface_paint (target, op, shadow_pattern,
1481 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1485 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1486 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1488 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1489 shadow_copy.color.green,
1490 shadow_copy.color.blue,
1491 shadow_copy.color.alpha);
1493 x_blur = ceil (shadow_copy.x_blur);
1494 y_blur = ceil (shadow_copy.y_blur);
1496 status = _cairo_surface_fill_get_offset_extents (target,
1503 &shadow_source.base,
1506 if (unlikely (status))
1509 if (shadow_extents.width == 0 && shadow_extents.height == 0)
1512 x_offset = shadow_extents.x - x_blur;
1513 y_offset = shadow_extents.y - y_blur;
1515 shadow_width = ceil (shadow_extents.width + x_blur * 2);
1516 shadow_height = ceil (shadow_extents.height + y_blur * 2);
1518 shadow_surface = _cairo_ensure_shadow_surface (target,
1519 &shadow_surface_extents,
1521 shadow_width, shadow_height);
1522 if (! shadow_surface || unlikely (shadow_surface->status))
1525 _cairo_surface_get_extents (shadow_surface, &extents);
1527 if ((shadow_cache_list.locked || device) &&
1528 shadow->enable_cache && has_blur) {
1529 content = cairo_surface_get_content (target);
1530 if (content == CAIRO_CONTENT_COLOR)
1531 content = CAIRO_CONTENT_COLOR_ALPHA;
1533 cache_surface = cairo_surface_create_similar (target, content,
1534 shadow_surface_extents.width,
1535 shadow_surface_extents.height);
1536 if (unlikely (cache_surface->status))
1540 _cairo_surface_release_device_reference (cache_surface);
1543 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1546 cairo_matrix_init_scale (&m, scale, scale);
1547 cairo_matrix_translate (&m, -x_offset, -y_offset);
1549 _cairo_color_init_rgba (&bg_color,
1550 shadow_copy.color.red,
1551 shadow_copy.color.green,
1552 shadow_copy.color.blue,
1553 shadow_copy.color.alpha);
1554 /* paint with offset and scale */
1555 status = _cairo_surface_scale_translate_fill (shadow_surface,
1558 CAIRO_OPERATOR_CLEAR,
1559 &shadow_source.base,
1566 if (unlikely (status))
1568 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
1569 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
1570 cairo_pattern_set_sigma (shadow_pattern,
1571 shadow_copy.x_blur * scale * 0.5,
1572 shadow_copy.y_blur * scale * 0.5);
1574 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
1575 if (unlikely (status))
1578 /* blur to cache surface */
1579 cairo_matrix_init_scale (&m, scale, scale);
1580 cairo_matrix_translate (&m, -x_offset, -y_offset);
1582 if ((shadow_cache_list.locked || device) &&
1583 shadow->enable_cache && has_blur) {
1584 status = _cairo_surface_paint (cache_surface, CAIRO_OPERATOR_OVER,
1585 shadow_pattern, NULL);
1587 if (unlikely (status))
1590 cairo_pattern_destroy (shadow_pattern);
1592 size = shadow_surface_extents.width * shadow_surface_extents.height;
1593 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1596 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1597 _cairo_shadow_cache_init (shadow_cache,
1605 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1606 *shadow_cache_list.size += size;
1608 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1610 cairo_pattern_set_matrix (shadow_pattern, &m);
1611 if (! shadow_copy.path_is_fill_with_spread)
1612 status = _cairo_surface_fill (target, op, shadow_pattern,
1613 path, fill_rule, tolerance,
1616 status = _cairo_surface_paint (target, op, shadow_pattern,
1620 cairo_pattern_set_matrix (shadow_pattern, &m);
1621 if (! shadow_copy.path_is_fill_with_spread)
1622 status = _cairo_surface_fill (target, op, shadow_pattern,
1623 path, fill_rule, tolerance,
1626 status = _cairo_surface_paint (target, op, shadow_pattern,
1630 _cairo_path_fixed_fini (&shadow_path);
1631 cairo_pattern_destroy (color_pattern);
1634 cairo_pattern_destroy (shadow_pattern);
1637 cairo_surface_destroy (cache_surface);
1639 cairo_surface_destroy (shadow_surface);
1641 if (shadow_cache_list.locked)
1642 target->backend->shadow_cache_release (target);
1644 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1645 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1650 _cairo_surface_shadow_fill (cairo_surface_t *target,
1651 cairo_operator_t op,
1652 const cairo_pattern_t*source,
1653 const cairo_path_fixed_t *path,
1654 cairo_fill_rule_t fill_rule,
1656 cairo_antialias_t antialias,
1657 const cairo_clip_t *clip,
1658 const cairo_shadow_t *shadow)
1660 cairo_status_t status;
1661 cairo_pattern_union_t shadow_source;
1662 cairo_path_fixed_t shadow_path;
1663 cairo_rectangle_t shadow_extents;
1664 cairo_pattern_t *shadow_pattern = NULL;
1665 cairo_pattern_t *color_pattern = NULL;
1666 cairo_surface_t *shadow_surface = NULL;
1667 cairo_rectangle_int_t shadow_surface_extents;
1668 cairo_content_t content;
1670 int shadow_width, shadow_height;
1672 cairo_shadow_t shadow_copy = *shadow;
1673 cairo_color_t bg_color;
1677 double x_offset = shadow->x_offset;
1678 double y_offset = shadow->y_offset;
1679 unsigned long hash = 0;
1680 cairo_shadow_cache_t *shadow_cache = NULL;
1681 cairo_device_t *device = target->device;
1683 cairo_surface_t *cache_surface = NULL;
1684 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
1685 cairo_shadow_type_t shadow_type = source->shadow.type;
1686 cairo_bool_t has_blur = ! (source->shadow.x_blur == 0.0 &&
1687 source->shadow.y_blur == 0.0);
1689 cairo_shadow_cache_list_t shadow_cache_list;
1691 if (shadow->type == CAIRO_SHADOW_NONE)
1692 return CAIRO_STATUS_SUCCESS;
1694 if (shadow->color.alpha == 0.0)
1695 return CAIRO_STATUS_SUCCESS;
1697 if (shadow->x_blur <= 0.0 && shadow->y_blur <= 0.0 &&
1698 shadow->x_offset == 0.0 && shadow->y_offset == 0.0)
1699 return CAIRO_STATUS_SUCCESS;
1701 if (_cairo_clip_is_all_clipped (clip))
1702 return CAIRO_STATUS_SUCCESS;
1704 if (shadow->type == CAIRO_SHADOW_INSET)
1705 return _cairo_surface_inset_shadow_fill (target, op, source,
1707 tolerance, antialias,
1710 if (shadow->x_blur == 0.0 && shadow->y_blur == 0.0) {
1711 status = _cairo_surface_fill_get_offset_extents (target,
1719 &shadow_source.base,
1722 if (unlikely (status)) {
1723 _cairo_path_fixed_fini (&shadow_path);
1727 cairo_matrix_init_identity (&m);
1728 cairo_matrix_translate (&m, -x_offset, -y_offset);
1730 /* stroke to target with offset */
1731 shadow_source.base.shadow.type = CAIRO_SHADOW_NONE;
1732 shadow_source.base.shadow.draw_shadow_only = FALSE;
1733 status = _cairo_surface_scale_translate_fill (target,
1737 &shadow_source.base,
1744 _cairo_path_fixed_fini (&shadow_path);
1745 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1746 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1750 _cairo_shadow_cache_list_init (&shadow_cache_list, target);
1751 if (shadow_cache_list.caches != NULL) {
1752 hash = _cairo_shadow_hash_for_fill (source, path, fill_rule, shadow);
1753 shadow_cache = _cairo_shadow_cache_list_find (&shadow_cache_list, hash);
1756 if (shadow_cache != NULL) {
1757 /* paint the shadow surface to target */
1758 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1759 shadow_copy.color.green,
1760 shadow_copy.color.blue,
1762 x_blur = shadow_cache->x_blur;
1763 y_blur = shadow_cache->y_blur;
1765 status = _cairo_surface_fill_get_offset_extents (target,
1773 &shadow_source.base,
1776 if (unlikely (status))
1779 if (shadow_extents.width == 0 || shadow_extents.height == 0)
1782 x_offset = shadow_extents.x - x_blur;
1783 y_offset = shadow_extents.y - y_blur;
1785 cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1786 cairo_matrix_translate (&m, -x_offset, -y_offset);
1788 shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1789 cairo_pattern_set_matrix (shadow_pattern, &m);
1791 status = _cairo_surface_mask (target, op, color_pattern,
1792 shadow_pattern, clip);
1793 cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1797 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1798 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1800 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1801 shadow_copy.color.green,
1802 shadow_copy.color.blue,
1803 shadow_copy.color.alpha);
1805 x_blur = ceil (shadow_copy.x_blur);
1806 y_blur = ceil (shadow_copy.y_blur);
1808 status = _cairo_surface_fill_get_offset_extents (target,
1815 &shadow_source.base,
1818 if (unlikely (status))
1821 if (shadow_extents.width == 0 && shadow_extents.height == 0)
1824 x_offset = shadow_extents.x - x_blur;
1825 y_offset = shadow_extents.y - y_blur;
1827 shadow_width = ceil (shadow_extents.width + x_blur * 2);
1828 shadow_height = ceil (shadow_extents.height + y_blur * 2);
1830 shadow_surface = _cairo_ensure_shadow_surface (target,
1831 &shadow_surface_extents,
1833 shadow_width, shadow_height);
1834 if (! shadow_surface || unlikely (shadow_surface->status))
1837 if ((shadow_cache_list.locked || device) &&
1838 shadow->enable_cache && has_blur) {
1839 content = cairo_surface_get_content (target);
1840 if (content == CAIRO_CONTENT_COLOR)
1841 content = CAIRO_CONTENT_COLOR_ALPHA;
1843 cache_surface = cairo_surface_create_similar (target, content,
1844 shadow_surface_extents.width,
1845 shadow_surface_extents.height);
1846 if (unlikely (cache_surface->status))
1850 _cairo_surface_release_device_reference (cache_surface);
1853 scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1856 cairo_matrix_init_scale (&m, scale, scale);
1857 cairo_matrix_translate (&m, -x_offset, -y_offset);
1859 /* paint with offset and scale */
1860 _cairo_color_init_rgba (&bg_color, 0, 0, 0, 0);
1861 status = _cairo_surface_scale_translate_fill (shadow_surface,
1864 CAIRO_OPERATOR_OVER,
1865 &shadow_source.base,
1872 if (unlikely (status))
1875 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
1876 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
1877 cairo_pattern_set_sigma (shadow_pattern,
1878 shadow_copy.x_blur * scale * 0.5,
1879 shadow_copy.y_blur * scale * 0.5);
1881 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
1882 if (unlikely (status))
1885 if ((shadow_cache_list.locked || device) &&
1886 shadow->enable_cache && has_blur) {
1887 status = _cairo_surface_mask (cache_surface, CAIRO_OPERATOR_OVER,
1888 color_pattern, shadow_pattern, NULL);
1889 if (unlikely (status))
1892 cairo_pattern_destroy (shadow_pattern);
1894 size = shadow_surface_extents.width * shadow_surface_extents.height;
1895 _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1898 shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1899 _cairo_shadow_cache_init (shadow_cache,
1907 cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1908 *shadow_cache_list.size += size;
1910 shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1911 cairo_pattern_set_matrix (shadow_pattern, &m);
1913 cairo_pattern_destroy (color_pattern);
1914 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1915 shadow_copy.color.green,
1916 shadow_copy.color.blue,
1920 cairo_pattern_set_matrix (shadow_pattern, &m);
1922 status = _cairo_surface_mask (target, op,
1923 color_pattern, shadow_pattern, clip);
1926 _cairo_path_fixed_fini (&shadow_path);
1927 cairo_pattern_destroy (color_pattern);
1930 cairo_pattern_destroy (shadow_pattern);
1932 cairo_surface_destroy (cache_surface);
1934 cairo_surface_destroy (shadow_surface);
1936 if (shadow_cache_list.locked)
1937 target->backend->shadow_cache_release (target);
1938 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1939 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1944 static cairo_status_t
1945 _cairo_surface_inset_shadow_glyphs (cairo_surface_t *target,
1946 cairo_operator_t op,
1947 const cairo_pattern_t *source,
1948 cairo_scaled_font_t *scaled_font,
1949 cairo_glyph_t *glyphs,
1951 const cairo_clip_t *clip,
1952 const cairo_shadow_t *shadow)
1954 cairo_status_t status;
1955 cairo_pattern_union_t shadow_source;
1956 cairo_rectangle_t shadow_extents;
1957 cairo_pattern_t *shadow_pattern = NULL;
1958 cairo_pattern_t *color_pattern = NULL;
1959 cairo_surface_t *shadow_surface = NULL;
1960 cairo_surface_t *mask_surface = NULL;
1961 cairo_rectangle_int_t shadow_surface_extents;
1962 cairo_glyph_t *shadow_glyphs;
1963 cairo_content_t content;
1964 cairo_color_t bg_color;
1966 int shadow_width, shadow_height;
1968 cairo_shadow_t shadow_copy = *shadow;
1971 double x_offset = shadow->x_offset;
1972 double y_offset = shadow->y_offset;
1973 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
1974 cairo_shadow_type_t shadow_type = source->shadow.type;
1976 if (shadow->color.alpha == 0.0)
1977 return CAIRO_STATUS_SUCCESS;
1979 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1980 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1982 x_blur = ceil (shadow_copy.x_blur);
1983 y_blur = ceil (shadow_copy.y_blur);
1985 shadow_glyphs = (cairo_glyph_t *)_cairo_malloc_ab (num_glyphs,
1986 sizeof (cairo_glyph_t));
1987 if (shadow_glyphs == NULL) {
1988 status = CAIRO_STATUS_NO_MEMORY;
1992 status = _cairo_surface_glyphs_get_offset_extents (target,
2000 &shadow_source.base,
2003 if (unlikely (status))
2006 if (shadow_extents.width == 0 && shadow_extents.height == 0)
2009 x_offset = shadow_extents.x - x_blur;
2010 y_offset = shadow_extents.y - y_blur;
2012 shadow_width = ceil (shadow_extents.width + x_blur * 2 + fabs (shadow->x_offset));
2013 shadow_height = ceil (shadow_extents.height + y_blur * 2 + fabs (shadow->y_offset));
2015 if (target->backend->get_glyph_shadow_surface) {
2016 shadow_surface = target->backend->get_glyph_shadow_surface (target,
2022 content = cairo_surface_get_content (target);
2023 if (content == CAIRO_CONTENT_COLOR)
2024 content = CAIRO_CONTENT_COLOR_ALPHA;
2025 shadow_surface = cairo_surface_create_similar (target,
2029 _cairo_surface_release_device_reference (shadow_surface);
2031 if (! shadow_surface || unlikely (shadow_surface->status))
2034 if(! _cairo_surface_get_extents (shadow_surface, &shadow_surface_extents))
2037 if (target->backend->get_glyph_shadow_mask_surface) {
2038 mask_surface = target->backend->get_glyph_shadow_mask_surface (shadow_surface,
2039 shadow_surface_extents.width,
2040 shadow_surface_extents.height,
2044 mask_surface = cairo_surface_create_similar (shadow_surface,
2045 CAIRO_CONTENT_COLOR_ALPHA,
2046 shadow_surface_extents.width,
2047 shadow_surface_extents.height);
2048 _cairo_surface_release_device_reference (mask_surface);
2050 if (! mask_surface || unlikely (mask_surface->status))
2053 cairo_matrix_init_translate (&m, -x_offset, -y_offset);
2055 /* paint with offset and scale */
2056 _cairo_color_init_rgba (&bg_color, 0, 0, 0, 0);
2057 color_pattern = cairo_pattern_create_rgba (1, 1, 1, 1);
2059 status = _cairo_surface_translate_glyphs (mask_surface,
2062 CAIRO_OPERATOR_OVER,
2069 if (unlikely (status))
2072 /* with fast path, we paint shadow color and source directly to
2073 * shadow_surface, and then blur to target */
2074 cairo_pattern_destroy (color_pattern);
2075 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
2076 shadow_copy.color.green,
2077 shadow_copy.color.blue,
2078 shadow_copy.color.alpha);
2080 status = _cairo_surface_paint (shadow_surface,
2081 CAIRO_OPERATOR_SOURCE,
2082 color_pattern, NULL);
2083 if (unlikely (status))
2086 shadow_pattern = cairo_pattern_create_for_surface (mask_surface);
2087 cairo_pattern_destroy (color_pattern);
2088 color_pattern = cairo_pattern_create_rgba (0, 0, 0, 0);
2090 status = _cairo_surface_mask (shadow_surface, CAIRO_OPERATOR_SOURCE,
2091 color_pattern, shadow_pattern,
2093 if (unlikely (status))
2096 cairo_pattern_destroy (shadow_pattern);
2097 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
2098 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
2099 cairo_pattern_set_sigma (shadow_pattern,
2100 shadow_copy.x_blur * 0.5,
2101 shadow_copy.y_blur * 0.5);
2102 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
2103 if (unlikely (status))
2106 cairo_pattern_destroy (color_pattern);
2107 color_pattern = cairo_pattern_create_for_surface (mask_surface);
2108 cairo_pattern_set_matrix (color_pattern, &m);
2110 cairo_matrix_translate (&m, -shadow->x_offset,
2112 cairo_pattern_set_matrix (shadow_pattern, &m);
2114 status = _cairo_surface_mask (target, op, shadow_pattern,
2115 color_pattern, clip);
2117 cairo_pattern_destroy (color_pattern);
2120 cairo_pattern_destroy (shadow_pattern);
2122 free (shadow_glyphs);
2124 cairo_surface_destroy (shadow_surface);
2125 cairo_surface_destroy (mask_surface);
2127 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
2128 ((cairo_pattern_t *)source)->shadow.type = shadow_type;
2133 _cairo_surface_shadow_glyphs (cairo_surface_t *target,
2134 cairo_operator_t op,
2135 const cairo_pattern_t *source,
2136 cairo_scaled_font_t *scaled_font,
2137 cairo_glyph_t *glyphs,
2139 const cairo_clip_t *clip,
2140 const cairo_shadow_t *shadow)
2142 cairo_status_t status;
2143 cairo_pattern_union_t shadow_source;
2144 cairo_rectangle_t shadow_extents;
2145 cairo_pattern_t *shadow_pattern = NULL;
2146 cairo_pattern_t *color_pattern;
2147 cairo_surface_t *shadow_surface = NULL;
2148 cairo_rectangle_int_t shadow_surface_extents;
2150 cairo_glyph_t *shadow_glyphs;
2151 cairo_content_t content;
2152 cairo_color_t bg_color;
2153 int shadow_width, shadow_height;
2155 cairo_shadow_t shadow_copy = *shadow;
2158 double x_offset = shadow->x_offset;
2159 double y_offset = shadow->y_offset;
2160 cairo_bool_t draw_shadow_only = source->shadow.draw_shadow_only;
2161 cairo_shadow_type_t shadow_type = source->shadow.type;
2163 if (shadow->type == CAIRO_SHADOW_NONE)
2164 return CAIRO_STATUS_SUCCESS;
2166 if (shadow->color.alpha == 0.0)
2167 return CAIRO_STATUS_SUCCESS;
2169 if (shadow->x_blur <= 0.0 && shadow->y_blur <= 0.0 &&
2170 shadow->x_offset == 0.0 && shadow->y_offset == 0.0)
2171 return CAIRO_STATUS_SUCCESS;
2173 if (_cairo_clip_is_all_clipped (clip))
2174 return CAIRO_STATUS_SUCCESS;
2176 if (shadow->type == CAIRO_SHADOW_INSET)
2177 return _cairo_surface_inset_shadow_glyphs (target, op, source,
2178 scaled_font, glyphs,
2181 shadow_glyphs = (cairo_glyph_t *)_cairo_malloc_ab (num_glyphs,
2182 sizeof (cairo_glyph_t));
2183 if (shadow_glyphs == NULL)
2184 return CAIRO_STATUS_NO_MEMORY;
2186 ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
2187 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
2189 x_blur = ceil (shadow_copy.x_blur);
2190 y_blur = ceil (shadow_copy.y_blur);
2192 color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
2193 shadow_copy.color.green,
2194 shadow_copy.color.blue,
2195 shadow_copy.color.alpha);
2197 status = _cairo_surface_glyphs_get_offset_extents (target,
2205 &shadow_source.base,
2208 if (unlikely (status))
2211 if (shadow_extents.width == 0 && shadow_extents.height == 0)
2214 x_offset = shadow_extents.x - x_blur;
2215 y_offset = shadow_extents.y - y_blur;
2217 shadow_width = ceil (shadow_extents.width + x_blur * 2);
2218 shadow_height = ceil (shadow_extents.height + y_blur * 2);
2220 if (target->backend->get_glyph_shadow_surface)
2221 shadow_surface = target->backend->get_glyph_shadow_surface (target,
2226 content = cairo_surface_get_content (target);
2227 if (content == CAIRO_CONTENT_COLOR)
2228 content = CAIRO_CONTENT_COLOR_ALPHA;
2229 shadow_surface = cairo_surface_create_similar (target,
2233 _cairo_surface_release_device_reference (shadow_surface);
2235 if (! shadow_surface || unlikely (shadow_surface->status))
2238 if(! _cairo_surface_get_extents (shadow_surface, &shadow_surface_extents))
2241 cairo_matrix_init_translate (&m, -x_offset, -y_offset);
2243 /* paint with offset and scale */
2244 _cairo_color_init_rgba (&bg_color, 0, 0, 0, 0);
2245 status = _cairo_surface_translate_glyphs (shadow_surface,
2248 CAIRO_OPERATOR_OVER,
2249 &shadow_source.base,
2255 if (unlikely (status))
2258 shadow_pattern = cairo_pattern_create_for_surface (shadow_surface);
2259 cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_GAUSSIAN);
2260 cairo_pattern_set_sigma (shadow_pattern,
2261 shadow_copy.x_blur * 0.5,
2262 shadow_copy.y_blur * 0.5);
2264 status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
2265 if (unlikely (status))
2268 cairo_pattern_set_matrix (shadow_pattern, &m);
2270 status = _cairo_surface_mask (target, op, color_pattern,
2271 shadow_pattern, NULL);
2274 cairo_pattern_destroy (color_pattern);
2277 cairo_pattern_destroy (shadow_pattern);
2279 free (shadow_glyphs);
2281 cairo_surface_destroy (shadow_surface);
2283 ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
2284 ((cairo_pattern_t *)source)->shadow.type = shadow_type;