~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to mi/miregion.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86: xc/programs/Xserver/mi/miregion.c,v 1.9 2003/04/23 21:51:53 tsi Exp $ */
 
2
/***********************************************************
 
3
 
 
4
Copyright 1987, 1988, 1989, 1998  The Open Group
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included in
 
13
all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
18
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
19
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
20
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
21
 
 
22
Except as contained in this notice, the name of The Open Group shall not be
 
23
used in advertising or otherwise to promote the sale, use or other dealings
 
24
in this Software without prior written authorization from The Open Group.
 
25
 
 
26
 
 
27
Copyright 1987, 1988, 1989 by 
 
28
Digital Equipment Corporation, Maynard, Massachusetts. 
 
29
 
 
30
                        All Rights Reserved
 
31
 
 
32
Permission to use, copy, modify, and distribute this software and its 
 
33
documentation for any purpose and without fee is hereby granted, 
 
34
provided that the above copyright notice appear in all copies and that
 
35
both that copyright notice and this permission notice appear in 
 
36
supporting documentation, and that the name of Digital not be
 
37
used in advertising or publicity pertaining to distribution of the
 
38
software without specific, written prior permission.  
 
39
 
 
40
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 
41
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 
42
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 
43
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 
44
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
45
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 
46
SOFTWARE.
 
47
 
 
48
******************************************************************/
 
49
/* $Xorg: miregion.c,v 1.4 2001/02/09 02:05:21 xorgcvs Exp $ */
 
50
 
 
51
/* The panoramix components contained the following notice */
 
52
/*****************************************************************
 
53
 
 
54
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
 
55
 
 
56
Permission is hereby granted, free of charge, to any person obtaining a copy
 
57
of this software and associated documentation files (the "Software"), to deal
 
58
in the Software without restriction, including without limitation the rights
 
59
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
60
copies of the Software.
 
61
 
 
62
The above copyright notice and this permission notice shall be included in
 
63
all copies or substantial portions of the Software.
 
64
 
 
65
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
66
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
67
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
68
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
 
69
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
 
70
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
 
71
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
72
 
 
73
Except as contained in this notice, the name of Digital Equipment Corporation
 
74
shall not be used in advertising or otherwise to promote the sale, use or other
 
75
dealings in this Software without prior written authorization from Digital
 
76
Equipment Corporation.
 
77
 
 
78
******************************************************************/
 
79
 
 
80
#ifdef HAVE_DIX_CONFIG_H
 
81
#include <dix-config.h>
 
82
#endif
 
83
 
 
84
#include "regionstr.h"
 
85
#include <X11/Xprotostr.h>
 
86
#include "gc.h"
 
87
#include "mi.h"
 
88
#include "mispans.h"
 
89
 
 
90
#if defined (__GNUC__) && !defined (NO_INLINES)
 
91
#define INLINE  __inline
 
92
#else
 
93
#define INLINE
 
94
#endif
 
95
 
 
96
#undef assert
 
97
#ifdef DEBUG
 
98
#define assert(expr) {if (!(expr)) \
 
99
                FatalError("Assertion failed file %s, line %d: expr\n", \
 
100
                        __FILE__, __LINE__); }
 
101
#else
 
102
#define assert(expr)
 
103
#endif
 
104
 
 
105
#define good(reg) assert(miValidRegion(reg))
 
106
 
 
107
/*
 
108
 * The functions in this file implement the Region abstraction used extensively
 
109
 * throughout the X11 sample server. A Region is simply a set of disjoint
 
110
 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
 
111
 * smallest single rectangle that contains all the non-overlapping rectangles.
 
112
 *
 
113
 * A Region is implemented as a "y-x-banded" array of rectangles.  This array
 
114
 * imposes two degrees of order.  First, all rectangles are sorted by top side
 
115
 * y coordinate first (y1), and then by left side x coordinate (x1).
 
116
 *
 
117
 * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
 
118
 * band has the same top y coordinate (y1), and each has the same bottom y
 
119
 * coordinate (y2).  Thus all rectangles in a band differ only in their left
 
120
 * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
 
121
 * there is no separate list of band start pointers.
 
122
 *
 
123
 * The y-x band representation does not minimize rectangles.  In particular,
 
124
 * if a rectangle vertically crosses a band (the rectangle has scanlines in 
 
125
 * the y1 to y2 area spanned by the band), then the rectangle may be broken
 
126
 * down into two or more smaller rectangles stacked one atop the other. 
 
127
 *
 
128
 *  -----------                             -----------
 
129
 *  |         |                             |         |             band 0
 
130
 *  |         |  --------                   -----------  --------
 
131
 *  |         |  |      |  in y-x banded    |         |  |      |   band 1
 
132
 *  |         |  |      |  form is          |         |  |      |
 
133
 *  -----------  |      |                   -----------  --------
 
134
 *               |      |                                |      |   band 2
 
135
 *               --------                                --------
 
136
 *
 
137
 * An added constraint on the rectangles is that they must cover as much
 
138
 * horizontal area as possible: no two rectangles within a band are allowed
 
139
 * to touch.
 
140
 *
 
141
 * Whenever possible, bands will be merged together to cover a greater vertical
 
142
 * distance (and thus reduce the number of rectangles). Two bands can be merged
 
143
 * only if the bottom of one touches the top of the other and they have
 
144
 * rectangles in the same places (of the same width, of course).
 
145
 *
 
146
 * Adam de Boor wrote most of the original region code.  Joel McCormack
 
147
 * substantially modified or rewrote most of the core arithmetic routines,
 
148
 * and added miRegionValidate in order to support several speed improvements
 
149
 * to miValidateTree.  Bob Scheifler changed the representation to be more
 
150
 * compact when empty or a single rectangle, and did a bunch of gratuitous
 
151
 * reformatting.
 
152
 */
 
153
 
 
154
/*  true iff two Boxes overlap */
 
155
#define EXTENTCHECK(r1,r2) \
 
156
      (!( ((r1)->x2 <= (r2)->x1)  || \
 
157
          ((r1)->x1 >= (r2)->x2)  || \
 
158
          ((r1)->y2 <= (r2)->y1)  || \
 
159
          ((r1)->y1 >= (r2)->y2) ) )
 
160
 
 
161
/* true iff (x,y) is in Box */
 
162
#define INBOX(r,x,y) \
 
163
      ( ((r)->x2 >  x) && \
 
164
        ((r)->x1 <= x) && \
 
165
        ((r)->y2 >  y) && \
 
166
        ((r)->y1 <= y) )
 
167
 
 
168
/* true iff Box r1 contains Box r2 */
 
169
#define SUBSUMES(r1,r2) \
 
170
      ( ((r1)->x1 <= (r2)->x1) && \
 
171
        ((r1)->x2 >= (r2)->x2) && \
 
172
        ((r1)->y1 <= (r2)->y1) && \
 
173
        ((r1)->y2 >= (r2)->y2) )
 
174
 
 
175
#define xallocData(n) (RegDataPtr)xalloc(REGION_SZOF(n))
 
176
#define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data)
 
177
 
 
178
#define RECTALLOC_BAIL(pReg,n,bail) \
 
179
if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
 
180
    if (!miRectAlloc(pReg, n)) { goto bail; }
 
181
 
 
182
#define RECTALLOC(pReg,n) \
 
183
if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
 
184
    if (!miRectAlloc(pReg, n)) { return FALSE; }
 
185
 
 
186
#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)      \
 
187
{                                               \
 
188
    pNextRect->x1 = nx1;                        \
 
189
    pNextRect->y1 = ny1;                        \
 
190
    pNextRect->x2 = nx2;                        \
 
191
    pNextRect->y2 = ny2;                        \
 
192
    pNextRect++;                                \
 
193
}
 
194
 
 
195
#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)                 \
 
196
{                                                                       \
 
197
    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
 
198
    {                                                                   \
 
199
        if (!miRectAlloc(pReg, 1))                                      \
 
200
            return FALSE;                                               \
 
201
        pNextRect = REGION_TOP(pReg);                                   \
 
202
    }                                                                   \
 
203
    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);                                 \
 
204
    pReg->data->numRects++;                                             \
 
205
    assert(pReg->data->numRects<=pReg->data->size);                     \
 
206
}
 
207
 
 
208
 
 
209
#define DOWNSIZE(reg,numRects)                                           \
 
210
if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
 
211
{                                                                        \
 
212
    RegDataPtr NewData;                                                  \
 
213
    NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects));  \
 
214
    if (NewData)                                                         \
 
215
    {                                                                    \
 
216
        NewData->size = (numRects);                                      \
 
217
        (reg)->data = NewData;                                           \
 
218
    }                                                                    \
 
219
}
 
220
 
 
221
 
 
222
BoxRec miEmptyBox = {0, 0, 0, 0};
 
223
RegDataRec miEmptyData = {0, 0};
 
224
 
 
225
RegDataRec  miBrokenData = {0, 0};
 
226
RegionRec   miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData };
 
227
 
 
228
#ifdef DEBUG
 
229
int
 
230
miPrintRegion(rgn)
 
231
    RegionPtr rgn;
 
232
{
 
233
    int num, size;
 
234
    register int i;
 
235
    BoxPtr rects;
 
236
 
 
237
    num = REGION_NUM_RECTS(rgn);
 
238
    size = REGION_SIZE(rgn);
 
239
    rects = REGION_RECTS(rgn);
 
240
    ErrorF("num: %d size: %d\n", num, size);
 
241
    ErrorF("extents: %d %d %d %d\n",
 
242
           rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
 
243
    for (i = 0; i < num; i++)
 
244
      ErrorF("%d %d %d %d \n",
 
245
             rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
 
246
    ErrorF("\n");
 
247
    return(num);
 
248
}
 
249
#endif /* DEBUG */
 
250
 
 
251
Bool
 
252
miRegionEqual(reg1, reg2)
 
253
    RegionPtr reg1;
 
254
    RegionPtr reg2;
 
255
{
 
256
    int i, num;
 
257
    BoxPtr rects1, rects2;
 
258
 
 
259
    if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
 
260
    if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
 
261
    if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
 
262
    if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
 
263
 
 
264
    num = REGION_NUM_RECTS(reg1);
 
265
    if (num != REGION_NUM_RECTS(reg2)) return FALSE;
 
266
    
 
267
    rects1 = REGION_RECTS(reg1);
 
268
    rects2 = REGION_RECTS(reg2);
 
269
    for (i = 0; i != num; i++) {
 
270
        if (rects1[i].x1 != rects2[i].x1) return FALSE;
 
271
        if (rects1[i].x2 != rects2[i].x2) return FALSE;
 
272
        if (rects1[i].y1 != rects2[i].y1) return FALSE;
 
273
        if (rects1[i].y2 != rects2[i].y2) return FALSE;
 
274
    }
 
275
    return TRUE;
 
276
}
 
277
 
 
278
#ifdef DEBUG
 
279
Bool
 
280
miValidRegion(reg)
 
281
    RegionPtr reg;
 
282
{
 
283
    register int i, numRects;
 
284
 
 
285
    if ((reg->extents.x1 > reg->extents.x2) ||
 
286
        (reg->extents.y1 > reg->extents.y2))
 
287
        return FALSE;
 
288
    numRects = REGION_NUM_RECTS(reg);
 
289
    if (!numRects)
 
290
        return ((reg->extents.x1 == reg->extents.x2) &&
 
291
                (reg->extents.y1 == reg->extents.y2) &&
 
292
                (reg->data->size || (reg->data == &miEmptyData)));
 
293
    else if (numRects == 1)
 
294
        return (!reg->data);
 
295
    else
 
296
    {
 
297
        register BoxPtr pboxP, pboxN;
 
298
        BoxRec box;
 
299
 
 
300
        pboxP = REGION_RECTS(reg);
 
301
        box = *pboxP;
 
302
        box.y2 = pboxP[numRects-1].y2;
 
303
        pboxN = pboxP + 1;
 
304
        for (i = numRects; --i > 0; pboxP++, pboxN++)
 
305
        {
 
306
            if ((pboxN->x1 >= pboxN->x2) ||
 
307
                (pboxN->y1 >= pboxN->y2))
 
308
                return FALSE;
 
309
            if (pboxN->x1 < box.x1)
 
310
                box.x1 = pboxN->x1;
 
311
            if (pboxN->x2 > box.x2)
 
312
                box.x2 = pboxN->x2;
 
313
            if ((pboxN->y1 < pboxP->y1) ||
 
314
                ((pboxN->y1 == pboxP->y1) &&
 
315
                 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
 
316
                return FALSE;
 
317
        }
 
318
        return ((box.x1 == reg->extents.x1) &&
 
319
                (box.x2 == reg->extents.x2) &&
 
320
                (box.y1 == reg->extents.y1) &&
 
321
                (box.y2 == reg->extents.y2));
 
322
    }
 
323
}
 
324
 
 
325
#endif /* DEBUG */
 
326
 
 
327
 
 
328
/*****************************************************************
 
329
 *   RegionCreate(rect, size)
 
330
 *     This routine does a simple malloc to make a structure of
 
331
 *     REGION of "size" number of rectangles.
 
332
 *****************************************************************/
 
333
 
 
334
RegionPtr
 
335
miRegionCreate(rect, size)
 
336
    BoxPtr rect;
 
337
    int size;
 
338
{
 
339
    register RegionPtr pReg;
 
340
   
 
341
    pReg = (RegionPtr)xalloc(sizeof(RegionRec));
 
342
    if (!pReg)
 
343
        return &miBrokenRegion;
 
344
    if (rect)
 
345
    {
 
346
        pReg->extents = *rect;
 
347
        pReg->data = (RegDataPtr)NULL;
 
348
    }
 
349
    else
 
350
    {
 
351
        pReg->extents = miEmptyBox;
 
352
        if ((size > 1) && (pReg->data = xallocData(size)))
 
353
        {
 
354
            pReg->data->size = size;
 
355
            pReg->data->numRects = 0;
 
356
        }
 
357
        else
 
358
            pReg->data = &miEmptyData;
 
359
    }
 
360
    return(pReg);
 
361
}
 
362
 
 
363
/*****************************************************************
 
364
 *   RegionInit(pReg, rect, size)
 
365
 *     Outer region rect is statically allocated.
 
366
 *****************************************************************/
 
367
 
 
368
void
 
369
miRegionInit(pReg, rect, size)
 
370
    RegionPtr pReg;
 
371
    BoxPtr rect;
 
372
    int size;
 
373
{
 
374
    if (rect)
 
375
    {
 
376
        pReg->extents = *rect;
 
377
        pReg->data = (RegDataPtr)NULL;
 
378
    }
 
379
    else
 
380
    {
 
381
        pReg->extents = miEmptyBox;
 
382
        if ((size > 1) && (pReg->data = xallocData(size)))
 
383
        {
 
384
            pReg->data->size = size;
 
385
            pReg->data->numRects = 0;
 
386
        }
 
387
        else
 
388
            pReg->data = &miEmptyData;
 
389
    }
 
390
}
 
391
 
 
392
void
 
393
miRegionDestroy(pReg)
 
394
    RegionPtr pReg;
 
395
{
 
396
    good(pReg);
 
397
    xfreeData(pReg);
 
398
    if (pReg != &miBrokenRegion)
 
399
        xfree(pReg);
 
400
}
 
401
 
 
402
void
 
403
miRegionUninit(pReg)
 
404
    RegionPtr pReg;
 
405
{
 
406
    good(pReg);
 
407
    xfreeData(pReg);
 
408
}
 
409
 
 
410
Bool
 
411
miRegionBreak (pReg)
 
412
    RegionPtr pReg;
 
413
{
 
414
    xfreeData (pReg);
 
415
    pReg->extents = miEmptyBox;
 
416
    pReg->data = &miBrokenData;
 
417
    return FALSE;
 
418
}
 
419
 
 
420
Bool
 
421
miRectAlloc(
 
422
    register RegionPtr pRgn,
 
423
    int n)
 
424
{
 
425
    RegDataPtr  data;
 
426
    
 
427
    if (!pRgn->data)
 
428
    {
 
429
        n++;
 
430
        pRgn->data = xallocData(n);
 
431
        if (!pRgn->data)
 
432
            return miRegionBreak (pRgn);
 
433
        pRgn->data->numRects = 1;
 
434
        *REGION_BOXPTR(pRgn) = pRgn->extents;
 
435
    }
 
436
    else if (!pRgn->data->size)
 
437
    {
 
438
        pRgn->data = xallocData(n);
 
439
        if (!pRgn->data)
 
440
            return miRegionBreak (pRgn);
 
441
        pRgn->data->numRects = 0;
 
442
    }
 
443
    else
 
444
    {
 
445
        if (n == 1)
 
446
        {
 
447
            n = pRgn->data->numRects;
 
448
            if (n > 500) /* XXX pick numbers out of a hat */
 
449
                n = 250;
 
450
        }
 
451
        n += pRgn->data->numRects;
 
452
        data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n));
 
453
        if (!data)
 
454
            return miRegionBreak (pRgn);
 
455
        pRgn->data = data;
 
456
    }
 
457
    pRgn->data->size = n;
 
458
    return TRUE;
 
459
}
 
460
 
 
461
Bool
 
462
miRegionCopy(dst, src)
 
463
    register RegionPtr dst;
 
464
    register RegionPtr src;
 
465
{
 
466
    good(dst);
 
467
    good(src);
 
468
    if (dst == src)
 
469
        return TRUE;
 
470
    dst->extents = src->extents;
 
471
    if (!src->data || !src->data->size)
 
472
    {
 
473
        xfreeData(dst);
 
474
        dst->data = src->data;
 
475
        return TRUE;
 
476
    }
 
477
    if (!dst->data || (dst->data->size < src->data->numRects))
 
478
    {
 
479
        xfreeData(dst);
 
480
        dst->data = xallocData(src->data->numRects);
 
481
        if (!dst->data)
 
482
            return miRegionBreak (dst);
 
483
        dst->data->size = src->data->numRects;
 
484
    }
 
485
    dst->data->numRects = src->data->numRects;
 
486
    memmove((char *)REGION_BOXPTR(dst),(char *)REGION_BOXPTR(src), 
 
487
          dst->data->numRects * sizeof(BoxRec));
 
488
    return TRUE;
 
489
}
 
490
 
 
491
 
 
492
/*======================================================================
 
493
 *          Generic Region Operator
 
494
 *====================================================================*/
 
495
 
 
496
/*-
 
497
 *-----------------------------------------------------------------------
 
498
 * miCoalesce --
 
499
 *      Attempt to merge the boxes in the current band with those in the
 
500
 *      previous one.  We are guaranteed that the current band extends to
 
501
 *      the end of the rects array.  Used only by miRegionOp.
 
502
 *
 
503
 * Results:
 
504
 *      The new index for the previous band.
 
505
 *
 
506
 * Side Effects:
 
507
 *      If coalescing takes place:
 
508
 *          - rectangles in the previous band will have their y2 fields
 
509
 *            altered.
 
510
 *          - pReg->data->numRects will be decreased.
 
511
 *
 
512
 *-----------------------------------------------------------------------
 
513
 */
 
514
INLINE static int
 
515
miCoalesce (
 
516
    register RegionPtr  pReg,           /* Region to coalesce                */
 
517
    int                 prevStart,      /* Index of start of previous band   */
 
518
    int                 curStart)       /* Index of start of current band    */
 
519
{
 
520
    register BoxPtr     pPrevBox;       /* Current box in previous band      */
 
521
    register BoxPtr     pCurBox;        /* Current box in current band       */
 
522
    register int        numRects;       /* Number rectangles in both bands   */
 
523
    register int        y2;             /* Bottom of current band            */
 
524
    /*
 
525
     * Figure out how many rectangles are in the band.
 
526
     */
 
527
    numRects = curStart - prevStart;
 
528
    assert(numRects == pReg->data->numRects - curStart);
 
529
 
 
530
    if (!numRects) return curStart;
 
531
 
 
532
    /*
 
533
     * The bands may only be coalesced if the bottom of the previous
 
534
     * matches the top scanline of the current.
 
535
     */
 
536
    pPrevBox = REGION_BOX(pReg, prevStart);
 
537
    pCurBox = REGION_BOX(pReg, curStart);
 
538
    if (pPrevBox->y2 != pCurBox->y1) return curStart;
 
539
 
 
540
    /*
 
541
     * Make sure the bands have boxes in the same places. This
 
542
     * assumes that boxes have been added in such a way that they
 
543
     * cover the most area possible. I.e. two boxes in a band must
 
544
     * have some horizontal space between them.
 
545
     */
 
546
    y2 = pCurBox->y2;
 
547
 
 
548
    do {
 
549
        if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
 
550
            return (curStart);
 
551
        }
 
552
        pPrevBox++;
 
553
        pCurBox++;
 
554
        numRects--;
 
555
    } while (numRects);
 
556
 
 
557
    /*
 
558
     * The bands may be merged, so set the bottom y of each box
 
559
     * in the previous band to the bottom y of the current band.
 
560
     */
 
561
    numRects = curStart - prevStart;
 
562
    pReg->data->numRects -= numRects;
 
563
    do {
 
564
        pPrevBox--;
 
565
        pPrevBox->y2 = y2;
 
566
        numRects--;
 
567
    } while (numRects);
 
568
    return prevStart;
 
569
}
 
570
 
 
571
 
 
572
/* Quicky macro to avoid trivial reject procedure calls to miCoalesce */
 
573
 
 
574
#define Coalesce(newReg, prevBand, curBand)                             \
 
575
    if (curBand - prevBand == newReg->data->numRects - curBand) {       \
 
576
        prevBand = miCoalesce(newReg, prevBand, curBand);               \
 
577
    } else {                                                            \
 
578
        prevBand = curBand;                                             \
 
579
    }
 
580
 
 
581
/*-
 
582
 *-----------------------------------------------------------------------
 
583
 * miAppendNonO --
 
584
 *      Handle a non-overlapping band for the union and subtract operations.
 
585
 *      Just adds the (top/bottom-clipped) rectangles into the region.
 
586
 *      Doesn't have to check for subsumption or anything.
 
587
 *
 
588
 * Results:
 
589
 *      None.
 
590
 *
 
591
 * Side Effects:
 
592
 *      pReg->data->numRects is incremented and the rectangles overwritten
 
593
 *      with the rectangles we're passed.
 
594
 *
 
595
 *-----------------------------------------------------------------------
 
596
 */
 
597
 
 
598
INLINE static Bool
 
599
miAppendNonO (
 
600
    register RegionPtr  pReg,
 
601
    register BoxPtr     r,
 
602
    BoxPtr              rEnd,
 
603
    register int        y1,
 
604
    register int        y2)
 
605
{
 
606
    register BoxPtr     pNextRect;
 
607
    register int        newRects;
 
608
 
 
609
    newRects = rEnd - r;
 
610
 
 
611
    assert(y1 < y2);
 
612
    assert(newRects != 0);
 
613
 
 
614
    /* Make sure we have enough space for all rectangles to be added */
 
615
    RECTALLOC(pReg, newRects);
 
616
    pNextRect = REGION_TOP(pReg);
 
617
    pReg->data->numRects += newRects;
 
618
    do {
 
619
        assert(r->x1 < r->x2);
 
620
        ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
 
621
        r++;
 
622
    } while (r != rEnd);
 
623
 
 
624
    return TRUE;
 
625
}
 
626
 
 
627
#define FindBand(r, rBandEnd, rEnd, ry1)                    \
 
628
{                                                           \
 
629
    ry1 = r->y1;                                            \
 
630
    rBandEnd = r+1;                                         \
 
631
    while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
 
632
        rBandEnd++;                                         \
 
633
    }                                                       \
 
634
}
 
635
 
 
636
#define AppendRegions(newReg, r, rEnd)                                  \
 
637
{                                                                       \
 
638
    int newRects;                                                       \
 
639
    if ((newRects = rEnd - r)) {                                        \
 
640
        RECTALLOC(newReg, newRects);                                    \
 
641
        memmove((char *)REGION_TOP(newReg),(char *)r,                   \
 
642
              newRects * sizeof(BoxRec));                               \
 
643
        newReg->data->numRects += newRects;                             \
 
644
    }                                                                   \
 
645
}
 
646
 
 
647
/*-
 
648
 *-----------------------------------------------------------------------
 
649
 * miRegionOp --
 
650
 *      Apply an operation to two regions. Called by miUnion, miInverse,
 
651
 *      miSubtract, miIntersect....  Both regions MUST have at least one
 
652
 *      rectangle, and cannot be the same object.
 
653
 *
 
654
 * Results:
 
655
 *      TRUE if successful.
 
656
 *
 
657
 * Side Effects:
 
658
 *      The new region is overwritten.
 
659
 *      pOverlap set to TRUE if overlapFunc ever returns TRUE.
 
660
 *
 
661
 * Notes:
 
662
 *      The idea behind this function is to view the two regions as sets.
 
663
 *      Together they cover a rectangle of area that this function divides
 
664
 *      into horizontal bands where points are covered only by one region
 
665
 *      or by both. For the first case, the nonOverlapFunc is called with
 
666
 *      each the band and the band's upper and lower extents. For the
 
667
 *      second, the overlapFunc is called to process the entire band. It
 
668
 *      is responsible for clipping the rectangles in the band, though
 
669
 *      this function provides the boundaries.
 
670
 *      At the end of each band, the new region is coalesced, if possible,
 
671
 *      to reduce the number of rectangles in the region.
 
672
 *
 
673
 *-----------------------------------------------------------------------
 
674
 */
 
675
 
 
676
typedef Bool (*OverlapProcPtr)(
 
677
    RegionPtr   pReg,
 
678
    BoxPtr      r1,
 
679
    BoxPtr      r1End,
 
680
    BoxPtr      r2,
 
681
    BoxPtr      r2End,
 
682
    short       y1,
 
683
    short       y2,
 
684
    Bool        *pOverlap);
 
685
 
 
686
static Bool
 
687
miRegionOp(
 
688
    RegionPtr       newReg,                 /* Place to store result         */
 
689
    RegionPtr       reg1,                   /* First region in operation     */
 
690
    RegionPtr       reg2,                   /* 2d region in operation        */
 
691
    OverlapProcPtr  overlapFunc,            /* Function to call for over-
 
692
                                             * lapping bands                 */
 
693
    Bool            appendNon1,             /* Append non-overlapping bands  */
 
694
                                            /* in region 1 ? */
 
695
    Bool            appendNon2,             /* Append non-overlapping bands  */
 
696
                                            /* in region 2 ? */
 
697
    Bool            *pOverlap)
 
698
{
 
699
    register BoxPtr r1;                     /* Pointer into first region     */
 
700
    register BoxPtr r2;                     /* Pointer into 2d region        */
 
701
    BoxPtr          r1End;                  /* End of 1st region             */
 
702
    BoxPtr          r2End;                  /* End of 2d region              */
 
703
    short           ybot;                   /* Bottom of intersection        */
 
704
    short           ytop;                   /* Top of intersection           */
 
705
    RegDataPtr      oldData;                /* Old data for newReg           */
 
706
    int             prevBand;               /* Index of start of
 
707
                                             * previous band in newReg       */
 
708
    int             curBand;                /* Index of start of current
 
709
                                             * band in newReg                */
 
710
    register BoxPtr r1BandEnd;              /* End of current band in r1     */
 
711
    register BoxPtr r2BandEnd;              /* End of current band in r2     */
 
712
    short           top;                    /* Top of non-overlapping band   */
 
713
    short           bot;                    /* Bottom of non-overlapping band*/
 
714
    register int    r1y1;                   /* Temps for r1->y1 and r2->y1   */
 
715
    register int    r2y1;
 
716
    int             newSize;
 
717
    int             numRects;
 
718
 
 
719
    /*
 
720
     * Break any region computed from a broken region
 
721
     */
 
722
    if (REGION_NAR (reg1) || REGION_NAR(reg2))
 
723
        return miRegionBreak (newReg);
 
724
    
 
725
    /*
 
726
     * Initialization:
 
727
     *  set r1, r2, r1End and r2End appropriately, save the rectangles
 
728
     * of the destination region until the end in case it's one of
 
729
     * the two source regions, then mark the "new" region empty, allocating
 
730
     * another array of rectangles for it to use.
 
731
     */
 
732
 
 
733
    r1 = REGION_RECTS(reg1);
 
734
    newSize = REGION_NUM_RECTS(reg1);
 
735
    r1End = r1 + newSize;
 
736
    numRects = REGION_NUM_RECTS(reg2);
 
737
    r2 = REGION_RECTS(reg2);
 
738
    r2End = r2 + numRects;
 
739
    assert(r1 != r1End);
 
740
    assert(r2 != r2End);
 
741
 
 
742
    oldData = (RegDataPtr)NULL;
 
743
    if (((newReg == reg1) && (newSize > 1)) ||
 
744
        ((newReg == reg2) && (numRects > 1)))
 
745
    {
 
746
        oldData = newReg->data;
 
747
        newReg->data = &miEmptyData;
 
748
    }
 
749
    /* guess at new size */
 
750
    if (numRects > newSize)
 
751
        newSize = numRects;
 
752
    newSize <<= 1;
 
753
    if (!newReg->data)
 
754
        newReg->data = &miEmptyData;
 
755
    else if (newReg->data->size)
 
756
        newReg->data->numRects = 0;
 
757
    if (newSize > newReg->data->size)
 
758
        if (!miRectAlloc(newReg, newSize))
 
759
            return FALSE;
 
760
 
 
761
    /*
 
762
     * Initialize ybot.
 
763
     * In the upcoming loop, ybot and ytop serve different functions depending
 
764
     * on whether the band being handled is an overlapping or non-overlapping
 
765
     * band.
 
766
     *  In the case of a non-overlapping band (only one of the regions
 
767
     * has points in the band), ybot is the bottom of the most recent
 
768
     * intersection and thus clips the top of the rectangles in that band.
 
769
     * ytop is the top of the next intersection between the two regions and
 
770
     * serves to clip the bottom of the rectangles in the current band.
 
771
     *  For an overlapping band (where the two regions intersect), ytop clips
 
772
     * the top of the rectangles of both regions and ybot clips the bottoms.
 
773
     */
 
774
 
 
775
    ybot = min(r1->y1, r2->y1);
 
776
    
 
777
    /*
 
778
     * prevBand serves to mark the start of the previous band so rectangles
 
779
     * can be coalesced into larger rectangles. qv. miCoalesce, above.
 
780
     * In the beginning, there is no previous band, so prevBand == curBand
 
781
     * (curBand is set later on, of course, but the first band will always
 
782
     * start at index 0). prevBand and curBand must be indices because of
 
783
     * the possible expansion, and resultant moving, of the new region's
 
784
     * array of rectangles.
 
785
     */
 
786
    prevBand = 0;
 
787
    
 
788
    do {
 
789
        /*
 
790
         * This algorithm proceeds one source-band (as opposed to a
 
791
         * destination band, which is determined by where the two regions
 
792
         * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
 
793
         * rectangle after the last one in the current band for their
 
794
         * respective regions.
 
795
         */
 
796
        assert(r1 != r1End);
 
797
        assert(r2 != r2End);
 
798
    
 
799
        FindBand(r1, r1BandEnd, r1End, r1y1);
 
800
        FindBand(r2, r2BandEnd, r2End, r2y1);
 
801
 
 
802
        /*
 
803
         * First handle the band that doesn't intersect, if any.
 
804
         *
 
805
         * Note that attention is restricted to one band in the
 
806
         * non-intersecting region at once, so if a region has n
 
807
         * bands between the current position and the next place it overlaps
 
808
         * the other, this entire loop will be passed through n times.
 
809
         */
 
810
        if (r1y1 < r2y1) {
 
811
            if (appendNon1) {
 
812
                top = max(r1y1, ybot);
 
813
                bot = min(r1->y2, r2y1);
 
814
                if (top != bot) {
 
815
                    curBand = newReg->data->numRects;
 
816
                    miAppendNonO(newReg, r1, r1BandEnd, top, bot);
 
817
                    Coalesce(newReg, prevBand, curBand);
 
818
                }
 
819
            }
 
820
            ytop = r2y1;
 
821
        } else if (r2y1 < r1y1) {
 
822
            if (appendNon2) {
 
823
                top = max(r2y1, ybot);
 
824
                bot = min(r2->y2, r1y1);
 
825
                if (top != bot) {
 
826
                    curBand = newReg->data->numRects;
 
827
                    miAppendNonO(newReg, r2, r2BandEnd, top, bot);
 
828
                    Coalesce(newReg, prevBand, curBand);
 
829
                }
 
830
            }
 
831
            ytop = r1y1;
 
832
        } else {
 
833
            ytop = r1y1;
 
834
        }
 
835
 
 
836
        /*
 
837
         * Now see if we've hit an intersecting band. The two bands only
 
838
         * intersect if ybot > ytop
 
839
         */
 
840
        ybot = min(r1->y2, r2->y2);
 
841
        if (ybot > ytop) {
 
842
            curBand = newReg->data->numRects;
 
843
            (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
 
844
                            pOverlap);
 
845
            Coalesce(newReg, prevBand, curBand);
 
846
        }
 
847
 
 
848
        /*
 
849
         * If we've finished with a band (y2 == ybot) we skip forward
 
850
         * in the region to the next band.
 
851
         */
 
852
        if (r1->y2 == ybot) r1 = r1BandEnd;
 
853
        if (r2->y2 == ybot) r2 = r2BandEnd;
 
854
 
 
855
    } while (r1 != r1End && r2 != r2End);
 
856
 
 
857
    /*
 
858
     * Deal with whichever region (if any) still has rectangles left.
 
859
     *
 
860
     * We only need to worry about banding and coalescing for the very first
 
861
     * band left.  After that, we can just group all remaining boxes,
 
862
     * regardless of how many bands, into one final append to the list.
 
863
     */
 
864
 
 
865
    if ((r1 != r1End) && appendNon1) {
 
866
        /* Do first nonOverlap1Func call, which may be able to coalesce */
 
867
        FindBand(r1, r1BandEnd, r1End, r1y1);
 
868
        curBand = newReg->data->numRects;
 
869
        miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
 
870
        Coalesce(newReg, prevBand, curBand);
 
871
        /* Just append the rest of the boxes  */
 
872
        AppendRegions(newReg, r1BandEnd, r1End);
 
873
 
 
874
    } else if ((r2 != r2End) && appendNon2) {
 
875
        /* Do first nonOverlap2Func call, which may be able to coalesce */
 
876
        FindBand(r2, r2BandEnd, r2End, r2y1);
 
877
        curBand = newReg->data->numRects;
 
878
        miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
 
879
        Coalesce(newReg, prevBand, curBand);
 
880
        /* Append rest of boxes */
 
881
        AppendRegions(newReg, r2BandEnd, r2End);
 
882
    }
 
883
 
 
884
    if (oldData)
 
885
        xfree(oldData);
 
886
 
 
887
    if (!(numRects = newReg->data->numRects))
 
888
    {
 
889
        xfreeData(newReg);
 
890
        newReg->data = &miEmptyData;
 
891
    }
 
892
    else if (numRects == 1)
 
893
    {
 
894
        newReg->extents = *REGION_BOXPTR(newReg);
 
895
        xfreeData(newReg);
 
896
        newReg->data = (RegDataPtr)NULL;
 
897
    }
 
898
    else
 
899
    {
 
900
        DOWNSIZE(newReg, numRects);
 
901
    }
 
902
 
 
903
    return TRUE;
 
904
}
 
905
 
 
906
/*-
 
907
 *-----------------------------------------------------------------------
 
908
 * miSetExtents --
 
909
 *      Reset the extents of a region to what they should be. Called by
 
910
 *      miSubtract and miIntersect as they can't figure it out along the
 
911
 *      way or do so easily, as miUnion can.
 
912
 *
 
913
 * Results:
 
914
 *      None.
 
915
 *
 
916
 * Side Effects:
 
917
 *      The region's 'extents' structure is overwritten.
 
918
 *
 
919
 *-----------------------------------------------------------------------
 
920
 */
 
921
void
 
922
miSetExtents (pReg)
 
923
    register RegionPtr pReg;
 
924
{
 
925
    register BoxPtr pBox, pBoxEnd;
 
926
 
 
927
    if (!pReg->data)
 
928
        return;
 
929
    if (!pReg->data->size)
 
930
    {
 
931
        pReg->extents.x2 = pReg->extents.x1;
 
932
        pReg->extents.y2 = pReg->extents.y1;
 
933
        return;
 
934
    }
 
935
 
 
936
    pBox = REGION_BOXPTR(pReg);
 
937
    pBoxEnd = REGION_END(pReg);
 
938
 
 
939
    /*
 
940
     * Since pBox is the first rectangle in the region, it must have the
 
941
     * smallest y1 and since pBoxEnd is the last rectangle in the region,
 
942
     * it must have the largest y2, because of banding. Initialize x1 and
 
943
     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
 
944
     * to...
 
945
     */
 
946
    pReg->extents.x1 = pBox->x1;
 
947
    pReg->extents.y1 = pBox->y1;
 
948
    pReg->extents.x2 = pBoxEnd->x2;
 
949
    pReg->extents.y2 = pBoxEnd->y2;
 
950
 
 
951
    assert(pReg->extents.y1 < pReg->extents.y2);
 
952
    while (pBox <= pBoxEnd) {
 
953
        if (pBox->x1 < pReg->extents.x1)
 
954
            pReg->extents.x1 = pBox->x1;
 
955
        if (pBox->x2 > pReg->extents.x2)
 
956
            pReg->extents.x2 = pBox->x2;
 
957
        pBox++;
 
958
    };
 
959
 
 
960
    assert(pReg->extents.x1 < pReg->extents.x2);
 
961
}
 
962
 
 
963
/*======================================================================
 
964
 *          Region Intersection
 
965
 *====================================================================*/
 
966
/*-
 
967
 *-----------------------------------------------------------------------
 
968
 * miIntersectO --
 
969
 *      Handle an overlapping band for miIntersect.
 
970
 *
 
971
 * Results:
 
972
 *      TRUE if successful.
 
973
 *
 
974
 * Side Effects:
 
975
 *      Rectangles may be added to the region.
 
976
 *
 
977
 *-----------------------------------------------------------------------
 
978
 */
 
979
/*ARGSUSED*/
 
980
static Bool
 
981
miIntersectO (
 
982
    register RegionPtr  pReg,
 
983
    register BoxPtr     r1,
 
984
    BoxPtr              r1End,
 
985
    register BoxPtr     r2,
 
986
    BoxPtr              r2End,
 
987
    short               y1,
 
988
    short               y2,
 
989
    Bool                *pOverlap)
 
990
{
 
991
    register int        x1;
 
992
    register int        x2;
 
993
    register BoxPtr     pNextRect;
 
994
 
 
995
    pNextRect = REGION_TOP(pReg);
 
996
 
 
997
    assert(y1 < y2);
 
998
    assert(r1 != r1End && r2 != r2End);
 
999
 
 
1000
    do {
 
1001
        x1 = max(r1->x1, r2->x1);
 
1002
        x2 = min(r1->x2, r2->x2);
 
1003
 
 
1004
        /*
 
1005
         * If there's any overlap between the two rectangles, add that
 
1006
         * overlap to the new region.
 
1007
         */
 
1008
        if (x1 < x2)
 
1009
            NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
 
1010
 
 
1011
        /*
 
1012
         * Advance the pointer(s) with the leftmost right side, since the next
 
1013
         * rectangle on that list may still overlap the other region's
 
1014
         * current rectangle.
 
1015
         */
 
1016
        if (r1->x2 == x2) {
 
1017
            r1++;
 
1018
        }
 
1019
        if (r2->x2 == x2) {
 
1020
            r2++;
 
1021
        }
 
1022
    } while ((r1 != r1End) && (r2 != r2End));
 
1023
 
 
1024
    return TRUE;
 
1025
}
 
1026
 
 
1027
 
 
1028
Bool
 
1029
miIntersect(newReg, reg1, reg2)
 
1030
    register RegionPtr  newReg;     /* destination Region */
 
1031
    register RegionPtr  reg1;
 
1032
    register RegionPtr  reg2;       /* source regions     */
 
1033
{
 
1034
    good(reg1);
 
1035
    good(reg2);
 
1036
    good(newReg);
 
1037
   /* check for trivial reject */
 
1038
    if (REGION_NIL(reg1)  || REGION_NIL(reg2) ||
 
1039
        !EXTENTCHECK(&reg1->extents, &reg2->extents))
 
1040
    {
 
1041
        /* Covers about 20% of all cases */
 
1042
        xfreeData(newReg);
 
1043
        newReg->extents.x2 = newReg->extents.x1;
 
1044
        newReg->extents.y2 = newReg->extents.y1;
 
1045
        if (REGION_NAR(reg1) || REGION_NAR(reg2))
 
1046
        {
 
1047
            newReg->data = &miBrokenData;
 
1048
            return FALSE;
 
1049
        }
 
1050
        else
 
1051
            newReg->data = &miEmptyData;
 
1052
    }
 
1053
    else if (!reg1->data && !reg2->data)
 
1054
    {
 
1055
        /* Covers about 80% of cases that aren't trivially rejected */
 
1056
        newReg->extents.x1 = max(reg1->extents.x1, reg2->extents.x1);
 
1057
        newReg->extents.y1 = max(reg1->extents.y1, reg2->extents.y1);
 
1058
        newReg->extents.x2 = min(reg1->extents.x2, reg2->extents.x2);
 
1059
        newReg->extents.y2 = min(reg1->extents.y2, reg2->extents.y2);
 
1060
        xfreeData(newReg);
 
1061
        newReg->data = (RegDataPtr)NULL;
 
1062
    }
 
1063
    else if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
 
1064
    {
 
1065
        return miRegionCopy(newReg, reg1);
 
1066
    }
 
1067
    else if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
 
1068
    {
 
1069
        return miRegionCopy(newReg, reg2);
 
1070
    }
 
1071
    else if (reg1 == reg2)
 
1072
    {
 
1073
        return miRegionCopy(newReg, reg1);
 
1074
    }
 
1075
    else
 
1076
    {
 
1077
        /* General purpose intersection */
 
1078
        Bool overlap; /* result ignored */
 
1079
        if (!miRegionOp(newReg, reg1, reg2, miIntersectO, FALSE, FALSE,
 
1080
                        &overlap))
 
1081
            return FALSE;
 
1082
        miSetExtents(newReg);
 
1083
    }
 
1084
 
 
1085
    good(newReg);
 
1086
    return(TRUE);
 
1087
}
 
1088
 
 
1089
#define MERGERECT(r)                                            \
 
1090
{                                                               \
 
1091
    if (r->x1 <= x2) {                                          \
 
1092
        /* Merge with current rectangle */                      \
 
1093
        if (r->x1 < x2) *pOverlap = TRUE;                               \
 
1094
        if (x2 < r->x2) x2 = r->x2;                             \
 
1095
    } else {                                                    \
 
1096
        /* Add current rectangle, start new one */              \
 
1097
        NEWRECT(pReg, pNextRect, x1, y1, x2, y2);               \
 
1098
        x1 = r->x1;                                             \
 
1099
        x2 = r->x2;                                             \
 
1100
    }                                                           \
 
1101
    r++;                                                        \
 
1102
}
 
1103
 
 
1104
/*======================================================================
 
1105
 *          Region Union
 
1106
 *====================================================================*/
 
1107
 
 
1108
/*-
 
1109
 *-----------------------------------------------------------------------
 
1110
 * miUnionO --
 
1111
 *      Handle an overlapping band for the union operation. Picks the
 
1112
 *      left-most rectangle each time and merges it into the region.
 
1113
 *
 
1114
 * Results:
 
1115
 *      TRUE if successful.
 
1116
 *
 
1117
 * Side Effects:
 
1118
 *      pReg is overwritten.
 
1119
 *      pOverlap is set to TRUE if any boxes overlap.
 
1120
 *
 
1121
 *-----------------------------------------------------------------------
 
1122
 */
 
1123
static Bool
 
1124
miUnionO (
 
1125
    register RegionPtr  pReg,
 
1126
    register BoxPtr     r1,
 
1127
             BoxPtr     r1End,
 
1128
    register BoxPtr     r2,
 
1129
             BoxPtr     r2End,
 
1130
             short      y1,
 
1131
             short      y2,
 
1132
             Bool       *pOverlap)
 
1133
{
 
1134
    register BoxPtr     pNextRect;
 
1135
    register int        x1;     /* left and right side of current union */
 
1136
    register int        x2;
 
1137
 
 
1138
    assert (y1 < y2);
 
1139
    assert(r1 != r1End && r2 != r2End);
 
1140
 
 
1141
    pNextRect = REGION_TOP(pReg);
 
1142
 
 
1143
    /* Start off current rectangle */
 
1144
    if (r1->x1 < r2->x1)
 
1145
    {
 
1146
        x1 = r1->x1;
 
1147
        x2 = r1->x2;
 
1148
        r1++;
 
1149
    }
 
1150
    else
 
1151
    {
 
1152
        x1 = r2->x1;
 
1153
        x2 = r2->x2;
 
1154
        r2++;
 
1155
    }
 
1156
    while (r1 != r1End && r2 != r2End)
 
1157
    {
 
1158
        if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
 
1159
    }
 
1160
 
 
1161
    /* Finish off whoever (if any) is left */
 
1162
    if (r1 != r1End)
 
1163
    {
 
1164
        do
 
1165
        {
 
1166
            MERGERECT(r1);
 
1167
        } while (r1 != r1End);
 
1168
    }
 
1169
    else if (r2 != r2End)
 
1170
    {
 
1171
        do
 
1172
        {
 
1173
            MERGERECT(r2);
 
1174
        } while (r2 != r2End);
 
1175
    }
 
1176
    
 
1177
    /* Add current rectangle */
 
1178
    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
 
1179
 
 
1180
    return TRUE;
 
1181
}
 
1182
 
 
1183
Bool 
 
1184
miUnion(newReg, reg1, reg2)
 
1185
    RegionPtr           newReg;                  /* destination Region */
 
1186
    register RegionPtr  reg1;
 
1187
    register RegionPtr  reg2;             /* source regions     */
 
1188
{
 
1189
    Bool overlap; /* result ignored */
 
1190
 
 
1191
    /* Return TRUE if some overlap between reg1, reg2 */
 
1192
    good(reg1);
 
1193
    good(reg2);
 
1194
    good(newReg);
 
1195
    /*  checks all the simple cases */
 
1196
 
 
1197
    /*
 
1198
     * Region 1 and 2 are the same
 
1199
     */
 
1200
    if (reg1 == reg2)
 
1201
    {
 
1202
        return miRegionCopy(newReg, reg1);
 
1203
    }
 
1204
 
 
1205
    /*
 
1206
     * Region 1 is empty
 
1207
     */
 
1208
    if (REGION_NIL(reg1))
 
1209
    {
 
1210
        if (REGION_NAR(reg1))
 
1211
            return miRegionBreak (newReg);
 
1212
        if (newReg != reg2)
 
1213
            return miRegionCopy(newReg, reg2);
 
1214
        return TRUE;
 
1215
    }
 
1216
 
 
1217
    /*
 
1218
     * Region 2 is empty
 
1219
     */
 
1220
    if (REGION_NIL(reg2))
 
1221
    {
 
1222
        if (REGION_NAR(reg2))
 
1223
            return miRegionBreak (newReg);
 
1224
        if (newReg != reg1)
 
1225
            return miRegionCopy(newReg, reg1);
 
1226
        return TRUE;
 
1227
    }
 
1228
 
 
1229
    /*
 
1230
     * Region 1 completely subsumes region 2
 
1231
     */
 
1232
    if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
 
1233
    {
 
1234
        if (newReg != reg1)
 
1235
            return miRegionCopy(newReg, reg1);
 
1236
        return TRUE;
 
1237
    }
 
1238
 
 
1239
    /*
 
1240
     * Region 2 completely subsumes region 1
 
1241
     */
 
1242
    if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
 
1243
    {
 
1244
        if (newReg != reg2)
 
1245
            return miRegionCopy(newReg, reg2);
 
1246
        return TRUE;
 
1247
    }
 
1248
 
 
1249
    if (!miRegionOp(newReg, reg1, reg2, miUnionO, TRUE, TRUE, &overlap))
 
1250
        return FALSE;
 
1251
 
 
1252
    newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
 
1253
    newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
 
1254
    newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
 
1255
    newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
 
1256
    good(newReg);
 
1257
    return TRUE;
 
1258
}
 
1259
 
 
1260
 
 
1261
/*======================================================================
 
1262
 *          Batch Rectangle Union
 
1263
 *====================================================================*/
 
1264
 
 
1265
/*-
 
1266
 *-----------------------------------------------------------------------
 
1267
 * miRegionAppend --
 
1268
 * 
 
1269
 *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
 
1270
 *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
 
1271
 *      becomes a non-y-x-banded random collection of rectangles, and not
 
1272
 *      yet a true region.  After a sequence of appends, the caller must
 
1273
 *      call miRegionValidate to ensure that a valid region is constructed.
 
1274
 *
 
1275
 * Results:
 
1276
 *      TRUE if successful.
 
1277
 *
 
1278
 * Side Effects:
 
1279
 *      dstrgn is modified if rgn has rectangles.
 
1280
 *
 
1281
 */
 
1282
Bool
 
1283
miRegionAppend(dstrgn, rgn)
 
1284
    register RegionPtr dstrgn;
 
1285
    register RegionPtr rgn;
 
1286
{
 
1287
    int numRects, dnumRects, size;
 
1288
    BoxPtr new, old;
 
1289
    Bool prepend;
 
1290
 
 
1291
    if (REGION_NAR(rgn))
 
1292
        return miRegionBreak (dstrgn);
 
1293
    
 
1294
    if (!rgn->data && (dstrgn->data == &miEmptyData))
 
1295
    {
 
1296
        dstrgn->extents = rgn->extents;
 
1297
        dstrgn->data = (RegDataPtr)NULL;
 
1298
        return TRUE;
 
1299
    }
 
1300
 
 
1301
    numRects = REGION_NUM_RECTS(rgn);
 
1302
    if (!numRects)
 
1303
        return TRUE;
 
1304
    prepend = FALSE;
 
1305
    size = numRects;
 
1306
    dnumRects = REGION_NUM_RECTS(dstrgn);
 
1307
    if (!dnumRects && (size < 200))
 
1308
        size = 200; /* XXX pick numbers out of a hat */
 
1309
    RECTALLOC(dstrgn, size);
 
1310
    old = REGION_RECTS(rgn);
 
1311
    if (!dnumRects)
 
1312
        dstrgn->extents = rgn->extents;
 
1313
    else if (dstrgn->extents.x2 > dstrgn->extents.x1)
 
1314
    {
 
1315
        register BoxPtr first, last;
 
1316
 
 
1317
        first = old;
 
1318
        last = REGION_BOXPTR(dstrgn) + (dnumRects - 1);
 
1319
        if ((first->y1 > last->y2) ||
 
1320
            ((first->y1 == last->y1) && (first->y2 == last->y2) &&
 
1321
             (first->x1 > last->x2)))
 
1322
        {
 
1323
            if (rgn->extents.x1 < dstrgn->extents.x1)
 
1324
                dstrgn->extents.x1 = rgn->extents.x1;
 
1325
            if (rgn->extents.x2 > dstrgn->extents.x2)
 
1326
                dstrgn->extents.x2 = rgn->extents.x2;
 
1327
            dstrgn->extents.y2 = rgn->extents.y2;
 
1328
        }
 
1329
        else
 
1330
        {
 
1331
            first = REGION_BOXPTR(dstrgn);
 
1332
            last = old + (numRects - 1);
 
1333
            if ((first->y1 > last->y2) ||
 
1334
                ((first->y1 == last->y1) && (first->y2 == last->y2) &&
 
1335
                 (first->x1 > last->x2)))
 
1336
            {
 
1337
                prepend = TRUE;
 
1338
                if (rgn->extents.x1 < dstrgn->extents.x1)
 
1339
                    dstrgn->extents.x1 = rgn->extents.x1;
 
1340
                if (rgn->extents.x2 > dstrgn->extents.x2)
 
1341
                    dstrgn->extents.x2 = rgn->extents.x2;
 
1342
                dstrgn->extents.y1 = rgn->extents.y1;
 
1343
            }
 
1344
            else
 
1345
                dstrgn->extents.x2 = dstrgn->extents.x1;
 
1346
        }
 
1347
    }
 
1348
    if (prepend)
 
1349
    {
 
1350
        new = REGION_BOX(dstrgn, numRects);
 
1351
        if (dnumRects == 1)
 
1352
            *new = *REGION_BOXPTR(dstrgn);
 
1353
        else
 
1354
            memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), 
 
1355
                  dnumRects * sizeof(BoxRec));
 
1356
        new = REGION_BOXPTR(dstrgn);
 
1357
    }
 
1358
    else
 
1359
        new = REGION_BOXPTR(dstrgn) + dnumRects;
 
1360
    if (numRects == 1)
 
1361
        *new = *old;
 
1362
    else
 
1363
        memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
 
1364
    dstrgn->data->numRects += numRects;
 
1365
    return TRUE;
 
1366
}
 
1367
 
 
1368
   
 
1369
#define ExchangeRects(a, b) \
 
1370
{                           \
 
1371
    BoxRec     t;           \
 
1372
    t = rects[a];           \
 
1373
    rects[a] = rects[b];    \
 
1374
    rects[b] = t;           \
 
1375
}
 
1376
 
 
1377
static void
 
1378
QuickSortRects(
 
1379
    register BoxRec     rects[],
 
1380
    register int        numRects)
 
1381
{
 
1382
    register int        y1;
 
1383
    register int        x1;
 
1384
    register int        i, j;
 
1385
    register BoxPtr     r;
 
1386
 
 
1387
    /* Always called with numRects > 1 */
 
1388
 
 
1389
    do
 
1390
    {
 
1391
        if (numRects == 2)
 
1392
        {
 
1393
            if (rects[0].y1 > rects[1].y1 ||
 
1394
                    (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
 
1395
                ExchangeRects(0, 1);
 
1396
            return;
 
1397
        }
 
1398
 
 
1399
        /* Choose partition element, stick in location 0 */
 
1400
        ExchangeRects(0, numRects >> 1);
 
1401
        y1 = rects[0].y1;
 
1402
        x1 = rects[0].x1;
 
1403
 
 
1404
        /* Partition array */
 
1405
        i = 0;
 
1406
        j = numRects;
 
1407
        do
 
1408
        {
 
1409
            r = &(rects[i]);
 
1410
            do
 
1411
            {
 
1412
                r++;
 
1413
                i++;
 
1414
            } while (i != numRects &&
 
1415
                     (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
 
1416
            r = &(rects[j]);
 
1417
            do
 
1418
            {
 
1419
                r--;
 
1420
                j--;
 
1421
            } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
 
1422
            if (i < j)
 
1423
                ExchangeRects(i, j);
 
1424
        } while (i < j);
 
1425
 
 
1426
        /* Move partition element back to middle */
 
1427
        ExchangeRects(0, j);
 
1428
 
 
1429
        /* Recurse */
 
1430
        if (numRects-j-1 > 1)
 
1431
            QuickSortRects(&rects[j+1], numRects-j-1);
 
1432
        numRects = j;
 
1433
    } while (numRects > 1);
 
1434
}
 
1435
 
 
1436
/*-
 
1437
 *-----------------------------------------------------------------------
 
1438
 * miRegionValidate --
 
1439
 * 
 
1440
 *      Take a ``region'' which is a non-y-x-banded random collection of
 
1441
 *      rectangles, and compute a nice region which is the union of all the
 
1442
 *      rectangles.
 
1443
 *
 
1444
 * Results:
 
1445
 *      TRUE if successful.
 
1446
 *
 
1447
 * Side Effects:
 
1448
 *      The passed-in ``region'' may be modified.
 
1449
 *      pOverlap set to TRUE if any retangles overlapped, else FALSE;
 
1450
 *
 
1451
 * Strategy:
 
1452
 *      Step 1. Sort the rectangles into ascending order with primary key y1
 
1453
 *              and secondary key x1.
 
1454
 *
 
1455
 *      Step 2. Split the rectangles into the minimum number of proper y-x
 
1456
 *              banded regions.  This may require horizontally merging
 
1457
 *              rectangles, and vertically coalescing bands.  With any luck,
 
1458
 *              this step in an identity tranformation (ala the Box widget),
 
1459
 *              or a coalescing into 1 box (ala Menus).
 
1460
 *
 
1461
 *      Step 3. Merge the separate regions down to a single region by calling
 
1462
 *              miUnion.  Maximize the work each miUnion call does by using
 
1463
 *              a binary merge.
 
1464
 *
 
1465
 *-----------------------------------------------------------------------
 
1466
 */
 
1467
 
 
1468
Bool
 
1469
miRegionValidate(badreg, pOverlap)
 
1470
    RegionPtr badreg;
 
1471
    Bool *pOverlap;
 
1472
{
 
1473
    /* Descriptor for regions under construction  in Step 2. */
 
1474
    typedef struct {
 
1475
        RegionRec   reg;
 
1476
        int         prevBand;
 
1477
        int         curBand;
 
1478
    } RegionInfo;
 
1479
 
 
1480
             int        numRects;   /* Original numRects for badreg         */
 
1481
             RegionInfo *ri;        /* Array of current regions             */
 
1482
             int        numRI;      /* Number of entries used in ri         */
 
1483
             int        sizeRI;     /* Number of entries available in ri    */
 
1484
             int        i;          /* Index into rects                     */
 
1485
    register int        j;          /* Index into ri                        */
 
1486
    register RegionInfo *rit;       /* &ri[j]                               */
 
1487
    register RegionPtr  reg;        /* ri[j].reg                            */
 
1488
    register BoxPtr     box;        /* Current box in rects                 */
 
1489
    register BoxPtr     riBox;      /* Last box in ri[j].reg                */
 
1490
    register RegionPtr  hreg;       /* ri[j_half].reg                       */
 
1491
    Bool                ret = TRUE;
 
1492
 
 
1493
    *pOverlap = FALSE;
 
1494
    if (!badreg->data)
 
1495
    {
 
1496
        good(badreg);
 
1497
        return TRUE;
 
1498
    }
 
1499
    numRects = badreg->data->numRects;
 
1500
    if (!numRects)
 
1501
    {
 
1502
        if (REGION_NAR(badreg))
 
1503
            return FALSE;
 
1504
        good(badreg);
 
1505
        return TRUE;
 
1506
    }
 
1507
    if (badreg->extents.x1 < badreg->extents.x2)
 
1508
    {
 
1509
        if ((numRects) == 1)
 
1510
        {
 
1511
            xfreeData(badreg);
 
1512
            badreg->data = (RegDataPtr) NULL;
 
1513
        }
 
1514
        else
 
1515
        {
 
1516
            DOWNSIZE(badreg, numRects);
 
1517
        }
 
1518
        good(badreg);
 
1519
        return TRUE;
 
1520
    }
 
1521
 
 
1522
    /* Step 1: Sort the rects array into ascending (y1, x1) order */
 
1523
    QuickSortRects(REGION_BOXPTR(badreg), numRects);
 
1524
 
 
1525
    /* Step 2: Scatter the sorted array into the minimum number of regions */
 
1526
 
 
1527
    /* Set up the first region to be the first rectangle in badreg */
 
1528
    /* Note that step 2 code will never overflow the ri[0].reg rects array */
 
1529
    ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo));
 
1530
    if (!ri)
 
1531
        return miRegionBreak (badreg);
 
1532
    sizeRI = 4;
 
1533
    numRI = 1;
 
1534
    ri[0].prevBand = 0;
 
1535
    ri[0].curBand = 0;
 
1536
    ri[0].reg = *badreg;
 
1537
    box = REGION_BOXPTR(&ri[0].reg);
 
1538
    ri[0].reg.extents = *box;
 
1539
    ri[0].reg.data->numRects = 1;
 
1540
 
 
1541
    /* Now scatter rectangles into the minimum set of valid regions.  If the
 
1542
       next rectangle to be added to a region would force an existing rectangle
 
1543
       in the region to be split up in order to maintain y-x banding, just
 
1544
       forget it.  Try the next region.  If it doesn't fit cleanly into any
 
1545
       region, make a new one. */
 
1546
 
 
1547
    for (i = numRects; --i > 0;)
 
1548
    {
 
1549
        box++;
 
1550
        /* Look for a region to append box to */
 
1551
        for (j = numRI, rit = ri; --j >= 0; rit++)
 
1552
        {
 
1553
            reg = &rit->reg;
 
1554
            riBox = REGION_END(reg);
 
1555
 
 
1556
            if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
 
1557
            {
 
1558
                /* box is in same band as riBox.  Merge or append it */
 
1559
                if (box->x1 <= riBox->x2)
 
1560
                {
 
1561
                    /* Merge it with riBox */
 
1562
                    if (box->x1 < riBox->x2) *pOverlap = TRUE;
 
1563
                    if (box->x2 > riBox->x2) riBox->x2 = box->x2;
 
1564
                }
 
1565
                else
 
1566
                {
 
1567
                    RECTALLOC_BAIL(reg, 1, bail);
 
1568
                    *REGION_TOP(reg) = *box;
 
1569
                    reg->data->numRects++;
 
1570
                }
 
1571
                goto NextRect;   /* So sue me */
 
1572
            }
 
1573
            else if (box->y1 >= riBox->y2)
 
1574
            {
 
1575
                /* Put box into new band */
 
1576
                if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
 
1577
                if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
 
1578
                Coalesce(reg, rit->prevBand, rit->curBand);
 
1579
                rit->curBand = reg->data->numRects;
 
1580
                RECTALLOC_BAIL(reg, 1, bail);
 
1581
                *REGION_TOP(reg) = *box;
 
1582
                reg->data->numRects++;
 
1583
                goto NextRect;
 
1584
            }
 
1585
            /* Well, this region was inappropriate.  Try the next one. */
 
1586
        } /* for j */
 
1587
 
 
1588
        /* Uh-oh.  No regions were appropriate.  Create a new one. */
 
1589
        if (sizeRI == numRI)
 
1590
        {
 
1591
            /* Oops, allocate space for new region information */
 
1592
            sizeRI <<= 1;
 
1593
            rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo));
 
1594
            if (!rit)
 
1595
                goto bail;
 
1596
            ri = rit;
 
1597
            rit = &ri[numRI];
 
1598
        }
 
1599
        numRI++;
 
1600
        rit->prevBand = 0;
 
1601
        rit->curBand = 0;
 
1602
        rit->reg.extents = *box;
 
1603
        rit->reg.data = (RegDataPtr)NULL;
 
1604
        if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
 
1605
            goto bail;
 
1606
NextRect: ;
 
1607
    } /* for i */
 
1608
 
 
1609
    /* Make a final pass over each region in order to Coalesce and set
 
1610
       extents.x2 and extents.y2 */
 
1611
 
 
1612
    for (j = numRI, rit = ri; --j >= 0; rit++)
 
1613
    {
 
1614
        reg = &rit->reg;
 
1615
        riBox = REGION_END(reg);
 
1616
        reg->extents.y2 = riBox->y2;
 
1617
        if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
 
1618
        Coalesce(reg, rit->prevBand, rit->curBand);
 
1619
        if (reg->data->numRects == 1) /* keep unions happy below */
 
1620
        {
 
1621
            xfreeData(reg);
 
1622
            reg->data = (RegDataPtr)NULL;
 
1623
        }
 
1624
    }
 
1625
 
 
1626
    /* Step 3: Union all regions into a single region */
 
1627
    while (numRI > 1)
 
1628
    {
 
1629
        int half = numRI/2;
 
1630
        for (j = numRI & 1; j < (half + (numRI & 1)); j++)
 
1631
        {
 
1632
            reg = &ri[j].reg;
 
1633
            hreg = &ri[j+half].reg;
 
1634
            if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap))
 
1635
                ret = FALSE;
 
1636
            if (hreg->extents.x1 < reg->extents.x1)
 
1637
                reg->extents.x1 = hreg->extents.x1;
 
1638
            if (hreg->extents.y1 < reg->extents.y1)
 
1639
                reg->extents.y1 = hreg->extents.y1;
 
1640
            if (hreg->extents.x2 > reg->extents.x2)
 
1641
                reg->extents.x2 = hreg->extents.x2;
 
1642
            if (hreg->extents.y2 > reg->extents.y2)
 
1643
                reg->extents.y2 = hreg->extents.y2;
 
1644
            xfreeData(hreg);
 
1645
        }
 
1646
        numRI -= half;
 
1647
    }
 
1648
    *badreg = ri[0].reg;
 
1649
    xfree(ri);
 
1650
    good(badreg);
 
1651
    return ret;
 
1652
bail:
 
1653
    for (i = 0; i < numRI; i++)
 
1654
        xfreeData(&ri[i].reg);
 
1655
    xfree (ri);
 
1656
    return miRegionBreak (badreg);
 
1657
}
 
1658
 
 
1659
RegionPtr
 
1660
miRectsToRegion(nrects, prect, ctype)
 
1661
    int                 nrects;
 
1662
    register xRectangle *prect;
 
1663
    int                 ctype;
 
1664
{
 
1665
    register RegionPtr  pRgn;
 
1666
    register RegDataPtr pData;
 
1667
    register BoxPtr     pBox;
 
1668
    register int        i;
 
1669
    int                 x1, y1, x2, y2;
 
1670
 
 
1671
    pRgn = miRegionCreate(NullBox, 0);
 
1672
    if (REGION_NAR (pRgn))
 
1673
        return pRgn;
 
1674
    if (!nrects)
 
1675
        return pRgn;
 
1676
    if (nrects == 1)
 
1677
    {
 
1678
        x1 = prect->x;
 
1679
        y1 = prect->y;
 
1680
        if ((x2 = x1 + (int) prect->width) > MAXSHORT)
 
1681
            x2 = MAXSHORT;
 
1682
        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
 
1683
            y2 = MAXSHORT;
 
1684
        if (x1 != x2 && y1 != y2)
 
1685
        {
 
1686
            pRgn->extents.x1 = x1;
 
1687
            pRgn->extents.y1 = y1;
 
1688
            pRgn->extents.x2 = x2;
 
1689
            pRgn->extents.y2 = y2;
 
1690
            pRgn->data = (RegDataPtr)NULL;
 
1691
        }
 
1692
        return pRgn;
 
1693
    }
 
1694
    pData = xallocData(nrects);
 
1695
    if (!pData)
 
1696
    {
 
1697
        miRegionBreak (pRgn);
 
1698
        return pRgn;
 
1699
    }
 
1700
    pBox = (BoxPtr) (pData + 1);
 
1701
    for (i = nrects; --i >= 0; prect++)
 
1702
    {
 
1703
        x1 = prect->x;
 
1704
        y1 = prect->y;
 
1705
        if ((x2 = x1 + (int) prect->width) > MAXSHORT)
 
1706
            x2 = MAXSHORT;
 
1707
        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
 
1708
            y2 = MAXSHORT;
 
1709
        if (x1 != x2 && y1 != y2)
 
1710
        {
 
1711
            pBox->x1 = x1;
 
1712
            pBox->y1 = y1;
 
1713
            pBox->x2 = x2;
 
1714
            pBox->y2 = y2;
 
1715
            pBox++;
 
1716
        }
 
1717
    }
 
1718
    if (pBox != (BoxPtr) (pData + 1))
 
1719
    {
 
1720
        pData->size = nrects;
 
1721
        pData->numRects = pBox - (BoxPtr) (pData + 1);
 
1722
        pRgn->data = pData;
 
1723
        if (ctype != CT_YXBANDED)
 
1724
        {
 
1725
            Bool overlap; /* result ignored */
 
1726
            pRgn->extents.x1 = pRgn->extents.x2 = 0;
 
1727
            miRegionValidate(pRgn, &overlap);
 
1728
        }
 
1729
        else
 
1730
            miSetExtents(pRgn);
 
1731
        good(pRgn);
 
1732
    }
 
1733
    else
 
1734
    {
 
1735
        xfree (pData);
 
1736
    }
 
1737
    return pRgn;
 
1738
}
 
1739
 
 
1740
/*======================================================================
 
1741
 *                Region Subtraction
 
1742
 *====================================================================*/
 
1743
 
 
1744
 
 
1745
/*-
 
1746
 *-----------------------------------------------------------------------
 
1747
 * miSubtractO --
 
1748
 *      Overlapping band subtraction. x1 is the left-most point not yet
 
1749
 *      checked.
 
1750
 *
 
1751
 * Results:
 
1752
 *      TRUE if successful.
 
1753
 *
 
1754
 * Side Effects:
 
1755
 *      pReg may have rectangles added to it.
 
1756
 *
 
1757
 *-----------------------------------------------------------------------
 
1758
 */
 
1759
/*ARGSUSED*/
 
1760
static Bool
 
1761
miSubtractO (
 
1762
    register RegionPtr  pReg,
 
1763
    register BoxPtr     r1,
 
1764
    BoxPtr              r1End,
 
1765
    register BoxPtr     r2,
 
1766
    BoxPtr              r2End,
 
1767
    register short      y1,
 
1768
             short      y2,
 
1769
    Bool                *pOverlap)
 
1770
{
 
1771
    register BoxPtr     pNextRect;
 
1772
    register int        x1;
 
1773
 
 
1774
    x1 = r1->x1;
 
1775
    
 
1776
    assert(y1<y2);
 
1777
    assert(r1 != r1End && r2 != r2End);
 
1778
 
 
1779
    pNextRect = REGION_TOP(pReg);
 
1780
 
 
1781
    do
 
1782
    {
 
1783
        if (r2->x2 <= x1)
 
1784
        {
 
1785
            /*
 
1786
             * Subtrahend entirely to left of minuend: go to next subtrahend.
 
1787
             */
 
1788
            r2++;
 
1789
        }
 
1790
        else if (r2->x1 <= x1)
 
1791
        {
 
1792
            /*
 
1793
             * Subtrahend preceeds minuend: nuke left edge of minuend.
 
1794
             */
 
1795
            x1 = r2->x2;
 
1796
            if (x1 >= r1->x2)
 
1797
            {
 
1798
                /*
 
1799
                 * Minuend completely covered: advance to next minuend and
 
1800
                 * reset left fence to edge of new minuend.
 
1801
                 */
 
1802
                r1++;
 
1803
                if (r1 != r1End)
 
1804
                    x1 = r1->x1;
 
1805
            }
 
1806
            else
 
1807
            {
 
1808
                /*
 
1809
                 * Subtrahend now used up since it doesn't extend beyond
 
1810
                 * minuend
 
1811
                 */
 
1812
                r2++;
 
1813
            }
 
1814
        }
 
1815
        else if (r2->x1 < r1->x2)
 
1816
        {
 
1817
            /*
 
1818
             * Left part of subtrahend covers part of minuend: add uncovered
 
1819
             * part of minuend to region and skip to next subtrahend.
 
1820
             */
 
1821
            assert(x1<r2->x1);
 
1822
            NEWRECT(pReg, pNextRect, x1, y1, r2->x1, y2);
 
1823
 
 
1824
            x1 = r2->x2;
 
1825
            if (x1 >= r1->x2)
 
1826
            {
 
1827
                /*
 
1828
                 * Minuend used up: advance to new...
 
1829
                 */
 
1830
                r1++;
 
1831
                if (r1 != r1End)
 
1832
                    x1 = r1->x1;
 
1833
            }
 
1834
            else
 
1835
            {
 
1836
                /*
 
1837
                 * Subtrahend used up
 
1838
                 */
 
1839
                r2++;
 
1840
            }
 
1841
        }
 
1842
        else
 
1843
        {
 
1844
            /*
 
1845
             * Minuend used up: add any remaining piece before advancing.
 
1846
             */
 
1847
            if (r1->x2 > x1)
 
1848
                NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2);
 
1849
            r1++;
 
1850
            if (r1 != r1End)
 
1851
                x1 = r1->x1;
 
1852
        }
 
1853
    } while ((r1 != r1End) && (r2 != r2End));
 
1854
 
 
1855
 
 
1856
    /*
 
1857
     * Add remaining minuend rectangles to region.
 
1858
     */
 
1859
    while (r1 != r1End)
 
1860
    {
 
1861
        assert(x1<r1->x2);
 
1862
        NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2);
 
1863
        r1++;
 
1864
        if (r1 != r1End)
 
1865
            x1 = r1->x1;
 
1866
    }
 
1867
    return TRUE;
 
1868
}
 
1869
        
 
1870
/*-
 
1871
 *-----------------------------------------------------------------------
 
1872
 * miSubtract --
 
1873
 *      Subtract regS from regM and leave the result in regD.
 
1874
 *      S stands for subtrahend, M for minuend and D for difference.
 
1875
 *
 
1876
 * Results:
 
1877
 *      TRUE if successful.
 
1878
 *
 
1879
 * Side Effects:
 
1880
 *      regD is overwritten.
 
1881
 *
 
1882
 *-----------------------------------------------------------------------
 
1883
 */
 
1884
Bool
 
1885
miSubtract(regD, regM, regS)
 
1886
    register RegionPtr  regD;               
 
1887
    register RegionPtr  regM;
 
1888
    register RegionPtr  regS;          
 
1889
{
 
1890
    Bool overlap; /* result ignored */
 
1891
 
 
1892
    good(regM);
 
1893
    good(regS);
 
1894
    good(regD);
 
1895
   /* check for trivial rejects */
 
1896
    if (REGION_NIL(regM) || REGION_NIL(regS) ||
 
1897
        !EXTENTCHECK(&regM->extents, &regS->extents))
 
1898
    {
 
1899
        if (REGION_NAR (regS))
 
1900
            return miRegionBreak (regD);
 
1901
        return miRegionCopy(regD, regM);
 
1902
    }
 
1903
    else if (regM == regS)
 
1904
    {
 
1905
        xfreeData(regD);
 
1906
        regD->extents.x2 = regD->extents.x1;
 
1907
        regD->extents.y2 = regD->extents.y1;
 
1908
        regD->data = &miEmptyData;
 
1909
        return TRUE;
 
1910
    }
 
1911
 
 
1912
    /* Add those rectangles in region 1 that aren't in region 2,
 
1913
       do yucky substraction for overlaps, and
 
1914
       just throw away rectangles in region 2 that aren't in region 1 */
 
1915
    if (!miRegionOp(regD, regM, regS, miSubtractO, TRUE, FALSE, &overlap))
 
1916
        return FALSE;
 
1917
 
 
1918
    /*
 
1919
     * Can't alter RegD's extents before we call miRegionOp because
 
1920
     * it might be one of the source regions and miRegionOp depends
 
1921
     * on the extents of those regions being unaltered. Besides, this
 
1922
     * way there's no checking against rectangles that will be nuked
 
1923
     * due to coalescing, so we have to examine fewer rectangles.
 
1924
     */
 
1925
    miSetExtents(regD);
 
1926
    good(regD);
 
1927
    return TRUE;
 
1928
}
 
1929
 
 
1930
/*======================================================================
 
1931
 *          Region Inversion
 
1932
 *====================================================================*/
 
1933
 
 
1934
/*-
 
1935
 *-----------------------------------------------------------------------
 
1936
 * miInverse --
 
1937
 *      Take a region and a box and return a region that is everything
 
1938
 *      in the box but not in the region. The careful reader will note
 
1939
 *      that this is the same as subtracting the region from the box...
 
1940
 *
 
1941
 * Results:
 
1942
 *      TRUE.
 
1943
 *
 
1944
 * Side Effects:
 
1945
 *      newReg is overwritten.
 
1946
 *
 
1947
 *-----------------------------------------------------------------------
 
1948
 */
 
1949
Bool
 
1950
miInverse(newReg, reg1, invRect)
 
1951
    RegionPtr     newReg;       /* Destination region */
 
1952
    RegionPtr     reg1;         /* Region to invert */
 
1953
    BoxPtr        invRect;      /* Bounding box for inversion */
 
1954
{
 
1955
    RegionRec     invReg;       /* Quick and dirty region made from the
 
1956
                                 * bounding box */
 
1957
    Bool          overlap;      /* result ignored */
 
1958
 
 
1959
    good(reg1);
 
1960
    good(newReg);
 
1961
   /* check for trivial rejects */
 
1962
    if (REGION_NIL(reg1) || !EXTENTCHECK(invRect, &reg1->extents))
 
1963
    {
 
1964
        if (REGION_NAR(reg1))
 
1965
            return miRegionBreak (newReg);
 
1966
        newReg->extents = *invRect;
 
1967
        xfreeData(newReg);
 
1968
        newReg->data = (RegDataPtr)NULL;
 
1969
        return TRUE;
 
1970
    }
 
1971
 
 
1972
    /* Add those rectangles in region 1 that aren't in region 2,
 
1973
       do yucky substraction for overlaps, and
 
1974
       just throw away rectangles in region 2 that aren't in region 1 */
 
1975
    invReg.extents = *invRect;
 
1976
    invReg.data = (RegDataPtr)NULL;
 
1977
    if (!miRegionOp(newReg, &invReg, reg1, miSubtractO, TRUE, FALSE, &overlap))
 
1978
        return FALSE;
 
1979
 
 
1980
    /*
 
1981
     * Can't alter newReg's extents before we call miRegionOp because
 
1982
     * it might be one of the source regions and miRegionOp depends
 
1983
     * on the extents of those regions being unaltered. Besides, this
 
1984
     * way there's no checking against rectangles that will be nuked
 
1985
     * due to coalescing, so we have to examine fewer rectangles.
 
1986
     */
 
1987
    miSetExtents(newReg);
 
1988
    good(newReg);
 
1989
    return TRUE;
 
1990
}
 
1991
 
 
1992
/*
 
1993
 *   RectIn(region, rect)
 
1994
 *   This routine takes a pointer to a region and a pointer to a box
 
1995
 *   and determines if the box is outside/inside/partly inside the region.
 
1996
 *
 
1997
 *   The idea is to travel through the list of rectangles trying to cover the
 
1998
 *   passed box with them. Anytime a piece of the rectangle isn't covered
 
1999
 *   by a band of rectangles, partOut is set TRUE. Any time a rectangle in
 
2000
 *   the region covers part of the box, partIn is set TRUE. The process ends
 
2001
 *   when either the box has been completely covered (we reached a band that
 
2002
 *   doesn't overlap the box, partIn is TRUE and partOut is false), the
 
2003
 *   box has been partially covered (partIn == partOut == TRUE -- because of
 
2004
 *   the banding, the first time this is true we know the box is only
 
2005
 *   partially in the region) or is outside the region (we reached a band
 
2006
 *   that doesn't overlap the box at all and partIn is false)
 
2007
 */
 
2008
 
 
2009
int
 
2010
miRectIn(region, prect)
 
2011
    register RegionPtr  region;
 
2012
    register BoxPtr     prect;
 
2013
{
 
2014
    register int        x;
 
2015
    register int        y;
 
2016
    register BoxPtr     pbox;
 
2017
    register BoxPtr     pboxEnd;
 
2018
    int                 partIn, partOut;
 
2019
    int                 numRects;
 
2020
 
 
2021
    good(region);
 
2022
    numRects = REGION_NUM_RECTS(region);
 
2023
    /* useful optimization */
 
2024
    if (!numRects || !EXTENTCHECK(&region->extents, prect))
 
2025
        return(rgnOUT);
 
2026
 
 
2027
    if (numRects == 1)
 
2028
    {
 
2029
        /* We know that it must be rgnIN or rgnPART */
 
2030
        if (SUBSUMES(&region->extents, prect))
 
2031
            return(rgnIN);
 
2032
        else
 
2033
            return(rgnPART);
 
2034
    }
 
2035
 
 
2036
    partOut = FALSE;
 
2037
    partIn = FALSE;
 
2038
 
 
2039
    /* (x,y) starts at upper left of rect, moving to the right and down */
 
2040
    x = prect->x1;
 
2041
    y = prect->y1;
 
2042
 
 
2043
    /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
 
2044
    for (pbox = REGION_BOXPTR(region), pboxEnd = pbox + numRects;
 
2045
         pbox != pboxEnd;
 
2046
         pbox++)
 
2047
    {
 
2048
 
 
2049
        if (pbox->y2 <= y)
 
2050
           continue;    /* getting up to speed or skipping remainder of band */
 
2051
 
 
2052
        if (pbox->y1 > y)
 
2053
        {
 
2054
           partOut = TRUE;      /* missed part of rectangle above */
 
2055
           if (partIn || (pbox->y1 >= prect->y2))
 
2056
              break;
 
2057
           y = pbox->y1;        /* x guaranteed to be == prect->x1 */
 
2058
        }
 
2059
 
 
2060
        if (pbox->x2 <= x)
 
2061
           continue;            /* not far enough over yet */
 
2062
 
 
2063
        if (pbox->x1 > x)
 
2064
        {
 
2065
           partOut = TRUE;      /* missed part of rectangle to left */
 
2066
           if (partIn)
 
2067
              break;
 
2068
        }
 
2069
 
 
2070
        if (pbox->x1 < prect->x2)
 
2071
        {
 
2072
            partIn = TRUE;      /* definitely overlap */
 
2073
            if (partOut)
 
2074
               break;
 
2075
        }
 
2076
 
 
2077
        if (pbox->x2 >= prect->x2)
 
2078
        {
 
2079
           y = pbox->y2;        /* finished with this band */
 
2080
           if (y >= prect->y2)
 
2081
              break;
 
2082
           x = prect->x1;       /* reset x out to left again */
 
2083
        }
 
2084
        else
 
2085
        {
 
2086
            /*
 
2087
             * Because boxes in a band are maximal width, if the first box
 
2088
             * to overlap the rectangle doesn't completely cover it in that
 
2089
             * band, the rectangle must be partially out, since some of it
 
2090
             * will be uncovered in that band. partIn will have been set true
 
2091
             * by now...
 
2092
             */
 
2093
            partOut = TRUE;
 
2094
            break;
 
2095
        }
 
2096
    }
 
2097
 
 
2098
    return(partIn ? ((y < prect->y2) ? rgnPART : rgnIN) : rgnOUT);
 
2099
}
 
2100
 
 
2101
/* TranslateRegion(pReg, x, y)
 
2102
   translates in place
 
2103
*/
 
2104
 
 
2105
void
 
2106
miTranslateRegion(pReg, x, y)
 
2107
    register RegionPtr pReg;
 
2108
    register int x;
 
2109
    register int y;
 
2110
{
 
2111
    int x1, x2, y1, y2;
 
2112
    register int nbox;
 
2113
    register BoxPtr pbox;
 
2114
 
 
2115
    good(pReg);
 
2116
    pReg->extents.x1 = x1 = pReg->extents.x1 + x;
 
2117
    pReg->extents.y1 = y1 = pReg->extents.y1 + y;
 
2118
    pReg->extents.x2 = x2 = pReg->extents.x2 + x;
 
2119
    pReg->extents.y2 = y2 = pReg->extents.y2 + y;
 
2120
    if (((x1 - MINSHORT)|(y1 - MINSHORT)|(MAXSHORT - x2)|(MAXSHORT - y2)) >= 0)
 
2121
    {
 
2122
        if (pReg->data && (nbox = pReg->data->numRects))
 
2123
        {
 
2124
            for (pbox = REGION_BOXPTR(pReg); nbox--; pbox++)
 
2125
            {
 
2126
                pbox->x1 += x;
 
2127
                pbox->y1 += y;
 
2128
                pbox->x2 += x;
 
2129
                pbox->y2 += y;
 
2130
            }
 
2131
        }
 
2132
        return;
 
2133
    }
 
2134
    if (((x2 - MINSHORT)|(y2 - MINSHORT)|(MAXSHORT - x1)|(MAXSHORT - y1)) <= 0)
 
2135
    {
 
2136
        pReg->extents.x2 = pReg->extents.x1;
 
2137
        pReg->extents.y2 = pReg->extents.y1;
 
2138
        xfreeData(pReg);
 
2139
        pReg->data = &miEmptyData;
 
2140
        return;
 
2141
    }
 
2142
    if (x1 < MINSHORT)
 
2143
        pReg->extents.x1 = MINSHORT;
 
2144
    else if (x2 > MAXSHORT)
 
2145
        pReg->extents.x2 = MAXSHORT;
 
2146
    if (y1 < MINSHORT)
 
2147
        pReg->extents.y1 = MINSHORT;
 
2148
    else if (y2 > MAXSHORT)
 
2149
        pReg->extents.y2 = MAXSHORT;
 
2150
    if (pReg->data && (nbox = pReg->data->numRects))
 
2151
    {
 
2152
        register BoxPtr pboxout;
 
2153
 
 
2154
        for (pboxout = pbox = REGION_BOXPTR(pReg); nbox--; pbox++)
 
2155
        {
 
2156
            pboxout->x1 = x1 = pbox->x1 + x;
 
2157
            pboxout->y1 = y1 = pbox->y1 + y;
 
2158
            pboxout->x2 = x2 = pbox->x2 + x;
 
2159
            pboxout->y2 = y2 = pbox->y2 + y;
 
2160
            if (((x2 - MINSHORT)|(y2 - MINSHORT)|
 
2161
                 (MAXSHORT - x1)|(MAXSHORT - y1)) <= 0)
 
2162
            {
 
2163
                pReg->data->numRects--;
 
2164
                continue;
 
2165
            }
 
2166
            if (x1 < MINSHORT)
 
2167
                pboxout->x1 = MINSHORT;
 
2168
            else if (x2 > MAXSHORT)
 
2169
                pboxout->x2 = MAXSHORT;
 
2170
            if (y1 < MINSHORT)
 
2171
                pboxout->y1 = MINSHORT;
 
2172
            else if (y2 > MAXSHORT)
 
2173
                pboxout->y2 = MAXSHORT;
 
2174
            pboxout++;
 
2175
        }
 
2176
        if (pboxout != pbox)
 
2177
        {
 
2178
            if (pReg->data->numRects == 1)
 
2179
            {
 
2180
                pReg->extents = *REGION_BOXPTR(pReg);
 
2181
                xfreeData(pReg);
 
2182
                pReg->data = (RegDataPtr)NULL;
 
2183
            }
 
2184
            else
 
2185
                miSetExtents(pReg);
 
2186
        }
 
2187
    }
 
2188
}
 
2189
 
 
2190
Bool
 
2191
miRegionDataCopy(
 
2192
    register RegionPtr dst,
 
2193
    register RegionPtr src)
 
2194
{
 
2195
    good(dst);
 
2196
    good(src);
 
2197
    if (dst->data) 
 
2198
        return TRUE;
 
2199
    if (dst == src)
 
2200
        return TRUE;
 
2201
    if (!src->data || !src->data->size)
 
2202
    {
 
2203
        xfreeData(dst);
 
2204
        dst->data = (RegDataPtr)NULL;
 
2205
        return TRUE;
 
2206
    }
 
2207
    if (!dst->data || (dst->data->size < src->data->numRects))
 
2208
    {
 
2209
        xfreeData(dst);
 
2210
        dst->data = xallocData(src->data->numRects);
 
2211
        if (!dst->data)
 
2212
            return miRegionBreak (dst);
 
2213
    }
 
2214
    dst->data->size = src->data->size;
 
2215
    dst->data->numRects = src->data->numRects;
 
2216
    return TRUE;
 
2217
}
 
2218
 
 
2219
void
 
2220
miRegionReset(pReg, pBox)
 
2221
    RegionPtr pReg;
 
2222
    BoxPtr pBox;
 
2223
{
 
2224
    good(pReg);
 
2225
    assert(pBox->x1<=pBox->x2);
 
2226
    assert(pBox->y1<=pBox->y2);
 
2227
    pReg->extents = *pBox;
 
2228
    xfreeData(pReg);
 
2229
    pReg->data = (RegDataPtr)NULL;
 
2230
}
 
2231
 
 
2232
Bool
 
2233
miPointInRegion(pReg, x, y, box)
 
2234
    register RegionPtr pReg;
 
2235
    register int x, y;
 
2236
    BoxPtr box;     /* "return" value */
 
2237
{
 
2238
    register BoxPtr pbox, pboxEnd;
 
2239
    int numRects;
 
2240
 
 
2241
    good(pReg);
 
2242
    numRects = REGION_NUM_RECTS(pReg);
 
2243
    if (!numRects || !INBOX(&pReg->extents, x, y))
 
2244
        return(FALSE);
 
2245
    if (numRects == 1)
 
2246
    {
 
2247
        *box = pReg->extents;
 
2248
        return(TRUE);
 
2249
    }
 
2250
    for (pbox = REGION_BOXPTR(pReg), pboxEnd = pbox + numRects;
 
2251
         pbox != pboxEnd;
 
2252
         pbox++)
 
2253
    {
 
2254
        if (y >= pbox->y2)
 
2255
           continue;            /* not there yet */
 
2256
        if ((y < pbox->y1) || (x < pbox->x1))
 
2257
           break;               /* missed it */
 
2258
        if (x >= pbox->x2)
 
2259
           continue;            /* not there yet */
 
2260
        *box = *pbox;
 
2261
        return(TRUE);
 
2262
    }
 
2263
    return(FALSE);
 
2264
}
 
2265
 
 
2266
Bool
 
2267
miRegionNotEmpty(pReg)
 
2268
    RegionPtr pReg;
 
2269
{
 
2270
    good(pReg);
 
2271
    return(!REGION_NIL(pReg));
 
2272
}
 
2273
 
 
2274
Bool
 
2275
miRegionBroken(RegionPtr pReg)
 
2276
{
 
2277
    good(pReg);
 
2278
    return (REGION_NAR(pReg));
 
2279
}
 
2280
 
 
2281
void
 
2282
miRegionEmpty(pReg)
 
2283
    RegionPtr pReg;
 
2284
{
 
2285
    good(pReg);
 
2286
    xfreeData(pReg);
 
2287
    pReg->extents.x2 = pReg->extents.x1;
 
2288
    pReg->extents.y2 = pReg->extents.y1;
 
2289
    pReg->data = &miEmptyData;
 
2290
}
 
2291
 
 
2292
BoxPtr
 
2293
miRegionExtents(pReg)
 
2294
    RegionPtr pReg;
 
2295
{
 
2296
    good(pReg);
 
2297
    return(&pReg->extents);
 
2298
}
 
2299
 
 
2300
#define ExchangeSpans(a, b)                                 \
 
2301
{                                                           \
 
2302
    DDXPointRec     tpt;                                    \
 
2303
    register int    tw;                                     \
 
2304
                                                            \
 
2305
    tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt;    \
 
2306
    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
 
2307
}
 
2308
 
 
2309
/* ||| I should apply the merge sort code to rectangle sorting above, and see
 
2310
   if mapping time can be improved.  But right now I've been at work 12 hours,
 
2311
   so forget it.
 
2312
*/
 
2313
 
 
2314
static void QuickSortSpans(
 
2315
    register DDXPointRec    spans[],
 
2316
    register int            widths[],
 
2317
    register int            numSpans)
 
2318
{
 
2319
    register int            y;
 
2320
    register int            i, j, m;
 
2321
    register DDXPointPtr    r;
 
2322
 
 
2323
    /* Always called with numSpans > 1 */
 
2324
    /* Sorts only by y, doesn't bother to sort by x */
 
2325
 
 
2326
    do
 
2327
    {
 
2328
        if (numSpans < 9)
 
2329
        {
 
2330
            /* Do insertion sort */
 
2331
            register int yprev;
 
2332
 
 
2333
            yprev = spans[0].y;
 
2334
            i = 1;
 
2335
            do
 
2336
            { /* while i != numSpans */
 
2337
                y = spans[i].y;
 
2338
                if (yprev > y)
 
2339
                {
 
2340
                    /* spans[i] is out of order.  Move into proper location. */
 
2341
                    DDXPointRec tpt;
 
2342
                    int     tw, k;
 
2343
 
 
2344
                    for (j = 0; y >= spans[j].y; j++) {}
 
2345
                    tpt = spans[i];
 
2346
                    tw  = widths[i];
 
2347
                    for (k = i; k != j; k--)
 
2348
                    {
 
2349
                        spans[k] = spans[k-1];
 
2350
                        widths[k] = widths[k-1];
 
2351
                    }
 
2352
                    spans[j] = tpt;
 
2353
                    widths[j] = tw;
 
2354
                    y = spans[i].y;
 
2355
                } /* if out of order */
 
2356
                yprev = y;
 
2357
                i++;
 
2358
            } while (i != numSpans);
 
2359
            return;
 
2360
        }
 
2361
 
 
2362
        /* Choose partition element, stick in location 0 */
 
2363
        m = numSpans / 2;
 
2364
        if (spans[m].y > spans[0].y)            ExchangeSpans(m, 0);
 
2365
        if (spans[m].y > spans[numSpans-1].y)   ExchangeSpans(m, numSpans-1);
 
2366
        if (spans[m].y > spans[0].y)            ExchangeSpans(m, 0);
 
2367
        y = spans[0].y;
 
2368
 
 
2369
        /* Partition array */
 
2370
        i = 0;
 
2371
        j = numSpans;
 
2372
        do
 
2373
        {
 
2374
            r = &(spans[i]);
 
2375
            do
 
2376
            {
 
2377
                r++;
 
2378
                i++;
 
2379
            } while (i != numSpans && r->y < y);
 
2380
            r = &(spans[j]);
 
2381
            do
 
2382
            {
 
2383
                r--;
 
2384
                j--;
 
2385
            } while (y < r->y);
 
2386
            if (i < j)
 
2387
                ExchangeSpans(i, j);
 
2388
        } while (i < j);
 
2389
 
 
2390
        /* Move partition element back to middle */
 
2391
        ExchangeSpans(0, j);
 
2392
 
 
2393
        /* Recurse */
 
2394
        if (numSpans-j-1 > 1)
 
2395
            QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
 
2396
        numSpans = j;
 
2397
    } while (numSpans > 1);
 
2398
}
 
2399
 
 
2400
#define NextBand()                                                  \
 
2401
{                                                                   \
 
2402
    clipy1 = pboxBandStart->y1;                                     \
 
2403
    clipy2 = pboxBandStart->y2;                                     \
 
2404
    pboxBandEnd = pboxBandStart + 1;                                \
 
2405
    while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) {  \
 
2406
        pboxBandEnd++;                                              \
 
2407
    }                                                               \
 
2408
    for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
 
2409
}
 
2410
 
 
2411
/*
 
2412
    Clip a list of scanlines to a region.  The caller has allocated the
 
2413
    space.  FSorted is non-zero if the scanline origins are in ascending
 
2414
    order.
 
2415
    returns the number of new, clipped scanlines.
 
2416
*/
 
2417
 
 
2418
int
 
2419
miClipSpans(
 
2420
    RegionPtr               prgnDst,
 
2421
    register DDXPointPtr    ppt,
 
2422
    register int            *pwidth,
 
2423
    int                     nspans,
 
2424
    register DDXPointPtr    pptNew,
 
2425
    int                     *pwidthNew,
 
2426
    int                     fSorted)
 
2427
{
 
2428
    register DDXPointPtr pptLast;
 
2429
    int                 *pwidthNewStart;        /* the vengeance of Xerox! */
 
2430
    register int        y, x1, x2;
 
2431
    register int        numRects;
 
2432
 
 
2433
    good(prgnDst);
 
2434
    pptLast = ppt + nspans;
 
2435
    pwidthNewStart = pwidthNew;
 
2436
 
 
2437
    if (!prgnDst->data)
 
2438
    {
 
2439
        /* Do special fast code with clip boundaries in registers(?) */
 
2440
        /* It doesn't pay much to make use of fSorted in this case, 
 
2441
           so we lump everything together. */
 
2442
 
 
2443
        register    int clipx1, clipx2, clipy1, clipy2;
 
2444
 
 
2445
        clipx1 = prgnDst->extents.x1;
 
2446
        clipy1 = prgnDst->extents.y1;
 
2447
        clipx2 = prgnDst->extents.x2;
 
2448
        clipy2 = prgnDst->extents.y2;
 
2449
            
 
2450
        for (; ppt != pptLast; ppt++, pwidth++)
 
2451
        {
 
2452
            y = ppt->y;
 
2453
            x1 = ppt->x;
 
2454
            if (clipy1 <= y && y < clipy2)
 
2455
            {
 
2456
                x2 = x1 + *pwidth;
 
2457
                if (x1 < clipx1)    x1 = clipx1;
 
2458
                if (x2 > clipx2)    x2 = clipx2;
 
2459
                if (x1 < x2)
 
2460
                {
 
2461
                    /* part of span in clip rectangle */
 
2462
                    pptNew->x = x1;
 
2463
                    pptNew->y = y;
 
2464
                    *pwidthNew = x2 - x1;
 
2465
                    pptNew++;
 
2466
                    pwidthNew++;
 
2467
                }
 
2468
            }
 
2469
        } /* end for */
 
2470
 
 
2471
    }
 
2472
    else if ((numRects = prgnDst->data->numRects))
 
2473
    {
 
2474
        /* Have to clip against many boxes */
 
2475
        BoxPtr          pboxBandStart, pboxBandEnd;
 
2476
        register BoxPtr pbox;
 
2477
        register BoxPtr pboxLast;
 
2478
        register int    clipy1, clipy2;
 
2479
 
 
2480
        /* In this case, taking advantage of sorted spans gains more than
 
2481
           the sorting costs. */
 
2482
        if ((! fSorted) && (nspans > 1))
 
2483
            QuickSortSpans(ppt, pwidth, nspans);
 
2484
 
 
2485
        pboxBandStart = REGION_BOXPTR(prgnDst);
 
2486
        pboxLast = pboxBandStart + numRects;
 
2487
    
 
2488
        NextBand();
 
2489
 
 
2490
        for (; ppt != pptLast; )
 
2491
        {
 
2492
            y = ppt->y;
 
2493
            if (y < clipy2)
 
2494
            {
 
2495
                /* span is in the current band */
 
2496
                pbox = pboxBandStart;
 
2497
                x1 = ppt->x;
 
2498
                x2 = x1 + *pwidth;
 
2499
                do
 
2500
                { /* For each box in band */
 
2501
                    register int    newx1, newx2;
 
2502
 
 
2503
                    newx1 = x1;
 
2504
                    newx2 = x2;
 
2505
                    if (newx1 < pbox->x1)   newx1 = pbox->x1;
 
2506
                    if (newx2 > pbox->x2)   newx2 = pbox->x2;
 
2507
                    if (newx1 < newx2)
 
2508
                    {
 
2509
                        /* Part of span in clip rectangle */
 
2510
                        pptNew->x = newx1;
 
2511
                        pptNew->y = y;
 
2512
                        *pwidthNew = newx2 - newx1;
 
2513
                        pptNew++;
 
2514
                        pwidthNew++;
 
2515
                    }
 
2516
                    pbox++;
 
2517
                } while (pbox != pboxBandEnd);
 
2518
                ppt++;
 
2519
                pwidth++;
 
2520
            }
 
2521
            else
 
2522
            {
 
2523
                /* Move to next band, adjust ppt as needed */
 
2524
                pboxBandStart = pboxBandEnd;
 
2525
                if (pboxBandStart == pboxLast)
 
2526
                    break; /* We're completely done */
 
2527
                NextBand();
 
2528
            }
 
2529
        }
 
2530
    }
 
2531
    return (pwidthNew - pwidthNewStart);
 
2532
}
 
2533
 
 
2534
/* find the band in a region with the most rectangles */
 
2535
int
 
2536
miFindMaxBand(prgn)
 
2537
    RegionPtr prgn;
 
2538
{
 
2539
    register int nbox;
 
2540
    register BoxPtr pbox;
 
2541
    register int nThisBand;
 
2542
    register int nMaxBand = 0;
 
2543
    short yThisBand;
 
2544
 
 
2545
    good(prgn);
 
2546
    nbox = REGION_NUM_RECTS(prgn);
 
2547
    pbox = REGION_RECTS(prgn);
 
2548
 
 
2549
    while(nbox > 0)
 
2550
    {
 
2551
        yThisBand = pbox->y1;
 
2552
        nThisBand = 0;
 
2553
        while((nbox > 0) && (pbox->y1 == yThisBand))
 
2554
        {
 
2555
            nbox--;
 
2556
            pbox++;
 
2557
            nThisBand++;
 
2558
        }
 
2559
        if (nThisBand > nMaxBand)
 
2560
            nMaxBand = nThisBand;
 
2561
    }
 
2562
    return (nMaxBand);
 
2563
}