]> git.saurik.com Git - wxWidgets.git/blame - src/generic/regiong.cpp
avoid duplicate move events
[wxWidgets.git] / src / generic / regiong.cpp
CommitLineData
4c3c3844 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/generic/regiong.cpp
4c3c3844
DE
3// Purpose: generic wxRegion class
4// Author: David Elliott
5// Modified by:
6// Created: 2004/04/12
4c3c3844 7// Copyright: (c) 2004 David Elliott
ca65c044 8// Licence: wxWindows licence
4c3c3844
DE
9/////////////////////////////////////////////////////////////////////////////
10
de6185e2
WS
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
9a6384ca 19#include "wx/region.h"
de6185e2
WS
20
21#ifndef WX_PRECOMP
22 #include "wx/utils.h"
23#endif
4c3c3844
DE
24
25// ========================================================================
26// Classes to interface with X.org code
27// ========================================================================
28
29typedef struct Box
30{
31 wxCoord x1, x2, y1, y2;
32} Box, BOX, BoxRec, *BoxPtr;
33
34typedef struct REGION *Region;
35
36struct REGION
37{
38public:
39 // Default constructor initializes nothing
40 REGION() {}
44bf7fe3 41
4c3c3844
DE
42 REGION(const wxRect& rect)
43 {
44 rects = &extents;
45 numRects = 1;
46 extents.x1 = rect.x;
47 extents.y1 = rect.y;
48 extents.x2 = rect.x + rect.width;
49 extents.y2 = rect.y + rect.height;
50 size = 1;
51 }
44bf7fe3
VZ
52
53 BoxPtr GetBox(int i)
54 {
55 return i < numRects ? rects + i : NULL;
56 }
4c3c3844
DE
57
58 // X.org methods
59 static bool XClipBox(
60 Region r,
61 wxRect *rect);
62 static bool XOffsetRegion(
63 register Region pRegion,
64 register int x,
65 register int y);
66 static bool XIntersectRegion(
ca65c044
WS
67 Region reg1,
68 Region reg2, /* source regions */
69 register Region newReg); /* destination Region */
4c3c3844 70 static bool XUnionRegion(
ca65c044
WS
71 Region reg1,
72 Region reg2, /* source regions */
73 Region newReg); /* destination Region */
4c3c3844 74 static bool XSubtractRegion(
ca65c044
WS
75 Region regM,
76 Region regS,
77 register Region regD);
4c3c3844
DE
78 static bool XXorRegion(Region sra, Region srb, Region dr);
79 static bool XEmptyRegion(
80 Region r);
81 static bool XEqualRegion(Region r1, Region r2);
82 static bool XPointInRegion(
83 Region pRegion,
84 int x, int y);
85 static wxRegionContain XRectInRegion(
ca65c044 86 register Region region,
4c3c3844
DE
87 int rx, int ry,
88 unsigned int rwidth, unsigned int rheight);
89
90protected:
91 static Region XCreateRegion(void);
92 static void miSetExtents (
ca65c044 93 Region pReg);
4c3c3844
DE
94 static bool XDestroyRegion(Region r);
95 static int miIntersectO (
ca65c044
WS
96 register Region pReg,
97 register BoxPtr r1,
98 BoxPtr r1End,
99 register BoxPtr r2,
100 BoxPtr r2End,
101 wxCoord y1,
102 wxCoord y2);
4c3c3844
DE
103 static void miRegionCopy(
104 register Region dstrgn,
105 register Region rgn);
106 static int miCoalesce(
ca65c044
WS
107 register Region pReg, /* Region to coalesce */
108 int prevStart, /* Index of start of previous band */
109 int curStart); /* Index of start of current band */
4c3c3844 110 static void miRegionOp(
ca65c044
WS
111 register Region newReg, /* Place to store result */
112 Region reg1, /* First region in operation */
113 Region reg2, /* 2d region in operation */
114 int (*overlapFunc)(
4c3c3844
DE
115 register Region pReg,
116 register BoxPtr r1,
117 BoxPtr r1End,
118 register BoxPtr r2,
119 BoxPtr r2End,
ca65c044
WS
120 wxCoord y1,
121 wxCoord y2), /* Function to call for over-
122 * lapping bands */
123 int (*nonOverlap1Func)(
4c3c3844
DE
124 register Region pReg,
125 register BoxPtr r,
126 BoxPtr rEnd,
ca65c044
WS
127 register wxCoord y1,
128 register wxCoord y2), /* Function to call for non-
129 * overlapping bands in region
130 * 1 */
131 int (*nonOverlap2Func)(
4c3c3844
DE
132 register Region pReg,
133 register BoxPtr r,
134 BoxPtr rEnd,
ca65c044
WS
135 register wxCoord y1,
136 register wxCoord y2)); /* Function to call for non-
137 * overlapping bands in region
138 * 2 */
4c3c3844 139 static int miUnionNonO (
ca65c044
WS
140 register Region pReg,
141 register BoxPtr r,
142 BoxPtr rEnd,
143 register wxCoord y1,
144 register wxCoord y2);
4c3c3844 145 static int miUnionO (
ca65c044
WS
146 register Region pReg,
147 register BoxPtr r1,
148 BoxPtr r1End,
149 register BoxPtr r2,
150 BoxPtr r2End,
151 register wxCoord y1,
152 register wxCoord y2);
4c3c3844 153 static int miSubtractNonO1 (
ca65c044
WS
154 register Region pReg,
155 register BoxPtr r,
156 BoxPtr rEnd,
157 register wxCoord y1,
158 register wxCoord y2);
4c3c3844 159 static int miSubtractO (
ca65c044
WS
160 register Region pReg,
161 register BoxPtr r1,
162 BoxPtr r1End,
163 register BoxPtr r2,
164 BoxPtr r2End,
165 register wxCoord y1,
166 register wxCoord y2);
4c3c3844
DE
167protected:
168 long size;
169 long numRects;
170 Box *rects;
171 Box extents;
172};
173
174// ========================================================================
175// wxRegionRefData
176// ========================================================================
44bf7fe3 177
8f884a0d 178class wxRegionRefData : public wxGDIRefData,
44bf7fe3 179 public REGION
4c3c3844
DE
180{
181public:
182 wxRegionRefData()
8f884a0d 183 : wxGDIRefData(),
44bf7fe3
VZ
184 REGION()
185 {
186 size = 1;
4c3c3844 187 numRects = 0;
8f6a082b 188 rects = ( BOX * )malloc( (unsigned) sizeof( BOX ));
4c3c3844
DE
189 extents.x1 = 0;
190 extents.x2 = 0;
191 extents.y1 = 0;
192 extents.y2 = 0;
193 }
44bf7fe3 194
4c3c3844 195 wxRegionRefData(const wxPoint& topLeft, const wxPoint& bottomRight)
8f884a0d 196 : wxGDIRefData(),
44bf7fe3
VZ
197 REGION()
198 {
199 rects = (BOX*)malloc(sizeof(BOX));
4c3c3844
DE
200 size = 1;
201 numRects = 1;
202 extents.x1 = topLeft.x;
203 extents.y1 = topLeft.y;
204 extents.x2 = bottomRight.x;
205 extents.y2 = bottomRight.y;
206 *rects = extents;
207 }
44bf7fe3 208
4c3c3844 209 wxRegionRefData(const wxRect& rect)
8f884a0d 210 : wxGDIRefData(),
44bf7fe3
VZ
211 REGION(rect)
212 {
213 rects = (BOX*)malloc(sizeof(BOX));
4c3c3844
DE
214 *rects = extents;
215 }
44bf7fe3 216
4c3c3844 217 wxRegionRefData(const wxRegionRefData& refData)
8f884a0d 218 : wxGDIRefData(),
44bf7fe3 219 REGION()
4c3c3844
DE
220 {
221 size = refData.size;
222 numRects = refData.numRects;
223 rects = (Box*)malloc(numRects*sizeof(Box));
44bf7fe3 224 memcpy(rects, refData.rects, numRects*sizeof(Box));
4c3c3844
DE
225 extents = refData.extents;
226 }
44bf7fe3 227
d3c7fc99 228 virtual ~wxRegionRefData()
4c3c3844
DE
229 {
230 free(rects);
231 }
44bf7fe3 232
4c3c3844
DE
233private:
234 // Don't allow this
235 wxRegionRefData(const REGION&);
236};
237
238// ========================================================================
239// wxRegionGeneric
240// ========================================================================
412e0d47 241//IMPLEMENT_DYNAMIC_CLASS(wxRegionGeneric, wxGDIObject)
4c3c3844
DE
242
243#define M_REGIONDATA ((wxRegionRefData *)m_refData)
244#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
245
246// ----------------------------------------------------------------------------
247// wxRegionGeneric construction
248// ----------------------------------------------------------------------------
249
250wxRegionGeneric::wxRegionGeneric()
251{
252}
253
254wxRegionGeneric::~wxRegionGeneric()
255{
256}
257
258wxRegionGeneric::wxRegionGeneric(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
259{
260 m_refData = new wxRegionRefData(wxRect(x,y,w,h));
261}
262
263wxRegionGeneric::wxRegionGeneric(const wxRect& rect)
264{
265 m_refData = new wxRegionRefData(rect);
266}
267
268wxRegionGeneric::wxRegionGeneric(const wxPoint& topLeft, const wxPoint& bottomRight)
269{
270 m_refData = new wxRegionRefData(topLeft, bottomRight);
271}
272
03647350 273wxRegionGeneric::wxRegionGeneric(const wxBitmap& bmp)
b916f712
KO
274{
275 wxFAIL_MSG("NOT IMPLEMENTED: wxRegionGeneric::wxRegionGeneric(const wxBitmap& bmp)");
276}
277
278wxRegionGeneric::wxRegionGeneric(size_t n, const wxPoint *points, wxPolygonFillMode fillStyle)
279{
280 wxFAIL_MSG("NOT IMPLEMENTED: wxRegionGeneric::wxRegionGeneric(size_t n, const wxPoint *points, wxPolygonFillMode fillStyle)");
281}
282
283wxRegionGeneric::wxRegionGeneric(const wxBitmap& bmp, const wxColour& transp, int tolerance)
284{
285 wxFAIL_MSG("NOT IMPLEMENTED: wxRegionGeneric::wxRegionGeneric(const wxBitmap& bmp, const wxColour& transp, int tolerance)");
286}
287
4c3c3844
DE
288void wxRegionGeneric::Clear()
289{
290 UnRef();
c6f2bde1
KO
291 if (!m_refData)
292 m_refData = new wxRegionRefData(wxRect(0,0,0,0));
4c3c3844
DE
293}
294
8f884a0d 295wxGDIRefData *wxRegionGeneric::CreateGDIRefData() const
4c3c3844
DE
296{
297 return new wxRegionRefData;
298}
299
8f884a0d 300wxGDIRefData *wxRegionGeneric::CloneGDIRefData(const wxGDIRefData *data) const
4c3c3844
DE
301{
302 return new wxRegionRefData(*(wxRegionRefData *)data);
303}
304
8a16d737 305bool wxRegionGeneric::DoIsEqual(const wxRegion& region) const
4c3c3844 306{
4c3c3844
DE
307 return REGION::XEqualRegion(M_REGIONDATA,M_REGIONDATA_OF(region));
308}
309
8a16d737 310bool wxRegionGeneric::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
4c3c3844 311{
8a16d737
VZ
312 if ( !m_refData )
313 return false;
4c3c3844 314
4c3c3844
DE
315 wxRect rect;
316 REGION::XClipBox(M_REGIONDATA,&rect);
317 x = rect.x;
318 y = rect.y;
319 w = rect.width;
320 h = rect.height;
8a16d737 321 return true;
4c3c3844
DE
322}
323
324// ----------------------------------------------------------------------------
325// wxRegionGeneric operations
326// ----------------------------------------------------------------------------
327
8a16d737 328bool wxRegionGeneric::DoUnionWithRect(const wxRect& rect)
4c3c3844 329{
8a16d737
VZ
330 if ( rect.IsEmpty() )
331 {
332 // nothing to do
333 return true;
334 }
4c3c3844
DE
335
336 AllocExclusive();
337 REGION region(rect);
338 return REGION::XUnionRegion(&region,M_REGIONDATA,M_REGIONDATA);
339}
340
97271940 341bool wxRegionGeneric::DoUnionWithRegion(const wxRegion& region)
4c3c3844
DE
342{
343 AllocExclusive();
344 return REGION::XUnionRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA);
345}
346
97271940 347bool wxRegionGeneric::DoIntersect(const wxRegion& region)
4c3c3844
DE
348{
349 AllocExclusive();
350 return REGION::XIntersectRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA);
351}
352
97271940 353bool wxRegionGeneric::DoSubtract(const wxRegion& region)
4c3c3844 354{
8a16d737
VZ
355 if ( region.IsEmpty() )
356 {
357 // nothing to do
358 return true;
359 }
4c3c3844 360
4c3c3844
DE
361 return REGION::XSubtractRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA);
362}
363
97271940 364bool wxRegionGeneric::DoXor(const wxRegion& region)
4c3c3844
DE
365{
366 AllocExclusive();
367 return REGION::XXorRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA);
368}
369
8a16d737 370bool wxRegionGeneric::DoOffset(wxCoord x, wxCoord y)
4c3c3844
DE
371{
372 AllocExclusive();
373 return REGION::XOffsetRegion(M_REGIONDATA, x, y);
374}
375
376// ----------------------------------------------------------------------------
377// wxRegionGeneric comparison
378// ----------------------------------------------------------------------------
379
8a16d737 380bool wxRegionGeneric::IsEmpty() const
4c3c3844
DE
381{
382 wxASSERT(m_refData);
383 return REGION::XEmptyRegion(M_REGIONDATA);
384}
385
386// Does the region contain the point (x,y)?
97271940 387wxRegionContain wxRegionGeneric::DoContainsPoint(wxCoord x, wxCoord y) const
4c3c3844
DE
388{
389 wxASSERT(m_refData);
8a16d737 390 return REGION::XPointInRegion(M_REGIONDATA,x,y) ? wxInRegion : wxOutRegion;
4c3c3844 391}
ca65c044 392
4c3c3844 393// Does the region contain the rectangle rect?
8a16d737 394wxRegionContain wxRegionGeneric::DoContainsRect(const wxRect& rect) const
4c3c3844
DE
395{
396 wxASSERT(m_refData);
397 return REGION::XRectInRegion(M_REGIONDATA,rect.x,rect.y,rect.width,rect.height);
398}
ca65c044 399
4c3c3844
DE
400// ========================================================================
401// wxRegionIteratorGeneric
402// ========================================================================
412e0d47 403//IMPLEMENT_DYNAMIC_CLASS(wxRegionIteratorGeneric,wxObject)
4c3c3844
DE
404
405wxRegionIteratorGeneric::wxRegionIteratorGeneric()
406{
407 m_current = 0;
408}
409
410wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionGeneric& region)
411: m_region(region)
412{
413 m_current = 0;
414}
415
416wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionIteratorGeneric& iterator)
417: m_region(iterator.m_region)
418{
419 m_current = iterator.m_current;
420}
421
422void wxRegionIteratorGeneric::Reset(const wxRegionGeneric& region)
423{
424 m_region = region;
425 m_current = 0;
426}
427
428bool wxRegionIteratorGeneric::HaveRects() const
429{
430 return M_REGIONDATA_OF(m_region)->GetBox(m_current);
431}
432
433wxRegionIteratorGeneric& wxRegionIteratorGeneric::operator++()
434{
435 ++m_current;
436 return *this;
437}
438
439wxRegionIteratorGeneric wxRegionIteratorGeneric::operator++(int)
440{
441 wxRegionIteratorGeneric copy(*this);
442 ++*this;
443 return copy;
444}
445
446wxRect wxRegionIteratorGeneric::GetRect() const
447{
936170f4 448 wxASSERT(m_region.m_refData);
4c3c3844
DE
449 const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current);
450 wxASSERT(box);
451 return wxRect
452 ( box->x1
453 , box->y1
454 , box->x2 - box->x1
455 , box->y2 - box->y1
456 );
457}
458
459long wxRegionIteratorGeneric::GetX() const
460{
936170f4 461 wxASSERT(m_region.m_refData);
4c3c3844
DE
462 const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current);
463 wxASSERT(box);
464 return box->x1;
465}
466
467long wxRegionIteratorGeneric::GetY() const
468{
936170f4 469 wxASSERT(m_region.m_refData);
4c3c3844
DE
470 const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current);
471 wxASSERT(box);
472 return box->y1;
473}
474
475long wxRegionIteratorGeneric::GetW() const
476{
936170f4 477 wxASSERT(m_region.m_refData);
4c3c3844
DE
478 const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current);
479 wxASSERT(box);
480 return box->x2 - box->x1;
481}
482
483long wxRegionIteratorGeneric::GetH() const
484{
936170f4 485 wxASSERT(m_region.m_refData);
4c3c3844
DE
486 const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current);
487 wxASSERT(box);
488 return box->y2 - box->y1;
489}
490
491wxRegionIteratorGeneric::~wxRegionIteratorGeneric()
492{
493}
494
495
496// ========================================================================
497// The guts (from X.org)
498// ========================================================================
499
500/************************************************************************
501
502Copyright 1987, 1988, 1998 The Open Group
503
504Permission to use, copy, modify, distribute, and sell this software and its
505documentation for any purpose is hereby granted without fee, provided that
506the above copyright notice appear in all copies and that both that
507copyright notice and this permission notice appear in supporting
508documentation.
509
510The above copyright notice and this permission notice shall be included in
511all copies or substantial portions of the Software.
512
513THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
514IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
515FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
516OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
517AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
518CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
519
520Except as contained in this notice, the name of The Open Group shall not be
521used in advertising or otherwise to promote the sale, use or other dealings
522in this Software without prior written authorization from The Open Group.
523
524
525Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
526
527 All Rights Reserved
528
ca65c044
WS
529Permission to use, copy, modify, and distribute this software and its
530documentation for any purpose and without fee is hereby granted,
4c3c3844 531provided that the above copyright notice appear in all copies and that
ca65c044 532both that copyright notice and this permission notice appear in
4c3c3844
DE
533supporting documentation, and that the name of Digital not be
534used in advertising or publicity pertaining to distribution of the
ca65c044 535software without specific, written prior permission.
4c3c3844
DE
536
537DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
538ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
539DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
540ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
541WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
542ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
543SOFTWARE.
544
545************************************************************************/
546
547/* 1 if two BOXs overlap.
548 * 0 if two BOXs do not overlap.
ca65c044 549 * Remember, x2 and y2 are not in the region
4c3c3844
DE
550 */
551#define EXTENTCHECK(r1, r2) \
ca65c044
WS
552 ((r1)->x2 > (r2)->x1 && \
553 (r1)->x1 < (r2)->x2 && \
554 (r1)->y2 > (r2)->y1 && \
555 (r1)->y1 < (r2)->y2)
4c3c3844
DE
556
557/*
558 * Check to see if there is enough memory in the present region.
559 */
560#define MEMCHECK(reg, rect, firstrect){\
561 if ((reg)->numRects >= ((reg)->size - 1)){\
562 (firstrect) = (BOX *) realloc \
563 ((char *)(firstrect), (unsigned) (2 * (sizeof(BOX)) * ((reg)->size)));\
564 if ((firstrect) == 0)\
565 return(0);\
566 (reg)->size *= 2;\
567 (rect) = &(firstrect)[(reg)->numRects];\
568 }\
569 }
570
571#define EMPTY_REGION(pReg) pReg->numRects = 0
572
573#define REGION_NOT_EMPTY(pReg) pReg->numRects
574
575#define INBOX(r, x, y) \
576 ( ( ((r).x2 > x)) && \
577 ( ((r).x1 <= x)) && \
578 ( ((r).y2 > y)) && \
579 ( ((r).y1 <= y)) )
580
581/*
582 * The functions in this file implement the Region abstraction, similar to one
583 * used in the X11 sample server. A Region is simply an area, as the name
584 * implies, and is implemented as a "y-x-banded" array of rectangles. To
585 * explain: Each Region is made up of a certain number of rectangles sorted
586 * by y coordinate first, and then by x coordinate.
587 *
588 * Furthermore, the rectangles are banded such that every rectangle with a
589 * given upper-left y coordinate (y1) will have the same lower-right y
590 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
591 * will span the entire vertical distance of the band. This means that some
592 * areas that could be merged into a taller rectangle will be represented as
593 * several shorter rectangles to account for shorter rectangles to its left
594 * or right but within its "vertical scope".
595 *
596 * An added constraint on the rectangles is that they must cover as much
597 * horizontal area as possible. E.g. no two rectangles in a band are allowed
598 * to touch.
599 *
600 * Whenever possible, bands will be merged together to cover a greater vertical
601 * distance (and thus reduce the number of rectangles). Two bands can be merged
602 * only if the bottom of one touches the top of the other and they have
603 * rectangles in the same places (of the same width, of course). This maintains
604 * the y-x-banding that's so nice to have...
605 */
606
ca65c044 607/* Create a new empty region */
9a6384ca 608Region REGION::XCreateRegion(void)
4c3c3844 609{
9a6384ca 610 Region temp = new REGION;
4c3c3844 611
9a6384ca 612 if (!temp)
ca65c044 613 return (Region) NULL;
9a6384ca
WS
614
615 temp->rects = ( BOX * )malloc( (unsigned) sizeof( BOX ));
616
617 if (!temp->rects)
618 {
869b1b26 619 delete temp;
ca65c044 620 return (Region) NULL;
4c3c3844
DE
621 }
622 temp->numRects = 0;
623 temp->extents.x1 = 0;
624 temp->extents.y1 = 0;
625 temp->extents.x2 = 0;
626 temp->extents.y2 = 0;
627 temp->size = 1;
628 return( temp );
629}
630
9a6384ca 631bool REGION::XClipBox(Region r, wxRect *rect)
4c3c3844
DE
632{
633 rect->x = r->extents.x1;
634 rect->y = r->extents.y1;
635 rect->width = r->extents.x2 - r->extents.x1;
636 rect->height = r->extents.y2 - r->extents.y1;
637 return true;
638}
639
640/*-
641 *-----------------------------------------------------------------------
642 * miSetExtents --
ca65c044
WS
643 * Reset the extents of a region to what they should be. Called by
644 * miSubtract and miIntersect b/c they can't figure it out along the
645 * way or do so easily, as miUnion can.
4c3c3844
DE
646 *
647 * Results:
ca65c044 648 * None.
4c3c3844
DE
649 *
650 * Side Effects:
ca65c044 651 * The region's 'extents' structure is overwritten.
4c3c3844
DE
652 *
653 *-----------------------------------------------------------------------
654 */
655void REGION::
ca65c044 656miSetExtents (Region pReg)
4c3c3844 657{
ca65c044
WS
658 register BoxPtr pBox,
659 pBoxEnd,
660 pExtents;
4c3c3844
DE
661
662 if (pReg->numRects == 0)
663 {
ca65c044
WS
664 pReg->extents.x1 = 0;
665 pReg->extents.y1 = 0;
666 pReg->extents.x2 = 0;
667 pReg->extents.y2 = 0;
668 return;
4c3c3844
DE
669 }
670
671 pExtents = &pReg->extents;
672 pBox = pReg->rects;
673 pBoxEnd = &pBox[pReg->numRects - 1];
674
675 /*
676 * Since pBox is the first rectangle in the region, it must have the
677 * smallest y1 and since pBoxEnd is the last rectangle in the region,
678 * it must have the largest y2, because of banding. Initialize x1 and
679 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
680 * to...
681 */
682 pExtents->x1 = pBox->x1;
683 pExtents->y1 = pBox->y1;
684 pExtents->x2 = pBoxEnd->x2;
685 pExtents->y2 = pBoxEnd->y2;
686
2e587bb9 687 wxASSERT_LEVEL_2(pExtents->y1 < pExtents->y2);
4c3c3844
DE
688 while (pBox <= pBoxEnd)
689 {
ca65c044
WS
690 if (pBox->x1 < pExtents->x1)
691 {
692 pExtents->x1 = pBox->x1;
693 }
694 if (pBox->x2 > pExtents->x2)
695 {
696 pExtents->x2 = pBox->x2;
697 }
698 pBox++;
4c3c3844 699 }
2e587bb9 700 wxASSERT_LEVEL_2(pExtents->x1 < pExtents->x2);
4c3c3844
DE
701}
702
703bool REGION::
704XDestroyRegion(
705 Region r)
706{
707 free( (char *) r->rects );
708 delete r;
709 return true;
710}
711
712/* TranslateRegion(pRegion, x, y)
713 translates in place
714 added by raymond
715*/
716
717bool REGION::
718XOffsetRegion(
719 register Region pRegion,
720 register int x,
721 register int y)
722{
723 register int nbox;
724 register BOX *pbox;
725
726 pbox = pRegion->rects;
727 nbox = pRegion->numRects;
728
729 while(nbox--)
730 {
ca65c044
WS
731 pbox->x1 += x;
732 pbox->x2 += x;
733 pbox->y1 += y;
734 pbox->y2 += y;
735 pbox++;
4c3c3844
DE
736 }
737 pRegion->extents.x1 += x;
738 pRegion->extents.x2 += x;
739 pRegion->extents.y1 += y;
740 pRegion->extents.y2 += y;
741 return 1;
742}
743
744/*======================================================================
ca65c044 745 * Region Intersection
4c3c3844
DE
746 *====================================================================*/
747/*-
748 *-----------------------------------------------------------------------
749 * miIntersectO --
ca65c044 750 * Handle an overlapping band for miIntersect.
4c3c3844
DE
751 *
752 * Results:
ca65c044 753 * None.
4c3c3844
DE
754 *
755 * Side Effects:
ca65c044 756 * Rectangles may be added to the region.
4c3c3844
DE
757 *
758 *-----------------------------------------------------------------------
759 */
760/* static void*/
761int REGION::
762miIntersectO (
ca65c044
WS
763 register Region pReg,
764 register BoxPtr r1,
765 BoxPtr r1End,
766 register BoxPtr r2,
767 BoxPtr r2End,
768 wxCoord y1,
769 wxCoord y2)
4c3c3844 770{
ca65c044
WS
771 register wxCoord x1;
772 register wxCoord x2;
773 register BoxPtr pNextRect;
4c3c3844
DE
774
775 pNextRect = &pReg->rects[pReg->numRects];
776
777 while ((r1 != r1End) && (r2 != r2End))
778 {
ca65c044
WS
779 x1 = wxMax(r1->x1,r2->x1);
780 x2 = wxMin(r1->x2,r2->x2);
781
782 /*
783 * If there's any overlap between the two rectangles, add that
784 * overlap to the new region.
785 * There's no need to check for subsumption because the only way
786 * such a need could arise is if some region has two rectangles
787 * right next to each other. Since that should never happen...
788 */
789 if (x1 < x2)
790 {
2e587bb9 791 wxASSERT_LEVEL_2(y1<y2);
ca65c044
WS
792
793 MEMCHECK(pReg, pNextRect, pReg->rects);
794 pNextRect->x1 = x1;
795 pNextRect->y1 = y1;
796 pNextRect->x2 = x2;
797 pNextRect->y2 = y2;
798 pReg->numRects += 1;
799 pNextRect++;
2e587bb9 800 wxASSERT_LEVEL_2(pReg->numRects <= pReg->size);
ca65c044
WS
801 }
802
803 /*
804 * Need to advance the pointers. Shift the one that extends
805 * to the right the least, since the other still has a chance to
806 * overlap with that region's next rectangle, if you see what I mean.
807 */
808 if (r1->x2 < r2->x2)
809 {
810 r1++;
811 }
812 else if (r2->x2 < r1->x2)
813 {
814 r2++;
815 }
816 else
817 {
818 r1++;
819 r2++;
820 }
4c3c3844 821 }
ca65c044 822 return 0; /* lint */
4c3c3844
DE
823}
824
825bool REGION::
826XIntersectRegion(
ca65c044
WS
827 Region reg1,
828 Region reg2, /* source regions */
829 register Region newReg) /* destination Region */
4c3c3844
DE
830{
831 /* check for trivial reject */
832 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
ca65c044 833 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
4c3c3844
DE
834 newReg->numRects = 0;
835 else
ca65c044
WS
836 miRegionOp (newReg, reg1, reg2,
837 miIntersectO, NULL, NULL);
838
4c3c3844
DE
839 /*
840 * Can't alter newReg's extents before we call miRegionOp because
841 * it might be one of the source regions and miRegionOp depends
842 * on the extents of those regions being the same. Besides, this
843 * way there's no checking against rectangles that will be nuked
844 * due to coalescing, so we have to examine fewer rectangles.
845 */
846 miSetExtents(newReg);
847 return 1;
848}
849
850void REGION::
851miRegionCopy(
852 register Region dstrgn,
853 register Region rgn)
854
855{
856 if (dstrgn != rgn) /* don't want to copy to itself */
ca65c044 857 {
4c3c3844
DE
858 if (dstrgn->size < rgn->numRects)
859 {
860 if (dstrgn->rects)
861 {
ca65c044
WS
862 BOX *prevRects = dstrgn->rects;
863
9a6384ca 864 dstrgn->rects = (BOX *)
ca65c044 865 realloc((char *) dstrgn->rects,
9a6384ca
WS
866 (unsigned) rgn->numRects * (sizeof(BOX)));
867 if (!dstrgn->rects)
ca65c044
WS
868 {
869 free(prevRects);
870 return;
871 }
4c3c3844
DE
872 }
873 dstrgn->size = rgn->numRects;
ca65c044 874 }
4c3c3844
DE
875 dstrgn->numRects = rgn->numRects;
876 dstrgn->extents.x1 = rgn->extents.x1;
877 dstrgn->extents.y1 = rgn->extents.y1;
878 dstrgn->extents.x2 = rgn->extents.x2;
879 dstrgn->extents.y2 = rgn->extents.y2;
880
ca65c044
WS
881 memcpy((char *) dstrgn->rects, (char *) rgn->rects,
882 (int) (rgn->numRects * sizeof(BOX)));
4c3c3844
DE
883 }
884}
885
886/*======================================================================
ca65c044 887 * Generic Region Operator
4c3c3844
DE
888 *====================================================================*/
889
890/*-
891 *-----------------------------------------------------------------------
892 * miCoalesce --
ca65c044
WS
893 * Attempt to merge the boxes in the current band with those in the
894 * previous one. Used only by miRegionOp.
4c3c3844
DE
895 *
896 * Results:
ca65c044 897 * The new index for the previous band.
4c3c3844
DE
898 *
899 * Side Effects:
ca65c044
WS
900 * If coalescing takes place:
901 * - rectangles in the previous band will have their y2 fields
902 * altered.
903 * - pReg->numRects will be decreased.
4c3c3844
DE
904 *
905 *-----------------------------------------------------------------------
906 */
907/* static int*/
908int REGION::
909miCoalesce(
ca65c044
WS
910 register Region pReg, /* Region to coalesce */
911 int prevStart, /* Index of start of previous band */
912 int curStart) /* Index of start of current band */
4c3c3844 913{
ca65c044
WS
914 register BoxPtr pPrevBox; /* Current box in previous band */
915 register BoxPtr pCurBox; /* Current box in current band */
916 register BoxPtr pRegEnd; /* End of region */
917 int curNumRects; /* Number of rectangles in current
918 * band */
919 int prevNumRects; /* Number of rectangles in previous
920 * band */
921 int bandY1; /* Y1 coordinate for current band */
4c3c3844
DE
922
923 pRegEnd = &pReg->rects[pReg->numRects];
924
925 pPrevBox = &pReg->rects[prevStart];
926 prevNumRects = curStart - prevStart;
927
928 /*
929 * Figure out how many rectangles are in the current band. Have to do
930 * this because multiple bands could have been added in miRegionOp
931 * at the end when one region has been exhausted.
932 */
933 pCurBox = &pReg->rects[curStart];
934 bandY1 = pCurBox->y1;
935 for (curNumRects = 0;
ca65c044
WS
936 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
937 curNumRects++)
4c3c3844 938 {
ca65c044 939 pCurBox++;
4c3c3844 940 }
ca65c044 941
4c3c3844
DE
942 if (pCurBox != pRegEnd)
943 {
ca65c044
WS
944 /*
945 * If more than one band was added, we have to find the start
946 * of the last band added so the next coalescing job can start
947 * at the right place... (given when multiple bands are added,
948 * this may be pointless -- see above).
949 */
950 pRegEnd--;
951 while (pRegEnd[-1].y1 == pRegEnd->y1)
952 {
953 pRegEnd--;
954 }
955 curStart = pRegEnd - pReg->rects;
956 pRegEnd = pReg->rects + pReg->numRects;
4c3c3844 957 }
ca65c044
WS
958
959 if ((curNumRects == prevNumRects) && (curNumRects != 0))
960 {
961 pCurBox -= curNumRects;
962 /*
963 * The bands may only be coalesced if the bottom of the previous
964 * matches the top scanline of the current.
965 */
966 if (pPrevBox->y2 == pCurBox->y1)
967 {
968 /*
969 * Make sure the bands have boxes in the same places. This
970 * assumes that boxes have been added in such a way that they
971 * cover the most area possible. I.e. two boxes in a band must
972 * have some horizontal space between them.
973 */
974 do
975 {
976 if ((pPrevBox->x1 != pCurBox->x1) ||
977 (pPrevBox->x2 != pCurBox->x2))
978 {
979 /*
980 * The bands don't line up so they can't be coalesced.
981 */
982 return (curStart);
983 }
984 pPrevBox++;
985 pCurBox++;
986 prevNumRects -= 1;
987 } while (prevNumRects != 0);
988
989 pReg->numRects -= curNumRects;
990 pCurBox -= curNumRects;
991 pPrevBox -= curNumRects;
992
993 /*
994 * The bands may be merged, so set the bottom y of each box
995 * in the previous band to that of the corresponding box in
996 * the current band.
997 */
998 do
999 {
1000 pPrevBox->y2 = pCurBox->y2;
1001 pPrevBox++;
1002 pCurBox++;
1003 curNumRects -= 1;
1004 } while (curNumRects != 0);
1005
1006 /*
1007 * If only one band was added to the region, we have to backup
1008 * curStart to the start of the previous band.
1009 *
1010 * If more than one band was added to the region, copy the
1011 * other bands down. The assumption here is that the other bands
1012 * came from the same region as the current one and no further
1013 * coalescing can be done on them since it's all been done
1014 * already... curStart is already in the right place.
1015 */
1016 if (pCurBox == pRegEnd)
1017 {
1018 curStart = prevStart;
1019 }
1020 else
1021 {
1022 do
1023 {
1024 *pPrevBox++ = *pCurBox++;
1025 } while (pCurBox != pRegEnd);
1026 }
1027
1028 }
4c3c3844
DE
1029 }
1030 return (curStart);
1031}
1032
1033/*-
1034 *-----------------------------------------------------------------------
1035 * miRegionOp --
ca65c044
WS
1036 * Apply an operation to two regions. Called by miUnion, miInverse,
1037 * miSubtract, miIntersect...
4c3c3844
DE
1038 *
1039 * Results:
ca65c044 1040 * None.
4c3c3844
DE
1041 *
1042 * Side Effects:
ca65c044 1043 * The new region is overwritten.
4c3c3844
DE
1044 *
1045 * Notes:
ca65c044
WS
1046 * The idea behind this function is to view the two regions as sets.
1047 * Together they cover a rectangle of area that this function divides
1048 * into horizontal bands where points are covered only by one region
1049 * or by both. For the first case, the nonOverlapFunc is called with
1050 * each the band and the band's upper and lower extents. For the
1051 * second, the overlapFunc is called to process the entire band. It
1052 * is responsible for clipping the rectangles in the band, though
1053 * this function provides the boundaries.
1054 * At the end of each band, the new region is coalesced, if possible,
1055 * to reduce the number of rectangles in the region.
4c3c3844
DE
1056 *
1057 *-----------------------------------------------------------------------
1058 */
1059/* static void*/
1060void REGION::
1061miRegionOp(
ca65c044
WS
1062 register Region newReg, /* Place to store result */
1063 Region reg1, /* First region in operation */
1064 Region reg2, /* 2d region in operation */
1065 int (*overlapFunc)(
4c3c3844
DE
1066 register Region pReg,
1067 register BoxPtr r1,
1068 BoxPtr r1End,
1069 register BoxPtr r2,
1070 BoxPtr r2End,
1071 wxCoord y1,
ca65c044
WS
1072 wxCoord y2), /* Function to call for over-
1073 * lapping bands */
1074 int (*nonOverlap1Func)(
4c3c3844
DE
1075 register Region pReg,
1076 register BoxPtr r,
1077 BoxPtr rEnd,
1078 register wxCoord y1,
ca65c044
WS
1079 register wxCoord y2), /* Function to call for non-
1080 * overlapping bands in region
1081 * 1 */
1082 int (*nonOverlap2Func)(
4c3c3844
DE
1083 register Region pReg,
1084 register BoxPtr r,
1085 BoxPtr rEnd,
1086 register wxCoord y1,
ca65c044
WS
1087 register wxCoord y2)) /* Function to call for non-
1088 * overlapping bands in region
1089 * 2 */
4c3c3844 1090{
ca65c044
WS
1091 register BoxPtr r1; /* Pointer into first region */
1092 register BoxPtr r2; /* Pointer into 2d region */
1093 BoxPtr r1End; /* End of 1st region */
1094 BoxPtr r2End; /* End of 2d region */
1095 register wxCoord ybot; /* Bottom of intersection */
1096 register wxCoord ytop; /* Top of intersection */
1097 BoxPtr oldRects; /* Old rects for newReg */
1098 int prevBand; /* Index of start of
1099 * previous band in newReg */
1100 int curBand; /* Index of start of current
1101 * band in newReg */
1102 register BoxPtr r1BandEnd; /* End of current band in r1 */
1103 register BoxPtr r2BandEnd; /* End of current band in r2 */
1104 wxCoord top; /* Top of non-overlapping
1105 * band */
1106 wxCoord bot; /* Bottom of non-overlapping
1107 * band */
1108
4c3c3844
DE
1109 /*
1110 * Initialization:
ca65c044 1111 * set r1, r2, r1End and r2End appropriately, preserve the important
4c3c3844
DE
1112 * parts of the destination region until the end in case it's one of
1113 * the two source regions, then mark the "new" region empty, allocating
1114 * another array of rectangles for it to use.
1115 */
1116 r1 = reg1->rects;
1117 r2 = reg2->rects;
1118 r1End = r1 + reg1->numRects;
1119 r2End = r2 + reg2->numRects;
ca65c044 1120
4c3c3844 1121 oldRects = newReg->rects;
ca65c044 1122
4c3c3844
DE
1123 EMPTY_REGION(newReg);
1124
1125 /*
1126 * Allocate a reasonable number of rectangles for the new region. The idea
1127 * is to allocate enough so the individual functions don't need to
1128 * reallocate and copy the array, which is time consuming, yet we don't
1129 * have to worry about using too much memory. I hope to be able to
1130 * nuke the realloc() at the end of this function eventually.
1131 */
1132 newReg->size = wxMax(reg1->numRects,reg2->numRects) * 2;
1133
9a6384ca
WS
1134 newReg->rects = (BoxPtr)malloc((unsigned) (sizeof(BoxRec) * newReg->size));
1135
1136 if (!newReg->rects)
1137 {
ca65c044
WS
1138 newReg->size = 0;
1139 return;
4c3c3844 1140 }
ca65c044 1141
4c3c3844
DE
1142 /*
1143 * Initialize ybot and ytop.
1144 * In the upcoming loop, ybot and ytop serve different functions depending
1145 * on whether the band being handled is an overlapping or non-overlapping
1146 * band.
ca65c044 1147 * In the case of a non-overlapping band (only one of the regions
4c3c3844
DE
1148 * has points in the band), ybot is the bottom of the most recent
1149 * intersection and thus clips the top of the rectangles in that band.
1150 * ytop is the top of the next intersection between the two regions and
1151 * serves to clip the bottom of the rectangles in the current band.
ca65c044 1152 * For an overlapping band (where the two regions intersect), ytop clips
4c3c3844
DE
1153 * the top of the rectangles of both regions and ybot clips the bottoms.
1154 */
1155 if (reg1->extents.y1 < reg2->extents.y1)
ca65c044 1156 ybot = reg1->extents.y1;
4c3c3844 1157 else
ca65c044
WS
1158 ybot = reg2->extents.y1;
1159
4c3c3844
DE
1160 /*
1161 * prevBand serves to mark the start of the previous band so rectangles
1162 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1163 * In the beginning, there is no previous band, so prevBand == curBand
1164 * (curBand is set later on, of course, but the first band will always
1165 * start at index 0). prevBand and curBand must be indices because of
1166 * the possible expansion, and resultant moving, of the new region's
1167 * array of rectangles.
1168 */
1169 prevBand = 0;
ca65c044 1170
4c3c3844
DE
1171 do
1172 {
ca65c044
WS
1173 curBand = newReg->numRects;
1174
1175 /*
1176 * This algorithm proceeds one source-band (as opposed to a
1177 * destination band, which is determined by where the two regions
1178 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1179 * rectangle after the last one in the current band for their
1180 * respective regions.
1181 */
1182 r1BandEnd = r1;
1183 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
1184 {
1185 r1BandEnd++;
1186 }
1187
1188 r2BandEnd = r2;
1189 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
1190 {
1191 r2BandEnd++;
1192 }
1193
1194 /*
1195 * First handle the band that doesn't intersect, if any.
1196 *
1197 * Note that attention is restricted to one band in the
1198 * non-intersecting region at once, so if a region has n
1199 * bands between the current position and the next place it overlaps
1200 * the other, this entire loop will be passed through n times.
1201 */
1202 if (r1->y1 < r2->y1)
1203 {
1204 top = wxMax(r1->y1,ybot);
1205 bot = wxMin(r1->y2,r2->y1);
1206
1207 if ((top != bot) && (nonOverlap1Func != NULL))
1208 {
1209 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1210 }
1211
1212 ytop = r2->y1;
1213 }
1214 else if (r2->y1 < r1->y1)
1215 {
1216 top = wxMax(r2->y1,ybot);
1217 bot = wxMin(r2->y2,r1->y1);
1218
1219 if ((top != bot) && (nonOverlap2Func != NULL))
1220 {
1221 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1222 }
1223
1224 ytop = r1->y1;
1225 }
1226 else
1227 {
1228 ytop = r1->y1;
1229 }
1230
1231 /*
1232 * If any rectangles got added to the region, try and coalesce them
1233 * with rectangles from the previous band. Note we could just do
1234 * this test in miCoalesce, but some machines incur a not
1235 * inconsiderable cost for function calls, so...
1236 */
1237 if (newReg->numRects != curBand)
1238 {
1239 prevBand = miCoalesce (newReg, prevBand, curBand);
1240 }
1241
1242 /*
1243 * Now see if we've hit an intersecting band. The two bands only
1244 * intersect if ybot > ytop
1245 */
1246 ybot = wxMin(r1->y2, r2->y2);
1247 curBand = newReg->numRects;
1248 if (ybot > ytop)
1249 {
1250 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1251
1252 }
1253
1254 if (newReg->numRects != curBand)
1255 {
1256 prevBand = miCoalesce (newReg, prevBand, curBand);
1257 }
1258
1259 /*
1260 * If we've finished with a band (y2 == ybot) we skip forward
1261 * in the region to the next band.
1262 */
1263 if (r1->y2 == ybot)
1264 {
1265 r1 = r1BandEnd;
1266 }
1267 if (r2->y2 == ybot)
1268 {
1269 r2 = r2BandEnd;
1270 }
4c3c3844
DE
1271 } while ((r1 != r1End) && (r2 != r2End));
1272
1273 /*
1274 * Deal with whichever region still has rectangles left.
1275 */
1276 curBand = newReg->numRects;
1277 if (r1 != r1End)
1278 {
ca65c044
WS
1279 if (nonOverlap1Func != NULL)
1280 {
1281 do
1282 {
1283 r1BandEnd = r1;
1284 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
1285 {
1286 r1BandEnd++;
1287 }
1288 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1289 wxMax(r1->y1,ybot), r1->y2);
1290 r1 = r1BandEnd;
1291 } while (r1 != r1End);
1292 }
4c3c3844
DE
1293 }
1294 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
1295 {
ca65c044
WS
1296 do
1297 {
1298 r2BandEnd = r2;
1299 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
1300 {
1301 r2BandEnd++;
1302 }
1303 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1304 wxMax(r2->y1,ybot), r2->y2);
1305 r2 = r2BandEnd;
1306 } while (r2 != r2End);
4c3c3844
DE
1307 }
1308
1309 if (newReg->numRects != curBand)
1310 {
ca65c044 1311 (void) miCoalesce (newReg, prevBand, curBand);
4c3c3844
DE
1312 }
1313
1314 /*
1315 * A bit of cleanup. To keep regions from growing without bound,
1316 * we shrink the array of rectangles to match the new number of
1317 * rectangles in the region. This never goes to 0, however...
1318 *
1319 * Only do this stuff if the number of rectangles allocated is more than
1320 * twice the number of rectangles in the region (a simple optimization...).
1321 */
1322 if (newReg->numRects < (newReg->size >> 1))
1323 {
ca65c044
WS
1324 if (REGION_NOT_EMPTY(newReg))
1325 {
1326 BoxPtr prev_rects = newReg->rects;
1327 newReg->size = newReg->numRects;
1328 newReg->rects = (BoxPtr) realloc ((char *) newReg->rects,
1329 (unsigned) (sizeof(BoxRec) * newReg->size));
1330 if (! newReg->rects)
1331 newReg->rects = prev_rects;
1332 }
1333 else
1334 {
1335 /*
1336 * No point in doing the extra work involved in an realloc if
1337 * the region is empty
1338 */
1339 newReg->size = 1;
1340 free((char *) newReg->rects);
1341 newReg->rects = (BoxPtr) malloc(sizeof(BoxRec));
1342 }
4c3c3844
DE
1343 }
1344 free ((char *) oldRects);
1345 return;
1346}
1347
1348/*======================================================================
ca65c044 1349 * Region Union
4c3c3844
DE
1350 *====================================================================*/
1351
1352/*-
1353 *-----------------------------------------------------------------------
1354 * miUnionNonO --
ca65c044
WS
1355 * Handle a non-overlapping band for the union operation. Just
1356 * Adds the rectangles into the region. Doesn't have to check for
1357 * subsumption or anything.
4c3c3844
DE
1358 *
1359 * Results:
ca65c044 1360 * None.
4c3c3844
DE
1361 *
1362 * Side Effects:
ca65c044
WS
1363 * pReg->numRects is incremented and the final rectangles overwritten
1364 * with the rectangles we're passed.
4c3c3844
DE
1365 *
1366 *-----------------------------------------------------------------------
1367 */
1368/* static void*/
1369int REGION::
1370miUnionNonO (
ca65c044
WS
1371 register Region pReg,
1372 register BoxPtr r,
1373 BoxPtr rEnd,
1374 register wxCoord y1,
1375 register wxCoord y2)
4c3c3844 1376{
ca65c044 1377 register BoxPtr pNextRect;
4c3c3844
DE
1378
1379 pNextRect = &pReg->rects[pReg->numRects];
1380
2e587bb9 1381 wxASSERT_LEVEL_2(y1 < y2);
4c3c3844
DE
1382
1383 while (r != rEnd)
1384 {
2e587bb9 1385 wxASSERT_LEVEL_2(r->x1 < r->x2);
ca65c044
WS
1386 MEMCHECK(pReg, pNextRect, pReg->rects);
1387 pNextRect->x1 = r->x1;
1388 pNextRect->y1 = y1;
1389 pNextRect->x2 = r->x2;
1390 pNextRect->y2 = y2;
1391 pReg->numRects += 1;
1392 pNextRect++;
1393
2e587bb9 1394 wxASSERT_LEVEL_2(pReg->numRects<=pReg->size);
ca65c044 1395 r++;
4c3c3844 1396 }
ca65c044 1397 return 0; /* lint */
4c3c3844
DE
1398}
1399
1400
1401/*-
1402 *-----------------------------------------------------------------------
1403 * miUnionO --
ca65c044
WS
1404 * Handle an overlapping band for the union operation. Picks the
1405 * left-most rectangle each time and merges it into the region.
4c3c3844
DE
1406 *
1407 * Results:
ca65c044 1408 * None.
4c3c3844
DE
1409 *
1410 * Side Effects:
ca65c044
WS
1411 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1412 * be changed.
4c3c3844
DE
1413 *
1414 *-----------------------------------------------------------------------
1415 */
1416
1417/* static void*/
1418int REGION::
1419miUnionO (
ca65c044
WS
1420 register Region pReg,
1421 register BoxPtr r1,
1422 BoxPtr r1End,
1423 register BoxPtr r2,
1424 BoxPtr r2End,
1425 register wxCoord y1,
1426 register wxCoord y2)
4c3c3844 1427{
ca65c044
WS
1428 register BoxPtr pNextRect;
1429
4c3c3844
DE
1430 pNextRect = &pReg->rects[pReg->numRects];
1431
1432#define MERGERECT(r) \
1433 if ((pReg->numRects != 0) && \
ca65c044
WS
1434 (pNextRect[-1].y1 == y1) && \
1435 (pNextRect[-1].y2 == y2) && \
1436 (pNextRect[-1].x2 >= r->x1)) \
4c3c3844 1437 { \
ca65c044
WS
1438 if (pNextRect[-1].x2 < r->x2) \
1439 { \
1440 pNextRect[-1].x2 = r->x2; \
2e587bb9 1441 wxASSERT_LEVEL_2(pNextRect[-1].x1<pNextRect[-1].x2); \
ca65c044 1442 } \
4c3c3844
DE
1443 } \
1444 else \
1445 { \
ca65c044
WS
1446 MEMCHECK(pReg, pNextRect, pReg->rects); \
1447 pNextRect->y1 = y1; \
1448 pNextRect->y2 = y2; \
1449 pNextRect->x1 = r->x1; \
1450 pNextRect->x2 = r->x2; \
1451 pReg->numRects += 1; \
4c3c3844
DE
1452 pNextRect += 1; \
1453 } \
2e587bb9 1454 wxASSERT_LEVEL_2(pReg->numRects<=pReg->size);\
4c3c3844 1455 r++;
ca65c044 1456
2e587bb9 1457 wxASSERT_LEVEL_2 (y1<y2);
4c3c3844
DE
1458 while ((r1 != r1End) && (r2 != r2End))
1459 {
ca65c044
WS
1460 if (r1->x1 < r2->x1)
1461 {
1462 MERGERECT(r1);
1463 }
1464 else
1465 {
1466 MERGERECT(r2);
1467 }
4c3c3844 1468 }
ca65c044 1469
4c3c3844
DE
1470 if (r1 != r1End)
1471 {
ca65c044
WS
1472 do
1473 {
1474 MERGERECT(r1);
1475 } while (r1 != r1End);
4c3c3844
DE
1476 }
1477 else while (r2 != r2End)
1478 {
ca65c044 1479 MERGERECT(r2);
4c3c3844 1480 }
ca65c044 1481 return 0; /* lint */
4c3c3844
DE
1482}
1483
1484bool REGION::
1485XUnionRegion(
ca65c044
WS
1486 Region reg1,
1487 Region reg2, /* source regions */
1488 Region newReg) /* destination Region */
4c3c3844
DE
1489{
1490 /* checks all the simple cases */
1491
1492 /*
1493 * Region 1 and 2 are the same or region 1 is empty
1494 */
1495 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1496 {
1497 if (newReg != reg2)
1498 miRegionCopy(newReg, reg2);
1499 return 1;
1500 }
1501
1502 /*
1503 * if nothing to union (region 2 empty)
1504 */
1505 if (!(reg2->numRects))
1506 {
1507 if (newReg != reg1)
1508 miRegionCopy(newReg, reg1);
1509 return 1;
1510 }
1511
1512 /*
1513 * Region 1 completely subsumes region 2
1514 */
ca65c044
WS
1515 if ((reg1->numRects == 1) &&
1516 (reg1->extents.x1 <= reg2->extents.x1) &&
1517 (reg1->extents.y1 <= reg2->extents.y1) &&
1518 (reg1->extents.x2 >= reg2->extents.x2) &&
1519 (reg1->extents.y2 >= reg2->extents.y2))
4c3c3844
DE
1520 {
1521 if (newReg != reg1)
1522 miRegionCopy(newReg, reg1);
1523 return 1;
1524 }
1525
1526 /*
1527 * Region 2 completely subsumes region 1
1528 */
ca65c044
WS
1529 if ((reg2->numRects == 1) &&
1530 (reg2->extents.x1 <= reg1->extents.x1) &&
1531 (reg2->extents.y1 <= reg1->extents.y1) &&
1532 (reg2->extents.x2 >= reg1->extents.x2) &&
1533 (reg2->extents.y2 >= reg1->extents.y2))
4c3c3844
DE
1534 {
1535 if (newReg != reg2)
1536 miRegionCopy(newReg, reg2);
1537 return 1;
1538 }
1539
ca65c044
WS
1540 miRegionOp (newReg, reg1, reg2, miUnionO,
1541 miUnionNonO, miUnionNonO);
4c3c3844
DE
1542
1543 newReg->extents.x1 = wxMin(reg1->extents.x1, reg2->extents.x1);
1544 newReg->extents.y1 = wxMin(reg1->extents.y1, reg2->extents.y1);
1545 newReg->extents.x2 = wxMax(reg1->extents.x2, reg2->extents.x2);
1546 newReg->extents.y2 = wxMax(reg1->extents.y2, reg2->extents.y2);
1547
1548 return 1;
1549}
1550
1551/*======================================================================
ca65c044 1552 * Region Subtraction
4c3c3844
DE
1553 *====================================================================*/
1554
1555/*-
1556 *-----------------------------------------------------------------------
1557 * miSubtractNonO --
ca65c044
WS
1558 * Deal with non-overlapping band for subtraction. Any parts from
1559 * region 2 we discard. Anything from region 1 we add to the region.
4c3c3844
DE
1560 *
1561 * Results:
ca65c044 1562 * None.
4c3c3844
DE
1563 *
1564 * Side Effects:
ca65c044 1565 * pReg may be affected.
4c3c3844
DE
1566 *
1567 *-----------------------------------------------------------------------
1568 */
1569/* static void*/
1570int REGION::
1571miSubtractNonO1 (
ca65c044
WS
1572 register Region pReg,
1573 register BoxPtr r,
1574 BoxPtr rEnd,
1575 register wxCoord y1,
1576 register wxCoord y2)
4c3c3844 1577{
ca65c044
WS
1578 register BoxPtr pNextRect;
1579
4c3c3844 1580 pNextRect = &pReg->rects[pReg->numRects];
ca65c044 1581
2e587bb9 1582 wxASSERT_LEVEL_2(y1<y2);
4c3c3844
DE
1583
1584 while (r != rEnd)
1585 {
2e587bb9 1586 wxASSERT_LEVEL_2(r->x1<r->x2);
ca65c044
WS
1587 MEMCHECK(pReg, pNextRect, pReg->rects);
1588 pNextRect->x1 = r->x1;
1589 pNextRect->y1 = y1;
1590 pNextRect->x2 = r->x2;
1591 pNextRect->y2 = y2;
1592 pReg->numRects += 1;
1593 pNextRect++;
1594
2e587bb9 1595 wxASSERT_LEVEL_2(pReg->numRects <= pReg->size);
ca65c044
WS
1596
1597 r++;
4c3c3844 1598 }
ca65c044 1599 return 0; /* lint */
4c3c3844
DE
1600}
1601
1602/*-
1603 *-----------------------------------------------------------------------
1604 * miSubtractO --
ca65c044
WS
1605 * Overlapping band subtraction. x1 is the left-most point not yet
1606 * checked.
4c3c3844
DE
1607 *
1608 * Results:
ca65c044 1609 * None.
4c3c3844
DE
1610 *
1611 * Side Effects:
ca65c044 1612 * pReg may have rectangles added to it.
4c3c3844
DE
1613 *
1614 *-----------------------------------------------------------------------
1615 */
1616/* static void*/
1617int REGION::
1618miSubtractO (
ca65c044
WS
1619 register Region pReg,
1620 register BoxPtr r1,
1621 BoxPtr r1End,
1622 register BoxPtr r2,
1623 BoxPtr r2End,
1624 register wxCoord y1,
1625 register wxCoord y2)
4c3c3844 1626{
ca65c044
WS
1627 register BoxPtr pNextRect;
1628 register int x1;
1629
4c3c3844 1630 x1 = r1->x1;
ca65c044 1631
2e587bb9 1632 wxASSERT_LEVEL_2(y1<y2);
4c3c3844
DE
1633 pNextRect = &pReg->rects[pReg->numRects];
1634
1635 while ((r1 != r1End) && (r2 != r2End))
1636 {
ca65c044
WS
1637 if (r2->x2 <= x1)
1638 {
1639 /*
1640 * Subtrahend missed the boat: go to next subtrahend.
1641 */
1642 r2++;
1643 }
1644 else if (r2->x1 <= x1)
1645 {
1646 /*
e75e8815 1647 * Subtrahend precedes minuend: nuke left edge of minuend.
ca65c044
WS
1648 */
1649 x1 = r2->x2;
1650 if (x1 >= r1->x2)
1651 {
1652 /*
1653 * Minuend completely covered: advance to next minuend and
1654 * reset left fence to edge of new minuend.
1655 */
1656 r1++;
1657 if (r1 != r1End)
1658 x1 = r1->x1;
1659 }
1660 else
1661 {
1662 /*
1663 * Subtrahend now used up since it doesn't extend beyond
1664 * minuend
1665 */
1666 r2++;
1667 }
1668 }
1669 else if (r2->x1 < r1->x2)
1670 {
1671 /*
1672 * Left part of subtrahend covers part of minuend: add uncovered
1673 * part of minuend to region and skip to next subtrahend.
1674 */
2e587bb9 1675 wxASSERT_LEVEL_2(x1<r2->x1);
ca65c044
WS
1676 MEMCHECK(pReg, pNextRect, pReg->rects);
1677 pNextRect->x1 = x1;
1678 pNextRect->y1 = y1;
1679 pNextRect->x2 = r2->x1;
1680 pNextRect->y2 = y2;
1681 pReg->numRects += 1;
1682 pNextRect++;
1683
2e587bb9 1684 wxASSERT_LEVEL_2(pReg->numRects<=pReg->size);
ca65c044
WS
1685
1686 x1 = r2->x2;
1687 if (x1 >= r1->x2)
1688 {
1689 /*
1690 * Minuend used up: advance to new...
1691 */
1692 r1++;
1693 if (r1 != r1End)
1694 x1 = r1->x1;
1695 }
1696 else
1697 {
1698 /*
1699 * Subtrahend used up
1700 */
1701 r2++;
1702 }
1703 }
1704 else
1705 {
1706 /*
1707 * Minuend used up: add any remaining piece before advancing.
1708 */
1709 if (r1->x2 > x1)
1710 {
1711 MEMCHECK(pReg, pNextRect, pReg->rects);
1712 pNextRect->x1 = x1;
1713 pNextRect->y1 = y1;
1714 pNextRect->x2 = r1->x2;
1715 pNextRect->y2 = y2;
1716 pReg->numRects += 1;
1717 pNextRect++;
2e587bb9 1718 wxASSERT_LEVEL_2(pReg->numRects<=pReg->size);
ca65c044
WS
1719 }
1720 r1++;
1721 if (r1 != r1End)
1722 x1 = r1->x1;
1723 }
4c3c3844
DE
1724 }
1725
1726 /*
1727 * Add remaining minuend rectangles to region.
1728 */
1729 while (r1 != r1End)
1730 {
2e587bb9 1731 wxASSERT_LEVEL_2(x1<r1->x2);
ca65c044
WS
1732 MEMCHECK(pReg, pNextRect, pReg->rects);
1733 pNextRect->x1 = x1;
1734 pNextRect->y1 = y1;
1735 pNextRect->x2 = r1->x2;
1736 pNextRect->y2 = y2;
1737 pReg->numRects += 1;
1738 pNextRect++;
1739
2e587bb9 1740 wxASSERT_LEVEL_2(pReg->numRects<=pReg->size);
ca65c044
WS
1741
1742 r1++;
1743 if (r1 != r1End)
1744 {
1745 x1 = r1->x1;
1746 }
4c3c3844 1747 }
ca65c044 1748 return 0; /* lint */
4c3c3844 1749}
ca65c044 1750
4c3c3844
DE
1751/*-
1752 *-----------------------------------------------------------------------
1753 * miSubtract --
ca65c044
WS
1754 * Subtract regS from regM and leave the result in regD.
1755 * S stands for subtrahend, M for minuend and D for difference.
4c3c3844
DE
1756 *
1757 * Results:
ca65c044 1758 * true.
4c3c3844
DE
1759 *
1760 * Side Effects:
ca65c044 1761 * regD is overwritten.
4c3c3844
DE
1762 *
1763 *-----------------------------------------------------------------------
1764 */
1765
9a6384ca 1766bool REGION::XSubtractRegion(Region regM, Region regS, register Region regD)
4c3c3844
DE
1767{
1768 /* check for trivial reject */
1769 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
ca65c044 1770 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
4c3c3844 1771 {
ca65c044 1772 miRegionCopy(regD, regM);
4c3c3844
DE
1773 return true;
1774 }
ca65c044
WS
1775
1776 miRegionOp (regD, regM, regS, miSubtractO,
1777 miSubtractNonO1, NULL);
4c3c3844
DE
1778
1779 /*
1780 * Can't alter newReg's extents before we call miRegionOp because
1781 * it might be one of the source regions and miRegionOp depends
1782 * on the extents of those regions being the unaltered. Besides, this
1783 * way there's no checking against rectangles that will be nuked
1784 * due to coalescing, so we have to examine fewer rectangles.
1785 */
1786 miSetExtents (regD);
1787 return true;
1788}
1789
9a6384ca 1790bool REGION::XXorRegion(Region sra, Region srb, Region dr)
4c3c3844 1791{
9a6384ca
WS
1792 Region tra = XCreateRegion();
1793
1794 wxCHECK_MSG( tra, false, wxT("region not created") );
1795
1796 Region trb = XCreateRegion();
1797
1798 wxCHECK_MSG( trb, false, wxT("region not created") );
4c3c3844 1799
4c3c3844
DE
1800 (void) XSubtractRegion(sra,srb,tra);
1801 (void) XSubtractRegion(srb,sra,trb);
1802 (void) XUnionRegion(tra,trb,dr);
1803 XDestroyRegion(tra);
1804 XDestroyRegion(trb);
1805 return 0;
1806}
1807
1808/*
ca65c044 1809 * Check to see if the region is empty. Assumes a region is passed
4c3c3844
DE
1810 * as a parameter
1811 */
9a6384ca 1812bool REGION::XEmptyRegion(Region r)
4c3c3844
DE
1813{
1814 if( r->numRects == 0 ) return true;
1815 else return false;
1816}
1817
1818/*
ca65c044 1819 * Check to see if two regions are equal
4c3c3844 1820 */
9a6384ca 1821bool REGION::XEqualRegion(Region r1, Region r2)
4c3c3844
DE
1822{
1823 int i;
1824
1825 if( r1->numRects != r2->numRects ) return false;
1826 else if( r1->numRects == 0 ) return true;
1827 else if ( r1->extents.x1 != r2->extents.x1 ) return false;
1828 else if ( r1->extents.x2 != r2->extents.x2 ) return false;
1829 else if ( r1->extents.y1 != r2->extents.y1 ) return false;
1830 else if ( r1->extents.y2 != r2->extents.y2 ) return false;
1831 else for( i=0; i < r1->numRects; i++ ) {
ca65c044
WS
1832 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return false;
1833 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return false;
1834 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return false;
1835 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return false;
4c3c3844
DE
1836 }
1837 return true;
1838}
1839
9a6384ca 1840bool REGION::XPointInRegion(Region pRegion, int x, int y)
4c3c3844
DE
1841{
1842 int i;
1843
1844 if (pRegion->numRects == 0)
1845 return false;
1846 if (!INBOX(pRegion->extents, x, y))
1847 return false;
1848 for (i=0; i<pRegion->numRects; i++)
1849 {
1850 if (INBOX (pRegion->rects[i], x, y))
ca65c044 1851 return true;
4c3c3844
DE
1852 }
1853 return false;
1854}
1855
9a6384ca
WS
1856wxRegionContain REGION::XRectInRegion(register Region region,
1857 int rx, int ry,
1858 unsigned int rwidth,
1859 unsigned int rheight)
4c3c3844
DE
1860{
1861 register BoxPtr pbox;
1862 register BoxPtr pboxEnd;
1863 Box rect;
1864 register BoxPtr prect = &rect;
1865 int partIn, partOut;
1866
1867 prect->x1 = rx;
1868 prect->y1 = ry;
1869 prect->x2 = rwidth + rx;
1870 prect->y2 = rheight + ry;
ca65c044 1871
4c3c3844
DE
1872 /* this is (just) a useful optimization */
1873 if ((region->numRects == 0) || !EXTENTCHECK(&region->extents, prect))
1874 return(wxOutRegion);
1875
ca65c044
WS
1876 partOut = false;
1877 partIn = false;
4c3c3844 1878
ca65c044 1879 /* can stop when both partOut and partIn are true, or we reach prect->y2 */
4c3c3844 1880 for (pbox = region->rects, pboxEnd = pbox + region->numRects;
ca65c044
WS
1881 pbox < pboxEnd;
1882 pbox++)
4c3c3844
DE
1883 {
1884
ca65c044
WS
1885 if (pbox->y2 <= ry)
1886 continue; /* getting up to speed or skipping remainder of band */
1887
1888 if (pbox->y1 > ry)
1889 {
1890 partOut = true; /* missed part of rectangle above */
1891 if (partIn || (pbox->y1 >= prect->y2))
1892 break;
1893 ry = pbox->y1; /* x guaranteed to be == prect->x1 */
1894 }
1895
1896 if (pbox->x2 <= rx)
1897 continue; /* not far enough over yet */
1898
1899 if (pbox->x1 > rx)
1900 {
1901 partOut = true; /* missed part of rectangle to left */
1902 if (partIn)
1903 break;
1904 }
1905
1906 if (pbox->x1 < prect->x2)
1907 {
1908 partIn = true; /* definitely overlap */
1909 if (partOut)
1910 break;
1911 }
1912
1913 if (pbox->x2 >= prect->x2)
1914 {
1915 ry = pbox->y2; /* finished with this band */
1916 if (ry >= prect->y2)
1917 break;
1918 rx = prect->x1; /* reset x out to left again */
1919 } else
1920 {
1921 /*
1922 * Because boxes in a band are maximal width, if the first box
1923 * to overlap the rectangle doesn't completely cover it in that
1924 * band, the rectangle must be partially out, since some of it
1925 * will be uncovered in that band. partIn will have been set true
1926 * by now...
1927 */
1928 break;
1929 }
4c3c3844
DE
1930
1931 }
1932
ca65c044
WS
1933 return(partIn ? ((ry < prect->y2) ? wxPartRegion : wxInRegion) :
1934 wxOutRegion);
4c3c3844 1935}