Tizen 2.0 Release
[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 (_cairo_pen_vertices_needed (tolerance, style->line_width/2, ctm) <= 1)
192         return CAIRO_INT_STATUS_NOTHING_TO_DO;
193
194     if (compositor->lazy_init) {
195         status = _cairo_composite_rectangles_lazy_init_for_stroke (&extents,
196                                                                    surface,
197                                                                    op, source,
198                                                                    path, style,
199                                                                    ctm, clip);
200         initialized = FALSE;
201     }
202     else
203         status = _cairo_composite_rectangles_init_for_stroke (&extents,
204                                                               surface,
205                                                               op, source,
206                                                               path, style,
207                                                               ctm, clip);
208     if (unlikely (status))
209         return status;
210
211     do {
212         while (compositor->stroke == NULL)
213             compositor = compositor->delegate;
214
215         if (! compositor->lazy_init && ! initialized) {
216             /* XXX: we should do better instead of re-init */
217             _cairo_composite_rectangles_fini (&extents);
218             status = _cairo_composite_rectangles_init_for_stroke (&extents,
219                                                                   surface,
220                                                                   op,
221                                                                   source,
222                                                                   path,
223                                                                   style,
224                                                                   ctm,
225                                                                   clip);
226             initialized = TRUE;
227
228             if (unlikely (status))
229                 return status;
230         }
231
232         status = compositor->stroke (compositor, &extents,
233                                      path, style, ctm, ctm_inverse,
234                                      tolerance, antialias);
235
236         compositor = compositor->delegate;
237     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
238
239     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
240         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
241                 __FUNCTION__,
242                 extents.unbounded.x, extents.unbounded.y,
243                 extents.unbounded.width, extents.unbounded.height));
244         surface->damage = _cairo_damage_add_rectangle (surface->damage,
245                                                        &extents.unbounded);
246     }
247
248     _cairo_composite_rectangles_fini (&extents);
249
250     return status;
251 }
252
253 cairo_int_status_t
254 _cairo_compositor_fill (const cairo_compositor_t        *compositor,
255                         cairo_surface_t                 *surface,
256                         cairo_operator_t                 op,
257                         const cairo_pattern_t           *source,
258                         const cairo_path_fixed_t        *path,
259                         cairo_fill_rule_t                fill_rule,
260                         double                           tolerance,
261                         cairo_antialias_t                antialias,
262                         const cairo_clip_t              *clip)
263 {
264     cairo_composite_rectangles_t extents;
265     cairo_int_status_t status;
266     cairo_bool_t initialized = TRUE;
267
268     TRACE ((stderr, "%s\n", __FUNCTION__));
269
270     if (compositor->lazy_init) {
271         status = _cairo_composite_rectangles_lazy_init_for_fill (&extents,
272                                                                  surface,
273                                                                  op, source,
274                                                                  path, clip);
275         initialized = FALSE;
276     }
277     else
278         status = _cairo_composite_rectangles_init_for_fill (&extents,
279                                                             surface,
280                                                             op, source,
281                                                             path, clip);
282     if (unlikely (status))
283         return status;
284
285     do {
286         while (compositor->fill == NULL)
287             compositor = compositor->delegate;
288
289         if (! compositor->lazy_init && ! initialized) {
290             /* XXX: we should do better instead of re-init */
291             _cairo_composite_rectangles_fini (&extents);
292             status = _cairo_composite_rectangles_init_for_fill (&extents,
293                                                                 surface,
294                                                                 op, source,
295                                                                 path, clip);
296             initialized = TRUE;
297
298             if (unlikely (status))
299                 return status;
300         }
301
302         status = compositor->fill (compositor, &extents,
303                                    path, fill_rule, tolerance, antialias);
304
305         compositor = compositor->delegate;
306     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
307
308     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
309         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
310                 __FUNCTION__,
311                 extents.unbounded.x, extents.unbounded.y,
312                 extents.unbounded.width, extents.unbounded.height));
313         surface->damage = _cairo_damage_add_rectangle (surface->damage,
314                                                        &extents.unbounded);
315     }
316
317     _cairo_composite_rectangles_fini (&extents);
318
319     return status;
320 }
321
322 cairo_int_status_t
323 _cairo_compositor_glyphs (const cairo_compositor_t              *compositor,
324                           cairo_surface_t                       *surface,
325                           cairo_operator_t                       op,
326                           const cairo_pattern_t                 *source,
327                           cairo_glyph_t                         *glyphs,
328                           int                                    num_glyphs,
329                           cairo_scaled_font_t                   *scaled_font,
330                           const cairo_clip_t                    *clip)
331 {
332     cairo_composite_rectangles_t extents;
333     cairo_bool_t overlap;
334     cairo_int_status_t status;
335     cairo_bool_t initialized = TRUE;
336
337     TRACE ((stderr, "%s\n", __FUNCTION__));
338
339     if (compositor->lazy_init) {
340         status = _cairo_composite_rectangles_lazy_init_for_glyphs (&extents, surface,
341                                                                   op, source,
342                                                                   scaled_font,
343                                                                   glyphs, num_glyphs,
344                                                                   clip, &overlap);
345         initialized = FALSE;
346     } else
347         status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
348                                                              op, source,
349                                                              scaled_font,
350                                                              glyphs, num_glyphs,
351                                                              clip, &overlap);
352     if (unlikely (status))
353         return status;
354
355     do {
356         while (compositor->glyphs == NULL)
357             compositor = compositor->delegate;
358
359         if (! compositor->lazy_init && ! initialized) {
360             /* XXX: we should do better instead of re-init */
361             _cairo_composite_rectangles_fini (&extents);
362             status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
363                                                                  op, source,
364                                                                  scaled_font,
365                                                                  glyphs, num_glyphs,
366                                                                  clip, &overlap);
367             initialized = TRUE;
368
369             if (unlikely (status))
370                 return status;
371         }
372
373         status = compositor->glyphs (compositor, &extents,
374                                      scaled_font, glyphs, num_glyphs, overlap);
375
376         compositor = compositor->delegate;
377     } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
378
379     if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) {
380         TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n",
381                 __FUNCTION__,
382                 extents.unbounded.x, extents.unbounded.y,
383                 extents.unbounded.width, extents.unbounded.height));
384         surface->damage = _cairo_damage_add_rectangle (surface->damage,
385                                                        &extents.unbounded);
386     }
387
388     _cairo_composite_rectangles_fini (&extents);
389
390     return status;
391 }