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