]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/carbon/graphics.cpp
move wxGridCellRenderer::Draw before other derived classes implementations (no real...
[wxWidgets.git] / src / osx / carbon / graphics.cpp
index 416880038a46f015172b04ed6314e496d15348a9..98ce41f0d8d54a139acb225bb1298f63a9bda85f 100644 (file)
@@ -5,7 +5,7 @@
 // Modified by:
 // Created:     01/02/97
 // RCS-ID:      $Id$
-// Copyright:   (c) Stefan Csomor
+// copyright:   (c) Stefan Csomor
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
     #include "wx/osx/dcprint.h"
     #include "wx/osx/dcclient.h"
     #include "wx/osx/dcmemory.h"
-#if wxOSX_USE_CARBON
-#include "wx/osx/uma.h"
-#else
-#include "wx/osx/private.h"
-#endif
-
+    #include "wx/osx/private.h"
 #else
     #include "CoreServices/CoreServices.h"
     #include "ApplicationServices/ApplicationServices.h"
@@ -78,10 +73,39 @@ int UMAGetSystemVersion()
 
 #if wxOSX_USE_COCOA_OR_IPHONE
 extern CGContextRef wxOSXGetContextFromCurrentNSContext() ;
-extern void wxOSXLockFocus( WXWidget view) ;
+extern bool wxOSXLockFocus( WXWidget view) ;
 extern void wxOSXUnlockFocus( WXWidget view) ;
 #endif
 
+#if 1 // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+
+// TODO test whether this private API also works under 10.3
+
+// copying values from NSCompositingModes (see also webkit and cairo sources)
+
+typedef enum CGCompositeOperation {
+   kCGCompositeOperationClear           = 0,
+   kCGCompositeOperationCopy            = 1,
+   kCGCompositeOperationSourceOver      = 2,
+   kCGCompositeOperationSourceIn        = 3,
+   kCGCompositeOperationSourceOut       = 4,
+   kCGCompositeOperationSourceAtop      = 5,
+   kCGCompositeOperationDestinationOver = 6,
+   kCGCompositeOperationDestinationIn   = 7,
+   kCGCompositeOperationDestinationOut  = 8,
+   kCGCompositeOperationDestinationAtop = 9,
+   kCGCompositeOperationXOR             = 10,
+   kCGCompositeOperationPlusDarker      = 11,
+// NS only, unsupported by CG : Highlight 
+   kCGCompositeOperationPlusLighter     = 12
+} CGCompositeOperation ;
+
+extern "C"
+{
+   CG_EXTERN void CGContextSetCompositeOperation (CGContextRef context, int operation);
+} ;
+
+#endif
 
 //-----------------------------------------------------------------------------
 // constants
@@ -539,12 +563,7 @@ void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context )
     }
     else
     {
-        if ( context->GetLogicalFunction() == wxINVERT || context->GetLogicalFunction() == wxXOR )
-        {
-            CGContextSetRGBStrokeColor( cg , (CGFloat) 1.0,(CGFloat)  1.0 , (CGFloat) 1.0, (CGFloat) 1.0 );
-        }
-        else
-            CGContextSetStrokeColorWithColor( cg , m_color );
+        CGContextSetStrokeColorWithColor( cg , m_color );
     }
 }
 
@@ -1321,7 +1340,14 @@ public:
 
     virtual void * GetNativeContext();
 
-    bool SetLogicalFunction( wxRasterOperationMode function );
+    virtual bool SetAntialiasMode(wxAntialiasMode antialias);
+
+    virtual bool SetCompositionMode(wxCompositionMode op);
+
+    virtual void BeginLayer(wxDouble opacity);
+
+    virtual void EndLayer();
+    
     //
     // transformation
     //
@@ -1391,7 +1417,7 @@ public:
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsContext)
 
 private:
-    void EnsureIsValid();
+    bool EnsureIsValid();
 
     virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
     virtual void DoDrawRotatedText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
@@ -1406,6 +1432,7 @@ private:
     CGAffineTransform m_windowTransform;
     wxDouble m_width;
     wxDouble m_height;
+    bool m_invisible;
 
 #if wxOSX_USE_COCOA_OR_CARBON
     wxCFRef<HIShapeRef> m_clipRgn;
@@ -1462,6 +1489,7 @@ void wxMacCoreGraphicsContext::Init()
 #if wxOSX_USE_COCOA_OR_IPHONE
     m_view = NULL;
 #endif
+    m_invisible = false;
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer)
@@ -1527,12 +1555,6 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
 wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
 {
     SetNativeContext(NULL);
-#if wxOSX_USE_COCOA_OR_IPHONE
-    if ( m_view )
-    {
-        CGContextFlush(m_cgContext);
-    }
-#endif
 }
 
 void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height)
@@ -1565,13 +1587,23 @@ void wxMacCoreGraphicsContext::Flush()
     CGContextFlush(m_cgContext);
 }
 
-void wxMacCoreGraphicsContext::EnsureIsValid()
+bool wxMacCoreGraphicsContext::EnsureIsValid()
 {
     if ( !m_cgContext )
     {
+        if (m_invisible)
+            return false;
+            
 #if wxOSX_USE_COCOA_OR_IPHONE
-        wxOSXLockFocus(m_view);
-        m_cgContext = wxOSXGetContextFromCurrentNSContext();
+        if ( wxOSXLockFocus(m_view) )
+        {
+            m_cgContext = wxOSXGetContextFromCurrentNSContext();
+            wxASSERT_MSG( m_cgContext != NULL, _T("Unable to retrieve drawing context from View"));
+        }
+        else
+        {
+            m_invisible = true;
+        }
 #endif
 #if wxOSX_USE_CARBON
         OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
@@ -1580,110 +1612,208 @@ void wxMacCoreGraphicsContext::EnsureIsValid()
             wxFAIL_MSG("Cannot nest wxDCs on the same window");
         }
 #endif
-        CGContextConcatCTM( m_cgContext, m_windowTransform );
-        CGContextSaveGState( m_cgContext );
-        m_contextSynthesized = true;
-        if ( m_clipRgn.get() )
+        if ( m_cgContext )
         {
-            // the clip region is in device coordinates, so we convert this again to user coordinates
-            wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
-            CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
-            HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
-            // if the shape is empty, HIShapeReplacePathInCGContext doesn't work
-            if ( HIShapeIsEmpty(hishape))
+            CGContextConcatCTM( m_cgContext, m_windowTransform );
+            CGContextSaveGState( m_cgContext );
+            m_contextSynthesized = true;
+            if ( m_clipRgn.get() )
             {
-                CGRect empty = CGRectMake( 0,0,0,0 );
-                CGContextClipToRect( m_cgContext, empty );
+                // the clip region is in device coordinates, so we convert this again to user coordinates
+                wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
+                CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
+                HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
+                // if the shape is empty, HIShapeReplacePathInCGContext doesn't work
+                if ( HIShapeIsEmpty(hishape))
+                {
+                    CGRect empty = CGRectMake( 0,0,0,0 );
+                    CGContextClipToRect( m_cgContext, empty );
+                }
+                else
+                {
+                    HIShapeReplacePathInCGContext( hishape, m_cgContext );
+                    CGContextClip( m_cgContext );
+                }
             }
-            else
+            CGContextSaveGState( m_cgContext );
+            
+#if 0 // turn on for debugging of clientdc
+            static float color = 0.5 ;
+            static int channel = 0 ;
+            CGRect bounds = CGRectMake(-1000,-1000,2000,2000);
+            CGContextSetRGBFillColor( m_cgContext, channel == 0 ? color : 0.5 ,
+                channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
+            CGContextFillRect( m_cgContext, bounds );
+            color += 0.1 ;
+            if ( color > 0.9 )
             {
-                HIShapeReplacePathInCGContext( hishape, m_cgContext );
-                CGContextClip( m_cgContext );
+                color = 0.5 ;
+                channel++ ;
+                if ( channel == 3 )
+                    channel = 0 ;
             }
-        }
-        CGContextSaveGState( m_cgContext );
-        
-#if 0 // turn on for debugging of clientdc
-        static float color = 0.5 ;
-        static int channel = 0 ;
-        CGRect bounds = CGRectMake(-1000,-1000,2000,2000);
-        CGContextSetRGBFillColor( m_cgContext, channel == 0 ? color : 0.5 ,
-            channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
-        CGContextFillRect( m_cgContext, bounds );
-        color += 0.1 ;
-        if ( color > 0.9 )
-        {
-            color = 0.5 ;
-            channel++ ;
-            if ( channel == 3 )
-                channel = 0 ;
-        }
 #endif
+        }
     }
+    return m_cgContext != NULL;
 }
 
-// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes)
-
-bool wxMacCoreGraphicsContext::SetLogicalFunction( wxRasterOperationMode function )
+bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias)
 {
-    if (m_logicalFunction == function)
+    if (EnsureIsValid()==false)
         return true;
 
-    EnsureIsValid();
+    if (m_antialias == antialias)
+        return true;
+    
+    m_antialias = antialias;
+    
+    bool antialiasMode;
+    switch (antialias)
+    {
+        case wxANTIALIAS_DEFAULT:
+            antialiasMode = true;
+            break;
+        case wxANTIALIAS_NONE:
+            antialiasMode = false;
+            break;
+        default:
+            return false;
+    }
+    CGContextSetShouldAntialias(m_cgContext, antialiasMode);
+    return true;
+}
 
-    bool retval = false;
-    bool shouldAntiAlias = true;
-    CGBlendMode mode = kCGBlendModeNormal;
+bool wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op)
+{
+    if (EnsureIsValid()==false)
+        return true;
 
-#if defined(__WXMAC__) && ( wxOSX_USE_IPHONE || ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 ) )
-#if wxOSX_USE_IPHONE
-    if ( 1 )
-#else
-    if ( UMAGetSystemVersion() >= 0x1050 )
-#endif
+    if ( m_composition == op )
+        return true;
+        
+    m_composition = op;
+    
+    if (m_composition == wxCOMPOSITION_DEST)
+        return true;
+        
+#if wxOSX_USE_COCOA_OR_CARBON
+    if ( UMAGetSystemVersion() < 0x1060 )
     {
-        retval = true;
-        switch ( function )
+        CGCompositeOperation cop = kCGCompositeOperationSourceOver;
+        CGBlendMode mode = kCGBlendModeNormal;
+        switch( op )
         {
-            // TODO find best corresponding porter duff modes
-            case wxCOPY :
-                mode = kCGBlendModeCopy;
-                break;
-            case wxCLEAR :
-                mode = kCGBlendModeClear;
-                break;
-            case wxXOR :
-                mode = kCGBlendModeXOR;
-                shouldAntiAlias = false;
-                break;
-            default :
-                retval = false;
-                break;
+        case wxCOMPOSITION_CLEAR:
+            cop = kCGCompositeOperationClear; 
+            break;
+        case wxCOMPOSITION_SOURCE:
+            cop = kCGCompositeOperationCopy; 
+            break;
+        case wxCOMPOSITION_OVER:
+            mode = kCGBlendModeNormal; 
+            break;
+        case wxCOMPOSITION_IN:
+            cop = kCGCompositeOperationSourceIn; 
+            break;
+        case wxCOMPOSITION_OUT:
+            cop = kCGCompositeOperationSourceOut; 
+            break;
+        case wxCOMPOSITION_ATOP:
+            cop = kCGCompositeOperationSourceAtop; 
+            break;
+        case wxCOMPOSITION_DEST_OVER:
+            cop = kCGCompositeOperationDestinationOver; 
+            break;
+        case wxCOMPOSITION_DEST_IN:
+            cop = kCGCompositeOperationDestinationIn; 
+            break;
+        case wxCOMPOSITION_DEST_OUT:
+            cop = kCGCompositeOperationDestinationOut; 
+            break;
+        case wxCOMPOSITION_DEST_ATOP:
+           cop = kCGCompositeOperationDestinationAtop; 
+            break;
+        case wxCOMPOSITION_XOR:
+            cop = kCGCompositeOperationXOR; 
+            break;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+        case wxCOMPOSITION_ADD:
+            mode = kCGBlendModePlusLighter ;
+            break;
+#endif
+        default:
+            return false;
         }
+        if ( cop != kCGCompositeOperationSourceOver )
+            CGContextSetCompositeOperation(m_cgContext, cop);
+        else
+            CGContextSetBlendMode(m_cgContext, mode);
     }
-    else
 #endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+    else
     {
-        if ( function == wxCOPY )
+        CGBlendMode mode = kCGBlendModeNormal;
+        switch( op )
         {
-            retval = true;
-        }
-        else if ( function == wxINVERT || function == wxXOR )
-        {
-            // change color to white
-            mode = kCGBlendModeExclusion;
-            shouldAntiAlias = false;
-            retval = true;
+        case wxCOMPOSITION_CLEAR:
+            mode = kCGBlendModeClear; 
+            break;
+        case wxCOMPOSITION_SOURCE:
+            mode = kCGBlendModeCopy; 
+            break;
+        case wxCOMPOSITION_OVER:
+            mode = kCGBlendModeNormal; 
+            break;
+        case wxCOMPOSITION_IN:
+            mode = kCGBlendModeSourceIn; 
+            break;
+        case wxCOMPOSITION_OUT:
+            mode = kCGBlendModeSourceOut; 
+            break;
+        case wxCOMPOSITION_ATOP:
+            mode = kCGBlendModeSourceAtop; 
+            break;
+        case wxCOMPOSITION_DEST_OVER:
+            mode = kCGBlendModeDestinationOver; 
+            break;
+        case wxCOMPOSITION_DEST_IN:
+            mode = kCGBlendModeDestinationIn; 
+            break;
+        case wxCOMPOSITION_DEST_OUT:
+            mode = kCGBlendModeDestinationOut; 
+            break;
+        case wxCOMPOSITION_DEST_ATOP:
+           mode = kCGBlendModeDestinationAtop; 
+            break;
+        case wxCOMPOSITION_XOR:
+            mode = kCGBlendModeXOR; 
+            break;
+            
+        case wxCOMPOSITION_ADD:
+            mode = kCGBlendModePlusLighter ;
+            break;
+        default:
+            return false;
         }
+        CGContextSetBlendMode(m_cgContext, mode);
     }
+#endif
+    return true;
+}
 
-    if (retval)
-    {
-        m_logicalFunction = function;
-        CGContextSetBlendMode( m_cgContext, mode );
-        CGContextSetShouldAntialias(m_cgContext, shouldAntiAlias);
-    }
-    return retval ;
+void wxMacCoreGraphicsContext::BeginLayer(wxDouble opacity)
+{
+    CGContextSaveGState(m_cgContext);
+    CGContextSetAlpha(m_cgContext, opacity);
+    CGContextBeginTransparencyLayer(m_cgContext, 0);
+}
+
+void wxMacCoreGraphicsContext::EndLayer()
+{
+    CGContextEndTransparencyLayer(m_cgContext);
+    CGContextRestoreGState(m_cgContext);
 }
 
 void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
@@ -1773,7 +1903,11 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
     if ( m_pen.IsNull() )
         return ;
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
 
     wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
 
@@ -1784,6 +1918,12 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
 
 void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle )
 {
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
     {
         // when using shading, we cannot draw pen and brush at the same time
@@ -1818,8 +1958,6 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF
         }
     }
 
-    EnsureIsValid();
-
     if ( !m_brush.IsNull() )
         ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
     if ( !m_pen.IsNull() )
@@ -1836,7 +1974,11 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF
     if ( m_brush.IsNull() )
         return;
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
 
     if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
     {
@@ -1933,7 +2075,12 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo
 
 void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+        
 #ifdef __WXMAC__
     wxMacCoreGraphicsBitmapData* refdata  =static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData());
     CGImageRef image = refdata->GetBitmap();
@@ -1970,30 +2117,36 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble
 
 void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
 
     CGRect r = CGRectMake( (CGFloat) 0.0 , (CGFloat) 0.0 , (CGFloat) w , (CGFloat) h );
     CGContextSaveGState( m_cgContext );
     CGContextTranslateCTM( m_cgContext,(CGFloat) x ,(CGFloat) (y + h) );
     CGContextScaleCTM( m_cgContext, 1, -1 );
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
     PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
-        NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
+        NULL , kPlotIconRefNormalFlags , icon.GetHICON() );
 #endif
     CGContextRestoreGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PushState()
 {
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     CGContextSaveGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PopState()
 {
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     CGContextRestoreGState( m_cgContext );
 }
 
@@ -2001,7 +2154,12 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo
 {
     wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {
@@ -2059,7 +2217,12 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str,
 {
     wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {