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
) ;
75 // guard against half constructed objects, this just leads to a empty clip
79 win
->MacWindowToRootWindow( &x
,&y
) ;
80 // get area including focus rect
81 CopyRgn( (RgnHandle
) ((wxWindow
*)win
)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip
) ;
82 if ( !EmptyRgn( m_newClip
) )
83 OffsetRgn( m_newClip
, x
, y
) ;
86 SetClip( m_newClip
) ;
90 wxMacWindowClipper::~wxMacWindowClipper()
92 SetPort( m_newPort
) ;
93 SetClip( m_formerClip
) ;
94 DisposeRgn( m_newClip
) ;
95 DisposeRgn( m_formerClip
) ;
98 wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow
* win
) :
99 wxMacWindowClipper( win
)
101 // the port is already set at this point
102 m_newPort
=(GrafPtr
) GetWindowPort((WindowRef
) win
->MacGetTopLevelWindowRef()) ;
103 GetThemeDrawingState( &m_themeDrawingState
) ;
106 wxMacWindowStateSaver::~wxMacWindowStateSaver()
108 SetPort( m_newPort
) ;
109 SetThemeDrawingState( m_themeDrawingState
, true ) ;
112 // minimal implementation only used for appearance drawing < 10.3
114 wxMacPortSetter::wxMacPortSetter( const wxDC
* dc
) :
115 m_ph( (GrafPtr
) dc
->m_macPort
)
117 wxASSERT( dc
->Ok() ) ;
119 // dc->MacSetupPort(&m_ph) ;
121 wxMacPortSetter::~wxMacPortSetter()
123 // m_dc->MacCleanupPort(&m_ph) ;
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
130 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
131 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
132 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
134 //-----------------------------------------------------------------------------
135 // device context implementation
137 // more and more of the dc functionality should be implemented by calling
138 // the appropricate wxMacCGContext, but we will have to do that step by step
139 // also coordinate conversions should be moved to native matrix ops
140 //-----------------------------------------------------------------------------
142 wxMacCGPath::wxMacCGPath()
144 m_path
= CGPathCreateMutable() ;
147 wxMacCGPath::~wxMacCGPath()
149 CGPathRelease( m_path
) ;
152 // Starts a new subpath at
153 void wxMacCGPath::MoveToPoint( wxCoord x1
, wxCoord y1
)
155 CGPathMoveToPoint( m_path
, NULL
, x1
, y1
) ;
158 void wxMacCGPath::AddLineToPoint( wxCoord x1
, wxCoord y1
)
160 CGPathAddLineToPoint( m_path
, NULL
, x1
, y1
) ;
163 void wxMacCGPath::AddRectangle( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
165 CGRect cgRect
= { { x
, y
} , { w
, h
} } ;
166 CGPathAddRect( m_path
, NULL
, cgRect
) ;
169 void wxMacCGPath::AddCircle( wxCoord x
, wxCoord y
, wxCoord r
)
171 CGPathAddArc( m_path
, NULL
, x
, y
, r
, 0.0 , 2 * M_PI
, true ) ;
174 // closes the current subpath
175 void wxMacCGPath::CloseSubpath()
177 CGPathCloseSubpath( m_path
) ;
180 CGPathRef
wxMacCGPath::GetPath() const
185 // we always stock two context states, one at entry, the other one after
186 // changing to HI Graphics orientation (this one is used for getting back clippings etc)
188 wxMacCGContext::wxMacCGContext( CGrafPtr port
)
194 wxMacCGContext::wxMacCGContext( CGContextRef cgcontext
)
197 m_cgContext
= cgcontext
;
198 CGContextSaveGState( m_cgContext
) ;
199 CGContextSaveGState( m_cgContext
) ;
202 wxMacCGContext::wxMacCGContext()
208 wxMacCGContext::~wxMacCGContext()
212 CGContextSynchronize( m_cgContext
) ;
213 CGContextRestoreGState( m_cgContext
) ;
214 CGContextRestoreGState( m_cgContext
) ;
217 CGContextRelease( m_cgContext
) ;
221 void wxMacCGContext::Clip( const wxRegion
®ion
)
223 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
226 void wxMacCGContext::StrokePath( const wxGraphicPath
*p
)
228 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
229 CGContextBeginPath( m_cgContext
) ;
230 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
231 CGContextClosePath( m_cgContext
) ;
232 CGContextStrokePath( m_cgContext
) ;
235 void wxMacCGContext::DrawPath( const wxGraphicPath
*p
, int fillStyle
)
237 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
238 CGPathDrawingMode mode
= m_mode
;
239 if ( fillStyle
== wxODDEVEN_RULE
)
241 if ( mode
== kCGPathFill
)
242 mode
= kCGPathEOFill
;
243 else if ( mode
== kCGPathFillStroke
)
244 mode
= kCGPathEOFillStroke
;
246 CGContextBeginPath( m_cgContext
) ;
247 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
248 CGContextClosePath( m_cgContext
) ;
249 CGContextDrawPath( m_cgContext
, mode
) ;
252 void wxMacCGContext::FillPath( const wxGraphicPath
*p
, const wxColor
&fillColor
, int fillStyle
)
254 const wxMacCGPath
* path
= dynamic_cast< const wxMacCGPath
*>( p
) ;
255 CGContextSaveGState( m_cgContext
) ;
257 RGBColor col
= MAC_WXCOLORREF( fillColor
.GetPixel() ) ;
258 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
259 CGPathDrawingMode mode
= kCGPathFill
;
261 if ( fillStyle
== wxODDEVEN_RULE
)
262 mode
= kCGPathEOFill
;
264 CGContextBeginPath( m_cgContext
) ;
265 CGContextAddPath( m_cgContext
, path
->GetPath() ) ;
266 CGContextClosePath( m_cgContext
) ;
267 CGContextDrawPath( m_cgContext
, mode
) ;
269 CGContextRestoreGState( m_cgContext
) ;
272 wxGraphicPath
* wxMacCGContext::CreatePath()
274 // make sure that we now have a real cgref, before doing
275 // anything with paths
276 CGContextRef cg
= GetNativeContext() ;
278 return new wxMacCGPath() ;
281 // in case we only got a QDPort only create a cgref now
283 CGContextRef
wxMacCGContext::GetNativeContext()
285 if( m_cgContext
== NULL
)
288 GetPortBounds( (CGrafPtr
) m_qdPort
, &bounds
) ;
289 OSStatus status
= CreateCGContextForPort((CGrafPtr
) m_qdPort
, &m_cgContext
) ;
290 CGContextSaveGState( m_cgContext
) ;
292 wxASSERT_MSG( status
== noErr
, wxT("Cannot nest wxDCs on the same window") ) ;
293 CGContextTranslateCTM( m_cgContext
, 0 , bounds
.bottom
- bounds
.top
) ;
294 CGContextScaleCTM( m_cgContext
, 1 , -1 ) ;
296 CGContextSaveGState( m_cgContext
) ;
298 SetBrush( m_brush
) ;
303 void wxMacCGContext::SetNativeContext( CGContextRef cg
)
305 wxASSERT( m_cgContext
== NULL
) ;
307 CGContextSaveGState( m_cgContext
) ;
310 void wxMacCGContext::SetPen( const wxPen
&pen
)
313 if ( m_cgContext
== NULL
)
315 bool fill
= m_brush
.GetStyle() != wxTRANSPARENT
;
316 bool stroke
= pen
.GetStyle() != wxTRANSPARENT
;
319 // we can benchmark performance, should go into a setting later
320 CGContextSetShouldAntialias( m_cgContext
, false ) ;
325 m_mode
= kCGPathFill
; // just a default
329 m_mode
= kCGPathFill
;
333 RGBColor col
= MAC_WXCOLORREF( pen
.GetColour().GetPixel() ) ;
334 CGContextSetRGBStrokeColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
337 switch( pen
.GetCap() )
340 cap
= kCGLineCapRound
;
342 case wxCAP_PROJECTING
:
343 cap
= kCGLineCapSquare
;
346 cap
= kCGLineCapButt
;
349 cap
= kCGLineCapButt
;
352 CGContextSetLineCap( m_cgContext
, cap
) ;
355 switch( pen
.GetJoin() )
358 join
= kCGLineJoinBevel
;
361 join
= kCGLineJoinMiter
;
364 join
= kCGLineJoinRound
;
367 join
= kCGLineJoinMiter
;
370 CGContextSetLineJoin( m_cgContext
, join
) ;
372 CGContextSetLineWidth( m_cgContext
, pen
.GetWidth() == 0 ? 0.1 : pen
.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
374 m_mode
= kCGPathStroke
;
376 const float *lengths
= NULL
;
377 float *userLengths
= NULL
;
379 const float dotted
[] = { 3 , 3 };
380 const float dashed
[] = { 19 , 9 };
381 const float short_dashed
[] = { 9 , 6 };
382 const float dotted_dashed
[] = { 9 , 6 , 3 , 3 };
384 switch( pen
.GetStyle() )
390 count
= WXSIZEOF(dotted
);
394 count
= WXSIZEOF(dashed
) ;
397 lengths
= short_dashed
;
398 count
= WXSIZEOF(short_dashed
) ;
401 lengths
= dotted_dashed
;
402 count
= WXSIZEOF(dotted_dashed
);
406 count
= pen
.GetDashes( &dashes
) ;
409 userLengths
= new float[count
] ;
410 for( int i
= 0 ; i
< count
; ++i
)
411 userLengths
[i
] = dashes
[i
] ;
413 lengths
= userLengths
;
419 CGContextSetLineDash( m_cgContext
, 0 , lengths
, count
) ;
420 delete[] userLengths
;
421 // we need to change the cap, otherwise everything overlaps
422 // and we get solid lines
424 CGContextSetLineCap( m_cgContext
, kCGLineCapButt
) ;
426 if ( fill
&& stroke
)
428 m_mode
= kCGPathFillStroke
;
433 void wxMacCGContext::SetBrush( const wxBrush
&brush
)
436 if ( m_cgContext
== NULL
)
439 bool fill
= brush
.GetStyle() != wxTRANSPARENT
;
440 bool stroke
= m_pen
.GetStyle() != wxTRANSPARENT
;
443 // we can benchmark performance, should go into a setting later
444 CGContextSetShouldAntialias( m_cgContext
, false ) ;
450 m_mode
= kCGPathFill
; // just a default
454 RGBColor col
= MAC_WXCOLORREF( brush
.GetColour().GetPixel() ) ;
455 CGContextSetRGBFillColor( m_cgContext
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
456 m_mode
= kCGPathFill
;
460 m_mode
= kCGPathStroke
;
462 if ( fill
&& stroke
)
464 m_mode
= kCGPathFillStroke
;
470 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
472 CGContextSaveGState(c
);
473 CGContextTranslateCTM(c
, center
.x
, center
.y
);
474 CGContextScaleCTM(c
, a
, b
);
475 CGContextMoveToPoint(c
, 1, 0);
476 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
477 CGContextClosePath(c
);
478 CGContextRestoreGState(c
);
481 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
485 if (ovalWidth
== 0 || ovalHeight
== 0)
487 CGContextAddRect(c
, rect
);
490 CGContextSaveGState(c
);
491 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
492 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
493 fw
= CGRectGetWidth(rect
) / ovalWidth
;
494 fh
= CGRectGetHeight(rect
) / ovalHeight
;
495 CGContextMoveToPoint(c
, fw
, fh
/2);
496 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
497 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
498 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
499 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
500 CGContextClosePath(c
);
501 CGContextRestoreGState(c
);
508 m_mm_to_pix_x
= mm2pt
;
509 m_mm_to_pix_y
= mm2pt
;
510 m_internalDeviceOriginX
= 0;
511 m_internalDeviceOriginY
= 0;
512 m_externalDeviceOriginX
= 0;
513 m_externalDeviceOriginY
= 0;
514 m_logicalScaleX
= 1.0;
515 m_logicalScaleY
= 1.0;
520 m_needComputeScaleX
= FALSE
;
521 m_needComputeScaleY
= FALSE
;
525 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
527 m_pen
= *wxBLACK_PEN
;
528 m_font
= *wxNORMAL_FONT
;
529 m_brush
= *wxWHITE_BRUSH
;
531 m_macATSUIStyle
= NULL
;
533 m_graphicContext
= NULL
;
538 if( m_macATSUIStyle
)
540 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
541 m_macATSUIStyle
= NULL
;
544 delete m_graphicContext
;
547 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
549 wxCHECK_RET( Ok(), wxT("invalid window dc") );
550 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
551 wxCoord xx
= XLOG2DEVMAC(x
);
552 wxCoord yy
= YLOG2DEVMAC(y
);
553 wxCoord w
= bmp
.GetWidth();
554 wxCoord h
= bmp
.GetHeight();
555 wxCoord ww
= XLOG2DEVREL(w
);
556 wxCoord hh
= YLOG2DEVREL(h
);
558 CGContextRef cg
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
559 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
560 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
561 HIViewDrawCGImage( cg
, &r
, image
) ;
562 CGImageRelease( image
) ;
565 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
567 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
568 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
570 wxCoord xx
= XLOG2DEVMAC(x
);
571 wxCoord yy
= YLOG2DEVMAC(y
);
572 wxCoord w
= icon
.GetWidth();
573 wxCoord h
= icon
.GetHeight();
574 wxCoord ww
= XLOG2DEVREL(w
);
575 wxCoord hh
= YLOG2DEVREL(h
);
577 CGContextRef cg
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
578 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
579 CGContextSaveGState(cg
);
580 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
581 CGContextScaleCTM(cg
, 1, -1);
582 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
583 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
584 CGContextRestoreGState( cg
) ;
587 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
589 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
590 wxCoord xx
, yy
, ww
, hh
;
593 ww
= XLOG2DEVREL(width
);
594 hh
= YLOG2DEVREL(height
);
596 CGContextRef cgContext
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
597 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
598 CGContextClipToRect( cgContext
, clipRect
) ;
600 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
601 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
604 m_clipX1
= wxMax( m_clipX1
, xx
);
605 m_clipY1
= wxMax( m_clipY1
, yy
);
606 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
607 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
617 // TODO as soon as we don't reset the context for each operation anymore
618 // we have to update the context as well
621 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
623 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
626 DestroyClippingRegion();
630 region
.GetBox( x
, y
, w
, h
);
631 wxCoord xx
, yy
, ww
, hh
;
636 // if we have a scaling that we cannot map onto native regions
637 // we must use the box
638 if ( ww
!= w
|| hh
!= h
)
640 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
645 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
646 if ( xx != x || yy != y )
648 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
650 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
654 m_clipX1
= wxMax( m_clipX1
, xx
);
655 m_clipY1
= wxMax( m_clipY1
, yy
);
656 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
657 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
670 void wxDC::DestroyClippingRegion()
672 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
673 CGContextRef cgContext
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
674 CGContextRestoreGState( cgContext
);
675 CGContextSaveGState( cgContext
);
677 SetBrush( m_brush
) ;
681 void wxDC::DoGetSizeMM( int* width
, int* height
) const
686 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
687 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
690 void wxDC::SetTextForeground( const wxColour
&col
)
692 wxCHECK_RET(Ok(), wxT("Invalid DC"));
693 if ( col
!= m_textForegroundColour
)
695 m_textForegroundColour
= col
;
700 void wxDC::SetTextBackground( const wxColour
&col
)
702 wxCHECK_RET(Ok(), wxT("Invalid DC"));
703 m_textBackgroundColour
= col
;
706 void wxDC::SetMapMode( int mode
)
711 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
714 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
717 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
720 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
724 SetLogicalScale( 1.0, 1.0 );
727 if (mode
!= wxMM_TEXT
)
729 m_needComputeScaleX
= TRUE
;
730 m_needComputeScaleY
= TRUE
;
734 void wxDC::SetUserScale( double x
, double y
)
736 // allow negative ? -> no
739 ComputeScaleAndOrigin();
742 void wxDC::SetLogicalScale( double x
, double y
)
747 ComputeScaleAndOrigin();
750 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
752 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
753 m_logicalOriginY
= y
* m_signY
;
754 ComputeScaleAndOrigin();
757 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
759 m_externalDeviceOriginX
= x
;
760 m_externalDeviceOriginY
= y
;
761 ComputeScaleAndOrigin();
764 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
766 m_signX
= (xLeftRight
? 1 : -1);
767 m_signY
= (yBottomUp
? -1 : 1);
768 ComputeScaleAndOrigin();
771 wxSize
wxDC::GetPPI() const
773 return wxSize(72, 72);
776 int wxDC::GetDepth() const
781 void wxDC::ComputeScaleAndOrigin()
783 // CMB: copy scale to see if it changes
784 double origScaleX
= m_scaleX
;
785 double origScaleY
= m_scaleY
;
786 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
787 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
788 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
789 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
790 // CMB: if scale has changed call SetPen to recalulate the line width
791 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
793 // this is a bit artificial, but we need to force wxDC to think
794 // the pen has changed
801 void wxDC::SetPalette( const wxPalette
& palette
)
805 void wxDC::SetBackgroundMode( int mode
)
807 m_backgroundMode
= mode
;
810 void wxDC::SetFont( const wxFont
&font
)
816 void wxDC::SetPen( const wxPen
&pen
)
821 if ( m_graphicContext
)
823 m_graphicContext
->SetPen( m_pen
) ;
827 void wxDC::SetBrush( const wxBrush
&brush
)
829 if (m_brush
== brush
)
832 if ( m_graphicContext
)
834 m_graphicContext
->SetBrush( m_brush
) ;
838 void wxDC::SetBackground( const wxBrush
&brush
)
840 if (m_backgroundBrush
== brush
)
842 m_backgroundBrush
= brush
;
843 if (!m_backgroundBrush
.Ok())
847 void wxDC::SetLogicalFunction( int function
)
849 if (m_logicalFunction
== function
)
851 m_logicalFunction
= function
;
854 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
855 const wxColour
& col
, int style
);
857 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
858 const wxColour
& col
, int style
)
860 return wxDoFloodFill(this, x
, y
, col
, style
);
863 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
865 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
866 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
867 wxMacPortSaver
helper((CGrafPtr
)m_macPort
) ;
870 XLOG2DEVMAC(x
) + m_macLocalOriginInPort
.x
- m_macLocalOrigin
.x
,
871 YLOG2DEVMAC(y
) + m_macLocalOriginInPort
.y
- m_macLocalOrigin
.y
, &colour
);
872 // Convert from Mac colour to wx
873 col
->Set( colour
.red
>> 8,
879 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
881 wxCHECK_RET(Ok(), wxT("Invalid DC"));
883 if ( m_logicalFunction
!= wxCOPY
)
886 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
887 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
888 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
889 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
891 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
892 path
->MoveToPoint( xx1
, yy1
) ;
893 path
->AddLineToPoint( xx2
, yy2
) ;
894 path
->CloseSubpath() ;
895 m_graphicContext
->StrokePath( path
) ;
898 CalcBoundingBox(x1
, y1
);
899 CalcBoundingBox(x2
, y2
);
902 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
904 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
906 if ( m_logicalFunction
!= wxCOPY
)
912 wxCoord xx
= XLOG2DEVMAC(x
);
913 wxCoord yy
= YLOG2DEVMAC(y
);
915 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
916 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
917 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
918 path
->CloseSubpath() ;
919 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
920 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
921 path
->CloseSubpath() ;
922 m_graphicContext
->StrokePath( path
) ;
925 CalcBoundingBox(x
, y
);
926 CalcBoundingBox(x
+w
, y
+h
);
930 * To draw arcs properly the angles need to be converted from the WX style:
931 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
932 * a normal axis on paper).
935 * Angles start on the +ve y axis and go clockwise.
938 static double wxConvertWXangleToMACangle(double angle
)
940 double newAngle
= 90 - angle
;
946 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
947 wxCoord x2
, wxCoord y2
,
948 wxCoord xc
, wxCoord yc
)
950 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
952 if ( m_logicalFunction
!= wxCOPY
)
955 wxCoord xx1
= XLOG2DEVMAC(x1
);
956 wxCoord yy1
= YLOG2DEVMAC(y1
);
957 wxCoord xx2
= XLOG2DEVMAC(x2
);
958 wxCoord yy2
= YLOG2DEVMAC(y2
);
959 wxCoord xxc
= XLOG2DEVMAC(xc
);
960 wxCoord yyc
= YLOG2DEVMAC(yc
);
961 double dx
= xx1
- xxc
;
962 double dy
= yy1
- yyc
;
963 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
964 wxCoord rad
= (wxCoord
)radius
;
965 double radius1
, radius2
;
966 if (xx1
== xx2
&& yy1
== yy2
)
971 else if (radius
== 0.0)
973 radius1
= radius2
= 0.0;
977 radius1
= (xx1
- xxc
== 0) ?
978 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
979 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
980 radius2
= (xx2
- xxc
== 0) ?
981 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
982 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
984 wxCoord alpha2
= wxCoord(radius2
- radius1
);
985 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
986 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
989 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
990 CGContextRef ctx
= mctx
->GetNativeContext() ;
991 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
992 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
995 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
996 double sa
, double ea
)
998 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1000 if ( m_logicalFunction
!= wxCOPY
)
1003 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1004 // we have to make sure that the filling is always counter-clockwise
1007 wxCoord xx
= XLOG2DEVMAC(x
);
1008 wxCoord yy
= YLOG2DEVMAC(y
);
1009 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1010 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1011 // handle -ve width and/or height
1012 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1013 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1014 sa
= wxConvertWXangleToMACangle(sa
);
1015 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1016 CGContextRef ctx
= mctx
->GetNativeContext() ;
1017 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1018 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1021 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1023 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1024 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1027 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1028 wxCoord xoffset
, wxCoord yoffset
)
1030 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1032 if ( m_logicalFunction
!= wxCOPY
)
1035 wxCoord x1
, x2
, y1
, y2
;
1036 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1037 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1038 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1039 path
->MoveToPoint( x1
, y1
) ;
1040 for (int i
= 1; i
< n
; i
++)
1042 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1043 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1045 path
->AddLineToPoint( x2
, y2
) ;
1047 m_graphicContext
->StrokePath( path
) ;
1051 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1052 wxCoord xoffset
, wxCoord yoffset
,
1055 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1056 wxCoord x1
, x2
, y1
, y2
;
1057 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1060 if ( m_logicalFunction
!= wxCOPY
)
1063 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1064 y2
= 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 if ( x1
!= x2
|| y1
!= y2
)
1077 path
->AddLineToPoint( x1
,y1
) ;
1079 path
->CloseSubpath() ;
1080 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1084 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1086 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1088 if ( m_logicalFunction
!= wxCOPY
)
1091 wxCoord xx
= XLOG2DEVMAC(x
);
1092 wxCoord yy
= YLOG2DEVMAC(y
);
1093 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1094 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1095 // CMB: draw nothing if transformed w or h is 0
1096 if (ww
== 0 || hh
== 0)
1098 // CMB: handle -ve width and/or height
1109 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1110 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1111 m_graphicContext
->DrawPath( path
) ;
1115 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1116 wxCoord width
, wxCoord height
,
1119 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1121 if ( m_logicalFunction
!= wxCOPY
)
1126 radius
= - radius
* ((width
< height
) ? width
: height
);
1127 wxCoord xx
= XLOG2DEVMAC(x
);
1128 wxCoord yy
= YLOG2DEVMAC(y
);
1129 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1130 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1131 // CMB: draw nothing if transformed w or h is 0
1132 if (ww
== 0 || hh
== 0)
1134 // CMB: handle -ve width and/or height
1145 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1146 CGContextRef ctx
= mctx
->GetNativeContext() ;
1147 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1148 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1151 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1153 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1155 if ( m_logicalFunction
!= wxCOPY
)
1158 wxCoord xx
= XLOG2DEVMAC(x
);
1159 wxCoord yy
= YLOG2DEVMAC(y
);
1160 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1161 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1162 // CMB: draw nothing if transformed w or h is 0
1163 if (ww
== 0 || hh
== 0)
1165 // CMB: handle -ve width and/or height
1177 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1178 CGContextRef ctx
= mctx
->GetNativeContext() ;
1179 if ( width
== height
)
1181 CGContextBeginPath(ctx
);
1182 CGContextAddArc(ctx
,
1189 CGContextClosePath(ctx
);
1191 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1195 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1196 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1200 bool wxDC::CanDrawBitmap(void) const
1205 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1206 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1207 wxCoord xsrcMask
, wxCoord ysrcMask
)
1209 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1210 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1211 if ( logical_func
== wxNO_OP
)
1213 if (xsrcMask
== -1 && ysrcMask
== -1)
1215 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1218 wxCoord yysrc
= source
->YLOG2DEVMAC(ysrc
) ;
1219 wxCoord xxsrc
= source
->XLOG2DEVMAC(xsrc
) ;
1220 wxCoord wwsrc
= source
->XLOG2DEVREL(width
) ;
1221 wxCoord hhsrc
= source
->YLOG2DEVREL(height
) ;
1223 wxCoord yydest
= YLOG2DEVMAC(ydest
) ;
1224 wxCoord xxdest
= XLOG2DEVMAC(xdest
) ;
1225 wxCoord wwdest
= XLOG2DEVREL(width
) ;
1226 wxCoord hhdest
= YLOG2DEVREL(height
) ;
1228 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1229 if ( memdc
&& logical_func
== wxCOPY
)
1231 wxBitmap blit
= memdc
->GetSelectedObject() ;
1232 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1234 wxCoord bmpwidth
= blit
.GetWidth();
1235 wxCoord bmpheight
= blit
.GetHeight();
1237 if ( xxsrc
!= 0 || yysrc
!= 0 || bmpwidth
!= wwsrc
|| bmpheight
!= hhsrc
)
1239 wwsrc
= wxMin( wwsrc
, bmpwidth
- xxsrc
) ;
1240 hhsrc
= wxMin( hhsrc
, bmpheight
- yysrc
) ;
1241 if ( wwsrc
> 0 && hhsrc
> 0 )
1243 if ( xxsrc
>= 0 && yysrc
>= 0 )
1245 wxRect
subrect( xxsrc
, yysrc
, wwsrc
, hhsrc
) ;
1246 blit
= blit
.GetSubBitmap( subrect
) ;
1250 // in this case we'd probably have to adjust the different coordinates, but
1251 // we have to find out proper contract first
1252 blit
= wxNullBitmap
;
1257 blit
= wxNullBitmap
;
1262 CGContextRef cg
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
1263 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1264 HIRect r
= CGRectMake( xxdest
, yydest
, wwdest
, hhdest
) ;
1265 HIViewDrawCGImage( cg
, &r
, image
) ;
1266 CGImageRelease( image
) ;
1273 CGContextRef cg = (wxMacCGContext*)(source->GetGraphicContext())->GetNativeContext() ;
1274 void *data = CGBitmapContextGetData( cg ) ;
1276 return FALSE
; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1281 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1284 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1286 if ( str
.Length() == 0 )
1289 if ( m_logicalFunction
!= wxCOPY
)
1292 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1294 OSStatus status
= noErr
;
1295 ATSUTextLayout atsuLayout
;
1296 UniCharCount chars
= str
.Length() ;
1297 UniChar
* ubuf
= NULL
;
1298 #if SIZEOF_WCHAR_T == 4
1299 wxMBConvUTF16BE converter
;
1301 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1302 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1303 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1305 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1306 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1307 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1308 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1310 chars
= unicharlen
/ 2 ;
1313 ubuf
= (UniChar
*) str
.wc_str() ;
1315 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1316 chars
= wxWcslen( wchar
.data() ) ;
1317 ubuf
= (UniChar
*) wchar
.data() ;
1321 int drawX
= XLOG2DEVMAC(x
) ;
1322 int drawY
= YLOG2DEVMAC(y
) ;
1324 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1325 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1327 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1329 status
= ::ATSUSetTransientFontMatching( atsuLayout
, true ) ;
1330 wxASSERT_MSG( status
== noErr
, wxT("couldn't setup transient font matching") );
1332 int iAngle
= int( angle
);
1333 if ( abs(iAngle
) > 0 )
1335 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1336 ATSUAttributeTag atsuTags
[] =
1338 kATSULineRotationTag
,
1340 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1344 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1348 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1349 atsuTags
, atsuSizes
, atsuValues
) ;
1352 CGContextRef cgContext
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
1353 ATSUAttributeTag atsuTags
[] =
1357 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1359 sizeof( CGContextRef
) ,
1361 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1365 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1366 atsuTags
, atsuSizes
, atsuValues
) ;
1369 ATSUTextMeasurement textBefore
;
1370 ATSUTextMeasurement textAfter
;
1371 ATSUTextMeasurement ascent
;
1372 ATSUTextMeasurement descent
;
1374 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1375 &textBefore
, &textAfter
, &ascent
, &descent
);
1376 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1380 if ( m_backgroundMode
== wxSOLID
)
1382 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1386 path
->AddLineToPoint(
1387 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1388 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1389 path
->AddLineToPoint(
1390 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1391 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1392 path
->AddLineToPoint(
1393 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1394 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1396 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1400 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1401 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1403 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1404 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1405 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1407 CGContextSaveGState(((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext());
1408 CGContextTranslateCTM(((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext(), drawX
, drawY
);
1409 CGContextScaleCTM(((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext(), 1, -1);
1410 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1411 IntToFixed(0) , IntToFixed(0) );
1412 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1413 CGContextRestoreGState( ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ) ;
1415 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1416 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1418 ::ATSUDisposeTextLayout(atsuLayout
);
1419 #if SIZEOF_WCHAR_T == 4
1424 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1426 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1427 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1430 bool wxDC::CanGetTextExtent() const
1432 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1436 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1437 wxCoord
*descent
, wxCoord
*externalLeading
,
1438 wxFont
*theFont
) const
1440 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1441 wxFont formerFont
= m_font
;
1444 // work around the constness
1445 *((wxFont
*)(&m_font
)) = *theFont
;
1449 if ( str
.Length() == 0 )
1452 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1454 OSStatus status
= noErr
;
1455 ATSUTextLayout atsuLayout
;
1456 UniCharCount chars
= str
.Length() ;
1457 UniChar
* ubuf
= NULL
;
1458 #if SIZEOF_WCHAR_T == 4
1459 wxMBConvUTF16BE converter
;
1461 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1462 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1463 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1465 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1466 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1467 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1468 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1470 chars
= unicharlen
/ 2 ;
1473 ubuf
= (UniChar
*) str
.wc_str() ;
1475 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1476 chars
= wxWcslen( wchar
.data() ) ;
1477 ubuf
= (UniChar
*) wchar
.data() ;
1482 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1483 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1485 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1487 ATSUTextMeasurement textBefore
;
1488 ATSUTextMeasurement textAfter
;
1489 ATSUTextMeasurement textAscent
;
1490 ATSUTextMeasurement textDescent
;
1492 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1493 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1496 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1498 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1499 if ( externalLeading
)
1500 *externalLeading
= 0 ;
1502 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1504 ::ATSUDisposeTextLayout(atsuLayout
);
1505 #if SIZEOF_WCHAR_T == 4
1510 // work around the constness
1511 *((wxFont
*)(&m_font
)) = formerFont
;
1517 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1519 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1522 widths
.Add(0, text
.Length());
1524 if (text
.Length() == 0)
1527 ATSUTextLayout atsuLayout
;
1528 UniCharCount chars
= text
.Length() ;
1529 UniChar
* ubuf
= NULL
;
1530 #if SIZEOF_WCHAR_T == 4
1531 wxMBConvUTF16BE converter
;
1533 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1534 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1535 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1537 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1538 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1539 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1540 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1542 chars
= unicharlen
/ 2 ;
1545 ubuf
= (UniChar
*) text
.wc_str() ;
1547 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1548 chars
= wxWcslen( wchar
.data() ) ;
1549 ubuf
= (UniChar
*) wchar
.data() ;
1554 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1555 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1557 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1558 unsigned long actualNumberOfBounds
= 0;
1559 ATSTrapezoid glyphBounds
;
1561 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1563 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1564 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1569 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1570 //unsigned char uch = s[i];
1573 ::ATSUDisposeTextLayout(atsuLayout
);
1577 wxCoord
wxDC::GetCharWidth(void) const
1580 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1584 wxCoord
wxDC::GetCharHeight(void) const
1587 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1591 void wxDC::Clear(void)
1593 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1595 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1597 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1598 CGContextRef cg
= ((wxMacCGContext
*)(m_graphicContext
))->GetNativeContext() ;
1599 switch( m_backgroundBrush
.MacGetBrushKind() )
1601 case kwxMacBrushTheme
:
1603 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1604 if ( HIThemeSetFill
!= 0 )
1606 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1607 CGContextFillRect(cg
, rect
);
1614 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1615 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1616 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1617 CGContextFillRect( cg
, rect
);
1619 // reset to normal value
1620 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1621 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1624 case kwxMacBrushThemeBackground
:
1626 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1627 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1628 if ( UMAGetSystemVersion() >= 0x1030 )
1630 HIThemeBackgroundDrawInfo drawInfo
;
1631 drawInfo
.version
= 0 ;
1632 drawInfo
.state
= kThemeStateActive
;
1633 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1634 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1635 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1636 kHIThemeOrientationNormal
) ;
1637 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1638 kHIThemeOrientationNormal
) ;
1646 case kwxMacBrushColour
:
1648 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1649 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1650 CGContextFillRect(cg
, rect
);
1652 // reset to normal value
1653 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1654 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1661 void wxDC::MacInstallFont() const
1663 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1665 if( m_macATSUIStyle
)
1667 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1668 m_macATSUIStyle
= NULL
;
1673 OSStatus status
= noErr
;
1674 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1675 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1677 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1678 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1679 ATSUAttributeTag atsuTags
[] =
1684 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1687 sizeof( RGBColor
) ,
1689 // Boolean kTrue = true ;
1690 // Boolean kFalse = false ;
1692 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1693 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1698 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1699 atsuTags
, atsuSizes
, atsuValues
);
1701 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1705 // ---------------------------------------------------------------------------
1706 // coordinates transformations
1707 // ---------------------------------------------------------------------------
1709 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1711 return ((wxDC
*)this)->XDEV2LOG(x
);
1714 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1716 return ((wxDC
*)this)->YDEV2LOG(y
);
1719 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1721 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1724 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1726 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1729 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1731 return ((wxDC
*)this)->XLOG2DEV(x
);
1734 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1736 return ((wxDC
*)this)->YLOG2DEV(y
);
1739 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1741 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1744 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1746 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1749 #endif // wxMAC_USE_CORE_GRAPHICS