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 // make sure that we now have a real cgref, before doing
256 // anything with paths
257 return new wxMacCGPath() ;
260 // in case we only got a QDPort only create a cgref now
262 CGContextRef
wxMacCGContext::GetNativeContext()
264 if( m_cgContext
== NULL
)
267 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
268 OSStatus status
= QDBeginCGContext( (CGrafPtr
) m_qdPort
, &m_cgContext
) ;
269 CGContextSaveGState( m_cgContext
) ;
271 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
272 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
273 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
275 CGContextSaveGState( m_cgContext
) ;
277 SetBrush( m_brush
) ;
282 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
284 wxASSERT( m_cgContext
== NULL
) ;
286 CGContextSaveGState( m_cgContext
) ;
289 void wxMacCGContext::SetPen( const wxPen
&pen
)
292 if ( m_cgContext
== NULL
)
294 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
295 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
298 // we can benchmark performance, should go into a setting later
299 CGContextSetShouldAntialias( m_cgContext
, false ) ;
304 m_mode
= kCGPathFill
; // just a default
308 m_mode
= kCGPathFill
;
312 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
313 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
316 switch( pen
.GetCap() )
319 cap
= kCGLineCapRound
;
321 case wxCAP_PROJECTING
:
322 cap
= kCGLineCapSquare
;
325 cap
= kCGLineCapButt
;
328 cap
= kCGLineCapButt
;
331 CGContextSetLineCap( m_cgContext
, cap
) ;
334 switch( pen
.GetJoin() )
337 join
= kCGLineJoinBevel
;
340 join
= kCGLineJoinMiter
;
343 join
= kCGLineJoinRound
;
346 join
= kCGLineJoinMiter
;
349 CGContextSetLineJoin( m_cgContext
, join
) ;
351 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
353 m_mode
= kCGPathStroke
;
355 const float *lengths
= NULL
;
356 float *userLengths
= NULL
;
358 const float dotted
[] = { 3 , 3 };
359 const float dashed
[] = { 19 , 9 };
360 const float short_dashed
[] = { 9 , 6 };
361 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
363 switch( pen
.GetStyle() )
369 count
= WXSIZEOF(dotted
);
373 count
= WXSIZEOF(dashed
) ;
376 lengths
= short_dashed
;
377 count
= WXSIZEOF(short_dashed
) ;
380 lengths
= dotted_dashed
;
381 count
= WXSIZEOF(dotted_dashed
);
385 count
= pen
.GetDashes( &dashes
) ;
388 userLengths
= new float[count
] ;
389 for( int i
= 0 ; i
< count
; ++i
)
390 userLengths
[i
] = dashes
[i
] ;
392 lengths
= userLengths
;
398 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
399 delete[] userLengths
;
400 // we need to change the cap, otherwise everything overlaps
401 // and we get solid lines
403 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
405 if ( fill
&& stroke
)
407 m_mode
= kCGPathFillStroke
;
412 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
415 if ( m_cgContext
== NULL
)
418 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
419 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
422 // we can benchmark performance, should go into a setting later
423 CGContextSetShouldAntialias( m_cgContext
, false ) ;
429 m_mode
= kCGPathFill
; // just a default
433 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
434 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
435 m_mode
= kCGPathFill
;
439 m_mode
= kCGPathStroke
;
441 if ( fill
&& stroke
)
443 m_mode
= kCGPathFillStroke
;
449 // snippets from Sketch Sample from Apple :
451 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
453 This function locates, opens, and returns the profile reference for the calibrated
454 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
455 with the profile reference this function returns.
457 CMProfileRef
wxMacOpenGenericProfile(void)
459 static CMProfileRef cachedRGBProfileRef
= NULL
;
461 // we only create the profile reference once
462 if (cachedRGBProfileRef
== NULL
)
464 CMProfileLocation loc
;
466 loc
.locType
= cmPathBasedProfile
;
467 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
469 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
472 if (cachedRGBProfileRef
)
474 // clone the profile reference so that the caller has their own reference, not our cached one
475 CMCloneProfileRef(cachedRGBProfileRef
);
478 return cachedRGBProfileRef
;
482 Return the generic RGB color space. This is a 'get' function and the caller should
483 not release the returned value unless the caller retains it first. Usually callers
484 of this routine will immediately use the returned colorspace with CoreGraphics
485 so they typically do not need to retain it themselves.
487 This function creates the generic RGB color space once and hangs onto it so it can
488 return it whenever this function is called.
491 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
493 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
495 if (genericRGBColorSpace
== NULL
)
497 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
499 if (genericRGBProfile
)
501 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
502 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
504 // we opened the profile so it is up to us to close it
505 CMCloseProfile(genericRGBProfile
);
508 return genericRGBColorSpace
;
511 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
513 CGContextSaveGState(c
);
514 CGContextTranslateCTM(c
, center
.x
, center
.y
);
515 CGContextScaleCTM(c
, a
, b
);
516 CGContextMoveToPoint(c
, 1, 0);
517 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
518 CGContextClosePath(c
);
519 CGContextRestoreGState(c
);
522 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
526 if (ovalWidth
== 0 || ovalHeight
== 0)
528 CGContextAddRect(c
, rect
);
531 CGContextSaveGState(c
);
532 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
533 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
534 fw
= CGRectGetWidth(rect
) / ovalWidth
;
535 fh
= CGRectGetHeight(rect
) / ovalHeight
;
536 CGContextMoveToPoint(c
, fw
, fh
/2);
537 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
538 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
539 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
540 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
541 CGContextClosePath(c
);
542 CGContextRestoreGState(c
);
549 m_mm_to_pix_x
= mm2pt
;
550 m_mm_to_pix_y
= mm2pt
;
551 m_internalDeviceOriginX
= 0;
552 m_internalDeviceOriginY
= 0;
553 m_externalDeviceOriginX
= 0;
554 m_externalDeviceOriginY
= 0;
555 m_logicalScaleX
= 1.0;
556 m_logicalScaleY
= 1.0;
561 m_needComputeScaleX
= FALSE
;
562 m_needComputeScaleY
= FALSE
;
566 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
568 m_pen
= *wxBLACK_PEN
;
569 m_font
= *wxNORMAL_FONT
;
570 m_brush
= *wxWHITE_BRUSH
;
572 m_macATSUIStyle
= NULL
;
574 m_graphicContext
= NULL
;
579 if( m_macATSUIStyle
)
581 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
582 m_macATSUIStyle
= NULL
;
585 delete m_graphicContext
;
588 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
590 wxCHECK_RET( Ok(), wxT("invalid window dc") );
591 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
592 wxCoord xx
= XLOG2DEVMAC(x
);
593 wxCoord yy
= YLOG2DEVMAC(y
);
594 wxCoord w
= bmp
.GetWidth();
595 wxCoord h
= bmp
.GetHeight();
596 wxCoord ww
= XLOG2DEVREL(w
);
597 wxCoord hh
= YLOG2DEVREL(h
);
599 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
600 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
601 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
602 HIViewDrawCGImage( cg
, &r
, image
) ;
603 CGImageRelease( image
) ;
606 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
608 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
609 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
611 wxCoord xx
= XLOG2DEVMAC(x
);
612 wxCoord yy
= YLOG2DEVMAC(y
);
613 wxCoord w
= icon
.GetWidth();
614 wxCoord h
= icon
.GetHeight();
615 wxCoord ww
= XLOG2DEVREL(w
);
616 wxCoord hh
= YLOG2DEVREL(h
);
618 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
619 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
620 CGContextSaveGState(cg
);
621 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
622 CGContextScaleCTM(cg
, 1, -1);
623 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
624 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
625 CGContextRestoreGState( cg
) ;
628 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
630 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
631 wxCoord xx
, yy
, ww
, hh
;
634 ww
= XLOG2DEVREL(width
);
635 hh
= YLOG2DEVREL(height
);
637 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
638 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
639 CGContextClipToRect( cgContext
, clipRect
) ;
641 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
642 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
645 m_clipX1
= wxMax( m_clipX1
, xx
);
646 m_clipY1
= wxMax( m_clipY1
, yy
);
647 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
648 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
658 // TODO as soon as we don't reset the context for each operation anymore
659 // we have to update the context as well
662 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
664 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
667 DestroyClippingRegion();
671 region
.GetBox( x
, y
, w
, h
);
672 wxCoord xx
, yy
, ww
, hh
;
677 // if we have a scaling that we cannot map onto native regions
678 // we must use the box
679 if ( ww
!= w
|| hh
!= h
)
681 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
686 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
687 if ( xx != x || yy != y )
689 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
691 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
695 m_clipX1
= wxMax( m_clipX1
, xx
);
696 m_clipY1
= wxMax( m_clipY1
, yy
);
697 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
698 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
711 void wxDC::DestroyClippingRegion()
713 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
714 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
715 CGContextRestoreGState( cgContext
);
716 CGContextSaveGState( cgContext
);
718 SetBrush( m_brush
) ;
722 void wxDC::DoGetSizeMM( int* width
, int* height
) const
727 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
728 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
731 void wxDC::SetTextForeground( const wxColour
&col
)
733 wxCHECK_RET(Ok(), wxT("Invalid DC"));
734 if ( col
!= m_textForegroundColour
)
736 m_textForegroundColour
= col
;
741 void wxDC::SetTextBackground( const wxColour
&col
)
743 wxCHECK_RET(Ok(), wxT("Invalid DC"));
744 m_textBackgroundColour
= col
;
747 void wxDC::SetMapMode( int mode
)
752 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
755 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
758 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
761 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
765 SetLogicalScale( 1.0, 1.0 );
768 if (mode
!= wxMM_TEXT
)
770 m_needComputeScaleX
= TRUE
;
771 m_needComputeScaleY
= TRUE
;
775 void wxDC::SetUserScale( double x
, double y
)
777 // allow negative ? -> no
780 ComputeScaleAndOrigin();
783 void wxDC::SetLogicalScale( double x
, double y
)
788 ComputeScaleAndOrigin();
791 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
793 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
794 m_logicalOriginY
= y
* m_signY
;
795 ComputeScaleAndOrigin();
798 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
800 m_externalDeviceOriginX
= x
;
801 m_externalDeviceOriginY
= y
;
802 ComputeScaleAndOrigin();
805 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
807 m_signX
= (xLeftRight
? 1 : -1);
808 m_signY
= (yBottomUp
? -1 : 1);
809 ComputeScaleAndOrigin();
812 wxSize
wxDC::GetPPI() const
814 return wxSize(72, 72);
817 int wxDC::GetDepth() const
822 void wxDC::ComputeScaleAndOrigin()
824 // CMB: copy scale to see if it changes
825 double origScaleX
= m_scaleX
;
826 double origScaleY
= m_scaleY
;
827 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
828 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
829 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
830 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
831 // CMB: if scale has changed call SetPen to recalulate the line width
832 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
834 // this is a bit artificial, but we need to force wxDC to think
835 // the pen has changed
842 void wxDC::SetPalette( const wxPalette
& palette
)
846 void wxDC::SetBackgroundMode( int mode
)
848 m_backgroundMode
= mode
;
851 void wxDC::SetFont( const wxFont
&font
)
857 void wxDC::SetPen( const wxPen
&pen
)
862 if ( m_graphicContext
)
864 m_graphicContext
->SetPen( m_pen
) ;
868 void wxDC::SetBrush( const wxBrush
&brush
)
870 if (m_brush
== brush
)
873 if ( m_graphicContext
)
875 m_graphicContext
->SetBrush( m_brush
) ;
879 void wxDC::SetBackground( const wxBrush
&brush
)
881 if (m_backgroundBrush
== brush
)
883 m_backgroundBrush
= brush
;
884 if (!m_backgroundBrush
.Ok())
888 void wxDC::SetLogicalFunction( int function
)
890 if (m_logicalFunction
== function
)
892 m_logicalFunction
= function
;
895 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
896 const wxColour
& col
, int style
);
898 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
899 const wxColour
& col
, int style
)
901 return wxDoFloodFill(this, x
, y
, col
, style
);
904 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
906 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
907 wxFAIL_MSG( wxT("GetPixel not implemented on Core Graphics") ) ;
911 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
913 wxCHECK_RET(Ok(), wxT("Invalid DC"));
915 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
916 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
917 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
918 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
920 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
921 path
->MoveToPoint( xx1
, yy1
) ;
922 path
->AddLineToPoint( xx2
, yy2
) ;
923 path
->CloseSubpath() ;
924 m_graphicContext
->StrokePath( path
) ;
927 CalcBoundingBox(x1
, y1
);
928 CalcBoundingBox(x2
, y2
);
931 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
933 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
939 wxCoord xx
= XLOG2DEVMAC(x
);
940 wxCoord yy
= YLOG2DEVMAC(y
);
942 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
943 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
944 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
945 path
->CloseSubpath() ;
946 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
947 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
948 path
->CloseSubpath() ;
949 m_graphicContext
->StrokePath( path
) ;
952 CalcBoundingBox(x
, y
);
953 CalcBoundingBox(x
+w
, y
+h
);
957 * To draw arcs properly the angles need to be converted from the WX style:
958 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
959 * a normal axis on paper).
962 * Angles start on the +ve y axis and go clockwise.
965 static double wxConvertWXangleToMACangle(double angle
)
967 double newAngle
= 90 - angle
;
973 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
974 wxCoord x2
, wxCoord y2
,
975 wxCoord xc
, wxCoord yc
)
977 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
978 wxCoord xx1
= XLOG2DEVMAC(x1
);
979 wxCoord yy1
= YLOG2DEVMAC(y1
);
980 wxCoord xx2
= XLOG2DEVMAC(x2
);
981 wxCoord yy2
= YLOG2DEVMAC(y2
);
982 wxCoord xxc
= XLOG2DEVMAC(xc
);
983 wxCoord yyc
= YLOG2DEVMAC(yc
);
984 double dx
= xx1
- xxc
;
985 double dy
= yy1
- yyc
;
986 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
987 wxCoord rad
= (wxCoord
)radius
;
988 double radius1
, radius2
;
989 if (xx1
== xx2
&& yy1
== yy2
)
994 else if (radius
== 0.0)
996 radius1
= radius2
= 0.0;
1000 radius1
= (xx1
- xxc
== 0) ?
1001 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1002 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1003 radius2
= (xx2
- xxc
== 0) ?
1004 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1005 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1007 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1008 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1011 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1012 CGContextRef ctx
= mctx
->GetNativeContext() ;
1013 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, 0 , 180 ) ;
1014 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1017 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1018 double sa
, double ea
)
1020 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1022 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1023 // we have to make sure that the filling is always counter-clockwise
1026 wxCoord xx
= XLOG2DEVMAC(x
);
1027 wxCoord yy
= YLOG2DEVMAC(y
);
1028 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1029 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1030 // handle -ve width and/or height
1031 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1032 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1033 sa
= wxConvertWXangleToMACangle(sa
);
1034 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1035 CGContextRef ctx
= mctx
->GetNativeContext() ;
1036 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1037 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1040 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1042 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1043 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1046 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1047 wxCoord xoffset
, wxCoord yoffset
)
1049 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1051 wxCoord x1
, x2
, y1
, y2
;
1052 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1053 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1054 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1055 path
->MoveToPoint( x1
, y1
) ;
1056 for (int i
= 1; i
< n
; i
++)
1058 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1059 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1061 path
->AddLineToPoint( x2
, y2
) ;
1063 m_graphicContext
->StrokePath( path
) ;
1067 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1068 wxCoord xoffset
, wxCoord yoffset
,
1071 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1072 wxCoord x1
, x2
, y1
, y2
;
1073 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1076 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1077 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1079 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1080 path
->MoveToPoint( x1
, y1
) ;
1081 for (int i
= 1; i
< n
; i
++)
1083 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1084 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1086 path
->AddLineToPoint( x2
, y2
) ;
1088 if ( x1
!= x2
|| y1
!= y2
)
1090 path
->AddLineToPoint( x1
,y1
) ;
1092 path
->CloseSubpath() ;
1093 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1097 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1099 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1100 wxCoord xx
= XLOG2DEVMAC(x
);
1101 wxCoord yy
= YLOG2DEVMAC(y
);
1102 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1103 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1104 // CMB: draw nothing if transformed w or h is 0
1105 if (ww
== 0 || hh
== 0)
1107 // CMB: handle -ve width and/or height
1118 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1119 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1120 m_graphicContext
->DrawPath( path
) ;
1124 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1125 wxCoord width
, wxCoord height
,
1128 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1130 radius
= - radius
* ((width
< height
) ? width
: height
);
1131 wxCoord xx
= XLOG2DEVMAC(x
);
1132 wxCoord yy
= YLOG2DEVMAC(y
);
1133 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1134 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1135 // CMB: draw nothing if transformed w or h is 0
1136 if (ww
== 0 || hh
== 0)
1138 // CMB: handle -ve width and/or height
1149 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1150 CGContextRef ctx
= mctx
->GetNativeContext() ;
1151 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1152 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1155 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1157 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1158 wxCoord xx
= XLOG2DEVMAC(x
);
1159 wxCoord yy
= YLOG2DEVMAC(y
);
1160 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1161 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1162 // CMB: draw nothing if transformed w or h is 0
1163 if (ww
== 0 || hh
== 0)
1165 // CMB: handle -ve width and/or height
1177 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1178 CGContextRef ctx
= mctx
->GetNativeContext() ;
1179 if ( width
== height
)
1181 CGContextBeginPath(ctx
);
1182 CGContextAddArc(ctx
,
1189 CGContextClosePath(ctx
);
1191 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1195 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1196 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1200 bool wxDC::CanDrawBitmap(void) const
1205 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1206 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1207 wxCoord xsrcMask
, wxCoord ysrcMask
)
1209 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1210 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1211 if ( logical_func
== wxNO_OP
)
1213 if (xsrcMask
== -1 && ysrcMask
== -1)
1215 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1218 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1221 wxBitmap blit
= memdc
->GetSelectedObject() ;
1222 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1224 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1225 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1226 wxCoord ww
= XLOG2DEVREL(width
);
1227 wxCoord hh
= YLOG2DEVREL(height
);
1229 wxCoord bmpwidth
= blit
.GetWidth();
1230 wxCoord bmpheight
= blit
.GetHeight();
1232 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1234 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1235 blit
= blit
.GetSubBitmap( subrect
) ;
1238 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1239 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1240 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1241 HIViewDrawCGImage( cg
, &r
, image
) ;
1242 CGImageRelease( image
) ;
1247 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1252 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1255 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1257 if ( str
.Length() == 0 )
1260 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1262 OSStatus status
= noErr
;
1263 ATSUTextLayout atsuLayout
;
1264 UniCharCount chars
= str
.Length() ;
1265 UniChar
* ubuf
= NULL
;
1266 #if SIZEOF_WCHAR_T == 4
1267 wxMBConvUTF16BE converter
;
1269 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1270 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1271 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1273 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1274 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1275 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1276 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1278 chars
= unicharlen
/ 2 ;
1281 ubuf
= (UniChar
*) str
.wc_str() ;
1283 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1284 chars
= wxWcslen( wchar
.data() ) ;
1285 ubuf
= (UniChar
*) wchar
.data() ;
1289 int drawX
= XLOG2DEVMAC(x
) ;
1290 int drawY
= YLOG2DEVMAC(y
) ;
1292 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1293 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1295 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1296 int iAngle
= int( angle
);
1300 if ( abs(iAngle
) > 0 )
1302 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1303 ATSUAttributeTag atsuTags
[] =
1305 kATSULineRotationTag
,
1307 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1311 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1315 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1316 atsuTags
, atsuSizes
, atsuValues
) ;
1319 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1320 ATSUAttributeTag atsuTags
[] =
1324 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1326 sizeof( CGContextRef
) ,
1328 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1332 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1333 atsuTags
, atsuSizes
, atsuValues
) ;
1336 ATSUTextMeasurement textBefore
;
1337 ATSUTextMeasurement textAfter
;
1338 ATSUTextMeasurement ascent
;
1339 ATSUTextMeasurement descent
;
1341 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1342 &textBefore
, &textAfter
, &ascent
, &descent
);
1343 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1347 if ( m_backgroundMode
== wxSOLID
)
1349 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1353 path
->AddLineToPoint(
1354 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1355 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1356 path
->AddLineToPoint(
1357 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1358 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1359 path
->AddLineToPoint(
1360 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1361 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1363 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1367 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1368 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1370 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1371 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1372 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1374 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1375 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1376 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1377 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1378 IntToFixed(0) , IntToFixed(0) );
1379 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1380 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1382 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1383 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1385 ::ATSUDisposeTextLayout(atsuLayout
);
1386 #if SIZEOF_WCHAR_T == 4
1391 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1393 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1394 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1397 bool wxDC::CanGetTextExtent() const
1399 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1403 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1404 wxCoord
*descent
, wxCoord
*externalLeading
,
1405 wxFont
*theFont
) const
1407 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1408 wxFont formerFont
= m_font
;
1411 // work around the constness
1412 *((wxFont
*)(&m_font
)) = *theFont
;
1416 if ( str
.Length() == 0 )
1419 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1421 OSStatus status
= noErr
;
1422 ATSUTextLayout atsuLayout
;
1423 UniCharCount chars
= str
.Length() ;
1424 UniChar
* ubuf
= NULL
;
1425 #if SIZEOF_WCHAR_T == 4
1426 wxMBConvUTF16BE converter
;
1428 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1429 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1430 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1432 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1433 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1434 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1435 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1437 chars
= unicharlen
/ 2 ;
1440 ubuf
= (UniChar
*) str
.wc_str() ;
1442 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1443 chars
= wxWcslen( wchar
.data() ) ;
1444 ubuf
= (UniChar
*) wchar
.data() ;
1449 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1450 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1452 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1454 ATSUTextMeasurement textBefore
;
1455 ATSUTextMeasurement textAfter
;
1456 ATSUTextMeasurement textAscent
;
1457 ATSUTextMeasurement textDescent
;
1459 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1460 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1463 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1465 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1466 if ( externalLeading
)
1467 *externalLeading
= 0 ;
1469 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1471 ::ATSUDisposeTextLayout(atsuLayout
);
1472 #if SIZEOF_WCHAR_T == 4
1477 // work around the constness
1478 *((wxFont
*)(&m_font
)) = formerFont
;
1484 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1486 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1489 widths
.Add(0, text
.Length());
1491 if (text
.Length() == 0)
1494 wxFAIL_MSG( wxT("Unimplemented for Core Graphics") ) ;
1499 wxCoord
wxDC::GetCharWidth(void) const
1502 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1506 wxCoord
wxDC::GetCharHeight(void) const
1509 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1513 void wxDC::Clear(void)
1515 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1517 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1519 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1520 switch( m_backgroundBrush
.MacGetBrushKind() )
1522 case kwxMacBrushTheme
:
1526 case kwxMacBrushThemeBackground
:
1528 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1529 if ( HIThemeDrawBackground
)
1531 HIThemeBackgroundDrawInfo drawInfo
;
1532 drawInfo
.version
= 0 ;
1533 drawInfo
.state
= kThemeStateActive
;
1534 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1535 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1536 HIThemeDrawBackground( &rect
, &drawInfo
, dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ,
1537 kHIThemeOrientationNormal
) ;
1538 HIThemeApplyBackground( &rect
, &drawInfo
, dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ,
1539 kHIThemeOrientationNormal
) ;
1544 case kwxMacBrushColour
:
1546 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1547 CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() , col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1548 CGContextFillRect(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), rect
);
1550 // reset to normal value
1551 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1552 CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() , col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1559 void wxDC::MacInstallFont() const
1561 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1563 if( m_macATSUIStyle
)
1565 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1566 m_macATSUIStyle
= NULL
;
1569 OSStatus status
= noErr
;
1570 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1571 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1573 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1574 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1575 ATSUAttributeTag atsuTags
[] =
1580 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1583 sizeof( RGBColor
) ,
1585 // Boolean kTrue = true ;
1586 // Boolean kFalse = false ;
1588 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1589 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1594 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1595 atsuTags
, atsuSizes
, atsuValues
);
1597 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1600 // ---------------------------------------------------------------------------
1601 // coordinates transformations
1602 // ---------------------------------------------------------------------------
1604 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1606 return ((wxDC
*)this)->XDEV2LOG(x
);
1609 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1611 return ((wxDC
*)this)->YDEV2LOG(y
);
1614 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1616 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1619 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1621 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1624 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1626 return ((wxDC
*)this)->XLOG2DEV(x
);
1629 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1631 return ((wxDC
*)this)->YLOG2DEV(y
);
1634 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1636 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1639 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1641 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1644 #endif // wxMAC_USE_CORE_GRAPHICS