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
7 // Copyright: (c) 1997 Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
13 #if wxOSX_USE_COCOA_OR_CARBON
15 #include "wx/region.h"
18 #include "wx/gdicmn.h"
19 #include "wx/dcmemory.h"
22 #include "wx/osx/private.h"
24 IMPLEMENT_DYNAMIC_CLASS(wxRegion
, wxGDIObject
)
25 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator
, wxObject
)
27 #define OSX_USE_SCANLINES 1
29 //-----------------------------------------------------------------------------
30 // wxRegionRefData implementation
31 //-----------------------------------------------------------------------------
33 class WXDLLEXPORT wxRegionRefData
: public wxGDIRefData
38 m_macRgn
.reset( HIShapeCreateMutable() );
41 wxRegionRefData(wxCFRef
<HIShapeRef
> ®ion
)
43 m_macRgn
.reset( HIShapeCreateMutableCopy(region
) );
46 wxRegionRefData(long x
, long y
, long w
, long h
)
48 CGRect r
= CGRectMake(x
,y
,w
,h
);
49 wxCFRef
<HIShapeRef
> rect(HIShapeCreateWithRect(&r
));
50 m_macRgn
.reset( HIShapeCreateMutableCopy(rect
) );
53 wxRegionRefData(const wxRegionRefData
& data
)
56 m_macRgn
.reset( HIShapeCreateMutableCopy(data
.m_macRgn
) );
59 virtual ~wxRegionRefData()
63 wxCFRef
<HIMutableShapeRef
> m_macRgn
;
66 #define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
67 #define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn)
69 //-----------------------------------------------------------------------------
71 //-----------------------------------------------------------------------------
73 wxRegion::wxRegion(WXHRGN hRegion
)
75 wxCFRef
< HIShapeRef
> shape( (HIShapeRef
) hRegion
);
76 m_refData
= new wxRegionRefData(shape
);
79 wxRegion::wxRegion(long x
, long y
, long w
, long h
)
81 m_refData
= new wxRegionRefData(x
, y
, w
, h
);
84 wxRegion::wxRegion(const wxPoint
& topLeft
, const wxPoint
& bottomRight
)
86 m_refData
= new wxRegionRefData(topLeft
.x
, topLeft
.y
,
87 bottomRight
.x
- topLeft
.x
,
88 bottomRight
.y
- topLeft
.y
);
91 wxRegion::wxRegion(const wxRect
& rect
)
93 m_refData
= new wxRegionRefData(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
100 Copyright 1987, 1998 The Open Group
102 Permission to use, copy, modify, distribute, and sell this software and its
103 documentation for any purpose is hereby granted without fee, provided that
104 the above copyright notice appear in all copies and that both that
105 copyright notice and this permission notice appear in supporting
108 The above copyright notice and this permission notice shall be included
109 in all copies or substantial portions of the Software.
111 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
112 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
113 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
114 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
115 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
116 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
117 OTHER DEALINGS IN THE SOFTWARE.
119 Except as contained in this notice, the name of The Open Group shall
120 not be used in advertising or otherwise to promote the sale, use or
121 other dealings in this Software without prior written authorization
131 * Written by Brian Kelleher; Jan 1985
133 * This file contains a few macros to help track
134 * the edge of a filled object. The object is assumed
135 * to be filled in scanline order, and thus the
136 * algorithm used is an extension of Bresenham's line
137 * drawing algorithm which assumes that y is always the
139 * Since these pieces of code are the same for any filled shape,
140 * it is more convenient to gather the library in one
141 * place, but since these pieces of code are also in
142 * the inner loops of output primitives, procedure call
143 * overhead is out of the question.
144 * See the author for a derivation if needed.
149 * In scan converting polygons, we want to choose those pixels
150 * which are inside the polygon. Thus, we add .5 to the starting
151 * x coordinate for both left and right edges. Now we choose the
152 * first pixel which is inside the pgon for the left edge and the
153 * first pixel which is outside the pgon for the right edge.
154 * Draw the left pixel, but not the right.
156 * How to add .5 to the starting x coordinate:
157 * If the edge is moving to the right, then subtract dy from the
158 * error term from the general form of the algorithm.
159 * If the edge is moving to the left, then add dy to the error term.
161 * The reason for the difference between edges moving to the left
162 * and edges moving to the right is simple: If an edge is moving
163 * to the right, then we want the algorithm to flip immediately.
164 * If it is moving to the left, then we don't want it to flip until
165 * we traverse an entire pixel.
167 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
168 int dx; /* local storage */ \
171 * if the edge is horizontal, then it is ignored \
172 * and assumed not to be processed. Otherwise, do this stuff. \
176 dx = (x2) - xStart; \
180 incr1 = -2 * dx + 2 * (dy) * m1; \
181 incr2 = -2 * dx + 2 * (dy) * m; \
182 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
186 incr1 = 2 * dx - 2 * (dy) * m1; \
187 incr2 = 2 * dx - 2 * (dy) * m; \
188 d = -2 * m * (dy) + 2 * dx; \
193 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
217 * This structure contains all of the information needed
218 * to run the bresenham algorithm.
219 * The variables may be hardcoded into the declarations
220 * instead of using this structure to make use of
221 * register declarations.
224 int minor
; /* minor axis */
225 int d
; /* decision variable */
226 int m
, m1
; /* slope and slope+1 */
227 int incr1
, incr2
; /* error increments */
231 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
232 BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
233 bres.m, bres.m1, bres.incr1, bres.incr2)
235 #define BRESINCRPGONSTRUCT(bres) \
236 BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
244 * Created by Brian Kelleher; Oct 1985
246 * Include file for filled polygon routines.
248 * These are the data structures needed to scan
249 * convert regions. Two different scan conversion
250 * methods are available -- the even-odd method, and
251 * the winding number method.
252 * The even-odd rule states that a point is inside
253 * the polygon if a ray drawn from that point in any
254 * direction will pass through an odd number of
256 * By the winding number rule, a point is decided
257 * to be inside the polygon if a ray drawn from that
258 * point in any direction passes through a different
259 * number of clockwise and counter-clockwise path
262 * These data structures are adapted somewhat from
263 * the algorithm in (Foley/Van Dam) for scan converting
265 * The basic algorithm is to start at the top (smallest y)
266 * of the polygon, stepping down to the bottom of
267 * the polygon by incrementing the y coordinate. We
268 * keep a list of edges which the current scanline crosses,
269 * sorted by x. This list is called the Active Edge Table (AET)
270 * As we change the y-coordinate, we update each entry in
271 * in the active edge table to reflect the edges new xcoord.
272 * This list must be sorted at each scanline in case
273 * two edges intersect.
274 * We also keep a data structure known as the Edge Table (ET),
275 * which keeps track of all the edges which the current
276 * scanline has not yet reached. The ET is basically a
277 * list of ScanLineList structures containing a list of
278 * edges which are entered at a given scanline. There is one
279 * ScanLineList per scanline at which an edge is entered.
280 * When we enter a new edge, we move it from the ET to the AET.
282 * From the AET, we can implement the even-odd rule as in
284 * The winding number rule is a little trickier. We also
285 * keep the EdgeTableEntries in the AET linked by the
286 * nextWETE (winding EdgeTableEntry) link. This allows
287 * the edges to be linked just as before for updating
288 * purposes, but only uses the edges linked by the nextWETE
289 * link as edges representing spans of the polygon to
290 * drawn (as with the even-odd rule).
294 * for the winding number rule
297 #define COUNTERCLOCKWISE -1
299 typedef struct _EdgeTableEntry
{
300 int ymax
; /* ycoord at which we exit this edge. */
301 BRESINFO bres
; /* Bresenham info to run the edge */
302 struct _EdgeTableEntry
*next
; /* next in the list */
303 struct _EdgeTableEntry
*back
; /* for insertion sort */
304 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
305 int ClockWise
; /* flag for winding number rule */
309 typedef struct _ScanLineList
{
310 int scanline
; /* the scanline represented */
311 EdgeTableEntry
*edgelist
; /* header node */
312 struct _ScanLineList
*next
; /* next in the list */
317 int ymax
; /* ymax for the polygon */
318 int ymin
; /* ymin for the polygon */
319 ScanLineList scanlines
; /* header node */
324 * Here is a struct to help with storage allocation
325 * so we can allocate a big chunk at a time, and then take
326 * pieces from this heap when we need to.
328 #define SLLSPERBLOCK 25
330 typedef struct _ScanLineListBlock
{
331 ScanLineList SLLs
[SLLSPERBLOCK
];
332 struct _ScanLineListBlock
*next
;
336 * number of points to buffer before sending them off
337 * to scanlines() : Must be an even number
339 #define NUMPTSTOBUFFER 200
344 * a few macros for the inner loops of the fill code where
345 * performance considerations don't allow a procedure call.
347 * Evaluate the given edge at the given scanline.
348 * If the edge has expired, then we leave it and fix up
349 * the active edge table; otherwise, we increment the
350 * x value to be ready for the next scanline.
351 * The winding number rule is in effect, so we must notify
352 * the caller when the edge has been removed so he
353 * can reorder the Winding Active Edge Table.
355 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
356 if (pAET->ymax == y) { /* leaving this edge */ \
357 pPrevAET->next = pAET->next; \
358 pAET = pPrevAET->next; \
361 pAET->back = pPrevAET; \
364 BRESINCRPGONSTRUCT(pAET->bres); \
372 * Evaluate the given edge at the given scanline.
373 * If the edge has expired, then we leave it and fix up
374 * the active edge table; otherwise, we increment the
375 * x value to be ready for the next scanline.
376 * The even-odd rule is in effect.
378 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
379 if (pAET->ymax == y) { /* leaving this edge */ \
380 pPrevAET->next = pAET->next; \
381 pAET = pPrevAET->next; \
383 pAET->back = pPrevAET; \
386 BRESINCRPGONSTRUCT(pAET->bres); \
394 static bool miCreateETandAET(
396 const wxPoint
* /*pts*/,
398 EdgeTableEntry
* /*AET*/,
399 EdgeTableEntry
* /*pETEs*/,
400 ScanLineListBlock
* /*pSLLBlock*/
403 static void miloadAET(
404 EdgeTableEntry
* /*AET*/,
405 EdgeTableEntry
* /*ETEs*/
408 static void micomputeWAET(
409 EdgeTableEntry
* /*AET*/
412 static int miInsertionSort(
413 EdgeTableEntry
* /*AET*/
416 static void miFreeStorage(
417 ScanLineListBlock
* /*pSLLBlock*/
423 * Written by Brian Kelleher; Oct. 1985
425 * This module contains all of the utility functions
426 * needed to scan convert a polygon.
433 * Insert the given edge into the edge table.
434 * First we must find the correct bucket in the
435 * Edge table, then find the right slot in the
436 * bucket. Finally, we can insert it.
440 miInsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
, int scanline
,
441 ScanLineListBlock
**SLLBlock
, int *iSLLBlock
)
443 EdgeTableEntry
*start
, *prev
;
444 ScanLineList
*pSLL
, *pPrevSLL
;
445 ScanLineListBlock
*tmpSLLBlock
;
448 * find the right bucket to put the edge into
450 pPrevSLL
= &ET
->scanlines
;
451 pSLL
= pPrevSLL
->next
;
452 while (pSLL
&& (pSLL
->scanline
< scanline
))
459 * reassign pSLL (pointer to ScanLineList) if necessary
461 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
463 if (*iSLLBlock
> SLLSPERBLOCK
-1)
466 (ScanLineListBlock
*)malloc(sizeof(ScanLineListBlock
));
469 (*SLLBlock
)->next
= tmpSLLBlock
;
470 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
471 *SLLBlock
= tmpSLLBlock
;
474 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
476 pSLL
->next
= pPrevSLL
->next
;
477 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
478 pPrevSLL
->next
= pSLL
;
480 pSLL
->scanline
= scanline
;
483 * now insert the edge in the right bucket
485 prev
= (EdgeTableEntry
*)NULL
;
486 start
= pSLL
->edgelist
;
487 while (start
&& (start
->bres
.minor
< ETE
->bres
.minor
))
497 pSLL
->edgelist
= ETE
;
504 * This routine creates the edge table for
505 * scan converting polygons.
506 * The Edge Table (ET) looks like:
510 * | ymax | ScanLineLists
511 * |scanline|-->------------>-------------->...
512 * -------- |scanline| |scanline|
513 * |edgelist| |edgelist|
514 * --------- ---------
518 * list of ETEs list of ETEs
520 * where ETE is an EdgeTableEntry data structure,
521 * and there is one ScanLineList per scanline at
522 * which an edge is initially entered.
527 miCreateETandAET(int count
, const wxPoint
* pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
528 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
530 const wxPoint
* top
, *bottom
;
531 const wxPoint
* PrevPt
, *CurrPt
;
536 if (count
< 2) return TRUE
;
539 * initialize the Active Edge Table
541 AET
->next
= (EdgeTableEntry
*)NULL
;
542 AET
->back
= (EdgeTableEntry
*)NULL
;
543 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
544 AET
->bres
.minor
= INT_MIN
;
547 * initialize the Edge Table.
549 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
552 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
554 PrevPt
= &pts
[count
-1];
557 * for each vertex in the array of points.
558 * In this loop we are dealing with two vertices at
559 * a time -- these make up one edge of the polygon.
566 * find out which point is above and which is below.
568 if (PrevPt
->y
> CurrPt
->y
)
570 bottom
= PrevPt
, top
= CurrPt
;
571 pETEs
->ClockWise
= 0;
575 bottom
= CurrPt
, top
= PrevPt
;
576 pETEs
->ClockWise
= 1;
580 * don't add horizontal edges to the Edge table.
582 if (bottom
->y
!= top
->y
)
584 pETEs
->ymax
= bottom
->y
-1; /* -1 so we don't get last scanline */
587 * initialize integer edge algorithm
589 dy
= bottom
->y
- top
->y
;
590 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
592 if (!miInsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
, &iSLLBlock
))
594 miFreeStorage(pSLLBlock
->next
);
598 ET
->ymax
= wxMax(ET
->ymax
, PrevPt
->y
);
599 ET
->ymin
= wxMin(ET
->ymin
, PrevPt
->y
);
611 * This routine moves EdgeTableEntries from the
612 * EdgeTable into the Active Edge Table,
613 * leaving them sorted by smaller x coordinate.
618 miloadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
620 EdgeTableEntry
*pPrevAET
;
627 while (AET
&& (AET
->bres
.minor
< ETEs
->bres
.minor
))
636 ETEs
->back
= pPrevAET
;
637 pPrevAET
->next
= ETEs
;
647 * This routine links the AET by the
648 * nextWETE (winding EdgeTableEntry) link for
649 * use by the winding number rule. The final
650 * Active Edge Table (AET) might look something
654 * ---------- --------- ---------
655 * |ymax | |ymax | |ymax |
656 * | ... | |... | |... |
657 * |next |->|next |->|next |->...
658 * |nextWETE| |nextWETE| |nextWETE|
659 * --------- --------- ^--------
661 * V-------------------> V---> ...
665 micomputeWAET(EdgeTableEntry
*AET
)
667 EdgeTableEntry
*pWETE
;
671 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
681 if ((!inside
&& !isInside
) ||
682 ( inside
&& isInside
))
684 pWETE
->nextWETE
= AET
;
690 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
696 * Just a simple insertion sort using
697 * pointers and back pointers to sort the Active
703 miInsertionSort(EdgeTableEntry
*AET
)
705 EdgeTableEntry
*pETEchase
;
706 EdgeTableEntry
*pETEinsert
;
707 EdgeTableEntry
*pETEchaseBackTMP
;
715 while (pETEchase
->back
->bres
.minor
> AET
->bres
.minor
)
716 pETEchase
= pETEchase
->back
;
719 if (pETEchase
!= pETEinsert
)
721 pETEchaseBackTMP
= pETEchase
->back
;
722 pETEinsert
->back
->next
= AET
;
724 AET
->back
= pETEinsert
->back
;
725 pETEinsert
->next
= pETEchase
;
726 pETEchase
->back
->next
= pETEinsert
;
727 pETEchase
->back
= pETEinsert
;
728 pETEinsert
->back
= pETEchaseBackTMP
;
739 miFreeStorage(ScanLineListBlock
*pSLLBlock
)
741 ScanLineListBlock
*tmpSLLBlock
;
745 tmpSLLBlock
= pSLLBlock
->next
;
747 pSLLBlock
= tmpSLLBlock
;
754 scanFillGeneralPoly( wxRegion
* rgn
,
755 int count
, /* number of points */
756 const wxPoint
*ptsIn
, /* the points */
757 wxPolygonFillMode fillStyle
760 EdgeTableEntry
*pAET
; /* the Active Edge Table */
761 int y
; /* the current scanline */
762 int nPts
= 0; /* number of pts in buffer */
763 EdgeTableEntry
*pWETE
; /* Winding Edge Table */
764 ScanLineList
*pSLL
; /* Current ScanLineList */
765 wxPoint
* ptsOut
; /* ptr to output buffers */
767 wxPoint FirstPoint
[NUMPTSTOBUFFER
]; /* the output buffers */
768 int FirstWidth
[NUMPTSTOBUFFER
];
769 EdgeTableEntry
*pPrevAET
; /* previous AET entry */
770 EdgeTable ET
; /* Edge Table header node */
771 EdgeTableEntry AET
; /* Active ET header node */
772 EdgeTableEntry
*pETEs
; /* Edge Table Entries buff */
773 ScanLineListBlock SLLBlock
; /* header for ScanLineList */
779 if(!(pETEs
= (EdgeTableEntry
*)
780 malloc(sizeof(EdgeTableEntry
) * count
)))
784 if (!miCreateETandAET(count
, ptsIn
, &ET
, &AET
, pETEs
, &SLLBlock
))
789 pSLL
= ET
.scanlines
.next
;
791 if (fillStyle
== wxODDEVEN_RULE
)
796 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
799 * Add a new edge to the active edge table when we
800 * get to the next edge.
802 if (pSLL
&& y
== pSLL
->scanline
)
804 miloadAET(&AET
, pSLL
->edgelist
);
811 * for each active edge
815 ptsOut
->x
= pAET
->bres
.minor
;
817 *width
++ = pAET
->next
->bres
.minor
- pAET
->bres
.minor
;
821 * send out the buffer when its full
823 if (nPts
== NUMPTSTOBUFFER
)
825 // (*pgc->ops->FillSpans)(dst, pgc,
826 // nPts, FirstPoint, FirstWidth,1);
828 for ( int i
= 0 ; i
< nPts
; ++i
)
831 rect
.y
= FirstPoint
[i
].y
;
832 rect
.x
= FirstPoint
[i
].x
;
834 rect
.width
= FirstWidth
[i
];
841 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
)
842 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
844 miInsertionSort(&AET
);
847 else /* default to WindingNumber */
852 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
855 * Add a new edge to the active edge table when we
856 * get to the next edge.
858 if (pSLL
&& y
== pSLL
->scanline
)
860 miloadAET(&AET
, pSLL
->edgelist
);
869 * for each active edge
874 * if the next edge in the active edge table is
875 * also the next edge in the winding active edge
880 ptsOut
->x
= pAET
->bres
.minor
;
882 *width
++ = pAET
->nextWETE
->bres
.minor
- pAET
->bres
.minor
;
886 * send out the buffer
888 if (nPts
== NUMPTSTOBUFFER
)
890 // (*pgc->ops->FillSpans)(dst, pgc,
891 // nPts, FirstPoint, FirstWidth,1);
892 for ( int i
= 0 ; i
< nPts
; ++i
)
895 rect
.y
= FirstPoint
[i
].y
;
896 rect
.x
= FirstPoint
[i
].x
;
898 rect
.width
= FirstWidth
[i
];
906 pWETE
= pWETE
->nextWETE
;
907 while (pWETE
!= pAET
)
908 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
909 pWETE
= pWETE
->nextWETE
;
911 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
915 * reevaluate the Winding active edge table if we
916 * just had to resort it or if we just exited an edge.
918 if (miInsertionSort(&AET
) || fixWAET
)
927 * Get any spans that we missed by buffering
929 // (*pgc->ops->FillSpans)(dst, pgc,
930 // nPts, FirstPoint, FirstWidth,1);
931 for ( int i
= 0 ; i
< nPts
; ++i
)
934 rect
.y
= FirstPoint
[i
].y
;
935 rect
.x
= FirstPoint
[i
].x
;
937 rect
.width
= FirstWidth
[i
];
942 miFreeStorage(SLLBlock
.next
);
948 wxRegion::wxRegion(size_t n
, const wxPoint
*points
, wxPolygonFillMode fillStyle
)
950 // Set the region to a polygon shape generically using a bitmap with the
951 // polygon drawn on it.
953 m_refData
= new wxRegionRefData();
955 #if OSX_USE_SCANLINES
956 scanFillGeneralPoly(this,n
,points
,fillStyle
);
963 // Find the max size needed to draw the polygon
964 for (idx
=0; idx
<n
; idx
++)
966 wxPoint pt
= points
[idx
];
974 wxBitmap
bmp(mx
, my
);
976 dc
.SetBackground(*wxBLACK_BRUSH
);
978 dc
.SetPen(*wxWHITE_PEN
);
979 dc
.SetBrush(*wxWHITE_BRUSH
);
980 dc
.DrawPolygon(n
, (wxPoint
*)points
, 0, 0, fillStyle
);
981 dc
.SelectObject(wxNullBitmap
);
982 bmp
.SetMask(new wxMask(bmp
, *wxBLACK
));
984 // Use it to set this region
989 wxRegion::~wxRegion()
991 // m_refData unrefed in ~wxObject
994 wxGDIRefData
*wxRegion::CreateGDIRefData() const
996 return new wxRegionRefData
;
999 wxGDIRefData
*wxRegion::CloneGDIRefData(const wxGDIRefData
*data
) const
1001 return new wxRegionRefData(*static_cast<const wxRegionRefData
*>(data
));
1004 //-----------------------------------------------------------------------------
1006 //-----------------------------------------------------------------------------
1008 //! Clear current region
1009 void wxRegion::Clear()
1015 bool wxRegion::DoOffset(wxCoord x
, wxCoord y
)
1017 wxCHECK_MSG( m_refData
, false, wxT("invalid wxRegion") );
1025 verify_noerr( HIShapeOffset( M_REGION
, x
, y
) ) ;
1030 bool wxRegion::DoUnionWithRect(const wxRect
& rect
)
1034 m_refData
= new wxRegionRefData(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
1040 CGRect r
= CGRectMake(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
1041 HIShapeUnionWithRect(M_REGION
, &r
);
1046 //! Union /e region with this.
1047 bool wxRegion::DoCombine(const wxRegion
& region
, wxRegionOp op
)
1049 wxCHECK_MSG( region
.IsOk(), false, wxT("invalid wxRegion") );
1051 // Handle the special case of not initialized (e.g. default constructed)
1052 // region as we can't use HIShape functions if we don't have any shape.
1060 // These operations make sense with a null region.
1066 // Those ones don't really make sense so just leave this region
1071 wxFAIL_MSG( wxT("Unknown region operation") );
1080 verify_noerr( HIShapeIntersect( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) );
1084 verify_noerr( HIShapeUnion( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) );
1089 // XOR is defined as the difference between union and intersection
1090 wxCFRef
< HIShapeRef
> unionshape( HIShapeCreateUnion( M_REGION
, OTHER_M_REGION(region
) ) );
1091 wxCFRef
< HIShapeRef
> intersectionshape( HIShapeCreateIntersection( M_REGION
, OTHER_M_REGION(region
) ) );
1092 verify_noerr( HIShapeDifference( unionshape
, intersectionshape
, M_REGION
) );
1097 verify_noerr( HIShapeDifference( M_REGION
, OTHER_M_REGION(region
) , M_REGION
) ) ;
1102 M_REGION
.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region
) ) );
1109 //-----------------------------------------------------------------------------
1110 //# Information on region
1111 //-----------------------------------------------------------------------------
1113 bool wxRegion::DoIsEqual(const wxRegion
& region
) const
1115 // There doesn't seem to be any native function for checking the equality
1116 // of HIShapes so we compute their differences to determine if they are
1124 wxRegion
r2(region
);
1127 return r2
.IsEmpty();
1130 // Outer bounds of region
1131 bool wxRegion::DoGetBox(wxCoord
& x
, wxCoord
& y
, wxCoord
& w
, wxCoord
& h
) const
1136 HIShapeGetBounds( M_REGION
, &box
) ;
1137 x
= static_cast<int>(box
.origin
.x
);
1138 y
= static_cast<int>(box
.origin
.y
);
1139 w
= static_cast<int>(box
.size
.width
);
1140 h
= static_cast<int>(box
.size
.height
);
1153 bool wxRegion::IsEmpty() const
1156 return HIShapeIsEmpty( M_REGION
) ;
1161 WXHRGN
wxRegion::GetWXHRGN() const
1169 //-----------------------------------------------------------------------------
1171 //-----------------------------------------------------------------------------
1173 // Does the region contain the point?
1174 wxRegionContain
wxRegion::DoContainsPoint(wxCoord x
, wxCoord y
) const
1179 CGPoint p
= CGPointMake( x
, y
) ;
1180 if (HIShapeContainsPoint( M_REGION
, &p
) )
1186 // Does the region contain the rectangle (x, y, w, h)?
1187 wxRegionContain
wxRegion::DoContainsRect(const wxRect
& r
) const
1192 CGRect rect
= CGRectMake(r
.x
,r
.y
,r
.width
,r
.height
);
1193 wxCFRef
<HIShapeRef
> rectshape(HIShapeCreateWithRect(&rect
));
1194 wxCFRef
<HIShapeRef
> intersect(HIShapeCreateIntersection(rectshape
,M_REGION
));
1196 HIShapeGetBounds(intersect
, &bounds
);
1198 if ( HIShapeIsRectangular(intersect
) && CGRectEqualToRect(rect
,bounds
) )
1200 else if ( HIShapeIsEmpty( intersect
) )
1203 return wxPartRegion
;
1206 ///////////////////////////////////////////////////////////////////////////////
1208 // wxRegionIterator //
1210 ///////////////////////////////////////////////////////////////////////////////
1213 * Initialize empty iterator
1215 wxRegionIterator::wxRegionIterator()
1216 : m_current(0), m_numRects(0), m_rects(NULL
)
1220 wxRegionIterator::~wxRegionIterator()
1225 wxRegionIterator::wxRegionIterator(const wxRegionIterator
& iterator
)
1227 , m_current(iterator
.m_current
)
1231 SetRects(iterator
.m_numRects
, iterator
.m_rects
);
1234 wxRegionIterator
& wxRegionIterator::operator=(const wxRegionIterator
& iterator
)
1236 m_current
= iterator
.m_current
;
1237 SetRects(iterator
.m_numRects
, iterator
.m_rects
);
1243 * Set iterator rects for region
1245 void wxRegionIterator::SetRects(long numRects
, wxRect
*rects
)
1249 if (rects
&& (numRects
> 0))
1253 m_rects
= new wxRect
[numRects
];
1254 for (i
= 0; i
< numRects
; i
++)
1255 m_rects
[i
] = rects
[i
];
1258 m_numRects
= numRects
;
1262 * Initialize iterator for region
1264 wxRegionIterator::wxRegionIterator(const wxRegion
& region
)
1272 * Reset iterator for a new /e region.
1275 class RegionToRectsCallbackData
1282 OSStatus
wxOSXRegionToRectsCounterCallback(
1283 int message
, HIShapeRef
WXUNUSED(region
), const CGRect
*WXUNUSED(rect
), void *data
)
1285 long *m_numRects
= (long*) data
;
1286 if ( message
== kHIShapeEnumerateInit
)
1290 else if (message
== kHIShapeEnumerateRect
)
1292 (*m_numRects
) += 1 ;
1298 OSStatus
wxOSXRegionToRectsSetterCallback(
1299 int message
, HIShapeRef
WXUNUSED(region
), const CGRect
*rect
, void *data
)
1301 if (message
== kHIShapeEnumerateRect
)
1303 RegionToRectsCallbackData
*cb
= (RegionToRectsCallbackData
*) data
;
1304 cb
->m_rects
[cb
->m_current
++] = wxRect( rect
->origin
.x
, rect
->origin
.y
, rect
->size
.width
, rect
->size
.height
) ;
1310 void wxRegionIterator::Reset(const wxRegion
& region
)
1317 if (m_region
.IsEmpty())
1324 // fallback code in case we ever need it again
1325 // copying this to a path and dissecting the path would be an option
1327 m_rects
= new wxRect
[m_numRects
];
1328 m_rects
[0] = m_region
.GetBox();
1330 OSStatus err
= HIShapeEnumerate (OTHER_M_REGION(region
), kHIShapeParseFromTopLeft
, wxOSXRegionToRectsCounterCallback
,
1331 (void*)&m_numRects
);
1334 m_rects
= new wxRect
[m_numRects
];
1335 RegionToRectsCallbackData data
;
1336 data
.m_rects
= m_rects
;
1337 data
.m_current
= 0 ;
1338 HIShapeEnumerate( OTHER_M_REGION(region
), kHIShapeParseFromTopLeft
, wxOSXRegionToRectsSetterCallback
,
1349 * Increment iterator. The rectangle returned is the one after the
1352 wxRegionIterator
& wxRegionIterator::operator ++ ()
1354 if (m_current
< m_numRects
)
1361 * Increment iterator. The rectangle returned is the one before the
1364 wxRegionIterator
wxRegionIterator::operator ++ (int)
1366 wxRegionIterator
previous(*this);
1368 if (m_current
< m_numRects
)
1374 long wxRegionIterator::GetX() const
1376 if (m_current
< m_numRects
)
1377 return m_rects
[m_current
].x
;
1382 long wxRegionIterator::GetY() const
1384 if (m_current
< m_numRects
)
1385 return m_rects
[m_current
].y
;
1390 long wxRegionIterator::GetW() const
1392 if (m_current
< m_numRects
)
1393 return m_rects
[m_current
].width
;
1398 long wxRegionIterator::GetH() const
1400 if (m_current
< m_numRects
)
1401 return m_rects
[m_current
].height
;