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