]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/region.cpp
changing code that doesn't work on 10.5 as advertised
[wxWidgets.git] / src / mac / carbon / region.cpp
index 3fb09a1ad27f2c20dae9ec455e599cf55049fe8b..d08fd4984c25b88208ffa5c7bd77738258a6bd85 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// File:      region.cpp
+// File:      src/mac/carbon/region.cpp
 // Purpose:   Region class
 // Author:    Stefan Csomor
 // Created:   Fri Oct 24 10:46:34 MET 1997
@@ -8,14 +8,14 @@
 // Licence:   wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "region.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #include "wx/region.h"
-#include "wx/gdicmn.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/gdicmn.h"
+#endif
+
 #include "wx/mac/uma.h"
 
 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
@@ -25,25 +25,37 @@ IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
 // wxRegionRefData implementation
 //-----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxRegionRefData : public wxGDIRefData {
+class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
+{
 public:
     wxRegionRefData()
     {
-        m_macRgn = NewRgn() ;
+        m_macRgn.reset( HIShapeCreateMutable() );
+    }
+
+    wxRegionRefData(wxCFRef<HIShapeRef> &region)
+    {
+        m_macRgn.reset( HIShapeCreateMutableCopy(region) );
+    }
+
+    wxRegionRefData(long x, long y, long w, long h)
+    {
+        CGRect r = CGRectMake(x,y,w,h);
+        wxCFRef<HIShapeRef> rect(HIShapeCreateWithRect(&r));
+        m_macRgn.reset( HIShapeCreateMutableCopy(rect) );
     }
 
     wxRegionRefData(const wxRegionRefData& data)
         : wxGDIRefData()
     {
-        m_macRgn = NewRgn() ;
-        CopyRgn( data.m_macRgn , m_macRgn ) ;
+        m_macRgn.reset( HIShapeCreateMutableCopy(data.m_macRgn) );
     }
 
-    ~wxRegionRefData()
+    virtual ~wxRegionRefData()
     {
-        DisposeRgn( m_macRgn ) ;
     }
-    RgnHandle    m_macRgn ;
+
+    wxCFRef<HIMutableShapeRef> m_macRgn;
 };
 
 #define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
@@ -58,66 +70,106 @@ public:
  */
 wxRegion::wxRegion()
 {
-    m_refData = new wxRegionRefData;
+    m_refData = new wxRegionRefData();
 }
 
 wxRegion::wxRegion(WXHRGN hRegion )
 {
-    m_refData = new wxRegionRefData;
-    CopyRgn( (RgnHandle) hRegion , (RgnHandle) M_REGION ) ;
+    wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion );
+    m_refData = new wxRegionRefData(shape);
 }
 
 wxRegion::wxRegion(long x, long y, long w, long h)
 {
-    m_refData = new wxRegionRefData;
-    SetRectRgn( (RgnHandle) M_REGION , x , y , x+w , y+h ) ;
+    m_refData = new wxRegionRefData(x , y , w , h );
 }
 
 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
 {
-    m_refData = new wxRegionRefData;
-    SetRectRgn( (RgnHandle) M_REGION , topLeft.x , topLeft.y , bottomRight.x , bottomRight.y ) ;
+    m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
+                                    topLeft.x - bottomRight.x ,
+                                    topLeft.y - bottomRight.y);
 }
 
 wxRegion::wxRegion(const wxRect& rect)
 {
-    m_refData = new wxRegionRefData;
-    SetRectRgn( (RgnHandle) M_REGION , rect.x , rect.y , rect.x+rect.width , rect.y+rect.height ) ;
+    m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
 }
 
 wxRegion::wxRegion(size_t n, const wxPoint *points, int WXUNUSED(fillStyle))
 {
-    m_refData = new wxRegionRefData;
+    wxUnusedVar(n);
+    wxUnusedVar(points);
+
+#ifndef __LP64__
 
-    OpenRgn();
+    // TODO : any APIs ?
+    // OS X somehow does not collect the region invisibly as before, so sometimes things
+    // get drawn on screen instead of just being combined into a region, therefore we allocate a temp gworld now
 
-    wxCoord x1, x2 , y1 , y2 ;
-    x2 = x1 = points[0].x ;
-    y2 = y1 = points[0].y ;
-    ::MoveTo(x1,y1);
-    for (size_t i = 1; i < n; i++)
+    GWorldPtr gWorld = NULL;
+    GWorldPtr oldWorld;
+    GDHandle oldGDHandle;
+    OSStatus err;
+    Rect destRect = { 0, 0, 1, 1 };
+
+    ::GetGWorld( &oldWorld, &oldGDHandle );
+    err = ::NewGWorld( &gWorld, 32, &destRect, NULL, NULL, 0 );
+    if ( err == noErr )
     {
-        x2 = points[i].x ;
-        y2 = points[i].y ;
-        ::LineTo(x2, y2);
+        ::SetGWorld( gWorld, GetGDevice() );
+
+        OpenRgn();
+
+        wxCoord x1, x2 , y1 , y2 ;
+        x2 = x1 = points[0].x ;
+        y2 = y1 = points[0].y ;
+
+        ::MoveTo( x1, y1 );
+        for (size_t i = 1; i < n; i++)
+        {
+            x2 = points[i].x ;
+            y2 = points[i].y ;
+            ::LineTo( x2, y2 );
+        }
+
+        // close the polyline if necessary
+        if ( x1 != x2 || y1 != y2 )
+            ::LineTo( x1, y1 ) ;
+
+        RgnHandle tempRgn = NewRgn();
+        CloseRgn( tempRgn ) ;
+        ::SetGWorld( oldWorld, oldGDHandle );
+        wxCFRef<HIShapeRef> tempShape( HIShapeCreateWithQDRgn(tempRgn ) );
+        m_refData = new wxRegionRefData(tempShape);
+        DisposeRgn( tempRgn );
     }
-    // close the polyline if necessary
-    if ( x1 != x2 || y1 != y2 )
+    else
     {
-        ::LineTo(x1,y1 ) ;
+        m_refData = new wxRegionRefData;
     }
-    ClosePoly();
-    CloseRgn( M_REGION ) ;
+#else
+    wxFAIL_MSG( "not implemented" );
+    m_refData = NULL;
+#endif
 }
 
-/*!
- * Destroy the region.
- */
 wxRegion::~wxRegion()
 {
     // m_refData unrefed in ~wxObject
 }
 
+wxGDIRefData *wxRegion::CreateGDIRefData() const
+{
+    return new wxRegionRefData;
+}
+
+wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
+{
+    return new wxRegionRefData(*wx_static_cast(const wxRegionRefData *, data));
+}
+
 //-----------------------------------------------------------------------------
 //# Modify region
 //-----------------------------------------------------------------------------
@@ -129,74 +181,31 @@ void wxRegion::Clear()
 }
 
 // Move the region
-bool wxRegion::Offset(wxCoord x, wxCoord y)
+bool wxRegion::DoOffset(wxCoord x, wxCoord y)
 {
     wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") );
 
     if ( !x && !y )
-    {
         // nothing to do
         return true;
-    }
 
-    OffsetRgn( M_REGION , x , y ) ;
+    verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
+
     return true ;
 }
 
 
-//! Combine rectangle (x, y, w, h) with this.
-bool wxRegion::Combine(long x, long y, long width, long height, wxRegionOp op)
-{
-    // Don't change shared data
-    if (!m_refData) 
-    {
-        m_refData = new wxRegionRefData();
-    } 
-    else if (m_refData->GetRefCount() > 1) 
-    {
-        wxRegionRefData* ref = (wxRegionRefData*)m_refData;
-        UnRef();
-        m_refData = new wxRegionRefData(*ref);
-    }
-    RgnHandle rgn = NewRgn() ;
-        SetRectRgn( rgn , x , y, x+width,y + height ) ;
-        
-    switch (op)
-    {
-        case wxRGN_AND:
-            SectRgn( M_REGION , rgn , M_REGION ) ;
-            break ;
-        case wxRGN_OR:
-            UnionRgn( M_REGION , rgn , M_REGION ) ;
-            break ;
-        case wxRGN_XOR:
-             XorRgn( M_REGION , rgn , M_REGION ) ;
-            break ;
-        case wxRGN_DIFF:
-            DiffRgn( M_REGION , rgn , M_REGION ) ;
-            break ;
-        case wxRGN_COPY:
-        default:
-                   CopyRgn( rgn ,M_REGION ) ;
-            break ;
-    }
-
-        DisposeRgn( rgn ) ;
-
-    return TRUE;
-}
-
 //! Union /e region with this.
-bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
+bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
 {
-    if (region.Empty())
-        return FALSE;
+    wxCHECK_MSG( region.Ok(), false, _T("invalid wxRegion") );
 
     // Don't change shared data
-    if (!m_refData) {
+    if (!m_refData)
+    {
         m_refData = new wxRegionRefData();
-    } 
-    else    if (m_refData->GetRefCount() > 1) 
+    }
+    else if (m_refData->GetRefCount() > 1)
     {
         wxRegionRefData* ref = (wxRegionRefData*)m_refData;
         UnRef();
@@ -206,64 +215,75 @@ bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
     switch (op)
     {
         case wxRGN_AND:
-            SectRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
+            verify_noerr( HIShapeIntersect( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
             break ;
+
         case wxRGN_OR:
-            UnionRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
+            verify_noerr( HIShapeUnion( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
             break ;
+
         case wxRGN_XOR:
-             XorRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
+            {
+                // XOR is defined as the difference between union and intersection
+                wxCFRef< HIShapeRef > unionshape( HIShapeCreateUnion( M_REGION , OTHER_M_REGION(region) ) );
+                wxCFRef< HIShapeRef > intersectionshape( HIShapeCreateIntersection( M_REGION , OTHER_M_REGION(region) ) );
+                verify_noerr( HIShapeDifference( unionshape, intersectionshape, M_REGION ) );
+            }
             break ;
+
         case wxRGN_DIFF:
-            DiffRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
+            verify_noerr( HIShapeDifference( M_REGION , OTHER_M_REGION(region) , M_REGION ) ) ;
             break ;
+
         case wxRGN_COPY:
         default:
-                   CopyRgn( OTHER_M_REGION(region) ,M_REGION ) ;
+            M_REGION.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region) ) );
             break ;
     }
 
-    return TRUE;
-}
-
-bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
-{
-    return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
+    return true;
 }
 
 //-----------------------------------------------------------------------------
 //# Information on region
 //-----------------------------------------------------------------------------
 
+bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const
+{
+    wxFAIL_MSG( _T("not implemented") );
+
+    return false;
+}
+
 // Outer bounds of region
-void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
+bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
 {
-    if (m_refData) 
+    if (m_refData)
     {
-        Rect box ;
-        GetRegionBounds( M_REGION , &box ) ;
-        x = box.left ;
-        y = box.top ;
-        w = box.right - box.left ;
-        h = box.bottom - box.top ;
-    } 
-    else 
+        CGRect box ;
+        HIShapeGetBounds( M_REGION , &box ) ;
+        x = wx_static_cast(int, box.origin.x);
+        y = wx_static_cast(int, box.origin.y);
+        w = wx_static_cast(int, box.size.width);
+        h = wx_static_cast(int, box.size.height);
+
+        return true;
+    }
+    else
     {
         x = y = w = h = 0;
-    }
-}
 
-wxRect wxRegion::GetBox() const
-{
-    wxCoord x, y, w, h;
-    GetBox(x, y, w, h);
-    return wxRect(x, y, w, h);
+        return false;
+    }
 }
 
 // Is region empty?
-bool wxRegion::Empty() const
+bool wxRegion::IsEmpty() const
 {
-    return EmptyRgn( M_REGION ) ;
+    if ( m_refData )
+        return HIShapeIsEmpty( M_REGION ) ;
+    else
+        return true ;
 }
 
 const WXHRGN wxRegion::GetWXHRGN() const
@@ -275,56 +295,37 @@ const WXHRGN wxRegion::GetWXHRGN() const
 //# Tests
 //-----------------------------------------------------------------------------
 
-// Does the region contain the point (x,y)?
-wxRegionContain wxRegion::Contains(long x, long y) const
+// Does the region contain the point?
+wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
 {
     if (!m_refData)
         return wxOutRegion;
 
-    // TODO. Return wxInRegion if within region.
-    if (0)
+    CGPoint p = { y , x } ;
+    if (HIShapeContainsPoint( M_REGION , &p ) )
         return wxInRegion;
-    return wxOutRegion;
-}
 
-// Does the region contain the point pt?
-wxRegionContain wxRegion::Contains(const wxPoint& pt) const
-{
-    if (!m_refData)
-        return wxOutRegion;
-
-    Point p = { pt.y , pt.x } ;
-    if (PtInRgn( p , M_REGION ) )
-        return wxInRegion;
-        
     return wxOutRegion;
 }
 
 // Does the region contain the rectangle (x, y, w, h)?
-wxRegionContain wxRegion::Contains(long x, long y, long w, long h) const
+wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
 {
     if (!m_refData)
         return wxOutRegion;
 
-    Rect rect = { y , x , y + h , x + w } ;
-    if (RectInRgn( &rect , M_REGION ) )
-        return wxInRegion;
-    else
-        return wxOutRegion;
-}
+    CGRect rect = CGRectMake(r.x,r.y,r.width,r.height);
+    wxCFRef<HIShapeRef> rectshape(HIShapeCreateWithRect(&rect));
+    wxCFRef<HIShapeRef> intersect(HIShapeCreateIntersection(rectshape,M_REGION));
+    CGRect bounds;
+    HIShapeGetBounds(intersect, &bounds);
 
-// Does the region contain the rectangle rect
-wxRegionContain wxRegion::Contains(const wxRect& rect) const
-{
-    if (!m_refData)
+    if ( HIShapeIsRectangular(intersect) && CGRectEqualToRect(rect,bounds) )
+        return wxInRegion;
+    else if ( HIShapeIsEmpty( intersect ) )
         return wxOutRegion;
-
-    long x, y, w, h;
-    x = rect.x;
-    y = rect.y;
-    w = rect.GetWidth();
-    h = rect.GetHeight();
-    return Contains(x, y, w, h);
+    else
+        return wxPartRegion;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -343,8 +344,9 @@ wxRegionIterator::wxRegionIterator()
 
 wxRegionIterator::~wxRegionIterator()
 {
-    if (m_rects) {
-        delete[] m_rects;
+    if (m_rects)
+    {
+        delete [] m_rects;
         m_rects = NULL;
     }
 }
@@ -362,6 +364,7 @@ wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
 {
     m_current  = iterator.m_current;
     SetRects(iterator.m_numRects, iterator.m_rects);
+
     return *this;
 }
 
@@ -370,17 +373,21 @@ wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
  */
 void wxRegionIterator::SetRects(long numRects, wxRect *rects)
 {
-    if (m_rects) {
-        delete[] m_rects;
+    if (m_rects)
+    {
+        delete [] m_rects;
         m_rects = NULL;
     }
-    if (rects)
+
+    if (rects && (numRects > 0))
     {
         int i;
+
         m_rects = new wxRect[numRects];
         for (i = 0; i < numRects; i++)
             m_rects[i] = rects[i];
     }
+
     m_numRects = numRects;
 }
 
@@ -397,9 +404,10 @@ wxRegionIterator::wxRegionIterator(const wxRegion& region)
 /*!
  * Reset iterator for a new /e region.
  */
-OSStatus wxMacRegionToRectsCounterCallback (
-    UInt16 message, RgnHandle region, const Rect *rect, void *data)
+
+#ifndef __LP64__
+OSStatus wxMacRegionToRectsCounterCallback(
+    UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data )
 {
     long *m_numRects = (long*) data ;
     if ( message == kQDRegionToRectsMsgInit )
@@ -410,60 +418,76 @@ OSStatus wxMacRegionToRectsCounterCallback (
     {
         (*m_numRects) += 1 ;
     }
+
     return noErr;
 }
-class RegionToRectsCallbackData 
+
+class RegionToRectsCallbackData
 {
 public :
     wxRect* m_rects ;
     long m_current ;
-} ;
+};
 
-OSStatus wxMacRegionToRectsSetterCallback (
-    UInt16 message, RgnHandle region, const Rect *rect, void *data)
+OSStatus wxMacRegionToRectsSetterCallback(
+    UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data )
 {
     if (message == kQDRegionToRectsMsgParse)
     {
         RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
         cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
     }
+
     return noErr;
 }
+#endif
 
 void wxRegionIterator::Reset(const wxRegion& region)
 {
     m_current = 0;
     m_region = region;
 
-    if (m_rects) {
-        delete[] m_rects;
+    if (m_rects)
+    {
+        delete [] m_rects;
         m_rects = NULL;
     }
 
-    if (m_region.Empty())
+    if (m_region.IsEmpty())
+    {
         m_numRects = 0;
+    }
     else
     {
-        RegionToRectsUPP proc = NewRegionToRectsUPP (wxMacRegionToRectsCounterCallback);
+#ifdef __LP64__
+        // copying this to a path and dissecting the path would be an option
+        m_numRects = 1;
+        m_rects = new wxRect[m_numRects];
+        m_rects[0] = m_region.GetBox();
+
+#else
+        RegionToRectsUPP proc = (RegionToRectsUPP) wxMacRegionToRectsCounterCallback;
 
         OSStatus err = noErr;
-        err = QDRegionToRects (OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&m_numRects); 
-        if (err == noErr) 
+        RgnHandle rgn = NewRgn();
+        HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn);
+
+        err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, proc, (void*)&m_numRects);
+        if (err == noErr)
         {
-            DisposeRegionToRectsUPP (proc);
-            proc = NewRegionToRectsUPP (wxMacRegionToRectsSetterCallback);
+            proc = (RegionToRectsUPP) wxMacRegionToRectsSetterCallback;
             m_rects = new wxRect[m_numRects];
             RegionToRectsCallbackData data ;
             data.m_rects = m_rects ;
             data.m_current = 0 ;
-            QDRegionToRects (OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&data); 
+            QDRegionToRects( rgn , kQDParseRegionFromTopLeft, proc, (void*)&data );
         }
-        else 
+        else
         {
-            m_numRects = 0 ;
+            m_numRects = 0;
         }
-        DisposeRegionToRectsUPP (proc);
+        DisposeRgn( rgn );
+#endif
     }
 }
 
@@ -475,6 +499,7 @@ wxRegionIterator& wxRegionIterator::operator ++ ()
 {
     if (m_current < m_numRects)
         ++m_current;
+
     return *this;
 }
 
@@ -496,6 +521,7 @@ long wxRegionIterator::GetX() const
 {
     if (m_current < m_numRects)
         return m_rects[m_current].x;
+
     return 0;
 }
 
@@ -503,6 +529,7 @@ long wxRegionIterator::GetY() const
 {
     if (m_current < m_numRects)
         return m_rects[m_current].y;
+
     return 0;
 }
 
@@ -510,6 +537,7 @@ long wxRegionIterator::GetW() const
 {
     if (m_current < m_numRects)
         return m_rects[m_current].width ;
+
     return 0;
 }
 
@@ -517,6 +545,6 @@ long wxRegionIterator::GetH() const
 {
     if (m_current < m_numRects)
         return m_rects[m_current].height;
+
     return 0;
 }
-