wxwidgets/src/mac/carbon/dc.cpp
Robert Roebling 621b83d9b3 Made device to logical and vv conversion methods
virtual and implement them like any other method
    in the wxDC classes, not only in the their files
    but somehow belonging to the wxDCBase class.
  This is required for plugging in differnt DC backends
    with different conversions.
  Ideally (and absolutely possible ) all these methods
    should be removed and just the one in wxDCBase
    should stay using values set in the various
    derived classes.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45741 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2007-05-01 21:28:29 +00:00

2293 lines
65 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/carbon/dc.cpp
// Purpose: wxDC class
// Author: Stefan Csomor
// Modified by:
// Created: 01/02/97
// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#include "wx/dc.h"
#if !wxMAC_USE_CORE_GRAPHICS
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/app.h"
#include "wx/dcmemory.h"
#include "wx/dcprint.h"
#include "wx/region.h"
#include "wx/image.h"
#endif
#include "wx/mac/uma.h"
#ifdef __MSL__
#if __MSL__ >= 0x6000
namespace std {}
using namespace std ;
#endif
#endif
#include "wx/mac/private.h"
#ifndef __DARWIN__
#include <ATSUnicode.h>
#include <TextCommon.h>
#include <TextEncodingConverter.h>
#endif
// set to 0 if problems arise
#define wxMAC_EXPERIMENTAL_DC 1
IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
//-----------------------------------------------------------------------------
// constants
//-----------------------------------------------------------------------------
const double RAD2DEG = 180.0 / M_PI;
const short kEmulatedMode = -1 ;
const short kUnsupportedMode = -2 ;
wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
m_ph( (GrafPtr) dc->m_macPort )
{
wxASSERT( dc->Ok() ) ;
m_dc = dc ;
dc->MacSetupPort(&m_ph) ;
}
wxMacPortSetter::~wxMacPortSetter()
{
m_dc->MacCleanupPort(&m_ph) ;
}
#if wxMAC_EXPERIMENTAL_DC
class wxMacFastPortSetter
{
public :
wxMacFastPortSetter( const wxDC *dc )
{
wxASSERT( dc->Ok() ) ;
m_swapped = QDSwapPort( (GrafPtr) dc->m_macPort , &m_oldPort ) ;
m_clipRgn = NewRgn() ;
GetClip( m_clipRgn ) ;
m_dc = dc ;
dc->MacSetupPort( NULL ) ;
}
~wxMacFastPortSetter()
{
// SetPort( (GrafPtr) m_dc->m_macPort ) ;
SetClip( m_clipRgn ) ;
if ( m_swapped )
SetPort( m_oldPort ) ;
m_dc->MacCleanupPort( NULL ) ;
DisposeRgn( m_clipRgn ) ;
}
private :
bool m_swapped ;
RgnHandle m_clipRgn ;
GrafPtr m_oldPort ;
const wxDC* m_dc ;
} ;
#else
typedef wxMacPortSetter wxMacFastPortSetter ;
#endif
wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
wxMacPortSaver( (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) )
{
m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
m_formerClip = NewRgn() ;
m_newClip = NewRgn() ;
GetClip( m_formerClip ) ;
if ( win )
{
// guard against half constructed objects, this just leads to a empty clip
if ( win->GetPeer() )
{
int x = 0 , y = 0;
win->MacWindowToRootWindow( &x, &y ) ;
// get area including focus rect
CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
if ( !EmptyRgn( m_newClip ) )
OffsetRgn( m_newClip , x , y ) ;
}
SetClip( m_newClip ) ;
}
}
wxMacWindowClipper::~wxMacWindowClipper()
{
SetPort( m_newPort ) ;
SetClip( m_formerClip ) ;
DisposeRgn( m_newClip ) ;
DisposeRgn( m_formerClip ) ;
}
wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
wxMacWindowClipper( win )
{
// the port is already set at this point
m_newPort = (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
GetThemeDrawingState( &m_themeDrawingState ) ;
}
wxMacWindowStateSaver::~wxMacWindowStateSaver()
{
SetPort( m_newPort ) ;
SetThemeDrawingState( m_themeDrawingState , true ) ;
}
//-----------------------------------------------------------------------------
// wxDC
//-----------------------------------------------------------------------------
// this function emulates all wx colour manipulations, used to verify the implementation
// by setting the mode in the blitting functions to kEmulatedMode
void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor ) ;
void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor )
{
switch ( logical_func )
{
case wxAND: // src AND dst
dstColor.red = dstColor.red & srcColor.red ;
dstColor.green = dstColor.green & srcColor.green ;
dstColor.blue = dstColor.blue & srcColor.blue ;
break ;
case wxAND_INVERT: // (NOT src) AND dst
dstColor.red = dstColor.red & ~srcColor.red ;
dstColor.green = dstColor.green & ~srcColor.green ;
dstColor.blue = dstColor.blue & ~srcColor.blue ;
break ;
case wxAND_REVERSE:// src AND (NOT dst)
dstColor.red = ~dstColor.red & srcColor.red ;
dstColor.green = ~dstColor.green & srcColor.green ;
dstColor.blue = ~dstColor.blue & srcColor.blue ;
break ;
case wxCLEAR: // 0
dstColor.red = 0 ;
dstColor.green = 0 ;
dstColor.blue = 0 ;
break ;
case wxCOPY: // src
dstColor.red = srcColor.red ;
dstColor.green = srcColor.green ;
dstColor.blue = srcColor.blue ;
break ;
case wxEQUIV: // (NOT src) XOR dst
dstColor.red = dstColor.red ^ ~srcColor.red ;
dstColor.green = dstColor.green ^ ~srcColor.green ;
dstColor.blue = dstColor.blue ^ ~srcColor.blue ;
break ;
case wxINVERT: // NOT dst
dstColor.red = ~dstColor.red ;
dstColor.green = ~dstColor.green ;
dstColor.blue = ~dstColor.blue ;
break ;
case wxNAND: // (NOT src) OR (NOT dst)
dstColor.red = ~dstColor.red | ~srcColor.red ;
dstColor.green = ~dstColor.green | ~srcColor.green ;
dstColor.blue = ~dstColor.blue | ~srcColor.blue ;
break ;
case wxNOR: // (NOT src) AND (NOT dst)
dstColor.red = ~dstColor.red & ~srcColor.red ;
dstColor.green = ~dstColor.green & ~srcColor.green ;
dstColor.blue = ~dstColor.blue & ~srcColor.blue ;
break ;
case wxOR: // src OR dst
dstColor.red = dstColor.red | srcColor.red ;
dstColor.green = dstColor.green | srcColor.green ;
dstColor.blue = dstColor.blue | srcColor.blue ;
break ;
case wxOR_INVERT: // (NOT src) OR dst
dstColor.red = dstColor.red | ~srcColor.red ;
dstColor.green = dstColor.green | ~srcColor.green ;
dstColor.blue = dstColor.blue | ~srcColor.blue ;
break ;
case wxOR_REVERSE: // src OR (NOT dst)
dstColor.red = ~dstColor.red | srcColor.red ;
dstColor.green = ~dstColor.green | srcColor.green ;
dstColor.blue = ~dstColor.blue | srcColor.blue ;
break ;
case wxSET: // 1
dstColor.red = 0xFFFF ;
dstColor.green = 0xFFFF ;
dstColor.blue = 0xFFFF ;
break ;
case wxSRC_INVERT: // (NOT src)
dstColor.red = ~srcColor.red ;
dstColor.green = ~srcColor.green ;
dstColor.blue = ~srcColor.blue ;
break ;
case wxXOR: // src XOR dst
dstColor.red = dstColor.red ^ srcColor.red ;
dstColor.green = dstColor.green ^ srcColor.green ;
dstColor.blue = dstColor.blue ^ srcColor.blue ;
break ;
case wxNO_OP: // dst
default:
break ;
}
}
wxDC::wxDC()
{
m_ok = false;
m_colour = true;
m_mm_to_pix_x = mm2pt;
m_mm_to_pix_y = mm2pt;
m_internalDeviceOriginX = 0;
m_internalDeviceOriginY = 0;
m_externalDeviceOriginX = 0;
m_externalDeviceOriginY = 0;
m_logicalScaleX = 1.0;
m_logicalScaleY = 1.0;
m_userScaleX = 1.0;
m_userScaleY = 1.0;
m_scaleX = 1.0;
m_scaleY = 1.0;
m_needComputeScaleX = false;
m_needComputeScaleY = false;
m_macPort = NULL ;
m_macMask = NULL ;
m_macFontInstalled = false ;
m_macBrushInstalled = false ;
m_macPenInstalled = false ;
m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
m_macBoundaryClipRgn = NewRgn() ;
m_macCurrentClipRgn = NewRgn() ;
SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , -32000 , -32000 , 32000 , 32000 ) ;
SetRectRgn( (RgnHandle) m_macCurrentClipRgn , -32000 , -32000 , 32000 , 32000 ) ;
m_pen = *wxBLACK_PEN;
m_font = *wxNORMAL_FONT;
m_brush = *wxWHITE_BRUSH;
#ifdef __WXDEBUG__
// needed to debug possible errors with two active drawing methods at the same time on
// the same DC
m_macCurrentPortStateHelper = NULL ;
#endif
m_macATSUIStyle = NULL ;
m_macAliasWasEnabled = false;
m_macForegroundPixMap = NULL ;
m_macBackgroundPixMap = NULL ;
}
wxDC::~wxDC(void)
{
DisposeRgn( (RgnHandle) m_macBoundaryClipRgn ) ;
DisposeRgn( (RgnHandle) m_macCurrentClipRgn ) ;
}
void wxDC::MacSetupPort(wxMacPortStateHelper* help) const
{
#ifdef __WXDEBUG__
wxASSERT( m_macCurrentPortStateHelper == NULL ) ;
m_macCurrentPortStateHelper = help ;
#endif
SetClip( (RgnHandle) m_macCurrentClipRgn);
#if ! wxMAC_EXPERIMENTAL_DC
m_macFontInstalled = false ;
m_macBrushInstalled = false ;
m_macPenInstalled = false ;
#endif
}
void wxDC::MacCleanupPort(wxMacPortStateHelper* help) const
{
#ifdef __WXDEBUG__
wxASSERT( m_macCurrentPortStateHelper == help ) ;
m_macCurrentPortStateHelper = NULL ;
#endif
if ( m_macATSUIStyle )
{
::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
m_macATSUIStyle = NULL ;
}
if ( m_macAliasWasEnabled )
{
SetAntiAliasedTextEnabled(m_macFormerAliasState, m_macFormerAliasSize);
m_macAliasWasEnabled = false ;
}
if ( m_macForegroundPixMap )
{
Pattern blackColor ;
::PenPat(GetQDGlobalsBlack(&blackColor));
DisposePixPat( (PixPatHandle) m_macForegroundPixMap ) ;
m_macForegroundPixMap = NULL ;
}
if ( m_macBackgroundPixMap )
{
Pattern whiteColor ;
::BackPat(GetQDGlobalsWhite(&whiteColor));
DisposePixPat( (PixPatHandle) m_macBackgroundPixMap ) ;
m_macBackgroundPixMap = NULL ;
}
}
void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
{
wxCHECK_RET( Ok(), wxT("wxDC::DoDrawBitmap - invalid DC") );
wxCHECK_RET( bmp.Ok(), wxT("wxDC::DoDrawBitmap - invalid bitmap") );
wxMacFastPortSetter helper(this) ;
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord w = bmp.GetWidth();
wxCoord h = bmp.GetHeight();
wxCoord ww = XLOG2DEVREL(w);
wxCoord hh = YLOG2DEVREL(h);
// Set up drawing mode
short mode = (m_logicalFunction == wxCOPY ? srcCopy :
//m_logicalFunction == wxCLEAR ? WHITENESS :
//m_logicalFunction == wxSET ? BLACKNESS :
m_logicalFunction == wxINVERT ? hilite :
//m_logicalFunction == wxAND ? MERGECOPY :
m_logicalFunction == wxOR ? srcOr :
m_logicalFunction == wxSRC_INVERT ? notSrcCopy :
m_logicalFunction == wxXOR ? srcXor :
m_logicalFunction == wxOR_REVERSE ? notSrcOr :
//m_logicalFunction == wxAND_REVERSE ? SRCERASE :
//m_logicalFunction == wxSRC_OR ? srcOr :
//m_logicalFunction == wxSRC_AND ? SRCAND :
srcCopy );
GWorldPtr maskworld = NULL ;
GWorldPtr bmapworld = MAC_WXHBITMAP( bmp.GetHBITMAP((WXHBITMAP*)&maskworld) );
PixMapHandle bmappixels ;
// Set foreground and background colours (for bitmaps depth = 1)
if (bmp.GetDepth() == 1)
{
RGBColor fore = MAC_WXCOLORREF(m_textForegroundColour.GetPixel());
RGBColor back = MAC_WXCOLORREF(m_textBackgroundColour.GetPixel());
RGBForeColor(&fore);
RGBBackColor(&back);
}
else
{
RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF } ;
RGBColor black = { 0, 0, 0 } ;
RGBForeColor( &black ) ;
RGBBackColor( &white ) ;
}
bmappixels = GetGWorldPixMap( bmapworld ) ;
wxCHECK_RET(LockPixels(bmappixels),
wxT("wxDC::DoDrawBitmap - failed to lock pixels"));
Rect source = { 0, 0, h, w };
Rect dest = { yy, xx, yy + hh, xx + ww };
if ( useMask && maskworld )
{
if ( LockPixels(GetGWorldPixMap(MAC_WXHBITMAP(maskworld))))
{
CopyDeepMask
(
GetPortBitMapForCopyBits(bmapworld),
GetPortBitMapForCopyBits(MAC_WXHBITMAP(maskworld)),
GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ),
&source, &source, &dest, mode, NULL
);
UnlockPixels(GetGWorldPixMap(MAC_WXHBITMAP(maskworld)));
}
}
else
{
CopyBits( GetPortBitMapForCopyBits( bmapworld ),
GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ),
&source, &dest, mode, NULL ) ;
}
UnlockPixels( bmappixels ) ;
m_macPenInstalled = false ;
m_macBrushInstalled = false ;
m_macFontInstalled = false ;
}
void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawIcon - invalid DC"));
wxCHECK_RET(icon.Ok(), wxT("wxDC::DoDrawIcon - invalid icon"));
wxMacFastPortSetter helper(this) ;
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord w = icon.GetWidth();
wxCoord h = icon.GetHeight();
wxCoord ww = XLOG2DEVREL(w);
wxCoord hh = YLOG2DEVREL(h);
Rect r = { yy , xx, yy + hh, xx + ww } ;
PlotIconRef( &r , kAlignNone , kTransformNone , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
}
void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion - invalid DC"));
wxCoord xx, yy, ww, hh;
xx = XLOG2DEVMAC(x);
yy = YLOG2DEVMAC(y);
ww = XLOG2DEVREL(width);
hh = YLOG2DEVREL(height);
SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
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_clipX1 = xx;
m_clipY1 = yy;
m_clipX2 = xx + ww;
m_clipY2 = yy + hh;
}
}
void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegionAsRegion - invalid DC"));
wxMacFastPortSetter helper(this) ;
wxCoord x, y, w, h;
region.GetBox( x, y, w, h );
wxCoord xx, yy, ww, hh;
xx = XLOG2DEVMAC(x);
yy = YLOG2DEVMAC(y);
ww = XLOG2DEVREL(w);
hh = YLOG2DEVREL(h);
// if we have a scaling that we cannot map onto native regions
// we must use the box
if ( ww != w || hh != h )
{
wxDC::DoSetClippingRegion( x, y, w, h );
}
else
{
CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
if ( xx != x || yy != y )
OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
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_clipX1 = xx;
m_clipY1 = yy;
m_clipX2 = xx + ww;
m_clipY2 = yy + hh;
}
}
}
void wxDC::DestroyClippingRegion()
{
wxMacFastPortSetter helper(this) ;
CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
ResetClipping();
}
void wxDC::DoGetSizeMM( int* width, int* height ) const
{
int w = 0, h = 0;
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 wxDC::SetTextForeground( const wxColour &col )
{
wxCHECK_RET(Ok(), wxT("wxDC::SetTextForeground - invalid DC"));
m_textForegroundColour = col;
m_macFontInstalled = false ;
}
void wxDC::SetTextBackground( const wxColour &col )
{
wxCHECK_RET(Ok(), wxT("wxDC::SetTextBackground - invalid DC"));
m_textBackgroundColour = col;
m_macFontInstalled = false ;
}
void wxDC::SetMapMode( int mode )
{
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;
default:
case wxMM_TEXT:
SetLogicalScale( 1.0, 1.0 );
break;
}
if (mode != wxMM_TEXT)
{
m_needComputeScaleX = true;
m_needComputeScaleY = true;
}
}
void wxDC::SetUserScale( double x, double y )
{
// allow negative ? -> no
m_userScaleX = x;
m_userScaleY = y;
ComputeScaleAndOrigin();
}
void wxDC::SetLogicalScale( double x, double y )
{
// allow negative ?
m_logicalScaleX = x;
m_logicalScaleY = y;
ComputeScaleAndOrigin();
}
void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
{
// is this still correct ?
m_logicalOriginX = x * m_signX;
m_logicalOriginY = y * m_signY;
ComputeScaleAndOrigin();
}
void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
{
m_externalDeviceOriginX = x;
m_externalDeviceOriginY = y;
ComputeScaleAndOrigin();
}
void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
{
m_signX = (xLeftRight ? 1 : -1);
m_signY = (yBottomUp ? -1 : 1);
ComputeScaleAndOrigin();
}
wxSize wxDC::GetPPI() const
{
return wxSize(72, 72);
}
int wxDC::GetDepth() const
{
if ( IsPortColor( (CGrafPtr) m_macPort ) )
return ( (**GetPortPixMap( (CGrafPtr) m_macPort)).pixelSize ) ;
return 1 ;
}
void wxDC::ComputeScaleAndOrigin()
{
// 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_internalDeviceOriginX + m_externalDeviceOriginX;
m_deviceOriginY = m_internalDeviceOriginY + m_externalDeviceOriginY;
// 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);
}
}
void wxDC::SetPalette( const wxPalette& palette )
{
}
void wxDC::SetBackgroundMode( int mode )
{
m_backgroundMode = mode ;
}
void wxDC::SetFont( const wxFont &font )
{
m_font = font;
m_macFontInstalled = false ;
}
void wxDC::SetPen( const wxPen &pen )
{
if ( m_pen == pen )
return ;
m_pen = pen;
m_macPenInstalled = false ;
}
void wxDC::SetBrush( const wxBrush &brush )
{
if (m_brush == brush)
return;
m_brush = brush;
m_macBrushInstalled = false ;
}
void wxDC::SetBackground( const wxBrush &brush )
{
if (m_backgroundBrush == brush)
return;
m_backgroundBrush = brush;
if (m_backgroundBrush.Ok())
m_macBrushInstalled = false ;
}
void wxDC::SetLogicalFunction( int function )
{
if (m_logicalFunction == function)
return;
m_logicalFunction = function ;
m_macFontInstalled = false ;
m_macBrushInstalled = false ;
m_macPenInstalled = false ;
}
extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
const wxColour & col, int style);
bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
const wxColour& col, int style)
{
return wxDoFloodFill(this, x, y, col, style);
}
bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
{
wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel - invalid DC") );
wxMacFastPortSetter helper(this) ;
// NOTE: Get/SetCPixel are slow!
RGBColor colour;
GetCPixel( XLOG2DEVMAC(x), YLOG2DEVMAC(y), &colour );
// convert from Mac colour to wx
*col = colour;
return true ;
}
void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawLine - invalid DC"));
wxMacFastPortSetter helper(this) ;
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen() ;
wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 :
m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2;
wxCoord xx1 = XLOG2DEVMAC(x1) - offset;
wxCoord yy1 = YLOG2DEVMAC(y1) - offset;
wxCoord xx2 = XLOG2DEVMAC(x2) - offset;
wxCoord yy2 = YLOG2DEVMAC(y2) - offset;
if ((m_pen.GetCap() == wxCAP_ROUND) &&
(m_pen.GetWidth() <= 1))
{
// Implement LAST_NOT for MAC at least for
// orthogonal lines. RR.
if (xx1 == xx2)
{
if (yy1 < yy2)
yy2--;
if (yy1 > yy2)
yy2++;
}
if (yy1 == yy2)
{
if (xx1 < xx2)
xx2--;
if (xx1 > xx2)
xx2++;
}
}
::MoveTo(xx1, yy1);
::LineTo(xx2, yy2);
}
}
void wxDC::DoCrossHair( wxCoord x, wxCoord y )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoCrossHair - invalid DC"));
wxMacFastPortSetter helper(this) ;
if (m_pen.GetStyle() != wxTRANSPARENT)
{
int w = 0, h = 0;
GetSize( &w, &h );
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
MacInstallPen();
::MoveTo( XLOG2DEVMAC(0), yy );
::LineTo( XLOG2DEVMAC(w), yy );
::MoveTo( xx, YLOG2DEVMAC(0) );
::LineTo( xx, YLOG2DEVMAC(h) );
CalcBoundingBox(x, y);
CalcBoundingBox(x + w, y + h);
}
}
/*
* To draw arcs properly the angles need to be converted from the WX style:
* Angles start on the +ve X axis and go anti-clockwise (As you would draw on
* a normal axis on paper).
* TO
* the Mac style:
* Angles start on the +ve y axis and go clockwise.
*/
static double wxConvertWXangleToMACangle(double angle)
{
double newAngle = 90 - angle ;
while ( newAngle > 360 )
newAngle -= 360 ;
while ( newAngle < 0 )
newAngle += 360 ;
return newAngle ;
}
void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
wxCoord x2, wxCoord y2,
wxCoord xc, wxCoord yc )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc - invalid DC"));
wxMacFastPortSetter helper(this) ;
wxCoord xx1 = XLOG2DEVMAC(x1);
wxCoord yy1 = YLOG2DEVMAC(y1);
wxCoord xx2 = XLOG2DEVMAC(x2);
wxCoord yy2 = YLOG2DEVMAC(y2);
wxCoord xxc = XLOG2DEVMAC(xc);
wxCoord yyc = YLOG2DEVMAC(yc);
double dx = xx1 - xxc;
double dy = yy1 - yyc;
double radius = sqrt((double)(dx * dx + dy * dy));
wxCoord rad = (wxCoord)radius;
double radius1, radius2;
if (xx1 == xx2 && yy1 == yy2)
{
radius1 = 0.0;
radius2 = 360.0;
}
else if (radius == 0.0)
{
radius1 = radius2 = 0.0;
}
else
{
radius1 = (xx1 - xxc == 0) ?
(yy1 - yyc < 0) ? 90.0 : -90.0 :
-atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG;
radius2 = (xx2 - xxc == 0) ?
(yy2 - yyc < 0) ? 90.0 : -90.0 :
-atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG;
}
wxCoord alpha2 = wxCoord(radius2 - radius1);
wxCoord alpha1 = wxCoord(wxConvertWXangleToMACangle(radius1));
while ( alpha2 < 0 )
alpha2 += 360 ;
alpha2 = -alpha2 ;
Rect r = { yyc - rad, xxc - rad, yyc + rad, xxc + rad };
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush();
PaintArc(&r, alpha1, alpha2);
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen();
FrameArc(&r, alpha1, alpha2);
}
}
void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
double sa, double ea )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc - invalid DC"));
wxMacFastPortSetter helper(this) ;
Rect r;
// Order important Mac in opposite direction to wx
// we have to make sure that the filling is always counter-clockwise
double angle = sa - ea;
if ( angle > 0 )
angle -= 360 ;
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord ww = m_signX * XLOG2DEVREL(w);
wxCoord hh = m_signY * YLOG2DEVREL(h);
// handle -ve width and/or height
if (ww < 0)
{
ww = -ww;
xx = xx - ww;
}
if (hh < 0)
{
hh = -hh;
yy = yy - hh;
}
sa = wxConvertWXangleToMACangle(sa);
r.top = yy;
r.left = xx;
r.bottom = yy + hh;
r.right = xx + ww;
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush();
PaintArc(&r, (short)sa, (short)angle);
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen();
FrameArc(&r, (short)sa, (short)angle);
}
}
void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawPoint - invalid DC"));
wxMacFastPortSetter helper(this) ;
if (m_pen.GetStyle() != wxTRANSPARENT)
{
wxCoord xx1 = XLOG2DEVMAC(x);
wxCoord yy1 = YLOG2DEVMAC(y);
RGBColor pencolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel());
// NOTE: Get/SetCPixel are slow!
::SetCPixel( xx1, yy1, &pencolor) ;
CalcBoundingBox(x, y);
}
}
void wxDC::DoDrawLines(int n, wxPoint points[],
wxCoord xoffset, wxCoord yoffset)
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawLines - invalid DC"));
if (m_pen.GetStyle() == wxTRANSPARENT)
return;
wxMacFastPortSetter helper(this) ;
MacInstallPen() ;
wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 :
m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2 ;
wxCoord x1, x2 , y1 , y2 ;
x1 = XLOG2DEVMAC(points[0].x + xoffset);
y1 = YLOG2DEVMAC(points[0].y + yoffset);
::MoveTo( x1 - offset, y1 - offset );
for (int i = 0; i < n-1; i++)
{
x2 = XLOG2DEVMAC(points[i + 1].x + xoffset);
y2 = YLOG2DEVMAC(points[i + 1].y + yoffset);
::LineTo( x2 - offset, y2 - offset );
}
}
void wxDC::DoDrawPolygon(int n, wxPoint points[],
wxCoord xoffset, wxCoord yoffset,
int fillStyle )
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawPolygon - invalid DC"));
if ( m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT )
return ;
wxMacFastPortSetter helper(this) ;
wxCoord x1, x2 , y1 , y2 ;
PolyHandle polygon = OpenPoly();
x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
::MoveTo(x1, y1);
for (int i = 1; i < n; i++)
{
x2 = XLOG2DEVMAC(points[i].x + xoffset);
y2 = YLOG2DEVMAC(points[i].y + yoffset);
::LineTo(x2, y2);
}
// close the polyline if necessary
if ( x1 != x2 || y1 != y2 )
::LineTo( x1, y1 ) ;
ClosePoly();
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush();
::PaintPoly( polygon );
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen() ;
::FramePoly( polygon ) ;
}
KillPoly( polygon );
}
void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawRectangle - invalid DC"));
wxMacFastPortSetter helper(this) ;
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord ww = m_signX * XLOG2DEVREL(width);
wxCoord hh = m_signY * YLOG2DEVREL(height);
// CMB: draw nothing if transformed w or h is 0
if (ww == 0 || hh == 0)
return;
// CMB: handle -ve width and/or height
if (ww < 0)
{
ww = -ww;
xx = xx - ww;
}
if (hh < 0)
{
hh = -hh;
yy = yy - hh;
}
Rect rect = { yy , xx , yy + hh , xx + ww } ;
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush() ;
::PaintRect( &rect ) ;
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen() ;
::FrameRect( &rect ) ;
}
}
void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
wxCoord width, wxCoord height,
double radius)
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawRoundedRectangle - invalid DC"));
wxMacFastPortSetter helper(this) ;
if (radius < 0.0)
radius = - radius * ((width < height) ? width : height);
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord ww = m_signX * XLOG2DEVREL(width);
wxCoord hh = m_signY * YLOG2DEVREL(height);
// CMB: draw nothing if transformed w or h is 0
if (ww == 0 || hh == 0)
return;
// CMB: handle -ve width and/or height
if (ww < 0)
{
ww = -ww;
xx = xx - ww;
}
if (hh < 0)
{
hh = -hh;
yy = yy - hh;
}
Rect rect = { yy , xx , yy + hh , xx + ww } ;
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush() ;
::PaintRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ;
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen() ;
::FrameRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ;
}
}
void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{
wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllipse - invalid DC"));
wxMacFastPortSetter helper(this) ;
wxCoord xx = XLOG2DEVMAC(x);
wxCoord yy = YLOG2DEVMAC(y);
wxCoord ww = m_signX * XLOG2DEVREL(width);
wxCoord hh = m_signY * YLOG2DEVREL(height);
// CMB: draw nothing if transformed w or h is 0
if (ww == 0 || hh == 0)
return;
// CMB: handle -ve width and/or height
if (ww < 0)
{
ww = -ww;
xx = xx - ww;
}
if (hh < 0)
{
hh = -hh;
yy = yy - hh;
}
Rect rect = { yy , xx , yy + hh , xx + ww } ;
if (m_brush.GetStyle() != wxTRANSPARENT)
{
MacInstallBrush() ;
::PaintOval( &rect ) ;
}
if (m_pen.GetStyle() != wxTRANSPARENT)
{
MacInstallPen() ;
::FrameOval( &rect ) ;
}
}
bool wxDC::CanDrawBitmap(void) const
{
return true ;
}
bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight,
wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
wxCoord xsrcMask, wxCoord ysrcMask )
{
return DoStretchBlit( xdest, ydest, dstWidth, dstHeight,
source, xsrc, ysrc, dstWidth, dstHeight,
logical_func, useMask,
xsrcMask, ysrcMask );
}
bool wxDC::DoStretchBlit(wxCoord xdest, wxCoord ydest,
wxCoord dstWidth, wxCoord dstHeight,
wxDC *source,
wxCoord xsrc, wxCoord ysrc,
wxCoord srcWidth, wxCoord srcHeight,
int logical_func, bool useMask,
wxCoord xsrcMask, wxCoord ysrcMask)
{
wxCHECK_MSG(Ok(), false, wxT("wxDC::DoStretchBlit - invalid DC"));
wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoStretchBlit - invalid source DC"));
if ( logical_func == wxNO_OP )
return true ;
if (xsrcMask == -1 && ysrcMask == -1)
{
xsrcMask = xsrc;
ysrcMask = ysrc;
}
// correct the parameter in case this dc does not have a mask at all
if ( useMask && !source->m_macMask )
useMask = false ;
Rect srcrect , dstrect ;
srcrect.top = source->YLOG2DEVMAC(ysrc) ;
srcrect.left = source->XLOG2DEVMAC(xsrc) ;
srcrect.right = source->XLOG2DEVMAC(xsrc + srcWidth ) ;
srcrect.bottom = source->YLOG2DEVMAC(ysrc + srcHeight) ;
dstrect.top = YLOG2DEVMAC(ydest) ;
dstrect.left = XLOG2DEVMAC(xdest) ;
dstrect.bottom = YLOG2DEVMAC(ydest + dstHeight ) ;
dstrect.right = XLOG2DEVMAC(xdest + dstWidth ) ;
short mode = kUnsupportedMode ;
bool invertDestinationFirst = false ;
switch ( logical_func )
{
case wxAND: // src AND dst
mode = adMin ; // ok
break ;
case wxAND_INVERT: // (NOT src) AND dst
mode = notSrcOr ; // ok
break ;
case wxAND_REVERSE:// src AND (NOT dst)
invertDestinationFirst = true ;
mode = srcOr ;
break ;
case wxCLEAR: // 0
mode = kEmulatedMode ;
break ;
case wxCOPY: // src
mode = srcCopy ; // ok
break ;
case wxEQUIV: // (NOT src) XOR dst
mode = srcXor ; // ok
break ;
case wxINVERT: // NOT dst
mode = kEmulatedMode ; //or hilite ;
break ;
case wxNAND: // (NOT src) OR (NOT dst)
invertDestinationFirst = true ;
mode = srcBic ;
break ;
case wxNOR: // (NOT src) AND (NOT dst)
invertDestinationFirst = true ;
mode = notSrcOr ;
break ;
case wxNO_OP: // dst
mode = kEmulatedMode ; // this has already been handled upon entry
break ;
case wxOR: // src OR dst
mode = notSrcBic ;
break ;
case wxOR_INVERT: // (NOT src) OR dst
mode = srcBic ;
break ;
case wxOR_REVERSE: // src OR (NOT dst)
invertDestinationFirst = true ;
mode = notSrcBic ;
break ;
case wxSET: // 1
mode = kEmulatedMode ;
break ;
case wxSRC_INVERT: // (NOT src)
mode = notSrcCopy ; // ok
break ;
case wxXOR: // src XOR dst
mode = notSrcXor ; // ok
break ;
default :
break ;
}
if ( mode == kUnsupportedMode )
{
wxFAIL_MSG(wxT("unsupported blitting mode" ));
return false ;
}
CGrafPtr sourcePort = (CGrafPtr) source->m_macPort ;
PixMapHandle bmappixels = GetGWorldPixMap( sourcePort ) ;
if ( LockPixels(bmappixels) )
{
wxMacFastPortSetter helper(this) ;
if ( source->GetDepth() == 1 )
{
RGBForeColor( &MAC_WXCOLORREF(m_textForegroundColour.GetPixel()) ) ;
RGBBackColor( &MAC_WXCOLORREF(m_textBackgroundColour.GetPixel()) ) ;
}
else
{
// the modes need this, otherwise we'll end up having really nice colors...
RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF } ;
RGBColor black = { 0, 0, 0 } ;
RGBForeColor( &black ) ;
RGBBackColor( &white ) ;
}
if ( useMask && source->m_macMask )
{
if ( mode == srcCopy )
{
if ( LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) )
{
CopyMask( GetPortBitMapForCopyBits( sourcePort ) ,
GetPortBitMapForCopyBits( MAC_WXHBITMAP(source->m_macMask) ) ,
GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
&srcrect, &srcrect , &dstrect ) ;
UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
}
}
else
{
RgnHandle clipRgn = NewRgn() ;
LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
OffsetRgn( clipRgn , -srcrect.left + dstrect.left, -srcrect.top + dstrect.top ) ;
if ( mode == kEmulatedMode )
{
Pattern pat ;
::PenPat(GetQDGlobalsBlack(&pat));
if ( logical_func == wxSET )
{
RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ;
::RGBForeColor( &col ) ;
::PaintRgn( clipRgn ) ;
}
else if ( logical_func == wxCLEAR )
{
RGBColor col= { 0x0000, 0x0000, 0x0000 } ;
::RGBForeColor( &col ) ;
::PaintRgn( clipRgn ) ;
}
else if ( logical_func == wxINVERT )
{
MacInvertRgn( clipRgn ) ;
}
else
{
for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y )
{
for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x )
{
Point dstPoint = { dstrect.top + y , dstrect.left + x } ;
Point srcPoint = { srcrect.top + y , srcrect.left + x } ;
if ( PtInRgn( dstPoint , clipRgn ) )
{
RGBColor srcColor, dstColor ;
// NOTE: Get/SetCPixel are slow!
SetPort( (GrafPtr) sourcePort ) ;
GetCPixel( srcPoint.h , srcPoint.v , &srcColor ) ;
SetPort( (GrafPtr) m_macPort ) ;
GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
wxMacCalculateColour( logical_func , srcColor , dstColor ) ;
SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
}
}
}
}
}
else
{
if ( invertDestinationFirst )
MacInvertRgn( clipRgn ) ;
CopyBits( GetPortBitMapForCopyBits( sourcePort ) ,
GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
&srcrect, &dstrect, mode, clipRgn ) ;
}
DisposeRgn( clipRgn ) ;
}
}
else
{
RgnHandle clipRgn = NewRgn() ;
SetRectRgn( clipRgn , dstrect.left , dstrect.top , dstrect.right , dstrect.bottom ) ;
if ( mode == kEmulatedMode )
{
Pattern pat ;
::PenPat(GetQDGlobalsBlack(&pat));
if ( logical_func == wxSET )
{
RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ;
::RGBForeColor( &col ) ;
::PaintRgn( clipRgn ) ;
}
else if ( logical_func == wxCLEAR )
{
RGBColor col = { 0x0000, 0x0000, 0x0000 } ;
::RGBForeColor( &col ) ;
::PaintRgn( clipRgn ) ;
}
else if ( logical_func == wxINVERT )
{
MacInvertRgn( clipRgn ) ;
}
else
{
for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y )
{
for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x )
{
Point dstPoint = { dstrect.top + y , dstrect.left + x } ;
Point srcPoint = { srcrect.top + y , srcrect.left + x } ;
{
RGBColor srcColor, dstColor ;
// NOTE: Get/SetCPixel are slow!
SetPort( (GrafPtr) sourcePort ) ;
GetCPixel( srcPoint.h , srcPoint.v , &srcColor) ;
SetPort( (GrafPtr) m_macPort ) ;
GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
wxMacCalculateColour( logical_func , srcColor , dstColor ) ;
SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
}
}
}
}
}
else
{
if ( invertDestinationFirst )
MacInvertRgn( clipRgn ) ;
CopyBits( GetPortBitMapForCopyBits( sourcePort ) ,
GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
&srcrect, &dstrect, mode, NULL ) ;
}
DisposeRgn( clipRgn ) ;
}
UnlockPixels( bmappixels ) ;
}
m_macPenInstalled = false ;
m_macBrushInstalled = false ;
m_macFontInstalled = false ;
return true;
}
void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
double angle)
{
wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText - invalid DC") );
if ( str.empty() )
return ;
wxMacFastPortSetter helper(this) ;
MacInstallFont() ;
OSStatus status = noErr ;
ATSUTextLayout atsuLayout ;
wxMacUniCharBuffer unibuf( str ) ;
UniCharCount chars = unibuf.GetChars() ;
status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
&chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
int iAngle = int( angle );
int drawX = XLOG2DEVMAC(x) ;
int drawY = YLOG2DEVMAC(y) ;
ATSUTextMeasurement textBefore, textAfter ;
ATSUTextMeasurement ascent, descent ;
ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
if (m_font.GetNoAntiAliasing())
{
layoutOptions |= kATSLineNoAntiAliasing ;
}
Fixed atsuAngle = IntToFixed( iAngle ) ;
ATSUAttributeTag atsuTags[] =
{
kATSULineLayoutOptionsTag ,
kATSULineRotationTag ,
} ;
ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
sizeof( ATSLineLayoutOptions ) ,
sizeof( Fixed ) ,
} ;
ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
&layoutOptions ,
&atsuAngle ,
} ;
status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) - ( abs(iAngle) > 0.001 ? 0 : 1),
atsuTags, atsuSizes, atsuValues ) ;
status = ::ATSUMeasureText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
&textBefore , &textAfter, &ascent , &descent );
wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
if ( m_backgroundMode == wxSOLID )
{
// background painting must be done by hand, cannot be done by ATSUI
wxCoord x2 , y2 ;
PolyHandle polygon = OpenPoly();
::MoveTo(drawX, drawY);
x2 = (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ;
y2 = (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) ;
::LineTo(x2, y2);
x2 = (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ;
y2 = (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ;
::LineTo(x2, y2);
x2 = (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ;
y2 = (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ;
::LineTo(x2, y2);
::LineTo( drawX, drawY) ;
ClosePoly();
::ErasePoly( polygon );
KillPoly( polygon );
}
drawX += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
drawY += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
IntToFixed(drawX) , IntToFixed(drawY) );
wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
Rect rect ;
status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
IntToFixed(drawX) , IntToFixed(drawY) , &rect );
wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
OffsetRect( &rect , -m_macLocalOrigin.x , -m_macLocalOrigin.y ) ;
CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
::ATSUDisposeTextLayout(atsuLayout);
}
void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
{
DoDrawRotatedText( strtext , x , y , 0) ;
}
bool wxDC::CanGetTextExtent() const
{
wxCHECK_MSG(Ok(), false, wxT("wxDC::CanGetTextExtent - invalid DC"));
return true ;
}
void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
wxCoord *descent, wxCoord *externalLeading ,
const wxFont *theFont ) const
{
wxCHECK_RET(Ok(), wxT("wxDC::DoGetTextExtent - invalid DC"));
wxMacFastPortSetter helper(this) ;
wxFont formerFont = m_font ;
if ( theFont )
{
// work around the constness
*((wxFont*)(&m_font)) = *theFont ;
}
MacInstallFont() ;
OSStatus status = noErr ;
ATSUTextLayout atsuLayout ;
wxMacUniCharBuffer unibuf( str ) ;
UniCharCount chars = unibuf.GetChars() ;
status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
&chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
if (m_font.GetNoAntiAliasing())
{
layoutOptions |= kATSLineNoAntiAliasing ;
}
ATSUAttributeTag atsuTags[] =
{
kATSULineLayoutOptionsTag ,
} ;
ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
sizeof( ATSLineLayoutOptions ) ,
} ;
ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
&layoutOptions ,
} ;
status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
atsuTags, atsuSizes, atsuValues ) ;
ATSUTextMeasurement textBefore, textAfter ;
ATSUTextMeasurement textAscent, textDescent ;
status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
&textBefore , &textAfter, &textAscent , &textDescent );
if ( height )
*height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
if ( descent )
*descent =YDEV2LOGREL( FixedToInt(textDescent) );
if ( externalLeading )
*externalLeading = 0 ;
if ( width )
*width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
::ATSUDisposeTextLayout(atsuLayout);
if ( theFont )
{
// work around the constness
*((wxFont*)(&m_font)) = formerFont ;
m_macFontInstalled = false ;
}
}
bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
{
wxCHECK_MSG(Ok(), false, wxT("wxDC::DoGetPartialTextExtents - invalid DC"));
widths.Empty();
widths.Add(0, text.length());
if (text.length() == 0)
return false;
wxMacFastPortSetter helper(this) ;
MacInstallFont() ;
OSStatus status = noErr ;
ATSUTextLayout atsuLayout ;
wxMacUniCharBuffer unibuf( text ) ;
UniCharCount chars = unibuf.GetChars() ;
status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
&chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
if (m_font.GetNoAntiAliasing())
{
layoutOptions |= kATSLineNoAntiAliasing ;
}
ATSUAttributeTag atsuTags[] =
{
kATSULineLayoutOptionsTag ,
} ;
ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
sizeof( ATSLineLayoutOptions ) ,
} ;
ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
&layoutOptions ,
} ;
status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
atsuTags, atsuSizes, atsuValues ) ;
for ( int pos = 0; pos < (int)chars ; pos ++ )
{
unsigned long actualNumberOfBounds = 0;
ATSTrapezoid glyphBounds;
// We get a single bound, since the text should only require one. If it requires more, there is an issue
OSStatus result;
result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
if (result != noErr || actualNumberOfBounds != 1 )
return false;
widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
}
::ATSUDisposeTextLayout(atsuLayout);
return true;
}
wxCoord wxDC::GetCharWidth(void) const
{
wxCoord width = 0 ;
DoGetTextExtent( wxT("g"), &width , NULL , NULL , NULL , NULL ) ;
return width ;
}
wxCoord wxDC::GetCharHeight(void) const
{
wxCoord height ;
DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
return height ;
}
void wxDC::Clear(void)
{
wxCHECK_RET(Ok(), wxT("wxDC::Clear - invalid DC"));
wxMacFastPortSetter helper(this) ;
Rect rect = { -31000 , -31000 , 31000 , 31000 } ;
if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
{
::PenNormal() ;
MacSetupBackgroundForCurrentPort( m_backgroundBrush ) ;
::EraseRect( &rect ) ;
}
}
void wxDC::MacInstallFont() const
{
wxCHECK_RET(Ok(), wxT("Invalid DC"));
// if ( m_macFontInstalled )
// return ;
Pattern blackColor ;
MacSetupBackgroundForCurrentPort(m_backgroundBrush) ;
if ( m_backgroundMode != wxTRANSPARENT )
{
Pattern whiteColor ;
::BackPat(GetQDGlobalsWhite(&whiteColor));
}
wxASSERT( m_font.Ok() ) ;
::TextFont( m_font.MacGetFontNum() ) ;
::TextSize( (short)(m_scaleY * m_font.MacGetFontSize()) ) ;
::TextFace( m_font.MacGetFontStyle() ) ;
m_macFontInstalled = true ;
m_macBrushInstalled = false ;
m_macPenInstalled = false ;
RGBColor forecolor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel());
RGBColor backcolor = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel());
::RGBForeColor( &forecolor );
::RGBBackColor( &backcolor );
// TODO:
short mode = patCopy ;
switch ( m_logicalFunction )
{
case wxCOPY: // src
mode = patCopy ;
break ;
case wxINVERT: // NOT dst
::PenPat(GetQDGlobalsBlack(&blackColor));
mode = patXor ;
break ;
case wxXOR: // src XOR dst
mode = patXor ;
break ;
case wxOR_REVERSE: // src OR (NOT dst)
mode = notPatOr ;
break ;
case wxSRC_INVERT: // (NOT src)
mode = notPatCopy ;
break ;
case wxAND: // src AND dst
mode = adMin ;
break ;
// TODO: unsupported
case wxCLEAR: // 0
case wxAND_REVERSE:// src AND (NOT dst)
case wxAND_INVERT: // (NOT src) AND dst
case wxNO_OP: // dst
case wxNOR: // (NOT src) AND (NOT dst)
case wxEQUIV: // (NOT src) XOR dst
case wxOR_INVERT: // (NOT src) OR dst
case wxNAND: // (NOT src) OR (NOT dst)
case wxOR: // src OR dst
case wxSET: // 1
// case wxSRC_OR: // source _bitmap_ OR destination
// case wxSRC_AND: // source _bitmap_ AND destination
break ;
default:
break ;
}
::PenMode( mode ) ;
OSStatus status = noErr ;
status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
ATSUAttributeTag atsuTags[] =
{
kATSUSizeTag ,
} ;
ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
sizeof( Fixed ) ,
} ;
ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
{
&atsuSize ,
} ;
status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
atsuTags, atsuSizes, atsuValues);
wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") ) ;
}
Pattern gPatterns[] =
{
// hatch patterns
{ { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } } ,
{ { 0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80 } } ,
{ { 0x80 , 0x40 , 0x20 , 0x10 , 0x08 , 0x04 , 0x02 , 0x01 } } ,
{ { 0x10 , 0x10 , 0x10 , 0xFF , 0x10 , 0x10 , 0x10 , 0x10 } } ,
{ { 0x00 , 0x00 , 0x00 , 0xFF , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ { 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 } } ,
{ { 0x81 , 0x42 , 0x24 , 0x18 , 0x18 , 0x24 , 0x42 , 0x81 } } ,
// dash patterns
{ { 0xCC , 0x99 , 0x33 , 0x66 , 0xCC , 0x99 , 0x33 , 0x66 } } , // DOT
{ { 0xFE , 0xFD , 0xFB , 0xF7 , 0xEF , 0xDF , 0xBF , 0x7F } } , // LONG_DASH
{ { 0xEE , 0xDD , 0xBB , 0x77 , 0xEE , 0xDD , 0xBB , 0x77 } } , // SHORT_DASH
{ { 0xDE , 0xBD , 0x7B , 0xF6 , 0xED , 0xDB , 0xB7 , 0x6F } } , // DOT_DASH
} ;
static void wxMacGetPattern(int penStyle, Pattern *pattern)
{
int index = 0; // solid pattern by default
switch (penStyle)
{
// hatches
case wxBDIAGONAL_HATCH: index = 1; break;
case wxFDIAGONAL_HATCH: index = 2; break;
case wxCROSS_HATCH: index = 3; break;
case wxHORIZONTAL_HATCH: index = 4; break;
case wxVERTICAL_HATCH: index = 5; break;
case wxCROSSDIAG_HATCH: index = 6; break;
// dashes
case wxDOT: index = 7; break;
case wxLONG_DASH: index = 8; break;
case wxSHORT_DASH: index = 9; break;
case wxDOT_DASH: index = 10; break;
default:
break;
}
*pattern = gPatterns[index];
}
void wxDC::MacInstallPen() const
{
wxCHECK_RET(Ok(), wxT("wxDC::MacInstallPen - invalid DC"));
//Pattern blackColor;
// if ( m_macPenInstalled )
// return ;
RGBColor forecolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel());
RGBColor backcolor = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel());
::RGBForeColor( &forecolor );
::RGBBackColor( &backcolor );
::PenNormal() ;
// null means only one pixel, at whatever resolution
int penWidth = (int) (m_pen.GetWidth() * m_scaleX) ;
if ( penWidth == 0 )
penWidth = 1 ;
::PenSize(penWidth, penWidth);
Pattern pat;
int penStyle = m_pen.GetStyle();
if (penStyle == wxUSER_DASH)
{
// FIXME: there should be exactly 8 items in the dash
wxDash* dash ;
int number = m_pen.GetDashes(&dash) ;
int index = 0;
for ( int i = 0 ; i < 8 ; ++i )
{
pat.pat[i] = dash[index] ;
if (index < number - 1)
index++;
}
}
else
{
wxMacGetPattern(penStyle, &pat);
}
::PenPat(&pat);
// TODO:
short mode = patCopy ;
switch ( m_logicalFunction )
{
case wxCOPY: // only foreground color, leave background (thus not patCopy)
mode = patOr ;
break ;
case wxINVERT: // NOT dst
// ::PenPat(GetQDGlobalsBlack(&blackColor));
mode = patXor ;
break ;
case wxXOR: // src XOR dst
mode = patXor ;
break ;
case wxOR_REVERSE: // src OR (NOT dst)
mode = notPatOr ;
break ;
case wxSRC_INVERT: // (NOT src)
mode = notPatCopy ;
break ;
case wxAND: // src AND dst
mode = adMin ;
break ;
// TODO: unsupported
case wxCLEAR: // 0
case wxAND_REVERSE:// src AND (NOT dst)
case wxAND_INVERT: // (NOT src) AND dst
case wxNO_OP: // dst
case wxNOR: // (NOT src) AND (NOT dst)
case wxEQUIV: // (NOT src) XOR dst
case wxOR_INVERT: // (NOT src) OR dst
case wxNAND: // (NOT src) OR (NOT dst)
case wxOR: // src OR dst
case wxSET: // 1
// case wxSRC_OR: // source _bitmap_ OR destination
// case wxSRC_AND: // source _bitmap_ AND destination
break ;
default:
break ;
}
::PenMode( mode ) ;
m_macPenInstalled = true ;
m_macBrushInstalled = false ;
m_macFontInstalled = false ;
}
void wxDC::MacSetupBackgroundForCurrentPort(const wxBrush& background )
{
Pattern whiteColor ;
if ( background.Ok() )
{
switch ( background.MacGetBrushKind() )
{
case kwxMacBrushTheme :
::SetThemeBackground( background.MacGetTheme() , wxDisplayDepth() , true ) ;
break ;
case kwxMacBrushThemeBackground :
{
Rect extent ;
ThemeBackgroundKind bg = background.MacGetThemeBackground( &extent ) ;
::ApplyThemeBackground( bg , &extent, kThemeStateActive , wxDisplayDepth() , true ) ;
}
break ;
case kwxMacBrushColour :
{
::RGBBackColor( &MAC_WXCOLORREF( background.GetColour().GetPixel()) );
int brushStyle = background.GetStyle();
if (brushStyle == wxSOLID)
::BackPat(GetQDGlobalsWhite(&whiteColor));
else if (background.IsHatch())
{
Pattern pat ;
wxMacGetPattern(brushStyle, &pat);
::BackPat(&pat);
}
else
{
::BackPat(GetQDGlobalsWhite(&whiteColor));
}
}
break ;
default:
break ;
}
}
}
void wxDC::MacInstallBrush() const
{
wxCHECK_RET(Ok(), wxT("Invalid DC"));
// if ( m_macBrushInstalled )
// return ;
Pattern blackColor ;
bool backgroundTransparent = (GetBackgroundMode() == wxTRANSPARENT) ;
::RGBForeColor( &MAC_WXCOLORREF( m_brush.GetColour().GetPixel()) );
::RGBBackColor( &MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) );
int brushStyle = m_brush.GetStyle();
if (brushStyle == wxSOLID)
{
switch ( m_brush.MacGetBrushKind() )
{
case kwxMacBrushTheme :
{
Pattern whiteColor ;
::BackPat(GetQDGlobalsWhite(&whiteColor));
::SetThemePen( m_brush.MacGetTheme() , wxDisplayDepth() , true ) ;
}
break ;
default :
::PenPat(GetQDGlobalsBlack(&blackColor));
break ;
}
}
else if (m_brush.IsHatch())
{
Pattern pat ;
wxMacGetPattern(brushStyle, &pat);
::PenPat(&pat);
}
else if ( m_brush.GetStyle() == wxSTIPPLE || m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
{
// we force this in order to be compliant with wxMSW
backgroundTransparent = false ;
// for these the text fore (and back for MASK_OPAQUE) colors are used
wxBitmap* bitmap = m_brush.GetStipple() ;
int width = bitmap->GetWidth() ;
int height = bitmap->GetHeight() ;
GWorldPtr gw = NULL ;
if ( m_brush.GetStyle() == wxSTIPPLE )
gw = MAC_WXHBITMAP(bitmap->GetHBITMAP(NULL)) ;
else
gw = MAC_WXHBITMAP(bitmap->GetMask()->GetHBITMAP()) ;
PixMapHandle gwpixmaphandle = GetGWorldPixMap( gw ) ;
LockPixels( gwpixmaphandle ) ;
bool isMonochrome = !IsPortColor( gw ) ;
if ( !isMonochrome )
{
if ( (**gwpixmaphandle).pixelSize == 1 )
isMonochrome = true ;
}
if ( isMonochrome && width == 8 && height == 8 )
{
::RGBForeColor( &MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) );
::RGBForeColor( &MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) );
BitMap* gwbitmap = (BitMap*) *gwpixmaphandle ; // since the color depth is 1 it is a BitMap
UInt8 *gwbits = (UInt8*) gwbitmap->baseAddr ;
int alignment = gwbitmap->rowBytes & 0x7FFF ;
Pattern pat ;
for ( int i = 0 ; i < 8 ; ++i )
{
pat.pat[i] = gwbits[i * alignment + 0] ;
}
UnlockPixels( GetGWorldPixMap( gw ) ) ;
::PenPat( &pat ) ;
}
else
{
// this will be the code to handle power of 2 patterns, we will have to arrive at a nice
// caching scheme before putting this into production
Handle image;
long imageSize;
PixPatHandle pixpat = NewPixPat() ;
CopyPixMap(gwpixmaphandle, (**pixpat).patMap);
imageSize = GetPixRowBytes((**pixpat).patMap) *
((**(**pixpat).patMap).bounds.bottom -
(**(**pixpat).patMap).bounds.top);
PtrToHand( (**gwpixmaphandle).baseAddr, &image, imageSize );
(**pixpat).patData = image;
if ( isMonochrome )
{
CTabHandle ctable = ((**((**pixpat).patMap)).pmTable) ;
ColorSpecPtr ctspec = (ColorSpecPtr) &(**ctable).ctTable ;
if ( ctspec[0].rgb.red == 0x0000 )
{
ctspec[1].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ;
ctspec[0].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ;
}
else
{
ctspec[0].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ;
ctspec[1].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ;
}
::CTabChanged( ctable ) ;
}
::PenPixPat(pixpat);
m_macForegroundPixMap = pixpat ;
}
UnlockPixels( gwpixmaphandle ) ;
}
else
{
::PenPat(GetQDGlobalsBlack(&blackColor));
}
short mode = patCopy ;
switch ( m_logicalFunction )
{
case wxCOPY: // src
if ( backgroundTransparent )
mode = patOr ;
else
mode = patCopy ;
break ;
case wxINVERT: // NOT dst
if ( !backgroundTransparent )
::PenPat(GetQDGlobalsBlack(&blackColor));
mode = patXor ;
break ;
case wxXOR: // src XOR dst
mode = patXor ;
break ;
case wxOR_REVERSE: // src OR (NOT dst)
mode = notPatOr ;
break ;
case wxSRC_INVERT: // (NOT src)
mode = notPatCopy ;
break ;
case wxAND: // src AND dst
mode = adMin ;
break ;
// TODO: unsupported
case wxCLEAR: // 0
case wxAND_REVERSE:// src AND (NOT dst)
case wxAND_INVERT: // (NOT src) AND dst
case wxNO_OP: // dst
case wxNOR: // (NOT src) AND (NOT dst)
case wxEQUIV: // (NOT src) XOR dst
case wxOR_INVERT: // (NOT src) OR dst
case wxNAND: // (NOT src) OR (NOT dst)
case wxOR: // src OR dst
case wxSET: // 1
// case wxSRC_OR: // source _bitmap_ OR destination
// case wxSRC_AND: // source _bitmap_ AND destination
break ;
default:
break ;
}
::PenMode( mode ) ;
m_macBrushInstalled = true ;
m_macPenInstalled = false ;
m_macFontInstalled = false ;
}
// ---------------------------------------------------------------------------
// coordinates transformations
// ---------------------------------------------------------------------------
wxCoord wxDC::DeviceToLogicalX(wxCoord x) const
{
return XDEV2LOG(x);
}
wxCoord wxDC::DeviceToLogicalY(wxCoord y) const
{
return YDEV2LOG(y);
}
wxCoord wxDC::DeviceToLogicalXRel(wxCoord x) const
{
return XDEV2LOGREL(x);
}
wxCoord wxDC::DeviceToLogicalYRel(wxCoord y) const
{
return YDEV2LOGREL(y);
}
wxCoord wxDC::LogicalToDeviceX(wxCoord x) const
{
return XLOG2DEV(x);
}
wxCoord wxDC::LogicalToDeviceY(wxCoord y) const
{
return YLOG2DEV(y);
}
wxCoord wxDC::LogicalToDeviceXRel(wxCoord x) const
{
return XLOG2DEVREL(x);
}
wxCoord wxDC::LogicalToDeviceYRel(wxCoord y) const
{
return YLOG2DEVREL(y);
}
#endif // !wxMAC_USE_CORE_GRAPHICS