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 CGContextRef cg
= GetNativeContext() ;
259 return new wxMacCGPath() ;
262 // in case we only got a QDPort only create a cgref now
264 CGContextRef
wxMacCGContext::GetNativeContext()
266 if( m_cgContext
== NULL
)
269 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
270 OSStatus status
= QDBeginCGContext( (CGrafPtr
) m_qdPort
, &m_cgContext
) ;
271 CGContextSaveGState( m_cgContext
) ;
273 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
274 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
275 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
277 CGContextSaveGState( m_cgContext
) ;
279 SetBrush( m_brush
) ;
284 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
286 wxASSERT( m_cgContext
== NULL
) ;
288 CGContextSaveGState( m_cgContext
) ;
291 void wxMacCGContext::SetPen( const wxPen
&pen
)
294 if ( m_cgContext
== NULL
)
296 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
297 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
300 // we can benchmark performance, should go into a setting later
301 CGContextSetShouldAntialias( m_cgContext
, false ) ;
306 m_mode
= kCGPathFill
; // just a default
310 m_mode
= kCGPathFill
;
314 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
315 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
318 switch( pen
.GetCap() )
321 cap
= kCGLineCapRound
;
323 case wxCAP_PROJECTING
:
324 cap
= kCGLineCapSquare
;
327 cap
= kCGLineCapButt
;
330 cap
= kCGLineCapButt
;
333 CGContextSetLineCap( m_cgContext
, cap
) ;
336 switch( pen
.GetJoin() )
339 join
= kCGLineJoinBevel
;
342 join
= kCGLineJoinMiter
;
345 join
= kCGLineJoinRound
;
348 join
= kCGLineJoinMiter
;
351 CGContextSetLineJoin( m_cgContext
, join
) ;
353 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
355 m_mode
= kCGPathStroke
;
357 const float *lengths
= NULL
;
358 float *userLengths
= NULL
;
360 const float dotted
[] = { 3 , 3 };
361 const float dashed
[] = { 19 , 9 };
362 const float short_dashed
[] = { 9 , 6 };
363 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
365 switch( pen
.GetStyle() )
371 count
= WXSIZEOF(dotted
);
375 count
= WXSIZEOF(dashed
) ;
378 lengths
= short_dashed
;
379 count
= WXSIZEOF(short_dashed
) ;
382 lengths
= dotted_dashed
;
383 count
= WXSIZEOF(dotted_dashed
);
387 count
= pen
.GetDashes( &dashes
) ;
390 userLengths
= new float[count
] ;
391 for( int i
= 0 ; i
< count
; ++i
)
392 userLengths
[i
] = dashes
[i
] ;
394 lengths
= userLengths
;
400 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
401 delete[] userLengths
;
402 // we need to change the cap, otherwise everything overlaps
403 // and we get solid lines
405 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
407 if ( fill
&& stroke
)
409 m_mode
= kCGPathFillStroke
;
414 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
417 if ( m_cgContext
== NULL
)
420 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
421 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
424 // we can benchmark performance, should go into a setting later
425 CGContextSetShouldAntialias( m_cgContext
, false ) ;
431 m_mode
= kCGPathFill
; // just a default
435 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
436 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
437 m_mode
= kCGPathFill
;
441 m_mode
= kCGPathStroke
;
443 if ( fill
&& stroke
)
445 m_mode
= kCGPathFillStroke
;
451 // snippets from Sketch Sample from Apple :
453 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
455 This function locates, opens, and returns the profile reference for the calibrated
456 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
457 with the profile reference this function returns.
459 CMProfileRef
wxMacOpenGenericProfile(void)
461 static CMProfileRef cachedRGBProfileRef
= NULL
;
463 // we only create the profile reference once
464 if (cachedRGBProfileRef
== NULL
)
466 CMProfileLocation loc
;
468 loc
.locType
= cmPathBasedProfile
;
469 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
471 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
474 if (cachedRGBProfileRef
)
476 // clone the profile reference so that the caller has their own reference, not our cached one
477 CMCloneProfileRef(cachedRGBProfileRef
);
480 return cachedRGBProfileRef
;
484 Return the generic RGB color space. This is a 'get' function and the caller should
485 not release the returned value unless the caller retains it first. Usually callers
486 of this routine will immediately use the returned colorspace with CoreGraphics
487 so they typically do not need to retain it themselves.
489 This function creates the generic RGB color space once and hangs onto it so it can
490 return it whenever this function is called.
493 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
495 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
497 if (genericRGBColorSpace
== NULL
)
499 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
501 if (genericRGBProfile
)
503 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
504 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
506 // we opened the profile so it is up to us to close it
507 CMCloseProfile(genericRGBProfile
);
510 return genericRGBColorSpace
;
513 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
515 CGContextSaveGState(c
);
516 CGContextTranslateCTM(c
, center
.x
, center
.y
);
517 CGContextScaleCTM(c
, a
, b
);
518 CGContextMoveToPoint(c
, 1, 0);
519 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
520 CGContextClosePath(c
);
521 CGContextRestoreGState(c
);
524 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
528 if (ovalWidth
== 0 || ovalHeight
== 0)
530 CGContextAddRect(c
, rect
);
533 CGContextSaveGState(c
);
534 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
535 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
536 fw
= CGRectGetWidth(rect
) / ovalWidth
;
537 fh
= CGRectGetHeight(rect
) / ovalHeight
;
538 CGContextMoveToPoint(c
, fw
, fh
/2);
539 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
540 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
541 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
542 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
543 CGContextClosePath(c
);
544 CGContextRestoreGState(c
);
551 m_mm_to_pix_x
= mm2pt
;
552 m_mm_to_pix_y
= mm2pt
;
553 m_internalDeviceOriginX
= 0;
554 m_internalDeviceOriginY
= 0;
555 m_externalDeviceOriginX
= 0;
556 m_externalDeviceOriginY
= 0;
557 m_logicalScaleX
= 1.0;
558 m_logicalScaleY
= 1.0;
563 m_needComputeScaleX
= FALSE
;
564 m_needComputeScaleY
= FALSE
;
568 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
570 m_pen
= *wxBLACK_PEN
;
571 m_font
= *wxNORMAL_FONT
;
572 m_brush
= *wxWHITE_BRUSH
;
574 m_macATSUIStyle
= NULL
;
576 m_graphicContext
= NULL
;
581 if( m_macATSUIStyle
)
583 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
584 m_macATSUIStyle
= NULL
;
587 delete m_graphicContext
;
590 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
592 wxCHECK_RET( Ok(), wxT("invalid window dc") );
593 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
594 wxCoord xx
= XLOG2DEVMAC(x
);
595 wxCoord yy
= YLOG2DEVMAC(y
);
596 wxCoord w
= bmp
.GetWidth();
597 wxCoord h
= bmp
.GetHeight();
598 wxCoord ww
= XLOG2DEVREL(w
);
599 wxCoord hh
= YLOG2DEVREL(h
);
601 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
602 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
603 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
604 HIViewDrawCGImage( cg
, &r
, image
) ;
605 CGImageRelease( image
) ;
608 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
610 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
611 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
613 wxCoord xx
= XLOG2DEVMAC(x
);
614 wxCoord yy
= YLOG2DEVMAC(y
);
615 wxCoord w
= icon
.GetWidth();
616 wxCoord h
= icon
.GetHeight();
617 wxCoord ww
= XLOG2DEVREL(w
);
618 wxCoord hh
= YLOG2DEVREL(h
);
620 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
621 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
622 CGContextSaveGState(cg
);
623 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
624 CGContextScaleCTM(cg
, 1, -1);
625 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
626 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
627 CGContextRestoreGState( cg
) ;
630 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
632 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
633 wxCoord xx
, yy
, ww
, hh
;
636 ww
= XLOG2DEVREL(width
);
637 hh
= YLOG2DEVREL(height
);
639 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
640 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
641 CGContextClipToRect( cgContext
, clipRect
) ;
643 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
644 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
647 m_clipX1
= wxMax( m_clipX1
, xx
);
648 m_clipY1
= wxMax( m_clipY1
, yy
);
649 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
650 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
660 // TODO as soon as we don't reset the context for each operation anymore
661 // we have to update the context as well
664 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
666 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
669 DestroyClippingRegion();
673 region
.GetBox( x
, y
, w
, h
);
674 wxCoord xx
, yy
, ww
, hh
;
679 // if we have a scaling that we cannot map onto native regions
680 // we must use the box
681 if ( ww
!= w
|| hh
!= h
)
683 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
688 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
689 if ( xx != x || yy != y )
691 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
693 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
697 m_clipX1
= wxMax( m_clipX1
, xx
);
698 m_clipY1
= wxMax( m_clipY1
, yy
);
699 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
700 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
713 void wxDC::DestroyClippingRegion()
715 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
716 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
717 CGContextRestoreGState( cgContext
);
718 CGContextSaveGState( cgContext
);
720 SetBrush( m_brush
) ;
724 void wxDC::DoGetSizeMM( int* width
, int* height
) const
729 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
730 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
733 void wxDC::SetTextForeground( const wxColour
&col
)
735 wxCHECK_RET(Ok(), wxT("Invalid DC"));
736 if ( col
!= m_textForegroundColour
)
738 m_textForegroundColour
= col
;
743 void wxDC::SetTextBackground( const wxColour
&col
)
745 wxCHECK_RET(Ok(), wxT("Invalid DC"));
746 m_textBackgroundColour
= col
;
749 void wxDC::SetMapMode( int mode
)
754 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
757 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
760 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
763 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
767 SetLogicalScale( 1.0, 1.0 );
770 if (mode
!= wxMM_TEXT
)
772 m_needComputeScaleX
= TRUE
;
773 m_needComputeScaleY
= TRUE
;
777 void wxDC::SetUserScale( double x
, double y
)
779 // allow negative ? -> no
782 ComputeScaleAndOrigin();
785 void wxDC::SetLogicalScale( double x
, double y
)
790 ComputeScaleAndOrigin();
793 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
795 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
796 m_logicalOriginY
= y
* m_signY
;
797 ComputeScaleAndOrigin();
800 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
802 m_externalDeviceOriginX
= x
;
803 m_externalDeviceOriginY
= y
;
804 ComputeScaleAndOrigin();
807 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
809 m_signX
= (xLeftRight
? 1 : -1);
810 m_signY
= (yBottomUp
? -1 : 1);
811 ComputeScaleAndOrigin();
814 wxSize
wxDC::GetPPI() const
816 return wxSize(72, 72);
819 int wxDC::GetDepth() const
824 void wxDC::ComputeScaleAndOrigin()
826 // CMB: copy scale to see if it changes
827 double origScaleX
= m_scaleX
;
828 double origScaleY
= m_scaleY
;
829 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
830 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
831 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
832 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
833 // CMB: if scale has changed call SetPen to recalulate the line width
834 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
836 // this is a bit artificial, but we need to force wxDC to think
837 // the pen has changed
844 void wxDC::SetPalette( const wxPalette
& palette
)
848 void wxDC::SetBackgroundMode( int mode
)
850 m_backgroundMode
= mode
;
853 void wxDC::SetFont( const wxFont
&font
)
859 void wxDC::SetPen( const wxPen
&pen
)
864 if ( m_graphicContext
)
866 m_graphicContext
->SetPen( m_pen
) ;
870 void wxDC::SetBrush( const wxBrush
&brush
)
872 if (m_brush
== brush
)
875 if ( m_graphicContext
)
877 m_graphicContext
->SetBrush( m_brush
) ;
881 void wxDC::SetBackground( const wxBrush
&brush
)
883 if (m_backgroundBrush
== brush
)
885 m_backgroundBrush
= brush
;
886 if (!m_backgroundBrush
.Ok())
890 void wxDC::SetLogicalFunction( int function
)
892 if (m_logicalFunction
== function
)
894 m_logicalFunction
= function
;
897 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
898 const wxColour
& col
, int style
);
900 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
901 const wxColour
& col
, int style
)
903 return wxDoFloodFill(this, x
, y
, col
, style
);
906 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
908 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
909 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
910 wxMacPortSaver
helper((CGrafPtr
)m_macPort
) ;
913 XLOG2DEVMAC(x
) + m_macLocalOriginInPort
.x
- m_macLocalOrigin
.x
,
914 YLOG2DEVMAC(y
) + m_macLocalOriginInPort
.y
- m_macLocalOrigin
.y
, &colour
);
915 // Convert from Mac colour to wx
916 col
->Set( colour
.red
>> 8,
922 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
924 wxCHECK_RET(Ok(), wxT("Invalid DC"));
926 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
927 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
928 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
929 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
931 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
932 path
->MoveToPoint( xx1
, yy1
) ;
933 path
->AddLineToPoint( xx2
, yy2
) ;
934 path
->CloseSubpath() ;
935 m_graphicContext
->StrokePath( path
) ;
938 CalcBoundingBox(x1
, y1
);
939 CalcBoundingBox(x2
, y2
);
942 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
944 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
950 wxCoord xx
= XLOG2DEVMAC(x
);
951 wxCoord yy
= YLOG2DEVMAC(y
);
953 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
954 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
955 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
956 path
->CloseSubpath() ;
957 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
958 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
959 path
->CloseSubpath() ;
960 m_graphicContext
->StrokePath( path
) ;
963 CalcBoundingBox(x
, y
);
964 CalcBoundingBox(x
+w
, y
+h
);
968 * To draw arcs properly the angles need to be converted from the WX style:
969 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
970 * a normal axis on paper).
973 * Angles start on the +ve y axis and go clockwise.
976 static double wxConvertWXangleToMACangle(double angle
)
978 double newAngle
= 90 - angle
;
984 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
985 wxCoord x2
, wxCoord y2
,
986 wxCoord xc
, wxCoord yc
)
988 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
989 wxCoord xx1
= XLOG2DEVMAC(x1
);
990 wxCoord yy1
= YLOG2DEVMAC(y1
);
991 wxCoord xx2
= XLOG2DEVMAC(x2
);
992 wxCoord yy2
= YLOG2DEVMAC(y2
);
993 wxCoord xxc
= XLOG2DEVMAC(xc
);
994 wxCoord yyc
= YLOG2DEVMAC(yc
);
995 double dx
= xx1
- xxc
;
996 double dy
= yy1
- yyc
;
997 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
998 wxCoord rad
= (wxCoord
)radius
;
999 double radius1
, radius2
;
1000 if (xx1
== xx2
&& yy1
== yy2
)
1005 else if (radius
== 0.0)
1007 radius1
= radius2
= 0.0;
1011 radius1
= (xx1
- xxc
== 0) ?
1012 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1013 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1014 radius2
= (xx2
- xxc
== 0) ?
1015 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1016 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1018 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1019 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1020 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1023 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1024 CGContextRef ctx
= mctx
->GetNativeContext() ;
1025 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1026 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1029 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1030 double sa
, double ea
)
1032 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1034 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1035 // we have to make sure that the filling is always counter-clockwise
1038 wxCoord xx
= XLOG2DEVMAC(x
);
1039 wxCoord yy
= YLOG2DEVMAC(y
);
1040 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1041 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1042 // handle -ve width and/or height
1043 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1044 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1045 sa
= wxConvertWXangleToMACangle(sa
);
1046 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1047 CGContextRef ctx
= mctx
->GetNativeContext() ;
1048 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1049 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1052 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1054 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1055 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1058 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1059 wxCoord xoffset
, wxCoord yoffset
)
1061 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1063 wxCoord x1
, x2
, y1
, y2
;
1064 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1065 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1066 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1067 path
->MoveToPoint( x1
, y1
) ;
1068 for (int i
= 1; i
< n
; i
++)
1070 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1071 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1073 path
->AddLineToPoint( x2
, y2
) ;
1075 m_graphicContext
->StrokePath( path
) ;
1079 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1080 wxCoord xoffset
, wxCoord yoffset
,
1083 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1084 wxCoord x1
, x2
, y1
, y2
;
1085 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1088 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1089 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1091 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1092 path
->MoveToPoint( x1
, y1
) ;
1093 for (int i
= 1; i
< n
; i
++)
1095 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1096 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1098 path
->AddLineToPoint( x2
, y2
) ;
1100 if ( x1
!= x2
|| y1
!= y2
)
1102 path
->AddLineToPoint( x1
,y1
) ;
1104 path
->CloseSubpath() ;
1105 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1109 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1111 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1112 wxCoord xx
= XLOG2DEVMAC(x
);
1113 wxCoord yy
= YLOG2DEVMAC(y
);
1114 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1115 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1116 // CMB: draw nothing if transformed w or h is 0
1117 if (ww
== 0 || hh
== 0)
1119 // CMB: handle -ve width and/or height
1130 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1131 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1132 m_graphicContext
->DrawPath( path
) ;
1136 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1137 wxCoord width
, wxCoord height
,
1140 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1142 radius
= - radius
* ((width
< height
) ? width
: height
);
1143 wxCoord xx
= XLOG2DEVMAC(x
);
1144 wxCoord yy
= YLOG2DEVMAC(y
);
1145 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1146 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1147 // CMB: draw nothing if transformed w or h is 0
1148 if (ww
== 0 || hh
== 0)
1150 // CMB: handle -ve width and/or height
1161 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1162 CGContextRef ctx
= mctx
->GetNativeContext() ;
1163 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1164 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1167 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1169 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1170 wxCoord xx
= XLOG2DEVMAC(x
);
1171 wxCoord yy
= YLOG2DEVMAC(y
);
1172 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1173 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1174 // CMB: draw nothing if transformed w or h is 0
1175 if (ww
== 0 || hh
== 0)
1177 // CMB: handle -ve width and/or height
1189 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1190 CGContextRef ctx
= mctx
->GetNativeContext() ;
1191 if ( width
== height
)
1193 CGContextBeginPath(ctx
);
1194 CGContextAddArc(ctx
,
1201 CGContextClosePath(ctx
);
1203 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1207 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1208 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1212 bool wxDC::CanDrawBitmap(void) const
1217 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1218 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1219 wxCoord xsrcMask
, wxCoord ysrcMask
)
1221 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1222 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1223 if ( logical_func
== wxNO_OP
)
1225 if (xsrcMask
== -1 && ysrcMask
== -1)
1227 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1230 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1233 wxBitmap blit
= memdc
->GetSelectedObject() ;
1234 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1236 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1237 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1238 wxCoord ww
= XLOG2DEVREL(width
);
1239 wxCoord hh
= YLOG2DEVREL(height
);
1241 wxCoord bmpwidth
= blit
.GetWidth();
1242 wxCoord bmpheight
= blit
.GetHeight();
1244 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1246 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1247 blit
= blit
.GetSubBitmap( subrect
) ;
1250 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1251 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1252 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1253 HIViewDrawCGImage( cg
, &r
, image
) ;
1254 CGImageRelease( image
) ;
1259 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1264 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1267 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1269 if ( str
.Length() == 0 )
1272 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1274 OSStatus status
= noErr
;
1275 ATSUTextLayout atsuLayout
;
1276 UniCharCount chars
= str
.Length() ;
1277 UniChar
* ubuf
= NULL
;
1278 #if SIZEOF_WCHAR_T == 4
1279 wxMBConvUTF16BE converter
;
1281 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1282 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1283 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1285 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1286 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1287 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1288 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1290 chars
= unicharlen
/ 2 ;
1293 ubuf
= (UniChar
*) str
.wc_str() ;
1295 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1296 chars
= wxWcslen( wchar
.data() ) ;
1297 ubuf
= (UniChar
*) wchar
.data() ;
1301 int drawX
= XLOG2DEVMAC(x
) ;
1302 int drawY
= YLOG2DEVMAC(y
) ;
1304 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1305 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1307 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1308 int iAngle
= int( angle
);
1312 if ( abs(iAngle
) > 0 )
1314 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1315 ATSUAttributeTag atsuTags
[] =
1317 kATSULineRotationTag
,
1319 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1323 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1327 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1328 atsuTags
, atsuSizes
, atsuValues
) ;
1331 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1332 ATSUAttributeTag atsuTags
[] =
1336 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1338 sizeof( CGContextRef
) ,
1340 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1344 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1345 atsuTags
, atsuSizes
, atsuValues
) ;
1348 ATSUTextMeasurement textBefore
;
1349 ATSUTextMeasurement textAfter
;
1350 ATSUTextMeasurement ascent
;
1351 ATSUTextMeasurement descent
;
1353 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1354 &textBefore
, &textAfter
, &ascent
, &descent
);
1355 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1359 if ( m_backgroundMode
== wxSOLID
)
1361 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1365 path
->AddLineToPoint(
1366 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1367 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1368 path
->AddLineToPoint(
1369 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1370 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1371 path
->AddLineToPoint(
1372 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1373 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1375 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1379 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1380 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1382 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1383 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1384 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1386 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1387 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1388 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1389 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1390 IntToFixed(0) , IntToFixed(0) );
1391 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1392 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1394 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1395 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1397 ::ATSUDisposeTextLayout(atsuLayout
);
1398 #if SIZEOF_WCHAR_T == 4
1403 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1405 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1406 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1409 bool wxDC::CanGetTextExtent() const
1411 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1415 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1416 wxCoord
*descent
, wxCoord
*externalLeading
,
1417 wxFont
*theFont
) const
1419 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1420 wxFont formerFont
= m_font
;
1423 // work around the constness
1424 *((wxFont
*)(&m_font
)) = *theFont
;
1428 if ( str
.Length() == 0 )
1431 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1433 OSStatus status
= noErr
;
1434 ATSUTextLayout atsuLayout
;
1435 UniCharCount chars
= str
.Length() ;
1436 UniChar
* ubuf
= NULL
;
1437 #if SIZEOF_WCHAR_T == 4
1438 wxMBConvUTF16BE converter
;
1440 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1441 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1442 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1444 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1445 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1446 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1447 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1449 chars
= unicharlen
/ 2 ;
1452 ubuf
= (UniChar
*) str
.wc_str() ;
1454 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1455 chars
= wxWcslen( wchar
.data() ) ;
1456 ubuf
= (UniChar
*) wchar
.data() ;
1461 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1462 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1464 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1466 ATSUTextMeasurement textBefore
;
1467 ATSUTextMeasurement textAfter
;
1468 ATSUTextMeasurement textAscent
;
1469 ATSUTextMeasurement textDescent
;
1471 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1472 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1475 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1477 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1478 if ( externalLeading
)
1479 *externalLeading
= 0 ;
1481 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1483 ::ATSUDisposeTextLayout(atsuLayout
);
1484 #if SIZEOF_WCHAR_T == 4
1489 // work around the constness
1490 *((wxFont
*)(&m_font
)) = formerFont
;
1496 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1498 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1501 widths
.Add(0, text
.Length());
1503 if (text
.Length() == 0)
1506 ATSUTextLayout atsuLayout
;
1507 UniCharCount chars
= text
.Length() ;
1508 UniChar
* ubuf
= NULL
;
1509 #if SIZEOF_WCHAR_T == 4
1510 wxMBConvUTF16BE converter
;
1512 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1513 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1514 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1516 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1517 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1518 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1519 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1521 chars
= unicharlen
/ 2 ;
1524 ubuf
= (UniChar
*) text
.wc_str() ;
1526 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1527 chars
= wxWcslen( wchar
.data() ) ;
1528 ubuf
= (UniChar
*) wchar
.data() ;
1533 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1534 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1536 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1537 unsigned long actualNumberOfBounds
= 0;
1538 ATSTrapezoid glyphBounds
;
1540 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1542 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1543 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1548 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1549 //unsigned char uch = s[i];
1552 ::ATSUDisposeTextLayout(atsuLayout
);
1556 wxCoord
wxDC::GetCharWidth(void) const
1559 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1563 wxCoord
wxDC::GetCharHeight(void) const
1566 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1570 void wxDC::Clear(void)
1572 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1574 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1576 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1577 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1578 switch( m_backgroundBrush
.MacGetBrushKind() )
1580 case kwxMacBrushTheme
:
1582 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1583 if ( HIThemeSetFill
!= 0 )
1585 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1586 CGContextFillRect(cg
, rect
);
1593 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1594 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1595 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1596 CGContextFillRect( cg
, rect
);
1598 // reset to normal value
1599 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1600 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1603 case kwxMacBrushThemeBackground
:
1605 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1606 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1607 if ( HIThemeDrawBackground
!= 0 )
1609 HIThemeBackgroundDrawInfo drawInfo
;
1610 drawInfo
.version
= 0 ;
1611 drawInfo
.state
= kThemeStateActive
;
1612 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1613 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1614 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1615 kHIThemeOrientationNormal
) ;
1616 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1617 kHIThemeOrientationNormal
) ;
1625 case kwxMacBrushColour
:
1627 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1628 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1629 CGContextFillRect(cg
, rect
);
1631 // reset to normal value
1632 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1633 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1640 void wxDC::MacInstallFont() const
1642 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1644 if( m_macATSUIStyle
)
1646 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1647 m_macATSUIStyle
= NULL
;
1650 OSStatus status
= noErr
;
1651 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1652 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1654 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1655 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1656 ATSUAttributeTag atsuTags
[] =
1661 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1664 sizeof( RGBColor
) ,
1666 // Boolean kTrue = true ;
1667 // Boolean kFalse = false ;
1669 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1670 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1675 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1676 atsuTags
, atsuSizes
, atsuValues
);
1678 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1681 // ---------------------------------------------------------------------------
1682 // coordinates transformations
1683 // ---------------------------------------------------------------------------
1685 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1687 return ((wxDC
*)this)->XDEV2LOG(x
);
1690 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1692 return ((wxDC
*)this)->YDEV2LOG(y
);
1695 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1697 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1700 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1702 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1705 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1707 return ((wxDC
*)this)->XLOG2DEV(x
);
1710 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1712 return ((wxDC
*)this)->YLOG2DEV(y
);
1715 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1717 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1720 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1722 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1725 #endif // wxMAC_USE_CORE_GRAPHICS