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 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1013 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1014 CGContextRef ctx
= mctx
->GetNativeContext() ;
1015 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1016 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1019 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1020 double sa
, double ea
)
1022 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1024 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1025 // we have to make sure that the filling is always counter-clockwise
1028 wxCoord xx
= XLOG2DEVMAC(x
);
1029 wxCoord yy
= YLOG2DEVMAC(y
);
1030 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1031 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1032 // handle -ve width and/or height
1033 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1034 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1035 sa
= wxConvertWXangleToMACangle(sa
);
1036 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1037 CGContextRef ctx
= mctx
->GetNativeContext() ;
1038 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1039 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1042 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1044 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1045 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1048 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1049 wxCoord xoffset
, wxCoord yoffset
)
1051 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1053 wxCoord x1
, x2
, y1
, y2
;
1054 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1055 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1056 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1057 path
->MoveToPoint( x1
, y1
) ;
1058 for (int i
= 1; i
< n
; i
++)
1060 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1061 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1063 path
->AddLineToPoint( x2
, y2
) ;
1065 m_graphicContext
->StrokePath( path
) ;
1069 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1070 wxCoord xoffset
, wxCoord yoffset
,
1073 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1074 wxCoord x1
, x2
, y1
, y2
;
1075 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1078 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1079 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1081 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1082 path
->MoveToPoint( x1
, y1
) ;
1083 for (int i
= 1; i
< n
; i
++)
1085 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1086 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1088 path
->AddLineToPoint( x2
, y2
) ;
1090 if ( x1
!= x2
|| y1
!= y2
)
1092 path
->AddLineToPoint( x1
,y1
) ;
1094 path
->CloseSubpath() ;
1095 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1099 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1101 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1102 wxCoord xx
= XLOG2DEVMAC(x
);
1103 wxCoord yy
= YLOG2DEVMAC(y
);
1104 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1105 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1106 // CMB: draw nothing if transformed w or h is 0
1107 if (ww
== 0 || hh
== 0)
1109 // CMB: handle -ve width and/or height
1120 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1121 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1122 m_graphicContext
->DrawPath( path
) ;
1126 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1127 wxCoord width
, wxCoord height
,
1130 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1132 radius
= - radius
* ((width
< height
) ? width
: height
);
1133 wxCoord xx
= XLOG2DEVMAC(x
);
1134 wxCoord yy
= YLOG2DEVMAC(y
);
1135 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1136 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1137 // CMB: draw nothing if transformed w or h is 0
1138 if (ww
== 0 || hh
== 0)
1140 // CMB: handle -ve width and/or height
1151 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1152 CGContextRef ctx
= mctx
->GetNativeContext() ;
1153 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1154 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1157 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1159 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1160 wxCoord xx
= XLOG2DEVMAC(x
);
1161 wxCoord yy
= YLOG2DEVMAC(y
);
1162 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1163 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1164 // CMB: draw nothing if transformed w or h is 0
1165 if (ww
== 0 || hh
== 0)
1167 // CMB: handle -ve width and/or height
1179 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1180 CGContextRef ctx
= mctx
->GetNativeContext() ;
1181 if ( width
== height
)
1183 CGContextBeginPath(ctx
);
1184 CGContextAddArc(ctx
,
1191 CGContextClosePath(ctx
);
1193 CGContextDrawPath( ctx
, kCGPathFillStroke
) ;
1197 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1198 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1202 bool wxDC::CanDrawBitmap(void) const
1207 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1208 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1209 wxCoord xsrcMask
, wxCoord ysrcMask
)
1211 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1212 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1213 if ( logical_func
== wxNO_OP
)
1215 if (xsrcMask
== -1 && ysrcMask
== -1)
1217 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1220 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1223 wxBitmap blit
= memdc
->GetSelectedObject() ;
1224 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1226 wxCoord xxdest
= XLOG2DEVMAC(xdest
);
1227 wxCoord yydest
= YLOG2DEVMAC(ydest
);
1228 wxCoord ww
= XLOG2DEVREL(width
);
1229 wxCoord hh
= YLOG2DEVREL(height
);
1231 wxCoord bmpwidth
= blit
.GetWidth();
1232 wxCoord bmpheight
= blit
.GetHeight();
1234 if ( xsrc
!= 0 || ysrc
!= 0 || bmpwidth
!= width
|| bmpheight
!= height
)
1236 wxRect
subrect( xsrc
, ysrc
, width
, height
) ;
1237 blit
= blit
.GetSubBitmap( subrect
) ;
1240 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1241 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1242 HIRect r
= CGRectMake( xxdest
, yydest
, ww
, hh
) ;
1243 HIViewDrawCGImage( cg
, &r
, image
) ;
1244 CGImageRelease( image
) ;
1249 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1254 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1257 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1259 if ( str
.Length() == 0 )
1262 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1264 OSStatus status
= noErr
;
1265 ATSUTextLayout atsuLayout
;
1266 UniCharCount chars
= str
.Length() ;
1267 UniChar
* ubuf
= NULL
;
1268 #if SIZEOF_WCHAR_T == 4
1269 wxMBConvUTF16BE converter
;
1271 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1272 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1273 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1275 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1276 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1277 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1278 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1280 chars
= unicharlen
/ 2 ;
1283 ubuf
= (UniChar
*) str
.wc_str() ;
1285 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1286 chars
= wxWcslen( wchar
.data() ) ;
1287 ubuf
= (UniChar
*) wchar
.data() ;
1291 int drawX
= XLOG2DEVMAC(x
) ;
1292 int drawY
= YLOG2DEVMAC(y
) ;
1294 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1295 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1297 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1298 int iAngle
= int( angle
);
1302 if ( abs(iAngle
) > 0 )
1304 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1305 ATSUAttributeTag atsuTags
[] =
1307 kATSULineRotationTag
,
1309 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1313 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1317 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1318 atsuTags
, atsuSizes
, atsuValues
) ;
1321 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1322 ATSUAttributeTag atsuTags
[] =
1326 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1328 sizeof( CGContextRef
) ,
1330 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1334 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1335 atsuTags
, atsuSizes
, atsuValues
) ;
1338 ATSUTextMeasurement textBefore
;
1339 ATSUTextMeasurement textAfter
;
1340 ATSUTextMeasurement ascent
;
1341 ATSUTextMeasurement descent
;
1343 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1344 &textBefore
, &textAfter
, &ascent
, &descent
);
1345 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1349 if ( m_backgroundMode
== wxSOLID
)
1351 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1355 path
->AddLineToPoint(
1356 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1357 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1358 path
->AddLineToPoint(
1359 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1360 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1361 path
->AddLineToPoint(
1362 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1363 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1365 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1369 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1370 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1372 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1373 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1374 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1376 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1377 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1378 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1379 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1380 IntToFixed(0) , IntToFixed(0) );
1381 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1382 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1384 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1385 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1387 ::ATSUDisposeTextLayout(atsuLayout
);
1388 #if SIZEOF_WCHAR_T == 4
1393 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1395 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1396 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1399 bool wxDC::CanGetTextExtent() const
1401 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1405 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1406 wxCoord
*descent
, wxCoord
*externalLeading
,
1407 wxFont
*theFont
) const
1409 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1410 wxFont formerFont
= m_font
;
1413 // work around the constness
1414 *((wxFont
*)(&m_font
)) = *theFont
;
1418 if ( str
.Length() == 0 )
1421 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1423 OSStatus status
= noErr
;
1424 ATSUTextLayout atsuLayout
;
1425 UniCharCount chars
= str
.Length() ;
1426 UniChar
* ubuf
= NULL
;
1427 #if SIZEOF_WCHAR_T == 4
1428 wxMBConvUTF16BE converter
;
1430 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1431 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1432 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1434 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1435 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1436 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1437 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1439 chars
= unicharlen
/ 2 ;
1442 ubuf
= (UniChar
*) str
.wc_str() ;
1444 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1445 chars
= wxWcslen( wchar
.data() ) ;
1446 ubuf
= (UniChar
*) wchar
.data() ;
1451 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1452 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1454 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1456 ATSUTextMeasurement textBefore
;
1457 ATSUTextMeasurement textAfter
;
1458 ATSUTextMeasurement textAscent
;
1459 ATSUTextMeasurement textDescent
;
1461 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1462 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1465 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1467 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1468 if ( externalLeading
)
1469 *externalLeading
= 0 ;
1471 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1473 ::ATSUDisposeTextLayout(atsuLayout
);
1474 #if SIZEOF_WCHAR_T == 4
1479 // work around the constness
1480 *((wxFont
*)(&m_font
)) = formerFont
;
1486 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1488 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1491 widths
.Add(0, text
.Length());
1493 if (text
.Length() == 0)
1496 wxFAIL_MSG( wxT("Unimplemented for Core Graphics") ) ;
1501 wxCoord
wxDC::GetCharWidth(void) const
1504 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1508 wxCoord
wxDC::GetCharHeight(void) const
1511 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1515 void wxDC::Clear(void)
1517 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1519 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1521 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1522 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1523 switch( m_backgroundBrush
.MacGetBrushKind() )
1525 case kwxMacBrushTheme
:
1527 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1528 if ( HIThemeSetFill
!= 0 )
1530 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1531 CGContextFillRect(cg
, rect
);
1538 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1539 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1540 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1541 CGContextFillRect( cg
, rect
);
1543 // reset to normal value
1544 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1545 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1548 case kwxMacBrushThemeBackground
:
1550 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1551 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1552 if ( HIThemeDrawBackground
!= 0 )
1554 HIThemeBackgroundDrawInfo drawInfo
;
1555 drawInfo
.version
= 0 ;
1556 drawInfo
.state
= kThemeStateActive
;
1557 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1558 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1559 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1560 kHIThemeOrientationNormal
) ;
1561 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1562 kHIThemeOrientationNormal
) ;
1570 case kwxMacBrushColour
:
1572 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1573 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1574 CGContextFillRect(cg
, rect
);
1576 // reset to normal value
1577 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1578 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1585 void wxDC::MacInstallFont() const
1587 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1589 if( m_macATSUIStyle
)
1591 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1592 m_macATSUIStyle
= NULL
;
1595 OSStatus status
= noErr
;
1596 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1597 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1599 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1600 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1601 ATSUAttributeTag atsuTags
[] =
1606 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1609 sizeof( RGBColor
) ,
1611 // Boolean kTrue = true ;
1612 // Boolean kFalse = false ;
1614 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1615 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1620 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1621 atsuTags
, atsuSizes
, atsuValues
);
1623 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1626 // ---------------------------------------------------------------------------
1627 // coordinates transformations
1628 // ---------------------------------------------------------------------------
1630 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1632 return ((wxDC
*)this)->XDEV2LOG(x
);
1635 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1637 return ((wxDC
*)this)->YDEV2LOG(y
);
1640 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1642 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1645 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1647 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1650 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1652 return ((wxDC
*)this)->XLOG2DEV(x
);
1655 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1657 return ((wxDC
*)this)->YLOG2DEV(y
);
1660 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1662 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1665 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1667 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1670 #endif // wxMAC_USE_CORE_GRAPHICS