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