Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-shape-mask-compositor.c
1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2012 Intel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is University of Southern
32  * California.
33  *
34  * Contributor(s):
35  *      Chris Wilson <chris@chris-wilson.co.uk>
36  */
37
38 #include "cairoint.h"
39
40 #include "cairo-compositor-private.h"
41 #include "cairo-clip-private.h"
42 #include "cairo-pattern-private.h"
43 #include "cairo-surface-private.h"
44 #include "cairo-surface-offset-private.h"
45
46 static cairo_int_status_t
47 _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
48                                      cairo_composite_rectangles_t *extents,
49                                      const cairo_path_fixed_t   *path,
50                                      const cairo_stroke_style_t *style,
51                                      const cairo_matrix_t       *ctm,
52                                      const cairo_matrix_t       *ctm_inverse,
53                                      double              tolerance,
54                                      cairo_antialias_t   antialias)
55 {
56     cairo_surface_t *mask;
57     cairo_surface_pattern_t pattern;
58     cairo_int_status_t status;
59     cairo_clip_t *clip;
60
61     if (! extents->is_bounded)
62         return CAIRO_INT_STATUS_UNSUPPORTED;
63
64     TRACE ((stderr, "%s\n", __FUNCTION__));
65     mask = _cairo_surface_create_similar_scratch (extents->surface,
66                                                   CAIRO_CONTENT_ALPHA,
67                                                   extents->bounded.width,
68                                                   extents->bounded.height);
69     if (unlikely (mask->status))
70         return mask->status;
71
72     clip = extents->clip;
73     if (! _cairo_clip_is_region (clip))
74         clip = _cairo_clip_copy_region (clip);
75
76     if (! mask->is_clear) {
77         status = _cairo_surface_offset_paint (mask,
78                                               extents->bounded.x,
79                                               extents->bounded.y,
80                                               CAIRO_OPERATOR_CLEAR,
81                                               &_cairo_pattern_clear.base,
82                                               clip);
83         if (unlikely (status))
84             goto error;
85     }
86
87     status = _cairo_surface_offset_stroke (mask,
88                                            extents->bounded.x,
89                                            extents->bounded.y,
90                                            CAIRO_OPERATOR_ADD,
91                                            &_cairo_pattern_white.base,
92                                            path, style, ctm, ctm_inverse,
93                                            tolerance, antialias,
94                                            clip);
95     if (unlikely (status))
96         goto error;
97
98     if (clip != extents->clip) {
99         status = _cairo_clip_combine_with_surface (extents->clip, mask,
100                                                    extents->bounded.x,
101                                                    extents->bounded.y);
102         if (unlikely (status))
103             goto error;
104     }
105
106     _cairo_pattern_init_for_surface (&pattern, mask);
107     cairo_matrix_init_translate (&pattern.base.matrix,
108                                  -extents->bounded.x,
109                                  -extents->bounded.y);
110     pattern.base.filter = CAIRO_FILTER_NEAREST;
111     pattern.base.extend = CAIRO_EXTEND_NONE;
112     if (extents->op == CAIRO_OPERATOR_SOURCE) {
113         status = _cairo_surface_mask (extents->surface,
114                                       CAIRO_OPERATOR_DEST_OUT,
115                                       &_cairo_pattern_white.base,
116                                       &pattern.base,
117                                       clip);
118         if ((status == CAIRO_INT_STATUS_SUCCESS)) {
119             status = _cairo_surface_mask (extents->surface,
120                                           CAIRO_OPERATOR_ADD,
121                                           &extents->source_pattern.base,
122                                           &pattern.base,
123                                           clip);
124         }
125     } else {
126         status = _cairo_surface_mask (extents->surface,
127                                       extents->op,
128                                       &extents->source_pattern.base,
129                                       &pattern.base,
130                                       clip);
131     }
132     _cairo_pattern_fini (&pattern.base);
133
134 error:
135     cairo_surface_destroy (mask);
136     if (clip != extents->clip)
137         _cairo_clip_destroy (clip);
138     return status;
139 }
140
141 static cairo_int_status_t
142 _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
143                                    cairo_composite_rectangles_t *extents,
144                                    const cairo_path_fixed_t     *path,
145                                    cairo_fill_rule_t     fill_rule,
146                                    double                        tolerance,
147                                    cairo_antialias_t     antialias)
148 {
149     cairo_surface_t *mask;
150     cairo_surface_pattern_t pattern;
151     cairo_int_status_t status;
152     cairo_clip_t *clip;
153
154     TRACE ((stderr, "%s\n", __FUNCTION__));
155
156     if (! extents->is_bounded)
157         return CAIRO_INT_STATUS_UNSUPPORTED;
158
159     mask = _cairo_surface_create_similar_scratch (extents->surface,
160                                                   CAIRO_CONTENT_ALPHA,
161                                                   extents->bounded.width,
162                                                   extents->bounded.height);
163     if (unlikely (mask->status))
164         return mask->status;
165
166     clip = extents->clip;
167     if (! _cairo_clip_is_region (clip))
168         clip = _cairo_clip_copy_region (clip);
169
170     if (! mask->is_clear) {
171         status = _cairo_surface_offset_paint (mask,
172                                               extents->bounded.x,
173                                               extents->bounded.y,
174                                               CAIRO_OPERATOR_CLEAR,
175                                               &_cairo_pattern_clear.base,
176                                               clip);
177         if (unlikely (status))
178             goto error;
179     }
180
181     status = _cairo_surface_offset_fill (mask,
182                                          extents->bounded.x,
183                                          extents->bounded.y,
184                                          CAIRO_OPERATOR_ADD,
185                                          &_cairo_pattern_white.base,
186                                          path, fill_rule, tolerance, antialias,
187                                          clip);
188     if (unlikely (status))
189         goto error;
190
191     if (clip != extents->clip) {
192         status = _cairo_clip_combine_with_surface (extents->clip, mask,
193                                                    extents->bounded.x,
194                                                    extents->bounded.y);
195         if (unlikely (status))
196             goto error;
197     }
198
199     _cairo_pattern_init_for_surface (&pattern, mask);
200     cairo_matrix_init_translate (&pattern.base.matrix,
201                                  -extents->bounded.x,
202                                  -extents->bounded.y);
203     pattern.base.filter = CAIRO_FILTER_NEAREST;
204     pattern.base.extend = CAIRO_EXTEND_NONE;
205     if (extents->op == CAIRO_OPERATOR_SOURCE) {
206         status = _cairo_surface_mask (extents->surface,
207                                       CAIRO_OPERATOR_DEST_OUT,
208                                       &_cairo_pattern_white.base,
209                                       &pattern.base,
210                                       clip);
211         if ((status == CAIRO_INT_STATUS_SUCCESS)) {
212             status = _cairo_surface_mask (extents->surface,
213                                           CAIRO_OPERATOR_ADD,
214                                           &extents->source_pattern.base,
215                                           &pattern.base,
216                                           clip);
217         }
218     } else {
219         status = _cairo_surface_mask (extents->surface,
220                                       extents->op,
221                                       &extents->source_pattern.base,
222                                       &pattern.base,
223                                       clip);
224     }
225     _cairo_pattern_fini (&pattern.base);
226
227 error:
228     if (clip != extents->clip)
229         _cairo_clip_destroy (clip);
230     cairo_surface_destroy (mask);
231     return status;
232 }
233
234 static cairo_int_status_t
235 _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
236                                      cairo_composite_rectangles_t *extents,
237                                      cairo_scaled_font_t        *scaled_font,
238                                      cairo_glyph_t              *glyphs,
239                                      int                         num_glyphs,
240                                      cairo_bool_t                overlap)
241 {
242     cairo_surface_t *mask;
243     cairo_surface_pattern_t pattern;
244     cairo_int_status_t status;
245     cairo_clip_t *clip;
246
247     if (! extents->is_bounded)
248         return CAIRO_INT_STATUS_UNSUPPORTED;
249
250     TRACE ((stderr, "%s\n", __FUNCTION__));
251     mask = _cairo_surface_create_similar_scratch (extents->surface,
252                                                   CAIRO_CONTENT_ALPHA,
253                                                   extents->bounded.width,
254                                                   extents->bounded.height);
255     if (unlikely (mask->status))
256         return mask->status;
257
258     clip = extents->clip;
259     if (! _cairo_clip_is_region (clip))
260         clip = _cairo_clip_copy_region (clip);
261
262     if (! mask->is_clear) {
263         status = _cairo_surface_offset_paint (mask,
264                                               extents->bounded.x,
265                                               extents->bounded.y,
266                                               CAIRO_OPERATOR_CLEAR,
267                                               &_cairo_pattern_clear.base,
268                                               clip);
269         if (unlikely (status))
270             goto error;
271     }
272
273     status = _cairo_surface_offset_glyphs (mask,
274                                            extents->bounded.x,
275                                            extents->bounded.y,
276                                            CAIRO_OPERATOR_ADD,
277                                            &_cairo_pattern_white.base,
278                                            scaled_font, glyphs, num_glyphs,
279                                            clip);
280     if (unlikely (status))
281         goto error;
282
283     if (clip != extents->clip) {
284         status = _cairo_clip_combine_with_surface (extents->clip, mask,
285                                                    extents->bounded.x,
286                                                    extents->bounded.y);
287         if (unlikely (status))
288             goto error;
289     }
290
291     _cairo_pattern_init_for_surface (&pattern, mask);
292     cairo_matrix_init_translate (&pattern.base.matrix,
293                                  -extents->bounded.x,
294                                  -extents->bounded.y);
295     pattern.base.filter = CAIRO_FILTER_NEAREST;
296     pattern.base.extend = CAIRO_EXTEND_NONE;
297     if (extents->op == CAIRO_OPERATOR_SOURCE) {
298         status = _cairo_surface_mask (extents->surface,
299                                       CAIRO_OPERATOR_DEST_OUT,
300                                       &_cairo_pattern_white.base,
301                                       &pattern.base,
302                                       clip);
303         if ((status == CAIRO_INT_STATUS_SUCCESS)) {
304             status = _cairo_surface_mask (extents->surface,
305                                           CAIRO_OPERATOR_ADD,
306                                           &extents->source_pattern.base,
307                                           &pattern.base,
308                                           clip);
309         }
310     } else {
311         status = _cairo_surface_mask (extents->surface,
312                                       extents->op,
313                                       &extents->source_pattern.base,
314                                       &pattern.base,
315                                       clip);
316     }
317     _cairo_pattern_fini (&pattern.base);
318
319 error:
320     if (clip != extents->clip)
321         _cairo_clip_destroy (clip);
322     cairo_surface_destroy (mask);
323     return status;
324 }
325
326 void
327 _cairo_shape_mask_compositor_init (cairo_compositor_t *compositor,
328                                    const cairo_compositor_t  *delegate)
329 {
330     compositor->delegate = delegate;
331
332     compositor->paint  = NULL;
333     compositor->mask   = NULL;
334     compositor->fill   = _cairo_shape_mask_compositor_fill;
335     compositor->stroke = _cairo_shape_mask_compositor_stroke;
336     compositor->glyphs = _cairo_shape_mask_compositor_glyphs;
337 }