1 /////////////////////////////////////////////////////////////////////////////
2 // File: src/osx/carbon/region.cpp
3 // Purpose: Region class
4 // Author: Stefan Csomor
5 // Created: Fri Oct 24 10:46:34 MET 1997
6 // Copyright: (c) 1997 Stefan Csomor
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
12 #if wxOSX_USE_COCOA_OR_CARBON
14 #include "wx/region.h"
17 #include "wx/gdicmn.h"
18 #include "wx/dcmemory.h"
21 #include "wx/osx/private.h"
23 IMPLEMENT_DYNAMIC_CLASS(wxRegion
, wxGDIObject
)
24 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator
, wxObject
)
26 #define OSX_USE_SCANLINES 1
28 //-----------------------------------------------------------------------------
29 // wxRegionRefData implementation
30 //-----------------------------------------------------------------------------
32 class WXDLLEXPORT wxRegionRefData
: public wxGDIRefData
37 m_macRgn
.reset( HIShapeCreateMutable() );
40 wxRegionRefData(wxCFRef
<HIShapeRef
> ®ion
)
42 m_macRgn
.reset( HIShapeCreateMutableCopy(region
) );
45 wxRegionRefData(long x
, long y
, long w
, long h
)
47 CGRect r
= CGRectMake(x
,y
,w
,h
);
48 wxCFRef
<HIShapeRef
> rect(HIShapeCreateWithRect(&r
));
49 m_macRgn
.reset( HIShapeCreateMutableCopy(rect
) );
52 wxRegionRefData(const wxRegionRefData
& data
)
55 m_macRgn
.reset( HIShapeCreateMutableCopy(data
.m_macRgn
) );
58 virtual ~wxRegionRefData()
62 wxCFRef
<HIMutableShapeRef
> m_macRgn
;
65 #define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
66 #define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn)
68 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
72 wxRegion::wxRegion(WXHRGN hRegion
)
74 wxCFRef
< HIShapeRef
> shape( (HIShapeRef
) hRegion
);
75 m_refData
= new wxRegionRefData(shape
);
78 wxRegion::wxRegion(long x
, long y
, long w
, long h
)
80 m_refData
= new wxRegionRefData(x
, y
, w
, h
);
83 wxRegion::wxRegion(const wxPoint
& topLeft
, const wxPoint
& bottomRight
)
85 m_refData
= new wxRegionRefData(topLeft
.x
, topLeft
.y
,
86 bottomRight
.x
- topLeft
.x
,
87 bottomRight
.y
- topLeft
.y
);
90 wxRegion::wxRegion(const wxRect
& rect
)
92 m_refData
= new wxRegionRefData(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
99 Copyright 1987, 1998 The Open Group
101 Permission to use, copy, modify, distribute, and sell this software and its
102 documentation for any purpose is hereby granted without fee, provided that
103 the above copyright notice appear in all copies and that both that
104 copyright notice and this permission notice appear in supporting
107 The above copyright notice and this permission notice shall be included
108 in all copies or substantial portions of the Software.
110 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
111 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
112 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
113 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
114 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
115 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
116 OTHER DEALINGS IN THE SOFTWARE.
118 Except as contained in this notice, the name of The Open Group shall
119 not be used in advertising or otherwise to promote the sale, use or
120 other dealings in this Software without prior written authorization
130 * Written by Brian Kelleher; Jan 1985
132 * This file contains a few macros to help track
133 * the edge of a filled object. The object is assumed
134 * to be filled in scanline order, and thus the
135 * algorithm used is an extension of Bresenham's line
136 * drawing algorithm which assumes that y is always the
138 * Since these pieces of code are the same for any filled shape,
139 * it is more convenient to gather the library in one
140 * place, but since these pieces of code are also in
141 * the inner loops of output primitives, procedure call
142 * overhead is out of the question.
143 * See the author for a derivation if needed.
148 * In scan converting polygons, we want to choose those pixels
149 * which are inside the polygon. Thus, we add .5 to the starting
150 * x coordinate for both left and right edges. Now we choose the
151 * first pixel which is inside the pgon for the left edge and the
152 * first pixel which is outside the pgon for the right edge.
153 * Draw the left pixel, but not the right.
155 * How to add .5 to the starting x coordinate:
156 * If the edge is moving to the right, then subtract dy from the
157 * error term from the general form of the algorithm.
158 * If the edge is moving to the left, then add dy to the error term.
160 * The reason for the difference between edges moving to the left
161 * and edges moving to the right is simple: If an edge is moving
162 * to the right, then we want the algorithm to flip immediately.
163 * If it is moving to the left, then we don't want it to flip until
164 * we traverse an entire pixel.
166 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
167 int dx; /* local storage */ \
170 * if the edge is horizontal, then it is ignored \
171 * and assumed not to be processed. Otherwise, do this stuff. \
175 dx = (x2) - xStart; \
179 incr1 = -2 * dx + 2 * (dy) * m1; \
180 incr2 = -2 * dx + 2 * (dy) * m; \
181 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
185 incr1 = 2 * dx - 2 * (dy) * m1; \
186 incr2 = 2 * dx - 2 * (dy) * m; \
187 d = -2 * m * (dy) + 2 * dx; \
192 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
216 * This structure contains all of the information needed
217 * to run the bresenham algorithm.
218 * The variables may be hardcoded into the declarations
219 * instead of using this structure to make use of
220 * register declarations.
223 int minor
; /* minor axis */
224 int d
; /* decision variable */
225 int m
, m1
; /* slope and slope+1 */
226 int incr1
, incr2
; /* error increments */
230 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
231 BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
232 bres.m, bres.m1, bres.incr1, bres.incr2)
234 #define BRESINCRPGONSTRUCT(bres) \
235 BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
243 * Created by Brian Kelleher; Oct 1985
245 * Include file for filled polygon routines.
247 * These are the data structures needed to scan
248 * convert regions. Two different scan conversion
249 * methods are available -- the even-odd method, and
250 * the winding number method.
251 * The even-odd rule states that a point is inside
252 * the polygon if a ray drawn from that point in any
253 * direction will pass through an odd number of
255 * By the winding number rule, a point is decided
256 * to be inside the polygon if a ray drawn from that
257 * point in any direction passes through a different
258 * number of clockwise and counter-clockwise path
261 * These data structures are adapted somewhat from
262 * the algorithm in (Foley/Van Dam) for scan converting
264 * The basic algorithm is to start at the top (smallest y)
265 * of the polygon, stepping down to the bottom of
266 * the polygon by incrementing the y coordinate. We
267 * keep a list of edges which the current scanline crosses,
268 * sorted by x. This list is called the Active Edge Table (AET)
269 * As we change the y-coordinate, we update each entry in
270 * in the active edge table to reflect the edges new xcoord.
271 * This list must be sorted at each scanline in case
272 * two edges intersect.
273 * We also keep a data structure known as the Edge Table (ET),
274 * which keeps track of all the edges which the current
275 * scanline has not yet reached. The ET is basically a
276 * list of ScanLineList structures containing a list of
277 * edges which are entered at a given scanline. There is one
278 * ScanLineList per scanline at which an edge is entered.
279 * When we enter a new edge, we move it from the ET to the AET.
281 * From the AET, we can implement the even-odd rule as in
283 * The winding number rule is a little trickier. We also
284 * keep the EdgeTableEntries in the AET linked by the
285 * nextWETE (winding EdgeTableEntry) link. This allows
286 * the edges to be linked just as before for updating
287 * purposes, but only uses the edges linked by the nextWETE
288 * link as edges representing spans of the polygon to
289 * drawn (as with the even-odd rule).
293 * for the winding number rule
296 #define COUNTERCLOCKWISE -1
298 typedef struct _EdgeTableEntry
{
299 int ymax
; /* ycoord at which we exit this edge. */
300 BRESINFO bres
; /* Bresenham info to run the edge */
301 struct _EdgeTableEntry
*next
; /* next in the list */
302 struct _EdgeTableEntry
*back
; /* for insertion sort */
303 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
304 int ClockWise
; /* flag for winding number rule */
308 typedef struct _ScanLineList
{
309 int scanline
; /* the scanline represented */
310 EdgeTableEntry
*edgelist
; /* header node */
311 struct _ScanLineList
*next
; /* next in the list */
316 int ymax
; /* ymax for the polygon */
317 int ymin
; /* ymin for the polygon */
318 ScanLineList scanlines
; /* header node */
323 * Here is a struct to help with storage allocation
324 * so we can allocate a big chunk at a time, and then take
325 * pieces from this heap when we need to.
327 #define SLLSPERBLOCK 25
329 typedef struct _ScanLineListBlock
{
330 ScanLineList SLLs
[SLLSPERBLOCK
];
331 struct _ScanLineListBlock
*next
;
335 * number of points to buffer before sending them off
336 * to scanlines() : Must be an even number
338 #define NUMPTSTOBUFFER 200
343 * a few macros for the inner loops of the fill code where
344 * performance considerations don't allow a procedure call.
346 * Evaluate the given edge at the given scanline.
347 * If the edge has expired, then we leave it and fix up
348 * the active edge table; otherwise, we increment the
349 * x value to be ready for the next scanline.
350 * The winding number rule is in effect, so we must notify
351 * the caller when the edge has been removed so he
352 * can reorder the Winding Active Edge Table.
354 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
355 if (pAET->ymax == y) { /* leaving this edge */ \
356 pPrevAET->next = pAET->next; \
357 pAET = pPrevAET->next; \
360 pAET->back = pPrevAET; \
363 BRESINCRPGONSTRUCT(pAET->bres); \
371 * Evaluate the given edge at the given scanline.
372 * If the edge has expired, then we leave it and fix up
373 * the active edge table; otherwise, we increment the
374 * x value to be ready for the next scanline.
375 * The even-odd rule is in effect.
377 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
378 if (pAET->ymax == y) { /* leaving this edge */ \
379 pPrevAET->next = pAET->next; \
380 pAET = pPrevAET->next; \
382 pAET->back = pPrevAET; \
385 BRESINCRPGONSTRUCT(pAET->bres); \
393 static bool miCreateETandAET(
395 const wxPoint
* /*pts*/,
397 EdgeTableEntry
* /*AET*/,
398 EdgeTableEntry
* /*pETEs*/,
399 ScanLineListBlock
* /*pSLLBlock*/
402 static void miloadAET(
403 EdgeTableEntry
* /*AET*/,
404 EdgeTableEntry
* /*ETEs*/
407 static void micomputeWAET(
408 EdgeTableEntry
* /*AET*/
411 static int miInsertionSort(
412 EdgeTableEntry
* /*AET*/
415 static void miFreeStorage(
416 ScanLineListBlock
* /*pSLLBlock*/
422 * Written by Brian Kelleher; Oct. 1985
424 * This module contains all of the utility functions
425 * needed to scan convert a polygon.
432 * Insert the given edge into the edge table.
433 * First we must find the correct bucket in the
434 * Edge table, then find the right slot in the
435 * bucket. Finally, we can insert it.
439 miInsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
, int scanline
,
440 ScanLineListBlock
**SLLBlock
, int *iSLLBlock
)
442 EdgeTableEntry
*start
, *prev
;
443 ScanLineList
*pSLL
, *pPrevSLL
;
444 ScanLineListBlock
*tmpSLLBlock
;
447 * find the right bucket to put the edge into
449 pPrevSLL
= &ET
->scanlines
;
450 pSLL
= pPrevSLL
->next
;
451 while (pSLL
&& (pSLL
->scanline
< scanline
))
458 * reassign pSLL (pointer to ScanLineList) if necessary
460 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
462 if (*iSLLBlock
> SLLSPERBLOCK
-1)
465 (ScanLineListBlock
*)malloc(sizeof(ScanLineListBlock
));
468 (*SLLBlock
)->next
= tmpSLLBlock
;
469 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
470 *SLLBlock
= tmpSLLBlock
;
473 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
475 pSLL
->next
= pPrevSLL
->next
;
476 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
477 pPrevSLL
->next
= pSLL
;
479 pSLL
->scanline
= scanline
;
482 * now insert the edge in the right bucket
484 prev
= (EdgeTableEntry
*)NULL
;
485 start
= pSLL
->edgelist
;
486 while (start
&& (start
->bres
.minor
< ETE
->bres
.minor
))
496 pSLL
->edgelist
= ETE
;
503 * This routine creates the edge table for
504 * scan converting polygons.
505 * The Edge Table (ET) looks like:
509 * | ymax | ScanLineLists
510 * |scanline|-->------------>-------------->...
511 * -------- |scanline| |scanline|
512 * |edgelist| |edgelist|
513 * --------- ---------
517 * list of ETEs list of ETEs
519 * where ETE is an EdgeTableEntry data structure,
520 * and there is one ScanLineList per scanline at
521 * which an edge is initially entered.
526 miCreateETandAET(int count
, const wxPoint
* pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
527 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
529 const wxPoint
* top
, *bottom
;
530 const wxPoint
* PrevPt
, *CurrPt
;
535 if (count
< 2) return TRUE
;
538 * initialize the Active Edge Table
540 AET
->next
= (EdgeTableEntry
*)NULL
;
541 AET
->back
= (EdgeTableEntry
*)NULL
;
542 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
543 AET
->bres
.minor
= INT_MIN
;
546 * initialize the Edge Table.
548 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
551 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
553 PrevPt
= &pts
[count
-1];
556 * for each vertex in the array of points.
557 * In this loop we are dealing with two vertices at
558 * a time -- these make up one edge of the polygon.
565 * find out which point is above and which is below.
567 if (PrevPt
->y
> CurrPt
->y
)
569 bottom
= PrevPt
, top
= CurrPt
;
570 pETEs
->ClockWise
= 0;
574 bottom
= CurrPt
, top
= PrevPt
;
575 pETEs
->ClockWise
= 1;
579 * don't add horizontal edges to the Edge table.
581 if (bottom
->y
!= top
->y
)
583 pETEs
->ymax
= bottom
->y
-1; /* -1 so we don't get last scanline */
586 * initialize integer edge algorithm
588 dy
= bottom
->y
- top
->y
;
589 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
591 if (!miInsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
, &iSLLBlock
))
593 miFreeStorage(pSLLBlock
->next
);
597 ET
->ymax
= wxMax(ET
->ymax
, PrevPt
->y
);
598 ET
->ymin
= wxMin(ET
->ymin
, PrevPt
->y
);
610 * This routine moves EdgeTableEntries from the
611 * EdgeTable into the Active Edge Table,
612 * leaving them sorted by smaller x coordinate.
617 miloadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
619 EdgeTableEntry
*pPrevAET
;
626 while (AET
&& (AET
->bres
.minor
< ETEs
->bres
.minor
))
635 ETEs
->back
= pPrevAET
;
636 pPrevAET
->next
= ETEs
;
646 * This routine links the AET by the
647 * nextWETE (winding EdgeTableEntry) link for
648 * use by the winding number rule. The final
649 * Active Edge Table (AET) might look something
653 * ---------- --------- ---------
654 * |ymax | |ymax | |ymax |
655 * | ... | |... | |... |
656 * |next |->|next |->|next |->...
657 * |nextWETE| |nextWETE| |nextWETE|
658 * --------- --------- ^--------
660 * V-------------------> V---> ...
664 micomputeWAET(EdgeTableEntry
*AET
)
666 EdgeTableEntry
*pWETE
;
670 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
680 if ((!inside
&& !isInside
) ||
681 ( inside
&& isInside
))
683 pWETE
->nextWETE
= AET
;
689 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
695 * Just a simple insertion sort using
696 * pointers and back pointers to sort the Active
702 miInsertionSort(EdgeTableEntry
*AET
)
704 EdgeTableEntry
*pETEchase
;
705 EdgeTableEntry
*pETEinsert
;
706 EdgeTableEntry
*pETEchaseBackTMP
;
714 while (pETEchase
->back
->bres
.minor
> AET
->bres
.minor
)
715 pETEchase
= pETEchase
->back
;
718 if (pETEchase
!= pETEinsert
)
720 pETEchaseBackTMP
= pETEchase
->back
;
721 pETEinsert
->back
->next
= AET
;
723 AET
->back
= pETEinsert
->back
;
724 pETEinsert
->next
= pETEchase
;
725 pETEchase
->back
->next
= pETEinsert
;
726 pETEchase
->back
= pETEinsert
;
727 pETEinsert
->back
= pETEchaseBackTMP
;
738 miFreeStorage(ScanLineListBlock
*pSLLBlock
)
740 ScanLineListBlock
*tmpSLLBlock
;
744 tmpSLLBlock
= pSLLBlock
->next
;
746 pSLLBlock
= tmpSLLBlock
;
753 scanFillGeneralPoly( wxRegion
* rgn
,
754 int count
, /* number of points */
755 const wxPoint
*ptsIn
, /* the points */
756 wxPolygonFillMode fillStyle
759 EdgeTableEntry
*pAET
; /* the Active Edge Table */
760 int y
; /* the current scanline */
761 int nPts
= 0; /* number of pts in buffer */
762 EdgeTableEntry
*pWETE
; /* Winding Edge Table */
763 ScanLineList
*pSLL
; /* Current ScanLineList */
764 wxPoint
* ptsOut
; /* ptr to output buffers */
766 wxPoint FirstPoint
[NUMPTSTOBUFFER
]; /* the output buffers */
767 int FirstWidth
[NUMPTSTOBUFFER
];
768 EdgeTableEntry
*pPrevAET
; /* previous AET entry */
769 EdgeTable ET
; /* Edge Table header node */
770 EdgeTableEntry AET
; /* Active ET header node */
771 EdgeTableEntry
*pETEs
; /* Edge Table Entries buff */
772 ScanLineListBlock SLLBlock
; /* header for ScanLineList */
778 if(!(pETEs
= (EdgeTableEntry
*)
779 malloc(sizeof(EdgeTableEntry
) * count
)))
783 if (!miCreateETandAET(count
, ptsIn
, &ET
, &AET
, pETEs
, &SLLBlock
))
788 pSLL
= ET
.scanlines
.next
;
790 if (fillStyle
== wxODDEVEN_RULE
)
795 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
798 * Add a new edge to the active edge table when we
799 * get to the next edge.
801 if (pSLL
&& y
== pSLL
->scanline
)
803 miloadAET(&AET
, pSLL
->edgelist
);
810 * for each active edge
814 ptsOut
->x
= pAET
->bres
.minor
;
816 *width
++ = pAET
->next
->bres
.minor
- pAET
->bres
.minor
;
820 * send out the buffer when its full
822 if (nPts
== NUMPTSTOBUFFER
)
824 // (*pgc->ops->FillSpans)(dst, pgc,
825 // nPts, FirstPoint, FirstWidth,1);
827 for ( int i
= 0 ; i
< nPts
; ++i
)
830 rect
.y
= FirstPoint
[i
].y
;
831 rect
.x
= FirstPoint
[i
].x
;
833 rect
.width
= FirstWidth
[i
];
840 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
)
841 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
843 miInsertionSort(&AET
);
846 else /* default to WindingNumber */
851 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
854 * Add a new edge to the active edge table when we
855 * get to the next edge.
857 if (pSLL
&& y
== pSLL
->scanline
)
859 miloadAET(&AET
, pSLL
->edgelist
);
868 * for each active edge
873 * if the next edge in the active edge table is
874 * also the next edge in the winding active edge
879 ptsOut
->x
= pAET
->bres
.minor
;
881 *width
++ = pAET
->nextWETE
->bres
.minor
- pAET
->bres
.minor
;
885 * send out the buffer
887 if (nPts
== NUMPTSTOBUFFER
)
889 // (*pgc->ops->FillSpans)(dst, pgc,
890 // nPts, FirstPoint, FirstWidth,1);
891 for ( int i
= 0 ; i
< nPts
; ++i
)
894 rect
.y
= FirstPoint
[i
].y
;
895 rect
.x
= FirstPoint
[i
].x
;
897 rect
.width
= FirstWidth
[i
];
905 pWETE
= pWETE
->nextWETE
;
906 while (pWETE
!= pAET
)
907 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
908 pWETE
= pWETE
->nextWETE
;
910 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
914 * reevaluate the Winding active edge table if we
915 * just had to resort it or if we just exited an edge.
917 if (miInsertionSort(&AET
) || fixWAET
)
926 * Get any spans that we missed by buffering
928 // (*pgc->ops->FillSpans)(dst, pgc,
929 // nPts, FirstPoint, FirstWidth,1);
930 for ( int i
= 0 ; i
< nPts
; ++i
)
933 rect
.y
= FirstPoint
[i
].y
;
934 rect
.x
= FirstPoint
[i
].x
;
936 rect
.width
= FirstWidth
[i
];
941 miFreeStorage(SLLBlock
.next
);
947 wxRegion::wxRegion(size_t n
, const wxPoint
*points
, wxPolygonFillMode fillStyle
)
949 // Set the region to a polygon shape generically using a bitmap with the
950 // polygon drawn on it.
952 m_refData
= new wxRegionRefData();
954 #if OSX_USE_SCANLINES
955 scanFillGeneralPoly(this,n
,points
,fillStyle
);
962 // Find the max size needed to draw the polygon
963 for (idx
=0; idx
<n
; idx
++)
965 wxPoint pt
= points
[idx
];
973 wxBitmap
bmp(mx
, my
);
975 dc
.SetBackground(*wxBLACK_BRUSH
);
977 dc
.SetPen(*wxWHITE_PEN
);
978 dc
.SetBrush(*wxWHITE_BRUSH
);
979 dc
.DrawPolygon(n
, (wxPoint
*)points
, 0, 0, fillStyle
);
980 dc
.SelectObject(wxNullBitmap
);
981 bmp
.SetMask(new wxMask(bmp
, *wxBLACK
));
983 // Use it to set this region
988 wxRegion::~wxRegion()
990 // m_refData unrefed in ~wxObject
993 wxGDIRefData
*wxRegion::CreateGDIRefData() const
995 return new wxRegionRefData
;
998 wxGDIRefData
*wxRegion::CloneGDIRefData(const wxGDIRefData
*data
) const
1000 return new wxRegionRefData(*static_cast<const wxRegionRefData
*>(data
));
1003 //-----------------------------------------------------------------------------
1005 //-----------------------------------------------------------------------------
1007 //! Clear current region
1008 void wxRegion::Clear()
1014 bool wxRegion::DoOffset(wxCoord x
, wxCoord y
)
1016 wxCHECK_MSG( m_refData
, false, wxT("invalid wxRegion") );
1024 verify_noerr( HIShapeOffset( M_REGION
, x
, y
) ) ;
1029 bool wxRegion::DoUnionWithRect(const wxRect
& rect
)
1033 m_refData
= new wxRegionRefData(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
1039 CGRect r
= CGRectMake(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
1040 HIShapeUnionWithRect(M_REGION
, &r
);
1045 //! Union /e region with this.
1046 bool wxRegion::DoCombine(const wxRegion
& region
, wxRegionOp op
)
1048 wxCHECK_MSG( region
.IsOk(), false, wxT("invalid wxRegion") );
1050 // Handle the special case of not initialized (e.g. default constructed)
1051 // region as we can't use HIShape functions if we don't have any shape.
1059 // These operations make sense with a null region.
1065 // Those ones don't really make sense so just leave this region
1070 wxFAIL_MSG( wxT("Unknown region operation") );
1079 verify_noerr( HIShapeIntersect( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) );
1083 verify_noerr( HIShapeUnion( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) );
1088 // XOR is defined as the difference between union and intersection
1089 wxCFRef
< HIShapeRef
> unionshape( HIShapeCreateUnion( M_REGION
, OTHER_M_REGION(region
) ) );
1090 wxCFRef
< HIShapeRef
> intersectionshape( HIShapeCreateIntersection( M_REGION
, OTHER_M_REGION(region
) ) );
1091 verify_noerr( HIShapeDifference( unionshape
, intersectionshape
, M_REGION
) );
1096 verify_noerr( HIShapeDifference( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) ) ;
1101 M_REGION
.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region
) ) );
1108 //-----------------------------------------------------------------------------
1109 //# Information on region
1110 //-----------------------------------------------------------------------------
1112 bool wxRegion::DoIsEqual(const wxRegion
& region
) const
1114 // There doesn't seem to be any native function for checking the equality
1115 // of HIShapes so we compute their differences to determine if they are
1123 wxRegion
r2(region
);
1126 return r2
.IsEmpty();
1129 // Outer bounds of region
1130 bool wxRegion::DoGetBox(wxCoord
& x
, wxCoord
& y
, wxCoord
& w
, wxCoord
& h
) const
1135 HIShapeGetBounds( M_REGION
, &box
) ;
1136 x
= static_cast<int>(box
.origin
.x
);
1137 y
= static_cast<int>(box
.origin
.y
);
1138 w
= static_cast<int>(box
.size
.width
);
1139 h
= static_cast<int>(box
.size
.height
);
1152 bool wxRegion::IsEmpty() const
1155 return HIShapeIsEmpty( M_REGION
) ;
1160 WXHRGN
wxRegion::GetWXHRGN() const
1168 //-----------------------------------------------------------------------------
1170 //-----------------------------------------------------------------------------
1172 // Does the region contain the point?
1173 wxRegionContain
wxRegion::DoContainsPoint(wxCoord x
, wxCoord y
) const
1178 CGPoint p
= CGPointMake( x
, y
) ;
1179 if (HIShapeContainsPoint( M_REGION
, &p
) )
1185 // Does the region contain the rectangle (x, y, w, h)?
1186 wxRegionContain
wxRegion::DoContainsRect(const wxRect
& r
) const
1191 CGRect rect
= CGRectMake(r
.x
,r
.y
,r
.width
,r
.height
);
1192 wxCFRef
<HIShapeRef
> rectshape(HIShapeCreateWithRect(&rect
));
1193 wxCFRef
<HIShapeRef
> intersect(HIShapeCreateIntersection(rectshape
,M_REGION
));
1195 HIShapeGetBounds(intersect
, &bounds
);
1197 if ( HIShapeIsRectangular(intersect
) && CGRectEqualToRect(rect
,bounds
) )
1199 else if ( HIShapeIsEmpty( intersect
) )
1202 return wxPartRegion
;
1205 ///////////////////////////////////////////////////////////////////////////////
1207 // wxRegionIterator //
1209 ///////////////////////////////////////////////////////////////////////////////
1212 * Initialize empty iterator
1214 wxRegionIterator::wxRegionIterator()
1215 : m_current(0), m_numRects(0), m_rects(NULL
)
1219 wxRegionIterator::~wxRegionIterator()
1224 wxRegionIterator::wxRegionIterator(const wxRegionIterator
& iterator
)
1226 , m_current(iterator
.m_current
)
1230 SetRects(iterator
.m_numRects
, iterator
.m_rects
);
1233 wxRegionIterator
& wxRegionIterator::operator=(const wxRegionIterator
& iterator
)
1235 m_current
= iterator
.m_current
;
1236 SetRects(iterator
.m_numRects
, iterator
.m_rects
);
1242 * Set iterator rects for region
1244 void wxRegionIterator::SetRects(long numRects
, wxRect
*rects
)
1248 if (rects
&& (numRects
> 0))
1252 m_rects
= new wxRect
[numRects
];
1253 for (i
= 0; i
< numRects
; i
++)
1254 m_rects
[i
] = rects
[i
];
1257 m_numRects
= numRects
;
1261 * Initialize iterator for region
1263 wxRegionIterator::wxRegionIterator(const wxRegion
& region
)
1271 * Reset iterator for a new /e region.
1274 class RegionToRectsCallbackData
1281 OSStatus
wxOSXRegionToRectsCounterCallback(
1282 int message
, HIShapeRef
WXUNUSED(region
), const CGRect
*WXUNUSED(rect
), void *data
)
1284 long *m_numRects
= (long*) data
;
1285 if ( message
== kHIShapeEnumerateInit
)
1289 else if (message
== kHIShapeEnumerateRect
)
1291 (*m_numRects
) += 1 ;
1297 OSStatus
wxOSXRegionToRectsSetterCallback(
1298 int message
, HIShapeRef
WXUNUSED(region
), const CGRect
*rect
, void *data
)
1300 if (message
== kHIShapeEnumerateRect
)
1302 RegionToRectsCallbackData
*cb
= (RegionToRectsCallbackData
*) data
;
1303 cb
->m_rects
[cb
->m_current
++] = wxRect( rect
->origin
.x
, rect
->origin
.y
, rect
->size
.width
, rect
->size
.height
) ;
1309 void wxRegionIterator::Reset(const wxRegion
& region
)
1316 if (m_region
.IsEmpty())
1323 // fallback code in case we ever need it again
1324 // copying this to a path and dissecting the path would be an option
1326 m_rects
= new wxRect
[m_numRects
];
1327 m_rects
[0] = m_region
.GetBox();
1329 OSStatus err
= HIShapeEnumerate (OTHER_M_REGION(region
), kHIShapeParseFromTopLeft
, wxOSXRegionToRectsCounterCallback
,
1330 (void*)&m_numRects
);
1333 m_rects
= new wxRect
[m_numRects
];
1334 RegionToRectsCallbackData data
;
1335 data
.m_rects
= m_rects
;
1336 data
.m_current
= 0 ;
1337 HIShapeEnumerate( OTHER_M_REGION(region
), kHIShapeParseFromTopLeft
, wxOSXRegionToRectsSetterCallback
,
1348 * Increment iterator. The rectangle returned is the one after the
1351 wxRegionIterator
& wxRegionIterator::operator ++ ()
1353 if (m_current
< m_numRects
)
1360 * Increment iterator. The rectangle returned is the one before the
1363 wxRegionIterator
wxRegionIterator::operator ++ (int)
1365 wxRegionIterator
previous(*this);
1367 if (m_current
< m_numRects
)
1373 long wxRegionIterator::GetX() const
1375 if (m_current
< m_numRects
)
1376 return m_rects
[m_current
].x
;
1381 long wxRegionIterator::GetY() const
1383 if (m_current
< m_numRects
)
1384 return m_rects
[m_current
].y
;
1389 long wxRegionIterator::GetW() const
1391 if (m_current
< m_numRects
)
1392 return m_rects
[m_current
].width
;
1397 long wxRegionIterator::GetH() const
1399 if (m_current
< m_numRects
)
1400 return m_rects
[m_current
].height
;