]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/region.cpp
check that the version of __sync_sub_and_fetch that returns a value is supported...
[wxWidgets.git] / src / mac / carbon / region.cpp
CommitLineData
e9576ca5 1/////////////////////////////////////////////////////////////////////////////
b3a44e05 2// File: src/mac/carbon/region.cpp
e9576ca5 3// Purpose: Region class
6aa89a22 4// Author: Stefan Csomor
e9576ca5 5// Created: Fri Oct 24 10:46:34 MET 1997
6aa89a22
JS
6// RCS-ID: $Id$
7// Copyright: (c) 1997 Stefan Csomor
65571936 8// Licence: wxWindows licence
e9576ca5
SC
9/////////////////////////////////////////////////////////////////////////////
10
3d1a4878
SC
11#include "wx/wxprec.h"
12
e9576ca5 13#include "wx/region.h"
b3a44e05 14
dd05139a
WS
15#ifndef WX_PRECOMP
16 #include "wx/gdicmn.h"
17#endif
18
2f1ae414 19#include "wx/mac/uma.h"
e9576ca5 20
fd04970a
SC
21IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
22IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
e9576ca5
SC
23
24//-----------------------------------------------------------------------------
25// wxRegionRefData implementation
26//-----------------------------------------------------------------------------
27
5fa7a49c
DS
28class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
29{
e9576ca5 30public:
e7600a2c 31 wxRegionRefData()
9a8864ca
VZ
32 {
33 m_macRgn.reset( HIShapeCreateMutable() );
1abfa172 34 }
e9576ca5 35
1abfa172 36 wxRegionRefData(HIShapeRef hRegion)
9a8864ca
VZ
37 {
38 m_macRgn.reset( HIShapeCreateMutableCopy(hRegion) );
1abfa172 39 }
9a8864ca 40
1abfa172
SC
41 wxRegionRefData(long x, long y, long w, long h)
42 {
43 CGRect r = CGRectMake(x,y,w,h);
44 wxCFRef<HIShapeRef> rect(HIShapeCreateWithRect(&r));
9a8864ca 45 m_macRgn.reset( HIShapeCreateMutableCopy(rect) );
1abfa172 46 }
9a8864ca 47
e7600a2c
GD
48 wxRegionRefData(const wxRegionRefData& data)
49 : wxGDIRefData()
50 {
1abfa172 51 m_macRgn.reset( HIShapeCreateMutableCopy(data.m_macRgn) );
e7600a2c 52 }
e9576ca5 53
d3c7fc99 54 virtual ~wxRegionRefData()
9a8864ca 55 {
1abfa172 56 }
5fa7a49c 57
1abfa172 58 wxCFRef<HIMutableShapeRef> m_macRgn;
e9576ca5
SC
59};
60
519cb848
SC
61#define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
62#define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn)
e9576ca5
SC
63
64//-----------------------------------------------------------------------------
65// wxRegion
66//-----------------------------------------------------------------------------
67
68/*!
69 * Create an empty region.
70 */
71wxRegion::wxRegion()
72{
1abfa172 73 m_refData = new wxRegionRefData();
519cb848
SC
74}
75
76wxRegion::wxRegion(WXHRGN hRegion )
77{
1abfa172 78 m_refData = new wxRegionRefData(hRegion);
e9576ca5
SC
79}
80
81wxRegion::wxRegion(long x, long y, long w, long h)
82{
1abfa172 83 m_refData = new wxRegionRefData(x , y , w , h );
e9576ca5
SC
84}
85
86wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
87{
9a8864ca
VZ
88 m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
89 topLeft.x - bottomRight.x ,
1abfa172 90 topLeft.y - bottomRight.y);
e9576ca5
SC
91}
92
93wxRegion::wxRegion(const wxRect& rect)
94{
1abfa172 95 m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
e9576ca5
SC
96}
97
564cb9de
SC
98wxRegion::wxRegion(size_t n, const wxPoint *points, int WXUNUSED(fillStyle))
99{
9a8864ca
VZ
100 wxUnusedVar(n);
101 wxUnusedVar(points);
564cb9de 102
0903bd05 103#if 0 // ndef __LP64__
9a8864ca
VZ
104 m_refData = new wxRegionRefData;
105
e6c3d3e6 106 // TODO : any APIs ?
5e8c9935
SC
107 // OS X somehow does not collect the region invisibly as before, so sometimes things
108 // get drawn on screen instead of just being combined into a region, therefore we allocate a temp gworld now
5fa7a49c
DS
109
110 GWorldPtr gWorld = NULL;
111 GWorldPtr oldWorld;
112 GDHandle oldGDHandle;
113 OSStatus err;
114 Rect destRect = { 0, 0, 1, 1 };
115
5e8c9935 116 ::GetGWorld( &oldWorld, &oldGDHandle );
5fa7a49c 117 err = ::NewGWorld( &gWorld, 32, &destRect, NULL, NULL, 0 );
5e8c9935 118 if ( err == noErr )
564cb9de 119 {
5e8c9935 120 ::SetGWorld( gWorld, GetGDevice() );
5fa7a49c 121
5e8c9935
SC
122 OpenRgn();
123
124 wxCoord x1, x2 , y1 , y2 ;
125 x2 = x1 = points[0].x ;
126 y2 = y1 = points[0].y ;
5fa7a49c
DS
127
128 ::MoveTo( x1, y1 );
5e8c9935
SC
129 for (size_t i = 1; i < n; i++)
130 {
131 x2 = points[i].x ;
132 y2 = points[i].y ;
5fa7a49c 133 ::LineTo( x2, y2 );
5e8c9935 134 }
5fa7a49c 135
5e8c9935
SC
136 // close the polyline if necessary
137 if ( x1 != x2 || y1 != y2 )
5fa7a49c
DS
138 ::LineTo( x1, y1 ) ;
139
5e8c9935 140 CloseRgn( M_REGION ) ;
5fa7a49c 141
5e8c9935 142 ::SetGWorld( oldWorld, oldGDHandle );
564cb9de 143 }
9a8864ca
VZ
144#else
145 wxFAIL_MSG( "not implemented" );
146 m_refData = NULL;
e6c3d3e6 147#endif
564cb9de
SC
148}
149
e9576ca5
SC
150wxRegion::~wxRegion()
151{
152 // m_refData unrefed in ~wxObject
153}
154
155//-----------------------------------------------------------------------------
156//# Modify region
157//-----------------------------------------------------------------------------
158
159//! Clear current region
160void wxRegion::Clear()
161{
162 UnRef();
163}
164
c871c71b 165// Move the region
8a16d737 166bool wxRegion::DoOffset(wxCoord x, wxCoord y)
c871c71b
SC
167{
168 wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") );
169
170 if ( !x && !y )
c871c71b
SC
171 // nothing to do
172 return true;
c871c71b 173
85baeafb 174 verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
5fa7a49c 175
c871c71b
SC
176 return true ;
177}
178
179
e9576ca5 180//! Union /e region with this.
8a16d737 181bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
e9576ca5 182{
8a16d737 183 wxCHECK_MSG( region.Ok(), false, _T("invalid wxRegion") );
e40298d5
JS
184
185 // Don't change shared data
5fa7a49c
DS
186 if (!m_refData)
187 {
e40298d5 188 m_refData = new wxRegionRefData();
5fa7a49c
DS
189 }
190 else if (m_refData->GetRefCount() > 1)
e40298d5
JS
191 {
192 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
193 UnRef();
194 m_refData = new wxRegionRefData(*ref);
195 }
e9576ca5 196
e9576ca5
SC
197 switch (op)
198 {
199 case wxRGN_AND:
85baeafb 200 verify_noerr( HIShapeIntersect( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
e9576ca5 201 break ;
5fa7a49c 202
e9576ca5 203 case wxRGN_OR:
85baeafb 204 verify_noerr( HIShapeUnion( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
e9576ca5 205 break ;
5fa7a49c 206
e9576ca5 207 case wxRGN_XOR:
1abfa172
SC
208 {
209 // XOR is defined as the difference between union and intersection
210 wxCFRef< HIShapeRef > unionshape( HIShapeCreateUnion( M_REGION , OTHER_M_REGION(region) ) );
211 wxCFRef< HIShapeRef > intersectionshape( HIShapeCreateIntersection( M_REGION , OTHER_M_REGION(region) ) );
85baeafb 212 verify_noerr( HIShapeDifference( unionshape, intersectionshape, M_REGION ) );
1abfa172 213 }
e9576ca5 214 break ;
5fa7a49c 215
e9576ca5 216 case wxRGN_DIFF:
85baeafb 217 verify_noerr( HIShapeDifference( M_REGION , OTHER_M_REGION(region) , M_REGION ) ) ;
e9576ca5 218 break ;
5fa7a49c 219
e9576ca5
SC
220 case wxRGN_COPY:
221 default:
1abfa172 222 M_REGION.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region) ) );
e9576ca5
SC
223 break ;
224 }
225
5fa7a49c 226 return true;
e9576ca5
SC
227}
228
e9576ca5
SC
229//-----------------------------------------------------------------------------
230//# Information on region
231//-----------------------------------------------------------------------------
232
89954433 233bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const
8a16d737
VZ
234{
235 wxFAIL_MSG( _T("not implemented") );
236
237 return false;
238}
239
e9576ca5 240// Outer bounds of region
8a16d737 241bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
e9576ca5 242{
5fa7a49c 243 if (m_refData)
e40298d5 244 {
1abfa172
SC
245 CGRect box ;
246 HIShapeGetBounds( M_REGION , &box ) ;
9a8864ca
VZ
247 x = wx_static_cast(int, box.origin.x);
248 y = wx_static_cast(int, box.origin.y);
249 w = wx_static_cast(int, box.size.width);
250 h = wx_static_cast(int, box.size.height);
8a16d737
VZ
251
252 return true;
5fa7a49c
DS
253 }
254 else
e40298d5
JS
255 {
256 x = y = w = h = 0;
5fa7a49c 257
8a16d737
VZ
258 return false;
259 }
e9576ca5
SC
260}
261
262// Is region empty?
8a16d737 263bool wxRegion::IsEmpty() const
e9576ca5 264{
54a6974c 265 if ( m_refData )
1abfa172 266 return HIShapeIsEmpty( M_REGION ) ;
54a6974c
SC
267 else
268 return true ;
519cb848
SC
269}
270
271const WXHRGN wxRegion::GetWXHRGN() const
272{
e40298d5 273 return M_REGION ;
e9576ca5
SC
274}
275
276//-----------------------------------------------------------------------------
277//# Tests
278//-----------------------------------------------------------------------------
279
5fa7a49c 280// Does the region contain the point?
8a16d737 281wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
e9576ca5 282{
e40298d5
JS
283 if (!m_refData)
284 return wxOutRegion;
e9576ca5 285
1abfa172
SC
286 CGPoint p = { y , x } ;
287 if (HIShapeContainsPoint( M_REGION , &p ) )
e9576ca5 288 return wxInRegion;
5fa7a49c 289
519cb848 290 return wxOutRegion;
e9576ca5
SC
291}
292
293// Does the region contain the rectangle (x, y, w, h)?
8a16d737 294wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
e9576ca5 295{
e40298d5
JS
296 if (!m_refData)
297 return wxOutRegion;
e9576ca5 298
1abfa172
SC
299 CGRect rect = CGRectMake(r.x,r.y,r.width,r.height);
300 wxCFRef<HIShapeRef> rectshape(HIShapeCreateWithRect(&rect));
301 wxCFRef<HIShapeRef> intersect(HIShapeCreateIntersection(rectshape,M_REGION));
302 CGRect bounds;
303 HIShapeGetBounds(intersect, &bounds);
9a8864ca 304
1abfa172 305 if ( HIShapeIsRectangular(intersect) && CGRectEqualToRect(rect,bounds) )
e9576ca5 306 return wxInRegion;
85baeafb 307 else if ( HIShapeIsEmpty( intersect ) )
e9576ca5 308 return wxOutRegion;
85baeafb
SC
309 else
310 return wxPartRegion;
e9576ca5
SC
311}
312
e9576ca5 313///////////////////////////////////////////////////////////////////////////////
e7600a2c
GD
314// //
315// wxRegionIterator //
316// //
e9576ca5
SC
317///////////////////////////////////////////////////////////////////////////////
318
319/*!
320 * Initialize empty iterator
321 */
e7600a2c
GD
322wxRegionIterator::wxRegionIterator()
323 : m_current(0), m_numRects(0), m_rects(NULL)
e9576ca5
SC
324{
325}
326
327wxRegionIterator::~wxRegionIterator()
328{
5fa7a49c
DS
329 if (m_rects)
330 {
331 delete [] m_rects;
6dcbb6d0
GD
332 m_rects = NULL;
333 }
e9576ca5
SC
334}
335
e7600a2c
GD
336wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
337 : wxObject()
338 , m_current(iterator.m_current)
6dcbb6d0 339 , m_numRects(0)
2012e3ea 340 , m_rects(NULL)
e7600a2c 341{
6dcbb6d0 342 SetRects(iterator.m_numRects, iterator.m_rects);
e7600a2c
GD
343}
344
345wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
346{
347 m_current = iterator.m_current;
6dcbb6d0 348 SetRects(iterator.m_numRects, iterator.m_rects);
5fa7a49c 349
e7600a2c
GD
350 return *this;
351}
352
6dcbb6d0
GD
353/*!
354 * Set iterator rects for region
355 */
356void wxRegionIterator::SetRects(long numRects, wxRect *rects)
357{
5fa7a49c
DS
358 if (m_rects)
359 {
360 delete [] m_rects;
6dcbb6d0
GD
361 m_rects = NULL;
362 }
5fa7a49c
DS
363
364 if (rects && (numRects > 0))
6dcbb6d0
GD
365 {
366 int i;
5fa7a49c 367
6dcbb6d0
GD
368 m_rects = new wxRect[numRects];
369 for (i = 0; i < numRects; i++)
370 m_rects[i] = rects[i];
371 }
5fa7a49c 372
6dcbb6d0
GD
373 m_numRects = numRects;
374}
375
e9576ca5
SC
376/*!
377 * Initialize iterator for region
378 */
379wxRegionIterator::wxRegionIterator(const wxRegion& region)
380{
381 m_rects = NULL;
382
e7600a2c 383 Reset(region);
e9576ca5
SC
384}
385
386/*!
387 * Reset iterator for a new /e region.
388 */
5fa7a49c 389
1abfa172 390#ifndef __LP64__
5fa7a49c 391OSStatus wxMacRegionToRectsCounterCallback(
89954433 392 UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data )
20b69855
SC
393{
394 long *m_numRects = (long*) data ;
395 if ( message == kQDRegionToRectsMsgInit )
396 {
397 (*m_numRects) = 0 ;
398 }
399 else if (message == kQDRegionToRectsMsgParse)
400 {
401 (*m_numRects) += 1 ;
402 }
5fa7a49c 403
20b69855
SC
404 return noErr;
405}
5fa7a49c
DS
406
407class RegionToRectsCallbackData
20b69855
SC
408{
409public :
410 wxRect* m_rects ;
411 long m_current ;
5fa7a49c 412};
20b69855 413
5fa7a49c 414OSStatus wxMacRegionToRectsSetterCallback(
89954433 415 UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data )
20b69855
SC
416{
417 if (message == kQDRegionToRectsMsgParse)
418 {
419 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
2b822a7e 420 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
20b69855 421 }
5fa7a49c 422
20b69855
SC
423 return noErr;
424}
1abfa172 425#endif
20b69855 426
e9576ca5
SC
427void wxRegionIterator::Reset(const wxRegion& region)
428{
6dcbb6d0
GD
429 m_current = 0;
430 m_region = region;
e9576ca5 431
5fa7a49c
DS
432 if (m_rects)
433 {
434 delete [] m_rects;
6dcbb6d0
GD
435 m_rects = NULL;
436 }
e9576ca5 437
8a16d737 438 if (m_region.IsEmpty())
5fa7a49c 439 {
6dcbb6d0 440 m_numRects = 0;
5fa7a49c 441 }
6dcbb6d0 442 else
e9576ca5 443 {
1abfa172
SC
444#ifdef __LP64__
445 // copying this to a path and dissecting the path would be an option
446 m_numRects = 1;
447 m_rects = new wxRect[m_numRects];
448 m_rects[0] = m_region.GetBox();
9a8864ca 449
e6c3d3e6 450#else
1abfa172 451 RegionToRectsUPP proc = (RegionToRectsUPP) wxMacRegionToRectsCounterCallback;
20b69855
SC
452
453 OSStatus err = noErr;
0903bd05
SC
454 RgnHandle rgn = NewRgn();
455 HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn);
9a8864ca 456
0903bd05 457 err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, proc, (void*)&m_numRects);
5fa7a49c 458 if (err == noErr)
20b69855 459 {
1abfa172 460 proc = (RegionToRectsUPP) wxMacRegionToRectsSetterCallback;
20b69855
SC
461 m_rects = new wxRect[m_numRects];
462 RegionToRectsCallbackData data ;
463 data.m_rects = m_rects ;
464 data.m_current = 0 ;
0903bd05 465 QDRegionToRects( rgn , kQDParseRegionFromTopLeft, proc, (void*)&data );
20b69855 466 }
5fa7a49c 467 else
20b69855 468 {
5fa7a49c 469 m_numRects = 0;
20b69855 470 }
0903bd05 471 DisposeRgn( rgn );
e6c3d3e6 472#endif
e9576ca5
SC
473 }
474}
475
476/*!
477 * Increment iterator. The rectangle returned is the one after the
478 * incrementation.
479 */
e7600a2c 480wxRegionIterator& wxRegionIterator::operator ++ ()
e9576ca5 481{
e7600a2c
GD
482 if (m_current < m_numRects)
483 ++m_current;
b3a44e05 484
e7600a2c 485 return *this;
e9576ca5
SC
486}
487
488/*!
489 * Increment iterator. The rectangle returned is the one before the
490 * incrementation.
491 */
e7600a2c 492wxRegionIterator wxRegionIterator::operator ++ (int)
e9576ca5 493{
e7600a2c
GD
494 wxRegionIterator previous(*this);
495
496 if (m_current < m_numRects)
497 ++m_current;
498
499 return previous;
e9576ca5
SC
500}
501
502long wxRegionIterator::GetX() const
503{
e40298d5
JS
504 if (m_current < m_numRects)
505 return m_rects[m_current].x;
5fa7a49c 506
e40298d5 507 return 0;
e9576ca5
SC
508}
509
510long wxRegionIterator::GetY() const
511{
e40298d5
JS
512 if (m_current < m_numRects)
513 return m_rects[m_current].y;
5fa7a49c 514
e40298d5 515 return 0;
e9576ca5
SC
516}
517
518long wxRegionIterator::GetW() const
519{
e40298d5
JS
520 if (m_current < m_numRects)
521 return m_rects[m_current].width ;
5fa7a49c 522
e40298d5 523 return 0;
e9576ca5
SC
524}
525
526long wxRegionIterator::GetH() const
527{
e40298d5
JS
528 if (m_current < m_numRects)
529 return m_rects[m_current].height;
5fa7a49c 530
e40298d5 531 return 0;
e9576ca5 532}