tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-surface-shadow.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2005 Red Hat, Inc
4  * Copyright © 2007 Adrian Johnson
5  * Copyright © 2009 Chris Wilson
6  * Copyright © 2013 Samsung Research America, Silicon Valley
7  *
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.
15  *
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
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is Red Hat, Inc.
34  *
35  * Contributor(s):
36  *      Henry Song <henry.song@samsung.com
37  */
38
39 #include "cairoint.h"
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"
50
51 #define MAX_SHADOW_SIZE 1024
52
53 typedef struct _cairo_shadow_cache_list {
54     cairo_list_t *caches;
55     unsigned long *size;
56     cairo_bool_t locked;
57 } cairo_shadow_cache_list_t;
58
59 static unsigned long
60 _cairo_stroke_style_hash (unsigned long hash,
61                           const cairo_stroke_style_t *style)
62 {
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);
66     return hash;
67 }
68
69 static unsigned long
70 _cairo_matrix_hash (unsigned long hash, const cairo_matrix_t *matrix)
71 {
72     return _cairo_hash_bytes (hash, matrix, sizeof (cairo_matrix_t));
73 }
74
75 static unsigned long
76 _cairo_path_fixed_rel_hash (unsigned long hash, const cairo_path_fixed_t *path)
77 {
78     const cairo_path_buf_t *buf;
79     unsigned int count;
80     cairo_path_fixed_t path_copy;
81     cairo_status_t status;
82     unsigned int i;
83     cairo_fixed_t dx, dy;
84
85     status = _cairo_path_fixed_init_copy (&path_copy, path);
86     if (unlikely (status))
87         return hash;
88
89     dx = path_copy.buf.points[0].x;
90     dy = path_copy.buf.points[0].y;
91
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;
96         }
97     } cairo_path_foreach_buf_end (buf, &path_copy);
98
99     count = 0;
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));
106
107     count = 0;
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));
114
115     _cairo_path_fixed_fini (&path_copy);
116
117     return hash;
118 }
119
120 static unsigned long
121 _cairo_shadow_hash (unsigned long hash, const cairo_shadow_t *shadow)
122 {
123     return _cairo_hash_bytes (hash, shadow, sizeof (cairo_shadow_t) - sizeof (cairo_bool_t));
124 }
125
126 static unsigned long
127 _cairo_shadow_hash_for_paint (const cairo_pattern_t *source,
128                               const cairo_shadow_t *shadow)
129 {
130     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
131     cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
132
133     hash = _cairo_pattern_hash_with_hash (hash, source, use_color);
134     return _cairo_shadow_hash (hash, shadow);
135 }
136
137 static unsigned long
138 _cairo_shadow_hash_for_mask (const cairo_pattern_t *source,
139                              const cairo_pattern_t *mask,
140                              const cairo_shadow_t *shadow)
141 {
142     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
143     cairo_bool_t use_color = shadow->type == CAIRO_SHADOW_INSET;
144
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);
148 }
149
150 static unsigned long
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)
155 {
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;
160     use_color = FALSE;
161
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);
166 }
167
168 static unsigned long
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)
174 {
175     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
176
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;
180     use_color = FALSE;
181
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);
187 }
188
189 static void
190 _cairo_shadow_cache_init (cairo_shadow_cache_t *shadow_cache,
191                           cairo_surface_t      *cache_surface,
192                           unsigned long         size,
193                           unsigned long         hash,
194                           int                   x_blur,
195                           int                   y_blur,
196                           double                scale)
197 {
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;
205 }
206
207 static void
208 _cairo_shadow_cache_destroy (cairo_shadow_cache_t *shadow_cache)
209 {
210     cairo_list_del (&shadow_cache->link);
211     cairo_surface_destroy (shadow_cache->surface);
212     free (shadow_cache);
213 }
214
215 static void
216 _cairo_shadow_cache_list_shrink_to_accomodate (cairo_shadow_cache_list_t *shadow_caches,
217                                                unsigned long additional)
218 {
219     cairo_shadow_cache_t *shadow_cache;
220
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,
224                                               link);
225         *(shadow_caches->size) -= shadow_cache->size;
226         _cairo_shadow_cache_destroy (shadow_cache);
227     }
228 }
229
230 static cairo_shadow_cache_t *
231 _cairo_shadow_cache_list_find (cairo_shadow_cache_list_t *shadow_caches,
232                                unsigned long hash)
233 {
234     cairo_shadow_cache_t *shadow_cache;
235
236     cairo_list_foreach_entry (shadow_cache,
237                               cairo_shadow_cache_t,
238                               shadow_caches->caches, link)
239         if (shadow_cache->hash == hash) {
240             return shadow_cache;
241         }
242
243     return NULL;
244 }
245
246 static double
247 _calculate_shadow_extents_scale (cairo_rectangle_int_t *extents,
248                                  int shadow_width,  int shadow_height)
249 {
250     double x_scale = (double)extents->width / (double)shadow_width;
251     double y_scale = (double)extents->height / (double)shadow_height;
252
253     return MIN (1.0, MIN (x_scale, y_scale));
254 }
255
256 static void
257 _cairo_shadow_cache_list_init (cairo_shadow_cache_list_t *shadow_cache_list,
258                                cairo_surface_t           *target)
259 {
260     cairo_status_t  status;
261     cairo_device_t *device = NULL;
262
263     if(target != NULL)
264         device = target->device;
265
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;
270     }
271     else if (target != NULL &&
272              target->backend &&
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;
277
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);
282             }
283         }
284     }
285 }
286
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)
292 {
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);
297
298     if (target->backend->get_shadow_surface)
299         shadow_surface = target->backend->get_shadow_surface (target,
300                                                               has_blur,
301                                                               shadow_width,
302                                                               shadow_height,
303                                                               &width_out,
304                                                               &height_out);
305     else {
306         if (has_blur) {
307             width_out = MIN (shadow_width, MAX_SHADOW_SIZE) * 0.5;
308             height_out = MIN (shadow_width, MAX_SHADOW_SIZE) * 0.5;
309         }
310         else {
311             width_out = MIN (shadow_width, MAX_SHADOW_SIZE);
312             height_out = MIN (shadow_width, MAX_SHADOW_SIZE);
313         }
314
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,
319                                                        content,
320                                                        width_out,
321                                                        height_out);
322         _cairo_surface_release_device_reference (shadow_surface);
323     }
324
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;
329
330     return shadow_surface;
331 }
332
333 /* A collection of routines to draw shadow*/
334
335 cairo_status_t
336 _cairo_surface_shadow_paint (cairo_surface_t            *target,
337                              cairo_operator_t            op,
338                              const cairo_pattern_t      *source,
339                              const cairo_clip_t         *clip,
340                              const cairo_shadow_t       *shadow)
341 {
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;
349
350     int                   shadow_width, shadow_height;
351     int                   x_blur, y_blur;
352     cairo_shadow_t        shadow_copy = *shadow;
353
354     cairo_matrix_t        m;
355     double                scale;
356     double                x_offset = shadow->x_offset;
357     double                y_offset = shadow->y_offset;
358     cairo_content_t       content;
359
360     unsigned long         hash = 0;
361     cairo_shadow_cache_t *shadow_cache = NULL;
362     cairo_device_t       *device = target->device;
363     unsigned long         size;
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);
370
371     cairo_shadow_cache_list_t shadow_cache_list;
372
373     if (shadow->type != CAIRO_SHADOW_DROP)
374         return CAIRO_STATUS_SUCCESS;
375
376     if (shadow->color.alpha == 0.0)
377         return CAIRO_STATUS_SUCCESS;
378
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;
382
383     if (_cairo_clip_is_all_clipped (clip))
384         return CAIRO_STATUS_SUCCESS;
385
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);
390     }
391
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;
396
397         color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
398                                                    shadow_copy.color.green,
399                                                    shadow_copy.color.blue,
400                                                    1.0);
401
402         status = _cairo_surface_paint_get_offset_extents (target,
403                                                           x_offset,
404                                                           y_offset,
405                                                           source,
406                                                           clip,
407                                                           &shadow_source.base,
408                                                           &shadow_extents,
409                                                           &bounded);
410         if (unlikely (status))
411             goto FINISH;
412
413         if (shadow_extents.width == 0 || shadow_extents.height == 0)
414             goto FINISH;
415
416         x_offset = shadow_extents.x - x_blur;
417         y_offset = shadow_extents.y - y_blur;
418
419         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
420         cairo_matrix_translate (&m, -x_offset, -y_offset);
421
422         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
423         cairo_pattern_set_matrix (shadow_pattern, &m);
424
425         status = _cairo_surface_mask (target, op, color_pattern,
426                                       shadow_pattern, clip);
427         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
428         goto FINISH;
429     }
430
431     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
432     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
433
434     x_blur = ceil (shadow_copy.x_blur);
435     y_blur = ceil (shadow_copy.y_blur);
436
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);
441
442     status = _cairo_surface_paint_get_offset_extents (target,
443                                                       x_offset, y_offset,
444                                                       source,
445                                                       clip,
446                                                       &shadow_source.base,
447                                                       &shadow_extents,
448                                                       &bounded);
449     if (unlikely (status))
450         goto FINISH;
451
452     if (shadow_extents.width == 0 && shadow_extents.height == 0)
453         goto FINISH;
454
455     x_offset = shadow_extents.x - x_blur;
456     y_offset = shadow_extents.y - y_blur;
457
458     shadow_width = ceil (shadow_extents.width + x_blur * 2);
459     shadow_height = ceil (shadow_extents.height + y_blur * 2);
460
461     shadow_surface = _cairo_ensure_shadow_surface (target,
462                                                    &shadow_surface_extents,
463                                                    x_blur, y_blur,
464                                                    shadow_width, shadow_height);
465     if (! shadow_surface || unlikely (shadow_surface->status))
466         goto FINISH;
467
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;
473
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))
478             goto FINISH;
479
480         if (device)
481             _cairo_surface_release_device_reference (cache_surface);
482     }
483
484     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
485                                              shadow_width,
486                                              shadow_height);
487     cairo_matrix_init_scale (&m, scale, scale);
488     cairo_matrix_translate (&m, -x_offset, -y_offset);
489
490     /* paint with offset and scale */
491     status = _cairo_surface_scale_translate_paint (shadow_surface,
492                                                    TRUE,
493                                                    &m,
494                                                    CAIRO_OPERATOR_OVER,
495                                                    &shadow_source.base,
496                                                    NULL);
497
498     if (unlikely (status))
499         goto FINISH;
500
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);
506
507     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
508     if (unlikely (status))
509         goto FINISH;
510
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))
516             goto FINISH;
517
518         cairo_pattern_destroy (shadow_pattern);
519
520         size = shadow_surface_extents.width * shadow_surface_extents.height;
521         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
522                                                        size);
523
524         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
525         _cairo_shadow_cache_init (shadow_cache,
526                                   cache_surface,
527                                   size,
528                                   hash,
529                                   x_blur,
530                                   y_blur,
531                                   scale);
532
533         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
534         *shadow_cache_list.size += size;
535
536         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
537         cairo_pattern_set_matrix (shadow_pattern, &m);
538
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,
543                                                    1.0);
544     }
545     else
546         cairo_pattern_set_matrix (shadow_pattern, &m);
547
548     status = _cairo_surface_mask (target, op,
549                                   color_pattern, shadow_pattern, clip);
550
551 FINISH:
552     cairo_pattern_destroy (color_pattern);
553
554     if (shadow_pattern)
555         cairo_pattern_destroy (shadow_pattern);
556
557     cairo_surface_destroy (shadow_surface);
558     cairo_surface_destroy (cache_surface);
559
560     if (shadow_cache_list.locked)
561         target->backend->shadow_cache_release (target);
562
563     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
564     ((cairo_pattern_t *)source)->shadow.type = shadow_type;
565     return status;
566 }
567
568 cairo_status_t
569 _cairo_surface_shadow_mask (cairo_surface_t             *target,
570                             cairo_operator_t             op,
571                             const cairo_pattern_t       *source,
572                             const cairo_pattern_t       *mask,
573                             const cairo_clip_t          *clip,
574                             const cairo_shadow_t        *shadow)
575 {
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;
585
586     int                   shadow_width, shadow_height;
587     int                   x_blur, y_blur;
588     cairo_shadow_t        shadow_copy = *shadow;
589
590     cairo_matrix_t        m;
591     double                scale;
592     double                x_offset = shadow->x_offset;
593     double                y_offset = shadow->y_offset;
594
595     unsigned long         hash = 0;
596     cairo_shadow_cache_t *shadow_cache = NULL;
597     cairo_device_t       *device = target->device;
598     unsigned long         size;
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);
605
606     cairo_shadow_cache_list_t shadow_cache_list;
607
608     if (shadow->type != CAIRO_SHADOW_DROP)
609         return CAIRO_STATUS_SUCCESS;
610
611     if (shadow->color.alpha == 0.0)
612         return CAIRO_STATUS_SUCCESS;
613
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;
617
618     if (_cairo_clip_is_all_clipped (clip))
619         return CAIRO_STATUS_SUCCESS;
620
621     if (shadow->x_blur == 0.0 && shadow->y_blur == 0.0) {
622         status = _cairo_surface_mask_get_offset_extents (target,
623                                                          x_offset,
624                                                          y_offset,
625                                                          source,
626                                                          mask,
627                                                          clip,
628                                                          &shadow_source.base,
629                                                          &shadow_mask.base,
630                                                          &shadow_extents,
631                                                          &bounded);
632         if (unlikely (status)) {
633             return status;
634         }
635
636         cairo_matrix_init_identity (&m);
637         cairo_matrix_translate (&m, -x_offset, -y_offset);
638
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,
643                                                       FALSE,
644                                                       &m,
645                                                       op,
646                                                       &shadow_source.base,
647                                                       &shadow_mask.base,
648                                                       clip);
649
650         ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
651         ((cairo_pattern_t *)source)->shadow.type = shadow_type;
652         return status;
653     }
654
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);
659     }
660
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;
665
666         color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
667                                                    shadow_copy.color.green,
668                                                    shadow_copy.color.blue,
669                                                    1.0);
670
671         status = _cairo_surface_mask_get_offset_extents (target,
672                                                           x_offset,
673                                                           y_offset,
674                                                           source,
675                                                           mask,
676                                                           clip,
677                                                           &shadow_source.base,
678                                                           &shadow_mask.base,
679                                                           &shadow_extents,
680                                                           &bounded);
681         if (unlikely (status))
682             goto FINISH;
683
684         if (shadow_extents.width == 0 || shadow_extents.height == 0)
685             goto FINISH;
686
687         x_offset = shadow_extents.x - x_blur;
688         y_offset = shadow_extents.y - y_blur;
689
690         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
691         cairo_matrix_translate (&m, -x_offset, -y_offset);
692
693         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
694         cairo_pattern_set_matrix (shadow_pattern, &m);
695
696         status = _cairo_surface_mask (target, op, color_pattern,
697                                       shadow_pattern, clip);
698         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
699         goto FINISH;
700     }
701
702     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
703     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
704
705     x_blur = ceil (shadow_copy.x_blur);
706     y_blur = ceil (shadow_copy.y_blur);
707
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);
712
713     status = _cairo_surface_mask_get_offset_extents (target,
714                                                      x_offset, y_offset,
715                                                      source,
716                                                      mask,
717                                                      clip,
718                                                      &shadow_source.base,
719                                                      &shadow_mask.base,
720                                                      &shadow_extents,
721                                                      &bounded);
722     if (unlikely (status))
723         goto FINISH;
724
725     if (shadow_extents.width == 0 && shadow_extents.height == 0)
726         goto FINISH;
727
728     x_offset = shadow_extents.x - x_blur;
729     y_offset = shadow_extents.y - y_blur;
730
731     shadow_width = ceil (shadow_extents.width + x_blur * 2);
732     shadow_height = ceil (shadow_extents.height + y_blur * 2);
733
734     shadow_surface = _cairo_ensure_shadow_surface (target,
735                                                    &shadow_surface_extents,
736                                                    x_blur, y_blur,
737                                                    shadow_width, shadow_height);
738     if (! shadow_surface || unlikely (shadow_surface->status))
739         goto FINISH;
740
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;
746
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))
751             goto FINISH;
752
753         if (device)
754             _cairo_surface_release_device_reference (cache_surface);
755     }
756
757     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
758                                              shadow_width,
759                                              shadow_height);
760     cairo_matrix_init_scale (&m, scale, scale);
761     cairo_matrix_translate (&m, -x_offset, -y_offset);
762
763     /* paint with offset and scale */
764     status = _cairo_surface_scale_translate_mask (shadow_surface,
765                                                    TRUE,
766                                                    &m,
767                                                    CAIRO_OPERATOR_OVER,
768                                                    &shadow_source.base,
769                                                    &shadow_mask.base,
770                                                    NULL);
771     if (unlikely (status))
772         goto FINISH;
773
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);
779
780     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
781     if (unlikely (status))
782         goto FINISH;
783
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))
789             goto FINISH;
790
791         cairo_pattern_destroy (shadow_pattern);
792
793         size = shadow_surface_extents.width * shadow_surface_extents.height;
794         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
795                                                        size);
796
797         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
798         _cairo_shadow_cache_init (shadow_cache,
799                                   cache_surface,
800                                   size,
801                                   hash,
802                                   x_blur,
803                                   y_blur,
804                                   scale);
805
806         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
807         *shadow_cache_list.size += size;
808
809         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
810         cairo_pattern_set_matrix (shadow_pattern, &m);
811
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,
816                                                    1.0);
817     }
818     else
819         cairo_pattern_set_matrix (shadow_pattern, &m);
820
821     status = _cairo_surface_mask (target, op,
822                                   color_pattern, shadow_pattern, clip);
823
824 FINISH:
825     cairo_pattern_destroy (color_pattern);
826
827     if (shadow_pattern)
828         cairo_pattern_destroy (shadow_pattern);
829
830     cairo_surface_destroy (shadow_surface);
831     cairo_surface_destroy (cache_surface);
832
833     if (shadow_cache_list.locked)
834         target->backend->shadow_cache_release (target);
835
836     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
837     ((cairo_pattern_t *)source)->shadow.type = shadow_type;
838     return status;
839 }
840
841 static cairo_status_t
842 _cairo_surface_inset_shadow_stroke (cairo_surface_t             *target,
843                                     cairo_operator_t             op,
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,
849                                     double                       tolerance,
850                                     cairo_antialias_t            antialias,
851                                     const cairo_clip_t          *clip,
852                                     const cairo_shadow_t        *shadow)
853 {
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;
865
866     int                   shadow_width, shadow_height;
867     int                   x_blur, y_blur;
868     cairo_shadow_t        shadow_copy = *shadow;
869     cairo_color_t         bg_color;
870
871     cairo_matrix_t        m;
872     double                scale;
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;
878     unsigned long         size;
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;
885
886     cairo_shadow_cache_list_t shadow_cache_list;
887
888     if (shadow->color.alpha == 0.0)
889         return CAIRO_STATUS_SUCCESS;
890
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);
895     }
896
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;
901
902         color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
903                                                    shadow_copy.color.green,
904                                                    shadow_copy.color.blue,
905                                                    1.0);
906
907         status = _cairo_surface_stroke_get_offset_extents (target,
908                                                            TRUE,
909                                                            x_offset,
910                                                            y_offset,
911                                                            source,
912                                                            path,
913                                                            stroke_style,
914                                                            ctm, ctm_inverse,
915                                                            tolerance, clip,
916                                                            &shadow_source.base,
917                                                            &shadow_path,
918                                                            &shadow_ctm,
919                                                            &shadow_ctm_inverse,
920                                                            &shadow_extents);
921         if (unlikely (status))
922             goto FINISH;
923
924         if (shadow_extents.width == 0 || shadow_extents.height == 0)
925             goto FINISH;
926
927         x_offset = shadow_extents.x - x_blur;
928         y_offset = shadow_extents.y - y_blur;
929
930         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
931         cairo_matrix_translate (&m, -x_offset, -y_offset);
932
933         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
934         cairo_pattern_set_matrix (shadow_pattern, &m);
935
936         status = _cairo_surface_stroke (target, op, shadow_pattern,
937                                         path, stroke_style,
938                                         ctm, ctm_inverse, tolerance,
939                                         antialias, clip);
940         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
941         goto FINISH;
942     }
943
944     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
945     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
946
947     x_blur = ceil (shadow_copy.x_blur);
948     y_blur = ceil (shadow_copy.y_blur);
949
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);
954
955     status = _cairo_surface_stroke_get_offset_extents (target,
956                                                        TRUE,
957                                                        x_offset, y_offset,
958                                                        source,
959                                                        path,
960                                                        stroke_style,
961                                                        ctm, ctm_inverse,
962                                                        tolerance, clip,
963                                                        &shadow_source.base,
964                                                        &shadow_path,
965                                                        &shadow_ctm,
966                                                        &shadow_ctm_inverse,
967                                                        &shadow_extents);
968     if (unlikely (status))
969         goto FINISH;
970
971     if (shadow_extents.width == 0 || shadow_extents.height == 0)
972         goto FINISH;
973
974     x_offset = shadow_extents.x  - x_blur;
975     y_offset = shadow_extents.y  - y_blur;
976
977     shadow_width = ceil (shadow_extents.width + x_blur * 2);
978     shadow_height = ceil (shadow_extents.height + y_blur * 2);
979
980     shadow_surface = _cairo_ensure_shadow_surface (target,
981                                                    &shadow_surface_extents,
982                                                    x_blur, y_blur,
983                                                    shadow_width, shadow_height);
984     if (! shadow_surface || unlikely (shadow_surface->status))
985         goto FINISH;
986
987     _cairo_surface_get_extents (shadow_surface, &extents);
988
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;
994
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))
999             goto FINISH;
1000
1001         if (device)
1002             _cairo_surface_release_device_reference (cache_surface);
1003     }
1004
1005     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1006                                              shadow_width,
1007                                              shadow_height);
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);
1012
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);
1018
1019     /* paint with offset and scale */
1020     status = _cairo_surface_scale_translate_stroke (shadow_surface,
1021                                                     &bg_color,
1022                                                     &m,
1023                                                     CAIRO_OPERATOR_CLEAR,
1024                                                     &shadow_source.base,
1025                                                     &shadow_path,
1026                                                     stroke_style,
1027                                                     &shadow_ctm,
1028                                                     &shadow_ctm_inverse,
1029                                                     tolerance,
1030                                                     antialias,
1031                                                     NULL);
1032
1033     if (unlikely (status))
1034         goto FINISH;
1035
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);
1041
1042     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern,
1043                                                     line_width * scale);
1044     if (unlikely (status))
1045         goto FINISH;
1046
1047     /* blur to mask surface */
1048     cairo_matrix_init_scale (&m, scale, scale);
1049     cairo_matrix_translate (&m, -x_offset, -y_offset);
1050
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))
1056             goto FINISH;
1057
1058         cairo_pattern_destroy (shadow_pattern);
1059
1060         size = shadow_surface_extents.width * shadow_surface_extents.height;
1061         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1062                                                        size);
1063
1064         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1065         _cairo_shadow_cache_init (shadow_cache,
1066                                   cache_surface,
1067                                   size,
1068                                   hash,
1069                                   x_blur,
1070                                   y_blur,
1071                                   scale);
1072
1073         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1074         *shadow_cache_list.size += size;
1075
1076         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1077         cairo_pattern_set_matrix (shadow_pattern, &m);
1078
1079         status = _cairo_surface_stroke (target, op, shadow_pattern,
1080                                         path, stroke_style, ctm,
1081                                         ctm_inverse, tolerance,
1082                                         antialias, clip);
1083
1084     }
1085     else {
1086         cairo_pattern_set_matrix (shadow_pattern, &m);
1087         status = _cairo_surface_stroke (target, op,  shadow_pattern,
1088                                         path, stroke_style,
1089                                         ctm, ctm_inverse,
1090                                         tolerance, antialias, clip);
1091     }
1092
1093 FINISH:
1094     _cairo_path_fixed_fini (&shadow_path);
1095     cairo_pattern_destroy (color_pattern);
1096
1097     if (shadow_pattern)
1098         cairo_pattern_destroy (shadow_pattern);
1099
1100     cairo_surface_destroy (shadow_surface);
1101     cairo_surface_destroy (cache_surface);
1102
1103     if (shadow_cache_list.locked)
1104         target->backend->shadow_cache_release (target);
1105
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;
1109     return status;
1110 }
1111
1112 cairo_status_t
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,
1120                               double                     tolerance,
1121                               cairo_antialias_t          antialias,
1122                               const cairo_clip_t                *clip,
1123                               const cairo_shadow_t      *shadow)
1124 {
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;
1136
1137     int                   shadow_width, shadow_height;
1138     int                   x_blur, y_blur;
1139     cairo_shadow_t        shadow_copy = *shadow;
1140
1141     cairo_matrix_t        m;
1142     double                scale;
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;
1148     unsigned long         size;
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;
1155
1156     cairo_shadow_cache_list_t shadow_cache_list;
1157
1158     if (shadow->type == CAIRO_SHADOW_NONE)
1159         return CAIRO_STATUS_SUCCESS;
1160
1161     if (shadow->color.alpha == 0.0)
1162         return CAIRO_STATUS_SUCCESS;
1163
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;
1167
1168     if (_cairo_clip_is_all_clipped (clip))
1169         return CAIRO_STATUS_SUCCESS;
1170
1171     if (shadow->type == CAIRO_SHADOW_INSET)
1172         return _cairo_surface_inset_shadow_stroke (target, op, source,
1173                                                    path, stroke_style,
1174                                                    ctm, ctm_inverse,
1175                                                    tolerance, antialias,
1176                                                    clip, shadow);
1177
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);
1182     }
1183
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;
1188
1189         color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red,
1190                                                    shadow_copy.color.green,
1191                                                    shadow_copy.color.blue,
1192                                                    1.0);
1193
1194         status = _cairo_surface_stroke_get_offset_extents (target,
1195                                                            FALSE,
1196                                                            x_offset,
1197                                                            y_offset,
1198                                                            source,
1199                                                            path,
1200                                                            stroke_style,
1201                                                            ctm, ctm_inverse,
1202                                                            tolerance, clip,
1203                                                            &shadow_source.base,
1204                                                            &shadow_path,
1205                                                            &shadow_ctm,
1206                                                            &shadow_ctm_inverse,
1207                                                            &shadow_extents);
1208         if (unlikely (status))
1209             goto FINISH;
1210
1211         if (shadow_extents.width == 0 || shadow_extents.height == 0)
1212             goto FINISH;
1213
1214         x_offset = shadow_extents.x - x_blur;
1215         y_offset = shadow_extents.y - y_blur;
1216
1217         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1218         cairo_matrix_translate (&m, -x_offset, -y_offset);
1219
1220         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1221         cairo_pattern_set_matrix (shadow_pattern, &m);
1222
1223         status = _cairo_surface_mask (target, op, color_pattern,
1224                                       shadow_pattern, clip);
1225         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1226         goto FINISH;
1227     }
1228
1229     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1230     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1231
1232     x_blur = ceil (shadow_copy.x_blur);
1233     y_blur = ceil (shadow_copy.y_blur);
1234
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);
1239
1240     status = _cairo_surface_stroke_get_offset_extents (target,
1241                                                        FALSE,
1242                                                        x_offset, y_offset,
1243                                                        source,
1244                                                        path,
1245                                                        stroke_style,
1246                                                        ctm, ctm_inverse,
1247                                                        tolerance, clip,
1248                                                        &shadow_source.base,
1249                                                        &shadow_path,
1250                                                        &shadow_ctm,
1251                                                        &shadow_ctm_inverse,
1252                                                        &shadow_extents);
1253     if (unlikely (status))
1254         goto FINISH;
1255
1256     if (shadow_extents.width == 0 || shadow_extents.height == 0)
1257         goto FINISH;
1258
1259     x_offset = shadow_extents.x - x_blur;
1260     y_offset = shadow_extents.y - y_blur;
1261
1262     shadow_width = ceil (shadow_extents.width + x_blur * 2);
1263     shadow_height = ceil (shadow_extents.height + y_blur * 2);
1264
1265     shadow_surface = _cairo_ensure_shadow_surface (target,
1266                                                    &shadow_surface_extents,
1267                                                    x_blur, y_blur,
1268                                                    shadow_width, shadow_height);
1269     if (! shadow_surface || unlikely (shadow_surface->status))
1270         goto FINISH;
1271
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;
1277
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))
1282             goto FINISH;
1283
1284         if (device)
1285             _cairo_surface_release_device_reference (cache_surface);
1286     }
1287
1288     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1289                                              shadow_width,
1290                                              shadow_height);
1291
1292     if (line_width * scale <= 1.0) 
1293         ((cairo_stroke_style_t *)stroke_style)->line_width = line_width / scale;
1294
1295     cairo_matrix_init_scale (&m, scale, scale);
1296     cairo_matrix_translate (&m, -x_offset, -y_offset);
1297
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,
1301                                                     &bg_color,
1302                                                     &m,
1303                                                     CAIRO_OPERATOR_OVER,
1304                                                     &shadow_source.base,
1305                                                     &shadow_path,
1306                                                     stroke_style,
1307                                                     &shadow_ctm,
1308                                                     &shadow_ctm_inverse,
1309                                                     tolerance,
1310                                                     antialias,
1311                                                     NULL);
1312
1313     if (unlikely (status))
1314         goto FINISH;
1315
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);
1321
1322     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern,
1323                                                     line_width * scale);
1324     if (unlikely (status))
1325         goto FINISH;
1326
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))
1332             goto FINISH;
1333
1334         cairo_pattern_destroy (shadow_pattern);
1335
1336         size = shadow_surface_extents.width * shadow_surface_extents.height;
1337         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1338                                                        size);
1339
1340         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1341         _cairo_shadow_cache_init (shadow_cache,
1342                                   cache_surface,
1343                                   size,
1344                                   hash,
1345                                   x_blur,
1346                                   y_blur,
1347                                   scale);
1348
1349         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1350         *shadow_cache_list.size += size;
1351
1352         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1353         cairo_pattern_set_matrix (shadow_pattern, &m);
1354
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,
1359                                                    1.0);
1360     }
1361     else
1362         cairo_pattern_set_matrix (shadow_pattern, &m);
1363
1364     status = _cairo_surface_mask (target, op,
1365                                   color_pattern, shadow_pattern, clip);
1366
1367 FINISH:
1368     _cairo_path_fixed_fini (&shadow_path);
1369     cairo_pattern_destroy (color_pattern);
1370
1371     if (shadow_pattern)
1372         cairo_pattern_destroy (shadow_pattern);
1373
1374     cairo_surface_destroy (shadow_surface);
1375     cairo_surface_destroy (cache_surface);
1376
1377     if (shadow_cache_list.locked)
1378         target->backend->shadow_cache_release (target);
1379
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;
1383     return status;
1384 }
1385
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,
1392                                   double                 tolerance,
1393                                   cairo_antialias_t      antialias,
1394                                   const cairo_clip_t    *clip,
1395                                   const cairo_shadow_t *shadow)
1396 {
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;
1408
1409     int                   shadow_width, shadow_height;
1410     int                   x_blur, y_blur;
1411     cairo_shadow_t        shadow_copy = *shadow;
1412
1413     cairo_matrix_t        m;
1414     double                scale;
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;
1420     unsigned long         size;
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);
1426
1427     cairo_shadow_cache_list_t shadow_cache_list;
1428
1429     if (shadow->color.alpha == 0.0)
1430         return CAIRO_STATUS_SUCCESS;
1431
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);
1436     }
1437
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,
1443                                                    1.0);
1444         x_blur = shadow_cache->x_blur;
1445         y_blur = shadow_cache->y_blur;
1446
1447         status = _cairo_surface_fill_get_offset_extents (target,
1448                                                          TRUE,
1449                                                          x_offset,
1450                                                          y_offset,
1451                                                          source,
1452                                                          path,
1453                                                          fill_rule,
1454                                                          clip,
1455                                                          &shadow_source.base,
1456                                                          &shadow_path,
1457                                                          &shadow_extents);
1458         if (unlikely (status))
1459             goto FINISH;
1460
1461         if (shadow_extents.width == 0 || shadow_extents.height == 0)
1462             goto FINISH;
1463
1464         x_offset = shadow_extents.x - x_blur;
1465         y_offset = shadow_extents.y - y_blur;
1466
1467         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1468         cairo_matrix_translate (&m, -x_offset, -y_offset);
1469
1470         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1471         cairo_pattern_set_matrix (shadow_pattern, &m);
1472
1473         if (! shadow->path_is_fill_with_spread)
1474             status = _cairo_surface_fill (target, op, shadow_pattern,
1475                                           path, fill_rule, tolerance,
1476                                           antialias, clip);
1477         else
1478             status = _cairo_surface_paint (target, op, shadow_pattern,
1479                                            clip);
1480
1481         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1482         goto FINISH;
1483     }
1484
1485     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1486     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1487
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);
1492
1493     x_blur = ceil (shadow_copy.x_blur);
1494     y_blur = ceil (shadow_copy.y_blur);
1495
1496     status = _cairo_surface_fill_get_offset_extents (target,
1497                                                      TRUE,
1498                                                      x_offset, y_offset,
1499                                                      source,
1500                                                      path,
1501                                                      fill_rule,
1502                                                      clip,
1503                                                      &shadow_source.base,
1504                                                      &shadow_path,
1505                                                      &shadow_extents);
1506     if (unlikely (status))
1507         goto FINISH;
1508
1509     if (shadow_extents.width == 0 && shadow_extents.height == 0)
1510         goto FINISH;
1511
1512     x_offset = shadow_extents.x  - x_blur;
1513     y_offset = shadow_extents.y  - y_blur;
1514
1515     shadow_width = ceil (shadow_extents.width + x_blur * 2);
1516     shadow_height = ceil (shadow_extents.height + y_blur * 2);
1517
1518     shadow_surface = _cairo_ensure_shadow_surface (target,
1519                                                    &shadow_surface_extents,
1520                                                    x_blur, y_blur,
1521                                                    shadow_width, shadow_height);
1522     if (! shadow_surface || unlikely (shadow_surface->status))
1523         goto FINISH;
1524
1525     _cairo_surface_get_extents (shadow_surface, &extents);
1526
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;
1532
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))
1537             goto FINISH;
1538
1539         if (device)
1540             _cairo_surface_release_device_reference (cache_surface);
1541     }
1542
1543     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1544                                              shadow_width,
1545                                              shadow_height);
1546     cairo_matrix_init_scale (&m, scale, scale);
1547     cairo_matrix_translate (&m, -x_offset, -y_offset);
1548
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,
1556                                                   &bg_color,
1557                                                   &m,
1558                                                   CAIRO_OPERATOR_CLEAR,
1559                                                   &shadow_source.base,
1560                                                   &shadow_path,
1561                                                   fill_rule,
1562                                                   tolerance,
1563                                                   antialias,
1564                                                   NULL);
1565
1566     if (unlikely (status))
1567         goto FINISH;
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);
1573
1574     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
1575     if (unlikely (status))
1576         goto FINISH;
1577
1578     /* blur to cache surface */
1579     cairo_matrix_init_scale (&m, scale, scale);
1580     cairo_matrix_translate (&m, -x_offset, -y_offset);
1581
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);
1586
1587         if (unlikely (status))
1588             goto FINISH;
1589
1590         cairo_pattern_destroy (shadow_pattern);
1591
1592         size = shadow_surface_extents.width * shadow_surface_extents.height;
1593         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1594                                                        size);
1595
1596         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1597         _cairo_shadow_cache_init (shadow_cache,
1598                                   cache_surface,
1599                                   size,
1600                                   hash,
1601                                   x_blur,
1602                                   y_blur,
1603                                   scale);
1604
1605         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1606         *shadow_cache_list.size += size;
1607
1608         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1609
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,
1614                                           antialias, clip);
1615         else
1616             status = _cairo_surface_paint (target, op, shadow_pattern,
1617                                            clip);
1618     }
1619     else {
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,
1624                                           antialias, clip);
1625         else
1626             status = _cairo_surface_paint (target, op, shadow_pattern,
1627                                            clip);
1628     }
1629 FINISH:
1630     _cairo_path_fixed_fini (&shadow_path);
1631     cairo_pattern_destroy (color_pattern);
1632
1633     if (shadow_pattern)
1634         cairo_pattern_destroy (shadow_pattern);
1635
1636     if (cache_surface)
1637         cairo_surface_destroy (cache_surface);
1638
1639     cairo_surface_destroy (shadow_surface);
1640
1641     if (shadow_cache_list.locked)
1642         target->backend->shadow_cache_release (target);
1643
1644     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
1645     ((cairo_pattern_t *)source)->shadow.type = shadow_type;
1646     return status;
1647 }
1648
1649 cairo_status_t
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,
1655                             double               tolerance,
1656                             cairo_antialias_t    antialias,
1657                             const cairo_clip_t  *clip,
1658                             const cairo_shadow_t *shadow)
1659 {
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;
1669
1670     int                   shadow_width, shadow_height;
1671     int                   x_blur, y_blur;
1672     cairo_shadow_t        shadow_copy = *shadow;
1673     cairo_color_t         bg_color;
1674
1675     cairo_matrix_t        m;
1676     double                scale;
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;
1682     unsigned long         size;
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);
1688
1689     cairo_shadow_cache_list_t shadow_cache_list;
1690
1691     if (shadow->type == CAIRO_SHADOW_NONE)
1692         return CAIRO_STATUS_SUCCESS;
1693
1694     if (shadow->color.alpha == 0.0)
1695         return CAIRO_STATUS_SUCCESS;
1696
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;
1700
1701     if (_cairo_clip_is_all_clipped (clip))
1702         return CAIRO_STATUS_SUCCESS;
1703
1704     if (shadow->type == CAIRO_SHADOW_INSET)
1705         return _cairo_surface_inset_shadow_fill (target, op, source,
1706                                                  path, fill_rule,
1707                                                  tolerance, antialias,
1708                                                  clip, shadow);
1709
1710     if (shadow->x_blur == 0.0 && shadow->y_blur == 0.0) {
1711         status = _cairo_surface_fill_get_offset_extents (target,
1712                                                          FALSE,
1713                                                          x_offset,
1714                                                          y_offset,
1715                                                          source,
1716                                                          path,
1717                                                          fill_rule,
1718                                                          clip,
1719                                                          &shadow_source.base,
1720                                                          &shadow_path,
1721                                                          &shadow_extents);
1722         if (unlikely (status)) {
1723             _cairo_path_fixed_fini (&shadow_path);
1724             return status;
1725         }
1726
1727         cairo_matrix_init_identity (&m);
1728         cairo_matrix_translate (&m, -x_offset, -y_offset);
1729
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,
1734                                                       NULL,
1735                                                       &m,
1736                                                       op,
1737                                                       &shadow_source.base,
1738                                                       &shadow_path,
1739                                                       fill_rule,
1740                                                       tolerance,
1741                                                       antialias,
1742                                                       clip);
1743
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;
1747         return status;
1748     }
1749
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);
1754     }
1755
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,
1761                                                    1.0);
1762         x_blur = shadow_cache->x_blur;
1763         y_blur = shadow_cache->y_blur;
1764
1765         status = _cairo_surface_fill_get_offset_extents (target,
1766                                                          FALSE,
1767                                                          x_offset,
1768                                                          y_offset,
1769                                                          source,
1770                                                          path,
1771                                                          fill_rule,
1772                                                          clip,
1773                                                          &shadow_source.base,
1774                                                          &shadow_path,
1775                                                          &shadow_extents);
1776         if (unlikely (status))
1777             goto FINISH;
1778
1779         if (shadow_extents.width == 0 || shadow_extents.height == 0)
1780             goto FINISH;
1781
1782         x_offset = shadow_extents.x - x_blur;
1783         y_offset = shadow_extents.y - y_blur;
1784
1785         cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale);
1786         cairo_matrix_translate (&m, -x_offset, -y_offset);
1787
1788         shadow_pattern = cairo_pattern_create_for_surface (shadow_cache->surface);
1789         cairo_pattern_set_matrix (shadow_pattern, &m);
1790
1791         status = _cairo_surface_mask (target, op, color_pattern,
1792                                       shadow_pattern, clip);
1793         cairo_list_move (&shadow_cache->link, shadow_cache_list.caches);
1794         goto FINISH;
1795     }
1796
1797     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1798     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1799
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);
1804
1805     x_blur = ceil (shadow_copy.x_blur);
1806     y_blur = ceil (shadow_copy.y_blur);
1807
1808     status = _cairo_surface_fill_get_offset_extents (target,
1809                                                      FALSE,
1810                                                      x_offset, y_offset,
1811                                                      source,
1812                                                      path,
1813                                                      fill_rule,
1814                                                      clip,
1815                                                      &shadow_source.base,
1816                                                      &shadow_path,
1817                                                      &shadow_extents);
1818     if (unlikely (status))
1819         goto FINISH;
1820
1821     if (shadow_extents.width == 0 && shadow_extents.height == 0)
1822         goto FINISH;
1823
1824     x_offset = shadow_extents.x - x_blur;
1825     y_offset = shadow_extents.y - y_blur;
1826
1827     shadow_width = ceil (shadow_extents.width + x_blur * 2);
1828     shadow_height = ceil (shadow_extents.height + y_blur * 2);
1829
1830     shadow_surface = _cairo_ensure_shadow_surface (target,
1831                                                    &shadow_surface_extents,
1832                                                    x_blur, y_blur,
1833                                                    shadow_width, shadow_height);
1834     if (! shadow_surface || unlikely (shadow_surface->status))
1835         goto FINISH;
1836
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;
1842
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))
1847             goto FINISH;
1848
1849         if (device)
1850             _cairo_surface_release_device_reference (cache_surface);
1851     }
1852
1853     scale = _calculate_shadow_extents_scale (&shadow_surface_extents,
1854                                              shadow_width,
1855                                              shadow_height);
1856     cairo_matrix_init_scale (&m, scale, scale);
1857     cairo_matrix_translate (&m, -x_offset, -y_offset);
1858
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,
1862                                                   &bg_color,
1863                                                   &m,
1864                                                   CAIRO_OPERATOR_OVER,
1865                                                   &shadow_source.base,
1866                                                   &shadow_path,
1867                                                   fill_rule,
1868                                                   tolerance,
1869                                                   antialias,
1870                                                   NULL);
1871
1872     if (unlikely (status))
1873         goto FINISH;
1874
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);
1880
1881     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
1882     if (unlikely (status))
1883         goto FINISH;
1884
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))
1890             goto FINISH;
1891
1892         cairo_pattern_destroy (shadow_pattern);
1893
1894         size = shadow_surface_extents.width * shadow_surface_extents.height;
1895         _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list,
1896                                                        size);
1897
1898         shadow_cache = malloc (sizeof (cairo_shadow_cache_t));
1899         _cairo_shadow_cache_init (shadow_cache,
1900                                   cache_surface,
1901                                   size,
1902                                   hash,
1903                                   x_blur,
1904                                   y_blur,
1905                                   scale);
1906
1907         cairo_list_add (&shadow_cache->link, shadow_cache_list.caches);
1908         *shadow_cache_list.size += size;
1909
1910         shadow_pattern = cairo_pattern_create_for_surface (cache_surface);
1911         cairo_pattern_set_matrix (shadow_pattern, &m);
1912
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,
1917                                                    1.0);
1918     }
1919     else
1920         cairo_pattern_set_matrix (shadow_pattern, &m);
1921
1922     status = _cairo_surface_mask (target, op,
1923                                   color_pattern, shadow_pattern, clip);
1924
1925 FINISH:
1926     _cairo_path_fixed_fini (&shadow_path);
1927     cairo_pattern_destroy (color_pattern);
1928
1929     if (shadow_pattern)
1930         cairo_pattern_destroy (shadow_pattern);
1931
1932     cairo_surface_destroy (cache_surface);
1933
1934     cairo_surface_destroy (shadow_surface);
1935
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;
1940
1941     return status;
1942 }
1943
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,
1950                                     int                         num_glyphs,
1951                                     const cairo_clip_t          *clip,
1952                                     const cairo_shadow_t        *shadow)
1953 {
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;
1965
1966     int                   shadow_width, shadow_height;
1967     int                   x_blur, y_blur;
1968     cairo_shadow_t        shadow_copy = *shadow;
1969
1970     cairo_matrix_t        m;
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;
1975
1976     if (shadow->color.alpha == 0.0)
1977         return CAIRO_STATUS_SUCCESS;
1978
1979     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
1980     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
1981
1982     x_blur = ceil (shadow_copy.x_blur);
1983     y_blur = ceil (shadow_copy.y_blur);
1984
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;
1989         goto FINISH;
1990     }
1991
1992     status = _cairo_surface_glyphs_get_offset_extents (target,
1993                                                        TRUE,
1994                                                        0, 0,
1995                                                        source,
1996                                                        scaled_font,
1997                                                        glyphs,
1998                                                        num_glyphs,
1999                                                        clip,
2000                                                        &shadow_source.base,
2001                                                        shadow_glyphs,
2002                                                        &shadow_extents);
2003     if (unlikely (status))
2004         goto FINISH;
2005
2006     if (shadow_extents.width == 0 && shadow_extents.height == 0)
2007         goto FINISH;
2008
2009     x_offset = shadow_extents.x - x_blur;
2010     y_offset = shadow_extents.y - y_blur;
2011
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));
2014
2015     if (target->backend->get_glyph_shadow_surface) {
2016         shadow_surface = target->backend->get_glyph_shadow_surface (target,
2017                                                                     shadow_width,
2018                                                                     shadow_height,
2019                                                                     FALSE);
2020     }
2021     else {
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,
2026                                                        content,
2027                                                        shadow_width,
2028                                                        shadow_height);
2029         _cairo_surface_release_device_reference (shadow_surface);
2030     }
2031     if (! shadow_surface || unlikely (shadow_surface->status))
2032         goto FINISH;
2033
2034     if(! _cairo_surface_get_extents (shadow_surface, &shadow_surface_extents))
2035         goto FINISH;
2036
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,
2041                                                                        0);
2042     }
2043     else {
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);
2049     }
2050     if (! mask_surface || unlikely (mask_surface->status))
2051         goto FINISH;
2052
2053     cairo_matrix_init_translate (&m, -x_offset, -y_offset);
2054
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);
2058
2059     status = _cairo_surface_translate_glyphs (mask_surface,
2060                                               &bg_color,
2061                                               &m,
2062                                               CAIRO_OPERATOR_OVER,
2063                                               color_pattern,
2064                                               scaled_font,
2065                                               shadow_glyphs,
2066                                               num_glyphs,
2067                                               NULL);
2068
2069     if (unlikely (status))
2070         goto FINISH;
2071
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);
2079
2080     status = _cairo_surface_paint (shadow_surface,
2081                                    CAIRO_OPERATOR_SOURCE,
2082                                    color_pattern, NULL);
2083     if (unlikely (status))
2084         goto FINISH;
2085
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);
2089
2090     status = _cairo_surface_mask (shadow_surface, CAIRO_OPERATOR_SOURCE,
2091                                   color_pattern, shadow_pattern,
2092                                   NULL);
2093     if (unlikely (status))
2094         goto FINISH;
2095
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))
2104         goto FINISH;
2105
2106     cairo_pattern_destroy (color_pattern);
2107     color_pattern = cairo_pattern_create_for_surface (mask_surface);
2108     cairo_pattern_set_matrix (color_pattern, &m);
2109
2110     cairo_matrix_translate (&m, -shadow->x_offset,
2111                             -shadow->y_offset);
2112     cairo_pattern_set_matrix (shadow_pattern, &m);
2113
2114     status = _cairo_surface_mask (target, op, shadow_pattern,
2115                                   color_pattern, clip);
2116 FINISH:
2117     cairo_pattern_destroy (color_pattern);
2118
2119     if (shadow_pattern)
2120         cairo_pattern_destroy (shadow_pattern);
2121
2122     free (shadow_glyphs);
2123
2124     cairo_surface_destroy (shadow_surface);
2125     cairo_surface_destroy (mask_surface);
2126
2127     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
2128     ((cairo_pattern_t *)source)->shadow.type = shadow_type;
2129     return status;
2130 }
2131
2132 cairo_status_t
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,
2138                               int                        num_glyphs,
2139                               const cairo_clip_t        *clip,
2140                               const cairo_shadow_t      *shadow)
2141 {
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;
2149
2150     cairo_glyph_t        *shadow_glyphs;
2151     cairo_content_t       content;
2152     cairo_color_t         bg_color;
2153     int                   shadow_width, shadow_height;
2154     int                   x_blur, y_blur;
2155     cairo_shadow_t        shadow_copy = *shadow;
2156
2157     cairo_matrix_t        m;
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;
2162
2163     if (shadow->type == CAIRO_SHADOW_NONE)
2164         return CAIRO_STATUS_SUCCESS;
2165
2166     if (shadow->color.alpha == 0.0)
2167         return CAIRO_STATUS_SUCCESS;
2168
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;
2172
2173     if (_cairo_clip_is_all_clipped (clip))
2174         return CAIRO_STATUS_SUCCESS;
2175
2176     if (shadow->type == CAIRO_SHADOW_INSET)
2177         return _cairo_surface_inset_shadow_glyphs (target, op, source,
2178                                                    scaled_font, glyphs,
2179                                                    num_glyphs, clip,
2180                                                    shadow);
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;
2185
2186     ((cairo_pattern_t *)source)->shadow.type = CAIRO_SHADOW_NONE;
2187     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = FALSE;
2188
2189     x_blur = ceil (shadow_copy.x_blur);
2190     y_blur = ceil (shadow_copy.y_blur);
2191
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);
2196
2197     status = _cairo_surface_glyphs_get_offset_extents (target,
2198                                                        FALSE,
2199                                                        x_offset, y_offset,
2200                                                        source,
2201                                                        scaled_font,
2202                                                        glyphs,
2203                                                        num_glyphs,
2204                                                        clip,
2205                                                        &shadow_source.base,
2206                                                        shadow_glyphs,
2207                                                        &shadow_extents);
2208     if (unlikely (status))
2209         goto FINISH;
2210
2211     if (shadow_extents.width == 0 && shadow_extents.height == 0)
2212         goto FINISH;
2213
2214     x_offset = shadow_extents.x - x_blur;
2215     y_offset = shadow_extents.y - y_blur;
2216
2217     shadow_width = ceil (shadow_extents.width + x_blur * 2);
2218     shadow_height = ceil (shadow_extents.height + y_blur * 2);
2219
2220     if (target->backend->get_glyph_shadow_surface)
2221         shadow_surface = target->backend->get_glyph_shadow_surface (target,
2222                                                                     shadow_width,
2223                                                                     shadow_height,
2224                                                                     FALSE);
2225     else {
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,
2230                                                        content,
2231                                                        shadow_width,
2232                                                        shadow_height);
2233         _cairo_surface_release_device_reference (shadow_surface);
2234     }
2235     if (! shadow_surface || unlikely (shadow_surface->status))
2236         goto FINISH;
2237
2238     if(! _cairo_surface_get_extents (shadow_surface, &shadow_surface_extents))
2239         goto FINISH;
2240
2241     cairo_matrix_init_translate (&m, -x_offset, -y_offset);
2242
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,
2246                                               &bg_color,
2247                                               &m,
2248                                               CAIRO_OPERATOR_OVER,
2249                                               &shadow_source.base,
2250                                               scaled_font,
2251                                               shadow_glyphs,
2252                                               num_glyphs,
2253                                               NULL);
2254
2255     if (unlikely (status))
2256         goto FINISH;
2257
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);
2263
2264     status = _cairo_pattern_create_gaussian_matrix (shadow_pattern, 1024);
2265     if (unlikely (status))
2266         goto FINISH;
2267
2268     cairo_pattern_set_matrix (shadow_pattern, &m);
2269
2270     status = _cairo_surface_mask (target, op, color_pattern,
2271                                   shadow_pattern, NULL);
2272
2273 FINISH:
2274     cairo_pattern_destroy (color_pattern);
2275
2276     if (shadow_pattern)
2277         cairo_pattern_destroy (shadow_pattern);
2278
2279     free (shadow_glyphs);
2280
2281     cairo_surface_destroy (shadow_surface);
2282
2283     ((cairo_pattern_t *)source)->shadow.draw_shadow_only = draw_shadow_only;
2284     ((cairo_pattern_t *)source)->shadow.type = shadow_type;
2285     return status;
2286 }