~ubuntu-branches/ubuntu/maverick/xorg-server/maverick-security

« back to all changes in this revision

Viewing changes to mi/miregion.c

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2010-08-05 11:25:14 UTC
  • mfrom: (1.1.35 upstream) (0.1.14 experimental)
  • Revision ID: james.westby@ubuntu.com-20100805112514-q4efdgj3nblevos2
Tags: 2:1.8.99.905-1ubuntu1
* Merge from (unreleased) Debian experimental.  Remaining Ubuntu changes:
  - rules, control:
    + Disable SELinux, libaudit-dev is not in main yet (LP 406226).
      Drop libaudit-dev from build-deps.
  - rules: Enable xcsecurity (LP 247537).
  - local/xvfb-run*: Add correct docs about error codes (LP 328205)
  - rules: Add --with-extra-module-dir to support GL alternatives.
  - control: Xvfb depends on xauth, x11-xkb-utils. (LP 500102)
  - rules, local/64-xorg-xkb.rules: Don't use keyboard-configuration
    until it's available.
  - control: Update some versioned Breaks for Ubuntu versions.
  - debian/patches:
    + 100_rethrow_signals.patch:
      When aborting, re-raise signals for apport
    + 109_fix-swcursor-crash.patch:
      Avoid dereferencing null pointer while reloading cursors during
      resume. (LP 371405)
    + 111_armel-drv-fallbacks.patch:
      Add support for armel driver fallbacks.
    + 121_only_switch_vt_when_active.diff:
      Add a check to prevent the X server from changing the VT when killing
      GDM from the console.
    + 122_xext_fix_card32_overflow_in_xauth.patch:
      Fix server crash when “xauth generate” is called with large timeout.
    + 157_check_null_modes.patch, 162_null_crtc_in_rotation.patch,
      166_nullptr_xinerama_keyrepeat.patch, 167_nullptr_xisbread.patch
      169_mipointer_nullptr_checks.patch,
      172_cwgetbackingpicture_nullptr_check.patch:
      Fix various segfaults in xserver by checking pointers for NULL
      values before dereferencing them.
    + 165_man_xorg_conf_no_device_ident.patch
      Correct man page
    + 168_glibc_trace_to_stderr.patch:
      Report abort traces to stderr instead of terminal
    + 184_virtual_devices_autodetect.patch:
      Use vesa for qemu device, which is not supported by cirrus
    + 187_edid_quirk_hp_nc8430.patch:
      Quirk for another LPL monitor (LP 380009)
    + 188_default_primary_to_first_busid.patch:
      Pick the first device and carry on (LP 459512)
    + 189_xserver_1.5.0_bg_none_root.patch:
      Create a root window with no background.
    + 190_cache-xkbcomp_output_for_fast_start_up.patch:
      Cache keyboard settings.
    + 191-Xorg-add-an-extra-module-path.patch:
      Add support for the alternatives module path.
    + 197_xvfb-randr.patch:
      Adds xrandr support to xvfb. (LP 516123)
    + 198_nohwaccess.patch:
      Adds a -nohwaccess argument to make X not access the hardware
      ports directly.
    + 200_randr-null.patch:
      Clarify a pointer initialization.
* Update changelog entries for 1.8.1.902-1 which became 1.8.99.904-1
* Drop 196_xvfbscreeninit-handling.patch: it's semantically empty, and now 
  doesn't apply.  Merge remaining #include change into 197_xvfb-randr.patch
* New upstream version will start correctly when no outputs are connected,
  as long as the video driver can dynamically resize the framebuffer
  (true for all KMS drivers) (LP: #337889)
* New upstream version fixes crash on non-admin logout with KDE (LP: #569879)
* Refresh 111_armel-drv-fallbacks.patch to fix the build on armel

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***********************************************************
2
 
 
3
 
Copyright 1987, 1988, 1989, 1998  The Open Group
4
 
 
5
 
Permission to use, copy, modify, distribute, and sell this software and its
6
 
documentation for any purpose is hereby granted without fee, provided that
7
 
the above copyright notice appear in all copies and that both that
8
 
copyright notice and this permission notice appear in supporting
9
 
documentation.
10
 
 
11
 
The above copyright notice and this permission notice shall be included in
12
 
all copies or substantial portions of the Software.
13
 
 
14
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17
 
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18
 
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
 
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
 
 
21
 
Except as contained in this notice, the name of The Open Group shall not be
22
 
used in advertising or otherwise to promote the sale, use or other dealings
23
 
in this Software without prior written authorization from The Open Group.
24
 
 
25
 
 
26
 
Copyright 1987, 1988, 1989 by 
27
 
Digital Equipment Corporation, Maynard, Massachusetts. 
28
 
 
29
 
                        All Rights Reserved
30
 
 
31
 
Permission to use, copy, modify, and distribute this software and its 
32
 
documentation for any purpose and without fee is hereby granted, 
33
 
provided that the above copyright notice appear in all copies and that
34
 
both that copyright notice and this permission notice appear in 
35
 
supporting documentation, and that the name of Digital not be
36
 
used in advertising or publicity pertaining to distribution of the
37
 
software without specific, written prior permission.  
38
 
 
39
 
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40
 
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41
 
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42
 
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43
 
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44
 
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45
 
SOFTWARE.
46
 
 
47
 
******************************************************************/
48
 
 
49
 
/* The panoramix components contained the following notice */
50
 
/*****************************************************************
51
 
 
52
 
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
53
 
 
54
 
Permission is hereby granted, free of charge, to any person obtaining a copy
55
 
of this software and associated documentation files (the "Software"), to deal
56
 
in the Software without restriction, including without limitation the rights
57
 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58
 
copies of the Software.
59
 
 
60
 
The above copyright notice and this permission notice shall be included in
61
 
all copies or substantial portions of the Software.
62
 
 
63
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
64
 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65
 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
66
 
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
67
 
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
68
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
69
 
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70
 
 
71
 
Except as contained in this notice, the name of Digital Equipment Corporation
72
 
shall not be used in advertising or otherwise to promote the sale, use or other
73
 
dealings in this Software without prior written authorization from Digital
74
 
Equipment Corporation.
75
 
 
76
 
******************************************************************/
77
 
 
78
 
#ifdef HAVE_DIX_CONFIG_H
79
 
#include <dix-config.h>
80
 
#endif
81
 
 
82
 
#include "regionstr.h"
83
 
#include <X11/Xprotostr.h>
84
 
#include <X11/Xfuncproto.h>
85
 
#include "gc.h"
86
 
#include "mi.h"
87
 
#include "mispans.h"
88
 
#include <pixman.h>
89
 
 
90
 
#undef assert
91
 
#ifdef REGION_DEBUG
92
 
#define assert(expr) { \
93
 
            CARD32 *foo = NULL; \
94
 
            if (!(expr)) { \
95
 
                ErrorF("Assertion failed file %s, line %d: %s\n", \
96
 
                       __FILE__, __LINE__, #expr); \
97
 
                *foo = 0xdeadbeef; /* to get a backtrace */ \
98
 
            } \
99
 
        }
100
 
#else
101
 
#define assert(expr)
102
 
#endif
103
 
 
104
 
#define good(reg) assert(miValidRegion(reg))
105
 
 
106
 
/*
107
 
 * The functions in this file implement the Region abstraction used extensively
108
 
 * throughout the X11 sample server. A Region is simply a set of disjoint
109
 
 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
110
 
 * smallest single rectangle that contains all the non-overlapping rectangles.
111
 
 *
112
 
 * A Region is implemented as a "y-x-banded" array of rectangles.  This array
113
 
 * imposes two degrees of order.  First, all rectangles are sorted by top side
114
 
 * y coordinate first (y1), and then by left side x coordinate (x1).
115
 
 *
116
 
 * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
117
 
 * band has the same top y coordinate (y1), and each has the same bottom y
118
 
 * coordinate (y2).  Thus all rectangles in a band differ only in their left
119
 
 * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
120
 
 * there is no separate list of band start pointers.
121
 
 *
122
 
 * The y-x band representation does not minimize rectangles.  In particular,
123
 
 * if a rectangle vertically crosses a band (the rectangle has scanlines in 
124
 
 * the y1 to y2 area spanned by the band), then the rectangle may be broken
125
 
 * down into two or more smaller rectangles stacked one atop the other. 
126
 
 *
127
 
 *  -----------                             -----------
128
 
 *  |         |                             |         |             band 0
129
 
 *  |         |  --------                   -----------  --------
130
 
 *  |         |  |      |  in y-x banded    |         |  |      |   band 1
131
 
 *  |         |  |      |  form is          |         |  |      |
132
 
 *  -----------  |      |                   -----------  --------
133
 
 *               |      |                                |      |   band 2
134
 
 *               --------                                --------
135
 
 *
136
 
 * An added constraint on the rectangles is that they must cover as much
137
 
 * horizontal area as possible: no two rectangles within a band are allowed
138
 
 * to touch.
139
 
 *
140
 
 * Whenever possible, bands will be merged together to cover a greater vertical
141
 
 * distance (and thus reduce the number of rectangles). Two bands can be merged
142
 
 * only if the bottom of one touches the top of the other and they have
143
 
 * rectangles in the same places (of the same width, of course).
144
 
 *
145
 
 * Adam de Boor wrote most of the original region code.  Joel McCormack
146
 
 * substantially modified or rewrote most of the core arithmetic routines,
147
 
 * and added miRegionValidate in order to support several speed improvements
148
 
 * to miValidateTree.  Bob Scheifler changed the representation to be more
149
 
 * compact when empty or a single rectangle, and did a bunch of gratuitous
150
 
 * reformatting.
151
 
 */
152
 
 
153
 
/*  true iff two Boxes overlap */
154
 
#define EXTENTCHECK(r1,r2) \
155
 
      (!( ((r1)->x2 <= (r2)->x1)  || \
156
 
          ((r1)->x1 >= (r2)->x2)  || \
157
 
          ((r1)->y2 <= (r2)->y1)  || \
158
 
          ((r1)->y1 >= (r2)->y2) ) )
159
 
 
160
 
/* true iff (x,y) is in Box */
161
 
#define INBOX(r,x,y) \
162
 
      ( ((r)->x2 >  x) && \
163
 
        ((r)->x1 <= x) && \
164
 
        ((r)->y2 >  y) && \
165
 
        ((r)->y1 <= y) )
166
 
 
167
 
/* true iff Box r1 contains Box r2 */
168
 
#define SUBSUMES(r1,r2) \
169
 
      ( ((r1)->x1 <= (r2)->x1) && \
170
 
        ((r1)->x2 >= (r2)->x2) && \
171
 
        ((r1)->y1 <= (r2)->y1) && \
172
 
        ((r1)->y2 >= (r2)->y2) )
173
 
 
174
 
#define xallocData(n) xalloc(REGION_SZOF(n))
175
 
#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data)
176
 
 
177
 
#define RECTALLOC_BAIL(pReg,n,bail) \
178
 
if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
179
 
    if (!miRectAlloc(pReg, n)) { goto bail; }
180
 
 
181
 
#define RECTALLOC(pReg,n) \
182
 
if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
183
 
    if (!miRectAlloc(pReg, n)) { return FALSE; }
184
 
 
185
 
#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)      \
186
 
{                                               \
187
 
    pNextRect->x1 = nx1;                        \
188
 
    pNextRect->y1 = ny1;                        \
189
 
    pNextRect->x2 = nx2;                        \
190
 
    pNextRect->y2 = ny2;                        \
191
 
    pNextRect++;                                \
192
 
}
193
 
 
194
 
#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)                 \
195
 
{                                                                       \
196
 
    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
197
 
    {                                                                   \
198
 
        if (!miRectAlloc(pReg, 1))                                      \
199
 
            return FALSE;                                               \
200
 
        pNextRect = REGION_TOP(pReg);                                   \
201
 
    }                                                                   \
202
 
    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);                                 \
203
 
    pReg->data->numRects++;                                             \
204
 
    assert(pReg->data->numRects<=pReg->data->size);                     \
205
 
}
206
 
 
207
 
 
208
 
#define DOWNSIZE(reg,numRects)                                           \
209
 
if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
210
 
{                                                                        \
211
 
    RegDataPtr NewData;                                                  \
212
 
    NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects));  \
213
 
    if (NewData)                                                         \
214
 
    {                                                                    \
215
 
        NewData->size = (numRects);                                      \
216
 
        (reg)->data = NewData;                                           \
217
 
    }                                                                    \
218
 
}
219
 
 
220
 
 
221
 
BoxRec miEmptyBox = {0, 0, 0, 0};
222
 
RegDataRec miEmptyData = {0, 0};
223
 
 
224
 
RegDataRec  miBrokenData = {0, 0};
225
 
static RegionRec   miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData };
226
 
 
227
 
void
228
 
InitRegions (void)
229
 
{
230
 
    pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData);
231
 
}
232
 
 
233
 
/*****************************************************************
234
 
 *   RegionCreate(rect, size)
235
 
 *     This routine does a simple malloc to make a structure of
236
 
 *     REGION of "size" number of rectangles.
237
 
 *****************************************************************/
238
 
 
239
 
RegionPtr
240
 
miRegionCreate(BoxPtr rect, int size)
241
 
{
242
 
    RegionPtr pReg;
243
 
   
244
 
    pReg = (RegionPtr)xalloc(sizeof(RegionRec));
245
 
    if (!pReg)
246
 
        return &miBrokenRegion;
247
 
 
248
 
    miRegionInit (pReg, rect, size);
249
 
    
250
 
    return(pReg);
251
 
}
252
 
 
253
 
void
254
 
miRegionDestroy(RegionPtr pReg)
255
 
{
256
 
    pixman_region_fini (pReg);
257
 
    if (pReg != &miBrokenRegion)
258
 
        xfree(pReg);
259
 
}
260
 
 
261
 
void
262
 
miPrintRegion(RegionPtr rgn)
263
 
{
264
 
    int num, size;
265
 
    int i;
266
 
    BoxPtr rects;
267
 
 
268
 
    num = REGION_NUM_RECTS(rgn);
269
 
    size = REGION_SIZE(rgn);
270
 
    rects = REGION_RECTS(rgn);
271
 
    ErrorF("[mi] num: %d size: %d\n", num, size);
272
 
    ErrorF("[mi] extents: %d %d %d %d\n",
273
 
           rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
274
 
    for (i = 0; i < num; i++)
275
 
      ErrorF("[mi] %d %d %d %d \n",
276
 
             rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
277
 
    ErrorF("[mi] \n");
278
 
}
279
 
 
280
 
Bool
281
 
miRegionEqual(RegionPtr reg1, RegionPtr reg2)
282
 
{
283
 
    return pixman_region_equal (reg1, reg2);
284
 
}
285
 
 
286
 
#ifdef DEBUG
287
 
Bool
288
 
miValidRegion(RegionPtr reg)
289
 
{
290
 
    int i, numRects;
291
 
    
292
 
    if ((reg->extents.x1 > reg->extents.x2) ||
293
 
        (reg->extents.y1 > reg->extents.y2))
294
 
        return FALSE;
295
 
    numRects = REGION_NUM_RECTS(reg);
296
 
    if (!numRects)
297
 
        return ((reg->extents.x1 == reg->extents.x2) &&
298
 
                (reg->extents.y1 == reg->extents.y2) &&
299
 
                (reg->data->size || (reg->data == &miEmptyData)));
300
 
    else if (numRects == 1)
301
 
        return (!reg->data);
302
 
    else
303
 
    {
304
 
        BoxPtr pboxP, pboxN;
305
 
        BoxRec box;
306
 
        
307
 
        pboxP = REGION_RECTS(reg);
308
 
        box = *pboxP;
309
 
        box.y2 = pboxP[numRects-1].y2;
310
 
        pboxN = pboxP + 1;
311
 
        for (i = numRects; --i > 0; pboxP++, pboxN++)
312
 
        {
313
 
            if ((pboxN->x1 >= pboxN->x2) ||
314
 
                (pboxN->y1 >= pboxN->y2))
315
 
                return FALSE;
316
 
            if (pboxN->x1 < box.x1)
317
 
                box.x1 = pboxN->x1;
318
 
            if (pboxN->x2 > box.x2)
319
 
                box.x2 = pboxN->x2;
320
 
            if ((pboxN->y1 < pboxP->y1) ||
321
 
                ((pboxN->y1 == pboxP->y1) &&
322
 
                 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
323
 
                return FALSE;
324
 
        }
325
 
        return ((box.x1 == reg->extents.x1) &&
326
 
                (box.x2 == reg->extents.x2) &&
327
 
                (box.y1 == reg->extents.y1) &&
328
 
                (box.y2 == reg->extents.y2));
329
 
    }
330
 
}
331
 
#endif /* DEBUG */
332
 
 
333
 
/*****************************************************************
334
 
 *   RegionInit(pReg, rect, size)
335
 
 *     Outer region rect is statically allocated.
336
 
 *****************************************************************/
337
 
 
338
 
void
339
 
miRegionInit(RegionPtr pReg, BoxPtr rect, int size)
340
 
{
341
 
    if (rect)
342
 
        pixman_region_init_with_extents (pReg, rect);
343
 
    else
344
 
        pixman_region_init (pReg);
345
 
}
346
 
 
347
 
void
348
 
miRegionUninit(RegionPtr pReg)
349
 
{
350
 
    pixman_region_fini (pReg);
351
 
}
352
 
 
353
 
Bool
354
 
miRegionBreak (RegionPtr pReg)
355
 
{
356
 
    xfreeData (pReg);
357
 
    pReg->extents = miEmptyBox;
358
 
    pReg->data = &miBrokenData;
359
 
    return FALSE;
360
 
}
361
 
 
362
 
Bool
363
 
miRectAlloc(RegionPtr pRgn, int n)
364
 
{
365
 
    RegDataPtr  data;
366
 
    
367
 
    if (!pRgn->data)
368
 
    {
369
 
        n++;
370
 
        pRgn->data = xallocData(n);
371
 
        if (!pRgn->data)
372
 
            return miRegionBreak (pRgn);
373
 
        pRgn->data->numRects = 1;
374
 
        *REGION_BOXPTR(pRgn) = pRgn->extents;
375
 
    }
376
 
    else if (!pRgn->data->size)
377
 
    {
378
 
        pRgn->data = xallocData(n);
379
 
        if (!pRgn->data)
380
 
            return miRegionBreak (pRgn);
381
 
        pRgn->data->numRects = 0;
382
 
    }
383
 
    else
384
 
    {
385
 
        if (n == 1)
386
 
        {
387
 
            n = pRgn->data->numRects;
388
 
            if (n > 500) /* XXX pick numbers out of a hat */
389
 
                n = 250;
390
 
        }
391
 
        n += pRgn->data->numRects;
392
 
        data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n));
393
 
        if (!data)
394
 
            return miRegionBreak (pRgn);
395
 
        pRgn->data = data;
396
 
    }
397
 
    pRgn->data->size = n;
398
 
    return TRUE;
399
 
}
400
 
 
401
 
Bool
402
 
miRegionCopy(RegionPtr dst, RegionPtr src)
403
 
{
404
 
    return pixman_region_copy (dst, src);
405
 
}
406
 
 
407
 
/*======================================================================
408
 
 *          Generic Region Operator
409
 
 *====================================================================*/
410
 
 
411
 
/*-
412
 
 *-----------------------------------------------------------------------
413
 
 * miCoalesce --
414
 
 *      Attempt to merge the boxes in the current band with those in the
415
 
 *      previous one.  We are guaranteed that the current band extends to
416
 
 *      the end of the rects array.  Used only by miRegionOp.
417
 
 *
418
 
 * Results:
419
 
 *      The new index for the previous band.
420
 
 *
421
 
 * Side Effects:
422
 
 *      If coalescing takes place:
423
 
 *          - rectangles in the previous band will have their y2 fields
424
 
 *            altered.
425
 
 *          - pReg->data->numRects will be decreased.
426
 
 *
427
 
 *-----------------------------------------------------------------------
428
 
 */
429
 
_X_INLINE static int
430
 
miCoalesce (
431
 
    RegionPtr   pReg,           /* Region to coalesce                */
432
 
    int                 prevStart,      /* Index of start of previous band   */
433
 
    int                 curStart)       /* Index of start of current band    */
434
 
{
435
 
    BoxPtr      pPrevBox;       /* Current box in previous band      */
436
 
    BoxPtr      pCurBox;        /* Current box in current band       */
437
 
    int         numRects;       /* Number rectangles in both bands   */
438
 
    int         y2;             /* Bottom of current band            */
439
 
    /*
440
 
     * Figure out how many rectangles are in the band.
441
 
     */
442
 
    numRects = curStart - prevStart;
443
 
    assert(numRects == pReg->data->numRects - curStart);
444
 
 
445
 
    if (!numRects) return curStart;
446
 
 
447
 
    /*
448
 
     * The bands may only be coalesced if the bottom of the previous
449
 
     * matches the top scanline of the current.
450
 
     */
451
 
    pPrevBox = REGION_BOX(pReg, prevStart);
452
 
    pCurBox = REGION_BOX(pReg, curStart);
453
 
    if (pPrevBox->y2 != pCurBox->y1) return curStart;
454
 
 
455
 
    /*
456
 
     * Make sure the bands have boxes in the same places. This
457
 
     * assumes that boxes have been added in such a way that they
458
 
     * cover the most area possible. I.e. two boxes in a band must
459
 
     * have some horizontal space between them.
460
 
     */
461
 
    y2 = pCurBox->y2;
462
 
 
463
 
    do {
464
 
        if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
465
 
            return (curStart);
466
 
        }
467
 
        pPrevBox++;
468
 
        pCurBox++;
469
 
        numRects--;
470
 
    } while (numRects);
471
 
 
472
 
    /*
473
 
     * The bands may be merged, so set the bottom y of each box
474
 
     * in the previous band to the bottom y of the current band.
475
 
     */
476
 
    numRects = curStart - prevStart;
477
 
    pReg->data->numRects -= numRects;
478
 
    do {
479
 
        pPrevBox--;
480
 
        pPrevBox->y2 = y2;
481
 
        numRects--;
482
 
    } while (numRects);
483
 
    return prevStart;
484
 
}
485
 
 
486
 
 
487
 
/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */
488
 
 
489
 
#define Coalesce(newReg, prevBand, curBand)                             \
490
 
    if (curBand - prevBand == newReg->data->numRects - curBand) {       \
491
 
        prevBand = miCoalesce(newReg, prevBand, curBand);               \
492
 
    } else {                                                            \
493
 
        prevBand = curBand;                                             \
494
 
    }
495
 
 
496
 
/*-
497
 
 *-----------------------------------------------------------------------
498
 
 * miAppendNonO --
499
 
 *      Handle a non-overlapping band for the union and subtract operations.
500
 
 *      Just adds the (top/bottom-clipped) rectangles into the region.
501
 
 *      Doesn't have to check for subsumption or anything.
502
 
 *
503
 
 * Results:
504
 
 *      None.
505
 
 *
506
 
 * Side Effects:
507
 
 *      pReg->data->numRects is incremented and the rectangles overwritten
508
 
 *      with the rectangles we're passed.
509
 
 *
510
 
 *-----------------------------------------------------------------------
511
 
 */
512
 
 
513
 
_X_INLINE static Bool
514
 
miAppendNonO (
515
 
    RegionPtr   pReg,
516
 
    BoxPtr      r,
517
 
    BoxPtr      rEnd,
518
 
    int         y1,
519
 
    int         y2)
520
 
{
521
 
    BoxPtr      pNextRect;
522
 
    int         newRects;
523
 
 
524
 
    newRects = rEnd - r;
525
 
 
526
 
    assert(y1 < y2);
527
 
    assert(newRects != 0);
528
 
 
529
 
    /* Make sure we have enough space for all rectangles to be added */
530
 
    RECTALLOC(pReg, newRects);
531
 
    pNextRect = REGION_TOP(pReg);
532
 
    pReg->data->numRects += newRects;
533
 
    do {
534
 
        assert(r->x1 < r->x2);
535
 
        ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
536
 
        r++;
537
 
    } while (r != rEnd);
538
 
 
539
 
    return TRUE;
540
 
}
541
 
 
542
 
#define FindBand(r, rBandEnd, rEnd, ry1)                    \
543
 
{                                                           \
544
 
    ry1 = r->y1;                                            \
545
 
    rBandEnd = r+1;                                         \
546
 
    while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
547
 
        rBandEnd++;                                         \
548
 
    }                                                       \
549
 
}
550
 
 
551
 
#define AppendRegions(newReg, r, rEnd)                                  \
552
 
{                                                                       \
553
 
    int newRects;                                                       \
554
 
    if ((newRects = rEnd - r)) {                                        \
555
 
        RECTALLOC(newReg, newRects);                                    \
556
 
        memmove((char *)REGION_TOP(newReg),(char *)r,                   \
557
 
              newRects * sizeof(BoxRec));                               \
558
 
        newReg->data->numRects += newRects;                             \
559
 
    }                                                                   \
560
 
}
561
 
 
562
 
/*-
563
 
 *-----------------------------------------------------------------------
564
 
 * miRegionOp --
565
 
 *      Apply an operation to two regions. Called by miUnion, miInverse,
566
 
 *      miSubtract, miIntersect....  Both regions MUST have at least one
567
 
 *      rectangle, and cannot be the same object.
568
 
 *
569
 
 * Results:
570
 
 *      TRUE if successful.
571
 
 *
572
 
 * Side Effects:
573
 
 *      The new region is overwritten.
574
 
 *      pOverlap set to TRUE if overlapFunc ever returns TRUE.
575
 
 *
576
 
 * Notes:
577
 
 *      The idea behind this function is to view the two regions as sets.
578
 
 *      Together they cover a rectangle of area that this function divides
579
 
 *      into horizontal bands where points are covered only by one region
580
 
 *      or by both. For the first case, the nonOverlapFunc is called with
581
 
 *      each the band and the band's upper and lower extents. For the
582
 
 *      second, the overlapFunc is called to process the entire band. It
583
 
 *      is responsible for clipping the rectangles in the band, though
584
 
 *      this function provides the boundaries.
585
 
 *      At the end of each band, the new region is coalesced, if possible,
586
 
 *      to reduce the number of rectangles in the region.
587
 
 *
588
 
 *-----------------------------------------------------------------------
589
 
 */
590
 
 
591
 
typedef Bool (*OverlapProcPtr)(
592
 
    RegionPtr   pReg,
593
 
    BoxPtr      r1,
594
 
    BoxPtr      r1End,
595
 
    BoxPtr      r2,
596
 
    BoxPtr      r2End,
597
 
    short       y1,
598
 
    short       y2,
599
 
    Bool        *pOverlap);
600
 
 
601
 
static Bool
602
 
miRegionOp(
603
 
    RegionPtr       newReg,                 /* Place to store result         */
604
 
    RegionPtr       reg1,                   /* First region in operation     */
605
 
    RegionPtr       reg2,                   /* 2d region in operation        */
606
 
    OverlapProcPtr  overlapFunc,            /* Function to call for over-
607
 
                                             * lapping bands                 */
608
 
    Bool            appendNon1,             /* Append non-overlapping bands  */
609
 
                                            /* in region 1 ? */
610
 
    Bool            appendNon2,             /* Append non-overlapping bands  */
611
 
                                            /* in region 2 ? */
612
 
    Bool            *pOverlap)
613
 
{
614
 
    BoxPtr      r1;                 /* Pointer into first region     */
615
 
    BoxPtr      r2;                 /* Pointer into 2d region        */
616
 
    BoxPtr      r1End;              /* End of 1st region             */
617
 
    BoxPtr      r2End;              /* End of 2d region              */
618
 
    short       ybot;               /* Bottom of intersection        */
619
 
    short       ytop;               /* Top of intersection           */
620
 
    RegDataPtr  oldData;            /* Old data for newReg           */
621
 
    int         prevBand;           /* Index of start of
622
 
                                     * previous band in newReg       */
623
 
    int         curBand;            /* Index of start of current
624
 
                                     * band in newReg                */
625
 
    BoxPtr      r1BandEnd;          /* End of current band in r1     */
626
 
    BoxPtr      r2BandEnd;          /* End of current band in r2     */
627
 
    short       top;                /* Top of non-overlapping band   */
628
 
    short       bot;                /* Bottom of non-overlapping band*/
629
 
    int         r1y1;               /* Temps for r1->y1 and r2->y1   */
630
 
    int         r2y1;
631
 
    int         newSize;
632
 
    int         numRects;
633
 
 
634
 
    /*
635
 
     * Break any region computed from a broken region
636
 
     */
637
 
    if (REGION_NAR (reg1) || REGION_NAR(reg2))
638
 
        return miRegionBreak (newReg);
639
 
    
640
 
    /*
641
 
     * Initialization:
642
 
     *  set r1, r2, r1End and r2End appropriately, save the rectangles
643
 
     * of the destination region until the end in case it's one of
644
 
     * the two source regions, then mark the "new" region empty, allocating
645
 
     * another array of rectangles for it to use.
646
 
     */
647
 
 
648
 
    r1 = REGION_RECTS(reg1);
649
 
    newSize = REGION_NUM_RECTS(reg1);
650
 
    r1End = r1 + newSize;
651
 
    numRects = REGION_NUM_RECTS(reg2);
652
 
    r2 = REGION_RECTS(reg2);
653
 
    r2End = r2 + numRects;
654
 
    assert(r1 != r1End);
655
 
    assert(r2 != r2End);
656
 
 
657
 
    oldData = NULL;
658
 
    if (((newReg == reg1) && (newSize > 1)) ||
659
 
        ((newReg == reg2) && (numRects > 1)))
660
 
    {
661
 
        oldData = newReg->data;
662
 
        newReg->data = &miEmptyData;
663
 
    }
664
 
    /* guess at new size */
665
 
    if (numRects > newSize)
666
 
        newSize = numRects;
667
 
    newSize <<= 1;
668
 
    if (!newReg->data)
669
 
        newReg->data = &miEmptyData;
670
 
    else if (newReg->data->size)
671
 
        newReg->data->numRects = 0;
672
 
    if (newSize > newReg->data->size)
673
 
        if (!miRectAlloc(newReg, newSize))
674
 
            return FALSE;
675
 
 
676
 
    /*
677
 
     * Initialize ybot.
678
 
     * In the upcoming loop, ybot and ytop serve different functions depending
679
 
     * on whether the band being handled is an overlapping or non-overlapping
680
 
     * band.
681
 
     *  In the case of a non-overlapping band (only one of the regions
682
 
     * has points in the band), ybot is the bottom of the most recent
683
 
     * intersection and thus clips the top of the rectangles in that band.
684
 
     * ytop is the top of the next intersection between the two regions and
685
 
     * serves to clip the bottom of the rectangles in the current band.
686
 
     *  For an overlapping band (where the two regions intersect), ytop clips
687
 
     * the top of the rectangles of both regions and ybot clips the bottoms.
688
 
     */
689
 
 
690
 
    ybot = min(r1->y1, r2->y1);
691
 
    
692
 
    /*
693
 
     * prevBand serves to mark the start of the previous band so rectangles
694
 
     * can be coalesced into larger rectangles. qv. miCoalesce, above.
695
 
     * In the beginning, there is no previous band, so prevBand == curBand
696
 
     * (curBand is set later on, of course, but the first band will always
697
 
     * start at index 0). prevBand and curBand must be indices because of
698
 
     * the possible expansion, and resultant moving, of the new region's
699
 
     * array of rectangles.
700
 
     */
701
 
    prevBand = 0;
702
 
    
703
 
    do {
704
 
        /*
705
 
         * This algorithm proceeds one source-band (as opposed to a
706
 
         * destination band, which is determined by where the two regions
707
 
         * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
708
 
         * rectangle after the last one in the current band for their
709
 
         * respective regions.
710
 
         */
711
 
        assert(r1 != r1End);
712
 
        assert(r2 != r2End);
713
 
    
714
 
        FindBand(r1, r1BandEnd, r1End, r1y1);
715
 
        FindBand(r2, r2BandEnd, r2End, r2y1);
716
 
 
717
 
        /*
718
 
         * First handle the band that doesn't intersect, if any.
719
 
         *
720
 
         * Note that attention is restricted to one band in the
721
 
         * non-intersecting region at once, so if a region has n
722
 
         * bands between the current position and the next place it overlaps
723
 
         * the other, this entire loop will be passed through n times.
724
 
         */
725
 
        if (r1y1 < r2y1) {
726
 
            if (appendNon1) {
727
 
                top = max(r1y1, ybot);
728
 
                bot = min(r1->y2, r2y1);
729
 
                if (top != bot) {
730
 
                    curBand = newReg->data->numRects;
731
 
                    miAppendNonO(newReg, r1, r1BandEnd, top, bot);
732
 
                    Coalesce(newReg, prevBand, curBand);
733
 
                }
734
 
            }
735
 
            ytop = r2y1;
736
 
        } else if (r2y1 < r1y1) {
737
 
            if (appendNon2) {
738
 
                top = max(r2y1, ybot);
739
 
                bot = min(r2->y2, r1y1);
740
 
                if (top != bot) {
741
 
                    curBand = newReg->data->numRects;
742
 
                    miAppendNonO(newReg, r2, r2BandEnd, top, bot);
743
 
                    Coalesce(newReg, prevBand, curBand);
744
 
                }
745
 
            }
746
 
            ytop = r1y1;
747
 
        } else {
748
 
            ytop = r1y1;
749
 
        }
750
 
 
751
 
        /*
752
 
         * Now see if we've hit an intersecting band. The two bands only
753
 
         * intersect if ybot > ytop
754
 
         */
755
 
        ybot = min(r1->y2, r2->y2);
756
 
        if (ybot > ytop) {
757
 
            curBand = newReg->data->numRects;
758
 
            (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
759
 
                            pOverlap);
760
 
            Coalesce(newReg, prevBand, curBand);
761
 
        }
762
 
 
763
 
        /*
764
 
         * If we've finished with a band (y2 == ybot) we skip forward
765
 
         * in the region to the next band.
766
 
         */
767
 
        if (r1->y2 == ybot) r1 = r1BandEnd;
768
 
        if (r2->y2 == ybot) r2 = r2BandEnd;
769
 
 
770
 
    } while (r1 != r1End && r2 != r2End);
771
 
 
772
 
    /*
773
 
     * Deal with whichever region (if any) still has rectangles left.
774
 
     *
775
 
     * We only need to worry about banding and coalescing for the very first
776
 
     * band left.  After that, we can just group all remaining boxes,
777
 
     * regardless of how many bands, into one final append to the list.
778
 
     */
779
 
 
780
 
    if ((r1 != r1End) && appendNon1) {
781
 
        /* Do first nonOverlap1Func call, which may be able to coalesce */
782
 
        FindBand(r1, r1BandEnd, r1End, r1y1);
783
 
        curBand = newReg->data->numRects;
784
 
        miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
785
 
        Coalesce(newReg, prevBand, curBand);
786
 
        /* Just append the rest of the boxes  */
787
 
        AppendRegions(newReg, r1BandEnd, r1End);
788
 
 
789
 
    } else if ((r2 != r2End) && appendNon2) {
790
 
        /* Do first nonOverlap2Func call, which may be able to coalesce */
791
 
        FindBand(r2, r2BandEnd, r2End, r2y1);
792
 
        curBand = newReg->data->numRects;
793
 
        miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
794
 
        Coalesce(newReg, prevBand, curBand);
795
 
        /* Append rest of boxes */
796
 
        AppendRegions(newReg, r2BandEnd, r2End);
797
 
    }
798
 
 
799
 
    if (oldData)
800
 
        xfree(oldData);
801
 
 
802
 
    if (!(numRects = newReg->data->numRects))
803
 
    {
804
 
        xfreeData(newReg);
805
 
        newReg->data = &miEmptyData;
806
 
    }
807
 
    else if (numRects == 1)
808
 
    {
809
 
        newReg->extents = *REGION_BOXPTR(newReg);
810
 
        xfreeData(newReg);
811
 
        newReg->data = NULL;
812
 
    }
813
 
    else
814
 
    {
815
 
        DOWNSIZE(newReg, numRects);
816
 
    }
817
 
 
818
 
    return TRUE;
819
 
}
820
 
 
821
 
/*-
822
 
 *-----------------------------------------------------------------------
823
 
 * miSetExtents --
824
 
 *      Reset the extents of a region to what they should be. Called by
825
 
 *      miSubtract and miIntersect as they can't figure it out along the
826
 
 *      way or do so easily, as miUnion can.
827
 
 *
828
 
 * Results:
829
 
 *      None.
830
 
 *
831
 
 * Side Effects:
832
 
 *      The region's 'extents' structure is overwritten.
833
 
 *
834
 
 *-----------------------------------------------------------------------
835
 
 */
836
 
static void
837
 
miSetExtents (RegionPtr pReg)
838
 
{
839
 
    BoxPtr pBox, pBoxEnd;
840
 
 
841
 
    if (!pReg->data)
842
 
        return;
843
 
    if (!pReg->data->size)
844
 
    {
845
 
        pReg->extents.x2 = pReg->extents.x1;
846
 
        pReg->extents.y2 = pReg->extents.y1;
847
 
        return;
848
 
    }
849
 
 
850
 
    pBox = REGION_BOXPTR(pReg);
851
 
    pBoxEnd = REGION_END(pReg);
852
 
 
853
 
    /*
854
 
     * Since pBox is the first rectangle in the region, it must have the
855
 
     * smallest y1 and since pBoxEnd is the last rectangle in the region,
856
 
     * it must have the largest y2, because of banding. Initialize x1 and
857
 
     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
858
 
     * to...
859
 
     */
860
 
    pReg->extents.x1 = pBox->x1;
861
 
    pReg->extents.y1 = pBox->y1;
862
 
    pReg->extents.x2 = pBoxEnd->x2;
863
 
    pReg->extents.y2 = pBoxEnd->y2;
864
 
 
865
 
    assert(pReg->extents.y1 < pReg->extents.y2);
866
 
    while (pBox <= pBoxEnd) {
867
 
        if (pBox->x1 < pReg->extents.x1)
868
 
            pReg->extents.x1 = pBox->x1;
869
 
        if (pBox->x2 > pReg->extents.x2)
870
 
            pReg->extents.x2 = pBox->x2;
871
 
        pBox++;
872
 
    };
873
 
 
874
 
    assert(pReg->extents.x1 < pReg->extents.x2);
875
 
}
876
 
 
877
 
/*======================================================================
878
 
 *          Region Intersection
879
 
 *====================================================================*/
880
 
/*-
881
 
 *-----------------------------------------------------------------------
882
 
 * miIntersectO --
883
 
 *      Handle an overlapping band for miIntersect.
884
 
 *
885
 
 * Results:
886
 
 *      TRUE if successful.
887
 
 *
888
 
 * Side Effects:
889
 
 *      Rectangles may be added to the region.
890
 
 *
891
 
 *-----------------------------------------------------------------------
892
 
 */
893
 
/*ARGSUSED*/
894
 
Bool
895
 
miIntersect(
896
 
    RegionPtr   newReg,     /* destination Region */
897
 
    RegionPtr   reg1,
898
 
    RegionPtr   reg2        /* source regions     */
899
 
    )
900
 
{
901
 
    return pixman_region_intersect (newReg, reg1, reg2);
902
 
}
903
 
 
904
 
#define MERGERECT(r)                                            \
905
 
{                                                               \
906
 
    if (r->x1 <= x2) {                                          \
907
 
        /* Merge with current rectangle */                      \
908
 
        if (r->x1 < x2) *pOverlap = TRUE;                               \
909
 
        if (x2 < r->x2) x2 = r->x2;                             \
910
 
    } else {                                                    \
911
 
        /* Add current rectangle, start new one */              \
912
 
        NEWRECT(pReg, pNextRect, x1, y1, x2, y2);               \
913
 
        x1 = r->x1;                                             \
914
 
        x2 = r->x2;                                             \
915
 
    }                                                           \
916
 
    r++;                                                        \
917
 
}
918
 
 
919
 
/*======================================================================
920
 
 *          Region Union
921
 
 *====================================================================*/
922
 
 
923
 
/*-
924
 
 *-----------------------------------------------------------------------
925
 
 * miUnionO --
926
 
 *      Handle an overlapping band for the union operation. Picks the
927
 
 *      left-most rectangle each time and merges it into the region.
928
 
 *
929
 
 * Results:
930
 
 *      TRUE if successful.
931
 
 *
932
 
 * Side Effects:
933
 
 *      pReg is overwritten.
934
 
 *      pOverlap is set to TRUE if any boxes overlap.
935
 
 *
936
 
 *-----------------------------------------------------------------------
937
 
 */
938
 
static Bool
939
 
miUnionO (
940
 
    RegionPtr   pReg,
941
 
    BoxPtr      r1,
942
 
    BoxPtr      r1End,
943
 
    BoxPtr      r2,
944
 
    BoxPtr      r2End,
945
 
    short       y1,
946
 
    short       y2,
947
 
    Bool        *pOverlap)
948
 
{
949
 
    BoxPtr     pNextRect;
950
 
    int        x1;     /* left and right side of current union */
951
 
    int        x2;
952
 
 
953
 
    assert (y1 < y2);
954
 
    assert(r1 != r1End && r2 != r2End);
955
 
 
956
 
    pNextRect = REGION_TOP(pReg);
957
 
 
958
 
    /* Start off current rectangle */
959
 
    if (r1->x1 < r2->x1)
960
 
    {
961
 
        x1 = r1->x1;
962
 
        x2 = r1->x2;
963
 
        r1++;
964
 
    }
965
 
    else
966
 
    {
967
 
        x1 = r2->x1;
968
 
        x2 = r2->x2;
969
 
        r2++;
970
 
    }
971
 
    while (r1 != r1End && r2 != r2End)
972
 
    {
973
 
        if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
974
 
    }
975
 
 
976
 
    /* Finish off whoever (if any) is left */
977
 
    if (r1 != r1End)
978
 
    {
979
 
        do
980
 
        {
981
 
            MERGERECT(r1);
982
 
        } while (r1 != r1End);
983
 
    }
984
 
    else if (r2 != r2End)
985
 
    {
986
 
        do
987
 
        {
988
 
            MERGERECT(r2);
989
 
        } while (r2 != r2End);
990
 
    }
991
 
    
992
 
    /* Add current rectangle */
993
 
    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
994
 
 
995
 
    return TRUE;
996
 
}
997
 
 
998
 
Bool
999
 
miUnion(
1000
 
    RegionPtr   newReg,          /* destination Region */
1001
 
    RegionPtr   reg1,
1002
 
    RegionPtr   reg2             /* source regions     */
1003
 
    )
1004
 
{
1005
 
    return pixman_region_union (newReg, reg1, reg2);
1006
 
}
1007
 
 
1008
 
/*======================================================================
1009
 
 *          Batch Rectangle Union
1010
 
 *====================================================================*/
1011
 
 
1012
 
/*-
1013
 
 *-----------------------------------------------------------------------
1014
 
 * miRegionAppend --
1015
 
 * 
1016
 
 *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
1017
 
 *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
1018
 
 *      becomes a non-y-x-banded random collection of rectangles, and not
1019
 
 *      yet a true region.  After a sequence of appends, the caller must
1020
 
 *      call miRegionValidate to ensure that a valid region is constructed.
1021
 
 *
1022
 
 * Results:
1023
 
 *      TRUE if successful.
1024
 
 *
1025
 
 * Side Effects:
1026
 
 *      dstrgn is modified if rgn has rectangles.
1027
 
 *
1028
 
 */
1029
 
Bool
1030
 
miRegionAppend(RegionPtr dstrgn, RegionPtr rgn)
1031
 
{
1032
 
    int numRects, dnumRects, size;
1033
 
    BoxPtr new, old;
1034
 
    Bool prepend;
1035
 
 
1036
 
    if (REGION_NAR(rgn))
1037
 
        return miRegionBreak (dstrgn);
1038
 
    
1039
 
    if (!rgn->data && (dstrgn->data == &miEmptyData))
1040
 
    {
1041
 
        dstrgn->extents = rgn->extents;
1042
 
        dstrgn->data = NULL;
1043
 
        return TRUE;
1044
 
    }
1045
 
 
1046
 
    numRects = REGION_NUM_RECTS(rgn);
1047
 
    if (!numRects)
1048
 
        return TRUE;
1049
 
    prepend = FALSE;
1050
 
    size = numRects;
1051
 
    dnumRects = REGION_NUM_RECTS(dstrgn);
1052
 
    if (!dnumRects && (size < 200))
1053
 
        size = 200; /* XXX pick numbers out of a hat */
1054
 
    RECTALLOC(dstrgn, size);
1055
 
    old = REGION_RECTS(rgn);
1056
 
    if (!dnumRects)
1057
 
        dstrgn->extents = rgn->extents;
1058
 
    else if (dstrgn->extents.x2 > dstrgn->extents.x1)
1059
 
    {
1060
 
        BoxPtr first, last;
1061
 
 
1062
 
        first = old;
1063
 
        last = REGION_BOXPTR(dstrgn) + (dnumRects - 1);
1064
 
        if ((first->y1 > last->y2) ||
1065
 
            ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1066
 
             (first->x1 > last->x2)))
1067
 
        {
1068
 
            if (rgn->extents.x1 < dstrgn->extents.x1)
1069
 
                dstrgn->extents.x1 = rgn->extents.x1;
1070
 
            if (rgn->extents.x2 > dstrgn->extents.x2)
1071
 
                dstrgn->extents.x2 = rgn->extents.x2;
1072
 
            dstrgn->extents.y2 = rgn->extents.y2;
1073
 
        }
1074
 
        else
1075
 
        {
1076
 
            first = REGION_BOXPTR(dstrgn);
1077
 
            last = old + (numRects - 1);
1078
 
            if ((first->y1 > last->y2) ||
1079
 
                ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1080
 
                 (first->x1 > last->x2)))
1081
 
            {
1082
 
                prepend = TRUE;
1083
 
                if (rgn->extents.x1 < dstrgn->extents.x1)
1084
 
                    dstrgn->extents.x1 = rgn->extents.x1;
1085
 
                if (rgn->extents.x2 > dstrgn->extents.x2)
1086
 
                    dstrgn->extents.x2 = rgn->extents.x2;
1087
 
                dstrgn->extents.y1 = rgn->extents.y1;
1088
 
            }
1089
 
            else
1090
 
                dstrgn->extents.x2 = dstrgn->extents.x1;
1091
 
        }
1092
 
    }
1093
 
    if (prepend)
1094
 
    {
1095
 
        new = REGION_BOX(dstrgn, numRects);
1096
 
        if (dnumRects == 1)
1097
 
            *new = *REGION_BOXPTR(dstrgn);
1098
 
        else
1099
 
            memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), 
1100
 
                  dnumRects * sizeof(BoxRec));
1101
 
        new = REGION_BOXPTR(dstrgn);
1102
 
    }
1103
 
    else
1104
 
        new = REGION_BOXPTR(dstrgn) + dnumRects;
1105
 
    if (numRects == 1)
1106
 
        *new = *old;
1107
 
    else
1108
 
        memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
1109
 
    dstrgn->data->numRects += numRects;
1110
 
    return TRUE;
1111
 
}
1112
 
 
1113
 
   
1114
 
#define ExchangeRects(a, b) \
1115
 
{                           \
1116
 
    BoxRec     t;           \
1117
 
    t = rects[a];           \
1118
 
    rects[a] = rects[b];    \
1119
 
    rects[b] = t;           \
1120
 
}
1121
 
 
1122
 
static void
1123
 
QuickSortRects(
1124
 
    BoxRec     rects[],
1125
 
    int        numRects)
1126
 
{
1127
 
    int y1;
1128
 
    int x1;
1129
 
    int        i, j;
1130
 
    BoxPtr     r;
1131
 
 
1132
 
    /* Always called with numRects > 1 */
1133
 
 
1134
 
    do
1135
 
    {
1136
 
        if (numRects == 2)
1137
 
        {
1138
 
            if (rects[0].y1 > rects[1].y1 ||
1139
 
                    (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1140
 
                ExchangeRects(0, 1);
1141
 
            return;
1142
 
        }
1143
 
 
1144
 
        /* Choose partition element, stick in location 0 */
1145
 
        ExchangeRects(0, numRects >> 1);
1146
 
        y1 = rects[0].y1;
1147
 
        x1 = rects[0].x1;
1148
 
 
1149
 
        /* Partition array */
1150
 
        i = 0;
1151
 
        j = numRects;
1152
 
        do
1153
 
        {
1154
 
            r = &(rects[i]);
1155
 
            do
1156
 
            {
1157
 
                r++;
1158
 
                i++;
1159
 
            } while (i != numRects &&
1160
 
                     (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1161
 
            r = &(rects[j]);
1162
 
            do
1163
 
            {
1164
 
                r--;
1165
 
                j--;
1166
 
            } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1167
 
            if (i < j)
1168
 
                ExchangeRects(i, j);
1169
 
        } while (i < j);
1170
 
 
1171
 
        /* Move partition element back to middle */
1172
 
        ExchangeRects(0, j);
1173
 
 
1174
 
        /* Recurse */
1175
 
        if (numRects-j-1 > 1)
1176
 
            QuickSortRects(&rects[j+1], numRects-j-1);
1177
 
        numRects = j;
1178
 
    } while (numRects > 1);
1179
 
}
1180
 
 
1181
 
/*-
1182
 
 *-----------------------------------------------------------------------
1183
 
 * miRegionValidate --
1184
 
 * 
1185
 
 *      Take a ``region'' which is a non-y-x-banded random collection of
1186
 
 *      rectangles, and compute a nice region which is the union of all the
1187
 
 *      rectangles.
1188
 
 *
1189
 
 * Results:
1190
 
 *      TRUE if successful.
1191
 
 *
1192
 
 * Side Effects:
1193
 
 *      The passed-in ``region'' may be modified.
1194
 
 *      pOverlap set to TRUE if any retangles overlapped, else FALSE;
1195
 
 *
1196
 
 * Strategy:
1197
 
 *      Step 1. Sort the rectangles into ascending order with primary key y1
1198
 
 *              and secondary key x1.
1199
 
 *
1200
 
 *      Step 2. Split the rectangles into the minimum number of proper y-x
1201
 
 *              banded regions.  This may require horizontally merging
1202
 
 *              rectangles, and vertically coalescing bands.  With any luck,
1203
 
 *              this step in an identity tranformation (ala the Box widget),
1204
 
 *              or a coalescing into 1 box (ala Menus).
1205
 
 *
1206
 
 *      Step 3. Merge the separate regions down to a single region by calling
1207
 
 *              miUnion.  Maximize the work each miUnion call does by using
1208
 
 *              a binary merge.
1209
 
 *
1210
 
 *-----------------------------------------------------------------------
1211
 
 */
1212
 
 
1213
 
Bool
1214
 
miRegionValidate(RegionPtr badreg, Bool *pOverlap)
1215
 
{
1216
 
    /* Descriptor for regions under construction  in Step 2. */
1217
 
    typedef struct {
1218
 
        RegionRec   reg;
1219
 
        int         prevBand;
1220
 
        int         curBand;
1221
 
    } RegionInfo;
1222
 
 
1223
 
    int numRects;   /* Original numRects for badreg         */
1224
 
    RegionInfo *ri;         /* Array of current regions             */
1225
 
    int numRI;      /* Number of entries used in ri         */
1226
 
    int sizeRI;     /* Number of entries available in ri    */
1227
 
    int i;          /* Index into rects                     */
1228
 
    int j;          /* Index into ri                        */
1229
 
    RegionInfo *rit;       /* &ri[j]                                */
1230
 
    RegionPtr  reg;        /* ri[j].reg                     */
1231
 
    BoxPtr      box;        /* Current box in rects                 */
1232
 
    BoxPtr      riBox;      /* Last box in ri[j].reg                */
1233
 
    RegionPtr  hreg;       /* ri[j_half].reg                        */
1234
 
    Bool                ret = TRUE;
1235
 
 
1236
 
    *pOverlap = FALSE;
1237
 
    if (!badreg->data)
1238
 
    {
1239
 
        good(badreg);
1240
 
        return TRUE;
1241
 
    }
1242
 
    numRects = badreg->data->numRects;
1243
 
    if (!numRects)
1244
 
    {
1245
 
        if (REGION_NAR(badreg))
1246
 
            return FALSE;
1247
 
        good(badreg);
1248
 
        return TRUE;
1249
 
    }
1250
 
    if (badreg->extents.x1 < badreg->extents.x2)
1251
 
    {
1252
 
        if ((numRects) == 1)
1253
 
        {
1254
 
            xfreeData(badreg);
1255
 
            badreg->data = (RegDataPtr) NULL;
1256
 
        }
1257
 
        else
1258
 
        {
1259
 
            DOWNSIZE(badreg, numRects);
1260
 
        }
1261
 
        good(badreg);
1262
 
        return TRUE;
1263
 
    }
1264
 
 
1265
 
    /* Step 1: Sort the rects array into ascending (y1, x1) order */
1266
 
    QuickSortRects(REGION_BOXPTR(badreg), numRects);
1267
 
 
1268
 
    /* Step 2: Scatter the sorted array into the minimum number of regions */
1269
 
 
1270
 
    /* Set up the first region to be the first rectangle in badreg */
1271
 
    /* Note that step 2 code will never overflow the ri[0].reg rects array */
1272
 
    ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo));
1273
 
    if (!ri)
1274
 
        return miRegionBreak (badreg);
1275
 
    sizeRI = 4;
1276
 
    numRI = 1;
1277
 
    ri[0].prevBand = 0;
1278
 
    ri[0].curBand = 0;
1279
 
    ri[0].reg = *badreg;
1280
 
    box = REGION_BOXPTR(&ri[0].reg);
1281
 
    ri[0].reg.extents = *box;
1282
 
    ri[0].reg.data->numRects = 1;
1283
 
 
1284
 
    /* Now scatter rectangles into the minimum set of valid regions.  If the
1285
 
       next rectangle to be added to a region would force an existing rectangle
1286
 
       in the region to be split up in order to maintain y-x banding, just
1287
 
       forget it.  Try the next region.  If it doesn't fit cleanly into any
1288
 
       region, make a new one. */
1289
 
 
1290
 
    for (i = numRects; --i > 0;)
1291
 
    {
1292
 
        box++;
1293
 
        /* Look for a region to append box to */
1294
 
        for (j = numRI, rit = ri; --j >= 0; rit++)
1295
 
        {
1296
 
            reg = &rit->reg;
1297
 
            riBox = REGION_END(reg);
1298
 
 
1299
 
            if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
1300
 
            {
1301
 
                /* box is in same band as riBox.  Merge or append it */
1302
 
                if (box->x1 <= riBox->x2)
1303
 
                {
1304
 
                    /* Merge it with riBox */
1305
 
                    if (box->x1 < riBox->x2) *pOverlap = TRUE;
1306
 
                    if (box->x2 > riBox->x2) riBox->x2 = box->x2;
1307
 
                }
1308
 
                else
1309
 
                {
1310
 
                    RECTALLOC_BAIL(reg, 1, bail);
1311
 
                    *REGION_TOP(reg) = *box;
1312
 
                    reg->data->numRects++;
1313
 
                }
1314
 
                goto NextRect;   /* So sue me */
1315
 
            }
1316
 
            else if (box->y1 >= riBox->y2)
1317
 
            {
1318
 
                /* Put box into new band */
1319
 
                if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1320
 
                if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
1321
 
                Coalesce(reg, rit->prevBand, rit->curBand);
1322
 
                rit->curBand = reg->data->numRects;
1323
 
                RECTALLOC_BAIL(reg, 1, bail);
1324
 
                *REGION_TOP(reg) = *box;
1325
 
                reg->data->numRects++;
1326
 
                goto NextRect;
1327
 
            }
1328
 
            /* Well, this region was inappropriate.  Try the next one. */
1329
 
        } /* for j */
1330
 
 
1331
 
        /* Uh-oh.  No regions were appropriate.  Create a new one. */
1332
 
        if (sizeRI == numRI)
1333
 
        {
1334
 
            /* Oops, allocate space for new region information */
1335
 
            sizeRI <<= 1;
1336
 
            rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo));
1337
 
            if (!rit)
1338
 
                goto bail;
1339
 
            ri = rit;
1340
 
            rit = &ri[numRI];
1341
 
        }
1342
 
        numRI++;
1343
 
        rit->prevBand = 0;
1344
 
        rit->curBand = 0;
1345
 
        rit->reg.extents = *box;
1346
 
        rit->reg.data = NULL;
1347
 
        if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
1348
 
            goto bail;
1349
 
NextRect: ;
1350
 
    } /* for i */
1351
 
 
1352
 
    /* Make a final pass over each region in order to Coalesce and set
1353
 
       extents.x2 and extents.y2 */
1354
 
 
1355
 
    for (j = numRI, rit = ri; --j >= 0; rit++)
1356
 
    {
1357
 
        reg = &rit->reg;
1358
 
        riBox = REGION_END(reg);
1359
 
        reg->extents.y2 = riBox->y2;
1360
 
        if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1361
 
        Coalesce(reg, rit->prevBand, rit->curBand);
1362
 
        if (reg->data->numRects == 1) /* keep unions happy below */
1363
 
        {
1364
 
            xfreeData(reg);
1365
 
            reg->data = NULL;
1366
 
        }
1367
 
    }
1368
 
 
1369
 
    /* Step 3: Union all regions into a single region */
1370
 
    while (numRI > 1)
1371
 
    {
1372
 
        int half = numRI/2;
1373
 
        for (j = numRI & 1; j < (half + (numRI & 1)); j++)
1374
 
        {
1375
 
            reg = &ri[j].reg;
1376
 
            hreg = &ri[j+half].reg;
1377
 
            if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap))
1378
 
                ret = FALSE;
1379
 
            if (hreg->extents.x1 < reg->extents.x1)
1380
 
                reg->extents.x1 = hreg->extents.x1;
1381
 
            if (hreg->extents.y1 < reg->extents.y1)
1382
 
                reg->extents.y1 = hreg->extents.y1;
1383
 
            if (hreg->extents.x2 > reg->extents.x2)
1384
 
                reg->extents.x2 = hreg->extents.x2;
1385
 
            if (hreg->extents.y2 > reg->extents.y2)
1386
 
                reg->extents.y2 = hreg->extents.y2;
1387
 
            xfreeData(hreg);
1388
 
        }
1389
 
        numRI -= half;
1390
 
    }
1391
 
    *badreg = ri[0].reg;
1392
 
    xfree(ri);
1393
 
    good(badreg);
1394
 
    return ret;
1395
 
bail:
1396
 
    for (i = 0; i < numRI; i++)
1397
 
        xfreeData(&ri[i].reg);
1398
 
    xfree (ri);
1399
 
    return miRegionBreak (badreg);
1400
 
}
1401
 
 
1402
 
RegionPtr
1403
 
miRectsToRegion(int nrects, xRectangle *prect, int ctype)
1404
 
{
1405
 
    
1406
 
    RegionPtr           pRgn;
1407
 
    RegDataPtr          pData;
1408
 
    BoxPtr              pBox;
1409
 
    int                 i;
1410
 
    int                 x1, y1, x2, y2;
1411
 
 
1412
 
    pRgn = miRegionCreate(NullBox, 0);
1413
 
    if (REGION_NAR (pRgn))
1414
 
        return pRgn;
1415
 
    if (!nrects)
1416
 
        return pRgn;
1417
 
    if (nrects == 1)
1418
 
    {
1419
 
        x1 = prect->x;
1420
 
        y1 = prect->y;
1421
 
        if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1422
 
            x2 = MAXSHORT;
1423
 
        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1424
 
            y2 = MAXSHORT;
1425
 
        if (x1 != x2 && y1 != y2)
1426
 
        {
1427
 
            pRgn->extents.x1 = x1;
1428
 
            pRgn->extents.y1 = y1;
1429
 
            pRgn->extents.x2 = x2;
1430
 
            pRgn->extents.y2 = y2;
1431
 
            pRgn->data = NULL;
1432
 
        }
1433
 
        return pRgn;
1434
 
    }
1435
 
    pData = xallocData(nrects);
1436
 
    if (!pData)
1437
 
    {
1438
 
        miRegionBreak (pRgn);
1439
 
        return pRgn;
1440
 
    }
1441
 
    pBox = (BoxPtr) (pData + 1);
1442
 
    for (i = nrects; --i >= 0; prect++)
1443
 
    {
1444
 
        x1 = prect->x;
1445
 
        y1 = prect->y;
1446
 
        if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1447
 
            x2 = MAXSHORT;
1448
 
        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1449
 
            y2 = MAXSHORT;
1450
 
        if (x1 != x2 && y1 != y2)
1451
 
        {
1452
 
            pBox->x1 = x1;
1453
 
            pBox->y1 = y1;
1454
 
            pBox->x2 = x2;
1455
 
            pBox->y2 = y2;
1456
 
            pBox++;
1457
 
        }
1458
 
    }
1459
 
    if (pBox != (BoxPtr) (pData + 1))
1460
 
    {
1461
 
        pData->size = nrects;
1462
 
        pData->numRects = pBox - (BoxPtr) (pData + 1);
1463
 
        pRgn->data = pData;
1464
 
        if (ctype != CT_YXBANDED)
1465
 
        {
1466
 
            Bool overlap; /* result ignored */
1467
 
            pRgn->extents.x1 = pRgn->extents.x2 = 0;
1468
 
            miRegionValidate(pRgn, &overlap);
1469
 
        }
1470
 
        else
1471
 
            miSetExtents(pRgn);
1472
 
        good(pRgn);
1473
 
    }
1474
 
    else
1475
 
    {
1476
 
        xfree (pData);
1477
 
    }
1478
 
    return pRgn;
1479
 
}
1480
 
 
1481
 
/*======================================================================
1482
 
 *                Region Subtraction
1483
 
 *====================================================================*/
1484
 
 
1485
 
 
1486
 
/*-
1487
 
 *-----------------------------------------------------------------------
1488
 
 * miSubtractO --
1489
 
 *      Overlapping band subtraction. x1 is the left-most point not yet
1490
 
 *      checked.
1491
 
 *
1492
 
 * Results:
1493
 
 *      TRUE if successful.
1494
 
 *
1495
 
 * Side Effects:
1496
 
 *      pReg may have rectangles added to it.
1497
 
 *
1498
 
 *-----------------------------------------------------------------------
1499
 
 */
1500
 
/*ARGSUSED*/
1501
 
 
1502
 
/*-
1503
 
 *-----------------------------------------------------------------------
1504
 
 * miSubtract --
1505
 
 *      Subtract regS from regM and leave the result in regD.
1506
 
 *      S stands for subtrahend, M for minuend and D for difference.
1507
 
 *
1508
 
 * Results:
1509
 
 *      TRUE if successful.
1510
 
 *
1511
 
 * Side Effects:
1512
 
 *      regD is overwritten.
1513
 
 *
1514
 
 *-----------------------------------------------------------------------
1515
 
 */
1516
 
Bool
1517
 
miSubtract(RegionPtr regD, RegionPtr regM, RegionPtr regS)
1518
 
{
1519
 
    return pixman_region_subtract (regD, regM, regS);
1520
 
}
1521
 
 
1522
 
/*======================================================================
1523
 
 *          Region Inversion
1524
 
 *====================================================================*/
1525
 
 
1526
 
/*-
1527
 
 *-----------------------------------------------------------------------
1528
 
 * miInverse --
1529
 
 *      Take a region and a box and return a region that is everything
1530
 
 *      in the box but not in the region. The careful reader will note
1531
 
 *      that this is the same as subtracting the region from the box...
1532
 
 *
1533
 
 * Results:
1534
 
 *      TRUE.
1535
 
 *
1536
 
 * Side Effects:
1537
 
 *      newReg is overwritten.
1538
 
 *
1539
 
 *-----------------------------------------------------------------------
1540
 
 */
1541
 
Bool
1542
 
miInverse(
1543
 
    RegionPtr     newReg,       /* Destination region */
1544
 
    RegionPtr     reg1,         /* Region to invert */
1545
 
    BoxPtr        invRect       /* Bounding box for inversion */
1546
 
    )
1547
 
{
1548
 
    return pixman_region_inverse (newReg, reg1, invRect);
1549
 
}
1550
 
int
1551
 
miRectIn(RegionPtr region, BoxPtr prect)
1552
 
{
1553
 
    return pixman_region_contains_rectangle (region, prect);
1554
 
}
1555
 
 
1556
 
/* TranslateRegion(pReg, x, y)
1557
 
   translates in place
1558
 
*/
1559
 
 
1560
 
void
1561
 
miTranslateRegion(RegionPtr pReg, int x, int y)
1562
 
{
1563
 
    pixman_region_translate (pReg, x, y);
1564
 
}
1565
 
 
1566
 
void
1567
 
miRegionReset(RegionPtr pReg, BoxPtr pBox)
1568
 
{
1569
 
    pixman_region_reset (pReg, pBox);
1570
 
}
1571
 
 
1572
 
Bool
1573
 
miPointInRegion(
1574
 
    RegionPtr pReg,
1575
 
    int x,
1576
 
    int y,
1577
 
    BoxPtr box      /* "return" value */
1578
 
    )
1579
 
{
1580
 
    return pixman_region_contains_point (pReg, x, y, box);
1581
 
}
1582
 
 
1583
 
Bool
1584
 
miRegionNotEmpty(RegionPtr pReg)
1585
 
{
1586
 
    return pixman_region_not_empty (pReg);
1587
 
}
1588
 
 
1589
 
Bool
1590
 
miRegionBroken(RegionPtr pReg)
1591
 
{
1592
 
    good(pReg);
1593
 
    return (REGION_NAR(pReg));
1594
 
}
1595
 
 
1596
 
void
1597
 
miRegionEmpty(RegionPtr pReg)
1598
 
{
1599
 
    good(pReg);
1600
 
    xfreeData(pReg);
1601
 
    pReg->extents.x2 = pReg->extents.x1;
1602
 
    pReg->extents.y2 = pReg->extents.y1;
1603
 
    pReg->data = &miEmptyData;
1604
 
}
1605
 
 
1606
 
BoxPtr
1607
 
miRegionExtents(RegionPtr pReg)
1608
 
{
1609
 
    good(pReg);
1610
 
    return(&pReg->extents);
1611
 
}
1612
 
 
1613
 
#define ExchangeSpans(a, b)                                 \
1614
 
{                                                           \
1615
 
    DDXPointRec tpt;                                        \
1616
 
    int         tw;                                         \
1617
 
                                                            \
1618
 
    tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt;    \
1619
 
    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
1620
 
}
1621
 
 
1622
 
/* ||| I should apply the merge sort code to rectangle sorting above, and see
1623
 
   if mapping time can be improved.  But right now I've been at work 12 hours,
1624
 
   so forget it.
1625
 
*/
1626
 
 
1627
 
static void QuickSortSpans(
1628
 
    DDXPointRec spans[],
1629
 
    int         widths[],
1630
 
    int         numSpans)
1631
 
{
1632
 
    int     y;
1633
 
    int     i, j, m;
1634
 
    DDXPointPtr    r;
1635
 
 
1636
 
    /* Always called with numSpans > 1 */
1637
 
    /* Sorts only by y, doesn't bother to sort by x */
1638
 
 
1639
 
    do
1640
 
    {
1641
 
        if (numSpans < 9)
1642
 
        {
1643
 
            /* Do insertion sort */
1644
 
            int yprev;
1645
 
 
1646
 
            yprev = spans[0].y;
1647
 
            i = 1;
1648
 
            do
1649
 
            { /* while i != numSpans */
1650
 
                y = spans[i].y;
1651
 
                if (yprev > y)
1652
 
                {
1653
 
                    /* spans[i] is out of order.  Move into proper location. */
1654
 
                    DDXPointRec tpt;
1655
 
                    int     tw, k;
1656
 
 
1657
 
                    for (j = 0; y >= spans[j].y; j++) {}
1658
 
                    tpt = spans[i];
1659
 
                    tw  = widths[i];
1660
 
                    for (k = i; k != j; k--)
1661
 
                    {
1662
 
                        spans[k] = spans[k-1];
1663
 
                        widths[k] = widths[k-1];
1664
 
                    }
1665
 
                    spans[j] = tpt;
1666
 
                    widths[j] = tw;
1667
 
                    y = spans[i].y;
1668
 
                } /* if out of order */
1669
 
                yprev = y;
1670
 
                i++;
1671
 
            } while (i != numSpans);
1672
 
            return;
1673
 
        }
1674
 
 
1675
 
        /* Choose partition element, stick in location 0 */
1676
 
        m = numSpans / 2;
1677
 
        if (spans[m].y > spans[0].y)            ExchangeSpans(m, 0);
1678
 
        if (spans[m].y > spans[numSpans-1].y)   ExchangeSpans(m, numSpans-1);
1679
 
        if (spans[m].y > spans[0].y)            ExchangeSpans(m, 0);
1680
 
        y = spans[0].y;
1681
 
 
1682
 
        /* Partition array */
1683
 
        i = 0;
1684
 
        j = numSpans;
1685
 
        do
1686
 
        {
1687
 
            r = &(spans[i]);
1688
 
            do
1689
 
            {
1690
 
                r++;
1691
 
                i++;
1692
 
            } while (i != numSpans && r->y < y);
1693
 
            r = &(spans[j]);
1694
 
            do
1695
 
            {
1696
 
                r--;
1697
 
                j--;
1698
 
            } while (y < r->y);
1699
 
            if (i < j)
1700
 
                ExchangeSpans(i, j);
1701
 
        } while (i < j);
1702
 
 
1703
 
        /* Move partition element back to middle */
1704
 
        ExchangeSpans(0, j);
1705
 
 
1706
 
        /* Recurse */
1707
 
        if (numSpans-j-1 > 1)
1708
 
            QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
1709
 
        numSpans = j;
1710
 
    } while (numSpans > 1);
1711
 
}
1712
 
 
1713
 
#define NextBand()                                                  \
1714
 
{                                                                   \
1715
 
    clipy1 = pboxBandStart->y1;                                     \
1716
 
    clipy2 = pboxBandStart->y2;                                     \
1717
 
    pboxBandEnd = pboxBandStart + 1;                                \
1718
 
    while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) {  \
1719
 
        pboxBandEnd++;                                              \
1720
 
    }                                                               \
1721
 
    for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
1722
 
}
1723
 
 
1724
 
/*
1725
 
    Clip a list of scanlines to a region.  The caller has allocated the
1726
 
    space.  FSorted is non-zero if the scanline origins are in ascending
1727
 
    order.
1728
 
    returns the number of new, clipped scanlines.
1729
 
*/
1730
 
 
1731
 
int
1732
 
miClipSpans(
1733
 
    RegionPtr   prgnDst,
1734
 
    DDXPointPtr ppt,
1735
 
    int         *pwidth,
1736
 
    int         nspans,
1737
 
    DDXPointPtr pptNew,
1738
 
    int         *pwidthNew,
1739
 
    int         fSorted)
1740
 
{
1741
 
    DDXPointPtr pptLast;
1742
 
    int *pwidthNewStart;        /* the vengeance of Xerox! */
1743
 
    int y, x1, x2;
1744
 
    int numRects;
1745
 
 
1746
 
    good(prgnDst);
1747
 
    pptLast = ppt + nspans;
1748
 
    pwidthNewStart = pwidthNew;
1749
 
 
1750
 
    if (!prgnDst->data)
1751
 
    {
1752
 
        /* Do special fast code with clip boundaries in registers(?) */
1753
 
        /* It doesn't pay much to make use of fSorted in this case, 
1754
 
           so we lump everything together. */
1755
 
 
1756
 
        int clipx1, clipx2, clipy1, clipy2;
1757
 
 
1758
 
        clipx1 = prgnDst->extents.x1;
1759
 
        clipy1 = prgnDst->extents.y1;
1760
 
        clipx2 = prgnDst->extents.x2;
1761
 
        clipy2 = prgnDst->extents.y2;
1762
 
            
1763
 
        for (; ppt != pptLast; ppt++, pwidth++)
1764
 
        {
1765
 
            y = ppt->y;
1766
 
            x1 = ppt->x;
1767
 
            if (clipy1 <= y && y < clipy2)
1768
 
            {
1769
 
                x2 = x1 + *pwidth;
1770
 
                if (x1 < clipx1)    x1 = clipx1;
1771
 
                if (x2 > clipx2)    x2 = clipx2;
1772
 
                if (x1 < x2)
1773
 
                {
1774
 
                    /* part of span in clip rectangle */
1775
 
                    pptNew->x = x1;
1776
 
                    pptNew->y = y;
1777
 
                    *pwidthNew = x2 - x1;
1778
 
                    pptNew++;
1779
 
                    pwidthNew++;
1780
 
                }
1781
 
            }
1782
 
        } /* end for */
1783
 
 
1784
 
    }
1785
 
    else if ((numRects = prgnDst->data->numRects))
1786
 
    {
1787
 
        /* Have to clip against many boxes */
1788
 
        BoxPtr pboxBandStart, pboxBandEnd;
1789
 
        BoxPtr pbox;
1790
 
        BoxPtr pboxLast;
1791
 
        int clipy1, clipy2;
1792
 
 
1793
 
        /* In this case, taking advantage of sorted spans gains more than
1794
 
           the sorting costs. */
1795
 
        if ((! fSorted) && (nspans > 1))
1796
 
            QuickSortSpans(ppt, pwidth, nspans);
1797
 
 
1798
 
        pboxBandStart = REGION_BOXPTR(prgnDst);
1799
 
        pboxLast = pboxBandStart + numRects;
1800
 
    
1801
 
        NextBand();
1802
 
 
1803
 
        for (; ppt != pptLast; )
1804
 
        {
1805
 
            y = ppt->y;
1806
 
            if (y < clipy2)
1807
 
            {
1808
 
                /* span is in the current band */
1809
 
                pbox = pboxBandStart;
1810
 
                x1 = ppt->x;
1811
 
                x2 = x1 + *pwidth;
1812
 
                do
1813
 
                { /* For each box in band */
1814
 
                    int newx1, newx2;
1815
 
 
1816
 
                    newx1 = x1;
1817
 
                    newx2 = x2;
1818
 
                    if (newx1 < pbox->x1)   newx1 = pbox->x1;
1819
 
                    if (newx2 > pbox->x2)   newx2 = pbox->x2;
1820
 
                    if (newx1 < newx2)
1821
 
                    {
1822
 
                        /* Part of span in clip rectangle */
1823
 
                        pptNew->x = newx1;
1824
 
                        pptNew->y = y;
1825
 
                        *pwidthNew = newx2 - newx1;
1826
 
                        pptNew++;
1827
 
                        pwidthNew++;
1828
 
                    }
1829
 
                    pbox++;
1830
 
                } while (pbox != pboxBandEnd);
1831
 
                ppt++;
1832
 
                pwidth++;
1833
 
            }
1834
 
            else
1835
 
            {
1836
 
                /* Move to next band, adjust ppt as needed */
1837
 
                pboxBandStart = pboxBandEnd;
1838
 
                if (pboxBandStart == pboxLast)
1839
 
                    break; /* We're completely done */
1840
 
                NextBand();
1841
 
            }
1842
 
        }
1843
 
    }
1844
 
    return (pwidthNew - pwidthNewStart);
1845
 
}