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 if ( m_logicalFunction
!= wxCOPY
)
943 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
944 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
945 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
946 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
948 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
949 path
->MoveToPoint( xx1
, yy1
) ;
950 path
->AddLineToPoint( xx2
, yy2
) ;
951 path
->CloseSubpath() ;
952 m_graphicContext
->StrokePath( path
) ;
955 CalcBoundingBox(x1
, y1
);
956 CalcBoundingBox(x2
, y2
);
959 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
961 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
963 if ( m_logicalFunction
!= wxCOPY
)
969 wxCoord xx
= XLOG2DEVMAC(x
);
970 wxCoord yy
= YLOG2DEVMAC(y
);
972 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
973 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
974 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
975 path
->CloseSubpath() ;
976 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
977 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
978 path
->CloseSubpath() ;
979 m_graphicContext
->StrokePath( path
) ;
982 CalcBoundingBox(x
, y
);
983 CalcBoundingBox(x
+w
, y
+h
);
987 * To draw arcs properly the angles need to be converted from the WX style:
988 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
989 * a normal axis on paper).
992 * Angles start on the +ve y axis and go clockwise.
995 static double wxConvertWXangleToMACangle(double angle
)
997 double newAngle
= 90 - angle
;
1003 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
1004 wxCoord x2
, wxCoord y2
,
1005 wxCoord xc
, wxCoord yc
)
1007 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1009 if ( m_logicalFunction
!= wxCOPY
)
1012 wxCoord xx1
= XLOG2DEVMAC(x1
);
1013 wxCoord yy1
= YLOG2DEVMAC(y1
);
1014 wxCoord xx2
= XLOG2DEVMAC(x2
);
1015 wxCoord yy2
= YLOG2DEVMAC(y2
);
1016 wxCoord xxc
= XLOG2DEVMAC(xc
);
1017 wxCoord yyc
= YLOG2DEVMAC(yc
);
1018 double dx
= xx1
- xxc
;
1019 double dy
= yy1
- yyc
;
1020 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
1021 wxCoord rad
= (wxCoord
)radius
;
1022 double radius1
, radius2
;
1023 if (xx1
== xx2
&& yy1
== yy2
)
1028 else if (radius
== 0.0)
1030 radius1
= radius2
= 0.0;
1034 radius1
= (xx1
- xxc
== 0) ?
1035 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1036 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1037 radius2
= (xx2
- xxc
== 0) ?
1038 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1039 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1041 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1042 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1043 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1046 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1047 CGContextRef ctx
= mctx
->GetNativeContext() ;
1048 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1049 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1052 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1053 double sa
, double ea
)
1055 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1057 if ( m_logicalFunction
!= wxCOPY
)
1060 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1061 // we have to make sure that the filling is always counter-clockwise
1064 wxCoord xx
= XLOG2DEVMAC(x
);
1065 wxCoord yy
= YLOG2DEVMAC(y
);
1066 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1067 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1068 // handle -ve width and/or height
1069 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1070 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1071 sa
= wxConvertWXangleToMACangle(sa
);
1072 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1073 CGContextRef ctx
= mctx
->GetNativeContext() ;
1074 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1075 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1078 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1080 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1081 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1084 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1085 wxCoord xoffset
, wxCoord yoffset
)
1087 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1089 if ( m_logicalFunction
!= wxCOPY
)
1092 wxCoord x1
, x2
, y1
, y2
;
1093 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1094 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1095 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1096 path
->MoveToPoint( x1
, y1
) ;
1097 for (int i
= 1; i
< n
; i
++)
1099 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1100 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1102 path
->AddLineToPoint( x2
, y2
) ;
1104 m_graphicContext
->StrokePath( path
) ;
1108 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1109 wxCoord xoffset
, wxCoord yoffset
,
1112 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1113 wxCoord x1
, x2
, y1
, y2
;
1114 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1117 if ( m_logicalFunction
!= wxCOPY
)
1120 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1121 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1123 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1124 path
->MoveToPoint( x1
, y1
) ;
1125 for (int i
= 1; i
< n
; i
++)
1127 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1128 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1130 path
->AddLineToPoint( x2
, y2
) ;
1132 if ( x1
!= x2
|| y1
!= y2
)
1134 path
->AddLineToPoint( x1
,y1
) ;
1136 path
->CloseSubpath() ;
1137 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1141 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1143 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1145 if ( m_logicalFunction
!= wxCOPY
)
1148 wxCoord xx
= XLOG2DEVMAC(x
);
1149 wxCoord yy
= YLOG2DEVMAC(y
);
1150 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1151 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1152 // CMB: draw nothing if transformed w or h is 0
1153 if (ww
== 0 || hh
== 0)
1155 // CMB: handle -ve width and/or height
1166 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1167 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1168 m_graphicContext
->DrawPath( path
) ;
1172 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1173 wxCoord width
, wxCoord height
,
1176 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1178 if ( m_logicalFunction
!= wxCOPY
)
1183 radius
= - radius
* ((width
< height
) ? width
: height
);
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
1202 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1203 CGContextRef ctx
= mctx
->GetNativeContext() ;
1204 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1205 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1208 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1210 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1212 if ( m_logicalFunction
!= wxCOPY
)
1215 wxCoord xx
= XLOG2DEVMAC(x
);
1216 wxCoord yy
= YLOG2DEVMAC(y
);
1217 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1218 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1219 // CMB: draw nothing if transformed w or h is 0
1220 if (ww
== 0 || hh
== 0)
1222 // CMB: handle -ve width and/or height
1234 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1235 CGContextRef ctx
= mctx
->GetNativeContext() ;
1236 if ( width
== height
)
1238 CGContextBeginPath(ctx
);
1239 CGContextAddArc(ctx
,
1246 CGContextClosePath(ctx
);
1248 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1252 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1253 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1257 bool wxDC::CanDrawBitmap(void) const
1262 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1263 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1264 wxCoord xsrcMask
, wxCoord ysrcMask
)
1266 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1267 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1268 if ( logical_func
== wxNO_OP
)
1270 if (xsrcMask
== -1 && ysrcMask
== -1)
1272 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1275 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1276 if ( memdc
&& logical_func
== wxCOPY
)
1278 wxBitmap blit
= memdc
->GetSelectedObject() ;
1279 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1281 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1282 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1283 wxCoord ww
= XLOG2DEVREL(width
);
1284 wxCoord hh
= YLOG2DEVREL(height
);
1286 wxCoord bmpwidth
= blit
.GetWidth();
1287 wxCoord bmpheight
= blit
.GetHeight();
1289 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1291 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1292 blit
= blit
.GetSubBitmap( subrect
) ;
1295 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1296 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1297 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1298 HIViewDrawCGImage( cg
, &r
, image
) ;
1299 CGImageRelease( image
) ;
1304 return FALSE
; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1309 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1312 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1314 if ( str
.Length() == 0 )
1317 if ( m_logicalFunction
!= wxCOPY
)
1320 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1322 OSStatus status
= noErr
;
1323 ATSUTextLayout atsuLayout
;
1324 UniCharCount chars
= str
.Length() ;
1325 UniChar
* ubuf
= NULL
;
1326 #if SIZEOF_WCHAR_T == 4
1327 wxMBConvUTF16BE converter
;
1329 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1330 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1331 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1333 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1334 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1335 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1336 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1338 chars
= unicharlen
/ 2 ;
1341 ubuf
= (UniChar
*) str
.wc_str() ;
1343 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1344 chars
= wxWcslen( wchar
.data() ) ;
1345 ubuf
= (UniChar
*) wchar
.data() ;
1349 int drawX
= XLOG2DEVMAC(x
) ;
1350 int drawY
= YLOG2DEVMAC(y
) ;
1352 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1353 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1355 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1356 int iAngle
= int( angle
);
1360 if ( abs(iAngle
) > 0 )
1362 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1363 ATSUAttributeTag atsuTags
[] =
1365 kATSULineRotationTag
,
1367 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1371 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1375 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1376 atsuTags
, atsuSizes
, atsuValues
) ;
1379 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1380 ATSUAttributeTag atsuTags
[] =
1384 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1386 sizeof( CGContextRef
) ,
1388 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1392 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1393 atsuTags
, atsuSizes
, atsuValues
) ;
1396 ATSUTextMeasurement textBefore
;
1397 ATSUTextMeasurement textAfter
;
1398 ATSUTextMeasurement ascent
;
1399 ATSUTextMeasurement descent
;
1401 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1402 &textBefore
, &textAfter
, &ascent
, &descent
);
1403 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1407 if ( m_backgroundMode
== wxSOLID
)
1409 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1413 path
->AddLineToPoint(
1414 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1415 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1416 path
->AddLineToPoint(
1417 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1418 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1419 path
->AddLineToPoint(
1420 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1421 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1423 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1427 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1428 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1430 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1431 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1432 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1434 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1435 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1436 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1437 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1438 IntToFixed(0) , IntToFixed(0) );
1439 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1440 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1442 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1443 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1445 ::ATSUDisposeTextLayout(atsuLayout
);
1446 #if SIZEOF_WCHAR_T == 4
1451 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1453 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1454 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1457 bool wxDC::CanGetTextExtent() const
1459 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1463 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1464 wxCoord
*descent
, wxCoord
*externalLeading
,
1465 wxFont
*theFont
) const
1467 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1468 wxFont formerFont
= m_font
;
1471 // work around the constness
1472 *((wxFont
*)(&m_font
)) = *theFont
;
1476 if ( str
.Length() == 0 )
1479 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1481 OSStatus status
= noErr
;
1482 ATSUTextLayout atsuLayout
;
1483 UniCharCount chars
= str
.Length() ;
1484 UniChar
* ubuf
= NULL
;
1485 #if SIZEOF_WCHAR_T == 4
1486 wxMBConvUTF16BE converter
;
1488 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1489 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1490 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1492 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1493 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1494 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1495 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1497 chars
= unicharlen
/ 2 ;
1500 ubuf
= (UniChar
*) str
.wc_str() ;
1502 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1503 chars
= wxWcslen( wchar
.data() ) ;
1504 ubuf
= (UniChar
*) wchar
.data() ;
1509 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1510 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1512 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1514 ATSUTextMeasurement textBefore
;
1515 ATSUTextMeasurement textAfter
;
1516 ATSUTextMeasurement textAscent
;
1517 ATSUTextMeasurement textDescent
;
1519 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1520 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1523 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1525 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1526 if ( externalLeading
)
1527 *externalLeading
= 0 ;
1529 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1531 ::ATSUDisposeTextLayout(atsuLayout
);
1532 #if SIZEOF_WCHAR_T == 4
1537 // work around the constness
1538 *((wxFont
*)(&m_font
)) = formerFont
;
1544 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1546 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1549 widths
.Add(0, text
.Length());
1551 if (text
.Length() == 0)
1554 ATSUTextLayout atsuLayout
;
1555 UniCharCount chars
= text
.Length() ;
1556 UniChar
* ubuf
= NULL
;
1557 #if SIZEOF_WCHAR_T == 4
1558 wxMBConvUTF16BE converter
;
1560 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1561 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1562 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1564 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1565 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1566 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1567 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1569 chars
= unicharlen
/ 2 ;
1572 ubuf
= (UniChar
*) text
.wc_str() ;
1574 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1575 chars
= wxWcslen( wchar
.data() ) ;
1576 ubuf
= (UniChar
*) wchar
.data() ;
1581 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1582 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1584 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1585 unsigned long actualNumberOfBounds
= 0;
1586 ATSTrapezoid glyphBounds
;
1588 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1590 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1591 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1596 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1597 //unsigned char uch = s[i];
1600 ::ATSUDisposeTextLayout(atsuLayout
);
1604 wxCoord
wxDC::GetCharWidth(void) const
1607 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1611 wxCoord
wxDC::GetCharHeight(void) const
1614 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1618 void wxDC::Clear(void)
1620 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1622 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1624 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1625 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1626 switch( m_backgroundBrush
.MacGetBrushKind() )
1628 case kwxMacBrushTheme
:
1630 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1631 if ( HIThemeSetFill
!= 0 )
1633 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1634 CGContextFillRect(cg
, rect
);
1641 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1642 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1643 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1644 CGContextFillRect( cg
, rect
);
1646 // reset to normal value
1647 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1648 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1651 case kwxMacBrushThemeBackground
:
1653 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1654 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1655 if ( HIThemeDrawBackground
!= 0 )
1657 HIThemeBackgroundDrawInfo drawInfo
;
1658 drawInfo
.version
= 0 ;
1659 drawInfo
.state
= kThemeStateActive
;
1660 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1661 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1662 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1663 kHIThemeOrientationNormal
) ;
1664 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1665 kHIThemeOrientationNormal
) ;
1673 case kwxMacBrushColour
:
1675 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1676 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1677 CGContextFillRect(cg
, rect
);
1679 // reset to normal value
1680 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1681 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1688 void wxDC::MacInstallFont() const
1690 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1692 if( m_macATSUIStyle
)
1694 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1695 m_macATSUIStyle
= NULL
;
1698 OSStatus status
= noErr
;
1699 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1700 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1702 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1703 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1704 ATSUAttributeTag atsuTags
[] =
1709 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1712 sizeof( RGBColor
) ,
1714 // Boolean kTrue = true ;
1715 // Boolean kFalse = false ;
1717 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1718 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1723 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1724 atsuTags
, atsuSizes
, atsuValues
);
1726 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1729 // ---------------------------------------------------------------------------
1730 // coordinates transformations
1731 // ---------------------------------------------------------------------------
1733 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1735 return ((wxDC
*)this)->XDEV2LOG(x
);
1738 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1740 return ((wxDC
*)this)->YDEV2LOG(y
);
1743 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1745 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1748 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1750 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1753 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1755 return ((wxDC
*)this)->XLOG2DEV(x
);
1758 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1760 return ((wxDC
*)this)->YLOG2DEV(y
);
1763 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1765 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1768 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1770 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1773 #endif // wxMAC_USE_CORE_GRAPHICS