Bug Summary

File:root/firefox-clang/gfx/cairo/libpixman/src/pixman-region.c
Warning:line 2277, column 13
Value stored to 'part_out' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pixman-region32.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/libpixman/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/libpixman/src -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D HAVE_PTHREADS -D PACKAGE=mozpixman -D USE_X86_MMX -D USE_SSE2 -D USE_SSSE3 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/cairo/libpixman/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/libpixman/src -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-address -Wno-braced-scalar-init -Wno-missing-field-initializers -Wno-sign-compare -Wno-incompatible-pointer-types -Wno-unused -Wno-incompatible-pointer-types -Wno-tautological-compare -Wno-tautological-constant-out-of-range-compare -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-26-231904-1820671-1 -x c /root/firefox-clang/gfx/cairo/libpixman/src/pixman-region32.c
1/*
2 * Copyright 1987, 1988, 1989, 1998 The Open Group
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 *
20 * Except as contained in this notice, the name of The Open Group shall not be
21 * used in advertising or otherwise to promote the sale, use or other dealings
22 * in this Software without prior written authorization from The Open Group.
23 *
24 * Copyright 1987, 1988, 1989 by
25 * Digital Equipment Corporation, Maynard, Massachusetts.
26 *
27 * All Rights Reserved
28 *
29 * Permission to use, copy, modify, and distribute this software and its
30 * documentation for any purpose and without fee is hereby granted,
31 * provided that the above copyright notice appear in all copies and that
32 * both that copyright notice and this permission notice appear in
33 * supporting documentation, and that the name of Digital not be
34 * used in advertising or publicity pertaining to distribution of the
35 * software without specific, written prior permission.
36 *
37 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 * SOFTWARE.
44 *
45 * Copyright © 1998 Keith Packard
46 *
47 * Permission to use, copy, modify, distribute, and sell this software and its
48 * documentation for any purpose is hereby granted without fee, provided that
49 * the above copyright notice appear in all copies and that both that
50 * copyright notice and this permission notice appear in supporting
51 * documentation, and that the name of Keith Packard not be used in
52 * advertising or publicity pertaining to distribution of the software without
53 * specific, written prior permission. Keith Packard makes no
54 * representations about the suitability of this software for any purpose. It
55 * is provided "as is" without express or implied warranty.
56 *
57 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
58 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
59 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
60 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
61 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
62 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
63 * PERFORMANCE OF THIS SOFTWARE.
64 */
65
66#include <stdlib.h>
67#include <limits.h>
68#include <string.h>
69#include <stdio.h>
70#include "pixman-private.h"
71
72#define PIXREGION_NIL(reg)((reg)->data && !(reg)->data->numRects) ((reg)->data && !(reg)->data->numRects)
73/* not a region */
74#define PIXREGION_NAR(reg)((reg)->data == pixman_broken_data) ((reg)->data == pixman_broken_data)
75#define PIXREGION_NUMRECTS(reg)((reg)->data ? (reg)->data->numRects : 1) ((reg)->data ? (reg)->data->numRects : 1)
76#define PIXREGION_SIZE(reg)((reg)->data ? (reg)->data->size : 0) ((reg)->data ? (reg)->data->size : 0)
77#define PIXREGION_RECTS(reg)((reg)->data ? (box_type_t *)((reg)->data + 1) : (box_type_t
*)&(reg)->extents)
\
78 ((reg)->data ? (box_type_t *)((reg)->data + 1) \
79 : (box_type_t *)&(reg)->extents)
80#define PIXREGION_BOXPTR(reg)((box_type_t *)((reg)->data + 1)) ((box_type_t *)((reg)->data + 1))
81#define PIXREGION_BOX(reg, i)(&((box_type_t *)((reg)->data + 1))[i]) (&PIXREGION_BOXPTR (reg)((box_type_t *)((reg)->data + 1))[i])
82#define PIXREGION_TOP(reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects])
PIXREGION_BOX (reg, (reg)->data->numRects)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects])
83#define PIXREGION_END(reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects - 1])
PIXREGION_BOX (reg, (reg)->data->numRects - 1)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects - 1])
84
85#define GOOD_RECT(rect)((rect)->x1 < (rect)->x2 && (rect)->y1 <
(rect)->y2)
((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2)
86#define BAD_RECT(rect)((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect
)->y2)
((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2)
87
88#ifdef DEBUG1
89
90#define GOOD(reg)do { if (!_moz_pixman_region32_selfcheck (reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg"
); } while (0)
\
91 do \
92 { \
93 if (!PREFIX (_selfcheck (reg))_moz_pixman_region32_selfcheck (reg)) \
94 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Malformed region " # reg); \
95 } while (0)
96
97#else
98
99#define GOOD(reg)do { if (!_moz_pixman_region32_selfcheck (reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg"
); } while (0)
100
101#endif
102
103static const box_type_t PREFIX (_empty_box_)pixman_region32_empty_box_ = { 0, 0, 0, 0 };
104static const region_data_type_t PREFIX (_empty_data_)pixman_region32_empty_data_ = { 0, 0 };
105#if defined (__llvm__1) && !defined (__clang__1)
106static const volatile region_data_type_t PREFIX (_broken_data_)pixman_region32_broken_data_ = { 0, 0 };
107#else
108static const region_data_type_t PREFIX (_broken_data_)pixman_region32_broken_data_ = { 0, 0 };
109#endif
110
111static box_type_t *pixman_region_empty_box =
112 (box_type_t *)&PREFIX (_empty_box_)pixman_region32_empty_box_;
113static region_data_type_t *pixman_region_empty_data =
114 (region_data_type_t *)&PREFIX (_empty_data_)pixman_region32_empty_data_;
115static region_data_type_t *pixman_broken_data =
116 (region_data_type_t *)&PREFIX (_broken_data_)pixman_region32_broken_data_;
117
118static pixman_bool_t
119pixman_break (region_type_t *region);
120
121/*
122 * The functions in this file implement the Region abstraction used extensively
123 * throughout the X11 sample server. A Region is simply a set of disjoint
124 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
125 * smallest single rectangle that contains all the non-overlapping rectangles.
126 *
127 * A Region is implemented as a "y-x-banded" array of rectangles. This array
128 * imposes two degrees of order. First, all rectangles are sorted by top side
129 * y coordinate first (y1), and then by left side x coordinate (x1).
130 *
131 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
132 * band has the same top y coordinate (y1), and each has the same bottom y
133 * coordinate (y2). Thus all rectangles in a band differ only in their left
134 * and right side (x1 and x2). Bands are implicit in the array of rectangles:
135 * there is no separate list of band start pointers.
136 *
137 * The y-x band representation does not minimize rectangles. In particular,
138 * if a rectangle vertically crosses a band (the rectangle has scanlines in
139 * the y1 to y2 area spanned by the band), then the rectangle may be broken
140 * down into two or more smaller rectangles stacked one atop the other.
141 *
142 * ----------- -----------
143 * | | | | band 0
144 * | | -------- ----------- --------
145 * | | | | in y-x banded | | | | band 1
146 * | | | | form is | | | |
147 * ----------- | | ----------- --------
148 * | | | | band 2
149 * -------- --------
150 *
151 * An added constraint on the rectangles is that they must cover as much
152 * horizontal area as possible: no two rectangles within a band are allowed
153 * to touch.
154 *
155 * Whenever possible, bands will be merged together to cover a greater vertical
156 * distance (and thus reduce the number of rectangles). Two bands can be merged
157 * only if the bottom of one touches the top of the other and they have
158 * rectangles in the same places (of the same width, of course).
159 *
160 * Adam de Boor wrote most of the original region code. Joel McCormack
161 * substantially modified or rewrote most of the core arithmetic routines, and
162 * added pixman_region_validate in order to support several speed improvements
163 * to pixman_region_validate_tree. Bob Scheifler changed the representation
164 * to be more compact when empty or a single rectangle, and did a bunch of
165 * gratuitous reformatting. Carl Worth did further gratuitous reformatting
166 * while re-merging the server and client region code into libpixregion.
167 * Soren Sandmann did even more gratuitous reformatting.
168 */
169
170/* true iff two Boxes overlap */
171#define EXTENTCHECK(r1, r2)(!( ((r1)->x2 <= (r2)->x1) || ((r1)->x1 >= (r2
)->x2) || ((r1)->y2 <= (r2)->y1) || ((r1)->y1 >=
(r2)->y2) ) )
\
172 (!( ((r1)->x2 <= (r2)->x1) || \
173 ((r1)->x1 >= (r2)->x2) || \
174 ((r1)->y2 <= (r2)->y1) || \
175 ((r1)->y1 >= (r2)->y2) ) )
176
177/* true iff (x,y) is in Box */
178#define INBOX(r, x, y)( ((r)->x2 > x) && ((r)->x1 <= x) &&
((r)->y2 > y) && ((r)->y1 <= y) )
\
179 ( ((r)->x2 > x) && \
180 ((r)->x1 <= x) && \
181 ((r)->y2 > y) && \
182 ((r)->y1 <= y) )
183
184/* true iff Box r1 contains Box r2 */
185#define SUBSUMES(r1, r2)( ((r1)->x1 <= (r2)->x1) && ((r1)->x2 >=
(r2)->x2) && ((r1)->y1 <= (r2)->y1) &&
((r1)->y2 >= (r2)->y2) )
\
186 ( ((r1)->x1 <= (r2)->x1) && \
187 ((r1)->x2 >= (r2)->x2) && \
188 ((r1)->y1 <= (r2)->y1) && \
189 ((r1)->y2 >= (r2)->y2) )
190
191static size_t
192PIXREGION_SZOF (size_t n)
193{
194 size_t size = n * sizeof(box_type_t);
195
196 if (n > UINT32_MAX(4294967295U) / sizeof(box_type_t))
197 return 0;
198
199 if (sizeof(region_data_type_t) > UINT32_MAX(4294967295U) - size)
200 return 0;
201
202 return size + sizeof(region_data_type_t);
203}
204
205static region_data_type_t *
206alloc_data (size_t n)
207{
208 size_t sz = PIXREGION_SZOF (n);
209
210 if (!sz)
211 return NULL((void*)0);
212
213 return malloc (sz);
214}
215
216#define FREE_DATA(reg)if ((reg)->data && (reg)->data->size) free (
(reg)->data)
if ((reg)->data && (reg)->data->size) free ((reg)->data)
217
218#define RECTALLOC_BAIL(region, n, bail)do { if (!(region)->data || (((region)->data->numRects
+ (n)) > (region)->data->size)) { if (!pixman_rect_alloc
(region, n)) goto bail; } } while (0)
\
219 do \
220 { \
221 if (!(region)->data || \
222 (((region)->data->numRects + (n)) > (region)->data->size)) \
223 { \
224 if (!pixman_rect_alloc (region, n)) \
225 goto bail; \
226 } \
227 } while (0)
228
229#define RECTALLOC(region, n)do { if (!(region)->data || (((region)->data->numRects
+ (n)) > (region)->data->size)) { if (!pixman_rect_alloc
(region, n)) { return 0; } } } while (0)
\
230 do \
231 { \
232 if (!(region)->data || \
233 (((region)->data->numRects + (n)) > (region)->data->size)) \
234 { \
235 if (!pixman_rect_alloc (region, n)) { \
236 return FALSE0; \
237 } \
238 } \
239 } while (0)
240
241#define ADDRECT(next_rect, nx1, ny1, nx2, ny2)do { next_rect->x1 = nx1; next_rect->y1 = ny1; next_rect
->x2 = nx2; next_rect->y2 = ny2; next_rect++; } while (
0)
\
242 do \
243 { \
244 next_rect->x1 = nx1; \
245 next_rect->y1 = ny1; \
246 next_rect->x2 = nx2; \
247 next_rect->y2 = ny2; \
248 next_rect++; \
249 } \
250 while (0)
251
252#define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = nx1; next_rect->y1 = ny1; next_rect->x2 = nx2
; next_rect->y2 = ny2; next_rect++; } while (0); region->
data->numRects++; do { if (__builtin_expect ((!(region->
data->numRects <= region->data->size)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
\
253 do \
254 { \
255 if (!(region)->data || \
256 ((region)->data->numRects == (region)->data->size)) \
257 { \
258 if (!pixman_rect_alloc (region, 1)) \
259 return FALSE0; \
260 next_rect = PIXREGION_TOP (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects])
; \
261 } \
262 ADDRECT (next_rect, nx1, ny1, nx2, ny2)do { next_rect->x1 = nx1; next_rect->y1 = ny1; next_rect
->x2 = nx2; next_rect->y2 = ny2; next_rect++; } while (
0)
; \
263 region->data->numRects++; \
264 critical_if_fail (region->data->numRects <= region->data->size)do { if (__builtin_expect ((!(region->data->numRects <=
region->data->size)), 0)) _pixman_log_error (((const char
*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0)
; \
265 } while (0)
266
267#define DOWNSIZE(reg, numRects)do { if (((numRects) < ((reg)->data->size >> 1
)) && ((reg)->data->size > 50)) { region_data_type_t
* new_data; size_t data_size = PIXREGION_SZOF (numRects); if
(!data_size) { new_data = ((void*)0); } else { new_data = (region_data_type_t
*) realloc ((reg)->data, data_size); } if (new_data) { new_data
->size = (numRects); (reg)->data = new_data; } } } while
(0)
\
268 do \
269 { \
270 if (((numRects) < ((reg)->data->size >> 1)) && \
271 ((reg)->data->size > 50)) \
272 { \
273 region_data_type_t * new_data; \
274 size_t data_size = PIXREGION_SZOF (numRects); \
275 \
276 if (!data_size) \
277 { \
278 new_data = NULL((void*)0); \
279 } \
280 else \
281 { \
282 new_data = (region_data_type_t *) \
283 realloc ((reg)->data, data_size); \
284 } \
285 \
286 if (new_data) \
287 { \
288 new_data->size = (numRects); \
289 (reg)->data = new_data; \
290 } \
291 } \
292 } while (0)
293
294PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
295PREFIX (_equal)_moz_pixman_region32_equal (const region_type_t *reg1, const region_type_t *reg2)
296{
297 int i;
298 box_type_t *rects1;
299 box_type_t *rects2;
300
301 if (reg1->extents.x1 != reg2->extents.x1)
302 return FALSE0;
303
304 if (reg1->extents.x2 != reg2->extents.x2)
305 return FALSE0;
306
307 if (reg1->extents.y1 != reg2->extents.y1)
308 return FALSE0;
309
310 if (reg1->extents.y2 != reg2->extents.y2)
311 return FALSE0;
312
313 if (PIXREGION_NUMRECTS (reg1)((reg1)->data ? (reg1)->data->numRects : 1) != PIXREGION_NUMRECTS (reg2)((reg2)->data ? (reg2)->data->numRects : 1))
314 return FALSE0;
315
316 rects1 = PIXREGION_RECTS (reg1)((reg1)->data ? (box_type_t *)((reg1)->data + 1) : (box_type_t
*)&(reg1)->extents)
;
317 rects2 = PIXREGION_RECTS (reg2)((reg2)->data ? (box_type_t *)((reg2)->data + 1) : (box_type_t
*)&(reg2)->extents)
;
318
319 for (i = 0; i != PIXREGION_NUMRECTS (reg1)((reg1)->data ? (reg1)->data->numRects : 1); i++)
320 {
321 if (rects1[i].x1 != rects2[i].x1)
322 return FALSE0;
323
324 if (rects1[i].x2 != rects2[i].x2)
325 return FALSE0;
326
327 if (rects1[i].y1 != rects2[i].y1)
328 return FALSE0;
329
330 if (rects1[i].y2 != rects2[i].y2)
331 return FALSE0;
332 }
333
334 return TRUE1;
335}
336
337int
338PREFIX (_print)_moz_pixman_region32_print (region_type_t *rgn)
339{
340 int num, size;
341 int i;
342 box_type_t * rects;
343
344 num = PIXREGION_NUMRECTS (rgn)((rgn)->data ? (rgn)->data->numRects : 1);
345 size = PIXREGION_SIZE (rgn)((rgn)->data ? (rgn)->data->size : 0);
346 rects = PIXREGION_RECTS (rgn)((rgn)->data ? (box_type_t *)((rgn)->data + 1) : (box_type_t
*)&(rgn)->extents)
;
347
348 fprintf (stderrstderr, "num: %d size: %d\n", num, size);
349 fprintf (stderrstderr, "extents: "
350 PRINT_SPECIFIER"%d" " "
351 PRINT_SPECIFIER"%d" " "
352 PRINT_SPECIFIER"%d" " "
353 PRINT_SPECIFIER"%d" "\n",
354 rgn->extents.x1,
355 rgn->extents.y1,
356 rgn->extents.x2,
357 rgn->extents.y2);
358
359 for (i = 0; i < num; i++)
360 {
361 fprintf (stderrstderr, PRINT_SPECIFIER"%d" " "
362 PRINT_SPECIFIER"%d" " "
363 PRINT_SPECIFIER"%d" " "
364 PRINT_SPECIFIER"%d" " \n",
365 rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
366 }
367
368 fprintf (stderrstderr, "\n");
369
370 return(num);
371}
372
373
374PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
375PREFIX (_init)_moz_pixman_region32_init (region_type_t *region)
376{
377 region->extents = *pixman_region_empty_box;
378 region->data = pixman_region_empty_data;
379}
380
381PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
382PREFIX (_init_rect)_moz_pixman_region32_init_rect (region_type_t * region,
383 int x,
384 int y,
385 unsigned int width,
386 unsigned int height)
387{
388 region->extents.x1 = x;
389 region->extents.y1 = y;
390 region->extents.x2 = x + width;
391 region->extents.y2 = y + height;
392
393 if (!GOOD_RECT (&region->extents)((&region->extents)->x1 < (&region->extents
)->x2 && (&region->extents)->y1 < (&
region->extents)->y2)
)
394 {
395 if (BAD_RECT (&region->extents)((&region->extents)->x1 > (&region->extents
)->x2 || (&region->extents)->y1 > (&region
->extents)->y2)
)
396 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Invalid rectangle passed");
397 PREFIX (_init)_moz_pixman_region32_init (region);
398 return;
399 }
400
401 region->data = NULL((void*)0);
402}
403
404PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
405PREFIX (_init_rectf)pixman_region32_init_rectf (region_type_t * region,
406 double x,
407 double y,
408 double width,
409 double height)
410{
411 region->extents.x1 = x;
412 region->extents.y1 = y;
413 region->extents.x2 = x + width;
414 region->extents.y2 = y + height;
415
416 if (!GOOD_RECT (&region->extents)((&region->extents)->x1 < (&region->extents
)->x2 && (&region->extents)->y1 < (&
region->extents)->y2)
)
417 {
418 if (BAD_RECT (&region->extents)((&region->extents)->x1 > (&region->extents
)->x2 || (&region->extents)->y1 > (&region
->extents)->y2)
)
419 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Invalid rectangle passed");
420 PREFIX (_init)_moz_pixman_region32_init (region);
421 return;
422 }
423
424 region->data = NULL((void*)0);
425}
426
427PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
428PREFIX (_init_with_extents)_moz_pixman_region32_init_with_extents (region_type_t *region, const box_type_t *extents)
429{
430 if (!GOOD_RECT (extents)((extents)->x1 < (extents)->x2 && (extents)->
y1 < (extents)->y2)
)
431 {
432 if (BAD_RECT (extents)((extents)->x1 > (extents)->x2 || (extents)->y1 >
(extents)->y2)
)
433 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Invalid rectangle passed");
434 PREFIX (_init)_moz_pixman_region32_init (region);
435 return;
436 }
437 region->extents = *extents;
438
439 region->data = NULL((void*)0);
440}
441
442PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
443PREFIX (_fini)_moz_pixman_region32_fini (region_type_t *region)
444{
445 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
446 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
447}
448
449PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) int
450PREFIX (_n_rects)_moz_pixman_region32_n_rects (const region_type_t *region)
451{
452 return PIXREGION_NUMRECTS (region)((region)->data ? (region)->data->numRects : 1);
453}
454
455PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) box_type_t *
456PREFIX (_rectangles)_moz_pixman_region32_rectangles (const region_type_t *region,
457 int *n_rects)
458{
459 if (n_rects)
460 *n_rects = PIXREGION_NUMRECTS (region)((region)->data ? (region)->data->numRects : 1);
461
462 return PIXREGION_RECTS (region)((region)->data ? (box_type_t *)((region)->data + 1) : (
box_type_t *)&(region)->extents)
;
463}
464
465static pixman_bool_t
466pixman_break (region_type_t *region)
467{
468 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
469
470 region->extents = *pixman_region_empty_box;
471 region->data = pixman_broken_data;
472
473 return FALSE0;
474}
475
476static pixman_bool_t
477pixman_rect_alloc (region_type_t * region,
478 int n)
479{
480 region_data_type_t *data;
481
482 if (!region->data)
483 {
484 n++;
485 region->data = alloc_data (n);
486
487 if (!region->data)
488 return pixman_break (region);
489
490 region->data->numRects = 1;
491 *PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1)) = region->extents;
492 }
493 else if (!region->data->size)
494 {
495 region->data = alloc_data (n);
496
497 if (!region->data)
498 return pixman_break (region);
499
500 region->data->numRects = 0;
501 }
502 else
503 {
504 size_t data_size;
505
506 if (n == 1)
507 {
508 n = region->data->numRects;
509 if (n > 500) /* XXX pick numbers out of a hat */
510 n = 250;
511 }
512
513 n += region->data->numRects;
514 data_size = PIXREGION_SZOF (n);
515
516 if (!data_size)
517 {
518 data = NULL((void*)0);
519 }
520 else
521 {
522 data = (region_data_type_t *)
523 realloc (region->data, PIXREGION_SZOF (n));
524 }
525
526 if (!data)
527 return pixman_break (region);
528
529 region->data = data;
530 }
531
532 region->data->size = n;
533
534 return TRUE1;
535}
536
537PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
538PREFIX (_copy)_moz_pixman_region32_copy (region_type_t *dst, const region_type_t *src)
539{
540 GOOD (dst)do { if (!_moz_pixman_region32_selfcheck (dst)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "dst"
); } while (0)
;
541 GOOD (src)do { if (!_moz_pixman_region32_selfcheck (src)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "src"
); } while (0)
;
542
543 if (dst == src)
544 return TRUE1;
545
546 dst->extents = src->extents;
547
548 if (!src->data || !src->data->size)
549 {
550 FREE_DATA (dst)if ((dst)->data && (dst)->data->size) free (
(dst)->data)
;
551 dst->data = src->data;
552 return TRUE1;
553 }
554
555 if (!dst->data || (dst->data->size < src->data->numRects))
556 {
557 FREE_DATA (dst)if ((dst)->data && (dst)->data->size) free (
(dst)->data)
;
558
559 dst->data = alloc_data (src->data->numRects);
560
561 if (!dst->data)
562 return pixman_break (dst);
563
564 dst->data->size = src->data->numRects;
565 }
566
567 dst->data->numRects = src->data->numRects;
568
569 memmove ((char *)PIXREGION_BOXPTR (dst)((box_type_t *)((dst)->data + 1)), (char *)PIXREGION_BOXPTR (src)((box_type_t *)((src)->data + 1)),
570 dst->data->numRects * sizeof(box_type_t));
571
572 return TRUE1;
573}
574
575/*======================================================================
576 * Generic Region Operator
577 *====================================================================*/
578
579/*-
580 *-----------------------------------------------------------------------
581 * pixman_coalesce --
582 * Attempt to merge the boxes in the current band with those in the
583 * previous one. We are guaranteed that the current band extends to
584 * the end of the rects array. Used only by pixman_op.
585 *
586 * Results:
587 * The new index for the previous band.
588 *
589 * Side Effects:
590 * If coalescing takes place:
591 * - rectangles in the previous band will have their y2 fields
592 * altered.
593 * - region->data->numRects will be decreased.
594 *
595 *-----------------------------------------------------------------------
596 */
597static inline__inline__ int
598pixman_coalesce (region_type_t * region, /* Region to coalesce */
599 int prev_start, /* Index of start of previous band */
600 int cur_start) /* Index of start of current band */
601{
602 box_type_t *prev_box; /* Current box in previous band */
603 box_type_t *cur_box; /* Current box in current band */
604 int numRects; /* Number rectangles in both bands */
605 primitive_t y2; /* Bottom of current band */
606
607 /*
608 * Figure out how many rectangles are in the band.
609 */
610 numRects = cur_start - prev_start;
611 critical_if_fail (numRects == region->data->numRects - cur_start)do { if (__builtin_expect ((!(numRects == region->data->
numRects - cur_start)), 0)) _pixman_log_error (((const char*)
(__PRETTY_FUNCTION__)), "The expression " "numRects == region->data->numRects - cur_start"
" was false"); } while (0)
;
612
613 if (!numRects) return cur_start;
614
615 /*
616 * The bands may only be coalesced if the bottom of the previous
617 * matches the top scanline of the current.
618 */
619 prev_box = PIXREGION_BOX (region, prev_start)(&((box_type_t *)((region)->data + 1))[prev_start]);
620 cur_box = PIXREGION_BOX (region, cur_start)(&((box_type_t *)((region)->data + 1))[cur_start]);
621 if (prev_box->y2 != cur_box->y1) return cur_start;
622
623 /*
624 * Make sure the bands have boxes in the same places. This
625 * assumes that boxes have been added in such a way that they
626 * cover the most area possible. I.e. two boxes in a band must
627 * have some horizontal space between them.
628 */
629 y2 = cur_box->y2;
630
631 do
632 {
633 if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2))
634 return (cur_start);
635
636 prev_box++;
637 cur_box++;
638 numRects--;
639 }
640 while (numRects);
641
642 /*
643 * The bands may be merged, so set the bottom y of each box
644 * in the previous band to the bottom y of the current band.
645 */
646 numRects = cur_start - prev_start;
647 region->data->numRects -= numRects;
648
649 do
650 {
651 prev_box--;
652 prev_box->y2 = y2;
653 numRects--;
654 }
655 while (numRects);
656
657 return prev_start;
658}
659
660/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
661
662#define COALESCE(new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
\
663 do \
664 { \
665 if (cur_band - prev_band == new_reg->data->numRects - cur_band) \
666 prev_band = pixman_coalesce (new_reg, prev_band, cur_band); \
667 else \
668 prev_band = cur_band; \
669 } while (0)
670
671/*-
672 *-----------------------------------------------------------------------
673 * pixman_region_append_non_o --
674 * Handle a non-overlapping band for the union and subtract operations.
675 * Just adds the (top/bottom-clipped) rectangles into the region.
676 * Doesn't have to check for subsumption or anything.
677 *
678 * Results:
679 * None.
680 *
681 * Side Effects:
682 * region->data->numRects is incremented and the rectangles overwritten
683 * with the rectangles we're passed.
684 *
685 *-----------------------------------------------------------------------
686 */
687static inline__inline__ pixman_bool_t
688pixman_region_append_non_o (region_type_t * region,
689 box_type_t * r,
690 box_type_t * r_end,
691 primitive_t y1,
692 primitive_t y2)
693{
694 box_type_t *next_rect;
695 int new_rects;
696
697 new_rects = r_end - r;
698
699 critical_if_fail (y1 < y2)do { if (__builtin_expect ((!(y1 < y2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "y1 < y2"
" was false"); } while (0)
;
700 critical_if_fail (new_rects != 0)do { if (__builtin_expect ((!(new_rects != 0)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "new_rects != 0"
" was false"); } while (0)
;
701
702 /* Make sure we have enough space for all rectangles to be added */
703 RECTALLOC (region, new_rects)do { if (!(region)->data || (((region)->data->numRects
+ (new_rects)) > (region)->data->size)) { if (!pixman_rect_alloc
(region, new_rects)) { return 0; } } } while (0)
;
704 next_rect = PIXREGION_TOP (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects])
;
705 region->data->numRects += new_rects;
706
707 do
708 {
709 critical_if_fail (r->x1 < r->x2)do { if (__builtin_expect ((!(r->x1 < r->x2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "r->x1 < r->x2"
" was false"); } while (0)
;
710 ADDRECT (next_rect, r->x1, y1, r->x2, y2)do { next_rect->x1 = r->x1; next_rect->y1 = y1; next_rect
->x2 = r->x2; next_rect->y2 = y2; next_rect++; } while
(0)
;
711 r++;
712 }
713 while (r != r_end);
714
715 return TRUE1;
716}
717
718#define FIND_BAND(r, r_band_end, r_end, ry1)do { ry1 = r->y1; r_band_end = r + 1; while ((r_band_end !=
r_end) && (r_band_end->y1 == ry1)) { r_band_end++
; } } while (0)
\
719 do \
720 { \
721 ry1 = r->y1; \
722 r_band_end = r + 1; \
723 while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
724 r_band_end++; \
725 } \
726 } while (0)
727
728#define APPEND_REGIONS(new_reg, r, r_end)do { int new_rects; if ((new_rects = r_end - r)) { do { if (!
(new_reg)->data || (((new_reg)->data->numRects + (new_rects
)) > (new_reg)->data->size)) { if (!pixman_rect_alloc
(new_reg, new_rects)) goto bail; } } while (0); memmove ((char
*)(&((box_type_t *)((new_reg)->data + 1))[(new_reg)->
data->numRects]), (char *)r, new_rects * sizeof(box_type_t
)); new_reg->data->numRects += new_rects; } } while (0)
\
729 do \
730 { \
731 int new_rects; \
732 if ((new_rects = r_end - r)) { \
733 RECTALLOC_BAIL (new_reg, new_rects, bail)do { if (!(new_reg)->data || (((new_reg)->data->numRects
+ (new_rects)) > (new_reg)->data->size)) { if (!pixman_rect_alloc
(new_reg, new_rects)) goto bail; } } while (0)
; \
734 memmove ((char *)PIXREGION_TOP (new_reg)(&((box_type_t *)((new_reg)->data + 1))[(new_reg)->
data->numRects])
, (char *)r, \
735 new_rects * sizeof(box_type_t)); \
736 new_reg->data->numRects += new_rects; \
737 } \
738 } while (0)
739
740/*-
741 *-----------------------------------------------------------------------
742 * pixman_op --
743 * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
744 * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one
745 * rectangle, and cannot be the same object.
746 *
747 * Results:
748 * TRUE if successful.
749 *
750 * Side Effects:
751 * The new region is overwritten.
752 * overlap set to TRUE if overlap_func ever returns TRUE.
753 *
754 * Notes:
755 * The idea behind this function is to view the two regions as sets.
756 * Together they cover a rectangle of area that this function divides
757 * into horizontal bands where points are covered only by one region
758 * or by both. For the first case, the non_overlap_func is called with
759 * each the band and the band's upper and lower extents. For the
760 * second, the overlap_func is called to process the entire band. It
761 * is responsible for clipping the rectangles in the band, though
762 * this function provides the boundaries.
763 * At the end of each band, the new region is coalesced, if possible,
764 * to reduce the number of rectangles in the region.
765 *
766 *-----------------------------------------------------------------------
767 */
768
769typedef pixman_bool_t (*overlap_proc_ptr) (region_type_t *region,
770 box_type_t * r1,
771 box_type_t * r1_end,
772 box_type_t * r2,
773 box_type_t * r2_end,
774 primitive_t y1,
775 primitive_t y2);
776
777static pixman_bool_t
778pixman_op (region_type_t * new_reg, /* Place to store result */
779 const region_type_t * reg1, /* First region in operation */
780 const region_type_t * reg2, /* 2d region in operation */
781 overlap_proc_ptr overlap_func, /* Function to call for over-
782 * lapping bands */
783 int append_non1, /* Append non-overlapping bands
784 * in region 1 ?
785 */
786 int append_non2 /* Append non-overlapping bands
787 * in region 2 ?
788 */
789 )
790{
791 box_type_t *r1; /* Pointer into first region */
792 box_type_t *r2; /* Pointer into 2d region */
793 box_type_t *r1_end; /* End of 1st region */
794 box_type_t *r2_end; /* End of 2d region */
795 primitive_t ybot; /* Bottom of intersection */
796 primitive_t ytop; /* Top of intersection */
797 region_data_type_t *old_data; /* Old data for new_reg */
798 int prev_band; /* Index of start of
799 * previous band in new_reg */
800 int cur_band; /* Index of start of current
801 * band in new_reg */
802 box_type_t * r1_band_end; /* End of current band in r1 */
803 box_type_t * r2_band_end; /* End of current band in r2 */
804 primitive_t top; /* Top of non-overlapping band */
805 primitive_t bot; /* Bottom of non-overlapping band*/
806 primitive_t r1y1; /* Temps for r1->y1 and r2->y1 */
807 primitive_t r2y1;
808 int new_size;
809 int numRects;
810
811 /*
812 * Break any region computed from a broken region
813 */
814 if (PIXREGION_NAR (reg1)((reg1)->data == pixman_broken_data) || PIXREGION_NAR (reg2)((reg2)->data == pixman_broken_data))
815 return pixman_break (new_reg);
816
817 /*
818 * Initialization:
819 * set r1, r2, r1_end and r2_end appropriately, save the rectangles
820 * of the destination region until the end in case it's one of
821 * the two source regions, then mark the "new" region empty, allocating
822 * another array of rectangles for it to use.
823 */
824
825 r1 = PIXREGION_RECTS (reg1)((reg1)->data ? (box_type_t *)((reg1)->data + 1) : (box_type_t
*)&(reg1)->extents)
;
826 new_size = PIXREGION_NUMRECTS (reg1)((reg1)->data ? (reg1)->data->numRects : 1);
827 r1_end = r1 + new_size;
828
829 numRects = PIXREGION_NUMRECTS (reg2)((reg2)->data ? (reg2)->data->numRects : 1);
830 r2 = PIXREGION_RECTS (reg2)((reg2)->data ? (box_type_t *)((reg2)->data + 1) : (box_type_t
*)&(reg2)->extents)
;
831 r2_end = r2 + numRects;
832
833 critical_if_fail (r1 != r1_end)do { if (__builtin_expect ((!(r1 != r1_end)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "r1 != r1_end"
" was false"); } while (0)
;
834 critical_if_fail (r2 != r2_end)do { if (__builtin_expect ((!(r2 != r2_end)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "r2 != r2_end"
" was false"); } while (0)
;
835
836 old_data = (region_data_type_t *)NULL((void*)0);
837
838 if (((new_reg == reg1) && (new_size > 1)) ||
839 ((new_reg == reg2) && (numRects > 1)))
840 {
841 old_data = new_reg->data;
842 new_reg->data = pixman_region_empty_data;
843 }
844
845 /* guess at new size */
846 if (numRects > new_size)
847 new_size = numRects;
848
849 new_size <<= 1;
850
851 if (!new_reg->data)
852 new_reg->data = pixman_region_empty_data;
853 else if (new_reg->data->size)
854 new_reg->data->numRects = 0;
855
856 if (new_size > new_reg->data->size)
857 {
858 if (!pixman_rect_alloc (new_reg, new_size))
859 {
860 free (old_data);
861 return FALSE0;
862 }
863 }
864
865 /*
866 * Initialize ybot.
867 * In the upcoming loop, ybot and ytop serve different functions depending
868 * on whether the band being handled is an overlapping or non-overlapping
869 * band.
870 * In the case of a non-overlapping band (only one of the regions
871 * has points in the band), ybot is the bottom of the most recent
872 * intersection and thus clips the top of the rectangles in that band.
873 * ytop is the top of the next intersection between the two regions and
874 * serves to clip the bottom of the rectangles in the current band.
875 * For an overlapping band (where the two regions intersect), ytop clips
876 * the top of the rectangles of both regions and ybot clips the bottoms.
877 */
878
879 ybot = MIN (r1->y1, r2->y1)((r1->y1 < r2->y1) ? r1->y1 : r2->y1);
880
881 /*
882 * prev_band serves to mark the start of the previous band so rectangles
883 * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
884 * In the beginning, there is no previous band, so prev_band == cur_band
885 * (cur_band is set later on, of course, but the first band will always
886 * start at index 0). prev_band and cur_band must be indices because of
887 * the possible expansion, and resultant moving, of the new region's
888 * array of rectangles.
889 */
890 prev_band = 0;
891
892 do
893 {
894 /*
895 * This algorithm proceeds one source-band (as opposed to a
896 * destination band, which is determined by where the two regions
897 * intersect) at a time. r1_band_end and r2_band_end serve to mark the
898 * rectangle after the last one in the current band for their
899 * respective regions.
900 */
901 critical_if_fail (r1 != r1_end)do { if (__builtin_expect ((!(r1 != r1_end)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "r1 != r1_end"
" was false"); } while (0)
;
902 critical_if_fail (r2 != r2_end)do { if (__builtin_expect ((!(r2 != r2_end)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "r2 != r2_end"
" was false"); } while (0)
;
903
904 FIND_BAND (r1, r1_band_end, r1_end, r1y1)do { r1y1 = r1->y1; r1_band_end = r1 + 1; while ((r1_band_end
!= r1_end) && (r1_band_end->y1 == r1y1)) { r1_band_end
++; } } while (0)
;
905 FIND_BAND (r2, r2_band_end, r2_end, r2y1)do { r2y1 = r2->y1; r2_band_end = r2 + 1; while ((r2_band_end
!= r2_end) && (r2_band_end->y1 == r2y1)) { r2_band_end
++; } } while (0)
;
906
907 /*
908 * First handle the band that doesn't intersect, if any.
909 *
910 * Note that attention is restricted to one band in the
911 * non-intersecting region at once, so if a region has n
912 * bands between the current position and the next place it overlaps
913 * the other, this entire loop will be passed through n times.
914 */
915 if (r1y1 < r2y1)
916 {
917 if (append_non1)
918 {
919 top = MAX (r1y1, ybot)((r1y1 > ybot) ? r1y1 : ybot);
920 bot = MIN (r1->y2, r2y1)((r1->y2 < r2y1) ? r1->y2 : r2y1);
921 if (top != bot)
922 {
923 cur_band = new_reg->data->numRects;
924 if (!pixman_region_append_non_o (new_reg, r1, r1_band_end, top, bot))
925 goto bail;
926 COALESCE (new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
;
927 }
928 }
929 ytop = r2y1;
930 }
931 else if (r2y1 < r1y1)
932 {
933 if (append_non2)
934 {
935 top = MAX (r2y1, ybot)((r2y1 > ybot) ? r2y1 : ybot);
936 bot = MIN (r2->y2, r1y1)((r2->y2 < r1y1) ? r2->y2 : r1y1);
937
938 if (top != bot)
939 {
940 cur_band = new_reg->data->numRects;
941
942 if (!pixman_region_append_non_o (new_reg, r2, r2_band_end, top, bot))
943 goto bail;
944
945 COALESCE (new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
;
946 }
947 }
948 ytop = r1y1;
949 }
950 else
951 {
952 ytop = r1y1;
953 }
954
955 /*
956 * Now see if we've hit an intersecting band. The two bands only
957 * intersect if ybot > ytop
958 */
959 ybot = MIN (r1->y2, r2->y2)((r1->y2 < r2->y2) ? r1->y2 : r2->y2);
960 if (ybot > ytop)
961 {
962 cur_band = new_reg->data->numRects;
963
964 if (!(*overlap_func)(new_reg,
965 r1, r1_band_end,
966 r2, r2_band_end,
967 ytop, ybot))
968 {
969 goto bail;
970 }
971
972 COALESCE (new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
;
973 }
974
975 /*
976 * If we've finished with a band (y2 == ybot) we skip forward
977 * in the region to the next band.
978 */
979 if (r1->y2 == ybot)
980 r1 = r1_band_end;
981
982 if (r2->y2 == ybot)
983 r2 = r2_band_end;
984
985 }
986 while (r1 != r1_end && r2 != r2_end);
987
988 /*
989 * Deal with whichever region (if any) still has rectangles left.
990 *
991 * We only need to worry about banding and coalescing for the very first
992 * band left. After that, we can just group all remaining boxes,
993 * regardless of how many bands, into one final append to the list.
994 */
995
996 if ((r1 != r1_end) && append_non1)
997 {
998 /* Do first non_overlap1Func call, which may be able to coalesce */
999 FIND_BAND (r1, r1_band_end, r1_end, r1y1)do { r1y1 = r1->y1; r1_band_end = r1 + 1; while ((r1_band_end
!= r1_end) && (r1_band_end->y1 == r1y1)) { r1_band_end
++; } } while (0)
;
1000
1001 cur_band = new_reg->data->numRects;
1002
1003 if (!pixman_region_append_non_o (new_reg,
1004 r1, r1_band_end,
1005 MAX (r1y1, ybot)((r1y1 > ybot) ? r1y1 : ybot), r1->y2))
1006 {
1007 goto bail;
1008 }
1009
1010 COALESCE (new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
;
1011
1012 /* Just append the rest of the boxes */
1013 APPEND_REGIONS (new_reg, r1_band_end, r1_end)do { int new_rects; if ((new_rects = r1_end - r1_band_end)) {
do { if (!(new_reg)->data || (((new_reg)->data->numRects
+ (new_rects)) > (new_reg)->data->size)) { if (!pixman_rect_alloc
(new_reg, new_rects)) goto bail; } } while (0); memmove ((char
*)(&((box_type_t *)((new_reg)->data + 1))[(new_reg)->
data->numRects]), (char *)r1_band_end, new_rects * sizeof(
box_type_t)); new_reg->data->numRects += new_rects; } }
while (0)
;
1014 }
1015 else if ((r2 != r2_end) && append_non2)
1016 {
1017 /* Do first non_overlap2Func call, which may be able to coalesce */
1018 FIND_BAND (r2, r2_band_end, r2_end, r2y1)do { r2y1 = r2->y1; r2_band_end = r2 + 1; while ((r2_band_end
!= r2_end) && (r2_band_end->y1 == r2y1)) { r2_band_end
++; } } while (0)
;
1019
1020 cur_band = new_reg->data->numRects;
1021
1022 if (!pixman_region_append_non_o (new_reg,
1023 r2, r2_band_end,
1024 MAX (r2y1, ybot)((r2y1 > ybot) ? r2y1 : ybot), r2->y2))
1025 {
1026 goto bail;
1027 }
1028
1029 COALESCE (new_reg, prev_band, cur_band)do { if (cur_band - prev_band == new_reg->data->numRects
- cur_band) prev_band = pixman_coalesce (new_reg, prev_band,
cur_band); else prev_band = cur_band; } while (0)
;
1030
1031 /* Append rest of boxes */
1032 APPEND_REGIONS (new_reg, r2_band_end, r2_end)do { int new_rects; if ((new_rects = r2_end - r2_band_end)) {
do { if (!(new_reg)->data || (((new_reg)->data->numRects
+ (new_rects)) > (new_reg)->data->size)) { if (!pixman_rect_alloc
(new_reg, new_rects)) goto bail; } } while (0); memmove ((char
*)(&((box_type_t *)((new_reg)->data + 1))[(new_reg)->
data->numRects]), (char *)r2_band_end, new_rects * sizeof(
box_type_t)); new_reg->data->numRects += new_rects; } }
while (0)
;
1033 }
1034
1035 free (old_data);
1036
1037 if (!(numRects = new_reg->data->numRects))
1038 {
1039 FREE_DATA (new_reg)if ((new_reg)->data && (new_reg)->data->size
) free ((new_reg)->data)
;
1040 new_reg->data = pixman_region_empty_data;
1041 }
1042 else if (numRects == 1)
1043 {
1044 new_reg->extents = *PIXREGION_BOXPTR (new_reg)((box_type_t *)((new_reg)->data + 1));
1045 FREE_DATA (new_reg)if ((new_reg)->data && (new_reg)->data->size
) free ((new_reg)->data)
;
1046 new_reg->data = (region_data_type_t *)NULL((void*)0);
1047 }
1048 else
1049 {
1050 DOWNSIZE (new_reg, numRects)do { if (((numRects) < ((new_reg)->data->size >>
1)) && ((new_reg)->data->size > 50)) { region_data_type_t
* new_data; size_t data_size = PIXREGION_SZOF (numRects); if
(!data_size) { new_data = ((void*)0); } else { new_data = (region_data_type_t
*) realloc ((new_reg)->data, data_size); } if (new_data) {
new_data->size = (numRects); (new_reg)->data = new_data
; } } } while (0)
;
1051 }
1052
1053 return TRUE1;
1054
1055bail:
1056 free (old_data);
1057
1058 return pixman_break (new_reg);
1059}
1060
1061/*-
1062 *-----------------------------------------------------------------------
1063 * pixman_set_extents --
1064 * Reset the extents of a region to what they should be. Called by
1065 * pixman_region_subtract and pixman_region_intersect as they can't
1066 * figure it out along the way or do so easily, as pixman_region_union can.
1067 *
1068 * Results:
1069 * None.
1070 *
1071 * Side Effects:
1072 * The region's 'extents' structure is overwritten.
1073 *
1074 *-----------------------------------------------------------------------
1075 */
1076static void
1077pixman_set_extents (region_type_t *region)
1078{
1079 box_type_t *box, *box_end;
1080
1081 if (!region->data)
1082 return;
1083
1084 if (!region->data->size)
1085 {
1086 region->extents.x2 = region->extents.x1;
1087 region->extents.y2 = region->extents.y1;
1088 return;
1089 }
1090
1091 box = PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1));
1092 box_end = PIXREGION_END (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects - 1])
;
1093
1094 /*
1095 * Since box is the first rectangle in the region, it must have the
1096 * smallest y1 and since box_end is the last rectangle in the region,
1097 * it must have the largest y2, because of banding. Initialize x1 and
1098 * x2 from box and box_end, resp., as good things to initialize them
1099 * to...
1100 */
1101 region->extents.x1 = box->x1;
1102 region->extents.y1 = box->y1;
1103 region->extents.x2 = box_end->x2;
1104 region->extents.y2 = box_end->y2;
1105
1106 critical_if_fail (region->extents.y1 < region->extents.y2)do { if (__builtin_expect ((!(region->extents.y1 < region
->extents.y2)), 0)) _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "region->extents.y1 < region->extents.y2"
" was false"); } while (0)
;
1107
1108 while (box <= box_end)
1109 {
1110 if (box->x1 < region->extents.x1)
1111 region->extents.x1 = box->x1;
1112 if (box->x2 > region->extents.x2)
1113 region->extents.x2 = box->x2;
1114 box++;
1115 }
1116
1117 critical_if_fail (region->extents.x1 < region->extents.x2)do { if (__builtin_expect ((!(region->extents.x1 < region
->extents.x2)), 0)) _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "region->extents.x1 < region->extents.x2"
" was false"); } while (0)
;
1118}
1119
1120/*======================================================================
1121 * Region Intersection
1122 *====================================================================*/
1123/*-
1124 *-----------------------------------------------------------------------
1125 * pixman_region_intersect_o --
1126 * Handle an overlapping band for pixman_region_intersect.
1127 *
1128 * Results:
1129 * TRUE if successful.
1130 *
1131 * Side Effects:
1132 * Rectangles may be added to the region.
1133 *
1134 *-----------------------------------------------------------------------
1135 */
1136/*ARGSUSED*/
1137static pixman_bool_t
1138pixman_region_intersect_o (region_type_t *region,
1139 box_type_t * r1,
1140 box_type_t * r1_end,
1141 box_type_t * r2,
1142 box_type_t * r2_end,
1143 primitive_t y1,
1144 primitive_t y2)
1145{
1146 primitive_t x1;
1147 primitive_t x2;
1148 box_type_t * next_rect;
1149
1150 next_rect = PIXREGION_TOP (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects])
;
1151
1152 critical_if_fail (y1 < y2)do { if (__builtin_expect ((!(y1 < y2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "y1 < y2"
" was false"); } while (0)
;
1153 critical_if_fail (r1 != r1_end && r2 != r2_end)do { if (__builtin_expect ((!(r1 != r1_end && r2 != r2_end
)), 0)) _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "r1 != r1_end && r2 != r2_end" " was false"
); } while (0)
;
1154
1155 do
1156 {
1157 x1 = MAX (r1->x1, r2->x1)((r1->x1 > r2->x1) ? r1->x1 : r2->x1);
1158 x2 = MIN (r1->x2, r2->x2)((r1->x2 < r2->x2) ? r1->x2 : r2->x2);
1159
1160 /*
1161 * If there's any overlap between the two rectangles, add that
1162 * overlap to the new region.
1163 */
1164 if (x1 < x2)
1165 NEWRECT (region, next_rect, x1, y1, x2, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
;
1166
1167 /*
1168 * Advance the pointer(s) with the leftmost right side, since the next
1169 * rectangle on that list may still overlap the other region's
1170 * current rectangle.
1171 */
1172 if (r1->x2 == x2)
1173 {
1174 r1++;
1175 }
1176 if (r2->x2 == x2)
1177 {
1178 r2++;
1179 }
1180 }
1181 while ((r1 != r1_end) && (r2 != r2_end));
1182
1183 return TRUE1;
1184}
1185
1186PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1187PREFIX (_intersect)_moz_pixman_region32_intersect (region_type_t * new_reg,
1188 const region_type_t * reg1,
1189 const region_type_t * reg2)
1190{
1191 GOOD (reg1)do { if (!_moz_pixman_region32_selfcheck (reg1)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg1"
); } while (0)
;
1192 GOOD (reg2)do { if (!_moz_pixman_region32_selfcheck (reg2)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg2"
); } while (0)
;
1193 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
1194
1195 /* check for trivial reject */
1196 if (PIXREGION_NIL (reg1)((reg1)->data && !(reg1)->data->numRects) || PIXREGION_NIL (reg2)((reg2)->data && !(reg2)->data->numRects) ||
1197 !EXTENTCHECK (&reg1->extents, &reg2->extents)(!( ((&reg1->extents)->x2 <= (&reg2->extents
)->x1) || ((&reg1->extents)->x1 >= (&reg2
->extents)->x2) || ((&reg1->extents)->y2 <=
(&reg2->extents)->y1) || ((&reg1->extents)->
y1 >= (&reg2->extents)->y2) ) )
)
1198 {
1199 /* Covers about 20% of all cases */
1200 FREE_DATA (new_reg)if ((new_reg)->data && (new_reg)->data->size
) free ((new_reg)->data)
;
1201 new_reg->extents.x2 = new_reg->extents.x1;
1202 new_reg->extents.y2 = new_reg->extents.y1;
1203 if (PIXREGION_NAR (reg1)((reg1)->data == pixman_broken_data) || PIXREGION_NAR (reg2)((reg2)->data == pixman_broken_data))
1204 {
1205 new_reg->data = pixman_broken_data;
1206 return FALSE0;
1207 }
1208 else
1209 {
1210 new_reg->data = pixman_region_empty_data;
1211 }
1212 }
1213 else if (!reg1->data && !reg2->data)
1214 {
1215 /* Covers about 80% of cases that aren't trivially rejected */
1216 new_reg->extents.x1 = MAX (reg1->extents.x1, reg2->extents.x1)((reg1->extents.x1 > reg2->extents.x1) ? reg1->extents
.x1 : reg2->extents.x1)
;
1217 new_reg->extents.y1 = MAX (reg1->extents.y1, reg2->extents.y1)((reg1->extents.y1 > reg2->extents.y1) ? reg1->extents
.y1 : reg2->extents.y1)
;
1218 new_reg->extents.x2 = MIN (reg1->extents.x2, reg2->extents.x2)((reg1->extents.x2 < reg2->extents.x2) ? reg1->extents
.x2 : reg2->extents.x2)
;
1219 new_reg->extents.y2 = MIN (reg1->extents.y2, reg2->extents.y2)((reg1->extents.y2 < reg2->extents.y2) ? reg1->extents
.y2 : reg2->extents.y2)
;
1220
1221 FREE_DATA (new_reg)if ((new_reg)->data && (new_reg)->data->size
) free ((new_reg)->data)
;
1222
1223 new_reg->data = (region_data_type_t *)NULL((void*)0);
1224 }
1225 else if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents)( ((&reg2->extents)->x1 <= (&reg1->extents
)->x1) && ((&reg2->extents)->x2 >= (&
reg1->extents)->x2) && ((&reg2->extents)
->y1 <= (&reg1->extents)->y1) && ((&
reg2->extents)->y2 >= (&reg1->extents)->y2
) )
)
1226 {
1227 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg1);
1228 }
1229 else if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents)( ((&reg1->extents)->x1 <= (&reg2->extents
)->x1) && ((&reg1->extents)->x2 >= (&
reg2->extents)->x2) && ((&reg1->extents)
->y1 <= (&reg2->extents)->y1) && ((&
reg1->extents)->y2 >= (&reg2->extents)->y2
) )
)
1230 {
1231 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg2);
1232 }
1233 else if (reg1 == reg2)
1234 {
1235 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg1);
1236 }
1237 else
1238 {
1239 /* General purpose intersection */
1240
1241 if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE0, FALSE0))
1242 return FALSE0;
1243
1244 pixman_set_extents (new_reg);
1245 }
1246
1247 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
1248 return(TRUE1);
1249}
1250
1251#define MERGERECT(r)do { if (r->x1 <= x2) { if (x2 < r->x2) x2 = r->
x2; } else { do { if (!(region)->data || ((region)->data
->numRects == (region)->data->size)) { if (!pixman_rect_alloc
(region, 1)) return 0; next_rect = (&((box_type_t *)((region
)->data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0); x1 = r->x1; x2 =
r->x2; } r++; } while (0)
\
1252 do \
1253 { \
1254 if (r->x1 <= x2) \
1255 { \
1256 /* Merge with current rectangle */ \
1257 if (x2 < r->x2) \
1258 x2 = r->x2; \
1259 } \
1260 else \
1261 { \
1262 /* Add current rectangle, start new one */ \
1263 NEWRECT (region, next_rect, x1, y1, x2, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
; \
1264 x1 = r->x1; \
1265 x2 = r->x2; \
1266 } \
1267 r++; \
1268 } while (0)
1269
1270/*======================================================================
1271 * Region Union
1272 *====================================================================*/
1273
1274/*-
1275 *-----------------------------------------------------------------------
1276 * pixman_region_union_o --
1277 * Handle an overlapping band for the union operation. Picks the
1278 * left-most rectangle each time and merges it into the region.
1279 *
1280 * Results:
1281 * TRUE if successful.
1282 *
1283 * Side Effects:
1284 * region is overwritten.
1285 * overlap is set to TRUE if any boxes overlap.
1286 *
1287 *-----------------------------------------------------------------------
1288 */
1289static pixman_bool_t
1290pixman_region_union_o (region_type_t *region,
1291 box_type_t * r1,
1292 box_type_t * r1_end,
1293 box_type_t * r2,
1294 box_type_t * r2_end,
1295 primitive_t y1,
1296 primitive_t y2)
1297{
1298 box_type_t *next_rect;
1299 primitive_t x1; /* left and right side of current union */
1300 primitive_t x2;
1301
1302 critical_if_fail (y1 < y2)do { if (__builtin_expect ((!(y1 < y2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "y1 < y2"
" was false"); } while (0)
;
1303 critical_if_fail (r1 != r1_end && r2 != r2_end)do { if (__builtin_expect ((!(r1 != r1_end && r2 != r2_end
)), 0)) _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "r1 != r1_end && r2 != r2_end" " was false"
); } while (0)
;
1304
1305 next_rect = PIXREGION_TOP (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects])
;
1306
1307 /* Start off current rectangle */
1308 if (r1->x1 < r2->x1)
1309 {
1310 x1 = r1->x1;
1311 x2 = r1->x2;
1312 r1++;
1313 }
1314 else
1315 {
1316 x1 = r2->x1;
1317 x2 = r2->x2;
1318 r2++;
1319 }
1320 while (r1 != r1_end && r2 != r2_end)
1321 {
1322 if (r1->x1 < r2->x1)
1323 MERGERECT (r1)do { if (r1->x1 <= x2) { if (x2 < r1->x2) x2 = r1
->x2; } else { do { if (!(region)->data || ((region)->
data->numRects == (region)->data->size)) { if (!pixman_rect_alloc
(region, 1)) return 0; next_rect = (&((box_type_t *)((region
)->data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0); x1 = r1->x1; x2 =
r1->x2; } r1++; } while (0)
;
1324 else
1325 MERGERECT (r2)do { if (r2->x1 <= x2) { if (x2 < r2->x2) x2 = r2
->x2; } else { do { if (!(region)->data || ((region)->
data->numRects == (region)->data->size)) { if (!pixman_rect_alloc
(region, 1)) return 0; next_rect = (&((box_type_t *)((region
)->data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0); x1 = r2->x1; x2 =
r2->x2; } r2++; } while (0)
;
1326 }
1327
1328 /* Finish off whoever (if any) is left */
1329 if (r1 != r1_end)
1330 {
1331 do
1332 {
1333 MERGERECT (r1)do { if (r1->x1 <= x2) { if (x2 < r1->x2) x2 = r1
->x2; } else { do { if (!(region)->data || ((region)->
data->numRects == (region)->data->size)) { if (!pixman_rect_alloc
(region, 1)) return 0; next_rect = (&((box_type_t *)((region
)->data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0); x1 = r1->x1; x2 =
r1->x2; } r1++; } while (0)
;
1334 }
1335 while (r1 != r1_end);
1336 }
1337 else if (r2 != r2_end)
1338 {
1339 do
1340 {
1341 MERGERECT (r2)do { if (r2->x1 <= x2) { if (x2 < r2->x2) x2 = r2
->x2; } else { do { if (!(region)->data || ((region)->
data->numRects == (region)->data->size)) { if (!pixman_rect_alloc
(region, 1)) return 0; next_rect = (&((box_type_t *)((region
)->data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0); x1 = r2->x1; x2 =
r2->x2; } r2++; } while (0)
;
1342 }
1343 while (r2 != r2_end);
1344 }
1345
1346 /* Add current rectangle */
1347 NEWRECT (region, next_rect, x1, y1, x2, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = x2; next_rect
->y2 = y2; next_rect++; } while (0); region->data->numRects
++; do { if (__builtin_expect ((!(region->data->numRects
<= region->data->size)), 0)) _pixman_log_error (((const
char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
;
1348
1349 return TRUE1;
1350}
1351
1352PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1353PREFIX(_intersect_rect)_moz_pixman_region32_intersect_rect (region_type_t *dest,
1354 const region_type_t *source,
1355 int x, int y,
1356 unsigned int width,
1357 unsigned int height)
1358{
1359 region_type_t region;
1360
1361 region.data = NULL((void*)0);
1362 region.extents.x1 = x;
1363 region.extents.y1 = y;
1364 region.extents.x2 = x + width;
1365 region.extents.y2 = y + height;
1366
1367 return PREFIX(_intersect)_moz_pixman_region32_intersect (dest, source, &region);
1368}
1369
1370PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1371PREFIX(_intersect_rectf)pixman_region32_intersect_rectf (region_type_t *dest,
1372 const region_type_t *source,
1373 double x, double y,
1374 double width,
1375 double height)
1376{
1377 region_type_t region;
1378
1379 region.data = NULL((void*)0);
1380 region.extents.x1 = x;
1381 region.extents.y1 = y;
1382 region.extents.x2 = x + width;
1383 region.extents.y2 = y + height;
1384
1385 return PREFIX(_intersect)_moz_pixman_region32_intersect (dest, source, &region);
1386}
1387
1388/* Convenience function for performing union of region with a
1389 * single rectangle
1390 */
1391PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1392PREFIX (_union_rect)_moz_pixman_region32_union_rect (region_type_t *dest,
1393 const region_type_t *source,
1394 int x,
1395 int y,
1396 unsigned int width,
1397 unsigned int height)
1398{
1399 region_type_t region;
1400
1401 region.extents.x1 = x;
1402 region.extents.y1 = y;
1403 region.extents.x2 = x + width;
1404 region.extents.y2 = y + height;
1405
1406 if (!GOOD_RECT (&region.extents)((&region.extents)->x1 < (&region.extents)->
x2 && (&region.extents)->y1 < (&region.
extents)->y2)
)
1407 {
1408 if (BAD_RECT (&region.extents)((&region.extents)->x1 > (&region.extents)->
x2 || (&region.extents)->y1 > (&region.extents)
->y2)
)
1409 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Invalid rectangle passed");
1410 return PREFIX (_copy)_moz_pixman_region32_copy (dest, source);
1411 }
1412
1413 region.data = NULL((void*)0);
1414
1415 return PREFIX (_union)_moz_pixman_region32_union (dest, source, &region);
1416}
1417
1418PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1419PREFIX (_union_rectf)pixman_region32_union_rectf (region_type_t *dest,
1420 const region_type_t *source,
1421 double x,
1422 double y,
1423 double width,
1424 double height)
1425{
1426 region_type_t region;
1427
1428 region.extents.x1 = x;
1429 region.extents.y1 = y;
1430 region.extents.x2 = x + width;
1431 region.extents.y2 = y + height;
1432
1433 if (!GOOD_RECT (&region.extents)((&region.extents)->x1 < (&region.extents)->
x2 && (&region.extents)->y1 < (&region.
extents)->y2)
)
1434 {
1435 if (BAD_RECT (&region.extents)((&region.extents)->x1 > (&region.extents)->
x2 || (&region.extents)->y1 > (&region.extents)
->y2)
)
1436 _pixman_log_error (FUNC((const char*) (__PRETTY_FUNCTION__)), "Invalid rectangle passed");
1437 return PREFIX (_copy)_moz_pixman_region32_copy (dest, source);
1438 }
1439
1440 region.data = NULL((void*)0);
1441
1442 return PREFIX (_union)_moz_pixman_region32_union (dest, source, &region);
1443}
1444
1445PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
1446PREFIX (_union)_moz_pixman_region32_union (region_type_t * new_reg,
1447 const region_type_t *reg1,
1448 const region_type_t *reg2)
1449{
1450 /* Return TRUE if some overlap
1451 * between reg1, reg2
1452 */
1453 GOOD (reg1)do { if (!_moz_pixman_region32_selfcheck (reg1)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg1"
); } while (0)
;
1454 GOOD (reg2)do { if (!_moz_pixman_region32_selfcheck (reg2)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg2"
); } while (0)
;
1455 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
1456
1457 /* checks all the simple cases */
1458
1459 /*
1460 * Region 1 and 2 are the same
1461 */
1462 if (reg1 == reg2)
1463 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg1);
1464
1465 /*
1466 * Region 1 is empty
1467 */
1468 if (PIXREGION_NIL (reg1)((reg1)->data && !(reg1)->data->numRects))
1469 {
1470 if (PIXREGION_NAR (reg1)((reg1)->data == pixman_broken_data))
1471 return pixman_break (new_reg);
1472
1473 if (new_reg != reg2)
1474 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg2);
1475
1476 return TRUE1;
1477 }
1478
1479 /*
1480 * Region 2 is empty
1481 */
1482 if (PIXREGION_NIL (reg2)((reg2)->data && !(reg2)->data->numRects))
1483 {
1484 if (PIXREGION_NAR (reg2)((reg2)->data == pixman_broken_data))
1485 return pixman_break (new_reg);
1486
1487 if (new_reg != reg1)
1488 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg1);
1489
1490 return TRUE1;
1491 }
1492
1493 /*
1494 * Region 1 completely subsumes region 2
1495 */
1496 if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents)( ((&reg1->extents)->x1 <= (&reg2->extents
)->x1) && ((&reg1->extents)->x2 >= (&
reg2->extents)->x2) && ((&reg1->extents)
->y1 <= (&reg2->extents)->y1) && ((&
reg1->extents)->y2 >= (&reg2->extents)->y2
) )
)
1497 {
1498 if (new_reg != reg1)
1499 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg1);
1500
1501 return TRUE1;
1502 }
1503
1504 /*
1505 * Region 2 completely subsumes region 1
1506 */
1507 if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents)( ((&reg2->extents)->x1 <= (&reg1->extents
)->x1) && ((&reg2->extents)->x2 >= (&
reg1->extents)->x2) && ((&reg2->extents)
->y1 <= (&reg1->extents)->y1) && ((&
reg2->extents)->y2 >= (&reg1->extents)->y2
) )
)
1508 {
1509 if (new_reg != reg2)
1510 return PREFIX (_copy)_moz_pixman_region32_copy (new_reg, reg2);
1511
1512 return TRUE1;
1513 }
1514
1515 if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE1, TRUE1))
1516 return FALSE0;
1517
1518 new_reg->extents.x1 = MIN (reg1->extents.x1, reg2->extents.x1)((reg1->extents.x1 < reg2->extents.x1) ? reg1->extents
.x1 : reg2->extents.x1)
;
1519 new_reg->extents.y1 = MIN (reg1->extents.y1, reg2->extents.y1)((reg1->extents.y1 < reg2->extents.y1) ? reg1->extents
.y1 : reg2->extents.y1)
;
1520 new_reg->extents.x2 = MAX (reg1->extents.x2, reg2->extents.x2)((reg1->extents.x2 > reg2->extents.x2) ? reg1->extents
.x2 : reg2->extents.x2)
;
1521 new_reg->extents.y2 = MAX (reg1->extents.y2, reg2->extents.y2)((reg1->extents.y2 > reg2->extents.y2) ? reg1->extents
.y2 : reg2->extents.y2)
;
1522
1523 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
1524
1525 return TRUE1;
1526}
1527
1528/*======================================================================
1529 * Batch Rectangle Union
1530 *====================================================================*/
1531
1532#define EXCHANGE_RECTS(a, b){ box_type_t t; t = rects[a]; rects[a] = rects[b]; rects[b] =
t; }
\
1533 { \
1534 box_type_t t; \
1535 t = rects[a]; \
1536 rects[a] = rects[b]; \
1537 rects[b] = t; \
1538 }
1539
1540static void
1541quick_sort_rects (
1542 box_type_t rects[],
1543 int numRects)
1544{
1545 primitive_t y1;
1546 primitive_t x1;
1547 int i, j;
1548 box_type_t *r;
1549
1550 /* Always called with numRects > 1 */
1551
1552 do
1553 {
1554 if (numRects == 2)
1555 {
1556 if (rects[0].y1 > rects[1].y1 ||
1557 (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1558 {
1559 EXCHANGE_RECTS (0, 1){ box_type_t t; t = rects[0]; rects[0] = rects[1]; rects[1] =
t; }
;
1560 }
1561
1562 return;
1563 }
1564
1565 /* Choose partition element, stick in location 0 */
1566 EXCHANGE_RECTS (0, numRects >> 1){ box_type_t t; t = rects[0]; rects[0] = rects[numRects >>
1]; rects[numRects >> 1] = t; }
;
1567 y1 = rects[0].y1;
1568 x1 = rects[0].x1;
1569
1570 /* Partition array */
1571 i = 0;
1572 j = numRects;
1573
1574 do
1575 {
1576 r = &(rects[i]);
1577 do
1578 {
1579 r++;
1580 i++;
1581 }
1582 while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1583
1584 r = &(rects[j]);
1585 do
1586 {
1587 r--;
1588 j--;
1589 }
1590 while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1591
1592 if (i < j)
1593 EXCHANGE_RECTS (i, j){ box_type_t t; t = rects[i]; rects[i] = rects[j]; rects[j] =
t; }
;
1594 }
1595 while (i < j);
1596
1597 /* Move partition element back to middle */
1598 EXCHANGE_RECTS (0, j){ box_type_t t; t = rects[0]; rects[0] = rects[j]; rects[j] =
t; }
;
1599
1600 /* Recurse */
1601 if (numRects - j - 1 > 1)
1602 quick_sort_rects (&rects[j + 1], numRects - j - 1);
1603
1604 numRects = j;
1605 }
1606 while (numRects > 1);
1607}
1608
1609/*-
1610 *-----------------------------------------------------------------------
1611 * pixman_region_validate --
1612 *
1613 * Take a ``region'' which is a non-y-x-banded random collection of
1614 * rectangles, and compute a nice region which is the union of all the
1615 * rectangles.
1616 *
1617 * Results:
1618 * TRUE if successful.
1619 *
1620 * Side Effects:
1621 * The passed-in ``region'' may be modified.
1622 * overlap set to TRUE if any retangles overlapped,
1623 * else FALSE;
1624 *
1625 * Strategy:
1626 * Step 1. Sort the rectangles into ascending order with primary key y1
1627 * and secondary key x1.
1628 *
1629 * Step 2. Split the rectangles into the minimum number of proper y-x
1630 * banded regions. This may require horizontally merging
1631 * rectangles, and vertically coalescing bands. With any luck,
1632 * this step in an identity transformation (ala the Box widget),
1633 * or a coalescing into 1 box (ala Menus).
1634 *
1635 * Step 3. Merge the separate regions down to a single region by calling
1636 * pixman_region_union. Maximize the work each pixman_region_union call does by using
1637 * a binary merge.
1638 *
1639 *-----------------------------------------------------------------------
1640 */
1641
1642static pixman_bool_t
1643validate (region_type_t * badreg)
1644{
1645 /* Descriptor for regions under construction in Step 2. */
1646 typedef struct
1647 {
1648 region_type_t reg;
1649 int prev_band;
1650 int cur_band;
1651 } region_info_t;
1652
1653 region_info_t stack_regions[64];
1654
1655 int numRects; /* Original numRects for badreg */
1656 region_info_t *ri; /* Array of current regions */
1657 int num_ri; /* Number of entries used in ri */
1658 int size_ri; /* Number of entries available in ri */
1659 int i; /* Index into rects */
1660 int j; /* Index into ri */
1661 region_info_t *rit; /* &ri[j] */
1662 region_type_t *reg; /* ri[j].reg */
1663 box_type_t *box; /* Current box in rects */
1664 box_type_t *ri_box; /* Last box in ri[j].reg */
1665 region_type_t *hreg; /* ri[j_half].reg */
1666 pixman_bool_t ret = TRUE1;
1667
1668 if (!badreg->data)
1669 {
1670 GOOD (badreg)do { if (!_moz_pixman_region32_selfcheck (badreg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "badreg"
); } while (0)
;
1671 return TRUE1;
1672 }
1673
1674 numRects = badreg->data->numRects;
1675 if (!numRects)
1676 {
1677 if (PIXREGION_NAR (badreg)((badreg)->data == pixman_broken_data))
1678 return FALSE0;
1679 GOOD (badreg)do { if (!_moz_pixman_region32_selfcheck (badreg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "badreg"
); } while (0)
;
1680 return TRUE1;
1681 }
1682
1683 if (badreg->extents.x1 < badreg->extents.x2)
1684 {
1685 if ((numRects) == 1)
1686 {
1687 FREE_DATA (badreg)if ((badreg)->data && (badreg)->data->size) free
((badreg)->data)
;
1688 badreg->data = (region_data_type_t *) NULL((void*)0);
1689 }
1690 else
1691 {
1692 DOWNSIZE (badreg, numRects)do { if (((numRects) < ((badreg)->data->size >>
1)) && ((badreg)->data->size > 50)) { region_data_type_t
* new_data; size_t data_size = PIXREGION_SZOF (numRects); if
(!data_size) { new_data = ((void*)0); } else { new_data = (region_data_type_t
*) realloc ((badreg)->data, data_size); } if (new_data) {
new_data->size = (numRects); (badreg)->data = new_data
; } } } while (0)
;
1693 }
1694
1695 GOOD (badreg)do { if (!_moz_pixman_region32_selfcheck (badreg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "badreg"
); } while (0)
;
1696
1697 return TRUE1;
1698 }
1699
1700 /* Step 1: Sort the rects array into ascending (y1, x1) order */
1701 quick_sort_rects (PIXREGION_BOXPTR (badreg)((box_type_t *)((badreg)->data + 1)), numRects);
1702
1703 /* Step 2: Scatter the sorted array into the minimum number of regions */
1704
1705 /* Set up the first region to be the first rectangle in badreg */
1706 /* Note that step 2 code will never overflow the ri[0].reg rects array */
1707 ri = stack_regions;
1708 size_ri = sizeof (stack_regions) / sizeof (stack_regions[0]);
1709 num_ri = 1;
1710 ri[0].prev_band = 0;
1711 ri[0].cur_band = 0;
1712 ri[0].reg = *badreg;
1713 box = PIXREGION_BOXPTR (&ri[0].reg)((box_type_t *)((&ri[0].reg)->data + 1));
1714 ri[0].reg.extents = *box;
1715 ri[0].reg.data->numRects = 1;
1716 badreg->extents = *pixman_region_empty_box;
1717 badreg->data = pixman_region_empty_data;
1718
1719 /* Now scatter rectangles into the minimum set of valid regions. If the
1720 * next rectangle to be added to a region would force an existing rectangle
1721 * in the region to be split up in order to maintain y-x banding, just
1722 * forget it. Try the next region. If it doesn't fit cleanly into any
1723 * region, make a new one.
1724 */
1725
1726 for (i = numRects; --i > 0;)
1727 {
1728 box++;
1729 /* Look for a region to append box to */
1730 for (j = num_ri, rit = ri; --j >= 0; rit++)
1731 {
1732 reg = &rit->reg;
1733 ri_box = PIXREGION_END (reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects - 1])
;
1734
1735 if (box->y1 == ri_box->y1 && box->y2 == ri_box->y2)
1736 {
1737 /* box is in same band as ri_box. Merge or append it */
1738 if (box->x1 <= ri_box->x2)
1739 {
1740 /* Merge it with ri_box */
1741 if (box->x2 > ri_box->x2)
1742 ri_box->x2 = box->x2;
1743 }
1744 else
1745 {
1746 RECTALLOC_BAIL (reg, 1, bail)do { if (!(reg)->data || (((reg)->data->numRects + (
1)) > (reg)->data->size)) { if (!pixman_rect_alloc (
reg, 1)) goto bail; } } while (0)
;
1747 *PIXREGION_TOP (reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects])
= *box;
1748 reg->data->numRects++;
1749 }
1750
1751 goto next_rect; /* So sue me */
1752 }
1753 else if (box->y1 >= ri_box->y2)
1754 {
1755 /* Put box into new band */
1756 if (reg->extents.x2 < ri_box->x2)
1757 reg->extents.x2 = ri_box->x2;
1758
1759 if (reg->extents.x1 > box->x1)
1760 reg->extents.x1 = box->x1;
1761
1762 COALESCE (reg, rit->prev_band, rit->cur_band)do { if (rit->cur_band - rit->prev_band == reg->data
->numRects - rit->cur_band) rit->prev_band = pixman_coalesce
(reg, rit->prev_band, rit->cur_band); else rit->prev_band
= rit->cur_band; } while (0)
;
1763 rit->cur_band = reg->data->numRects;
1764 RECTALLOC_BAIL (reg, 1, bail)do { if (!(reg)->data || (((reg)->data->numRects + (
1)) > (reg)->data->size)) { if (!pixman_rect_alloc (
reg, 1)) goto bail; } } while (0)
;
1765 *PIXREGION_TOP (reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects])
= *box;
1766 reg->data->numRects++;
1767
1768 goto next_rect;
1769 }
1770 /* Well, this region was inappropriate. Try the next one. */
1771 } /* for j */
1772
1773 /* Uh-oh. No regions were appropriate. Create a new one. */
1774 if (size_ri == num_ri)
1775 {
1776 size_t data_size;
1777
1778 /* Oops, allocate space for new region information */
1779 size_ri <<= 1;
1780
1781 data_size = size_ri * sizeof(region_info_t);
1782 if (data_size / size_ri != sizeof(region_info_t))
1783 goto bail;
1784
1785 if (ri == stack_regions)
1786 {
1787 rit = malloc (data_size);
1788 if (!rit)
1789 goto bail;
1790 memcpy (rit, ri, num_ri * sizeof (region_info_t));
1791 }
1792 else
1793 {
1794 rit = (region_info_t *) realloc (ri, data_size);
1795 if (!rit)
1796 goto bail;
1797 }
1798 ri = rit;
1799 rit = &ri[num_ri];
1800 }
1801 num_ri++;
1802 rit->prev_band = 0;
1803 rit->cur_band = 0;
1804 rit->reg.extents = *box;
1805 rit->reg.data = (region_data_type_t *)NULL((void*)0);
1806
1807 /* MUST force allocation */
1808 if (!pixman_rect_alloc (&rit->reg, (i + num_ri) / num_ri))
1809 goto bail;
1810
1811 next_rect: ;
1812 } /* for i */
1813
1814 /* Make a final pass over each region in order to COALESCE and set
1815 * extents.x2 and extents.y2
1816 */
1817 for (j = num_ri, rit = ri; --j >= 0; rit++)
1818 {
1819 reg = &rit->reg;
1820 ri_box = PIXREGION_END (reg)(&((box_type_t *)((reg)->data + 1))[(reg)->data->
numRects - 1])
;
1821 reg->extents.y2 = ri_box->y2;
1822
1823 if (reg->extents.x2 < ri_box->x2)
1824 reg->extents.x2 = ri_box->x2;
1825
1826 COALESCE (reg, rit->prev_band, rit->cur_band)do { if (rit->cur_band - rit->prev_band == reg->data
->numRects - rit->cur_band) rit->prev_band = pixman_coalesce
(reg, rit->prev_band, rit->cur_band); else rit->prev_band
= rit->cur_band; } while (0)
;
1827
1828 if (reg->data->numRects == 1) /* keep unions happy below */
1829 {
1830 FREE_DATA (reg)if ((reg)->data && (reg)->data->size) free (
(reg)->data)
;
1831 reg->data = (region_data_type_t *)NULL((void*)0);
1832 }
1833 }
1834
1835 /* Step 3: Union all regions into a single region */
1836 while (num_ri > 1)
1837 {
1838 int half = num_ri / 2;
1839 for (j = num_ri & 1; j < (half + (num_ri & 1)); j++)
1840 {
1841 reg = &ri[j].reg;
1842 hreg = &ri[j + half].reg;
1843
1844 if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE1, TRUE1))
1845 ret = FALSE0;
1846
1847 if (hreg->extents.x1 < reg->extents.x1)
1848 reg->extents.x1 = hreg->extents.x1;
1849
1850 if (hreg->extents.y1 < reg->extents.y1)
1851 reg->extents.y1 = hreg->extents.y1;
1852
1853 if (hreg->extents.x2 > reg->extents.x2)
1854 reg->extents.x2 = hreg->extents.x2;
1855
1856 if (hreg->extents.y2 > reg->extents.y2)
1857 reg->extents.y2 = hreg->extents.y2;
1858
1859 FREE_DATA (hreg)if ((hreg)->data && (hreg)->data->size) free
((hreg)->data)
;
1860 }
1861
1862 num_ri -= half;
1863
1864 if (!ret)
1865 goto bail;
1866 }
1867
1868 *badreg = ri[0].reg;
1869
1870 if (ri != stack_regions)
1871 free (ri);
1872
1873 GOOD (badreg)do { if (!_moz_pixman_region32_selfcheck (badreg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "badreg"
); } while (0)
;
1874 return ret;
1875
1876bail:
1877 for (i = 0; i < num_ri; i++)
1878 FREE_DATA (&ri[i].reg)if ((&ri[i].reg)->data && (&ri[i].reg)->
data->size) free ((&ri[i].reg)->data)
;
1879
1880 if (ri != stack_regions)
1881 free (ri);
1882
1883 return pixman_break (badreg);
1884}
1885
1886/*======================================================================
1887 * Region Subtraction
1888 *====================================================================*/
1889
1890/*-
1891 *-----------------------------------------------------------------------
1892 * pixman_region_subtract_o --
1893 * Overlapping band subtraction. x1 is the left-most point not yet
1894 * checked.
1895 *
1896 * Results:
1897 * TRUE if successful.
1898 *
1899 * Side Effects:
1900 * region may have rectangles added to it.
1901 *
1902 *-----------------------------------------------------------------------
1903 */
1904/*ARGSUSED*/
1905static pixman_bool_t
1906pixman_region_subtract_o (region_type_t * region,
1907 box_type_t * r1,
1908 box_type_t * r1_end,
1909 box_type_t * r2,
1910 box_type_t * r2_end,
1911 primitive_t y1,
1912 primitive_t y2)
1913{
1914 box_type_t * next_rect;
1915 primitive_t x1;
1916
1917 x1 = r1->x1;
1918
1919 critical_if_fail (y1 < y2)do { if (__builtin_expect ((!(y1 < y2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "y1 < y2"
" was false"); } while (0)
;
1920 critical_if_fail (r1 != r1_end && r2 != r2_end)do { if (__builtin_expect ((!(r1 != r1_end && r2 != r2_end
)), 0)) _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "r1 != r1_end && r2 != r2_end" " was false"
); } while (0)
;
1921
1922 next_rect = PIXREGION_TOP (region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects])
;
1923
1924 do
1925 {
1926 if (r2->x2 <= x1)
1927 {
1928 /*
1929 * Subtrahend entirely to left of minuend: go to next subtrahend.
1930 */
1931 r2++;
1932 }
1933 else if (r2->x1 <= x1)
1934 {
1935 /*
1936 * Subtrahend precedes minuend: nuke left edge of minuend.
1937 */
1938 x1 = r2->x2;
1939 if (x1 >= r1->x2)
1940 {
1941 /*
1942 * Minuend completely covered: advance to next minuend and
1943 * reset left fence to edge of new minuend.
1944 */
1945 r1++;
1946 if (r1 != r1_end)
1947 x1 = r1->x1;
1948 }
1949 else
1950 {
1951 /*
1952 * Subtrahend now used up since it doesn't extend beyond
1953 * minuend
1954 */
1955 r2++;
1956 }
1957 }
1958 else if (r2->x1 < r1->x2)
1959 {
1960 /*
1961 * Left part of subtrahend covers part of minuend: add uncovered
1962 * part of minuend to region and skip to next subtrahend.
1963 */
1964 critical_if_fail (x1 < r2->x1)do { if (__builtin_expect ((!(x1 < r2->x1)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "x1 < r2->x1"
" was false"); } while (0)
;
1965 NEWRECT (region, next_rect, x1, y1, r2->x1, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = r2->
x1; next_rect->y2 = y2; next_rect++; } while (0); region->
data->numRects++; do { if (__builtin_expect ((!(region->
data->numRects <= region->data->size)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
;
1966
1967 x1 = r2->x2;
1968 if (x1 >= r1->x2)
1969 {
1970 /*
1971 * Minuend used up: advance to new...
1972 */
1973 r1++;
1974 if (r1 != r1_end)
1975 x1 = r1->x1;
1976 }
1977 else
1978 {
1979 /*
1980 * Subtrahend used up
1981 */
1982 r2++;
1983 }
1984 }
1985 else
1986 {
1987 /*
1988 * Minuend used up: add any remaining piece before advancing.
1989 */
1990 if (r1->x2 > x1)
1991 NEWRECT (region, next_rect, x1, y1, r1->x2, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = r1->
x2; next_rect->y2 = y2; next_rect++; } while (0); region->
data->numRects++; do { if (__builtin_expect ((!(region->
data->numRects <= region->data->size)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
;
1992
1993 r1++;
1994
1995 if (r1 != r1_end)
1996 x1 = r1->x1;
1997 }
1998 }
1999 while ((r1 != r1_end) && (r2 != r2_end));
2000
2001 /*
2002 * Add remaining minuend rectangles to region.
2003 */
2004 while (r1 != r1_end)
2005 {
2006 critical_if_fail (x1 < r1->x2)do { if (__builtin_expect ((!(x1 < r1->x2)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "x1 < r1->x2"
" was false"); } while (0)
;
2007
2008 NEWRECT (region, next_rect, x1, y1, r1->x2, y2)do { if (!(region)->data || ((region)->data->numRects
== (region)->data->size)) { if (!pixman_rect_alloc (region
, 1)) return 0; next_rect = (&((box_type_t *)((region)->
data + 1))[(region)->data->numRects]); } do { next_rect
->x1 = x1; next_rect->y1 = y1; next_rect->x2 = r1->
x2; next_rect->y2 = y2; next_rect++; } while (0); region->
data->numRects++; do { if (__builtin_expect ((!(region->
data->numRects <= region->data->size)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "region->data->numRects <= region->data->size"
" was false"); } while (0); } while (0)
;
2009
2010 r1++;
2011 if (r1 != r1_end)
2012 x1 = r1->x1;
2013 }
2014 return TRUE1;
2015}
2016
2017/*-
2018 *-----------------------------------------------------------------------
2019 * pixman_region_subtract --
2020 * Subtract reg_s from reg_m and leave the result in reg_d.
2021 * S stands for subtrahend, M for minuend and D for difference.
2022 *
2023 * Results:
2024 * TRUE if successful.
2025 *
2026 * Side Effects:
2027 * reg_d is overwritten.
2028 *
2029 *-----------------------------------------------------------------------
2030 */
2031PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
2032PREFIX (_subtract)_moz_pixman_region32_subtract (region_type_t * reg_d,
2033 const region_type_t *reg_m,
2034 const region_type_t *reg_s)
2035{
2036 GOOD (reg_m)do { if (!_moz_pixman_region32_selfcheck (reg_m)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg_m"
); } while (0)
;
2037 GOOD (reg_s)do { if (!_moz_pixman_region32_selfcheck (reg_s)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg_s"
); } while (0)
;
2038 GOOD (reg_d)do { if (!_moz_pixman_region32_selfcheck (reg_d)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg_d"
); } while (0)
;
2039
2040 /* check for trivial rejects */
2041 if (PIXREGION_NIL (reg_m)((reg_m)->data && !(reg_m)->data->numRects) || PIXREGION_NIL (reg_s)((reg_s)->data && !(reg_s)->data->numRects) ||
2042 !EXTENTCHECK (&reg_m->extents, &reg_s->extents)(!( ((&reg_m->extents)->x2 <= (&reg_s->extents
)->x1) || ((&reg_m->extents)->x1 >= (&reg_s
->extents)->x2) || ((&reg_m->extents)->y2 <=
(&reg_s->extents)->y1) || ((&reg_m->extents
)->y1 >= (&reg_s->extents)->y2) ) )
)
2043 {
2044 if (PIXREGION_NAR (reg_s)((reg_s)->data == pixman_broken_data))
2045 return pixman_break (reg_d);
2046
2047 return PREFIX (_copy)_moz_pixman_region32_copy (reg_d, reg_m);
2048 }
2049 else if (reg_m == reg_s)
2050 {
2051 FREE_DATA (reg_d)if ((reg_d)->data && (reg_d)->data->size) free
((reg_d)->data)
;
2052 reg_d->extents.x2 = reg_d->extents.x1;
2053 reg_d->extents.y2 = reg_d->extents.y1;
2054 reg_d->data = pixman_region_empty_data;
2055
2056 return TRUE1;
2057 }
2058
2059 /* Add those rectangles in region 1 that aren't in region 2,
2060 do yucky subtraction for overlaps, and
2061 just throw away rectangles in region 2 that aren't in region 1 */
2062 if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE1, FALSE0))
2063 return FALSE0;
2064
2065 /*
2066 * Can't alter reg_d's extents before we call pixman_op because
2067 * it might be one of the source regions and pixman_op depends
2068 * on the extents of those regions being unaltered. Besides, this
2069 * way there's no checking against rectangles that will be nuked
2070 * due to coalescing, so we have to examine fewer rectangles.
2071 */
2072 pixman_set_extents (reg_d);
2073 GOOD (reg_d)do { if (!_moz_pixman_region32_selfcheck (reg_d)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg_d"
); } while (0)
;
2074 return TRUE1;
2075}
2076
2077/*======================================================================
2078 * Region Inversion
2079 *====================================================================*/
2080
2081/*-
2082 *-----------------------------------------------------------------------
2083 * pixman_region_inverse --
2084 * Take a region and a box and return a region that is everything
2085 * in the box but not in the region. The careful reader will note
2086 * that this is the same as subtracting the region from the box...
2087 *
2088 * Results:
2089 * TRUE.
2090 *
2091 * Side Effects:
2092 * new_reg is overwritten.
2093 *
2094 *-----------------------------------------------------------------------
2095 */
2096PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
2097PREFIX (_inverse)_moz_pixman_region32_inverse (region_type_t * new_reg, /* Destination region */
2098 const region_type_t *reg1, /* Region to invert */
2099 const box_type_t * inv_rect) /* Bounding box for inversion */
2100{
2101 region_type_t inv_reg; /* Quick and dirty region made from the
2102 * bounding box */
2103 GOOD (reg1)do { if (!_moz_pixman_region32_selfcheck (reg1)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "reg1"
); } while (0)
;
2104 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
2105
2106 /* check for trivial rejects */
2107 if (PIXREGION_NIL (reg1)((reg1)->data && !(reg1)->data->numRects) || !EXTENTCHECK (inv_rect, &reg1->extents)(!( ((inv_rect)->x2 <= (&reg1->extents)->x1) ||
((inv_rect)->x1 >= (&reg1->extents)->x2) || (
(inv_rect)->y2 <= (&reg1->extents)->y1) || ((
inv_rect)->y1 >= (&reg1->extents)->y2) ) )
)
2108 {
2109 if (PIXREGION_NAR (reg1)((reg1)->data == pixman_broken_data))
2110 return pixman_break (new_reg);
2111
2112 new_reg->extents = *inv_rect;
2113 FREE_DATA (new_reg)if ((new_reg)->data && (new_reg)->data->size
) free ((new_reg)->data)
;
2114 new_reg->data = (region_data_type_t *)NULL((void*)0);
2115
2116 return TRUE1;
2117 }
2118
2119 /* Add those rectangles in region 1 that aren't in region 2,
2120 * do yucky subtraction for overlaps, and
2121 * just throw away rectangles in region 2 that aren't in region 1
2122 */
2123 inv_reg.extents = *inv_rect;
2124 inv_reg.data = (region_data_type_t *)NULL((void*)0);
2125 if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE1, FALSE0))
2126 return FALSE0;
2127
2128 /*
2129 * Can't alter new_reg's extents before we call pixman_op because
2130 * it might be one of the source regions and pixman_op depends
2131 * on the extents of those regions being unaltered. Besides, this
2132 * way there's no checking against rectangles that will be nuked
2133 * due to coalescing, so we have to examine fewer rectangles.
2134 */
2135 pixman_set_extents (new_reg);
2136 GOOD (new_reg)do { if (!_moz_pixman_region32_selfcheck (new_reg)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "new_reg"
); } while (0)
;
2137 return TRUE1;
2138}
2139
2140/* In time O(log n), locate the first box whose y2 is greater than y.
2141 * Return @end if no such box exists.
2142 */
2143static box_type_t *
2144find_box_for_y (box_type_t *begin, box_type_t *end, primitive_t y)
2145{
2146 box_type_t *mid;
2147
2148 if (end == begin)
2149 return end;
2150
2151 if (end - begin == 1)
2152 {
2153 if (begin->y2 > y)
2154 return begin;
2155 else
2156 return end;
2157 }
2158
2159 mid = begin + (end - begin) / 2;
2160 if (mid->y2 > y)
2161 {
2162 /* If no box is found in [begin, mid], the function
2163 * will return @mid, which is then known to be the
2164 * correct answer.
2165 */
2166 return find_box_for_y (begin, mid, y);
2167 }
2168 else
2169 {
2170 return find_box_for_y (mid, end, y);
2171 }
2172}
2173
2174/*
2175 * rect_in(region, rect)
2176 * This routine takes a pointer to a region and a pointer to a box
2177 * and determines if the box is outside/inside/partly inside the region.
2178 *
2179 * The idea is to travel through the list of rectangles trying to cover the
2180 * passed box with them. Anytime a piece of the rectangle isn't covered
2181 * by a band of rectangles, part_out is set TRUE. Any time a rectangle in
2182 * the region covers part of the box, part_in is set TRUE. The process ends
2183 * when either the box has been completely covered (we reached a band that
2184 * doesn't overlap the box, part_in is TRUE and part_out is false), the
2185 * box has been partially covered (part_in == part_out == TRUE -- because of
2186 * the banding, the first time this is true we know the box is only
2187 * partially in the region) or is outside the region (we reached a band
2188 * that doesn't overlap the box at all and part_in is false)
2189 */
2190PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_region_overlap_t
2191PREFIX (_contains_rectangle)_moz_pixman_region32_contains_rectangle (const region_type_t * region,
2192 const box_type_t * prect)
2193{
2194 box_type_t * pbox;
2195 box_type_t * pbox_end;
2196 int part_in, part_out;
2197 int numRects;
2198 primitive_t x, y;
2199
2200 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2201
2202 numRects = PIXREGION_NUMRECTS (region)((region)->data ? (region)->data->numRects : 1);
2203
2204 /* useful optimization */
2205 if (!numRects || !EXTENTCHECK (&region->extents, prect)(!( ((&region->extents)->x2 <= (prect)->x1) ||
((&region->extents)->x1 >= (prect)->x2) || (
(&region->extents)->y2 <= (prect)->y1) || ((&
region->extents)->y1 >= (prect)->y2) ) )
)
2206 return(PIXMAN_REGION_OUT);
2207
2208 if (numRects == 1)
2209 {
2210 /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
2211 if (SUBSUMES (&region->extents, prect)( ((&region->extents)->x1 <= (prect)->x1) &&
((&region->extents)->x2 >= (prect)->x2) &&
((&region->extents)->y1 <= (prect)->y1) &&
((&region->extents)->y2 >= (prect)->y2) )
)
2212 return(PIXMAN_REGION_IN);
2213 else
2214 return(PIXMAN_REGION_PART);
2215 }
2216
2217 part_out = FALSE0;
2218 part_in = FALSE0;
2219
2220 /* (x,y) starts at upper left of rect, moving to the right and down */
2221 x = prect->x1;
2222 y = prect->y1;
2223
2224 /* can stop when both part_out and part_in are TRUE, or we reach prect->y2 */
2225 for (pbox = PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1)), pbox_end = pbox + numRects;
2226 pbox != pbox_end;
2227 pbox++)
2228 {
2229 /* getting up to speed or skipping remainder of band */
2230 if (pbox->y2 <= y)
2231 {
2232 if ((pbox = find_box_for_y (pbox, pbox_end, y)) == pbox_end)
2233 break;
2234 }
2235
2236 if (pbox->y1 > y)
2237 {
2238 part_out = TRUE1; /* missed part of rectangle above */
2239 if (part_in || (pbox->y1 >= prect->y2))
2240 break;
2241 y = pbox->y1; /* x guaranteed to be == prect->x1 */
2242 }
2243
2244 if (pbox->x2 <= x)
2245 continue; /* not far enough over yet */
2246
2247 if (pbox->x1 > x)
2248 {
2249 part_out = TRUE1; /* missed part of rectangle to left */
2250 if (part_in)
2251 break;
2252 }
2253
2254 if (pbox->x1 < prect->x2)
2255 {
2256 part_in = TRUE1; /* definitely overlap */
2257 if (part_out)
2258 break;
2259 }
2260
2261 if (pbox->x2 >= prect->x2)
2262 {
2263 y = pbox->y2; /* finished with this band */
2264 if (y >= prect->y2)
2265 break;
2266 x = prect->x1; /* reset x out to left again */
2267 }
2268 else
2269 {
2270 /*
2271 * Because boxes in a band are maximal width, if the first box
2272 * to overlap the rectangle doesn't completely cover it in that
2273 * band, the rectangle must be partially out, since some of it
2274 * will be uncovered in that band. part_in will have been set true
2275 * by now...
2276 */
2277 part_out = TRUE1;
Value stored to 'part_out' is never read
2278 break;
2279 }
2280 }
2281
2282 if (part_in)
2283 {
2284 if (y < prect->y2)
2285 return PIXMAN_REGION_PART;
2286 else
2287 return PIXMAN_REGION_IN;
2288 }
2289 else
2290 {
2291 return PIXMAN_REGION_OUT;
2292 }
2293}
2294
2295/* PREFIX(_translate) (region, x, y)
2296 * translates in place
2297 */
2298
2299PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
2300PREFIX (_translate)_moz_pixman_region32_translate (region_type_t *region, int x, int y)
2301{
2302 overflow_int_t x1, x2, y1, y2;
2303 int nbox;
2304 box_type_t * pbox;
2305
2306 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2307
2308 if (x == 0 && y == 0)
2309 return;
2310
2311 region->extents.x1 = x1 = region->extents.x1 + x;
2312 region->extents.y1 = y1 = region->extents.y1 + y;
2313 region->extents.x2 = x2 = region->extents.x2 + x;
2314 region->extents.y2 = y2 = region->extents.y2 + y;
2315
2316 if (((x1 - PIXMAN_REGION_MIN(-2147483647-1)) | (y1 - PIXMAN_REGION_MIN(-2147483647-1)) | (PIXMAN_REGION_MAX(2147483647) - x2) | (PIXMAN_REGION_MAX(2147483647) - y2)) >= 0)
2317 {
2318 if (region->data && (nbox = region->data->numRects))
2319 {
2320 for (pbox = PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1)); nbox--; pbox++)
2321 {
2322 pbox->x1 += x;
2323 pbox->y1 += y;
2324 pbox->x2 += x;
2325 pbox->y2 += y;
2326 }
2327 }
2328 return;
2329 }
2330
2331 if (((x2 - PIXMAN_REGION_MIN(-2147483647-1)) | (y2 - PIXMAN_REGION_MIN(-2147483647-1)) | (PIXMAN_REGION_MAX(2147483647) - x1) | (PIXMAN_REGION_MAX(2147483647) - y1)) <= 0)
2332 {
2333 region->extents.x2 = region->extents.x1;
2334 region->extents.y2 = region->extents.y1;
2335 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2336 region->data = pixman_region_empty_data;
2337 return;
2338 }
2339
2340 if (x1 < PIXMAN_REGION_MIN(-2147483647-1))
2341 region->extents.x1 = PIXMAN_REGION_MIN(-2147483647-1);
2342 else if (x2 > PIXMAN_REGION_MAX(2147483647))
2343 region->extents.x2 = PIXMAN_REGION_MAX(2147483647);
2344
2345 if (y1 < PIXMAN_REGION_MIN(-2147483647-1))
2346 region->extents.y1 = PIXMAN_REGION_MIN(-2147483647-1);
2347 else if (y2 > PIXMAN_REGION_MAX(2147483647))
2348 region->extents.y2 = PIXMAN_REGION_MAX(2147483647);
2349
2350 if (region->data && (nbox = region->data->numRects))
2351 {
2352 box_type_t * pbox_out;
2353
2354 for (pbox_out = pbox = PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1)); nbox--; pbox++)
2355 {
2356 pbox_out->x1 = x1 = pbox->x1 + x;
2357 pbox_out->y1 = y1 = pbox->y1 + y;
2358 pbox_out->x2 = x2 = pbox->x2 + x;
2359 pbox_out->y2 = y2 = pbox->y2 + y;
2360
2361 if (((x2 - PIXMAN_REGION_MIN(-2147483647-1)) | (y2 - PIXMAN_REGION_MIN(-2147483647-1)) |
2362 (PIXMAN_REGION_MAX(2147483647) - x1) | (PIXMAN_REGION_MAX(2147483647) - y1)) <= 0)
2363 {
2364 region->data->numRects--;
2365 continue;
2366 }
2367
2368 if (x1 < PIXMAN_REGION_MIN(-2147483647-1))
2369 pbox_out->x1 = PIXMAN_REGION_MIN(-2147483647-1);
2370 else if (x2 > PIXMAN_REGION_MAX(2147483647))
2371 pbox_out->x2 = PIXMAN_REGION_MAX(2147483647);
2372
2373 if (y1 < PIXMAN_REGION_MIN(-2147483647-1))
2374 pbox_out->y1 = PIXMAN_REGION_MIN(-2147483647-1);
2375 else if (y2 > PIXMAN_REGION_MAX(2147483647))
2376 pbox_out->y2 = PIXMAN_REGION_MAX(2147483647);
2377
2378 pbox_out++;
2379 }
2380
2381 if (pbox_out != pbox)
2382 {
2383 if (region->data->numRects == 1)
2384 {
2385 region->extents = *PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1));
2386 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2387 region->data = (region_data_type_t *)NULL((void*)0);
2388 }
2389 else
2390 {
2391 pixman_set_extents (region);
2392 }
2393 }
2394 }
2395
2396 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2397}
2398
2399PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
2400PREFIX (_reset)_moz_pixman_region32_reset (region_type_t *region, const box_type_t *box)
2401{
2402 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2403
2404 critical_if_fail (GOOD_RECT (box))do { if (__builtin_expect ((!(((box)->x1 < (box)->x2
&& (box)->y1 < (box)->y2))), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "GOOD_RECT (box)"
" was false"); } while (0)
;
2405
2406 region->extents = *box;
2407
2408 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2409
2410 region->data = NULL((void*)0);
2411}
2412
2413PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
2414PREFIX (_clear)_moz_pixman_region32_clear (region_type_t *region)
2415{
2416 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2417 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2418
2419 region->extents = *pixman_region_empty_box;
2420 region->data = pixman_region_empty_data;
2421}
2422
2423/* box is "return" value */
2424PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) int
2425PREFIX (_contains_point)_moz_pixman_region32_contains_point (const region_type_t * region,
2426 int x, int y,
2427 box_type_t * box)
2428{
2429 box_type_t *pbox, *pbox_end;
2430 int numRects;
2431
2432 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2433 numRects = PIXREGION_NUMRECTS (region)((region)->data ? (region)->data->numRects : 1);
2434
2435 if (!numRects || !INBOX (&region->extents, x, y)( ((&region->extents)->x2 > x) && ((&
region->extents)->x1 <= x) && ((&region->
extents)->y2 > y) && ((&region->extents)
->y1 <= y) )
)
2436 return(FALSE0);
2437
2438 if (numRects == 1)
2439 {
2440 if (box)
2441 *box = region->extents;
2442
2443 return(TRUE1);
2444 }
2445
2446 pbox = PIXREGION_BOXPTR (region)((box_type_t *)((region)->data + 1));
2447 pbox_end = pbox + numRects;
2448
2449 pbox = find_box_for_y (pbox, pbox_end, y);
2450
2451 for (;pbox != pbox_end; pbox++)
2452 {
2453 if ((y < pbox->y1) || (x < pbox->x1))
2454 break; /* missed it */
2455
2456 if (x >= pbox->x2)
2457 continue; /* not there yet */
2458
2459 if (box)
2460 *box = *pbox;
2461
2462 return(TRUE1);
2463 }
2464
2465 return(FALSE0);
2466}
2467
2468PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) int
2469PREFIX (_empty)pixman_region32_empty (const region_type_t * region)
2470{
2471 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2472
2473 return(PIXREGION_NIL (region)((region)->data && !(region)->data->numRects
)
);
2474}
2475
2476PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) int
2477PREFIX (_not_empty)_moz_pixman_region32_not_empty (const region_type_t * region)
2478{
2479 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2480
2481 return(!PIXREGION_NIL (region)((region)->data && !(region)->data->numRects
)
);
2482}
2483
2484PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) box_type_t *
2485PREFIX (_extents)_moz_pixman_region32_extents (const region_type_t * region)
2486{
2487 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2488
2489 return(box_type_t *)(&region->extents);
2490}
2491
2492/*
2493 * Clip a list of scanlines to a region. The caller has allocated the
2494 * space. FSorted is non-zero if the scanline origins are in ascending order.
2495 *
2496 * returns the number of new, clipped scanlines.
2497 */
2498
2499PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
2500PREFIX (_selfcheck)_moz_pixman_region32_selfcheck (region_type_t *reg)
2501{
2502 int i, numRects;
2503
2504 if ((reg->extents.x1 > reg->extents.x2) ||
2505 (reg->extents.y1 > reg->extents.y2))
2506 {
2507 return FALSE0;
2508 }
2509
2510 numRects = PIXREGION_NUMRECTS (reg)((reg)->data ? (reg)->data->numRects : 1);
2511 if (!numRects)
2512 {
2513 return ((reg->extents.x1 == reg->extents.x2) &&
2514 (reg->extents.y1 == reg->extents.y2) &&
2515 (reg->data->size || (reg->data == pixman_region_empty_data)));
2516 }
2517 else if (numRects == 1)
2518 {
2519 return (!reg->data);
2520 }
2521 else
2522 {
2523 box_type_t * pbox_p, * pbox_n;
2524 box_type_t box;
2525
2526 pbox_p = PIXREGION_RECTS (reg)((reg)->data ? (box_type_t *)((reg)->data + 1) : (box_type_t
*)&(reg)->extents)
;
2527 box = *pbox_p;
2528 box.y2 = pbox_p[numRects - 1].y2;
2529 pbox_n = pbox_p + 1;
2530
2531 for (i = numRects; --i > 0; pbox_p++, pbox_n++)
2532 {
2533 if ((pbox_n->x1 >= pbox_n->x2) ||
2534 (pbox_n->y1 >= pbox_n->y2))
2535 {
2536 return FALSE0;
2537 }
2538
2539 if (pbox_n->x1 < box.x1)
2540 box.x1 = pbox_n->x1;
2541
2542 if (pbox_n->x2 > box.x2)
2543 box.x2 = pbox_n->x2;
2544
2545 if ((pbox_n->y1 < pbox_p->y1) ||
2546 ((pbox_n->y1 == pbox_p->y1) &&
2547 ((pbox_n->x1 < pbox_p->x2) || (pbox_n->y2 != pbox_p->y2))))
2548 {
2549 return FALSE0;
2550 }
2551 }
2552
2553 return ((box.x1 == reg->extents.x1) &&
2554 (box.x2 == reg->extents.x2) &&
2555 (box.y1 == reg->extents.y1) &&
2556 (box.y2 == reg->extents.y2));
2557 }
2558}
2559
2560PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) pixman_bool_t
2561PREFIX (_init_rects)_moz_pixman_region32_init_rects (region_type_t *region,
2562 const box_type_t *boxes, int count)
2563{
2564 box_type_t *rects;
2565 int displacement;
2566 int i;
2567
2568 /* if it's 1, then we just want to set the extents, so call
2569 * the existing method. */
2570 if (count == 1)
2571 {
2572 PREFIX (_init_rect)_moz_pixman_region32_init_rect (region,
2573 boxes[0].x1,
2574 boxes[0].y1,
2575 boxes[0].x2 - boxes[0].x1,
2576 boxes[0].y2 - boxes[0].y1);
2577 return TRUE1;
2578 }
2579
2580 PREFIX (_init)_moz_pixman_region32_init (region);
2581
2582 /* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is
2583 * a special case, and causing pixman_rect_alloc would cause
2584 * us to leak memory (because the 0-rect case should be the
2585 * static pixman_region_empty_data data).
2586 */
2587 if (count == 0)
2588 return TRUE1;
2589
2590 if (!pixman_rect_alloc (region, count))
2591 return FALSE0;
2592
2593 rects = PIXREGION_RECTS (region)((region)->data ? (box_type_t *)((region)->data + 1) : (
box_type_t *)&(region)->extents)
;
2594
2595 /* Copy in the rects */
2596 memcpy (rects, boxes, sizeof(box_type_t) * count);
2597 region->data->numRects = count;
2598
2599 /* Eliminate empty and malformed rectangles */
2600 displacement = 0;
2601
2602 for (i = 0; i < count; ++i)
2603 {
2604 box_type_t *box = &rects[i];
2605
2606 if (box->x1 >= box->x2 || box->y1 >= box->y2)
2607 displacement++;
2608 else if (displacement)
2609 rects[i - displacement] = rects[i];
2610 }
2611
2612 region->data->numRects -= displacement;
2613
2614 /* If eliminating empty rectangles caused there
2615 * to be only 0 or 1 rectangles, deal with that.
2616 */
2617 if (region->data->numRects == 0)
2618 {
2619 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2620 PREFIX (_init)_moz_pixman_region32_init (region);
2621
2622 return TRUE1;
2623 }
2624
2625 if (region->data->numRects == 1)
2626 {
2627 region->extents = rects[0];
2628
2629 FREE_DATA (region)if ((region)->data && (region)->data->size) free
((region)->data)
;
2630 region->data = NULL((void*)0);
2631
2632 GOOD (region)do { if (!_moz_pixman_region32_selfcheck (region)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "Malformed region " "region"
); } while (0)
;
2633
2634 return TRUE1;
2635 }
2636
2637 /* Validate */
2638 region->extents.x1 = region->extents.x2 = 0;
2639
2640 return validate (region);
2641}
2642
2643#define READ(_ptr)(*(_ptr)) (*(_ptr))
2644
2645static inline__inline__ box_type_t *
2646bitmap_addrect (region_type_t *reg,
2647 box_type_t *r,
2648 box_type_t **first_rect,
2649 primitive_t rx1, primitive_t ry1,
2650 primitive_t rx2, primitive_t ry2)
2651{
2652 if ((rx1 < rx2) && (ry1 < ry2) &&
2653 (!(reg->data->numRects &&
2654 ((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) &&
2655 ((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2))))
2656 {
2657 if (reg->data->numRects == reg->data->size)
2658 {
2659 if (!pixman_rect_alloc (reg, 1))
2660 return NULL((void*)0);
2661 *first_rect = PIXREGION_BOXPTR(reg)((box_type_t *)((reg)->data + 1));
2662 r = *first_rect + reg->data->numRects;
2663 }
2664 r->x1 = rx1;
2665 r->y1 = ry1;
2666 r->x2 = rx2;
2667 r->y2 = ry2;
2668 reg->data->numRects++;
2669 if (r->x1 < reg->extents.x1)
2670 reg->extents.x1 = r->x1;
2671 if (r->x2 > reg->extents.x2)
2672 reg->extents.x2 = r->x2;
2673 r++;
2674 }
2675 return r;
2676}
2677
2678/* Convert bitmap clip mask into clipping region.
2679 * First, goes through each line and makes boxes by noting the transitions
2680 * from 0 to 1 and 1 to 0.
2681 * Then it coalesces the current line with the previous if they have boxes
2682 * at the same X coordinates.
2683 * Stride is in number of uint32_t per line.
2684 */
2685PIXMAN_EXPORTextern __attribute__((visibility("hidden"))) void
2686PREFIX (_init_from_image)_moz_pixman_region32_init_from_image (region_type_t *region,
2687 pixman_image_t *image)
2688{
2689 uint32_t mask0 = 0xffffffff & ~SCREEN_SHIFT_RIGHT(0xffffffff, 1)((0xffffffff) << (1));
2690 box_type_t *first_rect, *rects, *prect_line_start;
2691 box_type_t *old_rect, *new_rect;
2692 uint32_t *pw, w, *pw_line, *pw_line_end;
2693 int irect_prev_start, irect_line_start;
2694 int h, base, rx1 = 0, crects;
2695 int ib;
2696 pixman_bool_t in_box, same;
2697 int width, height, stride;
2698
2699 PREFIX(_init)_moz_pixman_region32_init (region);
2700
2701 critical_if_fail (region->data)do { if (__builtin_expect ((!(region->data)), 0)) _pixman_log_error
(((const char*) (__PRETTY_FUNCTION__)), "The expression " "region->data"
" was false"); } while (0)
;
2702
2703 return_if_fail (image->type == BITS)do { if (__builtin_expect ((!(image->type == BITS)), 0)) {
_pixman_log_error (((const char*) (__PRETTY_FUNCTION__)), "The expression "
"image->type == BITS" " was false"); return; } } while (0
)
;
2704 return_if_fail (image->bits.format == PIXMAN_a1)do { if (__builtin_expect ((!(image->bits.format == PIXMAN_a1
)), 0)) { _pixman_log_error (((const char*) (__PRETTY_FUNCTION__
)), "The expression " "image->bits.format == PIXMAN_a1" " was false"
); return; } } while (0)
;
2705
2706 pw_line = pixman_image_get_data_moz_pixman_image_get_data (image);
2707 width = pixman_image_get_width_moz_pixman_image_get_width (image);
2708 height = pixman_image_get_height_moz_pixman_image_get_height (image);
2709 stride = pixman_image_get_stride_moz_pixman_image_get_stride (image) / 4;
2710
2711 first_rect = PIXREGION_BOXPTR(region)((box_type_t *)((region)->data + 1));
2712 rects = first_rect;
2713
2714 region->extents.x1 = width - 1;
2715 region->extents.x2 = 0;
2716 irect_prev_start = -1;
2717 for (h = 0; h < height; h++)
2718 {
2719 pw = pw_line;
2720 pw_line += stride;
2721 irect_line_start = rects - first_rect;
2722
2723 /* If the Screen left most bit of the word is set, we're starting in
2724 * a box */
2725 if (READ(pw)(*(pw)) & mask0)
2726 {
2727 in_box = TRUE1;
2728 rx1 = 0;
2729 }
2730 else
2731 {
2732 in_box = FALSE0;
2733 }
2734
2735 /* Process all words which are fully in the pixmap */
2736 pw_line_end = pw + (width >> 5);
2737 for (base = 0; pw < pw_line_end; base += 32)
2738 {
2739 w = READ(pw++)(*(pw++));
2740 if (in_box)
2741 {
2742 if (!~w)
2743 continue;
2744 }
2745 else
2746 {
2747 if (!w)
2748 continue;
2749 }
2750 for (ib = 0; ib < 32; ib++)
2751 {
2752 /* If the Screen left most bit of the word is set, we're
2753 * starting a box */
2754 if (w & mask0)
2755 {
2756 if (!in_box)
2757 {
2758 rx1 = base + ib;
2759 /* start new box */
2760 in_box = TRUE1;
2761 }
2762 }
2763 else
2764 {
2765 if (in_box)
2766 {
2767 /* end box */
2768 rects = bitmap_addrect (region, rects, &first_rect,
2769 rx1, h, base + ib, h + 1);
2770 if (rects == NULL((void*)0))
2771 goto error;
2772 in_box = FALSE0;
2773 }
2774 }
2775 /* Shift the word VISUALLY left one. */
2776 w = SCREEN_SHIFT_LEFT(w, 1)((w) >> (1));
2777 }
2778 }
2779
2780 if (width & 31)
2781 {
2782 /* Process final partial word on line */
2783 w = READ(pw++)(*(pw++));
2784 for (ib = 0; ib < (width & 31); ib++)
2785 {
2786 /* If the Screen left most bit of the word is set, we're
2787 * starting a box */
2788 if (w & mask0)
2789 {
2790 if (!in_box)
2791 {
2792 rx1 = base + ib;
2793 /* start new box */
2794 in_box = TRUE1;
2795 }
2796 }
2797 else
2798 {
2799 if (in_box)
2800 {
2801 /* end box */
2802 rects = bitmap_addrect(region, rects, &first_rect,
2803 rx1, h, base + ib, h + 1);
2804 if (rects == NULL((void*)0))
2805 goto error;
2806 in_box = FALSE0;
2807 }
2808 }
2809 /* Shift the word VISUALLY left one. */
2810 w = SCREEN_SHIFT_LEFT(w, 1)((w) >> (1));
2811 }
2812 }
2813 /* If scanline ended with last bit set, end the box */
2814 if (in_box)
2815 {
2816 rects = bitmap_addrect(region, rects, &first_rect,
2817 rx1, h, base + (width & 31), h + 1);
2818 if (rects == NULL((void*)0))
2819 goto error;
2820 }
2821 /* if all rectangles on this line have the same x-coords as
2822 * those on the previous line, then add 1 to all the previous y2s and
2823 * throw away all the rectangles from this line
2824 */
2825 same = FALSE0;
2826 if (irect_prev_start != -1)
2827 {
2828 crects = irect_line_start - irect_prev_start;
2829 if (crects != 0 &&
2830 crects == ((rects - first_rect) - irect_line_start))
2831 {
2832 old_rect = first_rect + irect_prev_start;
2833 new_rect = prect_line_start = first_rect + irect_line_start;
2834 same = TRUE1;
2835 while (old_rect < prect_line_start)
2836 {
2837 if ((old_rect->x1 != new_rect->x1) ||
2838 (old_rect->x2 != new_rect->x2))
2839 {
2840 same = FALSE0;
2841 break;
2842 }
2843 old_rect++;
2844 new_rect++;
2845 }
2846 if (same)
2847 {
2848 old_rect = first_rect + irect_prev_start;
2849 while (old_rect < prect_line_start)
2850 {
2851 old_rect->y2 += 1;
2852 old_rect++;
2853 }
2854 rects -= crects;
2855 region->data->numRects -= crects;
2856 }
2857 }
2858 }
2859 if(!same)
2860 irect_prev_start = irect_line_start;
2861 }
2862 if (!region->data->numRects)
2863 {
2864 region->extents.x1 = region->extents.x2 = 0;
2865 }
2866 else
2867 {
2868 region->extents.y1 = PIXREGION_BOXPTR(region)((box_type_t *)((region)->data + 1))->y1;
2869 region->extents.y2 = PIXREGION_END(region)(&((box_type_t *)((region)->data + 1))[(region)->data
->numRects - 1])
->y2;
2870 if (region->data->numRects == 1)
2871 {
2872 free (region->data);
2873 region->data = NULL((void*)0);
2874 }
2875 }
2876
2877 error:
2878 return;
2879}