1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 #include "wx/wxprec.h"
20 #if wxMAC_USE_CORE_GRAPHICS
23 #include "wx/mac/uma.h"
24 #include "wx/dcmemory.h"
25 #include "wx/dcprint.h"
26 #include "wx/region.h"
36 #include "wx/mac/private.h"
37 #include <ATSUnicode.h>
38 #include <TextCommon.h>
39 #include <TextEncodingConverter.h>
41 #include <CGContext.h>
43 #if !USE_SHARED_LIBRARY
44 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
51 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
53 const double M_PI
= 3.14159265358979 ;
56 const double RAD2DEG
= 180.0 / M_PI
;
57 const short kEmulatedMode
= -1 ;
58 const short kUnsupportedMode
= -2 ;
60 extern TECObjectRef s_TECNativeCToUnicode
;
63 // The text ctrl implementation still needs that for the non hiview implementation
65 wxMacWindowClipper::wxMacWindowClipper( const wxWindow
* win
) :
66 wxMacPortSaver( (GrafPtr
) GetWindowPort((WindowRef
) win
->MacGetTopLevelWindowRef()) )
68 m_newPort
=(GrafPtr
) GetWindowPort((WindowRef
) win
->MacGetTopLevelWindowRef()) ;
69 m_formerClip
= NewRgn() ;
70 m_newClip
= NewRgn() ;
71 GetClip( m_formerClip
) ;
76 win
->MacWindowToRootWindow( &x
,&y
) ;
77 // get area including focus rect
78 CopyRgn( (RgnHandle
) ((wxWindow
*)win
)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip
) ;
79 if ( !EmptyRgn( m_newClip
) )
80 OffsetRgn( m_newClip
, x
, y
) ;
82 SetClip( m_newClip
) ;
86 wxMacWindowClipper::~wxMacWindowClipper()
88 SetPort( m_newPort
) ;
89 SetClip( m_formerClip
) ;
90 DisposeRgn( m_newClip
) ;
91 DisposeRgn( m_formerClip
) ;
94 wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow
* win
) :
95 wxMacWindowClipper( win
)
97 // the port is already set at this point
98 m_newPort
=(GrafPtr
) GetWindowPort((WindowRef
) win
->MacGetTopLevelWindowRef()) ;
99 GetThemeDrawingState( &m_themeDrawingState
) ;
102 wxMacWindowStateSaver::~wxMacWindowStateSaver()
104 SetPort( m_newPort
) ;
105 SetThemeDrawingState( m_themeDrawingState
, true ) ;
108 // minimal implementation only used for appearance drawing < 10.3
110 wxMacPortSetter::wxMacPortSetter( const wxDC
* dc
) :
111 m_ph( (GrafPtr
) dc
->m_macPort
)
113 wxASSERT( dc
->Ok() ) ;
115 // dc->MacSetupPort(&m_ph) ;
117 wxMacPortSetter::~wxMacPortSetter()
119 // m_dc->MacCleanupPort(&m_ph) ;
122 //-----------------------------------------------------------------------------
124 //-----------------------------------------------------------------------------
126 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
127 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
128 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
130 //-----------------------------------------------------------------------------
131 // device context implementation
133 // more and more of the dc functionality should be implemented by calling
134 // the appropricate wxMacCGContext, but we will have to do that step by step
135 // also coordinate conversions should be moved to native matrix ops
136 //-----------------------------------------------------------------------------
138 wxMacCGPath::wxMacCGPath()
140 m_path
= CGPathCreateMutable() ;
143 wxMacCGPath::~wxMacCGPath()
145 CGPathRelease( m_path
) ;
148 // Starts a new subpath at
149 void wxMacCGPath::MoveToPoint( wxCoord x1
, wxCoord y1
)
151 CGPathMoveToPoint( m_path
, NULL
, x1
, y1
) ;
154 void wxMacCGPath::AddLineToPoint( wxCoord x1
, wxCoord y1
)
156 CGPathAddLineToPoint( m_path
, NULL
, x1
, y1
) ;
159 void wxMacCGPath::AddRectangle( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
161 CGRect cgRect
= { { x
, y
} , { w
, h
} } ;
162 CGPathAddRect( m_path
, NULL
, cgRect
) ;
165 void wxMacCGPath::AddCircle( wxCoord x
, wxCoord y
, wxCoord r
)
167 CGPathAddArc( m_path
, NULL
, x
, y
, r
, 0.0 , 2 * M_PI
, true ) ;
170 // closes the current subpath
171 void wxMacCGPath::CloseSubpath()
173 CGPathCloseSubpath( m_path
) ;
176 CGPathRef
wxMacCGPath::GetPath() const
181 // we always stock two context states, one at entry, the other one after
182 // changing to HI Graphics orientation (this one is used for getting back clippings etc)
184 wxMacCGContext::wxMacCGContext( CGrafPtr port
)
190 wxMacCGContext::wxMacCGContext( CGContextRef cgcontext
)
193 m_cgContext
= cgcontext
;
194 CGContextSaveGState( m_cgContext
) ;
195 CGContextSaveGState( m_cgContext
) ;
198 wxMacCGContext::wxMacCGContext()
204 wxMacCGContext::~wxMacCGContext()
208 CGContextRestoreGState( m_cgContext
) ;
209 CGContextRestoreGState( m_cgContext
) ;
212 QDEndCGContext( m_qdPort
, &m_cgContext
) ;
216 void wxMacCGContext::Clip( const wxRegion
®ion
)
218 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
221 void wxMacCGContext::StrokePath( const wxGraphicPath
*p
)
223 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
224 CGContextBeginPath( m_cgContext
) ;
225 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
226 CGContextClosePath( m_cgContext
) ;
227 CGContextStrokePath( m_cgContext
) ;
230 void wxMacCGContext::DrawPath( const wxGraphicPath
*p
, int fillStyle
)
232 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
233 CGPathDrawingMode mode
= m_mode
;
234 if ( fillStyle
== wxODDEVEN_RULE
)
236 if ( mode
== kCGPathFill
)
237 mode
= kCGPathEOFill
;
238 else if ( mode
== kCGPathFillStroke
)
239 mode
= kCGPathEOFillStroke
;
241 CGContextBeginPath( m_cgContext
) ;
242 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
243 CGContextClosePath( m_cgContext
) ;
244 CGContextDrawPath( m_cgContext
, mode
) ;
247 void wxMacCGContext::FillPath( const wxGraphicPath
*p
, const wxColor
&fillColor
, int fillStyle
)
249 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
250 CGContextSaveGState( m_cgContext
) ;
252 RGBColor col
= MAC_WXCOLORREF( fillColor
.GetPixel() ) ;
253 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
254 CGPathDrawingMode mode
= kCGPathFill
;
256 if ( fillStyle
== wxODDEVEN_RULE
)
257 mode
= kCGPathEOFill
;
259 CGContextBeginPath( m_cgContext
) ;
260 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
261 CGContextClosePath( m_cgContext
) ;
262 CGContextDrawPath( m_cgContext
, mode
) ;
264 CGContextRestoreGState( m_cgContext
) ;
267 wxGraphicPath
* wxMacCGContext::CreatePath()
269 // make sure that we now have a real cgref, before doing
270 // anything with paths
271 CGContextRef cg
= GetNativeContext() ;
273 return new wxMacCGPath() ;
276 // in case we only got a QDPort only create a cgref now
278 CGContextRef
wxMacCGContext::GetNativeContext()
280 if( m_cgContext
== NULL
)
283 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
284 OSStatus status
= QDBeginCGContext( (CGrafPtr
) m_qdPort
, &m_cgContext
) ;
285 CGContextSaveGState( m_cgContext
) ;
287 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
288 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
289 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
291 CGContextSaveGState( m_cgContext
) ;
293 SetBrush( m_brush
) ;
298 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
300 wxASSERT( m_cgContext
== NULL
) ;
302 CGContextSaveGState( m_cgContext
) ;
305 void wxMacCGContext::SetPen( const wxPen
&pen
)
308 if ( m_cgContext
== NULL
)
310 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
311 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
314 // we can benchmark performance, should go into a setting later
315 CGContextSetShouldAntialias( m_cgContext
, false ) ;
320 m_mode
= kCGPathFill
; // just a default
324 m_mode
= kCGPathFill
;
328 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
329 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
332 switch( pen
.GetCap() )
335 cap
= kCGLineCapRound
;
337 case wxCAP_PROJECTING
:
338 cap
= kCGLineCapSquare
;
341 cap
= kCGLineCapButt
;
344 cap
= kCGLineCapButt
;
347 CGContextSetLineCap( m_cgContext
, cap
) ;
350 switch( pen
.GetJoin() )
353 join
= kCGLineJoinBevel
;
356 join
= kCGLineJoinMiter
;
359 join
= kCGLineJoinRound
;
362 join
= kCGLineJoinMiter
;
365 CGContextSetLineJoin( m_cgContext
, join
) ;
367 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
369 m_mode
= kCGPathStroke
;
371 const float *lengths
= NULL
;
372 float *userLengths
= NULL
;
374 const float dotted
[] = { 3 , 3 };
375 const float dashed
[] = { 19 , 9 };
376 const float short_dashed
[] = { 9 , 6 };
377 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
379 switch( pen
.GetStyle() )
385 count
= WXSIZEOF(dotted
);
389 count
= WXSIZEOF(dashed
) ;
392 lengths
= short_dashed
;
393 count
= WXSIZEOF(short_dashed
) ;
396 lengths
= dotted_dashed
;
397 count
= WXSIZEOF(dotted_dashed
);
401 count
= pen
.GetDashes( &dashes
) ;
404 userLengths
= new float[count
] ;
405 for( int i
= 0 ; i
< count
; ++i
)
406 userLengths
[i
] = dashes
[i
] ;
408 lengths
= userLengths
;
414 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
415 delete[] userLengths
;
416 // we need to change the cap, otherwise everything overlaps
417 // and we get solid lines
419 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
421 if ( fill
&& stroke
)
423 m_mode
= kCGPathFillStroke
;
428 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
431 if ( m_cgContext
== NULL
)
434 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
435 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
438 // we can benchmark performance, should go into a setting later
439 CGContextSetShouldAntialias( m_cgContext
, false ) ;
445 m_mode
= kCGPathFill
; // just a default
449 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
450 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
451 m_mode
= kCGPathFill
;
455 m_mode
= kCGPathStroke
;
457 if ( fill
&& stroke
)
459 m_mode
= kCGPathFillStroke
;
465 // snippets from Sketch Sample from Apple :
467 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
469 This function locates, opens, and returns the profile reference for the calibrated
470 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
471 with the profile reference this function returns.
473 CMProfileRef
wxMacOpenGenericProfile(void)
475 static CMProfileRef cachedRGBProfileRef
= NULL
;
477 // we only create the profile reference once
478 if (cachedRGBProfileRef
== NULL
)
480 CMProfileLocation loc
;
482 loc
.locType
= cmPathBasedProfile
;
483 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
485 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
488 if (cachedRGBProfileRef
)
490 // clone the profile reference so that the caller has their own reference, not our cached one
491 CMCloneProfileRef(cachedRGBProfileRef
);
494 return cachedRGBProfileRef
;
498 Return the generic RGB color space. This is a 'get' function and the caller should
499 not release the returned value unless the caller retains it first. Usually callers
500 of this routine will immediately use the returned colorspace with CoreGraphics
501 so they typically do not need to retain it themselves.
503 This function creates the generic RGB color space once and hangs onto it so it can
504 return it whenever this function is called.
507 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
509 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
511 if (genericRGBColorSpace
== NULL
)
513 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
515 if (genericRGBProfile
)
517 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
518 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
520 // we opened the profile so it is up to us to close it
521 CMCloseProfile(genericRGBProfile
);
524 return genericRGBColorSpace
;
527 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
529 CGContextSaveGState(c
);
530 CGContextTranslateCTM(c
, center
.x
, center
.y
);
531 CGContextScaleCTM(c
, a
, b
);
532 CGContextMoveToPoint(c
, 1, 0);
533 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
534 CGContextClosePath(c
);
535 CGContextRestoreGState(c
);
538 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
542 if (ovalWidth
== 0 || ovalHeight
== 0)
544 CGContextAddRect(c
, rect
);
547 CGContextSaveGState(c
);
548 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
549 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
550 fw
= CGRectGetWidth(rect
) / ovalWidth
;
551 fh
= CGRectGetHeight(rect
) / ovalHeight
;
552 CGContextMoveToPoint(c
, fw
, fh
/2);
553 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
554 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
555 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
556 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
557 CGContextClosePath(c
);
558 CGContextRestoreGState(c
);
565 m_mm_to_pix_x
= mm2pt
;
566 m_mm_to_pix_y
= mm2pt
;
567 m_internalDeviceOriginX
= 0;
568 m_internalDeviceOriginY
= 0;
569 m_externalDeviceOriginX
= 0;
570 m_externalDeviceOriginY
= 0;
571 m_logicalScaleX
= 1.0;
572 m_logicalScaleY
= 1.0;
577 m_needComputeScaleX
= FALSE
;
578 m_needComputeScaleY
= FALSE
;
582 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
584 m_pen
= *wxBLACK_PEN
;
585 m_font
= *wxNORMAL_FONT
;
586 m_brush
= *wxWHITE_BRUSH
;
588 m_macATSUIStyle
= NULL
;
590 m_graphicContext
= NULL
;
595 if( m_macATSUIStyle
)
597 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
598 m_macATSUIStyle
= NULL
;
601 delete m_graphicContext
;
604 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
606 wxCHECK_RET( Ok(), wxT("invalid window dc") );
607 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
608 wxCoord xx
= XLOG2DEVMAC(x
);
609 wxCoord yy
= YLOG2DEVMAC(y
);
610 wxCoord w
= bmp
.GetWidth();
611 wxCoord h
= bmp
.GetHeight();
612 wxCoord ww
= XLOG2DEVREL(w
);
613 wxCoord hh
= YLOG2DEVREL(h
);
615 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
616 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
617 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
618 HIViewDrawCGImage( cg
, &r
, image
) ;
619 CGImageRelease( image
) ;
622 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
624 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
625 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
627 wxCoord xx
= XLOG2DEVMAC(x
);
628 wxCoord yy
= YLOG2DEVMAC(y
);
629 wxCoord w
= icon
.GetWidth();
630 wxCoord h
= icon
.GetHeight();
631 wxCoord ww
= XLOG2DEVREL(w
);
632 wxCoord hh
= YLOG2DEVREL(h
);
634 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
635 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
636 CGContextSaveGState(cg
);
637 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
638 CGContextScaleCTM(cg
, 1, -1);
639 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
640 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
641 CGContextRestoreGState( cg
) ;
644 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
646 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
647 wxCoord xx
, yy
, ww
, hh
;
650 ww
= XLOG2DEVREL(width
);
651 hh
= YLOG2DEVREL(height
);
653 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
654 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
655 CGContextClipToRect( cgContext
, clipRect
) ;
657 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
658 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
661 m_clipX1
= wxMax( m_clipX1
, xx
);
662 m_clipY1
= wxMax( m_clipY1
, yy
);
663 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
664 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
674 // TODO as soon as we don't reset the context for each operation anymore
675 // we have to update the context as well
678 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
680 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
683 DestroyClippingRegion();
687 region
.GetBox( x
, y
, w
, h
);
688 wxCoord xx
, yy
, ww
, hh
;
693 // if we have a scaling that we cannot map onto native regions
694 // we must use the box
695 if ( ww
!= w
|| hh
!= h
)
697 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
702 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
703 if ( xx != x || yy != y )
705 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
707 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
711 m_clipX1
= wxMax( m_clipX1
, xx
);
712 m_clipY1
= wxMax( m_clipY1
, yy
);
713 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
714 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
727 void wxDC::DestroyClippingRegion()
729 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
730 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
731 CGContextRestoreGState( cgContext
);
732 CGContextSaveGState( cgContext
);
734 SetBrush( m_brush
) ;
738 void wxDC::DoGetSizeMM( int* width
, int* height
) const
743 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
744 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
747 void wxDC::SetTextForeground( const wxColour
&col
)
749 wxCHECK_RET(Ok(), wxT("Invalid DC"));
750 if ( col
!= m_textForegroundColour
)
752 m_textForegroundColour
= col
;
757 void wxDC::SetTextBackground( const wxColour
&col
)
759 wxCHECK_RET(Ok(), wxT("Invalid DC"));
760 m_textBackgroundColour
= col
;
763 void wxDC::SetMapMode( int mode
)
768 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
771 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
774 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
777 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
781 SetLogicalScale( 1.0, 1.0 );
784 if (mode
!= wxMM_TEXT
)
786 m_needComputeScaleX
= TRUE
;
787 m_needComputeScaleY
= TRUE
;
791 void wxDC::SetUserScale( double x
, double y
)
793 // allow negative ? -> no
796 ComputeScaleAndOrigin();
799 void wxDC::SetLogicalScale( double x
, double y
)
804 ComputeScaleAndOrigin();
807 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
809 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
810 m_logicalOriginY
= y
* m_signY
;
811 ComputeScaleAndOrigin();
814 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
816 m_externalDeviceOriginX
= x
;
817 m_externalDeviceOriginY
= y
;
818 ComputeScaleAndOrigin();
821 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
823 m_signX
= (xLeftRight
? 1 : -1);
824 m_signY
= (yBottomUp
? -1 : 1);
825 ComputeScaleAndOrigin();
828 wxSize
wxDC::GetPPI() const
830 return wxSize(72, 72);
833 int wxDC::GetDepth() const
838 void wxDC::ComputeScaleAndOrigin()
840 // CMB: copy scale to see if it changes
841 double origScaleX
= m_scaleX
;
842 double origScaleY
= m_scaleY
;
843 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
844 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
845 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
846 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
847 // CMB: if scale has changed call SetPen to recalulate the line width
848 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
850 // this is a bit artificial, but we need to force wxDC to think
851 // the pen has changed
858 void wxDC::SetPalette( const wxPalette
& palette
)
862 void wxDC::SetBackgroundMode( int mode
)
864 m_backgroundMode
= mode
;
867 void wxDC::SetFont( const wxFont
&font
)
873 void wxDC::SetPen( const wxPen
&pen
)
878 if ( m_graphicContext
)
880 m_graphicContext
->SetPen( m_pen
) ;
884 void wxDC::SetBrush( const wxBrush
&brush
)
886 if (m_brush
== brush
)
889 if ( m_graphicContext
)
891 m_graphicContext
->SetBrush( m_brush
) ;
895 void wxDC::SetBackground( const wxBrush
&brush
)
897 if (m_backgroundBrush
== brush
)
899 m_backgroundBrush
= brush
;
900 if (!m_backgroundBrush
.Ok())
904 void wxDC::SetLogicalFunction( int function
)
906 if (m_logicalFunction
== function
)
908 m_logicalFunction
= function
;
911 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
912 const wxColour
& col
, int style
);
914 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
915 const wxColour
& col
, int style
)
917 return wxDoFloodFill(this, x
, y
, col
, style
);
920 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
922 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
923 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
924 wxMacPortSaver
helper((CGrafPtr
)m_macPort
) ;
927 XLOG2DEVMAC(x
) + m_macLocalOriginInPort
.x
- m_macLocalOrigin
.x
,
928 YLOG2DEVMAC(y
) + m_macLocalOriginInPort
.y
- m_macLocalOrigin
.y
, &colour
);
929 // Convert from Mac colour to wx
930 col
->Set( colour
.red
>> 8,
936 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
938 wxCHECK_RET(Ok(), wxT("Invalid DC"));
940 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
941 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
942 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
943 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
945 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
946 path
->MoveToPoint( xx1
, yy1
) ;
947 path
->AddLineToPoint( xx2
, yy2
) ;
948 path
->CloseSubpath() ;
949 m_graphicContext
->StrokePath( path
) ;
952 CalcBoundingBox(x1
, y1
);
953 CalcBoundingBox(x2
, y2
);
956 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
958 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
964 wxCoord xx
= XLOG2DEVMAC(x
);
965 wxCoord yy
= YLOG2DEVMAC(y
);
967 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
968 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
969 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
970 path
->CloseSubpath() ;
971 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
972 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
973 path
->CloseSubpath() ;
974 m_graphicContext
->StrokePath( path
) ;
977 CalcBoundingBox(x
, y
);
978 CalcBoundingBox(x
+w
, y
+h
);
982 * To draw arcs properly the angles need to be converted from the WX style:
983 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
984 * a normal axis on paper).
987 * Angles start on the +ve y axis and go clockwise.
990 static double wxConvertWXangleToMACangle(double angle
)
992 double newAngle
= 90 - angle
;
998 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
999 wxCoord x2
, wxCoord y2
,
1000 wxCoord xc
, wxCoord yc
)
1002 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1003 wxCoord xx1
= XLOG2DEVMAC(x1
);
1004 wxCoord yy1
= YLOG2DEVMAC(y1
);
1005 wxCoord xx2
= XLOG2DEVMAC(x2
);
1006 wxCoord yy2
= YLOG2DEVMAC(y2
);
1007 wxCoord xxc
= XLOG2DEVMAC(xc
);
1008 wxCoord yyc
= YLOG2DEVMAC(yc
);
1009 double dx
= xx1
- xxc
;
1010 double dy
= yy1
- yyc
;
1011 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
1012 wxCoord rad
= (wxCoord
)radius
;
1013 double radius1
, radius2
;
1014 if (xx1
== xx2
&& yy1
== yy2
)
1019 else if (radius
== 0.0)
1021 radius1
= radius2
= 0.0;
1025 radius1
= (xx1
- xxc
== 0) ?
1026 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1027 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1028 radius2
= (xx2
- xxc
== 0) ?
1029 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1030 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1032 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1033 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1034 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1037 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1038 CGContextRef ctx
= mctx
->GetNativeContext() ;
1039 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1040 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1043 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1044 double sa
, double ea
)
1046 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1048 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1049 // we have to make sure that the filling is always counter-clockwise
1052 wxCoord xx
= XLOG2DEVMAC(x
);
1053 wxCoord yy
= YLOG2DEVMAC(y
);
1054 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1055 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1056 // handle -ve width and/or height
1057 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1058 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1059 sa
= wxConvertWXangleToMACangle(sa
);
1060 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1061 CGContextRef ctx
= mctx
->GetNativeContext() ;
1062 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1063 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1066 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1068 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1069 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1072 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1073 wxCoord xoffset
, wxCoord yoffset
)
1075 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1077 wxCoord x1
, x2
, y1
, y2
;
1078 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1079 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1080 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1081 path
->MoveToPoint( x1
, y1
) ;
1082 for (int i
= 1; i
< n
; i
++)
1084 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1085 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1087 path
->AddLineToPoint( x2
, y2
) ;
1089 m_graphicContext
->StrokePath( path
) ;
1093 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1094 wxCoord xoffset
, wxCoord yoffset
,
1097 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1098 wxCoord x1
, x2
, y1
, y2
;
1099 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1102 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1103 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1105 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1106 path
->MoveToPoint( x1
, y1
) ;
1107 for (int i
= 1; i
< n
; i
++)
1109 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1110 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1112 path
->AddLineToPoint( x2
, y2
) ;
1114 if ( x1
!= x2
|| y1
!= y2
)
1116 path
->AddLineToPoint( x1
,y1
) ;
1118 path
->CloseSubpath() ;
1119 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1123 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1125 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1126 wxCoord xx
= XLOG2DEVMAC(x
);
1127 wxCoord yy
= YLOG2DEVMAC(y
);
1128 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1129 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1130 // CMB: draw nothing if transformed w or h is 0
1131 if (ww
== 0 || hh
== 0)
1133 // CMB: handle -ve width and/or height
1144 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1145 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1146 m_graphicContext
->DrawPath( path
) ;
1150 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1151 wxCoord width
, wxCoord height
,
1154 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1156 radius
= - radius
* ((width
< height
) ? width
: height
);
1157 wxCoord xx
= XLOG2DEVMAC(x
);
1158 wxCoord yy
= YLOG2DEVMAC(y
);
1159 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1160 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1161 // CMB: draw nothing if transformed w or h is 0
1162 if (ww
== 0 || hh
== 0)
1164 // CMB: handle -ve width and/or height
1175 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1176 CGContextRef ctx
= mctx
->GetNativeContext() ;
1177 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1178 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1181 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1183 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1184 wxCoord xx
= XLOG2DEVMAC(x
);
1185 wxCoord yy
= YLOG2DEVMAC(y
);
1186 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1187 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1188 // CMB: draw nothing if transformed w or h is 0
1189 if (ww
== 0 || hh
== 0)
1191 // CMB: handle -ve width and/or height
1203 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1204 CGContextRef ctx
= mctx
->GetNativeContext() ;
1205 if ( width
== height
)
1207 CGContextBeginPath(ctx
);
1208 CGContextAddArc(ctx
,
1215 CGContextClosePath(ctx
);
1217 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1221 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1222 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1226 bool wxDC::CanDrawBitmap(void) const
1231 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1232 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1233 wxCoord xsrcMask
, wxCoord ysrcMask
)
1235 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1236 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1237 if ( logical_func
== wxNO_OP
)
1239 if (xsrcMask
== -1 && ysrcMask
== -1)
1241 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1244 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1245 if ( memdc
&& logical_func
== wxCOPY
)
1247 wxBitmap blit
= memdc
->GetSelectedObject() ;
1248 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1250 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1251 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1252 wxCoord ww
= XLOG2DEVREL(width
);
1253 wxCoord hh
= YLOG2DEVREL(height
);
1255 wxCoord bmpwidth
= blit
.GetWidth();
1256 wxCoord bmpheight
= blit
.GetHeight();
1258 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1260 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1261 blit
= blit
.GetSubBitmap( subrect
) ;
1264 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1265 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1266 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1267 HIViewDrawCGImage( cg
, &r
, image
) ;
1268 CGImageRelease( image
) ;
1273 return FALSE
; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1278 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1281 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1283 if ( str
.Length() == 0 )
1286 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1288 OSStatus status
= noErr
;
1289 ATSUTextLayout atsuLayout
;
1290 UniCharCount chars
= str
.Length() ;
1291 UniChar
* ubuf
= NULL
;
1292 #if SIZEOF_WCHAR_T == 4
1293 wxMBConvUTF16BE converter
;
1295 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1296 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1297 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1299 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1300 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1301 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1302 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1304 chars
= unicharlen
/ 2 ;
1307 ubuf
= (UniChar
*) str
.wc_str() ;
1309 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1310 chars
= wxWcslen( wchar
.data() ) ;
1311 ubuf
= (UniChar
*) wchar
.data() ;
1315 int drawX
= XLOG2DEVMAC(x
) ;
1316 int drawY
= YLOG2DEVMAC(y
) ;
1318 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1319 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1321 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1322 int iAngle
= int( angle
);
1326 if ( abs(iAngle
) > 0 )
1328 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1329 ATSUAttributeTag atsuTags
[] =
1331 kATSULineRotationTag
,
1333 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1337 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1341 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1342 atsuTags
, atsuSizes
, atsuValues
) ;
1345 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1346 ATSUAttributeTag atsuTags
[] =
1350 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1352 sizeof( CGContextRef
) ,
1354 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1358 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1359 atsuTags
, atsuSizes
, atsuValues
) ;
1362 ATSUTextMeasurement textBefore
;
1363 ATSUTextMeasurement textAfter
;
1364 ATSUTextMeasurement ascent
;
1365 ATSUTextMeasurement descent
;
1367 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1368 &textBefore
, &textAfter
, &ascent
, &descent
);
1369 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1373 if ( m_backgroundMode
== wxSOLID
)
1375 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1379 path
->AddLineToPoint(
1380 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1381 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1382 path
->AddLineToPoint(
1383 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1384 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1385 path
->AddLineToPoint(
1386 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1387 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1389 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1393 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1394 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1396 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1397 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1398 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1400 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1401 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1402 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1403 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1404 IntToFixed(0) , IntToFixed(0) );
1405 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1406 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1408 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1409 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1411 ::ATSUDisposeTextLayout(atsuLayout
);
1412 #if SIZEOF_WCHAR_T == 4
1417 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1419 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1420 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1423 bool wxDC::CanGetTextExtent() const
1425 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1429 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1430 wxCoord
*descent
, wxCoord
*externalLeading
,
1431 wxFont
*theFont
) const
1433 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1434 wxFont formerFont
= m_font
;
1437 // work around the constness
1438 *((wxFont
*)(&m_font
)) = *theFont
;
1442 if ( str
.Length() == 0 )
1445 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1447 OSStatus status
= noErr
;
1448 ATSUTextLayout atsuLayout
;
1449 UniCharCount chars
= str
.Length() ;
1450 UniChar
* ubuf
= NULL
;
1451 #if SIZEOF_WCHAR_T == 4
1452 wxMBConvUTF16BE converter
;
1454 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1455 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1456 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1458 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1459 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1460 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1461 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1463 chars
= unicharlen
/ 2 ;
1466 ubuf
= (UniChar
*) str
.wc_str() ;
1468 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1469 chars
= wxWcslen( wchar
.data() ) ;
1470 ubuf
= (UniChar
*) wchar
.data() ;
1475 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1476 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1478 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1480 ATSUTextMeasurement textBefore
;
1481 ATSUTextMeasurement textAfter
;
1482 ATSUTextMeasurement textAscent
;
1483 ATSUTextMeasurement textDescent
;
1485 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1486 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1489 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1491 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1492 if ( externalLeading
)
1493 *externalLeading
= 0 ;
1495 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1497 ::ATSUDisposeTextLayout(atsuLayout
);
1498 #if SIZEOF_WCHAR_T == 4
1503 // work around the constness
1504 *((wxFont
*)(&m_font
)) = formerFont
;
1510 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1512 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1515 widths
.Add(0, text
.Length());
1517 if (text
.Length() == 0)
1520 ATSUTextLayout atsuLayout
;
1521 UniCharCount chars
= text
.Length() ;
1522 UniChar
* ubuf
= NULL
;
1523 #if SIZEOF_WCHAR_T == 4
1524 wxMBConvUTF16BE converter
;
1526 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1527 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1528 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1530 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1531 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1532 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1533 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1535 chars
= unicharlen
/ 2 ;
1538 ubuf
= (UniChar
*) text
.wc_str() ;
1540 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1541 chars
= wxWcslen( wchar
.data() ) ;
1542 ubuf
= (UniChar
*) wchar
.data() ;
1547 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1548 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1550 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1551 unsigned long actualNumberOfBounds
= 0;
1552 ATSTrapezoid glyphBounds
;
1554 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1556 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1557 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1562 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1563 //unsigned char uch = s[i];
1566 ::ATSUDisposeTextLayout(atsuLayout
);
1570 wxCoord
wxDC::GetCharWidth(void) const
1573 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1577 wxCoord
wxDC::GetCharHeight(void) const
1580 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1584 void wxDC::Clear(void)
1586 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1588 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1590 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1591 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1592 switch( m_backgroundBrush
.MacGetBrushKind() )
1594 case kwxMacBrushTheme
:
1596 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1597 if ( HIThemeSetFill
!= 0 )
1599 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1600 CGContextFillRect(cg
, rect
);
1607 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1608 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1609 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1610 CGContextFillRect( cg
, rect
);
1612 // reset to normal value
1613 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1614 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1617 case kwxMacBrushThemeBackground
:
1619 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1620 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1621 if ( HIThemeDrawBackground
!= 0 )
1623 HIThemeBackgroundDrawInfo drawInfo
;
1624 drawInfo
.version
= 0 ;
1625 drawInfo
.state
= kThemeStateActive
;
1626 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1627 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1628 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1629 kHIThemeOrientationNormal
) ;
1630 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1631 kHIThemeOrientationNormal
) ;
1639 case kwxMacBrushColour
:
1641 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1642 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1643 CGContextFillRect(cg
, rect
);
1645 // reset to normal value
1646 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1647 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1654 void wxDC::MacInstallFont() const
1656 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1658 if( m_macATSUIStyle
)
1660 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1661 m_macATSUIStyle
= NULL
;
1664 OSStatus status
= noErr
;
1665 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1666 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1668 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1669 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1670 ATSUAttributeTag atsuTags
[] =
1675 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1678 sizeof( RGBColor
) ,
1680 // Boolean kTrue = true ;
1681 // Boolean kFalse = false ;
1683 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1684 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1689 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1690 atsuTags
, atsuSizes
, atsuValues
);
1692 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1695 // ---------------------------------------------------------------------------
1696 // coordinates transformations
1697 // ---------------------------------------------------------------------------
1699 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1701 return ((wxDC
*)this)->XDEV2LOG(x
);
1704 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1706 return ((wxDC
*)this)->YDEV2LOG(y
);
1709 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1711 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1714 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1716 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1719 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1721 return ((wxDC
*)this)->XLOG2DEV(x
);
1724 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1726 return ((wxDC
*)this)->YLOG2DEV(y
);
1729 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1731 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1734 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1736 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1739 #endif // wxMAC_USE_CORE_GRAPHICS