+
+wxGraphicPath* wxMacCGContext::CreatePath()
+{
+ // make sure that we now have a real cgref, before doing
+ // anything with paths
+ CGContextRef cg = GetNativeContext() ;
+ cg = NULL ;
+
+ return new wxMacCGPath() ;
+}
+
+// in case we only got a QDPort only create a cgref now
+
+CGContextRef wxMacCGContext::GetNativeContext()
+{
+ if ( m_cgContext == NULL )
+ {
+ Rect bounds ;
+ OSStatus status = noErr;
+#ifndef __LP64__
+ GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
+ status = QDBeginCGContext((CGrafPtr) m_qdPort , &m_cgContext) ;
+#endif
+ CGContextSaveGState( m_cgContext ) ;
+
+ wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
+
+ CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
+ CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
+
+ CGContextSaveGState( m_cgContext ) ;
+ SetPen( m_pen ) ;
+ SetBrush( m_brush ) ;
+ }
+
+ return m_cgContext ;
+}
+
+void wxMacCGContext::SetNativeContext( CGContextRef cg )
+{
+ // we allow either setting or clearing but not replacing
+ wxASSERT( m_cgContext == NULL || cg == NULL ) ;
+
+ if ( cg )
+ CGContextSaveGState( cg ) ;
+ m_cgContext = cg ;
+}
+
+void wxMacCGContext::Translate( wxCoord dx , wxCoord dy )
+{
+ CGContextTranslateCTM( m_cgContext, dx, dy );
+}
+
+void wxMacCGContext::Scale( wxCoord xScale , wxCoord yScale )
+{
+ CGContextScaleCTM( m_cgContext , xScale , yScale ) ;
+}
+
+void wxMacCGContext::DrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, wxCoord w, wxCoord h )
+{
+ CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ) ;
+ HIRect r = CGRectMake( 0 , 0 , w , h );
+
+ CGContextSaveGState( m_cgContext );
+ CGContextTranslateCTM( m_cgContext, x , y + h );
+ CGContextScaleCTM( m_cgContext, 1, -1 );
+
+ // in case image is a mask, set the foreground color
+ CGContextSetRGBFillColor( m_cgContext , m_textForegroundColor.Red() / 255.0 , m_textForegroundColor.Green() / 255.0 ,
+ m_textForegroundColor.Blue() / 255.0 , m_textForegroundColor.Alpha() / 255.0 ) ;
+ CGContextDrawImage( m_cgContext, r, image );
+ CGContextRestoreGState( m_cgContext );
+
+ CGImageRelease( image ) ;
+}
+
+void wxMacCGContext::DrawIcon( const wxIcon &icon, wxCoord x, wxCoord y, wxCoord w, wxCoord h )
+{
+ CGRect r = CGRectMake( 0 , 0 , w , h ) ;
+ CGContextSaveGState( m_cgContext );
+ CGContextTranslateCTM( m_cgContext, x , y + h );
+ CGContextScaleCTM( m_cgContext, 1, -1 );
+ PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
+ NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
+ CGContextRestoreGState( m_cgContext ) ;
+}
+
+void wxMacCGContext::PushState()
+{
+ CGContextSaveGState( m_cgContext );
+}
+
+void wxMacCGContext::PopState()
+{
+ CGContextRestoreGState( m_cgContext );
+}
+
+void wxMacCGContext::SetTextColor( const wxColour &col )
+{
+ m_textForegroundColor = col ;
+}
+
+#pragma mark -
+#pragma mark wxMacCGPattern, ImagePattern, HatchPattern classes
+
+// CGPattern wrapper class: always allocate on heap, never call destructor
+
+class wxMacCGPattern
+{
+public :
+ wxMacCGPattern() {}
+
+ // is guaranteed to be called only with a non-Null CGContextRef
+ virtual void Render( CGContextRef ctxRef ) = 0 ;
+
+ operator CGPatternRef() const { return m_patternRef ; }
+
+protected :
+ virtual ~wxMacCGPattern()
+ {
+ // as this is called only when the m_patternRef is been released;
+ // don't release it again
+ }
+
+ static void _Render( void *info, CGContextRef ctxRef )
+ {
+ wxMacCGPattern* self = (wxMacCGPattern*) info ;
+ if ( self && ctxRef )
+ self->Render( ctxRef ) ;
+ }
+
+ static void _Dispose( void *info )
+ {
+ wxMacCGPattern* self = (wxMacCGPattern*) info ;
+ delete self ;
+ }
+
+ CGPatternRef m_patternRef ;
+
+ static const CGPatternCallbacks ms_Callbacks ;
+} ;
+
+const CGPatternCallbacks wxMacCGPattern::ms_Callbacks = { 0, &wxMacCGPattern::_Render, &wxMacCGPattern::_Dispose };
+
+class ImagePattern : public wxMacCGPattern
+{
+public :
+ ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform )
+ {
+ wxASSERT( bmp && bmp->Ok() ) ;
+
+ Init( (CGImageRef) bmp->CGImageCreate() , transform ) ;
+ }
+
+ // ImagePattern takes ownership of CGImageRef passed in
+ ImagePattern( CGImageRef image , const CGAffineTransform& transform )
+ {
+ if ( image )
+ CFRetain( image ) ;
+
+ Init( image , transform ) ;
+ }
+
+ virtual void Render( CGContextRef ctxRef )
+ {
+ if (m_image != NULL)
+ HIViewDrawCGImage( ctxRef, &m_imageBounds, m_image );
+ }
+
+protected :
+ void Init( CGImageRef image, const CGAffineTransform& transform )
+ {
+ m_image = image ;
+ if ( m_image )
+ {
+ m_imageBounds = CGRectMake( 0.0, 0.0, (CGFloat)CGImageGetWidth( m_image ), (CGFloat)CGImageGetHeight( m_image ) ) ;
+ m_patternRef = CGPatternCreate(
+ this , m_imageBounds, transform ,
+ m_imageBounds.size.width, m_imageBounds.size.height,
+ kCGPatternTilingNoDistortion, true , &wxMacCGPattern::ms_Callbacks ) ;
+ }
+ }
+
+ virtual ~ImagePattern()
+ {
+ if ( m_image )
+ CGImageRelease( m_image ) ;
+ }
+
+ CGImageRef m_image ;
+ CGRect m_imageBounds ;
+} ;
+
+class HatchPattern : public wxMacCGPattern
+{
+public :
+ HatchPattern( int hatchstyle, const CGAffineTransform& transform )
+ {
+ m_hatch = hatchstyle ;
+ m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 ) ;
+ m_patternRef = CGPatternCreate(
+ this , m_imageBounds, transform ,
+ m_imageBounds.size.width, m_imageBounds.size.height,
+ kCGPatternTilingNoDistortion, false , &wxMacCGPattern::ms_Callbacks ) ;
+ }
+
+ void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
+ {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+ if ( UMAGetSystemVersion() >= 0x1040 )
+ {
+ CGContextStrokeLineSegments( ctxRef , pts , count ) ;
+ }
+ else
+#endif
+ {
+ CGContextBeginPath( ctxRef );
+ for (size_t i = 0; i < count; i += 2)
+ {
+ CGContextMoveToPoint(ctxRef, pts[i].x, pts[i].y);
+ CGContextAddLineToPoint(ctxRef, pts[i+1].x, pts[i+1].y);
+ }
+ CGContextStrokePath(ctxRef);
+ }
+ }
+
+ virtual void Render( CGContextRef ctxRef )
+ {
+ switch ( m_hatch )
+ {
+ case wxBDIAGONAL_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 8.0 , 0.0 } , { 0.0 , 8.0 }
+ };
+ StrokeLineSegments( ctxRef , pts , 2 ) ;
+ }
+ break ;
+
+ case wxCROSSDIAG_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 0.0 , 0.0 } , { 8.0 , 8.0 } ,
+ { 8.0 , 0.0 } , { 0.0 , 8.0 }
+ };
+ StrokeLineSegments( ctxRef , pts , 4 ) ;
+ }
+ break ;
+
+ case wxFDIAGONAL_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 0.0 , 0.0 } , { 8.0 , 8.0 }
+ };
+ StrokeLineSegments( ctxRef , pts , 2 ) ;
+ }
+ break ;
+
+ case wxCROSS_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
+ { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
+ };
+ StrokeLineSegments( ctxRef , pts , 4 ) ;
+ }
+ break ;
+
+ case wxHORIZONTAL_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
+ };
+ StrokeLineSegments( ctxRef , pts , 2 ) ;
+ }
+ break ;
+
+ case wxVERTICAL_HATCH :
+ {
+ CGPoint pts[] =
+ {
+ { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
+ };
+ StrokeLineSegments( ctxRef , pts , 2 ) ;
+ }
+ break ;
+
+ default:
+ break;
+ }
+ }
+
+protected :
+ virtual ~HatchPattern() {}
+
+ CGRect m_imageBounds ;
+ int m_hatch ;
+};
+
+#pragma mark -