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 //-----------------------------------------------------------------------------
110 //-----------------------------------------------------------------------------
112 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
113 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
114 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
116 //-----------------------------------------------------------------------------
117 // device context implementation
119 // more and more of the dc functionality should be implemented by calling
120 // the appropricate wxMacCGContext, but we will have to do that step by step
121 // also coordinate conversions should be moved to native matrix ops
122 //-----------------------------------------------------------------------------
124 wxMacCGPath::wxMacCGPath()
126 m_path
= CGPathCreateMutable() ;
129 wxMacCGPath::~wxMacCGPath()
131 CGPathRelease( m_path
) ;
134 // Starts a new subpath at
135 void wxMacCGPath::MoveToPoint( wxCoord x1
, wxCoord y1
)
137 CGPathMoveToPoint( m_path
, NULL
, x1
, y1
) ;
140 void wxMacCGPath::AddLineToPoint( wxCoord x1
, wxCoord y1
)
142 CGPathAddLineToPoint( m_path
, NULL
, x1
, y1
) ;
145 void wxMacCGPath::AddRectangle( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
147 CGRect cgRect
= { { x
, y
} , { w
, h
} } ;
148 CGPathAddRect( m_path
, NULL
, cgRect
) ;
151 void wxMacCGPath::AddCircle( wxCoord x
, wxCoord y
, wxCoord r
)
153 CGPathAddArc( m_path
, NULL
, x
, y
, r
, 0.0 , 2 * M_PI
, true ) ;
156 // closes the current subpath
157 void wxMacCGPath::CloseSubpath()
159 CGPathCloseSubpath( m_path
) ;
162 CGPathRef
wxMacCGPath::GetPath() const
167 // we always stock two context states, one at entry, the other one after
168 // changing to HI Graphics orientation (this one is used for getting back clippings etc)
170 wxMacCGContext::wxMacCGContext( CGrafPtr port
)
176 wxMacCGContext::wxMacCGContext( CGContextRef cgcontext
)
179 m_cgContext
= cgcontext
;
180 CGContextSaveGState( m_cgContext
) ;
181 CGContextSaveGState( m_cgContext
) ;
184 wxMacCGContext::wxMacCGContext()
190 wxMacCGContext::~wxMacCGContext()
194 CGContextRestoreGState( m_cgContext
) ;
195 CGContextRestoreGState( m_cgContext
) ;
198 QDEndCGContext( m_qdPort
, &m_cgContext
) ;
202 void wxMacCGContext::Clip( const wxRegion
®ion
)
204 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
207 void wxMacCGContext::StrokePath( const wxGraphicPath
*p
)
209 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
210 CGContextBeginPath( m_cgContext
) ;
211 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
212 CGContextClosePath( m_cgContext
) ;
213 CGContextStrokePath( m_cgContext
) ;
216 void wxMacCGContext::DrawPath( const wxGraphicPath
*p
, int fillStyle
)
218 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
219 CGPathDrawingMode mode
= m_mode
;
220 if ( fillStyle
== wxODDEVEN_RULE
)
222 if ( mode
== kCGPathFill
)
223 mode
= kCGPathEOFill
;
224 else if ( mode
== kCGPathFillStroke
)
225 mode
= kCGPathEOFillStroke
;
227 CGContextBeginPath( m_cgContext
) ;
228 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
229 CGContextClosePath( m_cgContext
) ;
230 CGContextDrawPath( m_cgContext
, mode
) ;
233 void wxMacCGContext::FillPath( const wxGraphicPath
*p
, const wxColor
&fillColor
, int fillStyle
)
235 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
236 CGContextSaveGState( m_cgContext
) ;
238 RGBColor col
= MAC_WXCOLORREF( fillColor
.GetPixel() ) ;
239 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
240 CGPathDrawingMode mode
= kCGPathFill
;
242 if ( fillStyle
== wxODDEVEN_RULE
)
243 mode
= kCGPathEOFill
;
245 CGContextBeginPath( m_cgContext
) ;
246 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
247 CGContextClosePath( m_cgContext
) ;
248 CGContextDrawPath( m_cgContext
, mode
) ;
250 CGContextRestoreGState( m_cgContext
) ;
253 wxGraphicPath
* wxMacCGContext::CreatePath()
255 CGContextRef cg
= GetNativeContext() ;
256 // make sure that we now have a real cgref, before doing
257 // anything with paths
258 return new wxMacCGPath() ;
261 // in case we only got a QDPort only create a cgref now
263 CGContextRef
wxMacCGContext::GetNativeContext()
265 if( m_cgContext
== NULL
)
268 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
269 OSStatus status
= QDBeginCGContext( (CGrafPtr
) m_qdPort
, &m_cgContext
) ;
270 CGContextSaveGState( m_cgContext
) ;
272 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
273 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
274 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
276 CGContextSaveGState( m_cgContext
) ;
278 SetBrush( m_brush
) ;
283 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
285 wxASSERT( m_cgContext
== NULL
) ;
287 CGContextSaveGState( m_cgContext
) ;
290 void wxMacCGContext::SetPen( const wxPen
&pen
)
293 if ( m_cgContext
== NULL
)
295 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
296 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
299 // we can benchmark performance, should go into a setting later
300 CGContextSetShouldAntialias( m_cgContext
, false ) ;
305 m_mode
= kCGPathFill
; // just a default
309 m_mode
= kCGPathFill
;
313 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
314 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
317 switch( pen
.GetCap() )
320 cap
= kCGLineCapRound
;
322 case wxCAP_PROJECTING
:
323 cap
= kCGLineCapSquare
;
326 cap
= kCGLineCapButt
;
329 cap
= kCGLineCapButt
;
332 CGContextSetLineCap( m_cgContext
, cap
) ;
335 switch( pen
.GetJoin() )
338 join
= kCGLineJoinBevel
;
341 join
= kCGLineJoinMiter
;
344 join
= kCGLineJoinRound
;
347 join
= kCGLineJoinMiter
;
350 CGContextSetLineJoin( m_cgContext
, join
) ;
352 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
354 m_mode
= kCGPathStroke
;
356 const float *lengths
= NULL
;
357 float *userLengths
= NULL
;
359 const float dotted
[] = { 3 , 3 };
360 const float dashed
[] = { 19 , 9 };
361 const float short_dashed
[] = { 9 , 6 };
362 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
364 switch( pen
.GetStyle() )
370 count
= WXSIZEOF(dotted
);
374 count
= WXSIZEOF(dashed
) ;
377 lengths
= short_dashed
;
378 count
= WXSIZEOF(short_dashed
) ;
381 lengths
= dotted_dashed
;
382 count
= WXSIZEOF(dotted_dashed
);
386 count
= pen
.GetDashes( &dashes
) ;
389 userLengths
= new float[count
] ;
390 for( int i
= 0 ; i
< count
; ++i
)
391 userLengths
[i
] = dashes
[i
] ;
393 lengths
= userLengths
;
399 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
400 delete[] userLengths
;
401 // we need to change the cap, otherwise everything overlaps
402 // and we get solid lines
404 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
406 if ( fill
&& stroke
)
408 m_mode
= kCGPathFillStroke
;
413 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
416 if ( m_cgContext
== NULL
)
419 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
420 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
423 // we can benchmark performance, should go into a setting later
424 CGContextSetShouldAntialias( m_cgContext
, false ) ;
430 m_mode
= kCGPathFill
; // just a default
434 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
435 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
436 m_mode
= kCGPathFill
;
440 m_mode
= kCGPathStroke
;
442 if ( fill
&& stroke
)
444 m_mode
= kCGPathFillStroke
;
450 // snippets from Sketch Sample from Apple :
452 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
454 This function locates, opens, and returns the profile reference for the calibrated
455 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
456 with the profile reference this function returns.
458 CMProfileRef
wxMacOpenGenericProfile(void)
460 static CMProfileRef cachedRGBProfileRef
= NULL
;
462 // we only create the profile reference once
463 if (cachedRGBProfileRef
== NULL
)
465 CMProfileLocation loc
;
467 loc
.locType
= cmPathBasedProfile
;
468 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
470 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
473 if (cachedRGBProfileRef
)
475 // clone the profile reference so that the caller has their own reference, not our cached one
476 CMCloneProfileRef(cachedRGBProfileRef
);
479 return cachedRGBProfileRef
;
483 Return the generic RGB color space. This is a 'get' function and the caller should
484 not release the returned value unless the caller retains it first. Usually callers
485 of this routine will immediately use the returned colorspace with CoreGraphics
486 so they typically do not need to retain it themselves.
488 This function creates the generic RGB color space once and hangs onto it so it can
489 return it whenever this function is called.
492 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
494 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
496 if (genericRGBColorSpace
== NULL
)
498 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
500 if (genericRGBProfile
)
502 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
503 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
505 // we opened the profile so it is up to us to close it
506 CMCloseProfile(genericRGBProfile
);
509 return genericRGBColorSpace
;
512 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
514 CGContextSaveGState(c
);
515 CGContextTranslateCTM(c
, center
.x
, center
.y
);
516 CGContextScaleCTM(c
, a
, b
);
517 CGContextMoveToPoint(c
, 1, 0);
518 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
519 CGContextClosePath(c
);
520 CGContextRestoreGState(c
);
523 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
527 if (ovalWidth
== 0 || ovalHeight
== 0)
529 CGContextAddRect(c
, rect
);
532 CGContextSaveGState(c
);
533 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
534 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
535 fw
= CGRectGetWidth(rect
) / ovalWidth
;
536 fh
= CGRectGetHeight(rect
) / ovalHeight
;
537 CGContextMoveToPoint(c
, fw
, fh
/2);
538 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
539 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
540 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
541 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
542 CGContextClosePath(c
);
543 CGContextRestoreGState(c
);
550 m_mm_to_pix_x
= mm2pt
;
551 m_mm_to_pix_y
= mm2pt
;
552 m_internalDeviceOriginX
= 0;
553 m_internalDeviceOriginY
= 0;
554 m_externalDeviceOriginX
= 0;
555 m_externalDeviceOriginY
= 0;
556 m_logicalScaleX
= 1.0;
557 m_logicalScaleY
= 1.0;
562 m_needComputeScaleX
= FALSE
;
563 m_needComputeScaleY
= FALSE
;
567 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
569 m_pen
= *wxBLACK_PEN
;
570 m_font
= *wxNORMAL_FONT
;
571 m_brush
= *wxWHITE_BRUSH
;
573 m_macATSUIStyle
= NULL
;
575 m_graphicContext
= NULL
;
580 if( m_macATSUIStyle
)
582 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
583 m_macATSUIStyle
= NULL
;
586 delete m_graphicContext
;
589 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
591 wxCHECK_RET( Ok(), wxT("invalid window dc") );
592 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
593 wxCoord xx
= XLOG2DEVMAC(x
);
594 wxCoord yy
= YLOG2DEVMAC(y
);
595 wxCoord w
= bmp
.GetWidth();
596 wxCoord h
= bmp
.GetHeight();
597 wxCoord ww
= XLOG2DEVREL(w
);
598 wxCoord hh
= YLOG2DEVREL(h
);
600 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
601 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
602 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
603 HIViewDrawCGImage( cg
, &r
, image
) ;
604 CGImageRelease( image
) ;
607 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
609 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
610 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
612 wxCoord xx
= XLOG2DEVMAC(x
);
613 wxCoord yy
= YLOG2DEVMAC(y
);
614 wxCoord w
= icon
.GetWidth();
615 wxCoord h
= icon
.GetHeight();
616 wxCoord ww
= XLOG2DEVREL(w
);
617 wxCoord hh
= YLOG2DEVREL(h
);
619 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
620 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
621 CGContextSaveGState(cg
);
622 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
623 CGContextScaleCTM(cg
, 1, -1);
624 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
625 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
626 CGContextRestoreGState( cg
) ;
629 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
631 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
632 wxCoord xx
, yy
, ww
, hh
;
635 ww
= XLOG2DEVREL(width
);
636 hh
= YLOG2DEVREL(height
);
638 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
639 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
640 CGContextClipToRect( cgContext
, clipRect
) ;
642 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
643 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
646 m_clipX1
= wxMax( m_clipX1
, xx
);
647 m_clipY1
= wxMax( m_clipY1
, yy
);
648 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
649 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
659 // TODO as soon as we don't reset the context for each operation anymore
660 // we have to update the context as well
663 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
665 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
668 DestroyClippingRegion();
672 region
.GetBox( x
, y
, w
, h
);
673 wxCoord xx
, yy
, ww
, hh
;
678 // if we have a scaling that we cannot map onto native regions
679 // we must use the box
680 if ( ww
!= w
|| hh
!= h
)
682 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
687 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
688 if ( xx != x || yy != y )
690 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
692 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
696 m_clipX1
= wxMax( m_clipX1
, xx
);
697 m_clipY1
= wxMax( m_clipY1
, yy
);
698 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
699 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
712 void wxDC::DestroyClippingRegion()
714 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
715 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
716 CGContextRestoreGState( cgContext
);
717 CGContextSaveGState( cgContext
);
719 SetBrush( m_brush
) ;
723 void wxDC::DoGetSizeMM( int* width
, int* height
) const
728 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
729 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
732 void wxDC::SetTextForeground( const wxColour
&col
)
734 wxCHECK_RET(Ok(), wxT("Invalid DC"));
735 if ( col
!= m_textForegroundColour
)
737 m_textForegroundColour
= col
;
742 void wxDC::SetTextBackground( const wxColour
&col
)
744 wxCHECK_RET(Ok(), wxT("Invalid DC"));
745 m_textBackgroundColour
= col
;
748 void wxDC::SetMapMode( int mode
)
753 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
756 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
759 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
762 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
766 SetLogicalScale( 1.0, 1.0 );
769 if (mode
!= wxMM_TEXT
)
771 m_needComputeScaleX
= TRUE
;
772 m_needComputeScaleY
= TRUE
;
776 void wxDC::SetUserScale( double x
, double y
)
778 // allow negative ? -> no
781 ComputeScaleAndOrigin();
784 void wxDC::SetLogicalScale( double x
, double y
)
789 ComputeScaleAndOrigin();
792 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
794 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
795 m_logicalOriginY
= y
* m_signY
;
796 ComputeScaleAndOrigin();
799 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
801 m_externalDeviceOriginX
= x
;
802 m_externalDeviceOriginY
= y
;
803 ComputeScaleAndOrigin();
806 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
808 m_signX
= (xLeftRight
? 1 : -1);
809 m_signY
= (yBottomUp
? -1 : 1);
810 ComputeScaleAndOrigin();
813 wxSize
wxDC::GetPPI() const
815 return wxSize(72, 72);
818 int wxDC::GetDepth() const
823 void wxDC::ComputeScaleAndOrigin()
825 // CMB: copy scale to see if it changes
826 double origScaleX
= m_scaleX
;
827 double origScaleY
= m_scaleY
;
828 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
829 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
830 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
831 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
832 // CMB: if scale has changed call SetPen to recalulate the line width
833 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
835 // this is a bit artificial, but we need to force wxDC to think
836 // the pen has changed
843 void wxDC::SetPalette( const wxPalette
& palette
)
847 void wxDC::SetBackgroundMode( int mode
)
849 m_backgroundMode
= mode
;
852 void wxDC::SetFont( const wxFont
&font
)
858 void wxDC::SetPen( const wxPen
&pen
)
863 if ( m_graphicContext
)
865 m_graphicContext
->SetPen( m_pen
) ;
869 void wxDC::SetBrush( const wxBrush
&brush
)
871 if (m_brush
== brush
)
874 if ( m_graphicContext
)
876 m_graphicContext
->SetBrush( m_brush
) ;
880 void wxDC::SetBackground( const wxBrush
&brush
)
882 if (m_backgroundBrush
== brush
)
884 m_backgroundBrush
= brush
;
885 if (!m_backgroundBrush
.Ok())
889 void wxDC::SetLogicalFunction( int function
)
891 if (m_logicalFunction
== function
)
893 m_logicalFunction
= function
;
896 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
897 const wxColour
& col
, int style
);
899 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
900 const wxColour
& col
, int style
)
902 return wxDoFloodFill(this, x
, y
, col
, style
);
905 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
907 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
908 wxFAIL_MSG( wxT("GetPixel not implemented on Core Graphics") ) ;
912 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
914 wxCHECK_RET(Ok(), wxT("Invalid DC"));
916 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
917 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
918 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
919 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
921 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
922 path
->MoveToPoint( xx1
, yy1
) ;
923 path
->AddLineToPoint( xx2
, yy2
) ;
924 path
->CloseSubpath() ;
925 m_graphicContext
->StrokePath( path
) ;
928 CalcBoundingBox(x1
, y1
);
929 CalcBoundingBox(x2
, y2
);
932 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
934 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
940 wxCoord xx
= XLOG2DEVMAC(x
);
941 wxCoord yy
= YLOG2DEVMAC(y
);
943 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
944 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
945 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
946 path
->CloseSubpath() ;
947 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
948 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
949 path
->CloseSubpath() ;
950 m_graphicContext
->StrokePath( path
) ;
953 CalcBoundingBox(x
, y
);
954 CalcBoundingBox(x
+w
, y
+h
);
958 * To draw arcs properly the angles need to be converted from the WX style:
959 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
960 * a normal axis on paper).
963 * Angles start on the +ve y axis and go clockwise.
966 static double wxConvertWXangleToMACangle(double angle
)
968 double newAngle
= 90 - angle
;
974 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
975 wxCoord x2
, wxCoord y2
,
976 wxCoord xc
, wxCoord yc
)
978 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
979 wxCoord xx1
= XLOG2DEVMAC(x1
);
980 wxCoord yy1
= YLOG2DEVMAC(y1
);
981 wxCoord xx2
= XLOG2DEVMAC(x2
);
982 wxCoord yy2
= YLOG2DEVMAC(y2
);
983 wxCoord xxc
= XLOG2DEVMAC(xc
);
984 wxCoord yyc
= YLOG2DEVMAC(yc
);
985 double dx
= xx1
- xxc
;
986 double dy
= yy1
- yyc
;
987 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
988 wxCoord rad
= (wxCoord
)radius
;
989 double radius1
, radius2
;
990 if (xx1
== xx2
&& yy1
== yy2
)
995 else if (radius
== 0.0)
997 radius1
= radius2
= 0.0;
1001 radius1
= (xx1
- xxc
== 0) ?
1002 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1003 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1004 radius2
= (xx2
- xxc
== 0) ?
1005 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1006 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1008 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1009 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1010 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1013 Rect r
= { yyc
- rad
, xxc
- rad
, yyc
+ rad
, xxc
+ rad
};
1014 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1015 CGContextRef ctx
= mctx
->GetNativeContext() ;
1016 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, 0 , 180 ) ;
1017 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1020 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1021 double sa
, double ea
)
1023 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1025 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1026 // we have to make sure that the filling is always counter-clockwise
1029 wxCoord xx
= XLOG2DEVMAC(x
);
1030 wxCoord yy
= YLOG2DEVMAC(y
);
1031 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1032 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1033 // handle -ve width and/or height
1034 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1035 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1036 sa
= wxConvertWXangleToMACangle(sa
);
1037 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1038 CGContextRef ctx
= mctx
->GetNativeContext() ;
1039 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1040 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1043 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1045 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1046 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1049 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1050 wxCoord xoffset
, wxCoord yoffset
)
1052 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1054 wxCoord x1
, x2
, y1
, y2
;
1055 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1056 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1057 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1058 path
->MoveToPoint( x1
, y1
) ;
1059 for (int i
= 1; i
< n
; i
++)
1061 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1062 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1064 path
->AddLineToPoint( x2
, y2
) ;
1066 m_graphicContext
->StrokePath( path
) ;
1070 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1071 wxCoord xoffset
, wxCoord yoffset
,
1074 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1075 wxCoord x1
, x2
, y1
, y2
;
1076 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1079 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1080 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1082 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1083 path
->MoveToPoint( x1
, y1
) ;
1084 for (int i
= 1; i
< n
; i
++)
1086 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1087 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1089 path
->AddLineToPoint( x2
, y2
) ;
1091 if ( x1
!= x2
|| y1
!= y2
)
1093 path
->AddLineToPoint( x1
,y1
) ;
1095 path
->CloseSubpath() ;
1096 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1100 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1102 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1103 wxCoord xx
= XLOG2DEVMAC(x
);
1104 wxCoord yy
= YLOG2DEVMAC(y
);
1105 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1106 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1107 // CMB: draw nothing if transformed w or h is 0
1108 if (ww
== 0 || hh
== 0)
1110 // CMB: handle -ve width and/or height
1121 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1122 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1123 m_graphicContext
->DrawPath( path
) ;
1127 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1128 wxCoord width
, wxCoord height
,
1131 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1133 radius
= - radius
* ((width
< height
) ? width
: height
);
1134 wxCoord xx
= XLOG2DEVMAC(x
);
1135 wxCoord yy
= YLOG2DEVMAC(y
);
1136 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1137 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1138 // CMB: draw nothing if transformed w or h is 0
1139 if (ww
== 0 || hh
== 0)
1141 // CMB: handle -ve width and/or height
1152 Rect rect
= { yy
, xx
, yy
+ hh
, xx
+ ww
} ;
1153 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1154 CGContextRef ctx
= mctx
->GetNativeContext() ;
1155 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1156 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1159 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1161 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1162 wxCoord xx
= XLOG2DEVMAC(x
);
1163 wxCoord yy
= YLOG2DEVMAC(y
);
1164 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1165 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1166 // CMB: draw nothing if transformed w or h is 0
1167 if (ww
== 0 || hh
== 0)
1169 // CMB: handle -ve width and/or height
1181 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1182 CGContextRef ctx
= mctx
->GetNativeContext() ;
1183 if ( width
== height
)
1185 CGContextBeginPath(ctx
);
1186 CGContextAddArc(ctx
,
1193 CGContextClosePath(ctx
);
1195 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1199 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1200 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1204 bool wxDC::CanDrawBitmap(void) const
1209 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1210 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1211 wxCoord xsrcMask
, wxCoord ysrcMask
)
1213 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1214 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1215 if ( logical_func
== wxNO_OP
)
1217 if (xsrcMask
== -1 && ysrcMask
== -1)
1219 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1222 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1225 wxBitmap blit
= memdc
->GetSelectedObject() ;
1226 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1228 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1229 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1230 wxCoord ww
= XLOG2DEVREL(width
);
1231 wxCoord hh
= YLOG2DEVREL(height
);
1233 wxCoord bmpwidth
= blit
.GetWidth();
1234 wxCoord bmpheight
= blit
.GetHeight();
1236 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1238 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1239 blit
= blit
.GetSubBitmap( subrect
) ;
1242 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1243 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1244 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1245 HIViewDrawCGImage( cg
, &r
, image
) ;
1246 CGImageRelease( image
) ;
1251 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1256 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1259 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1261 if ( str
.Length() == 0 )
1264 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1266 OSStatus status
= noErr
;
1267 ATSUTextLayout atsuLayout
;
1268 UniCharCount chars
= str
.Length() ;
1269 UniChar
* ubuf
= NULL
;
1270 #if SIZEOF_WCHAR_T == 4
1271 wxMBConvUTF16BE converter
;
1273 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1274 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1275 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1277 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1278 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1279 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1280 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1282 chars
= unicharlen
/ 2 ;
1285 ubuf
= (UniChar
*) str
.wc_str() ;
1287 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1288 chars
= wxWcslen( wchar
.data() ) ;
1289 ubuf
= (UniChar
*) wchar
.data() ;
1293 int drawX
= XLOG2DEVMAC(x
) ;
1294 int drawY
= YLOG2DEVMAC(y
) ;
1296 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1297 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1299 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1300 int iAngle
= int( angle
);
1304 if ( abs(iAngle
) > 0 )
1306 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1307 ATSUAttributeTag atsuTags
[] =
1309 kATSULineRotationTag
,
1311 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1315 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1319 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1320 atsuTags
, atsuSizes
, atsuValues
) ;
1323 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1324 ATSUAttributeTag atsuTags
[] =
1328 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1330 sizeof( CGContextRef
) ,
1332 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1336 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1337 atsuTags
, atsuSizes
, atsuValues
) ;
1340 ATSUTextMeasurement textBefore
;
1341 ATSUTextMeasurement textAfter
;
1342 ATSUTextMeasurement ascent
;
1343 ATSUTextMeasurement descent
;
1345 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1346 &textBefore
, &textAfter
, &ascent
, &descent
);
1347 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1351 if ( m_backgroundMode
== wxSOLID
)
1353 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1357 path
->AddLineToPoint(
1358 drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) ,
1359 drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) ) ;
1360 path
->AddLineToPoint(
1361 drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
) ,
1362 drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
) ) ;
1363 path
->AddLineToPoint(
1364 drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
) ,
1365 drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
) ) ;
1367 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1371 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1372 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1374 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1375 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1376 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1378 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1379 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1380 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1381 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1382 IntToFixed(0) , IntToFixed(0) );
1383 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1384 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1386 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1387 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1389 ::ATSUDisposeTextLayout(atsuLayout
);
1390 #if SIZEOF_WCHAR_T == 4
1395 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1397 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1398 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1401 bool wxDC::CanGetTextExtent() const
1403 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1407 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1408 wxCoord
*descent
, wxCoord
*externalLeading
,
1409 wxFont
*theFont
) const
1411 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1412 wxFont formerFont
= m_font
;
1415 // work around the constness
1416 *((wxFont
*)(&m_font
)) = *theFont
;
1420 if ( str
.Length() == 0 )
1423 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1425 OSStatus status
= noErr
;
1426 ATSUTextLayout atsuLayout
;
1427 UniCharCount chars
= str
.Length() ;
1428 UniChar
* ubuf
= NULL
;
1429 #if SIZEOF_WCHAR_T == 4
1430 wxMBConvUTF16BE converter
;
1432 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1433 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1434 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1436 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1437 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1438 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1439 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1441 chars
= unicharlen
/ 2 ;
1444 ubuf
= (UniChar
*) str
.wc_str() ;
1446 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1447 chars
= wxWcslen( wchar
.data() ) ;
1448 ubuf
= (UniChar
*) wchar
.data() ;
1453 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1454 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1456 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1458 ATSUTextMeasurement textBefore
;
1459 ATSUTextMeasurement textAfter
;
1460 ATSUTextMeasurement textAscent
;
1461 ATSUTextMeasurement textDescent
;
1463 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1464 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1467 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1469 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1470 if ( externalLeading
)
1471 *externalLeading
= 0 ;
1473 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1475 ::ATSUDisposeTextLayout(atsuLayout
);
1476 #if SIZEOF_WCHAR_T == 4
1481 // work around the constness
1482 *((wxFont
*)(&m_font
)) = formerFont
;
1488 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1490 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1493 widths
.Add(0, text
.Length());
1495 if (text
.Length() == 0)
1498 wxFAIL_MSG( wxT("Unimplemented for Core Graphics") ) ;
1503 wxCoord
wxDC::GetCharWidth(void) const
1506 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1510 wxCoord
wxDC::GetCharHeight(void) const
1513 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1517 void wxDC::Clear(void)
1519 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1521 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1523 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1524 switch( m_backgroundBrush
.MacGetBrushKind() )
1526 case kwxMacBrushTheme
:
1530 case kwxMacBrushThemeBackground
:
1532 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1533 if ( HIThemeDrawBackground
)
1535 HIThemeBackgroundDrawInfo drawInfo
;
1536 drawInfo
.version
= 0 ;
1537 drawInfo
.state
= kThemeStateActive
;
1538 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1539 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1540 HIThemeDrawBackground( &rect
, &drawInfo
, dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ,
1541 kHIThemeOrientationNormal
) ;
1542 HIThemeApplyBackground( &rect
, &drawInfo
, dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ,
1543 kHIThemeOrientationNormal
) ;
1548 case kwxMacBrushColour
:
1550 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1551 CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() , col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1552 CGContextFillRect(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), rect
);
1554 // reset to normal value
1555 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1556 CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() , col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1563 void wxDC::MacInstallFont() const
1565 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1567 if( m_macATSUIStyle
)
1569 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1570 m_macATSUIStyle
= NULL
;
1573 OSStatus status
= noErr
;
1574 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1575 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1577 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1578 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1579 ATSUAttributeTag atsuTags
[] =
1584 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1587 sizeof( RGBColor
) ,
1589 // Boolean kTrue = true ;
1590 // Boolean kFalse = false ;
1592 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1593 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1598 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1599 atsuTags
, atsuSizes
, atsuValues
);
1601 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1604 // ---------------------------------------------------------------------------
1605 // coordinates transformations
1606 // ---------------------------------------------------------------------------
1608 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1610 return ((wxDC
*)this)->XDEV2LOG(x
);
1613 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1615 return ((wxDC
*)this)->YDEV2LOG(y
);
1618 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1620 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1623 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1625 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1628 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1630 return ((wxDC
*)this)->XLOG2DEV(x
);
1633 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1635 return ((wxDC
*)this)->YLOG2DEV(y
);
1638 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1640 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1643 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1645 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1648 #endif // wxMAC_USE_CORE_GRAPHICS