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