From bf02a7f9761ce9c0a1279ae958a0e5d53f603e15 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sun, 15 Feb 2009 16:52:05 +0000 Subject: [PATCH] switching to compositing operators (fixes #9881), adding layers git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58917 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/graphics.h | 59 ++++++++- src/common/dcgraph.cpp | 137 +++++++++++++------ src/common/graphcmn.cpp | 16 +-- src/generic/graphicc.cpp | 118 ++++++++++++----- src/msw/graphics.cpp | 89 +++++++++++++ src/osx/carbon/graphics.cpp | 253 ++++++++++++++++++++++++++++-------- 6 files changed, 528 insertions(+), 144 deletions(-) diff --git a/include/wx/graphics.h b/include/wx/graphics.h index cd7ed7fcf0..4d94b75300 100644 --- a/include/wx/graphics.h +++ b/include/wx/graphics.h @@ -20,6 +20,38 @@ #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 diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index 4a713993a8..9e5e2b81fd 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -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, diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index f2396a06b1..9cdfdbac0c 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -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() ) diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 7380736638..12f147147d 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -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 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 //----------------------------------------------------------------------------- diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index e1173d1d95..bbecc50884 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -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(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") ); diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 4e1fac0d53..bb499d3df2 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -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 ®ion ) @@ -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(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 ) { -- 2.45.2