]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/region.cpp
Merge in from trunk r68684 - r69046
[wxWidgets.git] / src / osx / carbon / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: src/osx/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 #include "wx/dcmemory.h"
20 #endif
21
22 #include "wx/osx/private.h"
23
24 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
25 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
26
27 //-----------------------------------------------------------------------------
28 // wxRegionRefData implementation
29 //-----------------------------------------------------------------------------
30
31 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
32 {
33 public:
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 */
74 wxRegion::wxRegion()
75 {
76 m_refData = new wxRegionRefData();
77 }
78
79 wxRegion::wxRegion(WXHRGN hRegion )
80 {
81 wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion );
82 m_refData = new wxRegionRefData(shape);
83 }
84
85 wxRegion::wxRegion(long x, long y, long w, long h)
86 {
87 m_refData = new wxRegionRefData(x , y , w , h );
88 }
89
90 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
91 {
92 m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
93 bottomRight.x - topLeft.x,
94 bottomRight.y - topLeft.y);
95 }
96
97 wxRegion::wxRegion(const wxRect& rect)
98 {
99 m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
100 }
101
102 wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode WXUNUSED(fillStyle))
103 {
104 wxUnusedVar(n);
105 wxUnusedVar(points);
106
107 #if 0
108 // no non-QD APIs available
109 // TODO : remove ?
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 ) ;
145
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
161 wxRegion::~wxRegion()
162 {
163 // m_refData unrefed in ~wxObject
164 }
165
166 wxGDIRefData *wxRegion::CreateGDIRefData() const
167 {
168 return new wxRegionRefData;
169 }
170
171 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
172 {
173 return new wxRegionRefData(*static_cast<const wxRegionRefData *>(data));
174 }
175
176 //-----------------------------------------------------------------------------
177 //# Modify region
178 //-----------------------------------------------------------------------------
179
180 //! Clear current region
181 void wxRegion::Clear()
182 {
183 UnRef();
184 }
185
186 // Move the region
187 bool wxRegion::DoOffset(wxCoord x, wxCoord y)
188 {
189 wxCHECK_MSG( M_REGION, false, wxT("invalid wxRegion") );
190
191 if ( !x && !y )
192 // nothing to do
193 return true;
194
195 AllocExclusive();
196
197 verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
198
199 return true ;
200 }
201
202
203 //! Union /e region with this.
204 bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
205 {
206 wxCHECK_MSG( region.IsOk(), false, wxT("invalid wxRegion") );
207
208 AllocExclusive();
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
246 bool wxRegion::DoIsEqual(const wxRegion& region) const
247 {
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.
251 wxRegion r(*this);
252 r.Subtract(region);
253
254 if ( !r.IsEmpty() )
255 return false;
256
257 wxRegion r2(region);
258 r2.Subtract(*this);
259
260 return r2.IsEmpty();
261 }
262
263 // Outer bounds of region
264 bool 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 ) ;
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);
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?
286 bool wxRegion::IsEmpty() const
287 {
288 if ( m_refData )
289 return HIShapeIsEmpty( M_REGION ) ;
290 else
291 return true ;
292 }
293
294 WXHRGN wxRegion::GetWXHRGN() const
295 {
296 return M_REGION ;
297 }
298
299 //-----------------------------------------------------------------------------
300 //# Tests
301 //-----------------------------------------------------------------------------
302
303 // Does the region contain the point?
304 wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
305 {
306 if (!m_refData)
307 return wxOutRegion;
308
309 CGPoint p = { x, y } ;
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)?
317 wxRegionContain 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 */
345 wxRegionIterator::wxRegionIterator()
346 : m_current(0), m_numRects(0), m_rects(NULL)
347 {
348 }
349
350 wxRegionIterator::~wxRegionIterator()
351 {
352 wxDELETEA(m_rects);
353 }
354
355 wxRegionIterator::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
364 wxRegionIterator& 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 */
375 void wxRegionIterator::SetRects(long numRects, wxRect *rects)
376 {
377 wxDELETEA(m_rects);
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 */
394 wxRegionIterator::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
405 class RegionToRectsCallbackData
406 {
407 public :
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
414 OSStatus 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
430 OSStatus 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 }
441
442 #endif
443
444 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
445
446 OSStatus 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
462 OSStatus 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
474 #endif
475
476 void wxRegionIterator::Reset(const wxRegion& region)
477 {
478 m_current = 0;
479 m_region = region;
480
481 wxDELETEA(m_rects);
482
483 if (m_region.IsEmpty())
484 {
485 m_numRects = 0;
486 }
487 else
488 {
489 #if 0
490 // fallback code in case we ever need it again
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();
495 #endif
496
497 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
498 if ( HIShapeEnumerate != NULL )
499 {
500 OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback,
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 ;
508 HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback,
509 (void*)&data );
510 }
511 else
512 {
513 m_numRects = 0;
514 }
515 }
516 else
517 #endif
518 {
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 ;
532 QDRegionToRects( rgn , kQDParseRegionFromTopLeft, wxMacRegionToRectsSetterCallback,
533 (void*)&data );
534 }
535 else
536 {
537 m_numRects = 0;
538 }
539 DisposeRgn( rgn );
540 #endif
541 }
542 }
543 }
544
545 /*!
546 * Increment iterator. The rectangle returned is the one after the
547 * incrementation.
548 */
549 wxRegionIterator& 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 */
561 wxRegionIterator wxRegionIterator::operator ++ (int)
562 {
563 wxRegionIterator previous(*this);
564
565 if (m_current < m_numRects)
566 ++m_current;
567
568 return previous;
569 }
570
571 long wxRegionIterator::GetX() const
572 {
573 if (m_current < m_numRects)
574 return m_rects[m_current].x;
575
576 return 0;
577 }
578
579 long wxRegionIterator::GetY() const
580 {
581 if (m_current < m_numRects)
582 return m_rects[m_current].y;
583
584 return 0;
585 }
586
587 long wxRegionIterator::GetW() const
588 {
589 if (m_current < m_numRects)
590 return m_rects[m_current].width ;
591
592 return 0;
593 }
594
595 long wxRegionIterator::GetH() const
596 {
597 if (m_current < m_numRects)
598 return m_rects[m_current].height;
599
600 return 0;
601 }
602
603 #endif