]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/region.cpp
Create an autorelease pool to catch objects created during several special situations...
[wxWidgets.git] / src / osx / carbon / region.cpp
CommitLineData
489468fe
SC
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
5398a2e0 19#include "wx/osx/private.h"
489468fe
SC
20
21IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
22IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
23
24//-----------------------------------------------------------------------------
25// wxRegionRefData implementation
26//-----------------------------------------------------------------------------
27
28class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
29{
30public:
31 wxRegionRefData()
32 {
33 m_macRgn.reset( HIShapeCreateMutable() );
34 }
35
36 wxRegionRefData(wxCFRef<HIShapeRef> &region)
37 {
38 m_macRgn.reset( HIShapeCreateMutableCopy(region) );
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 */
71wxRegion::wxRegion()
72{
73 m_refData = new wxRegionRefData();
74}
75
76wxRegion::wxRegion(WXHRGN hRegion )
77{
78 wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion );
79 m_refData = new wxRegionRefData(shape);
80}
81
82wxRegion::wxRegion(long x, long y, long w, long h)
83{
84 m_refData = new wxRegionRefData(x , y , w , h );
85}
86
87wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
88{
89 m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
90 topLeft.x - bottomRight.x ,
91 topLeft.y - bottomRight.y);
92}
93
94wxRegion::wxRegion(const wxRect& rect)
95{
96 m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
97}
98
1ed06824 99wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode WXUNUSED(fillStyle))
489468fe
SC
100{
101 wxUnusedVar(n);
102 wxUnusedVar(points);
103
03647350 104#if 0
5398a2e0
SC
105 // no non-QD APIs available
106 // TODO : remove ?
489468fe
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
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 RgnHandle tempRgn = NewRgn();
141 CloseRgn( tempRgn ) ;
03647350 142
489468fe
SC
143 ::SetGWorld( oldWorld, oldGDHandle );
144 wxCFRef<HIShapeRef> tempShape( HIShapeCreateWithQDRgn(tempRgn ) );
145 m_refData = new wxRegionRefData(tempShape);
146 DisposeRgn( tempRgn );
147 }
148 else
149 {
150 m_refData = new wxRegionRefData;
151 }
152#else
153 wxFAIL_MSG( "not implemented" );
154 m_refData = NULL;
155#endif
156}
157
158wxRegion::~wxRegion()
159{
160 // m_refData unrefed in ~wxObject
161}
162
163wxGDIRefData *wxRegion::CreateGDIRefData() const
164{
165 return new wxRegionRefData;
166}
167
168wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
169{
5c33522f 170 return new wxRegionRefData(*static_cast<const wxRegionRefData *>(data));
489468fe
SC
171}
172
173//-----------------------------------------------------------------------------
174//# Modify region
175//-----------------------------------------------------------------------------
176
177//! Clear current region
178void wxRegion::Clear()
179{
180 UnRef();
181}
182
183// Move the region
184bool wxRegion::DoOffset(wxCoord x, wxCoord y)
185{
9a83f860 186 wxCHECK_MSG( M_REGION, false, wxT("invalid wxRegion") );
489468fe
SC
187
188 if ( !x && !y )
189 // nothing to do
190 return true;
191
192 verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
193
194 return true ;
195}
196
197
198//! Union /e region with this.
199bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
200{
9a83f860 201 wxCHECK_MSG( region.Ok(), false, wxT("invalid wxRegion") );
489468fe
SC
202
203 // Don't change shared data
204 if (!m_refData)
205 {
206 m_refData = new wxRegionRefData();
207 }
208 else if (m_refData->GetRefCount() > 1)
209 {
210 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
211 UnRef();
212 m_refData = new wxRegionRefData(*ref);
213 }
214
215 switch (op)
216 {
217 case wxRGN_AND:
218 verify_noerr( HIShapeIntersect( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
219 break ;
220
221 case wxRGN_OR:
222 verify_noerr( HIShapeUnion( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
223 break ;
224
225 case wxRGN_XOR:
226 {
227 // XOR is defined as the difference between union and intersection
228 wxCFRef< HIShapeRef > unionshape( HIShapeCreateUnion( M_REGION , OTHER_M_REGION(region) ) );
229 wxCFRef< HIShapeRef > intersectionshape( HIShapeCreateIntersection( M_REGION , OTHER_M_REGION(region) ) );
230 verify_noerr( HIShapeDifference( unionshape, intersectionshape, M_REGION ) );
231 }
232 break ;
233
234 case wxRGN_DIFF:
235 verify_noerr( HIShapeDifference( M_REGION , OTHER_M_REGION(region) , M_REGION ) ) ;
236 break ;
237
238 case wxRGN_COPY:
239 default:
240 M_REGION.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region) ) );
241 break ;
242 }
243
244 return true;
245}
246
247//-----------------------------------------------------------------------------
248//# Information on region
249//-----------------------------------------------------------------------------
250
251bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const
252{
9a83f860 253 wxFAIL_MSG( wxT("not implemented") );
489468fe
SC
254
255 return false;
256}
257
258// Outer bounds of region
259bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
260{
261 if (m_refData)
262 {
263 CGRect box ;
264 HIShapeGetBounds( M_REGION , &box ) ;
5c33522f
VZ
265 x = static_cast<int>(box.origin.x);
266 y = static_cast<int>(box.origin.y);
267 w = static_cast<int>(box.size.width);
268 h = static_cast<int>(box.size.height);
489468fe
SC
269
270 return true;
271 }
272 else
273 {
274 x = y = w = h = 0;
275
276 return false;
277 }
278}
279
280// Is region empty?
281bool wxRegion::IsEmpty() const
282{
283 if ( m_refData )
284 return HIShapeIsEmpty( M_REGION ) ;
285 else
286 return true ;
287}
288
289const WXHRGN wxRegion::GetWXHRGN() const
290{
291 return M_REGION ;
292}
293
294//-----------------------------------------------------------------------------
295//# Tests
296//-----------------------------------------------------------------------------
297
298// Does the region contain the point?
299wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
300{
301 if (!m_refData)
302 return wxOutRegion;
303
e331a94e 304 CGPoint p = { x, y } ;
489468fe
SC
305 if (HIShapeContainsPoint( M_REGION , &p ) )
306 return wxInRegion;
307
308 return wxOutRegion;
309}
310
311// Does the region contain the rectangle (x, y, w, h)?
312wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
313{
314 if (!m_refData)
315 return wxOutRegion;
316
317 CGRect rect = CGRectMake(r.x,r.y,r.width,r.height);
318 wxCFRef<HIShapeRef> rectshape(HIShapeCreateWithRect(&rect));
319 wxCFRef<HIShapeRef> intersect(HIShapeCreateIntersection(rectshape,M_REGION));
320 CGRect bounds;
321 HIShapeGetBounds(intersect, &bounds);
322
323 if ( HIShapeIsRectangular(intersect) && CGRectEqualToRect(rect,bounds) )
324 return wxInRegion;
325 else if ( HIShapeIsEmpty( intersect ) )
326 return wxOutRegion;
327 else
328 return wxPartRegion;
329}
330
331///////////////////////////////////////////////////////////////////////////////
332// //
333// wxRegionIterator //
334// //
335///////////////////////////////////////////////////////////////////////////////
336
337/*!
338 * Initialize empty iterator
339 */
340wxRegionIterator::wxRegionIterator()
341 : m_current(0), m_numRects(0), m_rects(NULL)
342{
343}
344
345wxRegionIterator::~wxRegionIterator()
346{
347 if (m_rects)
348 {
349 delete [] m_rects;
350 m_rects = NULL;
351 }
352}
353
354wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
355 : wxObject()
356 , m_current(iterator.m_current)
357 , m_numRects(0)
358 , m_rects(NULL)
359{
360 SetRects(iterator.m_numRects, iterator.m_rects);
361}
362
363wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
364{
365 m_current = iterator.m_current;
366 SetRects(iterator.m_numRects, iterator.m_rects);
367
368 return *this;
369}
370
371/*!
372 * Set iterator rects for region
373 */
374void wxRegionIterator::SetRects(long numRects, wxRect *rects)
375{
376 if (m_rects)
377 {
378 delete [] m_rects;
379 m_rects = NULL;
380 }
381
382 if (rects && (numRects > 0))
383 {
384 int i;
385
386 m_rects = new wxRect[numRects];
387 for (i = 0; i < numRects; i++)
388 m_rects[i] = rects[i];
389 }
390
391 m_numRects = numRects;
392}
393
394/*!
395 * Initialize iterator for region
396 */
397wxRegionIterator::wxRegionIterator(const wxRegion& region)
398{
399 m_rects = NULL;
400
401 Reset(region);
402}
403
404/*!
405 * Reset iterator for a new /e region.
406 */
407
5398a2e0
SC
408class RegionToRectsCallbackData
409{
410public :
411 wxRect* m_rects ;
412 long m_current ;
413};
414
415#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
416
489468fe
SC
417OSStatus wxMacRegionToRectsCounterCallback(
418 UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data )
419{
420 long *m_numRects = (long*) data ;
421 if ( message == kQDRegionToRectsMsgInit )
422 {
423 (*m_numRects) = 0 ;
424 }
425 else if (message == kQDRegionToRectsMsgParse)
426 {
427 (*m_numRects) += 1 ;
428 }
429
430 return noErr;
431}
432
489468fe
SC
433OSStatus wxMacRegionToRectsSetterCallback(
434 UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data )
435{
436 if (message == kQDRegionToRectsMsgParse)
437 {
438 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
439 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
440 }
441
442 return noErr;
443}
5398a2e0
SC
444
445#endif
446
447#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
448
449OSStatus wxOSXRegionToRectsCounterCallback(
450 int message, HIShapeRef WXUNUSED(region), const CGRect *WXUNUSED(rect), void *data )
451{
452 long *m_numRects = (long*) data ;
453 if ( message == kHIShapeEnumerateInit )
454 {
455 (*m_numRects) = 0 ;
456 }
457 else if (message == kHIShapeEnumerateRect)
458 {
459 (*m_numRects) += 1 ;
460 }
461
462 return noErr;
463}
464
465OSStatus wxOSXRegionToRectsSetterCallback(
466 int message, HIShapeRef WXUNUSED(region), const CGRect *rect, void *data )
467{
468 if (message == kHIShapeEnumerateRect)
469 {
470 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
471 cb->m_rects[cb->m_current++] = wxRect( rect->origin.x , rect->origin.y , rect->size.width , rect->size.height ) ;
472 }
473
474 return noErr;
475}
476
489468fe
SC
477#endif
478
479void wxRegionIterator::Reset(const wxRegion& region)
480{
481 m_current = 0;
482 m_region = region;
483
484 if (m_rects)
485 {
486 delete [] m_rects;
487 m_rects = NULL;
488 }
489
490 if (m_region.IsEmpty())
491 {
492 m_numRects = 0;
493 }
494 else
495 {
5398a2e0
SC
496#if 0
497 // fallback code in case we ever need it again
489468fe
SC
498 // copying this to a path and dissecting the path would be an option
499 m_numRects = 1;
500 m_rects = new wxRect[m_numRects];
501 m_rects[0] = m_region.GetBox();
5398a2e0 502#endif
489468fe 503
5398a2e0
SC
504#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
505 if ( HIShapeEnumerate != NULL )
489468fe 506 {
03647350 507 OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback,
5398a2e0
SC
508 (void*)&m_numRects);
509 if (err == noErr)
510 {
511 m_rects = new wxRect[m_numRects];
512 RegionToRectsCallbackData data ;
513 data.m_rects = m_rects ;
514 data.m_current = 0 ;
03647350 515 HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback,
5398a2e0
SC
516 (void*)&data );
517 }
518 else
519 {
520 m_numRects = 0;
521 }
489468fe
SC
522 }
523 else
5398a2e0 524#endif
489468fe 525 {
5398a2e0
SC
526#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
527 OSStatus err = noErr;
528 RgnHandle rgn = NewRgn();
529 HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn);
530
531 err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, wxMacRegionToRectsCounterCallback
532 , (void*)&m_numRects);
533 if (err == noErr)
534 {
535 m_rects = new wxRect[m_numRects];
536 RegionToRectsCallbackData data ;
537 data.m_rects = m_rects ;
538 data.m_current = 0 ;
03647350 539 QDRegionToRects( rgn , kQDParseRegionFromTopLeft, wxMacRegionToRectsSetterCallback,
5398a2e0
SC
540 (void*)&data );
541 }
542 else
543 {
544 m_numRects = 0;
545 }
546 DisposeRgn( rgn );
489468fe 547#endif
5398a2e0 548 }
489468fe
SC
549 }
550}
551
552/*!
553 * Increment iterator. The rectangle returned is the one after the
554 * incrementation.
555 */
556wxRegionIterator& wxRegionIterator::operator ++ ()
557{
558 if (m_current < m_numRects)
559 ++m_current;
560
561 return *this;
562}
563
564/*!
565 * Increment iterator. The rectangle returned is the one before the
566 * incrementation.
567 */
568wxRegionIterator wxRegionIterator::operator ++ (int)
569{
570 wxRegionIterator previous(*this);
571
572 if (m_current < m_numRects)
573 ++m_current;
574
575 return previous;
576}
577
578long wxRegionIterator::GetX() const
579{
580 if (m_current < m_numRects)
581 return m_rects[m_current].x;
582
583 return 0;
584}
585
586long wxRegionIterator::GetY() const
587{
588 if (m_current < m_numRects)
589 return m_rects[m_current].y;
590
591 return 0;
592}
593
594long wxRegionIterator::GetW() const
595{
596 if (m_current < m_numRects)
597 return m_rects[m_current].width ;
598
599 return 0;
600}
601
602long wxRegionIterator::GetH() const
603{
604 if (m_current < m_numRects)
605 return m_rects[m_current].height;
606
607 return 0;
608}