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 wxFAIL_MSG( wxT("GetPixel not implemented on Core Graphics") ) ;
913 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
915 wxCHECK_RET(Ok(), wxT("Invalid DC"));
917 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
918 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
919 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
920 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
922 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
923 path
->MoveToPoint( xx1
, yy1
) ;
924 path
->AddLineToPoint( xx2
, yy2
) ;
925 path
->CloseSubpath() ;
926 m_graphicContext
->StrokePath( path
) ;
929 CalcBoundingBox(x1
, y1
);
930 CalcBoundingBox(x2
, y2
);
933 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
935 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
941 wxCoord xx
= XLOG2DEVMAC(x
);
942 wxCoord yy
= YLOG2DEVMAC(y
);
944 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
945 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
946 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
947 path
->CloseSubpath() ;
948 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
949 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
950 path
->CloseSubpath() ;
951 m_graphicContext
->StrokePath( path
) ;
954 CalcBoundingBox(x
, y
);
955 CalcBoundingBox(x
+w
, y
+h
);
959 * To draw arcs properly the angles need to be converted from the WX style:
960 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
961 * a normal axis on paper).
964 * Angles start on the +ve y axis and go clockwise.
967 static double wxConvertWXangleToMACangle(double angle
)
969 double newAngle
= 90 - angle
;
975 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
976 wxCoord x2
, wxCoord y2
,
977 wxCoord xc
, wxCoord yc
)
979 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
980 wxCoord xx1
= XLOG2DEVMAC(x1
);
981 wxCoord yy1
= YLOG2DEVMAC(y1
);
982 wxCoord xx2
= XLOG2DEVMAC(x2
);
983 wxCoord yy2
= YLOG2DEVMAC(y2
);
984 wxCoord xxc
= XLOG2DEVMAC(xc
);
985 wxCoord yyc
= YLOG2DEVMAC(yc
);
986 double dx
= xx1
- xxc
;
987 double dy
= yy1
- yyc
;
988 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
989 wxCoord rad
= (wxCoord
)radius
;
990 double radius1
, radius2
;
991 if (xx1
== xx2
&& yy1
== yy2
)
996 else if (radius
== 0.0)
998 radius1
= radius2
= 0.0;
1002 radius1
= (xx1
- xxc
== 0) ?
1003 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1004 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1005 radius2
= (xx2
- xxc
== 0) ?
1006 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1007 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1009 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1010 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1011 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1014 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1015 CGContextRef ctx
= mctx
->GetNativeContext() ;
1016 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1017 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1020 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1021 double sa
, double ea
)
1023 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1025 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1026 // we have to make sure that the filling is always counter-clockwise
1029 wxCoord xx
= XLOG2DEVMAC(x
);
1030 wxCoord yy
= YLOG2DEVMAC(y
);
1031 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1032 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1033 // handle -ve width and/or height
1034 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1035 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1036 sa
= wxConvertWXangleToMACangle(sa
);
1037 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1038 CGContextRef ctx
= mctx
->GetNativeContext() ;
1039 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1040 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1043 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1045 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1046 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1049 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1050 wxCoord xoffset
, wxCoord yoffset
)
1052 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1054 wxCoord x1
, x2
, y1
, y2
;
1055 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1056 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1057 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1058 path
->MoveToPoint( x1
, y1
) ;
1059 for (int i
= 1; i
< n
; i
++)
1061 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1062 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1064 path
->AddLineToPoint( x2
, y2
) ;
1066 m_graphicContext
->StrokePath( path
) ;
1070 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1071 wxCoord xoffset
, wxCoord yoffset
,
1074 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1075 wxCoord x1
, x2
, y1
, y2
;
1076 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1079 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1080 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1082 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1083 path
->MoveToPoint( x1
, y1
) ;
1084 for (int i
= 1; i
< n
; i
++)
1086 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1087 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1089 path
->AddLineToPoint( x2
, y2
) ;
1091 if ( x1
!= x2
|| y1
!= y2
)
1093 path
->AddLineToPoint( x1
,y1
) ;
1095 path
->CloseSubpath() ;
1096 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1100 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1102 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1103 wxCoord xx
= XLOG2DEVMAC(x
);
1104 wxCoord yy
= YLOG2DEVMAC(y
);
1105 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1106 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1107 // CMB: draw nothing if transformed w or h is 0
1108 if (ww
== 0 || hh
== 0)
1110 // CMB: handle -ve width and/or height
1121 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1122 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1123 m_graphicContext
->DrawPath( path
) ;
1127 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1128 wxCoord width
, wxCoord height
,
1131 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1133 radius
= - radius
* ((width
< height
) ? width
: height
);
1134 wxCoord xx
= XLOG2DEVMAC(x
);
1135 wxCoord yy
= YLOG2DEVMAC(y
);
1136 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1137 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1138 // CMB: draw nothing if transformed w or h is 0
1139 if (ww
== 0 || hh
== 0)
1141 // CMB: handle -ve width and/or height
1152 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1153 CGContextRef ctx
= mctx
->GetNativeContext() ;
1154 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1155 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1158 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1160 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1161 wxCoord xx
= XLOG2DEVMAC(x
);
1162 wxCoord yy
= YLOG2DEVMAC(y
);
1163 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1164 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1165 // CMB: draw nothing if transformed w or h is 0
1166 if (ww
== 0 || hh
== 0)
1168 // CMB: handle -ve width and/or height
1180 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1181 CGContextRef ctx
= mctx
->GetNativeContext() ;
1182 if ( width
== height
)
1184 CGContextBeginPath(ctx
);
1185 CGContextAddArc(ctx
,
1192 CGContextClosePath(ctx
);
1194 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1198 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1199 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1203 bool wxDC::CanDrawBitmap(void) const
1208 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1209 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1210 wxCoord xsrcMask
, wxCoord ysrcMask
)
1212 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1213 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1214 if ( logical_func
== wxNO_OP
)
1216 if (xsrcMask
== -1 && ysrcMask
== -1)
1218 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1221 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1224 wxBitmap blit
= memdc
->GetSelectedObject() ;
1225 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1227 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1228 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1229 wxCoord ww
= XLOG2DEVREL(width
);
1230 wxCoord hh
= YLOG2DEVREL(height
);
1232 wxCoord bmpwidth
= blit
.GetWidth();
1233 wxCoord bmpheight
= blit
.GetHeight();
1235 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1237 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1238 blit
= blit
.GetSubBitmap( subrect
) ;
1241 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1242 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1243 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1244 HIViewDrawCGImage( cg
, &r
, image
) ;
1245 CGImageRelease( image
) ;
1250 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1255 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1258 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1260 if ( str
.Length() == 0 )
1263 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1265 OSStatus status
= noErr
;
1266 ATSUTextLayout atsuLayout
;
1267 UniCharCount chars
= str
.Length() ;
1268 UniChar
* ubuf
= NULL
;
1269 #if SIZEOF_WCHAR_T == 4
1270 wxMBConvUTF16BE converter
;
1272 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1273 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1274 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1276 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1277 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1278 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1279 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1281 chars
= unicharlen
/ 2 ;
1284 ubuf
= (UniChar
*) str
.wc_str() ;
1286 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1287 chars
= wxWcslen( wchar
.data() ) ;
1288 ubuf
= (UniChar
*) wchar
.data() ;
1292 int drawX
= XLOG2DEVMAC(x
) ;
1293 int drawY
= YLOG2DEVMAC(y
) ;
1295 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1296 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1298 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1299 int iAngle
= int( angle
);
1303 if ( abs(iAngle
) > 0 )
1305 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1306 ATSUAttributeTag atsuTags
[] =
1308 kATSULineRotationTag
,
1310 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1314 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1318 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1319 atsuTags
, atsuSizes
, atsuValues
) ;
1322 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1323 ATSUAttributeTag atsuTags
[] =
1327 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1329 sizeof( CGContextRef
) ,
1331 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1335 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1336 atsuTags
, atsuSizes
, atsuValues
) ;
1339 ATSUTextMeasurement textBefore
;
1340 ATSUTextMeasurement textAfter
;
1341 ATSUTextMeasurement ascent
;
1342 ATSUTextMeasurement descent
;
1344 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1345 &textBefore
, &textAfter
, &ascent
, &descent
);
1346 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1350 if ( m_backgroundMode
== wxSOLID
)
1352 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1356 path
->AddLineToPoint(
1357 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1358 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1359 path
->AddLineToPoint(
1360 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1361 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1362 path
->AddLineToPoint(
1363 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1364 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1366 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1370 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1371 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1373 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1374 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1375 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1377 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1378 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1379 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1380 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1381 IntToFixed(0) , IntToFixed(0) );
1382 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1383 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1385 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1386 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1388 ::ATSUDisposeTextLayout(atsuLayout
);
1389 #if SIZEOF_WCHAR_T == 4
1394 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1396 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1397 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1400 bool wxDC::CanGetTextExtent() const
1402 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1406 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1407 wxCoord
*descent
, wxCoord
*externalLeading
,
1408 wxFont
*theFont
) const
1410 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1411 wxFont formerFont
= m_font
;
1414 // work around the constness
1415 *((wxFont
*)(&m_font
)) = *theFont
;
1419 if ( str
.Length() == 0 )
1422 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1424 OSStatus status
= noErr
;
1425 ATSUTextLayout atsuLayout
;
1426 UniCharCount chars
= str
.Length() ;
1427 UniChar
* ubuf
= NULL
;
1428 #if SIZEOF_WCHAR_T == 4
1429 wxMBConvUTF16BE converter
;
1431 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1432 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1433 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1435 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1436 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1437 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1438 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1440 chars
= unicharlen
/ 2 ;
1443 ubuf
= (UniChar
*) str
.wc_str() ;
1445 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1446 chars
= wxWcslen( wchar
.data() ) ;
1447 ubuf
= (UniChar
*) wchar
.data() ;
1452 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1453 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1455 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1457 ATSUTextMeasurement textBefore
;
1458 ATSUTextMeasurement textAfter
;
1459 ATSUTextMeasurement textAscent
;
1460 ATSUTextMeasurement textDescent
;
1462 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1463 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1466 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1468 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1469 if ( externalLeading
)
1470 *externalLeading
= 0 ;
1472 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1474 ::ATSUDisposeTextLayout(atsuLayout
);
1475 #if SIZEOF_WCHAR_T == 4
1480 // work around the constness
1481 *((wxFont
*)(&m_font
)) = formerFont
;
1487 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1489 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1492 widths
.Add(0, text
.Length());
1494 if (text
.Length() == 0)
1497 wxFAIL_MSG( wxT("Unimplemented for Core Graphics") ) ;
1502 wxCoord
wxDC::GetCharWidth(void) const
1505 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1509 wxCoord
wxDC::GetCharHeight(void) const
1512 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1516 void wxDC::Clear(void)
1518 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1520 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1522 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1523 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1524 switch( m_backgroundBrush
.MacGetBrushKind() )
1526 case kwxMacBrushTheme
:
1528 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1529 if ( HIThemeSetFill
!= 0 )
1531 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1532 CGContextFillRect(cg
, rect
);
1539 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1540 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1541 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1542 CGContextFillRect( cg
, rect
);
1544 // reset to normal value
1545 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1546 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1549 case kwxMacBrushThemeBackground
:
1551 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1552 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1553 if ( HIThemeDrawBackground
!= 0 )
1555 HIThemeBackgroundDrawInfo drawInfo
;
1556 drawInfo
.version
= 0 ;
1557 drawInfo
.state
= kThemeStateActive
;
1558 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1559 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1560 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1561 kHIThemeOrientationNormal
) ;
1562 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1563 kHIThemeOrientationNormal
) ;
1571 case kwxMacBrushColour
:
1573 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1574 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1575 CGContextFillRect(cg
, rect
);
1577 // reset to normal value
1578 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1579 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1586 void wxDC::MacInstallFont() const
1588 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1590 if( m_macATSUIStyle
)
1592 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1593 m_macATSUIStyle
= NULL
;
1596 OSStatus status
= noErr
;
1597 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1598 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1600 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1601 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1602 ATSUAttributeTag atsuTags
[] =
1607 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1610 sizeof( RGBColor
) ,
1612 // Boolean kTrue = true ;
1613 // Boolean kFalse = false ;
1615 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1616 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1621 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1622 atsuTags
, atsuSizes
, atsuValues
);
1624 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1627 // ---------------------------------------------------------------------------
1628 // coordinates transformations
1629 // ---------------------------------------------------------------------------
1631 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1633 return ((wxDC
*)this)->XDEV2LOG(x
);
1636 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1638 return ((wxDC
*)this)->YDEV2LOG(y
);
1641 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1643 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1646 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1648 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1651 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1653 return ((wxDC
*)this)->XLOG2DEV(x
);
1656 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1658 return ((wxDC
*)this)->YLOG2DEV(y
);
1661 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1663 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1666 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1668 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1671 #endif // wxMAC_USE_CORE_GRAPHICS