]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/graphics.cpp
PCH support.
[wxWidgets.git] / src / mac / carbon / graphics.cpp
index 63a716c19b03d8cd44c77cbe5c8251c73f9a3f16..6aec43bfc27f71f15a462d08dbcae4b89b49c2bb 100755 (executable)
 
 #include "wx/wxprec.h"
 
-#include "wx/graphics.h"
-
 #if wxUSE_GRAPHICS_CONTEXT && wxMAC_USE_CORE_GRAPHICS
 
+#include "wx/graphics.h"
+
 #ifndef WX_PRECOMP
+    #include "wx/dcclient.h"
     #include "wx/log.h"
-    #include "wx/app.h"
-    #include "wx/dcmemory.h"
-    #include "wx/dcprint.h"
     #include "wx/region.h"
-    #include "wx/image.h"
 #endif
 
 #include "wx/mac/uma.h"
 
-
 #ifdef __MSL__
     #if __MSL__ >= 0x6000
         #include "math.h"
 typedef float CGFloat;
 #endif
 
+//-----------------------------------------------------------------------------
+// constants
+//-----------------------------------------------------------------------------
+
+#if !defined( __DARWIN__ ) || defined(__MWERKS__)
+#ifndef M_PI
+const double M_PI = 3.14159265358979;
+#endif
+#endif
+
+static const double RAD2DEG = 180.0 / M_PI;
+
 //
 // Graphics Path
 //
 
 class WXDLLEXPORT wxMacCoreGraphicsPath : public wxGraphicsPath
 {
-    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath)
 public :
     wxMacCoreGraphicsPath();
     ~wxMacCoreGraphicsPath();
@@ -88,11 +95,24 @@ public :
     // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
     virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
     
-    CGPathRef GetPath() const;
+       // returns the native path
+       virtual void * GetNativePath() const { return m_path; }
+       
+       // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
+       virtual void UnGetNativePath(void *p) {}
+
+    DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsPath)
+    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath)
 private :
     CGMutablePathRef m_path;
 };
 
+//-----------------------------------------------------------------------------
+// wxGraphicsPath implementation
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsPath, wxGraphicsPath)
+
 wxMacCoreGraphicsPath::wxMacCoreGraphicsPath()
 {
     m_path = CGPathCreateMutable();
@@ -153,11 +173,6 @@ void wxMacCoreGraphicsPath::CloseSubpath()
     CGPathCloseSubpath( m_path );
 }
 
-CGPathRef wxMacCoreGraphicsPath::GetPath() const
-{
-    return m_path;
-}
-
 // gets the last point of the current path, (0,0) if not yet set
 void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
 {
@@ -172,17 +187,18 @@ void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
 
 class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
 {
-    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
-
 public:
-    wxMacCoreGraphicsContext( CGrafPtr port );
-    
     wxMacCoreGraphicsContext( CGContextRef cgcontext );
     
+    wxMacCoreGraphicsContext( WindowRef window );
+    
+    wxMacCoreGraphicsContext( wxWindow* window );
+    
     wxMacCoreGraphicsContext();
     
     ~wxMacCoreGraphicsContext();
 
+       void Init();
 
     // creates a path instance that corresponds to the type of graphics context, ie GDIPlus, cairo, CoreGraphics ...
     virtual wxGraphicsPath * CreatePath();
@@ -196,6 +212,14 @@ public:
     // clips drawings to the region
     virtual void Clip( const wxRegion &region );
 
+    // clips drawings to the rect
+    virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
+       
+       // resets the clipping to original extent
+       virtual void ResetClip();
+
+       virtual void * GetNativeContext();
+       
     //
     // transformation
     //
@@ -264,44 +288,29 @@ public:
 
     virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
 
-    CGContextRef GetNativeContext();
     void SetNativeContext( CGContextRef cg );
     CGPathDrawingMode GetDrawingMode() const { return m_mode; }
     
+    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
+    DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
+
 private:
+       void EnsureIsValid();
+
     CGContextRef m_cgContext;
-    CGrafPtr m_qdPort;
+       WindowRef m_windowRef;
+       int m_originX;
+       int m_originY;
+       wxMacCFRefHolder<HIShapeRef> m_clipRgn;
+       bool m_releaseContext;
     CGPathDrawingMode m_mode;
     ATSUStyle m_macATSUIStyle;
     wxPen m_pen;
     wxBrush m_brush;
+       wxFont m_font;
     wxColor m_textForegroundColor;
 };
 
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
-
-#if !defined( __DARWIN__ ) || defined(__MWERKS__)
-#ifndef M_PI
-const double M_PI = 3.14159265358979;
-#endif
-#endif
-
-const double RAD2DEG = 180.0 / M_PI;
-const short kEmulatedMode = -1;
-const short kUnsupportedMode = -2;
-
-extern TECObjectRef s_TECNativeCToUnicode;
-
-//-----------------------------------------------------------------------------
-// Local functions
-//-----------------------------------------------------------------------------
-
-static inline double dmin(double a, double b) { return a < b ? a : b; }
-static inline double dmax(double a, double b) { return a > b ? a : b; }
-static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
-
 //-----------------------------------------------------------------------------
 // device context implementation
 //
@@ -314,68 +323,153 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
 // state we were called with, the other one after changing to HI Graphics orientation
 // (this one is used for getting back clippings etc)
 
-//-----------------------------------------------------------------------------
-// wxGraphicsPath implementation
-//-----------------------------------------------------------------------------
-
 //-----------------------------------------------------------------------------
 // wxGraphicsContext implementation
 //-----------------------------------------------------------------------------
 
-wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGrafPtr port )
+IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
+
+void wxMacCoreGraphicsContext::Init()
 {
-    m_qdPort = port;
     m_cgContext = NULL;
     m_mode = kCGPathFill;
     m_macATSUIStyle = NULL;
+       m_releaseContext = false;
+       m_clipRgn.Set(HIShapeCreateEmpty());
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGContextRef cgcontext )
 {
-    m_qdPort = NULL;
-    m_cgContext = cgcontext;
-    m_mode = kCGPathFill;
-    m_macATSUIStyle = NULL;
+       Init();
+       m_cgContext = cgcontext;
     CGContextSaveGState( m_cgContext );
     CGContextSaveGState( m_cgContext );
 }
 
+wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( WindowRef window )
+{
+       Init();
+       m_windowRef = window;
+}
+
+wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxWindow* window )
+{
+       Init();
+       m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
+    m_originX = m_originY = 0;
+    window->MacWindowToRootWindow( &m_originX , &m_originY );
+}
+
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext()
 {
-    m_qdPort = NULL;
-    m_cgContext = NULL;
-    m_mode = kCGPathFill;
-    m_macATSUIStyle = NULL;
+       Init();
 }
 
 wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
 {
     if ( m_cgContext )
     {
-        CGContextSynchronize( m_cgContext );
+        // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
         CGContextRestoreGState( m_cgContext );
         CGContextRestoreGState( m_cgContext );
     }
 
-    if ( m_qdPort )
-        CGContextRelease( m_cgContext );
+    if ( m_releaseContext )
+               QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
+}
+
+void wxMacCoreGraphicsContext::EnsureIsValid()
+{
+       if ( !m_cgContext )
+       {
+               OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
+               wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
+               Rect bounds;
+               GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
+               CGContextSaveGState( m_cgContext );
+               CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top );
+               CGContextScaleCTM( m_cgContext , 1 , -1 );
+               CGContextTranslateCTM( m_cgContext, m_originX, m_originY );
+               CGContextSaveGState( m_cgContext );
+               m_releaseContext = true;
+               if ( !HIShapeIsEmpty(m_clipRgn) )
+               {
+                       HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext );
+                       CGContextClip( m_cgContext );
+               }
+       }
 }
 
+
 void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
 {
-//    ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn );
+       if( m_cgContext )
+       {
+               HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
+               HIShapeReplacePathInCGContext( shape, m_cgContext );
+               CGContextClip( m_cgContext );
+               CFRelease( shape );
+       }
+       else
+       {
+               m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
+       }
 }
 
-void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *p )
+// clips drawings to the rect
+void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
-    CGContextAddPath( m_cgContext , path->GetPath() );
+       HIRect r = CGRectMake( x , y , w , h );
+       if ( m_cgContext )
+       {
+               CGContextClipToRect( m_cgContext, r );
+       }
+       else
+       {
+               m_clipRgn.Set(HIShapeCreateWithRect(&r));
+       }
+}
+       
+       // resets the clipping to original extent
+void wxMacCoreGraphicsContext::ResetClip()
+{
+       if ( m_cgContext )
+       {
+               CGContextRestoreGState( m_cgContext );
+               CGContextSaveGState( m_cgContext );
+       }
+       else
+       {
+               m_clipRgn.Set(HIShapeCreateEmpty());
+       }
+}
+
+void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *path )
+{
+       EnsureIsValid();
+       
+    int width = m_pen.GetWidth();
+    if ( width == 0 )
+        width = 1 ;
+    if ( m_pen.GetStyle() == wxTRANSPARENT )
+        width = 0 ;
+        
+    bool offset = ( width % 2 ) == 1 ; 
+
+    if ( offset )
+        CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
+
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     CGContextStrokePath( m_cgContext );
+
+    if ( offset )
+        CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
 }
 
-void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle )
+void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *path , int fillStyle )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
+       EnsureIsValid();
+       
     CGPathDrawingMode mode = m_mode;
 
     if ( fillStyle == wxODDEVEN_RULE )
@@ -386,15 +480,29 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle
             mode = kCGPathEOFillStroke;
     }
 
-    CGContextAddPath( m_cgContext , path->GetPath() );
+    int width = m_pen.GetWidth();
+    if ( width == 0 )
+        width = 1 ;
+    if ( m_pen.GetStyle() == wxTRANSPARENT )
+        width = 0 ;
+        
+    bool offset = ( width % 2 ) == 1 ; 
+
+    if ( offset )
+        CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
+
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     CGContextDrawPath( m_cgContext , mode );
+
+    if ( offset )
+        CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
 }
 
-void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle )
+void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *path , int fillStyle )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
-
-    CGContextAddPath( m_cgContext , path->GetPath() );
+       EnsureIsValid();
+       
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     if ( fillStyle == wxODDEVEN_RULE )
         CGContextEOFillPath( m_cgContext );
     else
@@ -403,19 +511,9 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle
 
 wxGraphicsPath* wxMacCoreGraphicsContext::CreatePath()
 {
-    // make sure that we now have a real cgref, before doing
-    // anything with paths
-    CGContextRef cg = GetNativeContext();
-    cg = NULL;
-
     return new wxMacCoreGraphicsPath();
 }
 
-CGContextRef wxMacCoreGraphicsContext::GetNativeContext()
-{
-    return m_cgContext;
-}
-
 void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
 {
     // we allow either setting or clearing but not replacing
@@ -428,21 +526,29 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
 
 void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy ) 
 {
+       EnsureIsValid();
+       
     CGContextTranslateCTM( m_cgContext, dx, dy );
 }
 
 void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
 {
+       EnsureIsValid();
+       
     CGContextScaleCTM( m_cgContext , xScale , yScale );
 }
 
 void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
 {
+       EnsureIsValid();
+       
     CGContextRotateCTM( m_cgContext , angle );
 }
 
 void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) 
 {
+       EnsureIsValid();
+       
     CGImageRef image = (CGImageRef)( bmp.CGImageCreate() );
     HIRect r = CGRectMake( x , y , w , h );
     HIViewDrawCGImage( m_cgContext , &r , image );
@@ -451,6 +557,8 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo
 
 void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) 
 {
+       EnsureIsValid();
+       
     CGRect r = CGRectMake( 00 , 00 , w , h );
     CGContextSaveGState( m_cgContext );
     CGContextTranslateCTM( m_cgContext, x , y + h );
@@ -462,17 +570,23 @@ void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDoubl
 
 void wxMacCoreGraphicsContext::PushState()
 {
+       EnsureIsValid();
+       
     CGContextSaveGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PopState() 
 {
+       EnsureIsValid();
+       
     CGContextRestoreGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::SetTextColor( const wxColour &col ) 
 {
     m_textForegroundColor = col;
+       // to recreate the native font after color change
+       SetFont( m_font );
 }
 
 #pragma mark -
@@ -520,7 +634,7 @@ const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCor
 class ImagePattern : public wxMacCoreGraphicsPattern
 {
 public :
-    ImagePattern( const wxBitmap* bmp , CGAffineTransform transform )
+    ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform )
     {
         wxASSERT( bmp && bmp->Ok() );
 
@@ -528,7 +642,7 @@ public :
     }
 
     // ImagePattern takes ownership of CGImageRef passed in
-    ImagePattern( CGImageRef image , CGAffineTransform transform )
+    ImagePattern( CGImageRef image , const CGAffineTransform& transform )
     {
         if ( image )
             CFRetain( image );
@@ -543,7 +657,7 @@ public :
     }
 
 protected :
-    void Init( CGImageRef image, CGAffineTransform transform )
+    void Init( CGImageRef image, const CGAffineTransform& transform )
     {
         m_image = image;
         if ( m_image )
@@ -569,7 +683,7 @@ protected :
 class HatchPattern : public wxMacCoreGraphicsPattern
 {
 public :
-    HatchPattern( int hatchstyle, CGAffineTransform transform )
+    HatchPattern( int hatchstyle, const CGAffineTransform& transform )
     {
         m_hatch = hatchstyle;
         m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 );
@@ -693,7 +807,7 @@ void wxMacCoreGraphicsContext::SetPen( const wxPen &pen )
     CGContextSetShouldAntialias( m_cgContext , false );
 #endif
 
-    if ( fill | stroke )
+    if ( fill || stroke )
     {
         // set up brushes
         m_mode = kCGPathFill; // just a default
@@ -870,7 +984,7 @@ void wxMacCoreGraphicsContext::SetBrush( const wxBrush &brush )
     CGContextSetShouldAntialias( m_cgContext , false );
 #endif
 
-    if ( fill | stroke )
+    if ( fill || stroke )
     {
         // setup brushes
         m_mode = kCGPathFill; // just a default
@@ -938,6 +1052,8 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub
 
 void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) 
 {
+       EnsureIsValid();
+       
     OSStatus status = noErr;
     ATSUTextLayout atsuLayout;
     UniCharCount chars = str.length();
@@ -1156,8 +1272,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr
 #endif
 #endif
 
-    OSStatus status;
-    status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
+    ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
         &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout );
 
     for ( int pos = 0; pos < (int)chars; pos ++ )
@@ -1189,6 +1304,7 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font )
 
     if ( font.Ok() )
     {
+               m_font = font ;
         OSStatus status;
 
         status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle );
@@ -1223,9 +1339,29 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font )
     }
 }
 
+void * wxMacCoreGraphicsContext::GetNativeContext() 
+{
+       return m_cgContext;
+}
+
 wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc )
 {
     return new wxMacCoreGraphicsContext((CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
 }
 
+wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
+{
+       return new wxMacCoreGraphicsContext( window );
+}
+
+wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
+{
+    return new wxMacCoreGraphicsContext((CGContextRef)context);
+}
+
+wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window )
+{
+    return new wxMacCoreGraphicsContext((WindowRef)window);
+}
+
 #endif // wxMAC_USE_CORE_GRAPHICS