/work/workdir/UnpackedTarball/cairo/src/cairo-surface-clipper.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* cairo - a vector graphics library with display and print output |
2 | | * |
3 | | * Copyright © 2009 Chris Wilson |
4 | | * |
5 | | * This library is free software; you can redistribute it and/or |
6 | | * modify it either under the terms of the GNU Lesser General Public |
7 | | * License version 2.1 as published by the Free Software Foundation |
8 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
9 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
10 | | * notice, a recipient may use your version of this file under either |
11 | | * the MPL or the LGPL. |
12 | | * |
13 | | * You should have received a copy of the LGPL along with this library |
14 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
15 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
16 | | * You should have received a copy of the MPL along with this library |
17 | | * in the file COPYING-MPL-1.1 |
18 | | * |
19 | | * The contents of this file are subject to the Mozilla Public License |
20 | | * Version 1.1 (the "License"); you may not use this file except in |
21 | | * compliance with the License. You may obtain a copy of the License at |
22 | | * http://www.mozilla.org/MPL/ |
23 | | * |
24 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
25 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
26 | | * the specific language governing rights and limitations. |
27 | | * |
28 | | * The Original Code is the cairo graphics library. |
29 | | * |
30 | | * The Initial Developer of the Original Code is Red Hat, Inc. |
31 | | * |
32 | | * Contributor(s): |
33 | | * Chris Wilson <chris@chris-wilson.co.uk> |
34 | | */ |
35 | | |
36 | | #include "cairoint.h" |
37 | | |
38 | | #include "cairo-clip-inline.h" |
39 | | #include "cairo-surface-clipper-private.h" |
40 | | |
41 | | /* A collection of routines to facilitate vector surface clipping */ |
42 | | |
43 | | /* XXX Eliminate repeated paths and nested clips */ |
44 | | |
45 | | static cairo_status_t |
46 | | _cairo_path_fixed_add_box (cairo_path_fixed_t *path, |
47 | | const cairo_box_t *box) |
48 | 0 | { |
49 | 0 | cairo_status_t status; |
50 | |
|
51 | 0 | status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y); |
52 | 0 | if (unlikely (status)) |
53 | 0 | return status; |
54 | | |
55 | 0 | status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y); |
56 | 0 | if (unlikely (status)) |
57 | 0 | return status; |
58 | | |
59 | 0 | status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y); |
60 | 0 | if (unlikely (status)) |
61 | 0 | return status; |
62 | | |
63 | 0 | status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y); |
64 | 0 | if (unlikely (status)) |
65 | 0 | return status; |
66 | | |
67 | 0 | return _cairo_path_fixed_close_path (path); |
68 | 0 | } |
69 | | |
70 | | static cairo_status_t |
71 | | _cairo_surface_clipper_intersect_clip_boxes (cairo_surface_clipper_t *clipper, |
72 | | const cairo_clip_t *clip) |
73 | 0 | { |
74 | 0 | cairo_path_fixed_t path; |
75 | 0 | cairo_status_t status; |
76 | 0 | int i; |
77 | |
|
78 | 0 | if (clip->num_boxes == 0) |
79 | 0 | return CAIRO_STATUS_SUCCESS; |
80 | | |
81 | | /* Reconstruct the path for the clip boxes. |
82 | | * XXX maybe a new clipper callback? |
83 | | */ |
84 | | |
85 | 0 | _cairo_path_fixed_init (&path); |
86 | 0 | for (i = 0; i < clip->num_boxes; i++) { |
87 | 0 | status = _cairo_path_fixed_add_box (&path, &clip->boxes[i]); |
88 | 0 | if (unlikely (status)) { |
89 | 0 | _cairo_path_fixed_fini (&path); |
90 | 0 | return status; |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 0 | status = clipper->intersect_clip_path (clipper, &path, |
95 | 0 | CAIRO_FILL_RULE_WINDING, |
96 | 0 | 0., |
97 | 0 | CAIRO_ANTIALIAS_DEFAULT); |
98 | 0 | _cairo_path_fixed_fini (&path); |
99 | |
|
100 | 0 | return status; |
101 | 0 | } |
102 | | |
103 | | static cairo_status_t |
104 | | _cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper, |
105 | | cairo_clip_path_t *clip_path, |
106 | | cairo_clip_path_t *end) |
107 | 0 | { |
108 | 0 | cairo_status_t status; |
109 | |
|
110 | 0 | if (clip_path->prev != end) { |
111 | 0 | status = |
112 | 0 | _cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
113 | 0 | clip_path->prev, |
114 | 0 | end); |
115 | 0 | if (unlikely (status)) |
116 | 0 | return status; |
117 | 0 | } |
118 | | |
119 | 0 | return clipper->intersect_clip_path (clipper, |
120 | 0 | &clip_path->path, |
121 | 0 | clip_path->fill_rule, |
122 | 0 | clip_path->tolerance, |
123 | 0 | clip_path->antialias); |
124 | 0 | } |
125 | | |
126 | | cairo_status_t |
127 | | _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, |
128 | | const cairo_clip_t *clip) |
129 | 0 | { |
130 | 0 | cairo_status_t status; |
131 | 0 | cairo_bool_t incremental = FALSE; |
132 | |
|
133 | 0 | if (_cairo_clip_equal (clip, clipper->clip)) |
134 | 0 | return CAIRO_STATUS_SUCCESS; |
135 | | |
136 | | /* all clipped out state should never propagate this far */ |
137 | 0 | assert (!_cairo_clip_is_all_clipped (clip)); |
138 | | |
139 | | /* XXX Is this an incremental clip? */ |
140 | 0 | if (clipper->clip && clip && |
141 | 0 | clip->num_boxes == clipper->clip->num_boxes && |
142 | 0 | memcmp (clip->boxes, clipper->clip->boxes, |
143 | 0 | sizeof (cairo_box_t) * clip->num_boxes) == 0) |
144 | 0 | { |
145 | 0 | cairo_clip_path_t *clip_path = clip->path; |
146 | 0 | while (clip_path != NULL && clip_path != clipper->clip->path) |
147 | 0 | clip_path = clip_path->prev; |
148 | |
|
149 | 0 | if (clip_path) { |
150 | 0 | incremental = TRUE; |
151 | 0 | status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
152 | 0 | clip->path, |
153 | 0 | clipper->clip->path); |
154 | 0 | } |
155 | 0 | } |
156 | |
|
157 | 0 | _cairo_clip_destroy (clipper->clip); |
158 | 0 | clipper->clip = _cairo_clip_copy (clip); |
159 | |
|
160 | 0 | if (incremental) |
161 | 0 | return status; |
162 | | |
163 | 0 | status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); |
164 | 0 | if (unlikely (status)) |
165 | 0 | return status; |
166 | | |
167 | 0 | if (clip == NULL) |
168 | 0 | return CAIRO_STATUS_SUCCESS; |
169 | | |
170 | 0 | status = _cairo_surface_clipper_intersect_clip_boxes (clipper, clip); |
171 | 0 | if (unlikely (status)) |
172 | 0 | return status; |
173 | | |
174 | 0 | if (clip->path != NULL) { |
175 | 0 | status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
176 | 0 | clip->path, |
177 | 0 | NULL); |
178 | 0 | } |
179 | |
|
180 | 0 | return status; |
181 | 0 | } |
182 | | |
183 | | void |
184 | | _cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, |
185 | | cairo_surface_clipper_intersect_clip_path_func_t func) |
186 | 2 | { |
187 | 2 | clipper->clip = NULL; |
188 | 2 | clipper->intersect_clip_path = func; |
189 | 2 | } |
190 | | |
191 | | void |
192 | | _cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper) |
193 | 4 | { |
194 | 4 | _cairo_clip_destroy (clipper->clip); |
195 | 4 | clipper->clip = NULL; |
196 | 4 | } |