X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f43426c1b97fe120b04c9a65d855d6861404ac14..b64c92ee20b022a88d3fe5371b0e17fb7818894f:/src/mac/carbon/graphics.cpp diff --git a/src/mac/carbon/graphics.cpp b/src/mac/carbon/graphics.cpp index 63a716c19b..6aec43bfc2 100755 --- a/src/mac/carbon/graphics.cpp +++ b/src/mac/carbon/graphics.cpp @@ -11,22 +11,18 @@ #include "wx/wxprec.h" -#include "wx/graphics.h" - #if wxUSE_GRAPHICS_CONTEXT && wxMAC_USE_CORE_GRAPHICS +#include "wx/graphics.h" + #ifndef WX_PRECOMP + #include "wx/dcclient.h" #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 #include "math.h" @@ -42,13 +38,24 @@ typedef float CGFloat; #endif +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +#if !defined( __DARWIN__ ) || defined(__MWERKS__) +#ifndef M_PI +const double M_PI = 3.14159265358979; +#endif +#endif + +static const double RAD2DEG = 180.0 / M_PI; + // // Graphics Path // class WXDLLEXPORT wxMacCoreGraphicsPath : public wxGraphicsPath { - DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath) public : wxMacCoreGraphicsPath(); ~wxMacCoreGraphicsPath(); @@ -88,11 +95,24 @@ public : // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ); - CGPathRef GetPath() const; + // returns the native path + virtual void * GetNativePath() const { return m_path; } + + // give the native path returned by GetNativePath() back (there might be some deallocations necessary) + virtual void UnGetNativePath(void *p) {} + + DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsPath) + DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath) private : CGMutablePathRef m_path; }; +//----------------------------------------------------------------------------- +// wxGraphicsPath implementation +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsPath, wxGraphicsPath) + wxMacCoreGraphicsPath::wxMacCoreGraphicsPath() { m_path = CGPathCreateMutable(); @@ -153,11 +173,6 @@ void wxMacCoreGraphicsPath::CloseSubpath() CGPathCloseSubpath( m_path ); } -CGPathRef wxMacCoreGraphicsPath::GetPath() const -{ - return m_path; -} - // gets the last point of the current path, (0,0) if not yet set void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y) { @@ -172,17 +187,18 @@ void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y) class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext { - DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext) - public: - wxMacCoreGraphicsContext( CGrafPtr port ); - wxMacCoreGraphicsContext( CGContextRef cgcontext ); + wxMacCoreGraphicsContext( WindowRef window ); + + wxMacCoreGraphicsContext( wxWindow* window ); + wxMacCoreGraphicsContext(); ~wxMacCoreGraphicsContext(); + void Init(); // creates a path instance that corresponds to the type of graphics context, ie GDIPlus, cairo, CoreGraphics ... virtual wxGraphicsPath * CreatePath(); @@ -196,6 +212,14 @@ public: // clips drawings to the region virtual void Clip( const wxRegion ®ion ); + // clips drawings to the rect + virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + + // resets the clipping to original extent + virtual void ResetClip(); + + virtual void * GetNativeContext(); + // // transformation // @@ -264,44 +288,29 @@ public: virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - CGContextRef GetNativeContext(); void SetNativeContext( CGContextRef cg ); CGPathDrawingMode GetDrawingMode() const { return m_mode; } + DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext) + DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext) + private: + void EnsureIsValid(); + CGContextRef m_cgContext; - CGrafPtr m_qdPort; + WindowRef m_windowRef; + int m_originX; + int m_originY; + wxMacCFRefHolder m_clipRgn; + bool m_releaseContext; CGPathDrawingMode m_mode; ATSUStyle m_macATSUIStyle; wxPen m_pen; wxBrush m_brush; + wxFont m_font; wxColor m_textForegroundColor; }; -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -#if !defined( __DARWIN__ ) || defined(__MWERKS__) -#ifndef M_PI -const double M_PI = 3.14159265358979; -#endif -#endif - -const double RAD2DEG = 180.0 / M_PI; -const short kEmulatedMode = -1; -const short kUnsupportedMode = -2; - -extern TECObjectRef s_TECNativeCToUnicode; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double dmin(double a, double b) { return a < b ? a : b; } -static inline double dmax(double a, double b) { return a > b ? a : b; } -static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } - //----------------------------------------------------------------------------- // device context implementation // @@ -314,68 +323,153 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } // state we were called with, the other one after changing to HI Graphics orientation // (this one is used for getting back clippings etc) -//----------------------------------------------------------------------------- -// wxGraphicsPath implementation -//----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- // wxGraphicsContext implementation //----------------------------------------------------------------------------- -wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGrafPtr port ) +IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext) + +void wxMacCoreGraphicsContext::Init() { - m_qdPort = port; m_cgContext = NULL; m_mode = kCGPathFill; m_macATSUIStyle = NULL; + m_releaseContext = false; + m_clipRgn.Set(HIShapeCreateEmpty()); } wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGContextRef cgcontext ) { - m_qdPort = NULL; - m_cgContext = cgcontext; - m_mode = kCGPathFill; - m_macATSUIStyle = NULL; + Init(); + m_cgContext = cgcontext; CGContextSaveGState( m_cgContext ); CGContextSaveGState( m_cgContext ); } +wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( WindowRef window ) +{ + Init(); + m_windowRef = window; +} + +wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxWindow* window ) +{ + Init(); + m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef(); + m_originX = m_originY = 0; + window->MacWindowToRootWindow( &m_originX , &m_originY ); +} + wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() { - m_qdPort = NULL; - m_cgContext = NULL; - m_mode = kCGPathFill; - m_macATSUIStyle = NULL; + Init(); } wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext() { if ( m_cgContext ) { - CGContextSynchronize( m_cgContext ); + // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext ); CGContextRestoreGState( m_cgContext ); CGContextRestoreGState( m_cgContext ); } - if ( m_qdPort ) - CGContextRelease( m_cgContext ); + if ( m_releaseContext ) + QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext); +} + +void wxMacCoreGraphicsContext::EnsureIsValid() +{ + if ( !m_cgContext ) + { + OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext ); + wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ); + Rect bounds; + GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds ); + CGContextSaveGState( m_cgContext ); + CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ); + CGContextScaleCTM( m_cgContext , 1 , -1 ); + CGContextTranslateCTM( m_cgContext, m_originX, m_originY ); + CGContextSaveGState( m_cgContext ); + m_releaseContext = true; + if ( !HIShapeIsEmpty(m_clipRgn) ) + { + HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext ); + CGContextClip( m_cgContext ); + } + } } + void wxMacCoreGraphicsContext::Clip( const wxRegion ®ion ) { -// ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ); + if( m_cgContext ) + { + HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ); + HIShapeReplacePathInCGContext( shape, m_cgContext ); + CGContextClip( m_cgContext ); + CFRelease( shape ); + } + else + { + m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() )); + } } -void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *p ) +// clips drawings to the rect +void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p ); - CGContextAddPath( m_cgContext , path->GetPath() ); + HIRect r = CGRectMake( x , y , w , h ); + if ( m_cgContext ) + { + CGContextClipToRect( m_cgContext, r ); + } + else + { + m_clipRgn.Set(HIShapeCreateWithRect(&r)); + } +} + + // resets the clipping to original extent +void wxMacCoreGraphicsContext::ResetClip() +{ + if ( m_cgContext ) + { + CGContextRestoreGState( m_cgContext ); + CGContextSaveGState( m_cgContext ); + } + else + { + m_clipRgn.Set(HIShapeCreateEmpty()); + } +} + +void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *path ) +{ + EnsureIsValid(); + + int width = m_pen.GetWidth(); + if ( width == 0 ) + width = 1 ; + if ( m_pen.GetStyle() == wxTRANSPARENT ) + width = 0 ; + + bool offset = ( width % 2 ) == 1 ; + + if ( offset ) + CGContextTranslateCTM( m_cgContext, 0.5, 0.5 ); + + CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() ); CGContextStrokePath( m_cgContext ); + + if ( offset ) + CGContextTranslateCTM( m_cgContext, -0.5, -0.5 ); } -void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle ) +void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *path , int fillStyle ) { - const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p ); + EnsureIsValid(); + CGPathDrawingMode mode = m_mode; if ( fillStyle == wxODDEVEN_RULE ) @@ -386,15 +480,29 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle mode = kCGPathEOFillStroke; } - CGContextAddPath( m_cgContext , path->GetPath() ); + int width = m_pen.GetWidth(); + if ( width == 0 ) + width = 1 ; + if ( m_pen.GetStyle() == wxTRANSPARENT ) + width = 0 ; + + bool offset = ( width % 2 ) == 1 ; + + if ( offset ) + CGContextTranslateCTM( m_cgContext, 0.5, 0.5 ); + + CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() ); CGContextDrawPath( m_cgContext , mode ); + + if ( offset ) + CGContextTranslateCTM( m_cgContext, -0.5, -0.5 ); } -void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle ) +void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *path , int fillStyle ) { - const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p ); - - CGContextAddPath( m_cgContext , path->GetPath() ); + EnsureIsValid(); + + CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() ); if ( fillStyle == wxODDEVEN_RULE ) CGContextEOFillPath( m_cgContext ); else @@ -403,19 +511,9 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle wxGraphicsPath* wxMacCoreGraphicsContext::CreatePath() { - // make sure that we now have a real cgref, before doing - // anything with paths - CGContextRef cg = GetNativeContext(); - cg = NULL; - return new wxMacCoreGraphicsPath(); } -CGContextRef wxMacCoreGraphicsContext::GetNativeContext() -{ - return m_cgContext; -} - void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) { // we allow either setting or clearing but not replacing @@ -428,21 +526,29 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy ) { + EnsureIsValid(); + CGContextTranslateCTM( m_cgContext, dx, dy ); } void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale ) { + EnsureIsValid(); + CGContextScaleCTM( m_cgContext , xScale , yScale ); } void wxMacCoreGraphicsContext::Rotate( wxDouble angle ) { + EnsureIsValid(); + CGContextRotateCTM( m_cgContext , angle ); } void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { + EnsureIsValid(); + CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ); HIRect r = CGRectMake( x , y , w , h ); HIViewDrawCGImage( m_cgContext , &r , image ); @@ -451,6 +557,8 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { + EnsureIsValid(); + CGRect r = CGRectMake( 00 , 00 , w , h ); CGContextSaveGState( m_cgContext ); CGContextTranslateCTM( m_cgContext, x , y + h ); @@ -462,17 +570,23 @@ void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDoubl void wxMacCoreGraphicsContext::PushState() { + EnsureIsValid(); + CGContextSaveGState( m_cgContext ); } void wxMacCoreGraphicsContext::PopState() { + EnsureIsValid(); + CGContextRestoreGState( m_cgContext ); } void wxMacCoreGraphicsContext::SetTextColor( const wxColour &col ) { m_textForegroundColor = col; + // to recreate the native font after color change + SetFont( m_font ); } #pragma mark - @@ -520,7 +634,7 @@ const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCor class ImagePattern : public wxMacCoreGraphicsPattern { public : - ImagePattern( const wxBitmap* bmp , CGAffineTransform transform ) + ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform ) { wxASSERT( bmp && bmp->Ok() ); @@ -528,7 +642,7 @@ public : } // ImagePattern takes ownership of CGImageRef passed in - ImagePattern( CGImageRef image , CGAffineTransform transform ) + ImagePattern( CGImageRef image , const CGAffineTransform& transform ) { if ( image ) CFRetain( image ); @@ -543,7 +657,7 @@ public : } protected : - void Init( CGImageRef image, CGAffineTransform transform ) + void Init( CGImageRef image, const CGAffineTransform& transform ) { m_image = image; if ( m_image ) @@ -569,7 +683,7 @@ protected : class HatchPattern : public wxMacCoreGraphicsPattern { public : - HatchPattern( int hatchstyle, CGAffineTransform transform ) + HatchPattern( int hatchstyle, const CGAffineTransform& transform ) { m_hatch = hatchstyle; m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 ); @@ -693,7 +807,7 @@ void wxMacCoreGraphicsContext::SetPen( const wxPen &pen ) CGContextSetShouldAntialias( m_cgContext , false ); #endif - if ( fill | stroke ) + if ( fill || stroke ) { // set up brushes m_mode = kCGPathFill; // just a default @@ -870,7 +984,7 @@ void wxMacCoreGraphicsContext::SetBrush( const wxBrush &brush ) CGContextSetShouldAntialias( m_cgContext , false ); #endif - if ( fill | stroke ) + if ( fill || stroke ) { // setup brushes m_mode = kCGPathFill; // just a default @@ -938,6 +1052,8 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) { + EnsureIsValid(); + OSStatus status = noErr; ATSUTextLayout atsuLayout; UniCharCount chars = str.length(); @@ -1156,8 +1272,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr #endif #endif - OSStatus status; - status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 , + ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 , &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ); for ( int pos = 0; pos < (int)chars; pos ++ ) @@ -1189,6 +1304,7 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font ) if ( font.Ok() ) { + m_font = font ; OSStatus status; status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ); @@ -1223,9 +1339,29 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font ) } } +void * wxMacCoreGraphicsContext::GetNativeContext() +{ + return m_cgContext; +} + wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc ) { return new wxMacCoreGraphicsContext((CGContextRef)dc.GetWindow()->MacGetCGContextRef() ); } +wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window ) +{ + return new wxMacCoreGraphicsContext( window ); +} + +wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) +{ + return new wxMacCoreGraphicsContext((CGContextRef)context); +} + +wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) +{ + return new wxMacCoreGraphicsContext((WindowRef)window); +} + #endif // wxMAC_USE_CORE_GRAPHICS