X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1b89a5cd94246c473b73fea239ee8a6066d410da..77c8efc8c37da6d6a5e2e8022d21d1cd7d76371d:/src/common/dcgraph.cpp diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index 136775cbad..2b9b2913a5 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -1,9 +1,9 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/common/graphcmn.cpp +// Name: src/common/dcgraph.cpp // Purpose: graphics context methods common to all platforms // Author: Stefan Csomor // Modified by: -// Created: +// Created: // RCS-ID: $Id$ // Copyright: (c) Stefan Csomor // Licence: wxWindows licence @@ -18,13 +18,12 @@ #if wxUSE_GRAPHICS_CONTEXT -#include "wx/graphics.h" +#include "wx/dcgraph.h" #ifndef WX_PRECOMP #include "wx/icon.h" - #include "wx/bitmap.h" + #include "wx/dcclient.h" #include "wx/dcmemory.h" - #include "wx/region.h" #endif //----------------------------------------------------------------------------- @@ -42,41 +41,164 @@ static inline double DegToRad(double deg) return (deg * M_PI) / 180.0; } +static wxCompositionMode TranslateRasterOp(wxRasterOperationMode function) +{ + switch ( function ) + { + case wxCOPY: // src + // since we are supporting alpha, _OVER is closer to the intention than _SOURCE + // since the latter would overwrite even when alpha is not set to opaque + return wxCOMPOSITION_OVER; + + case wxOR: // src OR dst + return wxCOMPOSITION_ADD; + + case wxNO_OP: // dst + return wxCOMPOSITION_DEST; // ignore the source + + case wxCLEAR: // 0 + return wxCOMPOSITION_CLEAR;// clear dst + + case wxXOR: // src XOR dst + return wxCOMPOSITION_XOR; + + 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 + break; + } + + return wxCOMPOSITION_INVALID; +} + //----------------------------------------------------------------------------- // wxDC bridge class //----------------------------------------------------------------------------- -#ifdef __WXMAC__ -IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase) -#else IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC) + +wxGCDC::wxGCDC(const wxWindowDC& dc) : + wxDC( new wxGCDCImpl( this, dc ) ) +{ +} + +wxGCDC::wxGCDC( const wxMemoryDC& dc) : + wxDC( new wxGCDCImpl( this, dc ) ) +{ +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxGCDC::wxGCDC( const wxPrinterDC& dc) : + wxDC( new wxGCDCImpl( this, dc ) ) +{ +} +#endif + +#if defined(__WXMSW__) && wxUSE_ENH_METAFILE +wxGCDC::wxGCDC(const wxEnhMetaFileDC& dc) + : wxDC(new wxGCDCImpl(this, dc)) +{ +} #endif -wxGCDC::wxGCDC() +wxGCDC::wxGCDC(wxGraphicsContext* context) : + wxDC( new wxGCDCImpl( this ) ) +{ + SetGraphicsContext(context); +} + +wxGCDC::wxGCDC() : + wxDC( new wxGCDCImpl( this ) ) +{ +} + +wxGCDC::~wxGCDC() +{ +} + +wxGraphicsContext* wxGCDC::GetGraphicsContext() const { - Init(); + if (!m_pimpl) return NULL; + wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl; + return gc_impl->GetGraphicsContext(); } void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) -{ +{ + if (!m_pimpl) return; + wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl; + gc_impl->SetGraphicsContext( ctx ); +} + +IMPLEMENT_ABSTRACT_CLASS(wxGCDCImpl, wxDCImpl) + +wxGCDCImpl::wxGCDCImpl( wxDC *owner ) : + wxDCImpl( owner ) +{ + Init(wxGraphicsContext::Create()); +} + +void wxGCDCImpl::SetGraphicsContext( wxGraphicsContext* ctx ) +{ delete m_graphicContext; m_graphicContext = ctx; + if ( m_graphicContext ) + { + m_matrixOriginal = m_graphicContext->GetTransform(); + m_ok = true; + // apply the stored transformations to the passed in context + ComputeScaleAndOrigin(); + m_graphicContext->SetFont( m_font , m_textForegroundColour ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush); + } } -wxGCDC::wxGCDC(const wxWindowDC& dc) +wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxWindowDC& dc ) : + wxDCImpl( owner ) { - Init(); - m_graphicContext = wxGraphicsContext::Create(dc); - m_ok = true; - if ( dc.GetFont().Ok()) - m_graphicContext->SetFont( m_graphicContext->CreateFont(dc.GetFont(),dc.GetTextForeground())); - if ( dc.GetPen().Ok()) - m_graphicContext->SetPen( m_graphicContext->CreatePen(dc.GetPen())); - if ( dc.GetBrush().Ok()) - m_graphicContext->SetBrush( m_graphicContext->CreateBrush(dc.GetBrush())); + Init(wxGraphicsContext::Create(dc)); + m_window = dc.GetWindow(); } -void wxGCDC::Init() +wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxMemoryDC& dc ) : + wxDCImpl( owner ) +{ + Init(wxGraphicsContext::Create(dc)); +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxPrinterDC& dc ) : + wxDCImpl( owner ) +{ + Init(wxGraphicsContext::Create(dc)); +} +#endif + +#if defined(__WXMSW__) && wxUSE_ENH_METAFILE +wxGCDCImpl::wxGCDCImpl(wxDC *owner, const wxEnhMetaFileDC& dc) + : wxDCImpl(owner) +{ + Init(wxGraphicsContext::Create(dc)); +} +#endif + +wxGCDCImpl::wxGCDCImpl(wxDC* owner, int) + : wxDCImpl(owner) +{ + // derived class will set a context + Init(NULL); +} + +void wxGCDCImpl::Init(wxGraphicsContext* ctx) { m_ok = false; m_colour = true; @@ -88,438 +210,329 @@ void wxGCDC::Init() m_brush = *wxWHITE_BRUSH; m_graphicContext = NULL; -} + if (ctx) + SetGraphicsContext(ctx); + m_logicalFunctionSupported = true; +} -wxGCDC::~wxGCDC() +wxGCDCImpl::~wxGCDCImpl() { delete m_graphicContext; } -void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) +void wxGCDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, + bool useMask ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); - wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); + wxCHECK_RET( bmp.IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord w = bmp.GetWidth(); - wxCoord h = bmp.GetHeight(); - wxCoord ww = LogicalToDeviceXRel(w); - wxCoord hh = LogicalToDeviceYRel(h); + int w = bmp.GetWidth(); + int h = bmp.GetHeight(); + if ( bmp.GetDepth() == 1 ) + { + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); + m_graphicContext->DrawRectangle( x, y, w, h ); + m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); + m_graphicContext->DrawBitmap( bmp, x, y, w, h ); + m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); + m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); + } + else // not a monochrome bitmap, handle it normally + { + // make a copy in case we need to remove its mask, if we don't modify + // it the copy is cheap as bitmaps are reference-counted + wxBitmap bmpCopy(bmp); + if ( !useMask && bmp.GetMask() ) + bmpCopy.SetMask(NULL); - m_graphicContext->DrawBitmap( bmp, xx , yy , ww , hh ); + m_graphicContext->DrawBitmap( bmpCopy, x, y, w, h ); + } } -void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +void wxGCDCImpl::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); - wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); + wxCHECK_RET( icon.IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); wxCoord w = icon.GetWidth(); wxCoord h = icon.GetHeight(); - wxCoord ww = LogicalToDeviceXRel(w); - wxCoord hh = LogicalToDeviceYRel(h); - m_graphicContext->DrawIcon( icon , xx, yy, ww, hh ); + m_graphicContext->DrawIcon( icon , x, y, w, h ); } -void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +bool wxGCDCImpl::StartDoc( const wxString& WXUNUSED(message) ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); + return true; +} - wxCoord xx, yy, ww, hh; - xx = LogicalToDeviceX(x); - yy = LogicalToDeviceY(y); - ww = LogicalToDeviceXRel(width); - hh = LogicalToDeviceYRel(height); +void wxGCDCImpl::EndDoc() +{ +} - m_graphicContext->Clip( xx, yy, ww, hh ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, xx ); - m_clipY1 = wxMax( m_clipY1, yy ); - m_clipX2 = wxMin( m_clipX2, (xx + ww) ); - m_clipY2 = wxMin( m_clipY2, (yy + hh) ); - } - else - { - m_clipping = true; +void wxGCDCImpl::StartPage() +{ +} - m_clipX1 = xx; - m_clipY1 = yy; - m_clipX2 = xx + ww; - m_clipY2 = yy + hh; - } +void wxGCDCImpl::EndPage() +{ +} + +void wxGCDCImpl::Flush() +{ + m_graphicContext->Flush(); } -void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxGCDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); + + m_graphicContext->Clip( x, y, w, h ); + + wxDCImpl::DoSetClippingRegion(x, y, w, h); +} + +void wxGCDCImpl::DoSetDeviceClippingRegion( const wxRegion ®ion ) +{ + // region is in device coordinates + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetDeviceClippingRegion - invalid DC") ); if (region.Empty()) { - DestroyClippingRegion(); + //DestroyClippingRegion(); return; } + wxRegion logRegion( region ); wxCoord x, y, w, h; - region.GetBox( x, y, w, h ); - wxCoord xx, yy, ww, hh; - xx = LogicalToDeviceX(x); - yy = LogicalToDeviceY(y); - ww = LogicalToDeviceXRel(w); - hh = LogicalToDeviceYRel(h); - - // if we have a scaling that we cannot map onto native regions - // we must use the box - if ( ww != w || hh != h ) + + logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); + logRegion.GetBox( x, y, w, h ); + + m_graphicContext->Clip( logRegion ); + if ( m_clipping ) { - wxGCDC::DoSetClippingRegion( x, y, w, h ); + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); } else { - m_graphicContext->Clip( region ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, xx ); - m_clipY1 = wxMax( m_clipY1, yy ); - m_clipX2 = wxMin( m_clipX2, (xx + ww) ); - m_clipY2 = wxMin( m_clipY2, (yy + hh) ); - } - else - { - m_clipping = true; + m_clipping = true; - m_clipX1 = xx; - m_clipY1 = yy; - m_clipX2 = xx + ww; - m_clipY2 = yy + hh; - } + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; } } -void wxGCDC::DestroyClippingRegion() +void wxGCDCImpl::DestroyClippingRegion() { m_graphicContext->ResetClip(); + // currently the clip eg of a window extends to the area between the scrollbars + // so we must explicitly make sure it only covers the area we want it to draw + int width, height ; + GetOwner()->GetSize( &width , &height ) ; + m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) ); + m_graphicContext->SetPen( m_pen ); m_graphicContext->SetBrush( m_brush ); m_clipping = false; } -void wxGCDC::DoGetSizeMM( int* width, int* height ) const +void wxGCDCImpl::DoGetSizeMM( int* width, int* height ) const { int w = 0, h = 0; - GetSize( &w, &h ); + GetOwner()->GetSize( &w, &h ); if (width) *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) ); if (height) *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) ); } -void wxGCDC::SetTextForeground( const wxColour &col ) +void wxGCDCImpl::SetTextForeground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); - if ( col != m_textForegroundColour ) + // don't set m_textForegroundColour to an invalid colour as we'd crash + // later then (we use m_textForegroundColour.GetColor() without checking + // in a few places) + if ( col.IsOk() ) { m_textForegroundColour = col; m_graphicContext->SetFont( m_font, m_textForegroundColour ); } } -void wxGCDC::SetTextBackground( const wxColour &col ) +void wxGCDCImpl::SetTextBackground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); m_textBackgroundColour = col; } -void wxGCDC::SetMapMode( int mode ) +wxSize wxGCDCImpl::GetPPI() const { - switch (mode) - { - case wxMM_TWIPS: - SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); - break; - - case wxMM_POINTS: - SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); - break; - - case wxMM_METRIC: - SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); - break; - - case wxMM_LOMETRIC: - SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); - break; - - case wxMM_TEXT: - default: - SetLogicalScale( 1.0, 1.0 ); - break; - } - - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetUserScale( double x, double y ) -{ - // allow negative ? -> no - - m_userScaleX = x; - m_userScaleY = y; - ComputeScaleAndOrigin(); + return wxSize(72, 72); } -void wxGCDC::SetLogicalScale( double x, double y ) +int wxGCDCImpl::GetDepth() const { - // allow negative ? - m_logicalScaleX = x; - m_logicalScaleY = y; - ComputeScaleAndOrigin(); + return 32; } -void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +void wxGCDCImpl::ComputeScaleAndOrigin() { - m_logicalOriginX = x * m_signX; // is this still correct ? - m_logicalOriginY = y * m_signY; - ComputeScaleAndOrigin(); -} + wxDCImpl::ComputeScaleAndOrigin(); -void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y ) -{ - m_deviceOriginX = x; - m_deviceOriginY = y; - ComputeScaleAndOrigin(); -} + if ( m_graphicContext ) + { + m_matrixCurrent = m_graphicContext->CreateMatrix(); -void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) -{ - m_signX = (xLeftRight ? 1 : -1); - m_signY = (yBottomUp ? -1 : 1); - ComputeScaleAndOrigin(); -} + // the logical origin sets the origin to have new coordinates + m_matrixCurrent.Translate( m_deviceOriginX - m_logicalOriginX * m_signX * m_scaleX, + m_deviceOriginY-m_logicalOriginY * m_signY * m_scaleY); -wxSize wxGCDC::GetPPI() const -{ - return wxSize(72, 72); -} + m_matrixCurrent.Scale( m_scaleX * m_signX, m_scaleY * m_signY ); -int wxGCDC::GetDepth() const -{ - return 32; + m_graphicContext->SetTransform( m_matrixOriginal ); + m_graphicContext->ConcatTransform( m_matrixCurrent ); + } } -void wxGCDC::ComputeScaleAndOrigin() +void* wxGCDCImpl::GetHandle() const { - // CMB: copy scale to see if it changes - double origScaleX = m_scaleX; - double origScaleY = m_scaleY; - m_scaleX = m_logicalScaleX * m_userScaleX; - m_scaleY = m_logicalScaleY * m_userScaleY; - m_deviceOriginX = m_deviceOriginX + m_logicalOriginX; - m_deviceOriginY = m_deviceOriginY + m_logicalOriginY; - - // CMB: if scale has changed call SetPen to recalulate the line width - if (m_scaleX != origScaleX || m_scaleY != origScaleY) - { - // this is a bit artificial, but we need to force wxDC to think - // the pen has changed - wxPen pen(GetPen()); - m_pen = wxNullPen; - SetPen(pen); - SetFont(m_font); + void* cgctx = NULL; + wxGraphicsContext* gc = GetGraphicsContext(); + if (gc) { + cgctx = gc->GetNativeContext(); } + return cgctx; } -void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +void wxGCDCImpl::SetPalette( const wxPalette& WXUNUSED(palette) ) { } -void wxGCDC::SetBackgroundMode( int mode ) +void wxGCDCImpl::SetBackgroundMode( int mode ) { m_backgroundMode = mode; } -void wxGCDC::SetFont( const wxFont &font ) +void wxGCDCImpl::SetFont( const wxFont &font ) { m_font = font; if ( m_graphicContext ) { - wxFont f = font; - if ( f.Ok() ) - f.SetPointSize( LogicalToDeviceYRel(font.GetPointSize())); - m_graphicContext->SetFont( f, m_textForegroundColour ); + m_graphicContext->SetFont(font, m_textForegroundColour); } } -void wxGCDC::SetPen( const wxPen &pen ) +void wxGCDCImpl::SetPen( const wxPen &pen ) { - if ( m_pen == pen ) - return; - m_pen = pen; if ( m_graphicContext ) { - if ( m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT ) - { - m_graphicContext->SetPen( m_pen ); - } - else - { - // we have to compensate for moved device origins etc. otherwise patterned pens are standing still - // eg when using a wxScrollWindow and scrolling around - int origX = LogicalToDeviceX( 0 ); - int origY = LogicalToDeviceY( 0 ); - m_graphicContext->Translate( origX , origY ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->Translate( -origX , -origY ); - } + m_graphicContext->SetPen( m_pen ); } } -void wxGCDC::SetBrush( const wxBrush &brush ) +void wxGCDCImpl::SetBrush( const wxBrush &brush ) { - if (m_brush == brush) - return; - m_brush = brush; if ( m_graphicContext ) { - if ( brush.GetStyle() == wxSOLID || brush.GetStyle() == wxTRANSPARENT ) - { - m_graphicContext->SetBrush( m_brush ); - } - else - { - // we have to compensate for moved device origins etc. otherwise patterned brushes are standing still - // eg when using a wxScrollWindow and scrolling around - // TODO on MSW / GDIPlus this still occurs with hatched brushes - int origX = LogicalToDeviceX(0); - int origY = LogicalToDeviceY(0); - m_graphicContext->Translate( origX , origY ); - m_graphicContext->SetBrush( m_brush ); - m_graphicContext->Translate( -origX , -origY ); - } + m_graphicContext->SetBrush( m_brush ); } } -void wxGCDC::SetBackground( const wxBrush &brush ) +void wxGCDCImpl::SetBackground( const wxBrush &brush ) { - if (m_backgroundBrush == brush) - return; - m_backgroundBrush = brush; - if (!m_backgroundBrush.Ok()) + if (!m_backgroundBrush.IsOk()) return; } -void wxGCDC::SetLogicalFunction( int function ) +void wxGCDCImpl::SetLogicalFunction( wxRasterOperationMode function ) { - if (m_logicalFunction == function) - return; - m_logicalFunction = function; -#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES - CGContextRef cgContext = ((wxCairoContext*)(m_graphicContext))->GetNativeContext(); - if ( m_logicalFunction == wxCOPY ) - CGContextSetBlendMode( cgContext, kCGBlendModeNormal ); - else if ( m_logicalFunction == wxINVERT ) - CGContextSetBlendMode( cgContext, kCGBlendModeExclusion ); - else - CGContextSetBlendMode( cgContext, kCGBlendModeNormal ); -#endif + wxCompositionMode mode = TranslateRasterOp( function ); + m_logicalFunctionSupported = mode != wxCOMPOSITION_INVALID; + if (m_logicalFunctionSupported) + m_logicalFunctionSupported = m_graphicContext->SetCompositionMode(mode); + if ( function == wxXOR ) + m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE); + else + m_graphicContext->SetAntialiasMode(wxANTIALIAS_DEFAULT); } -bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour& WXUNUSED(col), int WXUNUSED(style)) +bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), + const wxColour& WXUNUSED(col), + wxFloodFillStyle WXUNUSED(style)) { return false; } -bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const +bool wxGCDCImpl::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const { // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") ); return false; } -void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +void wxGCDCImpl::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); -#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES - - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; -#endif - wxCoord xx1 = LogicalToDeviceX(x1); - wxCoord yy1 = LogicalToDeviceY(y1); - wxCoord xx2 = LogicalToDeviceX(x2); - wxCoord yy2 = LogicalToDeviceY(y2); - - m_graphicContext->StrokeLine(xx1,yy1,xx2,yy2); + m_graphicContext->StrokeLine(x1,y1,x2,y2); CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); } -void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) +void wxGCDCImpl::DoCrossHair( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; int w = 0, h = 0; - GetSize( &w, &h ); - - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord xw = LogicalToDeviceX(w); - wxCoord x0 = LogicalToDeviceX(0); - wxCoord y0 = LogicalToDeviceY(0); - wxCoord yh = LogicalToDeviceY(h); + GetOwner()->GetSize( &w, &h ); - m_graphicContext->StrokeLine(x0,yy,xw,yy); - m_graphicContext->StrokeLine(xx,y0,xx,yh); + m_graphicContext->StrokeLine(0,y,w,y); + m_graphicContext->StrokeLine(x,0,x,h); - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0+xw, y0+yh); + CalcBoundingBox(0, 0); + CalcBoundingBox(0+w, 0+h); } -void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, +void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx1 = LogicalToDeviceX(x1); - wxCoord yy1 = LogicalToDeviceY(y1); - wxCoord xx2 = LogicalToDeviceX(x2); - wxCoord yy2 = LogicalToDeviceY(y2); - wxCoord xxc = LogicalToDeviceX(xc); - wxCoord yyc = LogicalToDeviceY(yc); - - double dx = xx1 - xxc; - double dy = yy1 - yyc; + double dx = x1 - xc; + double dy = y1 - yc; double radius = sqrt((double)(dx * dx + dy * dy)); wxCoord rad = (wxCoord)radius; double sa, ea; - if (xx1 == xx2 && yy1 == yy2) + if (x1 == x2 && y1 == y2) { sa = 0.0; ea = 360.0; @@ -530,93 +543,84 @@ void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, } else { - sa = (xx1 - xxc == 0) ? - (yy1 - yyc < 0) ? 90.0 : -90.0 : - -atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG; - ea = (xx2 - xxc == 0) ? - (yy2 - yyc < 0) ? 90.0 : -90.0 : - -atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG; + sa = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; + ea = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; } bool fill = m_brush.GetStyle() != wxTRANSPARENT; - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); if ( fill && ((x1!=x2)||(y1!=y2)) ) - path->MoveToPoint( xxc, yyc ); - path->AddArc( xxc, yyc , rad , DegToRad(sa) , DegToRad(ea), false ); + path.MoveToPoint( xc, yc ); + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); if ( fill && ((x1!=x2)||(y1!=y2)) ) - path->AddLineToPoint( xxc, yyc ); + path.AddLineToPoint( xc, yc ); m_graphicContext->DrawPath(path); - delete path; } -void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, +void wxGCDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, double sa, double ea ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(w); - wxCoord hh = m_signY * LogicalToDeviceYRel(h); + m_graphicContext->PushState(); + m_graphicContext->Translate(x+w/2.0,y+h/2.0); + wxDouble factor = ((wxDouble) w) / h; + m_graphicContext->Scale( factor , 1.0); - // handle -ve width and/or height - if (ww < 0) + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + if ( m_brush.GetStyle() != wxTRANSPARENT ) { - ww = -ww; - xx = xx - ww; + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.MoveToPoint( 0, 0 ); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + path.AddLineToPoint( 0, 0 ); + m_graphicContext->FillPath( path ); + + path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->StrokePath( path ); } - if (hh < 0) + else { - hh = -hh; - yy = yy - hh; + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->DrawPath( path ); } - bool fill = m_brush.GetStyle() != wxTRANSPARENT; - - wxGraphicsPath* path = m_graphicContext->CreatePath(); - m_graphicContext->PushState(); - m_graphicContext->Translate(xx+ww/2,yy+hh/2); - wxDouble factor = ((wxDouble) ww) / hh; - m_graphicContext->Scale( factor , 1.0); - if ( fill && (sa!=ea) ) - path->MoveToPoint(0,0); - // since these angles (ea,sa) are measured counter-clockwise, we invert them to - // get clockwise angles - path->AddArc( 0, 0, hh/2 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - if ( fill && (sa!=ea) ) - path->AddLineToPoint(0,0); - m_graphicContext->DrawPath( path ); m_graphicContext->PopState(); - delete path; } -void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) +void wxGCDCImpl::DoDrawPoint( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); DoDrawLine( x , y , x + 1 , y + 1 ); } -void wxGCDC::DoDrawLines(int n, wxPoint points[], +void wxGCDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); - -#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; -#endif wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; for( int i = 0; i < n; ++i) { - pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset); - pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset); + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; } m_graphicContext->StrokeLines( n , pointsD); @@ -624,45 +628,45 @@ void wxGCDC::DoDrawLines(int n, wxPoint points[], } #if wxUSE_SPLINES -void wxGCDC::DoDrawSpline(wxList *points) +void wxGCDCImpl::DoDrawSpline(const wxPointList *points) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); - wxList::compatibility_iterator node = points->GetFirst(); - if (node == wxList::compatibility_iterator()) + wxPointList::compatibility_iterator node = points->GetFirst(); + if ( !node ) // empty list return; - wxPoint *p = (wxPoint *)node->GetData(); + wxPoint *p = node->GetData(); wxCoord x1 = p->x; wxCoord y1 = p->y; node = node->GetNext(); - p = (wxPoint *)node->GetData(); + p = node->GetData(); wxCoord x2 = p->x; wxCoord y2 = p->y; wxCoord cx1 = ( x1 + x2 ) / 2; wxCoord cy1 = ( y1 + y2 ) / 2; - path->MoveToPoint( LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) ); - path->AddLineToPoint( LogicalToDeviceX( cx1 ) , LogicalToDeviceY( cy1 ) ); -#if !wxUSE_STL + path.MoveToPoint( x1 , y1 ); + path.AddLineToPoint( cx1 , cy1 ); +#if !wxUSE_STD_CONTAINERS while ((node = node->GetNext()) != NULL) #else while ((node = node->GetNext())) -#endif // !wxUSE_STL +#endif // !wxUSE_STD_CONTAINERS { - p = (wxPoint *)node->GetData(); + p = node->GetData(); x1 = x2; y1 = y2; x2 = p->x; @@ -670,30 +674,27 @@ void wxGCDC::DoDrawSpline(wxList *points) wxCoord cx4 = (x1 + x2) / 2; wxCoord cy4 = (y1 + y2) / 2; - path->AddQuadCurveToPoint( - LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) , - LogicalToDeviceX( cx4 ) , LogicalToDeviceY( cy4 ) ); + path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); cx1 = cx4; cy1 = cy4; } - path->AddLineToPoint( LogicalToDeviceX( x2 ) , LogicalToDeviceY( y2 ) ); + path.AddLineToPoint( x2 , y2 ); m_graphicContext->StrokePath( path ); - delete path; } #endif // wxUSE_SPLINES -void wxGCDC::DoDrawPolygon( int n, wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle ) +void wxGCDCImpl::DoDrawPolygon( int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + wxPolygonFillMode fillStyle ) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) return; - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; bool closeIt = false; @@ -703,8 +704,8 @@ void wxGCDC::DoDrawPolygon( int n, wxPoint points[], wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; for( int i = 0; i < n; ++i) { - pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset); - pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset); + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; } if ( closeIt ) pointsD[n] = pointsD[0]; @@ -713,256 +714,257 @@ void wxGCDC::DoDrawPolygon( int n, wxPoint points[], delete[] pointsD; } -void wxGCDC::DoDrawPolyPolygon(int n, +void wxGCDCImpl::DoDrawPolyPolygon(int n, int count[], wxPoint points[], wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { wxASSERT(n > 1); - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); int i = 0; for ( int j = 0; j < n; ++j) { wxPoint start = points[i]; - path->MoveToPoint(LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset)); + path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); ++i; int l = count[j]; for ( int k = 1; k < l; ++k) { - path->AddLineToPoint( LogicalToDeviceX(points[i].x+ xoffset), LogicalToDeviceY(points[i].y+ yoffset)); + path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); ++i; } // close the polygon if ( start != points[i-1]) - path->AddLineToPoint( LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset)); + path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); } m_graphicContext->DrawPath( path , fillStyle); - delete path; } -void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +void wxGCDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(width); - wxCoord hh = m_signY * LogicalToDeviceYRel(height); - // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) + if (w == 0 || h == 0) return; - // CMB: handle -ve width and/or height - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) + if ( m_graphicContext->ShouldOffset() ) { - hh = -hh; - yy = yy - hh; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(x,y,w,h); } -void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, - wxCoord width, wxCoord height, +void wxGCDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, + wxCoord w, wxCoord h, double radius) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; if (radius < 0.0) - radius = - radius * ((width < height) ? width : height); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(width); - wxCoord hh = m_signY * LogicalToDeviceYRel(height); + radius = - radius * ((w < h) ? w : h); // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) + if (w == 0 || h == 0) return; - // CMB: handle -ve width and/or height - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) + if ( m_graphicContext->ShouldOffset() ) { - hh = -hh; - yy = yy - hh; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - - m_graphicContext->DrawRoundedRectangle( xx,yy,ww,hh,radius); + m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); } -void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +void wxGCDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); - - if ( m_logicalFunction != wxCOPY ) - return; - - wxDouble xx = LogicalToDeviceX(x); - wxDouble yy = LogicalToDeviceY(y); - wxDouble ww = m_signX * LogicalToDeviceXRel(width); - wxDouble hh = m_signY * LogicalToDeviceYRel(height); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); - // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) + if ( !m_logicalFunctionSupported ) return; - // CMB: handle -ve width and/or height - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) + if ( m_graphicContext->ShouldOffset() ) { - hh = -hh; - yy = yy - hh; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - - m_graphicContext->DrawEllipse(xx,yy,ww,hh); + m_graphicContext->DrawEllipse(x,y,w,h); } -bool wxGCDC::CanDrawBitmap() const +bool wxGCDCImpl::CanDrawBitmap() const { return true; } -bool wxGCDC::DoBlit( +bool wxGCDCImpl::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), + wxDC *source, wxCoord xsrc, wxCoord ysrc, + wxRasterOperationMode logical_func , bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + return DoStretchBlit( xdest, ydest, width, height, + source, xsrc, ysrc, width, height, logical_func, useMask, + xsrcMask,ysrcMask ); +} + +bool wxGCDCImpl::DoStretchBlit( + wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight, + wxRasterOperationMode logical_func , bool useMask, wxCoord xsrcMask, wxCoord ysrcMask ) { - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); - wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); + wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") ); + wxCHECK_MSG( source->IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") ); if ( logical_func == wxNO_OP ) return true; - if (xsrcMask == -1 && ysrcMask == -1) + wxCompositionMode mode = TranslateRasterOp(logical_func); + if ( mode == wxCOMPOSITION_INVALID ) { - xsrcMask = xsrc; - ysrcMask = ysrc; + wxFAIL_MSG( wxT("Blitting is not supported with this logical operation.") ); + return false; } - wxCoord yysrc = source-> LogicalToDeviceY(ysrc); - wxCoord xxsrc = source-> LogicalToDeviceX(xsrc); - wxCoord wwsrc = source-> LogicalToDeviceXRel(width); - wxCoord hhsrc = source-> LogicalToDeviceYRel(height); + wxRect subrect(source->LogicalToDeviceX(xsrc), + source->LogicalToDeviceY(ysrc), + source->LogicalToDeviceXRel(srcWidth), + source->LogicalToDeviceYRel(srcHeight)); + const wxRect subrectOrig = subrect; + // clip the subrect down to the size of the source DC + wxRect clip; + source->GetSize(&clip.width, &clip.height); + subrect.Intersect(clip); + if (subrect.width == 0) + return true; - wxCoord yydest = LogicalToDeviceY(ydest); - wxCoord xxdest = LogicalToDeviceX(xdest); - wxCoord wwdest = LogicalToDeviceXRel(width); - wxCoord hhdest = LogicalToDeviceYRel(height); + bool retval = true; - wxMemoryDC* memdc = wxDynamicCast(source,wxMemoryDC); - if ( memdc && logical_func == wxCOPY ) + wxCompositionMode formerMode = m_graphicContext->GetCompositionMode(); + if (m_graphicContext->SetCompositionMode(mode)) { - wxBitmap blit = memdc->GetSelectedBitmap(); + wxAntialiasMode formerAa = m_graphicContext->GetAntialiasMode(); + if (mode == wxCOMPOSITION_XOR) + { + m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE); + } - wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ); + if (xsrcMask == -1 && ysrcMask == -1) + { + xsrcMask = xsrc; + ysrcMask = ysrc; + } - wxCoord bmpwidth = blit.GetWidth(); - wxCoord bmpheight = blit.GetHeight(); + wxBitmap blit = source->GetAsBitmap( &subrect ); - if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc ) + if ( blit.IsOk() ) { - wwsrc = wxMin( wwsrc , bmpwidth - xxsrc ); - hhsrc = wxMin( hhsrc , bmpheight - yysrc ); - if ( wwsrc > 0 && hhsrc > 0 ) - { - if ( xxsrc >= 0 && yysrc >= 0 ) - { - wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc ); - // TODO we perhaps could add a DrawSubBitmap call to dc for performance reasons - blit = blit.GetSubBitmap( subrect ); - } - else - { - // in this case we'd probably have to adjust the different coordinates, but - // we have to find out proper contract first - blit = wxNullBitmap; - } - } - else + if ( !useMask && blit.GetMask() ) + blit.SetMask(NULL); + + double x = xdest; + double y = ydest; + double w = dstWidth; + double h = dstHeight; + // adjust dest rect if source rect is clipped + if (subrect.width != subrectOrig.width || subrect.height != subrectOrig.height) { - blit = wxNullBitmap; + x += (subrect.x - subrectOrig.x) / double(subrectOrig.width) * dstWidth; + y += (subrect.y - subrectOrig.y) / double(subrectOrig.height) * dstHeight; + w *= double(subrect.width) / subrectOrig.width; + h *= double(subrect.height) / subrectOrig.height; } + m_graphicContext->DrawBitmap(blit, x, y, w, h); + } + else + { + wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); + retval = false; } - if ( blit.Ok() ) + if (mode == wxCOMPOSITION_XOR) { - m_graphicContext->DrawBitmap( blit, xxdest , yydest , wwdest , hhdest ); + m_graphicContext->SetAntialiasMode(formerAa); } } - else - { - wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts, and only with wxCOPY logical operation.") ); - return false; - } + // reset composition + m_graphicContext->SetCompositionMode(formerMode); - return true; + return retval; } -void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, +void wxGCDCImpl::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, double angle) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - if ( str.length() == 0 ) + if ( str.empty() ) return; - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - int drawX = LogicalToDeviceX(x); - int drawY = LogicalToDeviceY(y); - - m_graphicContext->DrawText( str, drawX ,drawY , DegToRad(angle )); + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); + else + m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); } -void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) +void wxGCDCImpl::DoDrawText(const wxString& str, wxCoord x, wxCoord y) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - - if ( str.length() == 0 ) + // For compatibility with other ports (notably wxGTK) and because it's + // genuinely useful, we allow passing multiline strings to DrawText(). + // However there is no native OSX function to draw them directly so we + // instead reuse the generic DrawLabel() method to render them. Of course, + // DrawLabel() itself will call back to us but with single line strings + // only so there won't be any infinite recursion here. + if ( str.find('\n') != wxString::npos ) + { + GetOwner()->DrawLabel(str, wxRect(x, y, 0, 0)); return; - if ( m_logicalFunction != wxCOPY ) + } + + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawText - invalid DC") ); + + if ( str.empty() ) return; - int drawX = LogicalToDeviceX(x); - int drawY = LogicalToDeviceY(y); + if ( !m_logicalFunctionSupported ) + return; - m_graphicContext->DrawText( str, drawX ,drawY); + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y); + else + m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); } -bool wxGCDC::CanGetTextExtent() const +bool wxGCDCImpl::CanGetTextExtent() const { - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); + wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); return true; } -void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, +void wxGCDCImpl::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, wxCoord *descent, wxCoord *externalLeading , - wxFont *theFont ) const + const wxFont *theFont ) const { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); + wxCHECK_RET( m_graphicContext, wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); if ( theFont ) { @@ -974,13 +976,13 @@ void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *heig m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); if ( height ) - *height = DeviceToLogicalYRel((wxCoord)h); + *height = (wxCoord)(h+0.5); if ( descent ) - *descent = DeviceToLogicalYRel((wxCoord)d); + *descent = (wxCoord)(d+0.5); if ( externalLeading ) - *externalLeading = DeviceToLogicalYRel((wxCoord)e); + *externalLeading = (wxCoord)(e+0.5); if ( width ) - *width = DeviceToLogicalXRel((wxCoord)w); + *width = (wxCoord)(w+0.5); if ( theFont ) { @@ -988,9 +990,9 @@ void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *heig } } -bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +bool wxGCDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const { - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); + wxCHECK_MSG( m_graphicContext, false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); widths.Clear(); widths.Add(0,text.Length()); if ( text.IsEmpty() ) @@ -1000,12 +1002,12 @@ bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) c m_graphicContext->GetPartialTextExtents( text, widthsD ); for ( size_t i = 0; i < widths.GetCount(); ++i ) - widths[i] = DeviceToLogicalXRel((wxCoord)(widthsD[i] + 0.5)); + widths[i] = (wxCoord)(widthsD[i] + 0.5); return true; } -wxCoord wxGCDC::GetCharWidth(void) const +wxCoord wxGCDCImpl::GetCharWidth(void) const { wxCoord width; DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ); @@ -1013,7 +1015,7 @@ wxCoord wxGCDC::GetCharWidth(void) const return width; } -wxCoord wxGCDC::GetCharHeight(void) const +wxCoord wxGCDCImpl::GetCharHeight(void) const { wxCoord height; DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ); @@ -1021,25 +1023,36 @@ wxCoord wxGCDC::GetCharHeight(void) const return height; } -void wxGCDC::Clear(void) +void wxGCDCImpl::Clear(void) { - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") ); + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::Clear - invalid DC") ); // TODO better implementation / incorporate size info into wxGCDC or context m_graphicContext->SetBrush( m_backgroundBrush ); wxPen p = *wxTRANSPARENT_PEN; m_graphicContext->SetPen( p ); - DoDrawRectangle( 0, 0, 32000 , 32000 ); - m_graphicContext->SetPen( m_pen ); + wxCompositionMode formerMode = m_graphicContext->GetCompositionMode(); + m_graphicContext->SetCompositionMode(wxCOMPOSITION_SOURCE); + // maximum positive coordinate Cairo can handle is 2^23 - 1 + DoDrawRectangle( + DeviceToLogicalX(0), DeviceToLogicalY(0), + DeviceToLogicalXRel(0x007fffff), DeviceToLogicalYRel(0x007fffff)); + m_graphicContext->SetCompositionMode(formerMode); + m_graphicContext->SetPen( m_pen ); m_graphicContext->SetBrush( m_brush ); } -void wxGCDC::DoGetSize(int *width, int *height) const +void wxGCDCImpl::DoGetSize(int *width, int *height) const { - *width = 1000; - *height = 1000; + wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoGetSize - invalid DC") ); + wxDouble w,h; + m_graphicContext->GetSize( &w, &h ); + if ( height ) + *height = (int) (h+0.5); + if ( width ) + *width = (int) (w+0.5); } -void wxGCDC::DoGradientFillLinear(const wxRect& rect, +void wxGCDCImpl::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection ) @@ -1072,35 +1085,18 @@ void wxGCDC::DoGradientFillLinear(const wxRect& rect, break; } - m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( - LogicalToDeviceX(start.x),LogicalToDeviceY(start.y), - LogicalToDeviceX(end.x),LogicalToDeviceY(end.y), initialColour, destColour)); - - wxDouble xx = LogicalToDeviceX(rect.x); - wxDouble yy = LogicalToDeviceY(rect.y); - wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width); - wxDouble hh = m_signY * LogicalToDeviceYRel(rect.height); - - if (ww == 0 || hh == 0) + if (rect.width == 0 || rect.height == 0) return; - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - + m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( + start.x,start.y,end.x,end.y, initialColour, destColour)); m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->DrawRectangle(xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetPen(m_pen); + m_graphicContext->SetBrush(m_brush); } -void wxGCDC::DoGradientFillConcentric(const wxRect& rect, +void wxGCDCImpl::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter) @@ -1114,43 +1110,42 @@ void wxGCDC::DoGradientFillConcentric(const wxRect& rect, else nRadius = cy; - wxDouble xx = LogicalToDeviceX(rect.x); - wxDouble yy = LogicalToDeviceY(rect.y); - wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width); - wxDouble hh = m_signY * LogicalToDeviceYRel(rect.height); - - if (ww == 0 || hh == 0) - return; - - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - + // make sure the background is filled (todo move into specific platform implementation ?) m_graphicContext->SetPen(*wxTRANSPARENT_PEN); m_graphicContext->SetBrush( wxBrush( destColour) ); - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( - xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y), - xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y), - LogicalToDeviceXRel(nRadius), - initialColour,destColour)); + rect.x+circleCenter.x,rect.y+circleCenter.y, + rect.x+circleCenter.x,rect.y+circleCenter.y, + nRadius,initialColour,destColour)); - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetPen(m_pen); + m_graphicContext->SetBrush(m_brush); } -void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y, +void wxGCDCImpl::DoDrawCheckMark(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { - wxDCBase::DoDrawCheckMark(x,y,width,height); + wxDCImpl::DoDrawCheckMark(x,y,width,height); +} + +#ifdef __WXMSW__ +wxRect wxGCDCImpl::MSWApplyGDIPlusTransform(const wxRect& r) const +{ + wxGraphicsContext* const gc = GetGraphicsContext(); + wxCHECK_MSG( gc, r, wxT("Invalid wxGCDC") ); + + double x = 0, + y = 0; + gc->GetTransform().TransformPoint(&x, &y); + + wxRect rect(r); + rect.Offset(x, y); + + return rect; } +#endif // __WXMSW__ #endif // wxUSE_GRAPHICS_CONTEXT