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 CGContextSynchronize( m_cgContext
) ;
209 CGContextRestoreGState( m_cgContext
) ;
210 CGContextRestoreGState( m_cgContext
) ;
213 CGContextRelease( m_cgContext
) ;
217 void wxMacCGContext::Clip( const wxRegion
®ion
)
219 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
222 void wxMacCGContext::StrokePath( const wxGraphicPath
*p
)
224 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
225 CGContextBeginPath( m_cgContext
) ;
226 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
227 CGContextClosePath( m_cgContext
) ;
228 CGContextStrokePath( m_cgContext
) ;
231 void wxMacCGContext::DrawPath( const wxGraphicPath
*p
, int fillStyle
)
233 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
234 CGPathDrawingMode mode
= m_mode
;
235 if ( fillStyle
== wxODDEVEN_RULE
)
237 if ( mode
== kCGPathFill
)
238 mode
= kCGPathEOFill
;
239 else if ( mode
== kCGPathFillStroke
)
240 mode
= kCGPathEOFillStroke
;
242 CGContextBeginPath( m_cgContext
) ;
243 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
244 CGContextClosePath( m_cgContext
) ;
245 CGContextDrawPath( m_cgContext
, mode
) ;
248 void wxMacCGContext::FillPath( const wxGraphicPath
*p
, const wxColor
&fillColor
, int fillStyle
)
250 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
251 CGContextSaveGState( m_cgContext
) ;
253 RGBColor col
= MAC_WXCOLORREF( fillColor
.GetPixel() ) ;
254 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
255 CGPathDrawingMode mode
= kCGPathFill
;
257 if ( fillStyle
== wxODDEVEN_RULE
)
258 mode
= kCGPathEOFill
;
260 CGContextBeginPath( m_cgContext
) ;
261 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
262 CGContextClosePath( m_cgContext
) ;
263 CGContextDrawPath( m_cgContext
, mode
) ;
265 CGContextRestoreGState( m_cgContext
) ;
268 wxGraphicPath
* wxMacCGContext::CreatePath()
270 // make sure that we now have a real cgref, before doing
271 // anything with paths
272 CGContextRef cg
= GetNativeContext() ;
274 return new wxMacCGPath() ;
277 // in case we only got a QDPort only create a cgref now
279 CGContextRef
wxMacCGContext::GetNativeContext()
281 if( m_cgContext
== NULL
)
284 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
285 OSStatus status
= CreateCGContextForPort((CGrafPtr
) m_qdPort
, &m_cgContext
) ;
286 CGContextSaveGState( m_cgContext
) ;
288 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
289 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
290 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
292 CGContextSaveGState( m_cgContext
) ;
294 SetBrush( m_brush
) ;
299 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
301 wxASSERT( m_cgContext
== NULL
) ;
303 CGContextSaveGState( m_cgContext
) ;
306 void wxMacCGContext::SetPen( const wxPen
&pen
)
309 if ( m_cgContext
== NULL
)
311 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
312 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
315 // we can benchmark performance, should go into a setting later
316 CGContextSetShouldAntialias( m_cgContext
, false ) ;
321 m_mode
= kCGPathFill
; // just a default
325 m_mode
= kCGPathFill
;
329 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
330 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
333 switch( pen
.GetCap() )
336 cap
= kCGLineCapRound
;
338 case wxCAP_PROJECTING
:
339 cap
= kCGLineCapSquare
;
342 cap
= kCGLineCapButt
;
345 cap
= kCGLineCapButt
;
348 CGContextSetLineCap( m_cgContext
, cap
) ;
351 switch( pen
.GetJoin() )
354 join
= kCGLineJoinBevel
;
357 join
= kCGLineJoinMiter
;
360 join
= kCGLineJoinRound
;
363 join
= kCGLineJoinMiter
;
366 CGContextSetLineJoin( m_cgContext
, join
) ;
368 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
370 m_mode
= kCGPathStroke
;
372 const float *lengths
= NULL
;
373 float *userLengths
= NULL
;
375 const float dotted
[] = { 3 , 3 };
376 const float dashed
[] = { 19 , 9 };
377 const float short_dashed
[] = { 9 , 6 };
378 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
380 switch( pen
.GetStyle() )
386 count
= WXSIZEOF(dotted
);
390 count
= WXSIZEOF(dashed
) ;
393 lengths
= short_dashed
;
394 count
= WXSIZEOF(short_dashed
) ;
397 lengths
= dotted_dashed
;
398 count
= WXSIZEOF(dotted_dashed
);
402 count
= pen
.GetDashes( &dashes
) ;
405 userLengths
= new float[count
] ;
406 for( int i
= 0 ; i
< count
; ++i
)
407 userLengths
[i
] = dashes
[i
] ;
409 lengths
= userLengths
;
415 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
416 delete[] userLengths
;
417 // we need to change the cap, otherwise everything overlaps
418 // and we get solid lines
420 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
422 if ( fill
&& stroke
)
424 m_mode
= kCGPathFillStroke
;
429 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
432 if ( m_cgContext
== NULL
)
435 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
436 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
439 // we can benchmark performance, should go into a setting later
440 CGContextSetShouldAntialias( m_cgContext
, false ) ;
446 m_mode
= kCGPathFill
; // just a default
450 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
451 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
452 m_mode
= kCGPathFill
;
456 m_mode
= kCGPathStroke
;
458 if ( fill
&& stroke
)
460 m_mode
= kCGPathFillStroke
;
466 // snippets from Sketch Sample from Apple :
468 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
470 This function locates, opens, and returns the profile reference for the calibrated
471 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
472 with the profile reference this function returns.
474 CMProfileRef
wxMacOpenGenericProfile(void)
476 static CMProfileRef cachedRGBProfileRef
= NULL
;
478 // we only create the profile reference once
479 if (cachedRGBProfileRef
== NULL
)
481 CMProfileLocation loc
;
483 loc
.locType
= cmPathBasedProfile
;
484 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
486 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
489 if (cachedRGBProfileRef
)
491 // clone the profile reference so that the caller has their own reference, not our cached one
492 CMCloneProfileRef(cachedRGBProfileRef
);
495 return cachedRGBProfileRef
;
499 Return the generic RGB color space. This is a 'get' function and the caller should
500 not release the returned value unless the caller retains it first. Usually callers
501 of this routine will immediately use the returned colorspace with CoreGraphics
502 so they typically do not need to retain it themselves.
504 This function creates the generic RGB color space once and hangs onto it so it can
505 return it whenever this function is called.
508 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
510 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
512 if (genericRGBColorSpace
== NULL
)
514 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
516 if (genericRGBProfile
)
518 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
519 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
521 // we opened the profile so it is up to us to close it
522 CMCloseProfile(genericRGBProfile
);
525 return genericRGBColorSpace
;
528 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
530 CGContextSaveGState(c
);
531 CGContextTranslateCTM(c
, center
.x
, center
.y
);
532 CGContextScaleCTM(c
, a
, b
);
533 CGContextMoveToPoint(c
, 1, 0);
534 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
535 CGContextClosePath(c
);
536 CGContextRestoreGState(c
);
539 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
543 if (ovalWidth
== 0 || ovalHeight
== 0)
545 CGContextAddRect(c
, rect
);
548 CGContextSaveGState(c
);
549 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
550 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
551 fw
= CGRectGetWidth(rect
) / ovalWidth
;
552 fh
= CGRectGetHeight(rect
) / ovalHeight
;
553 CGContextMoveToPoint(c
, fw
, fh
/2);
554 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
555 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
556 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
557 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
558 CGContextClosePath(c
);
559 CGContextRestoreGState(c
);
566 m_mm_to_pix_x
= mm2pt
;
567 m_mm_to_pix_y
= mm2pt
;
568 m_internalDeviceOriginX
= 0;
569 m_internalDeviceOriginY
= 0;
570 m_externalDeviceOriginX
= 0;
571 m_externalDeviceOriginY
= 0;
572 m_logicalScaleX
= 1.0;
573 m_logicalScaleY
= 1.0;
578 m_needComputeScaleX
= FALSE
;
579 m_needComputeScaleY
= FALSE
;
583 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
585 m_pen
= *wxBLACK_PEN
;
586 m_font
= *wxNORMAL_FONT
;
587 m_brush
= *wxWHITE_BRUSH
;
589 m_macATSUIStyle
= NULL
;
591 m_graphicContext
= NULL
;
596 if( m_macATSUIStyle
)
598 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
599 m_macATSUIStyle
= NULL
;
602 delete m_graphicContext
;
605 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
607 wxCHECK_RET( Ok(), wxT("invalid window dc") );
608 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
609 wxCoord xx
= XLOG2DEVMAC(x
);
610 wxCoord yy
= YLOG2DEVMAC(y
);
611 wxCoord w
= bmp
.GetWidth();
612 wxCoord h
= bmp
.GetHeight();
613 wxCoord ww
= XLOG2DEVREL(w
);
614 wxCoord hh
= YLOG2DEVREL(h
);
616 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
617 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
618 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
619 HIViewDrawCGImage( cg
, &r
, image
) ;
620 CGImageRelease( image
) ;
623 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
625 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
626 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
628 wxCoord xx
= XLOG2DEVMAC(x
);
629 wxCoord yy
= YLOG2DEVMAC(y
);
630 wxCoord w
= icon
.GetWidth();
631 wxCoord h
= icon
.GetHeight();
632 wxCoord ww
= XLOG2DEVREL(w
);
633 wxCoord hh
= YLOG2DEVREL(h
);
635 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
636 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
637 CGContextSaveGState(cg
);
638 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
639 CGContextScaleCTM(cg
, 1, -1);
640 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
641 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
642 CGContextRestoreGState( cg
) ;
645 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
647 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
648 wxCoord xx
, yy
, ww
, hh
;
651 ww
= XLOG2DEVREL(width
);
652 hh
= YLOG2DEVREL(height
);
654 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
655 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
656 CGContextClipToRect( cgContext
, clipRect
) ;
658 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
659 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
662 m_clipX1
= wxMax( m_clipX1
, xx
);
663 m_clipY1
= wxMax( m_clipY1
, yy
);
664 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
665 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
675 // TODO as soon as we don't reset the context for each operation anymore
676 // we have to update the context as well
679 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
681 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
684 DestroyClippingRegion();
688 region
.GetBox( x
, y
, w
, h
);
689 wxCoord xx
, yy
, ww
, hh
;
694 // if we have a scaling that we cannot map onto native regions
695 // we must use the box
696 if ( ww
!= w
|| hh
!= h
)
698 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
703 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
704 if ( xx != x || yy != y )
706 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
708 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
712 m_clipX1
= wxMax( m_clipX1
, xx
);
713 m_clipY1
= wxMax( m_clipY1
, yy
);
714 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
715 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
728 void wxDC::DestroyClippingRegion()
730 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
731 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
732 CGContextRestoreGState( cgContext
);
733 CGContextSaveGState( cgContext
);
735 SetBrush( m_brush
) ;
739 void wxDC::DoGetSizeMM( int* width
, int* height
) const
744 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
745 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
748 void wxDC::SetTextForeground( const wxColour
&col
)
750 wxCHECK_RET(Ok(), wxT("Invalid DC"));
751 if ( col
!= m_textForegroundColour
)
753 m_textForegroundColour
= col
;
758 void wxDC::SetTextBackground( const wxColour
&col
)
760 wxCHECK_RET(Ok(), wxT("Invalid DC"));
761 m_textBackgroundColour
= col
;
764 void wxDC::SetMapMode( int mode
)
769 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
772 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
775 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
778 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
782 SetLogicalScale( 1.0, 1.0 );
785 if (mode
!= wxMM_TEXT
)
787 m_needComputeScaleX
= TRUE
;
788 m_needComputeScaleY
= TRUE
;
792 void wxDC::SetUserScale( double x
, double y
)
794 // allow negative ? -> no
797 ComputeScaleAndOrigin();
800 void wxDC::SetLogicalScale( double x
, double y
)
805 ComputeScaleAndOrigin();
808 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
810 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
811 m_logicalOriginY
= y
* m_signY
;
812 ComputeScaleAndOrigin();
815 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
817 m_externalDeviceOriginX
= x
;
818 m_externalDeviceOriginY
= y
;
819 ComputeScaleAndOrigin();
822 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
824 m_signX
= (xLeftRight
? 1 : -1);
825 m_signY
= (yBottomUp
? -1 : 1);
826 ComputeScaleAndOrigin();
829 wxSize
wxDC::GetPPI() const
831 return wxSize(72, 72);
834 int wxDC::GetDepth() const
839 void wxDC::ComputeScaleAndOrigin()
841 // CMB: copy scale to see if it changes
842 double origScaleX
= m_scaleX
;
843 double origScaleY
= m_scaleY
;
844 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
845 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
846 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
847 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
848 // CMB: if scale has changed call SetPen to recalulate the line width
849 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
851 // this is a bit artificial, but we need to force wxDC to think
852 // the pen has changed
859 void wxDC::SetPalette( const wxPalette
& palette
)
863 void wxDC::SetBackgroundMode( int mode
)
865 m_backgroundMode
= mode
;
868 void wxDC::SetFont( const wxFont
&font
)
874 void wxDC::SetPen( const wxPen
&pen
)
879 if ( m_graphicContext
)
881 m_graphicContext
->SetPen( m_pen
) ;
885 void wxDC::SetBrush( const wxBrush
&brush
)
887 if (m_brush
== brush
)
890 if ( m_graphicContext
)
892 m_graphicContext
->SetBrush( m_brush
) ;
896 void wxDC::SetBackground( const wxBrush
&brush
)
898 if (m_backgroundBrush
== brush
)
900 m_backgroundBrush
= brush
;
901 if (!m_backgroundBrush
.Ok())
905 void wxDC::SetLogicalFunction( int function
)
907 if (m_logicalFunction
== function
)
909 m_logicalFunction
= function
;
912 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
913 const wxColour
& col
, int style
);
915 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
916 const wxColour
& col
, int style
)
918 return wxDoFloodFill(this, x
, y
, col
, style
);
921 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
923 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
924 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
925 wxMacPortSaver
helper((CGrafPtr
)m_macPort
) ;
928 XLOG2DEVMAC(x
) + m_macLocalOriginInPort
.x
- m_macLocalOrigin
.x
,
929 YLOG2DEVMAC(y
) + m_macLocalOriginInPort
.y
- m_macLocalOrigin
.y
, &colour
);
930 // Convert from Mac colour to wx
931 col
->Set( colour
.red
>> 8,
937 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
939 wxCHECK_RET(Ok(), wxT("Invalid DC"));
941 if ( m_logicalFunction
!= wxCOPY
)
944 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
945 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
946 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
947 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
949 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
950 path
->MoveToPoint( xx1
, yy1
) ;
951 path
->AddLineToPoint( xx2
, yy2
) ;
952 path
->CloseSubpath() ;
953 m_graphicContext
->StrokePath( path
) ;
956 CalcBoundingBox(x1
, y1
);
957 CalcBoundingBox(x2
, y2
);
960 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
962 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
964 if ( m_logicalFunction
!= wxCOPY
)
970 wxCoord xx
= XLOG2DEVMAC(x
);
971 wxCoord yy
= YLOG2DEVMAC(y
);
973 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
974 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
975 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
976 path
->CloseSubpath() ;
977 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
978 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
979 path
->CloseSubpath() ;
980 m_graphicContext
->StrokePath( path
) ;
983 CalcBoundingBox(x
, y
);
984 CalcBoundingBox(x
+w
, y
+h
);
988 * To draw arcs properly the angles need to be converted from the WX style:
989 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
990 * a normal axis on paper).
993 * Angles start on the +ve y axis and go clockwise.
996 static double wxConvertWXangleToMACangle(double angle
)
998 double newAngle
= 90 - angle
;
1004 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
1005 wxCoord x2
, wxCoord y2
,
1006 wxCoord xc
, wxCoord yc
)
1008 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1010 if ( m_logicalFunction
!= wxCOPY
)
1013 wxCoord xx1
= XLOG2DEVMAC(x1
);
1014 wxCoord yy1
= YLOG2DEVMAC(y1
);
1015 wxCoord xx2
= XLOG2DEVMAC(x2
);
1016 wxCoord yy2
= YLOG2DEVMAC(y2
);
1017 wxCoord xxc
= XLOG2DEVMAC(xc
);
1018 wxCoord yyc
= YLOG2DEVMAC(yc
);
1019 double dx
= xx1
- xxc
;
1020 double dy
= yy1
- yyc
;
1021 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
1022 wxCoord rad
= (wxCoord
)radius
;
1023 double radius1
, radius2
;
1024 if (xx1
== xx2
&& yy1
== yy2
)
1029 else if (radius
== 0.0)
1031 radius1
= radius2
= 0.0;
1035 radius1
= (xx1
- xxc
== 0) ?
1036 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1037 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1038 radius2
= (xx2
- xxc
== 0) ?
1039 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1040 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1042 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1043 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1044 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1047 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1048 CGContextRef ctx
= mctx
->GetNativeContext() ;
1049 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1050 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1053 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1054 double sa
, double ea
)
1056 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1058 if ( m_logicalFunction
!= wxCOPY
)
1061 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1062 // we have to make sure that the filling is always counter-clockwise
1065 wxCoord xx
= XLOG2DEVMAC(x
);
1066 wxCoord yy
= YLOG2DEVMAC(y
);
1067 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1068 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1069 // handle -ve width and/or height
1070 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1071 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1072 sa
= wxConvertWXangleToMACangle(sa
);
1073 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1074 CGContextRef ctx
= mctx
->GetNativeContext() ;
1075 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1076 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1079 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1081 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1082 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1085 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1086 wxCoord xoffset
, wxCoord yoffset
)
1088 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1090 if ( m_logicalFunction
!= wxCOPY
)
1093 wxCoord x1
, x2
, y1
, y2
;
1094 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1095 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1096 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1097 path
->MoveToPoint( x1
, y1
) ;
1098 for (int i
= 1; i
< n
; i
++)
1100 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1101 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1103 path
->AddLineToPoint( x2
, y2
) ;
1105 m_graphicContext
->StrokePath( path
) ;
1109 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1110 wxCoord xoffset
, wxCoord yoffset
,
1113 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1114 wxCoord x1
, x2
, y1
, y2
;
1115 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1118 if ( m_logicalFunction
!= wxCOPY
)
1121 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1122 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1124 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1125 path
->MoveToPoint( x1
, y1
) ;
1126 for (int i
= 1; i
< n
; i
++)
1128 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1129 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1131 path
->AddLineToPoint( x2
, y2
) ;
1133 if ( x1
!= x2
|| y1
!= y2
)
1135 path
->AddLineToPoint( x1
,y1
) ;
1137 path
->CloseSubpath() ;
1138 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1142 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1144 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1146 if ( m_logicalFunction
!= wxCOPY
)
1149 wxCoord xx
= XLOG2DEVMAC(x
);
1150 wxCoord yy
= YLOG2DEVMAC(y
);
1151 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1152 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1153 // CMB: draw nothing if transformed w or h is 0
1154 if (ww
== 0 || hh
== 0)
1156 // CMB: handle -ve width and/or height
1167 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1168 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1169 m_graphicContext
->DrawPath( path
) ;
1173 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1174 wxCoord width
, wxCoord height
,
1177 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1179 if ( m_logicalFunction
!= wxCOPY
)
1184 radius
= - radius
* ((width
< height
) ? width
: height
);
1185 wxCoord xx
= XLOG2DEVMAC(x
);
1186 wxCoord yy
= YLOG2DEVMAC(y
);
1187 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1188 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1189 // CMB: draw nothing if transformed w or h is 0
1190 if (ww
== 0 || hh
== 0)
1192 // CMB: handle -ve width and/or height
1203 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1204 CGContextRef ctx
= mctx
->GetNativeContext() ;
1205 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1206 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1209 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1211 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1213 if ( m_logicalFunction
!= wxCOPY
)
1216 wxCoord xx
= XLOG2DEVMAC(x
);
1217 wxCoord yy
= YLOG2DEVMAC(y
);
1218 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1219 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1220 // CMB: draw nothing if transformed w or h is 0
1221 if (ww
== 0 || hh
== 0)
1223 // CMB: handle -ve width and/or height
1235 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1236 CGContextRef ctx
= mctx
->GetNativeContext() ;
1237 if ( width
== height
)
1239 CGContextBeginPath(ctx
);
1240 CGContextAddArc(ctx
,
1247 CGContextClosePath(ctx
);
1249 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1253 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1254 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1258 bool wxDC::CanDrawBitmap(void) const
1263 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1264 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1265 wxCoord xsrcMask
, wxCoord ysrcMask
)
1267 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1268 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1269 if ( logical_func
== wxNO_OP
)
1271 if (xsrcMask
== -1 && ysrcMask
== -1)
1273 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1276 wxCoord yysrc
= source
->YLOG2DEVMAC(ysrc
) ;
1277 wxCoord xxsrc
= source
->XLOG2DEVMAC(xsrc
) ;
1278 wxCoord wwsrc
= source
->XLOG2DEVREL(width
) ;
1279 wxCoord hhsrc
= source
->YLOG2DEVREL(height
) ;
1281 wxCoord yydest
= YLOG2DEVMAC(ydest
) ;
1282 wxCoord xxdest
= XLOG2DEVMAC(xdest
) ;
1283 wxCoord wwdest
= XLOG2DEVREL(width
) ;
1284 wxCoord hhdest
= YLOG2DEVREL(height
) ;
1286 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1287 if ( memdc
&& logical_func
== wxCOPY
)
1289 wxBitmap blit
= memdc
->GetSelectedObject() ;
1290 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1292 wxCoord bmpwidth
= blit
.GetWidth();
1293 wxCoord bmpheight
= blit
.GetHeight();
1295 if ( xxsrc
!= 0 || yysrc
!= 0 || bmpwidth
!= wwsrc
|| bmpheight
!= hhsrc
)
1297 wwsrc
= wxMin( wwsrc
, bmpwidth
- xxsrc
) ;
1298 hhsrc
= wxMin( hhsrc
, bmpheight
- yysrc
) ;
1299 if ( wwsrc
> 0 && hhsrc
> 0 )
1301 if ( xxsrc
>= 0 && yysrc
>= 0 )
1303 wxRect
subrect( xxsrc
, yysrc
, wwsrc
, hhsrc
) ;
1304 blit
= blit
.GetSubBitmap( subrect
) ;
1308 // in this case we'd probably have to adjust the different coordinates, but
1309 // we have to find out proper contract first
1310 blit
= wxNullBitmap
;
1315 blit
= wxNullBitmap
;
1320 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1321 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1322 HIRect r
= CGRectMake( xxdest
, yydest
, wwdest
, hhdest
) ;
1323 HIViewDrawCGImage( cg
, &r
, image
) ;
1324 CGImageRelease( image
) ;
1331 CGContextRef cg = dynamic_cast<wxMacCGContext*>(source->GetGraphicContext())->GetNativeContext() ;
1332 void *data = CGBitmapContextGetData( cg ) ;
1334 return FALSE
; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1339 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1342 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1344 if ( str
.Length() == 0 )
1347 if ( m_logicalFunction
!= wxCOPY
)
1350 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1352 OSStatus status
= noErr
;
1353 ATSUTextLayout atsuLayout
;
1354 UniCharCount chars
= str
.Length() ;
1355 UniChar
* ubuf
= NULL
;
1356 #if SIZEOF_WCHAR_T == 4
1357 wxMBConvUTF16BE converter
;
1359 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1360 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1361 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1363 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1364 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1365 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1366 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1368 chars
= unicharlen
/ 2 ;
1371 ubuf
= (UniChar
*) str
.wc_str() ;
1373 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1374 chars
= wxWcslen( wchar
.data() ) ;
1375 ubuf
= (UniChar
*) wchar
.data() ;
1379 int drawX
= XLOG2DEVMAC(x
) ;
1380 int drawY
= YLOG2DEVMAC(y
) ;
1382 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1383 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1385 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1386 int iAngle
= int( angle
);
1390 if ( abs(iAngle
) > 0 )
1392 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1393 ATSUAttributeTag atsuTags
[] =
1395 kATSULineRotationTag
,
1397 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1401 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1405 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1406 atsuTags
, atsuSizes
, atsuValues
) ;
1409 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1410 ATSUAttributeTag atsuTags
[] =
1414 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1416 sizeof( CGContextRef
) ,
1418 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1422 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1423 atsuTags
, atsuSizes
, atsuValues
) ;
1426 ATSUTextMeasurement textBefore
;
1427 ATSUTextMeasurement textAfter
;
1428 ATSUTextMeasurement ascent
;
1429 ATSUTextMeasurement descent
;
1431 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1432 &textBefore
, &textAfter
, &ascent
, &descent
);
1433 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1437 if ( m_backgroundMode
== wxSOLID
)
1439 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1443 path
->AddLineToPoint(
1444 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1445 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1446 path
->AddLineToPoint(
1447 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1448 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1449 path
->AddLineToPoint(
1450 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1451 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1453 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1457 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1458 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1460 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1461 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1462 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1464 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1465 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1466 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1467 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1468 IntToFixed(0) , IntToFixed(0) );
1469 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1470 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1472 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1473 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1475 ::ATSUDisposeTextLayout(atsuLayout
);
1476 #if SIZEOF_WCHAR_T == 4
1481 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1483 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1484 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1487 bool wxDC::CanGetTextExtent() const
1489 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1493 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1494 wxCoord
*descent
, wxCoord
*externalLeading
,
1495 wxFont
*theFont
) const
1497 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1498 wxFont formerFont
= m_font
;
1501 // work around the constness
1502 *((wxFont
*)(&m_font
)) = *theFont
;
1506 if ( str
.Length() == 0 )
1509 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1511 OSStatus status
= noErr
;
1512 ATSUTextLayout atsuLayout
;
1513 UniCharCount chars
= str
.Length() ;
1514 UniChar
* ubuf
= NULL
;
1515 #if SIZEOF_WCHAR_T == 4
1516 wxMBConvUTF16BE converter
;
1518 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1519 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1520 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1522 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1523 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1524 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1525 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1527 chars
= unicharlen
/ 2 ;
1530 ubuf
= (UniChar
*) str
.wc_str() ;
1532 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1533 chars
= wxWcslen( wchar
.data() ) ;
1534 ubuf
= (UniChar
*) wchar
.data() ;
1539 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1540 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1542 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1544 ATSUTextMeasurement textBefore
;
1545 ATSUTextMeasurement textAfter
;
1546 ATSUTextMeasurement textAscent
;
1547 ATSUTextMeasurement textDescent
;
1549 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1550 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1553 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1555 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1556 if ( externalLeading
)
1557 *externalLeading
= 0 ;
1559 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1561 ::ATSUDisposeTextLayout(atsuLayout
);
1562 #if SIZEOF_WCHAR_T == 4
1567 // work around the constness
1568 *((wxFont
*)(&m_font
)) = formerFont
;
1574 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1576 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1579 widths
.Add(0, text
.Length());
1581 if (text
.Length() == 0)
1584 ATSUTextLayout atsuLayout
;
1585 UniCharCount chars
= text
.Length() ;
1586 UniChar
* ubuf
= NULL
;
1587 #if SIZEOF_WCHAR_T == 4
1588 wxMBConvUTF16BE converter
;
1590 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1591 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1592 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1594 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1595 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1596 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1597 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1599 chars
= unicharlen
/ 2 ;
1602 ubuf
= (UniChar
*) text
.wc_str() ;
1604 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1605 chars
= wxWcslen( wchar
.data() ) ;
1606 ubuf
= (UniChar
*) wchar
.data() ;
1611 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1612 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1614 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1615 unsigned long actualNumberOfBounds
= 0;
1616 ATSTrapezoid glyphBounds
;
1618 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1620 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1621 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1626 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1627 //unsigned char uch = s[i];
1630 ::ATSUDisposeTextLayout(atsuLayout
);
1634 wxCoord
wxDC::GetCharWidth(void) const
1637 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1641 wxCoord
wxDC::GetCharHeight(void) const
1644 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1648 void wxDC::Clear(void)
1650 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1652 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1654 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1655 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1656 switch( m_backgroundBrush
.MacGetBrushKind() )
1658 case kwxMacBrushTheme
:
1660 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1661 if ( HIThemeSetFill
!= 0 )
1663 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1664 CGContextFillRect(cg
, rect
);
1671 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1672 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1673 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1674 CGContextFillRect( cg
, rect
);
1676 // reset to normal value
1677 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1678 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1681 case kwxMacBrushThemeBackground
:
1683 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1684 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1685 if ( HIThemeDrawBackground
!= 0 )
1687 HIThemeBackgroundDrawInfo drawInfo
;
1688 drawInfo
.version
= 0 ;
1689 drawInfo
.state
= kThemeStateActive
;
1690 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1691 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1692 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1693 kHIThemeOrientationNormal
) ;
1694 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1695 kHIThemeOrientationNormal
) ;
1703 case kwxMacBrushColour
:
1705 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1706 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1707 CGContextFillRect(cg
, rect
);
1709 // reset to normal value
1710 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1711 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1718 void wxDC::MacInstallFont() const
1720 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1722 if( m_macATSUIStyle
)
1724 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1725 m_macATSUIStyle
= NULL
;
1730 OSStatus status
= noErr
;
1731 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1732 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1734 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1735 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1736 ATSUAttributeTag atsuTags
[] =
1741 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1744 sizeof( RGBColor
) ,
1746 // Boolean kTrue = true ;
1747 // Boolean kFalse = false ;
1749 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1750 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1755 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1756 atsuTags
, atsuSizes
, atsuValues
);
1758 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1762 // ---------------------------------------------------------------------------
1763 // coordinates transformations
1764 // ---------------------------------------------------------------------------
1766 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1768 return ((wxDC
*)this)->XDEV2LOG(x
);
1771 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1773 return ((wxDC
*)this)->YDEV2LOG(y
);
1776 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1778 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1781 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1783 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1786 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1788 return ((wxDC
*)this)->XLOG2DEV(x
);
1791 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1793 return ((wxDC
*)this)->YLOG2DEV(y
);
1796 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1798 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1801 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1803 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1806 #endif // wxMAC_USE_CORE_GRAPHICS