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 // snippets from Sketch Sample from Apple :
472 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
474 This function locates, opens, and returns the profile reference for the calibrated
475 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
476 with the profile reference this function returns.
478 CMProfileRef
wxMacOpenGenericProfile(void)
480 static CMProfileRef cachedRGBProfileRef
= NULL
;
482 // we only create the profile reference once
483 if (cachedRGBProfileRef
== NULL
)
485 CMProfileLocation loc
;
487 loc
.locType
= cmPathBasedProfile
;
488 strcpy(loc
.u
.pathLoc
.path
, kGenericRGBProfilePathStr
);
490 verify_noerr( CMOpenProfile(&cachedRGBProfileRef
, &loc
) );
493 if (cachedRGBProfileRef
)
495 // clone the profile reference so that the caller has their own reference, not our cached one
496 CMCloneProfileRef(cachedRGBProfileRef
);
499 return cachedRGBProfileRef
;
503 Return the generic RGB color space. This is a 'get' function and the caller should
504 not release the returned value unless the caller retains it first. Usually callers
505 of this routine will immediately use the returned colorspace with CoreGraphics
506 so they typically do not need to retain it themselves.
508 This function creates the generic RGB color space once and hangs onto it so it can
509 return it whenever this function is called.
512 CGColorSpaceRef
wxMacGetGenericRGBColorSpace()
514 static CGColorSpaceRef genericRGBColorSpace
= NULL
;
516 if (genericRGBColorSpace
== NULL
)
518 CMProfileRef genericRGBProfile
= wxMacOpenGenericProfile();
520 if (genericRGBProfile
)
522 genericRGBColorSpace
= CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile
);
523 wxASSERT_MSG( genericRGBColorSpace
!= NULL
, wxT("couldn't create the generic RGB color space") ) ;
525 // we opened the profile so it is up to us to close it
526 CMCloseProfile(genericRGBProfile
);
529 return genericRGBColorSpace
;
532 void AddEllipticArcToPath(CGContextRef c
, CGPoint center
, float a
, float b
, float fromDegree
, float toDegree
)
534 CGContextSaveGState(c
);
535 CGContextTranslateCTM(c
, center
.x
, center
.y
);
536 CGContextScaleCTM(c
, a
, b
);
537 CGContextMoveToPoint(c
, 1, 0);
538 CGContextAddArc(c
, 0, 0, 1, DegToRad(fromDegree
), DegToRad(toDegree
), 0);
539 CGContextClosePath(c
);
540 CGContextRestoreGState(c
);
543 void AddRoundedRectToPath(CGContextRef c
, CGRect rect
, float ovalWidth
,
547 if (ovalWidth
== 0 || ovalHeight
== 0)
549 CGContextAddRect(c
, rect
);
552 CGContextSaveGState(c
);
553 CGContextTranslateCTM(c
, CGRectGetMinX(rect
), CGRectGetMinY(rect
));
554 CGContextScaleCTM(c
, ovalWidth
, ovalHeight
);
555 fw
= CGRectGetWidth(rect
) / ovalWidth
;
556 fh
= CGRectGetHeight(rect
) / ovalHeight
;
557 CGContextMoveToPoint(c
, fw
, fh
/2);
558 CGContextAddArcToPoint(c
, fw
, fh
, fw
/2, fh
, 1);
559 CGContextAddArcToPoint(c
, 0, fh
, 0, fh
/2, 1);
560 CGContextAddArcToPoint(c
, 0, 0, fw
/2, 0, 1);
561 CGContextAddArcToPoint(c
, fw
, 0, fw
, fh
/2, 1);
562 CGContextClosePath(c
);
563 CGContextRestoreGState(c
);
570 m_mm_to_pix_x
= mm2pt
;
571 m_mm_to_pix_y
= mm2pt
;
572 m_internalDeviceOriginX
= 0;
573 m_internalDeviceOriginY
= 0;
574 m_externalDeviceOriginX
= 0;
575 m_externalDeviceOriginY
= 0;
576 m_logicalScaleX
= 1.0;
577 m_logicalScaleY
= 1.0;
582 m_needComputeScaleX
= FALSE
;
583 m_needComputeScaleY
= FALSE
;
587 m_macLocalOrigin
.x
= m_macLocalOrigin
.y
= 0 ;
589 m_pen
= *wxBLACK_PEN
;
590 m_font
= *wxNORMAL_FONT
;
591 m_brush
= *wxWHITE_BRUSH
;
593 m_macATSUIStyle
= NULL
;
595 m_graphicContext
= NULL
;
600 if( m_macATSUIStyle
)
602 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
603 m_macATSUIStyle
= NULL
;
606 delete m_graphicContext
;
609 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
611 wxCHECK_RET( Ok(), wxT("invalid window dc") );
612 wxCHECK_RET( bmp
.Ok(), wxT("invalid bitmap") );
613 wxCoord xx
= XLOG2DEVMAC(x
);
614 wxCoord yy
= YLOG2DEVMAC(y
);
615 wxCoord w
= bmp
.GetWidth();
616 wxCoord h
= bmp
.GetHeight();
617 wxCoord ww
= XLOG2DEVREL(w
);
618 wxCoord hh
= YLOG2DEVREL(h
);
620 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
621 CGImageRef image
= (CGImageRef
)( bmp
.CGImageCreate() ) ;
622 HIRect r
= CGRectMake( xx
, yy
, ww
, hh
) ;
623 HIViewDrawCGImage( cg
, &r
, image
) ;
624 CGImageRelease( image
) ;
627 void wxDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
629 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
630 wxCHECK_RET(icon
.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
632 wxCoord xx
= XLOG2DEVMAC(x
);
633 wxCoord yy
= YLOG2DEVMAC(y
);
634 wxCoord w
= icon
.GetWidth();
635 wxCoord h
= icon
.GetHeight();
636 wxCoord ww
= XLOG2DEVREL(w
);
637 wxCoord hh
= YLOG2DEVREL(h
);
639 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
640 CGRect r
= CGRectMake( 00 , 00 , ww
, hh
) ;
641 CGContextSaveGState(cg
);
642 CGContextTranslateCTM(cg
, xx
, yy
+ hh
);
643 CGContextScaleCTM(cg
, 1, -1);
644 PlotIconRefInContext( cg
, &r
, kAlignNone
, kTransformNone
,
645 NULL
, kPlotIconRefNormalFlags
, MAC_WXHICON( icon
.GetHICON() ) ) ;
646 CGContextRestoreGState( cg
) ;
649 void wxDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
651 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
652 wxCoord xx
, yy
, ww
, hh
;
655 ww
= XLOG2DEVREL(width
);
656 hh
= YLOG2DEVREL(height
);
658 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
659 CGRect clipRect
= CGRectMake( xx
,yy
, ww
, hh
) ;
660 CGContextClipToRect( cgContext
, clipRect
) ;
662 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
663 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
666 m_clipX1
= wxMax( m_clipX1
, xx
);
667 m_clipY1
= wxMax( m_clipY1
, yy
);
668 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
669 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
679 // TODO as soon as we don't reset the context for each operation anymore
680 // we have to update the context as well
683 void wxDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
685 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
688 DestroyClippingRegion();
692 region
.GetBox( x
, y
, w
, h
);
693 wxCoord xx
, yy
, ww
, hh
;
698 // if we have a scaling that we cannot map onto native regions
699 // we must use the box
700 if ( ww
!= w
|| hh
!= h
)
702 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
707 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
708 if ( xx != x || yy != y )
710 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
712 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
716 m_clipX1
= wxMax( m_clipX1
, xx
);
717 m_clipY1
= wxMax( m_clipY1
, yy
);
718 m_clipX2
= wxMin( m_clipX2
, (xx
+ ww
));
719 m_clipY2
= wxMin( m_clipY2
, (yy
+ hh
));
732 void wxDC::DestroyClippingRegion()
734 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
735 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
736 CGContextRestoreGState( cgContext
);
737 CGContextSaveGState( cgContext
);
739 SetBrush( m_brush
) ;
743 void wxDC::DoGetSizeMM( int* width
, int* height
) const
748 *width
= long( double(w
) / (m_scaleX
*m_mm_to_pix_x
) );
749 *height
= long( double(h
) / (m_scaleY
*m_mm_to_pix_y
) );
752 void wxDC::SetTextForeground( const wxColour
&col
)
754 wxCHECK_RET(Ok(), wxT("Invalid DC"));
755 if ( col
!= m_textForegroundColour
)
757 m_textForegroundColour
= col
;
762 void wxDC::SetTextBackground( const wxColour
&col
)
764 wxCHECK_RET(Ok(), wxT("Invalid DC"));
765 m_textBackgroundColour
= col
;
768 void wxDC::SetMapMode( int mode
)
773 SetLogicalScale( twips2mm
*m_mm_to_pix_x
, twips2mm
*m_mm_to_pix_y
);
776 SetLogicalScale( pt2mm
*m_mm_to_pix_x
, pt2mm
*m_mm_to_pix_y
);
779 SetLogicalScale( m_mm_to_pix_x
, m_mm_to_pix_y
);
782 SetLogicalScale( m_mm_to_pix_x
/10.0, m_mm_to_pix_y
/10.0 );
786 SetLogicalScale( 1.0, 1.0 );
789 if (mode
!= wxMM_TEXT
)
791 m_needComputeScaleX
= TRUE
;
792 m_needComputeScaleY
= TRUE
;
796 void wxDC::SetUserScale( double x
, double y
)
798 // allow negative ? -> no
801 ComputeScaleAndOrigin();
804 void wxDC::SetLogicalScale( double x
, double y
)
809 ComputeScaleAndOrigin();
812 void wxDC::SetLogicalOrigin( wxCoord x
, wxCoord y
)
814 m_logicalOriginX
= x
* m_signX
; // is this still correct ?
815 m_logicalOriginY
= y
* m_signY
;
816 ComputeScaleAndOrigin();
819 void wxDC::SetDeviceOrigin( wxCoord x
, wxCoord y
)
821 m_externalDeviceOriginX
= x
;
822 m_externalDeviceOriginY
= y
;
823 ComputeScaleAndOrigin();
826 void wxDC::SetAxisOrientation( bool xLeftRight
, bool yBottomUp
)
828 m_signX
= (xLeftRight
? 1 : -1);
829 m_signY
= (yBottomUp
? -1 : 1);
830 ComputeScaleAndOrigin();
833 wxSize
wxDC::GetPPI() const
835 return wxSize(72, 72);
838 int wxDC::GetDepth() const
843 void wxDC::ComputeScaleAndOrigin()
845 // CMB: copy scale to see if it changes
846 double origScaleX
= m_scaleX
;
847 double origScaleY
= m_scaleY
;
848 m_scaleX
= m_logicalScaleX
* m_userScaleX
;
849 m_scaleY
= m_logicalScaleY
* m_userScaleY
;
850 m_deviceOriginX
= m_internalDeviceOriginX
+ m_externalDeviceOriginX
;
851 m_deviceOriginY
= m_internalDeviceOriginY
+ m_externalDeviceOriginY
;
852 // CMB: if scale has changed call SetPen to recalulate the line width
853 if (m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
)
855 // this is a bit artificial, but we need to force wxDC to think
856 // the pen has changed
863 void wxDC::SetPalette( const wxPalette
& palette
)
867 void wxDC::SetBackgroundMode( int mode
)
869 m_backgroundMode
= mode
;
872 void wxDC::SetFont( const wxFont
&font
)
878 void wxDC::SetPen( const wxPen
&pen
)
883 if ( m_graphicContext
)
885 m_graphicContext
->SetPen( m_pen
) ;
889 void wxDC::SetBrush( const wxBrush
&brush
)
891 if (m_brush
== brush
)
894 if ( m_graphicContext
)
896 m_graphicContext
->SetBrush( m_brush
) ;
900 void wxDC::SetBackground( const wxBrush
&brush
)
902 if (m_backgroundBrush
== brush
)
904 m_backgroundBrush
= brush
;
905 if (!m_backgroundBrush
.Ok())
909 void wxDC::SetLogicalFunction( int function
)
911 if (m_logicalFunction
== function
)
913 m_logicalFunction
= function
;
916 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
917 const wxColour
& col
, int style
);
919 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
,
920 const wxColour
& col
, int style
)
922 return wxDoFloodFill(this, x
, y
, col
, style
);
925 bool wxDC::DoGetPixel( wxCoord x
, wxCoord y
, wxColour
*col
) const
927 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
928 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
929 wxMacPortSaver
helper((CGrafPtr
)m_macPort
) ;
932 XLOG2DEVMAC(x
) + m_macLocalOriginInPort
.x
- m_macLocalOrigin
.x
,
933 YLOG2DEVMAC(y
) + m_macLocalOriginInPort
.y
- m_macLocalOrigin
.y
, &colour
);
934 // Convert from Mac colour to wx
935 col
->Set( colour
.red
>> 8,
941 void wxDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
943 wxCHECK_RET(Ok(), wxT("Invalid DC"));
945 if ( m_logicalFunction
!= wxCOPY
)
948 wxCoord xx1
= XLOG2DEVMAC(x1
) ;
949 wxCoord yy1
= YLOG2DEVMAC(y1
) ;
950 wxCoord xx2
= XLOG2DEVMAC(x2
) ;
951 wxCoord yy2
= YLOG2DEVMAC(y2
) ;
953 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
954 path
->MoveToPoint( xx1
, yy1
) ;
955 path
->AddLineToPoint( xx2
, yy2
) ;
956 path
->CloseSubpath() ;
957 m_graphicContext
->StrokePath( path
) ;
960 CalcBoundingBox(x1
, y1
);
961 CalcBoundingBox(x2
, y2
);
964 void wxDC::DoCrossHair( wxCoord x
, wxCoord y
)
966 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
968 if ( m_logicalFunction
!= wxCOPY
)
974 wxCoord xx
= XLOG2DEVMAC(x
);
975 wxCoord yy
= YLOG2DEVMAC(y
);
977 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
978 path
->MoveToPoint( XLOG2DEVMAC(0), yy
) ;
979 path
->AddLineToPoint( XLOG2DEVMAC(w
), yy
) ;
980 path
->CloseSubpath() ;
981 path
->MoveToPoint( xx
, YLOG2DEVMAC(0) ) ;
982 path
->AddLineToPoint( xx
, YLOG2DEVMAC(h
) ) ;
983 path
->CloseSubpath() ;
984 m_graphicContext
->StrokePath( path
) ;
987 CalcBoundingBox(x
, y
);
988 CalcBoundingBox(x
+w
, y
+h
);
992 * To draw arcs properly the angles need to be converted from the WX style:
993 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
994 * a normal axis on paper).
997 * Angles start on the +ve y axis and go clockwise.
1000 static double wxConvertWXangleToMACangle(double angle
)
1002 double newAngle
= 90 - angle
;
1008 void wxDC::DoDrawArc( wxCoord x1
, wxCoord y1
,
1009 wxCoord x2
, wxCoord y2
,
1010 wxCoord xc
, wxCoord yc
)
1012 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1014 if ( m_logicalFunction
!= wxCOPY
)
1017 wxCoord xx1
= XLOG2DEVMAC(x1
);
1018 wxCoord yy1
= YLOG2DEVMAC(y1
);
1019 wxCoord xx2
= XLOG2DEVMAC(x2
);
1020 wxCoord yy2
= YLOG2DEVMAC(y2
);
1021 wxCoord xxc
= XLOG2DEVMAC(xc
);
1022 wxCoord yyc
= YLOG2DEVMAC(yc
);
1023 double dx
= xx1
- xxc
;
1024 double dy
= yy1
- yyc
;
1025 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
1026 wxCoord rad
= (wxCoord
)radius
;
1027 double radius1
, radius2
;
1028 if (xx1
== xx2
&& yy1
== yy2
)
1033 else if (radius
== 0.0)
1035 radius1
= radius2
= 0.0;
1039 radius1
= (xx1
- xxc
== 0) ?
1040 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
1041 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
1042 radius2
= (xx2
- xxc
== 0) ?
1043 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
1044 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
1046 wxCoord alpha2
= wxCoord(radius2
- radius1
);
1047 wxCoord alpha1
= wxCoord(wxConvertWXangleToMACangle(radius1
));
1048 if( (xx1
> xx2
) || (yy1
> yy2
) ) {
1051 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1052 CGContextRef ctx
= mctx
->GetNativeContext() ;
1053 AddEllipticArcToPath( ctx
, CGPointMake( xxc
, yyc
) , rad
, rad
, alpha1
, alpha2
) ;
1054 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1057 void wxDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
1058 double sa
, double ea
)
1060 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1062 if ( m_logicalFunction
!= wxCOPY
)
1065 double angle
= sa
- ea
; // Order important Mac in opposite direction to wx
1066 // we have to make sure that the filling is always counter-clockwise
1069 wxCoord xx
= XLOG2DEVMAC(x
);
1070 wxCoord yy
= YLOG2DEVMAC(y
);
1071 wxCoord ww
= m_signX
* XLOG2DEVREL(w
);
1072 wxCoord hh
= m_signY
* YLOG2DEVREL(h
);
1073 // handle -ve width and/or height
1074 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
1075 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
1076 sa
= wxConvertWXangleToMACangle(sa
);
1077 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1078 CGContextRef ctx
= mctx
->GetNativeContext() ;
1079 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , sa
, angle
) ;
1080 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1083 void wxDC::DoDrawPoint( wxCoord x
, wxCoord y
)
1085 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1086 DoDrawLine( x
, y
, x
+ 1 , y
+ 1 ) ;
1089 void wxDC::DoDrawLines(int n
, wxPoint points
[],
1090 wxCoord xoffset
, wxCoord yoffset
)
1092 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1094 if ( m_logicalFunction
!= wxCOPY
)
1097 wxCoord x1
, x2
, y1
, y2
;
1098 x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1099 y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1100 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1101 path
->MoveToPoint( x1
, y1
) ;
1102 for (int i
= 1; i
< n
; i
++)
1104 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1105 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1107 path
->AddLineToPoint( x2
, y2
) ;
1109 m_graphicContext
->StrokePath( path
) ;
1113 void wxDC::DoDrawPolygon(int n
, wxPoint points
[],
1114 wxCoord xoffset
, wxCoord yoffset
,
1117 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1118 wxCoord x1
, x2
, y1
, y2
;
1119 if ( n
== 0 || (m_brush
.GetStyle() == wxTRANSPARENT
&& m_pen
.GetStyle() == wxTRANSPARENT
) )
1122 if ( m_logicalFunction
!= wxCOPY
)
1125 x2
= x1
= XLOG2DEVMAC(points
[0].x
+ xoffset
);
1126 y2
= y1
= YLOG2DEVMAC(points
[0].y
+ yoffset
);
1128 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1129 path
->MoveToPoint( x1
, y1
) ;
1130 for (int i
= 1; i
< n
; i
++)
1132 x2
= XLOG2DEVMAC(points
[i
].x
+ xoffset
);
1133 y2
= YLOG2DEVMAC(points
[i
].y
+ yoffset
);
1135 path
->AddLineToPoint( x2
, y2
) ;
1137 if ( x1
!= x2
|| y1
!= y2
)
1139 path
->AddLineToPoint( x1
,y1
) ;
1141 path
->CloseSubpath() ;
1142 m_graphicContext
->DrawPath( path
, fillStyle
) ;
1146 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1148 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1150 if ( m_logicalFunction
!= wxCOPY
)
1153 wxCoord xx
= XLOG2DEVMAC(x
);
1154 wxCoord yy
= YLOG2DEVMAC(y
);
1155 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1156 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1157 // CMB: draw nothing if transformed w or h is 0
1158 if (ww
== 0 || hh
== 0)
1160 // CMB: handle -ve width and/or height
1171 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1172 path
->AddRectangle(xx
,yy
, ww
, hh
) ;
1173 m_graphicContext
->DrawPath( path
) ;
1177 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
,
1178 wxCoord width
, wxCoord height
,
1181 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1183 if ( m_logicalFunction
!= wxCOPY
)
1188 radius
= - radius
* ((width
< height
) ? width
: height
);
1189 wxCoord xx
= XLOG2DEVMAC(x
);
1190 wxCoord yy
= YLOG2DEVMAC(y
);
1191 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1192 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1193 // CMB: draw nothing if transformed w or h is 0
1194 if (ww
== 0 || hh
== 0)
1196 // CMB: handle -ve width and/or height
1207 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1208 CGContextRef ctx
= mctx
->GetNativeContext() ;
1209 AddRoundedRectToPath( ctx
, CGRectMake( xx
, yy
, ww
, hh
) , 16 ,16 ) ;
1210 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1213 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1215 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1217 if ( m_logicalFunction
!= wxCOPY
)
1220 wxCoord xx
= XLOG2DEVMAC(x
);
1221 wxCoord yy
= YLOG2DEVMAC(y
);
1222 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
1223 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
1224 // CMB: draw nothing if transformed w or h is 0
1225 if (ww
== 0 || hh
== 0)
1227 // CMB: handle -ve width and/or height
1239 wxMacCGContext
* mctx
= ((wxMacCGContext
*) m_graphicContext
) ;
1240 CGContextRef ctx
= mctx
->GetNativeContext() ;
1241 if ( width
== height
)
1243 CGContextBeginPath(ctx
);
1244 CGContextAddArc(ctx
,
1251 CGContextClosePath(ctx
);
1253 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1257 AddEllipticArcToPath( ctx
, CGPointMake( xx
+ ww
/ 2 , yy
+ hh
/ 2 ) , ww
/ 2 , hh
/ 2 , 0 , 360) ;
1258 CGContextDrawPath( ctx
, mctx
->GetDrawingMode() ) ;
1262 bool wxDC::CanDrawBitmap(void) const
1267 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1268 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int logical_func
, bool useMask
,
1269 wxCoord xsrcMask
, wxCoord ysrcMask
)
1271 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1272 wxCHECK_MSG(source
->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1273 if ( logical_func
== wxNO_OP
)
1275 if (xsrcMask
== -1 && ysrcMask
== -1)
1277 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1280 wxCoord yysrc
= source
->YLOG2DEVMAC(ysrc
) ;
1281 wxCoord xxsrc
= source
->XLOG2DEVMAC(xsrc
) ;
1282 wxCoord wwsrc
= source
->XLOG2DEVREL(width
) ;
1283 wxCoord hhsrc
= source
->YLOG2DEVREL(height
) ;
1285 wxCoord yydest
= YLOG2DEVMAC(ydest
) ;
1286 wxCoord xxdest
= XLOG2DEVMAC(xdest
) ;
1287 wxCoord wwdest
= XLOG2DEVREL(width
) ;
1288 wxCoord hhdest
= YLOG2DEVREL(height
) ;
1290 wxMemoryDC
* memdc
= dynamic_cast<wxMemoryDC
*>(source
) ;
1291 if ( memdc
&& logical_func
== wxCOPY
)
1293 wxBitmap blit
= memdc
->GetSelectedObject() ;
1294 wxASSERT_MSG( blit
.Ok() , wxT("Invalid bitmap for blitting") ) ;
1296 wxCoord bmpwidth
= blit
.GetWidth();
1297 wxCoord bmpheight
= blit
.GetHeight();
1299 if ( xxsrc
!= 0 || yysrc
!= 0 || bmpwidth
!= wwsrc
|| bmpheight
!= hhsrc
)
1301 wwsrc
= wxMin( wwsrc
, bmpwidth
- xxsrc
) ;
1302 hhsrc
= wxMin( hhsrc
, bmpheight
- yysrc
) ;
1303 if ( wwsrc
> 0 && hhsrc
> 0 )
1305 if ( xxsrc
>= 0 && yysrc
>= 0 )
1307 wxRect
subrect( xxsrc
, yysrc
, wwsrc
, hhsrc
) ;
1308 blit
= blit
.GetSubBitmap( subrect
) ;
1312 // in this case we'd probably have to adjust the different coordinates, but
1313 // we have to find out proper contract first
1314 blit
= wxNullBitmap
;
1319 blit
= wxNullBitmap
;
1324 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1325 CGImageRef image
= (CGImageRef
)( blit
.CGImageCreate() ) ;
1326 HIRect r
= CGRectMake( xxdest
, yydest
, wwdest
, hhdest
) ;
1327 HIViewDrawCGImage( cg
, &r
, image
) ;
1328 CGImageRelease( image
) ;
1335 CGContextRef cg = dynamic_cast<wxMacCGContext*>(source->GetGraphicContext())->GetNativeContext() ;
1336 void *data = CGBitmapContextGetData( cg ) ;
1338 return FALSE
; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1343 void wxDC::DoDrawRotatedText(const wxString
& str
, wxCoord x
, wxCoord y
,
1346 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1348 if ( str
.Length() == 0 )
1351 if ( m_logicalFunction
!= wxCOPY
)
1354 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1356 OSStatus status
= noErr
;
1357 ATSUTextLayout atsuLayout
;
1358 UniCharCount chars
= str
.Length() ;
1359 UniChar
* ubuf
= NULL
;
1360 #if SIZEOF_WCHAR_T == 4
1361 wxMBConvUTF16BE converter
;
1363 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1364 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1365 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1367 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1368 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1369 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1370 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1372 chars
= unicharlen
/ 2 ;
1375 ubuf
= (UniChar
*) str
.wc_str() ;
1377 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1378 chars
= wxWcslen( wchar
.data() ) ;
1379 ubuf
= (UniChar
*) wchar
.data() ;
1383 int drawX
= XLOG2DEVMAC(x
) ;
1384 int drawY
= YLOG2DEVMAC(y
) ;
1386 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1387 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1389 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the rotated text") );
1390 int iAngle
= int( angle
);
1394 if ( abs(iAngle
) > 0 )
1396 Fixed atsuAngle
= IntToFixed( iAngle
) ;
1397 ATSUAttributeTag atsuTags
[] =
1399 kATSULineRotationTag
,
1401 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1405 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1409 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1410 atsuTags
, atsuSizes
, atsuValues
) ;
1413 CGContextRef cgContext
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1414 ATSUAttributeTag atsuTags
[] =
1418 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1420 sizeof( CGContextRef
) ,
1422 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1426 status
= ::ATSUSetLayoutControls(atsuLayout
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
),
1427 atsuTags
, atsuSizes
, atsuValues
) ;
1430 ATSUTextMeasurement textBefore
;
1431 ATSUTextMeasurement textAfter
;
1432 ATSUTextMeasurement ascent
;
1433 ATSUTextMeasurement descent
;
1435 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1436 &textBefore
, &textAfter
, &ascent
, &descent
);
1437 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1441 if ( m_backgroundMode
== wxSOLID
)
1443 wxGraphicPath
* path
= m_graphicContext
->CreatePath() ;
1447 path
->AddLineToPoint(
1448 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ,
1449 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
)) ) ;
1450 path
->AddLineToPoint(
1451 (int) (drawX
+ sin(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) + cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1452 (int) (drawY
+ cos(angle
/RAD2DEG
) * FixedToInt(ascent
+ descent
) - sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1453 path
->AddLineToPoint(
1454 (int) (drawX
+ cos(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ,
1455 (int) (drawY
- sin(angle
/RAD2DEG
) * FixedToInt(textAfter
)) ) ;
1457 m_graphicContext
->FillPath( path
, m_textBackgroundColour
) ;
1461 drawX
+= (int)(sin(angle
/RAD2DEG
) * FixedToInt(ascent
));
1462 drawY
+= (int)(cos(angle
/RAD2DEG
) * FixedToInt(ascent
));
1464 status
= ::ATSUMeasureTextImage( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1465 IntToFixed(drawX
) , IntToFixed(drawY
) , &rect
);
1466 wxASSERT_MSG( status
== noErr
, wxT("couldn't measure the rotated text") );
1468 CGContextSaveGState(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext());
1469 CGContextTranslateCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), drawX
, drawY
);
1470 CGContextScaleCTM(dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext(), 1, -1);
1471 status
= ::ATSUDrawText( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1472 IntToFixed(0) , IntToFixed(0) );
1473 wxASSERT_MSG( status
== noErr
, wxT("couldn't draw the rotated text") );
1474 CGContextRestoreGState( dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ) ;
1476 CalcBoundingBox(XDEV2LOG(rect
.left
), YDEV2LOG(rect
.top
) );
1477 CalcBoundingBox(XDEV2LOG(rect
.right
), YDEV2LOG(rect
.bottom
) );
1479 ::ATSUDisposeTextLayout(atsuLayout
);
1480 #if SIZEOF_WCHAR_T == 4
1485 void wxDC::DoDrawText(const wxString
& strtext
, wxCoord x
, wxCoord y
)
1487 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1488 DoDrawRotatedText( strtext
, x
, y
, 0.0 ) ;
1491 bool wxDC::CanGetTextExtent() const
1493 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1497 void wxDC::DoGetTextExtent( const wxString
&str
, wxCoord
*width
, wxCoord
*height
,
1498 wxCoord
*descent
, wxCoord
*externalLeading
,
1499 wxFont
*theFont
) const
1501 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1502 wxFont formerFont
= m_font
;
1505 // work around the constness
1506 *((wxFont
*)(&m_font
)) = *theFont
;
1510 if ( str
.Length() == 0 )
1513 wxCHECK_RET( m_macATSUIStyle
!= NULL
, wxT("No valid font set") ) ;
1515 OSStatus status
= noErr
;
1516 ATSUTextLayout atsuLayout
;
1517 UniCharCount chars
= str
.Length() ;
1518 UniChar
* ubuf
= NULL
;
1519 #if SIZEOF_WCHAR_T == 4
1520 wxMBConvUTF16BE converter
;
1522 size_t unicharlen
= converter
.WC2MB( NULL
, str
.wc_str() , 0 ) ;
1523 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1524 converter
.WC2MB( (char*) ubuf
, str
.wc_str(), unicharlen
+ 2 ) ;
1526 const wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1527 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1528 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1529 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1531 chars
= unicharlen
/ 2 ;
1534 ubuf
= (UniChar
*) str
.wc_str() ;
1536 wxWCharBuffer wchar
= str
.wc_str( wxConvLocal
) ;
1537 chars
= wxWcslen( wchar
.data() ) ;
1538 ubuf
= (UniChar
*) wchar
.data() ;
1543 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1544 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1546 wxASSERT_MSG( status
== noErr
, wxT("couldn't create the layout of the text") );
1548 ATSUTextMeasurement textBefore
;
1549 ATSUTextMeasurement textAfter
;
1550 ATSUTextMeasurement textAscent
;
1551 ATSUTextMeasurement textDescent
;
1553 status
= ::ATSUGetUnjustifiedBounds( atsuLayout
, kATSUFromTextBeginning
, kATSUToTextEnd
,
1554 &textBefore
, &textAfter
, &textAscent
, &textDescent
);
1557 *height
= YDEV2LOGREL( FixedToInt(textAscent
+ textDescent
) ) ;
1559 *descent
=YDEV2LOGREL( FixedToInt(textDescent
) );
1560 if ( externalLeading
)
1561 *externalLeading
= 0 ;
1563 *width
= XDEV2LOGREL( FixedToInt(textAfter
- textBefore
) ) ;
1565 ::ATSUDisposeTextLayout(atsuLayout
);
1566 #if SIZEOF_WCHAR_T == 4
1571 // work around the constness
1572 *((wxFont
*)(&m_font
)) = formerFont
;
1578 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1580 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1583 widths
.Add(0, text
.Length());
1585 if (text
.Length() == 0)
1588 ATSUTextLayout atsuLayout
;
1589 UniCharCount chars
= text
.Length() ;
1590 UniChar
* ubuf
= NULL
;
1591 #if SIZEOF_WCHAR_T == 4
1592 wxMBConvUTF16BE converter
;
1594 size_t unicharlen
= converter
.WC2MB( NULL
, text
.wc_str() , 0 ) ;
1595 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1596 converter
.WC2MB( (char*) ubuf
, text
.wc_str(), unicharlen
+ 2 ) ;
1598 const wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1599 size_t unicharlen
= converter
.WC2MB( NULL
, wchar
.data() , 0 ) ;
1600 ubuf
= (UniChar
*) malloc( unicharlen
+ 2 ) ;
1601 converter
.WC2MB( (char*) ubuf
, wchar
.data() , unicharlen
+ 2 ) ;
1603 chars
= unicharlen
/ 2 ;
1606 ubuf
= (UniChar
*) text
.wc_str() ;
1608 wxWCharBuffer wchar
= text
.wc_str( wxConvLocal
) ;
1609 chars
= wxWcslen( wchar
.data() ) ;
1610 ubuf
= (UniChar
*) wchar
.data() ;
1615 status
= ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr
) ubuf
, 0 , chars
, chars
, 1 ,
1616 &chars
, (ATSUStyle
*) &m_macATSUIStyle
, &atsuLayout
) ;
1618 for ( int pos
= 0; pos
< chars
; pos
++ ) {
1619 unsigned long actualNumberOfBounds
= 0;
1620 ATSTrapezoid glyphBounds
;
1622 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1624 result
= ATSUGetGlyphBounds( atsuLayout
, 0, 0, kATSUFromTextBeginning
, pos
+ 1, kATSUseDeviceOrigins
, 1, &glyphBounds
, &actualNumberOfBounds
);
1625 if (result
!= noErr
|| actualNumberOfBounds
!= 1 )
1630 widths
[pos
] = XDEV2LOGREL(FixedToInt( glyphBounds
.upperRight
.x
- glyphBounds
.upperLeft
.x
));
1631 //unsigned char uch = s[i];
1634 ::ATSUDisposeTextLayout(atsuLayout
);
1638 wxCoord
wxDC::GetCharWidth(void) const
1641 DoGetTextExtent(wxT("g") , &width
, NULL
, NULL
, NULL
, NULL
) ;
1645 wxCoord
wxDC::GetCharHeight(void) const
1648 DoGetTextExtent(wxT("g") , NULL
, &height
, NULL
, NULL
, NULL
) ;
1652 void wxDC::Clear(void)
1654 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1656 if ( m_backgroundBrush
.Ok() && m_backgroundBrush
.GetStyle() != wxTRANSPARENT
)
1658 HIRect rect
= CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1659 CGContextRef cg
= dynamic_cast<wxMacCGContext
*>(m_graphicContext
)->GetNativeContext() ;
1660 switch( m_backgroundBrush
.MacGetBrushKind() )
1662 case kwxMacBrushTheme
:
1664 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1665 if ( HIThemeSetFill
!= 0 )
1667 HIThemeSetFill( m_backgroundBrush
.MacGetTheme() , cg
) ;
1668 CGContextFillRect(cg
, rect
);
1675 GetThemeBrushAsColor( m_backgroundBrush
.MacGetTheme() , 32, true, &color
);
1676 CGContextSetRGBFillColor( cg
, (float) color
.red
/ 65536,
1677 (float) color
.green
/ 65536, (float) color
.blue
/ 65536, 1 );
1678 CGContextFillRect( cg
, rect
);
1680 // reset to normal value
1681 RGBColor col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1682 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1685 case kwxMacBrushThemeBackground
:
1687 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1688 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1689 if ( HIThemeDrawBackground
!= 0 )
1691 HIThemeBackgroundDrawInfo drawInfo
;
1692 drawInfo
.version
= 0 ;
1693 drawInfo
.state
= kThemeStateActive
;
1694 drawInfo
.kind
= m_backgroundBrush
.MacGetThemeBackground(NULL
) ;
1695 if ( drawInfo
.kind
== kThemeBackgroundMetal
)
1696 HIThemeDrawBackground( &rect
, &drawInfo
, cg
,
1697 kHIThemeOrientationNormal
) ;
1698 HIThemeApplyBackground( &rect
, &drawInfo
, cg
,
1699 kHIThemeOrientationNormal
) ;
1707 case kwxMacBrushColour
:
1709 RGBColor col
= MAC_WXCOLORREF( m_backgroundBrush
.GetColour().GetPixel()) ;
1710 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1711 CGContextFillRect(cg
, rect
);
1713 // reset to normal value
1714 col
= MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1715 CGContextSetRGBFillColor( cg
, col
.red
/ 65536.0 , col
.green
/ 65536.0 , col
.blue
/ 65536.0 , 1.0 ) ;
1722 void wxDC::MacInstallFont() const
1724 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1726 if( m_macATSUIStyle
)
1728 ::ATSUDisposeStyle((ATSUStyle
)m_macATSUIStyle
);
1729 m_macATSUIStyle
= NULL
;
1734 OSStatus status
= noErr
;
1735 status
= ATSUCreateAndCopyStyle( (ATSUStyle
) m_font
.MacGetATSUStyle() , (ATSUStyle
*) &m_macATSUIStyle
) ;
1736 wxASSERT_MSG( status
== noErr
, wxT("couldn't set create ATSU style") ) ;
1738 Fixed atsuSize
= IntToFixed( int(m_scaleY
* m_font
.MacGetFontSize()) ) ;
1739 RGBColor atsuColor
= MAC_WXCOLORREF( m_textForegroundColour
.GetPixel() ) ;
1740 ATSUAttributeTag atsuTags
[] =
1745 ByteCount atsuSizes
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1748 sizeof( RGBColor
) ,
1750 // Boolean kTrue = true ;
1751 // Boolean kFalse = false ;
1753 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1754 ATSUAttributeValuePtr atsuValues
[sizeof(atsuTags
)/sizeof(ATSUAttributeTag
)] =
1759 status
= ::ATSUSetAttributes((ATSUStyle
)m_macATSUIStyle
, sizeof(atsuTags
)/sizeof(ATSUAttributeTag
) ,
1760 atsuTags
, atsuSizes
, atsuValues
);
1762 wxASSERT_MSG( status
== noErr
, wxT("couldn't Modify ATSU style") ) ;
1766 // ---------------------------------------------------------------------------
1767 // coordinates transformations
1768 // ---------------------------------------------------------------------------
1770 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1772 return ((wxDC
*)this)->XDEV2LOG(x
);
1775 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1777 return ((wxDC
*)this)->YDEV2LOG(y
);
1780 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1782 return ((wxDC
*)this)->XDEV2LOGREL(x
);
1785 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1787 return ((wxDC
*)this)->YDEV2LOGREL(y
);
1790 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1792 return ((wxDC
*)this)->XLOG2DEV(x
);
1795 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1797 return ((wxDC
*)this)->YLOG2DEV(y
);
1800 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1802 return ((wxDC
*)this)->XLOG2DEVREL(x
);
1805 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1807 return ((wxDC
*)this)->YLOG2DEVREL(y
);
1810 #endif // wxMAC_USE_CORE_GRAPHICS