]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/graphics.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / mac / carbon / graphics.cpp
old mode 100755 (executable)
new mode 100644 (file)
index ec1da84..b2bcb07
@@ -17,6 +17,7 @@
 
 #ifndef WX_PRECOMP
     #include "wx/dcclient.h"
+    #include "wx/dcmemory.h"
     #include "wx/log.h"
     #include "wx/region.h"
 #endif
 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
 typedef float CGFloat;
 #endif
+#ifndef wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+    #define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 1
+#else
+    #define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0
+#endif
+#endif
 
 //-----------------------------------------------------------------------------
 // constants
@@ -161,7 +169,7 @@ public :
     void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
     {
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
-        if ( UMAGetSystemVersion() >= 0x1040 )
+        if ( CGContextStrokeLineSegments!=NULL  )
         {
             CGContextStrokeLineSegments( ctxRef , pts , count );
         }
@@ -395,7 +403,7 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer
                 if ( bmp && bmp->Ok() )
                 {
                     m_colorSpace.Set( CGColorSpaceCreatePattern( NULL ) );
-                    m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
+                    m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeScale( 1,-1 ) ) ) );
                     m_patternColorComponents = new CGFloat[1] ;
                     m_patternColorComponents[0] = 1.0;
                     m_isPattern = true;
@@ -407,7 +415,7 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer
             {
                 m_isPattern = true;
                 m_colorSpace.Set( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
-                m_pattern.Set( *( new HatchPattern( pen.GetStyle() , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
+                m_pattern.Set( *( new HatchPattern( pen.GetStyle() , CGAffineTransformMakeScale( 1,-1 ) ) ) );
                 m_patternColorComponents = new CGFloat[4] ;
                 m_patternColorComponents[0] = pen.GetColour().Red() / 255.0;
                 m_patternColorComponents[1] = pen.GetColour().Green() / 255.0;
@@ -450,12 +458,19 @@ void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context )
 
     if ( m_isPattern )
     {
+        CGAffineTransform matrix = CGContextGetCTM( cg );
+        CGContextSetPatternPhase( cg, CGSizeMake(matrix.tx, matrix.ty) );
         CGContextSetStrokeColorSpace( cg , m_colorSpace );
         CGContextSetStrokePattern( cg, m_pattern , m_patternColorComponents );
     }
     else
     {
-        CGContextSetStrokeColorWithColor( cg , m_color );
+        if ( context->GetLogicalFunction() == wxINVERT || context->GetLogicalFunction() == wxXOR )
+        {
+            CGContextSetRGBStrokeColor( cg , 1.0, 1.0 , 1.0, 1.0 );
+        }
+        else
+            CGContextSetStrokeColorWithColor( cg , m_color );
     }
 }
 
@@ -523,15 +538,38 @@ wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* rende
 
     if ( brush.GetStyle() == wxSOLID )
     {
-        float components[4] = { brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
+        if ( brush.MacGetBrushKind() == kwxMacBrushTheme )
+        {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+            if ( HIThemeBrushCreateCGColor != 0 )
+            {
+                CGColorRef color ;
+                HIThemeBrushCreateCGColor( brush.MacGetTheme(), &color );
+                m_color.Set( color ) ;
+            }
+            else
+#endif
+            {
+                // as close as we can get, unfortunately < 10.4 things get difficult
+                RGBColor color;
+                GetThemeBrushAsColor( brush.MacGetTheme(), 32, true, &color );
+                float components[4] = {  (CGFloat) color.red / 65536,
+                    (CGFloat) color.green / 65536, (CGFloat) color.blue / 65536, 1 } ;
+                m_color.Set( CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ) ;
+            }
+        }
+        else
+        {
+            float components[4] = { brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
                 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 } ;
-        m_color.Set( CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ) ;
+            m_color.Set( CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ) ;
+        }
     }
     else if ( brush.IsHatch() )
     {
         m_isPattern = true;
         m_colorSpace.Set( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
-        m_pattern.Set( *( new HatchPattern( brush.GetStyle() , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
+        m_pattern.Set( *( new HatchPattern( brush.GetStyle() , CGAffineTransformMakeScale( 1,-1 ) ) ) );
 
         m_patternColorComponents = new CGFloat[4] ;
         m_patternColorComponents[0] = brush.GetColour().Red() / 255.0;
@@ -549,7 +587,7 @@ wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* rende
             m_patternColorComponents = new CGFloat[1] ;
             m_patternColorComponents[0] = 1.0;
             m_colorSpace.Set( CGColorSpaceCreatePattern( NULL ) );
-            m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
+            m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeScale( 1,-1 ) ) ) );
         }
     }
 }
@@ -582,11 +620,14 @@ void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context )
 
     if ( m_isShading )
     {
+        // nothing to set as shades are processed by clipping using the path and filling
     }
     else
     {
         if ( m_isPattern )
         {
+            CGAffineTransform matrix = CGContextGetCTM( cg );
+            CGContextSetPatternPhase( cg, CGSizeMake(matrix.tx, matrix.ty) );
             CGContextSetFillColorSpace( cg , m_colorSpace );
             CGContextSetFillPattern( cg, m_pattern , m_patternColorComponents );
         }
@@ -714,6 +755,10 @@ public :
     virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
         wxDouble tx=0.0, wxDouble ty=0.0);
 
+    // gets the component valuess of the matrix
+    virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL,  wxDouble* c=NULL,
+                     wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
+       
     // makes this the inverse matrix
     virtual void Invert();
 
@@ -785,6 +830,18 @@ void wxMacCoreGraphicsMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDoub
     m_matrix = CGAffineTransformMake(a,b,c,d,tx,ty);
 }
 
+// gets the component valuess of the matrix
+void wxMacCoreGraphicsMatrixData::Get(wxDouble* a, wxDouble* b,  wxDouble* c,
+                                      wxDouble* d, wxDouble* tx, wxDouble* ty) const
+{
+    if (a)  *a = m_matrix.a;
+    if (b)  *b = m_matrix.b;
+    if (c)  *c = m_matrix.c;
+    if (d)  *d = m_matrix.d;
+    if (tx) *tx= m_matrix.tx;
+    if (ty) *ty= m_matrix.ty;
+}
+
 // makes this the inverse matrix
 void wxMacCoreGraphicsMatrixData::Invert()
 {
@@ -795,15 +852,22 @@ void wxMacCoreGraphicsMatrixData::Invert()
 bool wxMacCoreGraphicsMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
 {
     const CGAffineTransform* tm = (CGAffineTransform*) t->GetNativeMatrix();
-    return (
-        m_matrix.a == tm->a &&
-        m_matrix.b == tm->b &&
-        m_matrix.c == tm->c &&
-        m_matrix.d == tm->d &&
-        m_matrix.tx == tm->tx &&
-        m_matrix.ty == tm->ty ) ;
-
-    return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()));
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+    if ( CGAffineTransformEqualToTransform!=NULL )
+    {
+        return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()));
+    }
+    else
+#endif
+    {
+        return (
+            m_matrix.a == tm->a &&
+            m_matrix.b == tm->b &&
+            m_matrix.c == tm->c &&
+            m_matrix.d == tm->d &&
+            m_matrix.tx == tm->tx &&
+            m_matrix.ty == tm->ty ) ;
+    }
 }
 
 // return true if this is the identity matrix
@@ -1042,7 +1106,18 @@ void wxMacCoreGraphicsPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wx
 
 bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, int fillStyle) const
 {
-    return CGPathContainsPoint( m_path, NULL, CGPointMake(x,y), fillStyle == wxODDEVEN_RULE );
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+    if ( CGPathContainsPoint!=NULL )
+    {
+        return CGPathContainsPoint( m_path, NULL, CGPointMake(x,y), fillStyle == wxODDEVEN_RULE );
+    }
+    else
+#endif
+    {
+        // TODO : implementation for 10.3
+        CGRect bounds = CGPathGetBoundingBox( m_path ) ;
+        return CGRectContainsPoint( bounds, CGPointMake(x,y) ) == 1;
+    }
 }
 
 //
@@ -1087,6 +1162,7 @@ public:
 
     virtual void * GetNativeContext();
 
+    bool SetLogicalFunction( int function );
     //
     // transformation
     //
@@ -1122,7 +1198,7 @@ public:
     virtual void DrawPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE );
 
     virtual bool ShouldOffset() const
-    {
+    {     
         int penwidth = 0 ;
         if ( !m_pen.IsNull() )
         {
@@ -1252,13 +1328,55 @@ void wxMacCoreGraphicsContext::EnsureIsValid()
                m_releaseContext = true;
                if ( !HIShapeIsEmpty(m_clipRgn) )
                {
-                       HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext );
+            // the clip region is in device coordinates, so we convert this again to user coordinates
+            wxMacCFRefHolder<HIMutableShapeRef> hishape ;
+            hishape.Set( HIShapeCreateMutableCopy( m_clipRgn ) );
+            CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
+            HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
+                       HIShapeReplacePathInCGContext( hishape, m_cgContext );
                        CGContextClip( m_cgContext );
                }
                CGContextSaveGState( m_cgContext );
        }
 }
 
+bool wxMacCoreGraphicsContext::SetLogicalFunction( int function )
+{
+    if (m_logicalFunction == function)
+        return true;
+
+    EnsureIsValid();
+    
+    bool retval = false;
+
+    if ( function == wxCOPY )
+    {
+        retval = true;
+#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
+        if ( CGContextSetBlendMode != NULL )
+        {
+            CGContextSetBlendMode( m_cgContext, kCGBlendModeNormal );
+            CGContextSetShouldAntialias( m_cgContext, true );
+        }
+#endif
+    }
+    else if ( function == wxINVERT || function == wxXOR )
+    {
+#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
+        if ( CGContextSetBlendMode != NULL )
+        {
+            // change color to white
+            CGContextSetBlendMode( m_cgContext, kCGBlendModeExclusion );
+            CGContextSetShouldAntialias( m_cgContext, false );
+            retval = true;
+        }
+#endif
+    }
+    
+    if (retval)
+        m_logicalFunction = function;
+    return retval ;
+}
 
 void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
 {
@@ -1271,7 +1389,15 @@ void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
     }
     else
     {
-        m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
+        // this offsetting to device coords is not really correct, but since we cannot apply affine transforms
+        // to regions we try at least to have correct translations
+        wxMacCFRefHolder<HIShapeRef> hishape ;
+        hishape.Set( HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
+        HIMutableShapeRef mutableShape = HIShapeCreateMutableCopy( hishape );
+        
+        CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero, m_windowTransform );
+        HIShapeOffset( mutableShape, transformedOrigin.x, transformedOrigin.y );
+        m_clipRgn.Set(mutableShape);
     }
 }
 
@@ -1285,6 +1411,9 @@ void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDoubl
     }
     else
     {
+        // the clipping itself must be stored as device coordinates, otherwise 
+        // we cannot apply it back correctly
+        r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform );
         m_clipRgn.Set(HIShapeCreateWithRect(&r));
     }
 }
@@ -1294,8 +1423,15 @@ void wxMacCoreGraphicsContext::ResetClip()
 {
     if ( m_cgContext )
     {
+        // there is no way for clearing the clip, we can only revert to the stored
+        // state, but then we have to make sure everything else is NOT restored
+        CGAffineTransform transform = CGContextGetCTM( m_cgContext );
         CGContextRestoreGState( m_cgContext );
         CGContextSaveGState( m_cgContext );
+        CGAffineTransform transformNew = CGContextGetCTM( m_cgContext );
+        transformNew = CGAffineTransformInvert( transformNew ) ;
+        CGContextConcatCTM( m_cgContext, transformNew);
+        CGContextConcatCTM( m_cgContext, transform);
     }
     else
     {
@@ -1469,7 +1605,33 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo
 
     CGImageRef image = (CGImageRef)( bmp.CGImageCreate() );
     HIRect r = CGRectMake( x , y , w , h );
-    HIViewDrawCGImage( m_cgContext , &r , image );
+    if ( bmp.GetDepth() == 1 )
+    {
+        // is is a mask, the '1' in the mask tell where to draw the current brush
+        if (  !m_brush.IsNull() )
+        {
+            if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
+            {
+                // TODO clip to mask
+            /*
+                CGContextSaveGState( m_cgContext );
+                CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
+                CGContextClip( m_cgContext );
+                CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
+                CGContextRestoreGState( m_cgContext);
+            */
+            }
+            else
+            {
+                ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
+                HIViewDrawCGImage( m_cgContext , &r , image );
+            }
+        }
+    }
+    else
+    {
+        HIViewDrawCGImage( m_cgContext , &r , image );
+    }
     CGImageRelease( image );
 }
 
@@ -1595,28 +1757,8 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub
     wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
 
     Rect rect;
-/*
-    // TODO
-    if ( m_backgroundMode == wxSOLID )
-    {
-        wxGraphicsPath* path = m_graphicContext->CreatePath();
-        path->MoveToPoint( drawX , drawY );
-        path->AddLineToPoint(
-            (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ,
-            (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) );
-        path->AddLineToPoint(
-            (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
-            (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
-        path->AddLineToPoint(
-            (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
-            (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
-
-        m_graphicContext->FillPath( path , m_textBackgroundColour );
-        delete path;
-    }
-*/
-    x += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
-    y += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
+    x += (int)(sin(angle) * FixedToInt(ascent));
+    y += (int)(cos(angle) * FixedToInt(ascent));
 
     status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
         IntToFixed(x) , IntToFixed(y) , &rect );
@@ -1695,6 +1837,9 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid
         *width = FixedToInt(textAfter - textBefore);
 
     ::ATSUDisposeTextLayout(atsuLayout);
+#if SIZEOF_WCHAR_T == 4
+    free( ubuf ) ;
+#endif
 }
 
 void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
@@ -1753,6 +1898,9 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr
     }
 
     ::ATSUDisposeTextLayout(atsuLayout);
+#if SIZEOF_WCHAR_T == 4
+    free( ubuf ) ;
+#endif
 }
 
 void * wxMacCoreGraphicsContext::GetNativeContext()
@@ -1818,6 +1966,8 @@ public :
     virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
 
     virtual wxGraphicsContext * CreateContext( wxWindow* window );
+    
+    virtual wxGraphicsContext * CreateMeasuringContext();
 
     // Path
 
@@ -1864,7 +2014,16 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
 
 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc)
 {
-   return new wxMacCoreGraphicsContext(this,(CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
+    wxMemoryDC* mdc = wxDynamicCast(&dc, wxMemoryDC);
+    if ( mdc )
+    {
+        return new wxMacCoreGraphicsContext(this, 
+            (CGContextRef)mdc->GetGraphicsContext()->GetNativeContext());
+    }
+    else
+    {
+        return new wxMacCoreGraphicsContext(this,(CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
+    }
 }
 
 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
@@ -1883,6 +2042,11 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
     return new wxMacCoreGraphicsContext(this, window );
 }
 
+wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateMeasuringContext()
+{
+    return new wxMacCoreGraphicsContext(this);
+}
+
 // Path
 
 wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()