]> git.saurik.com Git - wxWidgets.git/commitdiff
switching to compositing operators (fixes #9881), adding layers
authorStefan Csomor <csomor@advancedconcepts.ch>
Sun, 15 Feb 2009 16:52:05 +0000 (16:52 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Sun, 15 Feb 2009 16:52:05 +0000 (16:52 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58917 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/graphics.h
src/common/dcgraph.cpp
src/common/graphcmn.cpp
src/generic/graphicc.cpp
src/msw/graphics.cpp
src/osx/carbon/graphics.cpp

index cd7ed7fcf084aae9189478ba716b4b06b01e5764..4d94b753003a515f8ac7958bee1b1852e6efb306 100644 (file)
 #include "wx/dynarray.h"
 #include "wx/dc.h"
 
+enum wxAntialiasMode
+{
+    wxANTIALIAS_NONE, // should be 0
+    wxANTIALIAS_DEFAULT,
+};
+
+enum wxCompositionMode
+{
+    // R = Result, S = Source, D = Destination, premultiplied with alpha
+    // Ra, Sa, Da their alpha components
+    
+    // classic Porter-Duff compositions
+    // http://keithp.com/~keithp/porterduff/p253-porter.pdf
+    
+    wxCOMPOSITION_CLEAR, /* R = 0 */
+    wxCOMPOSITION_SOURCE, /* R = S */
+    wxCOMPOSITION_OVER, /* R = S + D*(1 - Sa) */
+    wxCOMPOSITION_IN, /* R = S*Da */
+    wxCOMPOSITION_OUT, /* R = S*(1 - Da) */
+    wxCOMPOSITION_ATOP, /* R = S*Da + D*(1 - Sa) */
+
+    wxCOMPOSITION_DEST, /* R = D, essentially a noop */
+    wxCOMPOSITION_DEST_OVER, /* R = S*(1 - Da) + D */
+    wxCOMPOSITION_DEST_IN, /* R = D*Sa */
+    wxCOMPOSITION_DEST_OUT, /* R = D*(1 - Sa) */
+    wxCOMPOSITION_DEST_ATOP, /* R = S*(1 - Da) + D*Sa */
+    wxCOMPOSITION_XOR, /* R = S*(1 - Da) + D*(1 - Sa) */
+    
+    // mathematical compositions
+    wxCOMPOSITION_ADD, /* R = S + D */
+};
+
 class WXDLLIMPEXP_FWD_CORE wxWindowDC;
 class WXDLLIMPEXP_FWD_CORE wxMemoryDC;
 #if wxUSE_PRINTING_ARCHITECTURE
@@ -356,11 +388,17 @@ public:
     // returns the native context
     virtual void * GetNativeContext() = 0;
 
-    // returns the current logical function
-    virtual wxRasterOperationMode GetLogicalFunction() const { return m_logicalFunction; }
+    // returns the current shape antialiasing mode
+    virtual wxAntialiasMode GetAntialiasMode() const { return m_antialias; }
+    
+    // sets the antialiasing mode, returns true if it supported
+    virtual bool SetAntialiasMode(wxAntialiasMode antialias) = 0;
 
-    // sets the current logical function, returns true if it supported
-    virtual bool SetLogicalFunction(wxRasterOperationMode function);
+    // returns the current compositing operator
+    virtual wxCompositionMode GetCompositionMode() const { return m_composition; }
+    
+    // sets the compositing operator, returns true if it supported
+    virtual bool SetCompositionMode(wxCompositionMode op) = 0;
 
     // returns the size of the graphics context in device coordinates
     virtual void GetSize( wxDouble* width, wxDouble* height);
@@ -375,6 +413,14 @@ public:
     // returns the alpha on this context
     virtual wxDouble GetAlpha() const;
 #endif
+
+    // all rendering is done into a fully transparent temporary context
+    virtual void BeginLayer(wxDouble opacity) = 0;
+
+    // composites back the drawings into the content with the opacity given at 
+    // the BeginLayer call
+    virtual void EndLayer() = 0;
+
     //
     // transformation : changes the current transformation matrix CTM of the context
     //
@@ -477,7 +523,7 @@ public:
     // draws a polygon
     virtual void DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode fillStyle = wxODDEVEN_RULE );
 
-    // draws a polygon
+    // draws a rectangle
     virtual void DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h);
 
     // draws an ellipse
@@ -496,7 +542,8 @@ protected:
     wxGraphicsPen m_pen;
     wxGraphicsBrush m_brush;
     wxGraphicsFont m_font;
-    wxRasterOperationMode m_logicalFunction;
+    wxAntialiasMode m_antialias;
+    wxCompositionMode m_composition;
 
 protected:
     // implementations of overloaded public functions: we use different names
index 4a713993a8c3c96f0a7b36915122e36fa84c0c96..9e5e2b81fdb9ca010975a06536fe490038278ec4 100644 (file)
@@ -53,6 +53,43 @@ static inline double DegToRad(double deg)
     return (deg * M_PI) / 180.0;
 }
 
+static bool TranslateRasterOp(wxRasterOperationMode function, wxCompositionMode *op)
+{
+    switch ( function )
+    {
+        case wxCOPY:       // (default) src
+            *op = wxCOMPOSITION_SOURCE; //
+            break;
+        case wxOR:         // src OR dst
+            *op = wxCOMPOSITION_ADD;
+            break;
+        case wxNO_OP:      // dst
+            *op = wxCOMPOSITION_DEST; // ignore the source
+            break;
+        case wxCLEAR:      // 0
+            *op = wxCOMPOSITION_CLEAR;// clear dst
+            break;
+        case wxXOR:        // src XOR dst
+            *op = wxCOMPOSITION_XOR;
+            break;
+            
+        case wxAND:        // src AND dst
+        case wxAND_INVERT: // (NOT src) AND dst
+        case wxAND_REVERSE:// src AND (NOT dst)
+        case wxEQUIV:      // (NOT src) XOR dst
+        case wxINVERT:     // NOT dst
+        case wxNAND:       // (NOT src) OR (NOT dst)
+        case wxNOR:        // (NOT src) AND (NOT dst)
+        case wxOR_INVERT:  // (NOT src) OR dst
+        case wxOR_REVERSE: // src OR (NOT dst)
+        case wxSET:        // 1
+        case wxSRC_INVERT: // NOT src
+        default:
+            return false;
+    }
+    return true;
+}
+
 //-----------------------------------------------------------------------------
 // wxDC bridge class
 //-----------------------------------------------------------------------------
@@ -456,10 +493,16 @@ void wxGCDCImpl::SetLogicalFunction( wxRasterOperationMode function )
         return;
 
     m_logicalFunction = function;
-    if ( m_graphicContext->SetLogicalFunction( function ) )
-        m_logicalFunctionSupported=true;
+    
+    wxCompositionMode mode;
+    m_logicalFunctionSupported = TranslateRasterOp( function, &mode);
+    if (m_logicalFunctionSupported)
+        m_logicalFunctionSupported = m_graphicContext->SetCompositionMode(mode);
+        
+    if (mode == wxCOMPOSITION_XOR)
+        m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE);
     else
-        m_logicalFunctionSupported=false;
+        m_graphicContext->SetAntialiasMode(wxANTIALIAS_DEFAULT);
 }
 
 bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
@@ -822,53 +865,71 @@ bool wxGCDCImpl::DoStretchBlit(
 
     if ( logical_func == wxNO_OP )
         return true;
-    else if ( !m_graphicContext->SetLogicalFunction( logical_func ) )
+        
+    wxCompositionMode mode;
+    if ( !TranslateRasterOp(logical_func, &mode) )
     {
-        wxFAIL_MSG( wxT("Blitting is only supported with wxCOPY logical operation.") );
+        wxFAIL_MSG( wxT("Blitting is not supported with this logical operation.") );
         return false;
     }
 
-    if (xsrcMask == -1 && ysrcMask == -1)
+    bool retval = true;
+    
+    wxCompositionMode formerMode = m_graphicContext->GetCompositionMode();
+    if (m_graphicContext->SetCompositionMode(mode))
     {
-        xsrcMask = xsrc;
-        ysrcMask = ysrc;
-    }
+        wxAntialiasMode formerAa = m_graphicContext->GetAntialiasMode();
+        if (mode == wxCOMPOSITION_XOR)
+        {
+            m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE);
+        }
+            
+        if (xsrcMask == -1 && ysrcMask == -1)
+        {
+            xsrcMask = xsrc;
+            ysrcMask = ysrc;
+        }
 
-    wxRect subrect(source->LogicalToDeviceX(xsrc),
-                   source->LogicalToDeviceY(ysrc),
-                   source->LogicalToDeviceXRel(srcWidth),
-                   source->LogicalToDeviceYRel(srcHeight));
+        wxRect subrect(source->LogicalToDeviceX(xsrc),
+                       source->LogicalToDeviceY(ysrc),
+                       source->LogicalToDeviceXRel(srcWidth),
+                       source->LogicalToDeviceYRel(srcHeight));
 
-    // if needed clip the subrect down to the size of the source DC
-    wxCoord sw, sh;
-    source->GetSize(&sw, &sh);
-    sw = source->LogicalToDeviceXRel(sw);
-    sh = source->LogicalToDeviceYRel(sh);
-    if (subrect.x + subrect.width > sw)
-        subrect.width = sw - subrect.x;
-    if (subrect.y + subrect.height > sh)
-        subrect.height = sh - subrect.y;
+        // if needed clip the subrect down to the size of the source DC
+        wxCoord sw, sh;
+        source->GetSize(&sw, &sh);
+        sw = source->LogicalToDeviceXRel(sw);
+        sh = source->LogicalToDeviceYRel(sh);
+        if (subrect.x + subrect.width > sw)
+            subrect.width = sw - subrect.x;
+        if (subrect.y + subrect.height > sh)
+            subrect.height = sh - subrect.y;
 
-    wxBitmap blit = source->GetAsBitmap( &subrect );
+        wxBitmap blit = source->GetAsBitmap( &subrect );
 
-    if ( blit.IsOk() )
-    {
-        if ( !useMask && blit.GetMask() )
-            blit.SetMask(NULL);
+        if ( blit.IsOk() )
+        {
+            if ( !useMask && blit.GetMask() )
+                blit.SetMask(NULL);
 
-        m_graphicContext->DrawBitmap( blit, xdest, ydest,
-                                      dstWidth, dstHeight);
-    }
-    else
-    {
-        wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
-        return false;
+            m_graphicContext->DrawBitmap( blit, xdest, ydest,
+                                          dstWidth, dstHeight);
+        }
+        else
+        {
+            wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
+            retval = false;
+        }
+        
+        if (mode == wxCOMPOSITION_XOR)
+        {
+            m_graphicContext->SetAntialiasMode(formerAa);
+        }
     }
+    // reset composition
+    m_graphicContext->SetCompositionMode(formerMode);
 
-    // reset logical function
-    m_graphicContext->SetLogicalFunction( m_logicalFunction );
-
-    return true;
+    return retval;
 }
 
 void wxGCDCImpl::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
index f2396a06b1c5e82f48226f4709e4cf1f56ad7bc1..9cdfdbac0cfb96fc3337970bc84e55e53046cf12 100644 (file)
@@ -501,9 +501,11 @@ void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2,
 IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject)
 
 
-wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer)
+wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : 
+    wxGraphicsObject(renderer),
+      m_antialias(wxANTIALIAS_DEFAULT),
+      m_composition(wxCOMPOSITION_OVER)
 {
-    m_logicalFunction = wxCOPY;
 }
 
 wxGraphicsContext::~wxGraphicsContext()
@@ -589,16 +591,6 @@ void wxGraphicsContext::SetFont( const wxGraphicsFont& font )
     m_font = font;
 }
 
-bool wxGraphicsContext::SetLogicalFunction( wxRasterOperationMode function )
-{
-    if ( function == wxCOPY )
-    {
-        m_logicalFunction = function;
-        return true;
-    }
-    return false;
-}
-
 void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour )
 {
     if ( font.Ok() )
index 7380736638342091af7bba2e1d53655fb081f0d0..12f147147dc6d2af3111d1b37dc73d0240f3fdf9 100644 (file)
@@ -347,8 +347,14 @@ public:
 
     virtual void * GetNativeContext();
 
-    virtual bool SetLogicalFunction( wxRasterOperationMode function );
+    virtual bool SetAntialiasMode(wxAntialiasMode antialias);
 
+    virtual bool SetCompositionMode(wxCompositionMode op);
+
+    virtual void BeginLayer(wxDouble opacity);
+
+    virtual void EndLayer();
+    
     virtual void StrokePath( const wxGraphicsPath& p );
     virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE );
 
@@ -380,6 +386,8 @@ private:
     virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
 
     cairo_t* m_context;
+    
+    wxVector<float> m_layerOpacities;
 
     wxDECLARE_NO_COPY_CLASS(wxCairoContext);
 };
@@ -1536,54 +1544,98 @@ void * wxCairoContext::GetNativeContext()
     return m_context;
 }
 
-// Cairo doesn't support bitwise logical function (a.k.a. ROP, raster output
-// mode). Cairo supports Porter-Duff compositing operators, but they are quite
-// different, although in some cases have similar names.
-bool wxCairoContext::SetLogicalFunction( wxRasterOperationMode function )
+bool wxCairoContext::SetAntialiasMode(wxAntialiasMode antialias)
 {
-    if (m_logicalFunction == function)
+    if (m_antialias == antialias)
         return true;
 
-    cairo_operator_t op;
+    m_antialias = antialias;
+    
+    cairo_antialias_t antialiasMode;
+    switch (antialias)
+    {
+        case wxANTIALIAS_DEFAULT:
+            antialiasMode = CAIRO_ANTIALIAS_DEFAULT;
+            break;
+        case wxANTIALIAS_NONE:
+            antialiasMode = CAIRO_ANTIALIAS_NONE;
+            break;
+        default:
+            return false;
+    }
+    cairo_set_antialias(m_context, antialiasMode);
+    return true;
+}
 
-    switch ( function )
+bool wxCairoContext::SetCompositionMode(wxCompositionMode op)
+{
+    if ( m_composition == op )
+        return true;
+        
+    m_composition = op;
+    cairo_operator_t cop;
+    switch (op)
     {
-        case wxCOPY:       // (default) src
-            op = CAIRO_OPERATOR_OVER; // (also default)
+        case wxCOMPOSITION__CLEAR:
+            cop = CAIRO_OPERATOR_CLEAR;
             break;
-        case wxOR:         // src OR dst
-            op = CAIRO_OPERATOR_ADD;
+        case wxCOMPOSITION_SOURCE:
+            cop = CAIRO_OPERATOR_SOURCE;
             break;
-        case wxNO_OP:      // dst
-            op = CAIRO_OPERATOR_DEST; // ignore the source
+        case wxCOMPOSITION_OVER:
+            cop = CAIRO_OPERATOR_OVER;
             break;
-        case wxCLEAR:      // 0
-            op = CAIRO_OPERATOR_CLEAR;// clear dst
+        case wxCOMPOSITION_IN:
+            cop = CAIRO_OPERATOR_IN;
+            break;
+        case wxCOMPOSITION_OUT:
+            cop = CAIRO_OPERATOR_OUT;
+            break;
+        case wxCOMPOSITION_ATOP:
+            cop = CAIRO_OPERATOR_ATOP;
+            break;
+        case wxCOMPOSITION_DEST:
+            cop = CAIRO_OPERATOR_DEST;
+            break;
+        case wxCOMPOSITION_DEST_OVER:
+            cop = CAIRO_OPERATOR_DEST_OVER;
+            break;
+        case wxCOMPOSITION_DEST_IN:
+            cop = CAIRO_OPERATOR_DEST_IN;
+            break;
+        case wxCOMPOSITION_DEST_OUT:
+            cop = CAIRO_OPERATOR_DEST_OUT;
+            break;
+        case wxCOMPOSITION_DEST_ATOP:
+            cop = CAIRO_OPERATOR_DEST_ATOP;
+            break;
+        case wxCOMPOSITION_XOR:
+            cop = CAIRO_OPERATOR_XOR;
+            break;
+        case wxCOMPOSITION_ADD:
+            cop = CAIRO_OPERATOR_ADD;
             break;
-
-        case wxAND:        // src AND dst
-        case wxAND_INVERT: // (NOT src) AND dst
-        case wxAND_REVERSE:// src AND (NOT dst)
-        case wxEQUIV:      // (NOT src) XOR dst
-        case wxINVERT:     // NOT dst
-        case wxNAND:       // (NOT src) OR (NOT dst)
-        case wxNOR:        // (NOT src) AND (NOT dst)
-        case wxOR_INVERT:  // (NOT src) OR dst
-        case wxOR_REVERSE: // src OR (NOT dst)
-        case wxSET:        // 1
-        case wxSRC_INVERT: // NOT src
-        //wxXOR does _not_ correspond to CAIRO_OPERATOR_XOR
-        case wxXOR:        // src XOR dst
         default:
             return false;
     }
-
-    m_logicalFunction = function;
-    cairo_set_operator(m_context, op);
+    cairo_set_operator(m_context, cop);
     return true;
 }
 
+void wxCairoContext::BeginLayer(wxDouble opacity)
+{
+    m_layerOpacities.push_back(opacity);
+    cairo_push_group(m_context);
+}
 
+void wxCairoContext::EndLayer()
+{
+    float opacity = m_layerOpacities.back();
+    m_layerOpacities.pop_back();
+    cairo_pop_group_to_source(m_context);
+    cairo_paint_with_alpha(m_context,opacity);
+}
+    
 //-----------------------------------------------------------------------------
 // wxCairoRenderer declaration
 //-----------------------------------------------------------------------------
index e1173d1d9586c9f88f90e6257c11bf34050db2fa..bbecc508846f6997575f7a28f1a4901ade4f5a73 100644 (file)
@@ -304,6 +304,14 @@ public:
     // draws a polygon
     virtual void DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode fillStyle = wxODDEVEN_RULE );
 
+    virtual bool SetAntialiasMode(wxAntialiasMode antialias);
+
+    virtual bool SetCompositionMode(wxCompositionMode op);
+
+    virtual void BeginLayer(wxDouble opacity);
+
+    virtual void EndLayer();
+    
     virtual void Translate( wxDouble dx , wxDouble dy );
     virtual void Scale( wxDouble xScale , wxDouble yScale );
     virtual void Rotate( wxDouble angle );
@@ -1110,6 +1118,9 @@ void wxGDIPlusContext::ResetClip()
 
 void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
        if ( !m_pen.IsNull() )
        {
         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
@@ -1127,6 +1138,9 @@ void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
 
 void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode WXUNUSED(fillStyle) )
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
        Point *cpoints = new Point[n];
        for (size_t i = 0; i < n; i++)
@@ -1144,6 +1158,9 @@ void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPol
 
 void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     if ( !m_pen.IsNull() )
     {
         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
@@ -1153,6 +1170,9 @@ void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
 
 void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     if ( !m_brush.IsNull() )
     {
         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
@@ -1162,6 +1182,66 @@ void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode
     }
 }
 
+bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias)
+{
+    if (m_antialias == antialias)
+        return true;
+    
+    m_antialias = antialias;
+    
+    SmoothingMode antialiasMode;
+    switch (antialias)
+    {
+        case wxANTIALIAS_DEFAULT:
+            antialiasMode = SmoothingModeHighQuality;
+            break;
+        case wxANTIALIAS_NONE:
+            antialiasMode = SmoothingModeNone;
+            break;
+        default:
+            return false;
+    }
+    m_context->SetSmoothingMode(antialiasMode);
+    return true;
+}
+
+bool wxGDIPlusContext::SetCompositionMode(wxCompositionMode op)
+{
+    if ( m_composition == op )
+        return true;
+        
+    m_composition = op;
+    
+    if (m_composition == wxCOMPOSITION_DEST)
+        return true;
+
+    CompositingMode cop;
+    switch (op)
+    {
+        case wxCOMPOSITION_SOURCE:
+            cop = CompositingModeSourceCopy;
+            break;
+        case wxCOMPOSITION_OVER:
+            cop = CompositingModeSourceOver;
+            break;
+        default:
+            return false;
+    }
+
+    m_context->SetCompositingMode(cop);
+    return true;
+}
+
+void wxGDIPlusContext::BeginLayer(wxDouble opacity)
+{
+    // TODO
+}
+
+void wxGDIPlusContext::EndLayer()
+{
+    // TODO
+}    
+
 void wxGDIPlusContext::Rotate( wxDouble angle )
 {
     m_context->RotateTransform( RadToDeg(angle) );
@@ -1192,6 +1272,9 @@ void wxGDIPlusContext::PopState()
 
 void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bmp.GetRefData())->GetGDIPlusBitmap();
     if ( image )
     {
@@ -1215,6 +1298,9 @@ void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y,
 
 void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
     // find out by looking at the bitmap data whether there really was alpha in it
     HICON hIcon = (HICON)icon.GetHICON();
@@ -1278,6 +1364,9 @@ void wxGDIPlusContext::DoDrawFilledText(const wxString& str,
                                         wxDouble x, wxDouble y,
                                         const wxGraphicsBrush& brush)
 {
+   if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     wxCHECK_RET( !m_font.IsNull(),
                  wxT("wxGDIPlusContext::DrawText - no valid font set") );
 
index 4e1fac0d53335a1f738f3f1f41c24df52f4731e1..bb499d3df21488847a2a42630989448c0355afb0 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
 /////////////////////////////////////////////////////////////////////////////
 
@@ -77,6 +77,35 @@ 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
@@ -534,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 );
     }
 }
 
@@ -829,7 +853,7 @@ wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* rendere
     OSStatus status = noErr;
     m_macATSUIStyle = NULL;
 
-    status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , &m_macATSUIStyle );
+    status = ATSUCreateAndcopyStyle( (ATSUStyle) font.MacGetATSUStyle() , &m_macATSUIStyle );
 
     wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") );
 
@@ -1316,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
     //
@@ -1627,69 +1658,160 @@ bool wxMacCoreGraphicsContext::EnsureIsValid()
     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;
+
+    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 wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op)
+{
     if (EnsureIsValid()==false)
         return true;
-        
-    bool retval = false;
-    bool shouldAntiAlias = true;
-    CGBlendMode mode = kCGBlendModeNormal;
 
-#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 1 // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+    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;
+        case wxCOMPOSITION_ADD:
+            mode = kCGBlendModePlusLighter ;
+            break;
+        default:
+            return false;
         }
+        if ( cop != kCGCompositeOperationSourceOver )
+            CGContextSetCompositeOperation(m_cgContext, cop);
+        else
+            CGContextSetBlendMode(m_cgContext, mode);
     }
     else
+#endif
 #endif
     {
-        if ( function == wxCOPY )
-        {
-            retval = true;
-        }
-        else if ( function == wxINVERT || function == wxXOR )
+        CGBlendMode mode = kCGBlendModeNormal;
+        switch( op )
         {
-            // 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);
     }
+    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 )
@@ -1782,6 +1904,9 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
     if (EnsureIsValid()==false)
         return;
         
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
 
     ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
@@ -1794,6 +1919,9 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF
     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
@@ -1847,6 +1975,9 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF
     if (EnsureIsValid()==false)
         return;
         
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
     if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
     {
         CGContextSaveGState( m_cgContext );
@@ -1944,6 +2075,9 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble
 {
     if (EnsureIsValid()==false)
         return;
+
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
         
 #ifdef __WXMAC__
     wxMacCoreGraphicsBitmapData* refdata  =static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData());
@@ -1984,6 +2118,9 @@ void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDoubl
     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) );
@@ -2018,6 +2155,9 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo
     if (EnsureIsValid()==false)
         return;
         
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {
@@ -2078,6 +2218,9 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str,
     if (EnsureIsValid()==false)
         return;
         
+    if (m_composition == wxCOMPOSITION_DEST)
+        return;
+
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {