827348978a5e851b96289eb1265aa2e82571c72f
[framework/graphics/cairo.git] / src / cairo-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 © 2011 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-damage-private.h"
42 #include "cairo-error-private.h"
43
44 cairo_int_status_t
45 _cairo_compositor_paint (const cairo_compositor_t       *compositor,
46                          cairo_surface_t                *surface,
47                          cairo_operator_t                op,
48                          const cairo_pattern_t          *source,
49                          const cairo_clip_t             *clip)
50 {
51     cairo_composite_rectangles_t extents;
52     cairo_int_status_t status;
53     cairo_bool_t initialized = TRUE;
54
55     TRACE ((stderr, "%s\n", __FUNCTION__));
56
57     if (compositor->lazy_init) {
58         status = _cairo_composite_rectangles_lazy_init_for_paint (&extents,
59                                                                   surface,
60                                                                   op, source,
61                                                                   clip);
62         initialized = FALSE;
63     }
64     else
65         status = _cairo_composite_rectangles_init_for_paint (&extents,
66                                                              surface,
67                                                              op, source,
68                                                              clip);
69     if (unlikely (status))
70         return status;
71
72     do {
73         while (compositor->paint == NULL)
74             compositor = compositor->delegate;
75
76         if (! compositor->lazy_init && ! initialized) {
77             /* XXX: we should do better instead of re-init */
78             _cairo_composite_rectangles_fini (&extents);
79             status = _cairo_composite_rectangles_init_for_paint (&extents,
80                                                                  surface,
81                                                                  op, source,
82                                                                  clip);
83             initialized = TRUE;
84
85             if (unlikely (status))
86                 return status;
87         }
88
89         status = compositor->paint (compositor, &extents);
90
91         compositor = compositor->delegate;
92     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
93
94     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
95         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
96                 __FUNCTION__,
97                 extents.unbounded.x, extents.unbounded.y,
98                 extents.unbounded.width, extents.unbounded.height));
99         surface->damage = _cairo_damage_add_rectangle (surface->damage,
100                                                        &extents.unbounded);
101     }
102
103     _cairo_composite_rectangles_fini (&extents);
104
105     return status;
106 }
107
108 cairo_int_status_t
109 _cairo_compositor_mask (const cairo_compositor_t        *compositor,
110                         cairo_surface_t                 *surface,
111                         cairo_operator_t                 op,
112                         const cairo_pattern_t           *source,
113                         const cairo_pattern_t           *mask,
114                         const cairo_clip_t              *clip)
115 {
116     cairo_composite_rectangles_t extents;
117     cairo_int_status_t status;
118     cairo_bool_t initialized = TRUE;
119
120     TRACE ((stderr, "%s\n", __FUNCTION__));
121
122     if (compositor->lazy_init) {
123         status = _cairo_composite_rectangles_lazy_init_for_mask (&extents,
124                                                                  surface,
125                                                                  op, source,
126                                                                  mask, clip);
127         initialized = FALSE;
128     } else
129         status = _cairo_composite_rectangles_init_for_mask (&extents,
130                                                             surface,
131                                                             op, source,
132                                                             mask, clip);
133     if (unlikely (status))
134         return status;
135
136     do {
137         while (compositor->mask == NULL)
138             compositor = compositor->delegate;
139
140         if (! compositor->lazy_init && ! initialized) {
141             /* XXX: we should do better instead of re-init */
142             _cairo_composite_rectangles_fini (&extents);
143             status = _cairo_composite_rectangles_init_for_mask (&extents,
144                                                                 surface,
145                                                                 op, source,
146                                                                 mask, clip);
147             initialized = TRUE;
148
149             if (unlikely (status))
150                 return status;
151         }
152
153         status = compositor->mask (compositor, &extents);
154
155         compositor = compositor->delegate;
156     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
157
158     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
159         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
160                 __FUNCTION__,
161                 extents.unbounded.x, extents.unbounded.y,
162                 extents.unbounded.width, extents.unbounded.height));
163         surface->damage = _cairo_damage_add_rectangle (surface->damage,
164                                                        &extents.unbounded);
165     }
166
167     _cairo_composite_rectangles_fini (&extents);
168
169     return status;
170 }
171
172 cairo_int_status_t
173 _cairo_compositor_stroke (const cairo_compositor_t      *compositor,
174                           cairo_surface_t               *surface,
175                           cairo_operator_t               op,
176                           const cairo_pattern_t         *source,
177                           const cairo_path_fixed_t      *path,
178                           const cairo_stroke_style_t    *style,
179                           const cairo_matrix_t          *ctm,
180                           const cairo_matrix_t          *ctm_inverse,
181                           double                         tolerance,
182                           cairo_antialias_t              antialias,
183                           const cairo_clip_t            *clip)
184 {
185     cairo_composite_rectangles_t extents;
186     cairo_int_status_t status;
187     cairo_bool_t initialized = TRUE;
188
189     TRACE ((stderr, "%s\n", __FUNCTION__));
190
191     if (compositor->lazy_init) {
192         status = _cairo_composite_rectangles_lazy_init_for_stroke (&extents,
193                                                                    surface,
194                                                                    op, source,
195                                                                    path, style,
196                                                                    ctm, clip);
197         initialized = FALSE;
198     }
199     else
200         status = _cairo_composite_rectangles_init_for_stroke (&extents,
201                                                               surface,
202                                                               op, source,
203                                                               path, style,
204                                                               ctm, clip);
205     if (unlikely (status))
206         return status;
207
208     do {
209         while (compositor->stroke == NULL)
210             compositor = compositor->delegate;
211
212         if (! compositor->lazy_init && ! initialized) {
213             /* XXX: we should do better instead of re-init */
214             _cairo_composite_rectangles_fini (&extents);
215             status = _cairo_composite_rectangles_init_for_stroke (&extents,
216                                                                   surface,
217                                                                   op,
218                                                                   source,
219                                                                   path,
220                                                                   style,
221                                                                   ctm,
222                                                                   clip);
223             initialized = TRUE;
224
225             if (unlikely (status))
226                 return status;
227         }
228
229         status = compositor->stroke (compositor, &extents,
230                                      path, style, ctm, ctm_inverse,
231                                      tolerance, antialias);
232
233         compositor = compositor->delegate;
234     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
235
236     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
237         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
238                 __FUNCTION__,
239                 extents.unbounded.x, extents.unbounded.y,
240                 extents.unbounded.width, extents.unbounded.height));
241         surface->damage = _cairo_damage_add_rectangle (surface->damage,
242                                                        &extents.unbounded);
243     }
244
245     _cairo_composite_rectangles_fini (&extents);
246
247     return status;
248 }
249
250 cairo_int_status_t
251 _cairo_compositor_fill (const cairo_compositor_t        *compositor,
252                         cairo_surface_t                 *surface,
253                         cairo_operator_t                 op,
254                         const cairo_pattern_t           *source,
255                         const cairo_path_fixed_t        *path,
256                         cairo_fill_rule_t                fill_rule,
257                         double                           tolerance,
258                         cairo_antialias_t                antialias,
259                         const cairo_clip_t              *clip)
260 {
261     cairo_composite_rectangles_t extents;
262     cairo_int_status_t status;
263     cairo_bool_t initialized = TRUE;
264
265     TRACE ((stderr, "%s\n", __FUNCTION__));
266
267     if (compositor->lazy_init) {
268         status = _cairo_composite_rectangles_lazy_init_for_fill (&extents,
269                                                                  surface,
270                                                                  op, source,
271                                                                  path, clip);
272         initialized = FALSE;
273     }
274     else
275         status = _cairo_composite_rectangles_init_for_fill (&extents,
276                                                             surface,
277                                                             op, source,
278                                                             path, clip);
279     if (unlikely (status))
280         return status;
281
282     do {
283         while (compositor->fill == NULL)
284             compositor = compositor->delegate;
285
286         if (! compositor->lazy_init && ! initialized) {
287             /* XXX: we should do better instead of re-init */
288             _cairo_composite_rectangles_fini (&extents);
289             status = _cairo_composite_rectangles_init_for_fill (&extents,
290                                                                 surface,
291                                                                 op, source,
292                                                                 path, clip);
293             initialized = TRUE;
294
295             if (unlikely (status))
296                 return status;
297         }
298
299         status = compositor->fill (compositor, &extents,
300                                    path, fill_rule, tolerance, antialias);
301
302         compositor = compositor->delegate;
303     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
304
305     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
306         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
307                 __FUNCTION__,
308                 extents.unbounded.x, extents.unbounded.y,
309                 extents.unbounded.width, extents.unbounded.height));
310         surface->damage = _cairo_damage_add_rectangle (surface->damage,
311                                                        &extents.unbounded);
312     }
313
314     _cairo_composite_rectangles_fini (&extents);
315
316     return status;
317 }
318
319 cairo_int_status_t
320 _cairo_compositor_glyphs (const cairo_compositor_t              *compositor,
321                           cairo_surface_t                       *surface,
322                           cairo_operator_t                       op,
323                           const cairo_pattern_t                 *source,
324                           cairo_glyph_t                         *glyphs,
325                           int                                    num_glyphs,
326                           cairo_scaled_font_t                   *scaled_font,
327                           const cairo_clip_t                    *clip)
328 {
329     cairo_composite_rectangles_t extents;
330     cairo_bool_t overlap;
331     cairo_int_status_t status;
332     cairo_bool_t initialized = TRUE;
333
334     TRACE ((stderr, "%s\n", __FUNCTION__));
335
336     if (compositor->lazy_init) {
337         status = _cairo_composite_rectangles_lazy_init_for_glyphs (&extents, surface,
338                                                                   op, source,
339                                                                   scaled_font,
340                                                                   glyphs, num_glyphs,
341                                                                   clip, &overlap);
342         initialized = FALSE;
343     } else
344         status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
345                                                              op, source,
346                                                              scaled_font,
347                                                              glyphs, num_glyphs,
348                                                              clip, &overlap);
349     if (unlikely (status))
350         return status;
351
352     do {
353         while (compositor->glyphs == NULL)
354             compositor = compositor->delegate;
355
356         if (! compositor->lazy_init && ! initialized) {
357             /* XXX: we should do better instead of re-init */
358             _cairo_composite_rectangles_fini (&extents);
359             status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
360                                                                  op, source,
361                                                                  scaled_font,
362                                                                  glyphs, num_glyphs,
363                                                                  clip, &overlap);
364             initialized = TRUE;
365
366             if (unlikely (status))
367                 return status;
368         }
369
370         status = compositor->glyphs (compositor, &extents,
371                                      scaled_font, glyphs, num_glyphs, overlap);
372
373         compositor = compositor->delegate;
374     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
375
376     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
377         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
378                 __FUNCTION__,
379                 extents.unbounded.x, extents.unbounded.y,
380                 extents.unbounded.width, extents.unbounded.height));
381         surface->damage = _cairo_damage_add_rectangle (surface->damage,
382                                                        &extents.unbounded);
383     }
384
385     _cairo_composite_rectangles_fini (&extents);
386
387     return status;
388 }