/src/cairo/src/cairo-damage.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2012 Intel Corporation |
3 | | * |
4 | | * This library is free software; you can redistribute it and/or |
5 | | * modify it either under the terms of the GNU Lesser General Public |
6 | | * License version 2.1 as published by the Free Software Foundation |
7 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
8 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
9 | | * notice, a recipient may use your version of this file under either |
10 | | * the MPL or the LGPL. |
11 | | * |
12 | | * You should have received a copy of the LGPL along with this library |
13 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
15 | | * You should have received a copy of the MPL along with this library |
16 | | * in the file COPYING-MPL-1.1 |
17 | | * |
18 | | * The contents of this file are subject to the Mozilla Public License |
19 | | * Version 1.1 (the "License"); you may not use this file except in |
20 | | * compliance with the License. You may obtain a copy of the License at |
21 | | * http://www.mozilla.org/MPL/ |
22 | | * |
23 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
24 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
25 | | * the specific language governing rights and limitations. |
26 | | * |
27 | | * The Original Code is the cairo graphics library. |
28 | | * |
29 | | * The Initial Developer of the Original Code is Chris Wilson |
30 | | * |
31 | | * Contributor(s): |
32 | | * Chris Wilson <chris@chris-wilson.co.uk> |
33 | | */ |
34 | | |
35 | | #include "cairoint.h" |
36 | | |
37 | | #include "cairo-damage-private.h" |
38 | | #include "cairo-region-private.h" |
39 | | |
40 | | static const cairo_damage_t __cairo_damage__nil = { CAIRO_STATUS_NO_MEMORY }; |
41 | | |
42 | | cairo_damage_t * |
43 | | _cairo_damage_create_in_error (cairo_status_t status) |
44 | 0 | { |
45 | 0 | _cairo_error_throw (status); |
46 | 0 | return (cairo_damage_t *) &__cairo_damage__nil; |
47 | 0 | } |
48 | | |
49 | | cairo_damage_t * |
50 | | _cairo_damage_create (void) |
51 | 0 | { |
52 | 0 | cairo_damage_t *damage; |
53 | |
|
54 | 0 | damage = _cairo_calloc (sizeof (*damage)); |
55 | 0 | if (unlikely (damage == NULL)) { |
56 | 0 | _cairo_error_throw(CAIRO_STATUS_NO_MEMORY); |
57 | 0 | return (cairo_damage_t *) &__cairo_damage__nil; |
58 | 0 | } |
59 | | |
60 | 0 | damage->status = CAIRO_STATUS_SUCCESS; |
61 | 0 | damage->region = NULL; |
62 | 0 | damage->dirty = 0; |
63 | 0 | damage->tail = &damage->chunks; |
64 | 0 | damage->chunks.base = damage->boxes; |
65 | 0 | damage->chunks.size = ARRAY_LENGTH(damage->boxes); |
66 | 0 | damage->chunks.count = 0; |
67 | 0 | damage->chunks.next = NULL; |
68 | |
|
69 | 0 | damage->remain = damage->chunks.size; |
70 | |
|
71 | 0 | return damage; |
72 | 0 | } |
73 | | |
74 | | void |
75 | | _cairo_damage_destroy (cairo_damage_t *damage) |
76 | 0 | { |
77 | 0 | struct _cairo_damage_chunk *chunk, *next; |
78 | |
|
79 | 0 | if (damage == (cairo_damage_t *) &__cairo_damage__nil) |
80 | 0 | return; |
81 | | |
82 | 0 | for (chunk = damage->chunks.next; chunk != NULL; chunk = next) { |
83 | 0 | next = chunk->next; |
84 | 0 | free (chunk); |
85 | 0 | } |
86 | 0 | cairo_region_destroy (damage->region); |
87 | 0 | free (damage); |
88 | 0 | } |
89 | | |
90 | | static cairo_damage_t * |
91 | | _cairo_damage_add_boxes(cairo_damage_t *damage, |
92 | | const cairo_box_t *boxes, |
93 | | int count) |
94 | 0 | { |
95 | 0 | struct _cairo_damage_chunk *chunk; |
96 | 0 | int n, size; |
97 | |
|
98 | 0 | TRACE ((stderr, "%s x%d\n", __FUNCTION__, count)); |
99 | |
|
100 | 0 | if (damage == NULL) |
101 | 0 | damage = _cairo_damage_create (); |
102 | 0 | if (damage->status) |
103 | 0 | return damage; |
104 | | |
105 | 0 | damage->dirty += count; |
106 | |
|
107 | 0 | n = count; |
108 | 0 | if (n > damage->remain) |
109 | 0 | n = damage->remain; |
110 | |
|
111 | 0 | memcpy (damage->tail->base + damage->tail->count, boxes, |
112 | 0 | n * sizeof (cairo_box_t)); |
113 | |
|
114 | 0 | count -= n; |
115 | 0 | damage->tail->count += n; |
116 | 0 | damage->remain -= n; |
117 | |
|
118 | 0 | if (count == 0) |
119 | 0 | return damage; |
120 | | |
121 | 0 | size = 2 * damage->tail->size; |
122 | 0 | if (size < count) |
123 | 0 | size = (count + 64) & ~63; |
124 | |
|
125 | 0 | chunk = _cairo_malloc (sizeof (*chunk) + sizeof (cairo_box_t) * size); |
126 | 0 | if (unlikely (chunk == NULL)) { |
127 | 0 | _cairo_damage_destroy (damage); |
128 | 0 | return (cairo_damage_t *) &__cairo_damage__nil; |
129 | 0 | } |
130 | | |
131 | 0 | chunk->next = NULL; |
132 | 0 | chunk->base = (cairo_box_t *) (chunk + 1); |
133 | 0 | chunk->size = size; |
134 | 0 | chunk->count = count; |
135 | |
|
136 | 0 | damage->tail->next = chunk; |
137 | 0 | damage->tail = chunk; |
138 | |
|
139 | 0 | memcpy (damage->tail->base, boxes + n, |
140 | 0 | count * sizeof (cairo_box_t)); |
141 | 0 | damage->remain = size - count; |
142 | |
|
143 | 0 | return damage; |
144 | 0 | } |
145 | | |
146 | | cairo_damage_t * |
147 | | _cairo_damage_add_box(cairo_damage_t *damage, |
148 | | const cairo_box_t *box) |
149 | 0 | { |
150 | 0 | TRACE ((stderr, "%s: (%d, %d),(%d, %d)\n", __FUNCTION__, |
151 | 0 | box->p1.x, box->p1.y, box->p2.x, box->p2.y)); |
152 | |
|
153 | 0 | return _cairo_damage_add_boxes(damage, box, 1); |
154 | 0 | } |
155 | | |
156 | | cairo_damage_t * |
157 | | _cairo_damage_add_rectangle(cairo_damage_t *damage, |
158 | | const cairo_rectangle_int_t *r) |
159 | 0 | { |
160 | 0 | cairo_box_t box; |
161 | |
|
162 | 0 | TRACE ((stderr, "%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, |
163 | 0 | r->x, r->y, r->width, r->height)); |
164 | |
|
165 | 0 | box.p1.x = r->x; |
166 | 0 | box.p1.y = r->y; |
167 | 0 | box.p2.x = r->x + r->width; |
168 | 0 | box.p2.y = r->y + r->height; |
169 | |
|
170 | 0 | return _cairo_damage_add_boxes(damage, &box, 1); |
171 | 0 | } |
172 | | |
173 | | cairo_damage_t * |
174 | | _cairo_damage_add_region (cairo_damage_t *damage, |
175 | | const cairo_region_t *region) |
176 | 0 | { |
177 | 0 | cairo_box_t *boxes; |
178 | 0 | int nbox; |
179 | |
|
180 | 0 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
181 | |
|
182 | 0 | boxes = _cairo_region_get_boxes (region, &nbox); |
183 | 0 | return _cairo_damage_add_boxes(damage, boxes, nbox); |
184 | 0 | } |
185 | | |
186 | | cairo_damage_t * |
187 | | _cairo_damage_reduce (cairo_damage_t *damage) |
188 | 0 | { |
189 | 0 | cairo_box_t *free_boxes = NULL; |
190 | 0 | cairo_box_t *boxes, *b; |
191 | 0 | struct _cairo_damage_chunk *chunk, *last; |
192 | |
|
193 | 0 | TRACE ((stderr, "%s: dirty=%d\n", __FUNCTION__, |
194 | 0 | damage ? damage->dirty : -1)); |
195 | 0 | if (damage == NULL || damage->status || !damage->dirty) |
196 | 0 | return damage; |
197 | | |
198 | 0 | if (damage->region) { |
199 | 0 | cairo_region_t *region; |
200 | |
|
201 | 0 | region = damage->region; |
202 | 0 | damage->region = NULL; |
203 | |
|
204 | 0 | damage = _cairo_damage_add_region (damage, region); |
205 | 0 | cairo_region_destroy (region); |
206 | |
|
207 | 0 | if (unlikely (damage->status)) |
208 | 0 | return damage; |
209 | 0 | } |
210 | | |
211 | 0 | boxes = damage->tail->base; |
212 | 0 | if (damage->dirty > damage->tail->size) { |
213 | 0 | boxes = free_boxes = _cairo_malloc (damage->dirty * sizeof (cairo_box_t)); |
214 | 0 | if (unlikely (boxes == NULL)) { |
215 | 0 | _cairo_damage_destroy (damage); |
216 | 0 | return (cairo_damage_t *) &__cairo_damage__nil; |
217 | 0 | } |
218 | | |
219 | 0 | b = boxes; |
220 | 0 | last = NULL; |
221 | 0 | } else { |
222 | 0 | b = boxes + damage->tail->count; |
223 | 0 | last = damage->tail; |
224 | 0 | } |
225 | | |
226 | 0 | for (chunk = &damage->chunks; chunk != last; chunk = chunk->next) { |
227 | 0 | memcpy (b, chunk->base, chunk->count * sizeof (cairo_box_t)); |
228 | 0 | b += chunk->count; |
229 | 0 | } |
230 | |
|
231 | 0 | damage->region = _cairo_region_create_from_boxes (boxes, damage->dirty); |
232 | 0 | free (free_boxes); |
233 | |
|
234 | 0 | if (unlikely (damage->region->status)) { |
235 | 0 | _cairo_damage_destroy (damage); |
236 | 0 | return (cairo_damage_t *) &__cairo_damage__nil; |
237 | 0 | } |
238 | | |
239 | 0 | damage->dirty = 0; |
240 | 0 | return damage; |
241 | 0 | } |