]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/dccg.cpp
making virtual lists faster by not sorting items
[wxWidgets.git] / src / mac / carbon / dccg.cpp
CommitLineData
613a24f7 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/mac/carbon/dccg.cpp
613a24f7
SC
3// Purpose: wxDC class
4// Author: Stefan Csomor
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
e4db172a 9// Licence: wxWindows licence
613a24f7
SC
10/////////////////////////////////////////////////////////////////////////////
11
20b69855
SC
12#include "wx/wxprec.h"
13
613a24f7 14#include "wx/dc.h"
20b69855
SC
15
16#if wxMAC_USE_CORE_GRAPHICS
17
e4db172a
WS
18#ifndef WX_PRECOMP
19 #include "wx/log.h"
670f9935 20 #include "wx/app.h"
f38924e8 21 #include "wx/dcmemory.h"
6d50343d 22 #include "wx/dcprint.h"
b3a44e05 23 #include "wx/region.h"
155ecd4c 24 #include "wx/image.h"
e4db172a
WS
25#endif
26
613a24f7 27#include "wx/mac/uma.h"
613a24f7 28
20b69855 29
138861bc
VZ
30#ifdef __MSL__
31 #if __MSL__ >= 0x6000
32 #include "math.h"
d281db8b 33 // in case our functions were defined outside std, we make it known all the same
0f4c3aa2 34 namespace std { }
138861bc
VZ
35 using namespace std ;
36 #endif
613a24f7
SC
37#endif
38
39#include "wx/mac/private.h"
613a24f7 40
613a24f7 41IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
613a24f7 42
01b5ab33
SC
43#ifndef wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
44#define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0
45#endif
46
bc78039c
SC
47#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
48typedef float CGFloat ;
49#endif
50
613a24f7
SC
51//-----------------------------------------------------------------------------
52// constants
53//-----------------------------------------------------------------------------
54
55#if !defined( __DARWIN__ ) || defined(__MWERKS__)
56#ifndef M_PI
57const double M_PI = 3.14159265358979 ;
58#endif
59#endif
b21d67a0 60
0f4c3aa2 61const double RAD2DEG = 180.0 / M_PI;
613a24f7
SC
62const short kEmulatedMode = -1 ;
63const short kUnsupportedMode = -2 ;
64
65extern TECObjectRef s_TECNativeCToUnicode ;
66
613a24f7 67
eb1a7cf9 68// TODO: update
b21d67a0
DS
69// The textctrl implementation still needs that (needs what?) for the non-HIView implementation
70//
613a24f7 71wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
0f4c3aa2 72 wxMacPortSaver( (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) )
613a24f7 73{
0f4c3aa2 74 m_newPort = (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) ;
613a24f7
SC
75 m_formerClip = NewRgn() ;
76 m_newClip = NewRgn() ;
77 GetClip( m_formerClip ) ;
97071cdb 78
613a24f7
SC
79 if ( win )
80 {
bcbbfab8 81 // guard against half constructed objects, this just leads to a empty clip
97071cdb 82 if ( win->GetPeer() )
bcbbfab8
SC
83 {
84 int x = 0 , y = 0;
eb1a7cf9 85 win->MacWindowToRootWindow( &x, &y ) ;
0f4c3aa2 86
bcbbfab8
SC
87 // get area including focus rect
88 CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
89 if ( !EmptyRgn( m_newClip ) )
90 OffsetRgn( m_newClip , x , y ) ;
91 }
613a24f7
SC
92
93 SetClip( m_newClip ) ;
94 }
95}
96
0f4c3aa2 97wxMacWindowClipper::~wxMacWindowClipper()
613a24f7
SC
98{
99 SetPort( m_newPort ) ;
100 SetClip( m_formerClip ) ;
101 DisposeRgn( m_newClip ) ;
102 DisposeRgn( m_formerClip ) ;
103}
104
105wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
106 wxMacWindowClipper( win )
107{
108 // the port is already set at this point
0f4c3aa2 109 m_newPort = (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) ;
613a24f7
SC
110 GetThemeDrawingState( &m_themeDrawingState ) ;
111}
112
0f4c3aa2 113wxMacWindowStateSaver::~wxMacWindowStateSaver()
613a24f7
SC
114{
115 SetPort( m_newPort ) ;
116 SetThemeDrawingState( m_themeDrawingState , true ) ;
117}
118
a8f234d2
SC
119// minimal implementation only used for appearance drawing < 10.3
120
121wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
122 m_ph( (GrafPtr) dc->m_macPort )
123{
124 wxASSERT( dc->Ok() ) ;
125 m_dc = dc ;
b21d67a0 126
a8f234d2
SC
127// dc->MacSetupPort(&m_ph) ;
128}
97071cdb 129
a8f234d2
SC
130wxMacPortSetter::~wxMacPortSetter()
131{
132// m_dc->MacCleanupPort(&m_ph) ;
133}
134
613a24f7
SC
135//-----------------------------------------------------------------------------
136// Local functions
137//-----------------------------------------------------------------------------
20b69855 138
613a24f7
SC
139static inline double dmin(double a, double b) { return a < b ? a : b; }
140static inline double dmax(double a, double b) { return a > b ? a : b; }
141static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
142
143//-----------------------------------------------------------------------------
20b69855
SC
144// device context implementation
145//
146// more and more of the dc functionality should be implemented by calling
147// the appropricate wxMacCGContext, but we will have to do that step by step
148// also coordinate conversions should be moved to native matrix ops
613a24f7 149//-----------------------------------------------------------------------------
613a24f7 150
04732a7f
SC
151// we always stock two context states, one at entry, to be able to preserve the
152// state we were called with, the other one after changing to HI Graphics orientation
153// (this one is used for getting back clippings etc)
154
ded83b1a
SC
155//-----------------------------------------------------------------------------
156// wxGraphicPath implementation
157//-----------------------------------------------------------------------------
158
20b69855 159wxMacCGPath::wxMacCGPath()
613a24f7 160{
20b69855 161 m_path = CGPathCreateMutable() ;
613a24f7
SC
162}
163
20b69855 164wxMacCGPath::~wxMacCGPath()
613a24f7 165{
20b69855
SC
166 CGPathRelease( m_path ) ;
167}
613a24f7 168
b21d67a0 169// opens (starts) a new subpath
20b69855
SC
170void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
171{
172 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
173}
613a24f7 174
0f4c3aa2 175void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
20b69855
SC
176{
177 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
178}
613a24f7 179
e828c96a
SC
180void wxMacCGPath::AddQuadCurveToPoint( wxCoord cx1, wxCoord cy1, wxCoord x1, wxCoord y1 )
181{
182 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x1 , y1 );
183}
184
20b69855 185void wxMacCGPath::AddRectangle( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
613a24f7 186{
20b69855
SC
187 CGRect cgRect = { { x , y } , { w , h } } ;
188 CGPathAddRect( m_path , NULL , cgRect ) ;
189}
613a24f7 190
20b69855
SC
191void wxMacCGPath::AddCircle( wxCoord x, wxCoord y , wxCoord r )
192{
193 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true ) ;
194}
613a24f7 195
20b69855
SC
196// closes the current subpath
197void wxMacCGPath::CloseSubpath()
198{
199 CGPathCloseSubpath( m_path ) ;
200}
613a24f7 201
0f4c3aa2 202CGPathRef wxMacCGPath::GetPath() const
613a24f7 203{
20b69855
SC
204 return m_path ;
205}
206
ded83b1a
SC
207void wxMacCGPath::AddArcToPoint( wxCoord x1, wxCoord y1 , wxCoord x2, wxCoord y2, wxCoord r )
208{
209 CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
210}
211
212void wxMacCGPath::AddArc( wxCoord x, wxCoord y, wxCoord r, double startAngle, double endAngle, bool clockwise )
213{
214 CGPathAddArc( m_path, NULL , x, y, r, startAngle, endAngle, clockwise);
215}
216
217//-----------------------------------------------------------------------------
218// wxGraphicContext implementation
219//-----------------------------------------------------------------------------
220
0f4c3aa2 221wxMacCGContext::wxMacCGContext( CGrafPtr port )
20b69855
SC
222{
223 m_qdPort = port ;
cb4b0966 224 m_cgContext = NULL ;
ded83b1a
SC
225 m_mode = kCGPathFill;
226 m_macATSUIStyle = NULL ;
20b69855
SC
227}
228
229wxMacCGContext::wxMacCGContext( CGContextRef cgcontext )
230{
231 m_qdPort = NULL ;
232 m_cgContext = cgcontext ;
ded83b1a
SC
233 m_mode = kCGPathFill;
234 m_macATSUIStyle = NULL ;
b014adcc
SC
235 CGContextSaveGState( m_cgContext ) ;
236 CGContextSaveGState( m_cgContext ) ;
20b69855
SC
237}
238
239wxMacCGContext::wxMacCGContext()
240{
241 m_qdPort = NULL ;
242 m_cgContext = NULL ;
ded83b1a
SC
243 m_mode = kCGPathFill;
244 m_macATSUIStyle = NULL ;
20b69855 245}
613a24f7 246
0f4c3aa2 247wxMacCGContext::~wxMacCGContext()
20b69855 248{
b014adcc
SC
249 if ( m_cgContext )
250 {
68654a82 251 CGContextSynchronize( m_cgContext ) ;
b014adcc
SC
252 CGContextRestoreGState( m_cgContext ) ;
253 CGContextRestoreGState( m_cgContext ) ;
254 }
97071cdb 255
20b69855 256 if ( m_qdPort )
68654a82 257 CGContextRelease( m_cgContext ) ;
20b69855
SC
258}
259
260
261void wxMacCGContext::Clip( const wxRegion &region )
262{
97071cdb 263// ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
20b69855
SC
264}
265
0f4c3aa2 266void wxMacCGContext::StrokePath( const wxGraphicPath *p )
20b69855
SC
267{
268 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
20b69855 269 CGContextAddPath( m_cgContext , path->GetPath() ) ;
20b69855
SC
270 CGContextStrokePath( m_cgContext ) ;
271}
272
0f4c3aa2 273void wxMacCGContext::DrawPath( const wxGraphicPath *p , int fillStyle )
20b69855
SC
274{
275 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
276 CGPathDrawingMode mode = m_mode ;
97071cdb 277
20b69855
SC
278 if ( fillStyle == wxODDEVEN_RULE )
279 {
280 if ( mode == kCGPathFill )
281 mode = kCGPathEOFill ;
282 else if ( mode == kCGPathFillStroke )
283 mode = kCGPathEOFillStroke ;
284 }
97071cdb 285
20b69855 286 CGContextAddPath( m_cgContext , path->GetPath() ) ;
20b69855 287 CGContextDrawPath( m_cgContext , mode ) ;
613a24f7
SC
288}
289
0f4c3aa2 290void wxMacCGContext::FillPath( const wxGraphicPath *p , const wxColor &fillColor , int fillStyle )
613a24f7 291{
20b69855
SC
292 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
293 CGContextSaveGState( m_cgContext ) ;
0f4c3aa2 294
20b69855
SC
295 RGBColor col = MAC_WXCOLORREF( fillColor.GetPixel() ) ;
296 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
297 CGPathDrawingMode mode = kCGPathFill ;
298
299 if ( fillStyle == wxODDEVEN_RULE )
300 mode = kCGPathEOFill ;
0f4c3aa2 301
20b69855
SC
302 CGContextBeginPath( m_cgContext ) ;
303 CGContextAddPath( m_cgContext , path->GetPath() ) ;
304 CGContextClosePath( m_cgContext ) ;
305 CGContextDrawPath( m_cgContext , mode ) ;
0f4c3aa2 306
20b69855
SC
307 CGContextRestoreGState( m_cgContext ) ;
308}
0f4c3aa2
DS
309
310wxGraphicPath* wxMacCGContext::CreatePath()
311{
cb4b0966
SC
312 // make sure that we now have a real cgref, before doing
313 // anything with paths
a63b4755
SC
314 CGContextRef cg = GetNativeContext() ;
315 cg = NULL ;
75f0a06e 316
0f4c3aa2 317 return new wxMacCGPath() ;
cb4b0966
SC
318}
319
320// in case we only got a QDPort only create a cgref now
321
0f4c3aa2
DS
322CGContextRef wxMacCGContext::GetNativeContext()
323{
97071cdb 324 if ( m_cgContext == NULL )
cb4b0966
SC
325 {
326 Rect bounds ;
327 GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
68654a82 328 OSStatus status = CreateCGContextForPort((CGrafPtr) m_qdPort , &m_cgContext) ;
b014adcc 329 CGContextSaveGState( m_cgContext ) ;
cb4b0966
SC
330
331 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
75f0a06e 332
cb4b0966
SC
333 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
334 CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
0f4c3aa2 335
b014adcc 336 CGContextSaveGState( m_cgContext ) ;
cb4b0966
SC
337 SetPen( m_pen ) ;
338 SetBrush( m_brush ) ;
339 }
97071cdb 340
0f4c3aa2 341 return m_cgContext ;
cb4b0966
SC
342}
343
0f4c3aa2
DS
344void wxMacCGContext::SetNativeContext( CGContextRef cg )
345{
0e71e845
SC
346 // we allow either setting or clearing but not replacing
347 wxASSERT( m_cgContext == NULL || cg == NULL ) ;
75f0a06e 348
0e71e845
SC
349 if ( cg )
350 CGContextSaveGState( cg ) ;
0f4c3aa2 351 m_cgContext = cg ;
cb4b0966 352}
20b69855 353
ded83b1a
SC
354void wxMacCGContext::Translate( wxCoord dx , wxCoord dy )
355{
356 CGContextTranslateCTM( m_cgContext, dx, dy );
357}
358
359void wxMacCGContext::Scale( wxCoord xScale , wxCoord yScale )
360{
361 CGContextScaleCTM( m_cgContext , xScale , yScale ) ;
362}
363
364void wxMacCGContext::DrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, wxCoord w, wxCoord h )
365{
366 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ) ;
367 HIRect r = CGRectMake( x , y , w , h ) ;
368 HIViewDrawCGImage( m_cgContext , &r , image ) ;
369 CGImageRelease( image ) ;
370}
371
372void wxMacCGContext::DrawIcon( const wxIcon &icon, wxCoord x, wxCoord y, wxCoord w, wxCoord h )
373{
374 CGRect r = CGRectMake( 00 , 00 , w , h ) ;
375 CGContextSaveGState( m_cgContext );
376 CGContextTranslateCTM( m_cgContext, x , y + h );
377 CGContextScaleCTM( m_cgContext, 1, -1 );
378 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
379 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
380 CGContextRestoreGState( m_cgContext ) ;
381}
382
383void wxMacCGContext::PushState()
384{
385 CGContextSaveGState( m_cgContext );
386}
387
388void wxMacCGContext::PopState()
389{
390 CGContextRestoreGState( m_cgContext );
391}
392
393void wxMacCGContext::SetTextColor( const wxColour &col )
394{
395 m_textForegroundColor = col ;
396}
397
72ba915e 398#pragma mark -
b21d67a0 399#pragma mark wxMacCGPattern, ImagePattern, HatchPattern classes
72ba915e 400
b21d67a0 401// CGPattern wrapper class: always allocate on heap, never call destructor
72ba915e 402
24cd6f82 403class wxMacCGPattern
72ba915e 404{
24cd6f82 405public :
97071cdb
DS
406 wxMacCGPattern() {}
407
24cd6f82 408 // is guaranteed to be called only with a non-Null CGContextRef
75f0a06e 409 virtual void Render( CGContextRef ctxRef ) = 0 ;
72ba915e 410
24cd6f82 411 operator CGPatternRef() const { return m_patternRef ; }
97071cdb 412
24cd6f82
SC
413protected :
414 virtual ~wxMacCGPattern()
415 {
b21d67a0 416 // as this is called only when the m_patternRef is been released;
97071cdb 417 // don't release it again
24cd6f82 418 }
97071cdb 419
24cd6f82
SC
420 static void _Render( void *info, CGContextRef ctxRef )
421 {
422 wxMacCGPattern* self = (wxMacCGPattern*) info ;
423 if ( self && ctxRef )
424 self->Render( ctxRef ) ;
425 }
97071cdb 426
24cd6f82
SC
427 static void _Dispose( void *info )
428 {
429 wxMacCGPattern* self = (wxMacCGPattern*) info ;
430 delete self ;
431 }
97071cdb 432
24cd6f82 433 CGPatternRef m_patternRef ;
72ba915e 434
24cd6f82
SC
435 static const CGPatternCallbacks ms_Callbacks ;
436} ;
72ba915e 437
24cd6f82 438const CGPatternCallbacks wxMacCGPattern::ms_Callbacks = { 0, &wxMacCGPattern::_Render, &wxMacCGPattern::_Dispose };
72ba915e 439
24cd6f82 440class ImagePattern : public wxMacCGPattern
72ba915e 441{
24cd6f82 442public :
75f0a06e 443 ImagePattern( const wxBitmap* bmp , CGAffineTransform transform )
24cd6f82
SC
444 {
445 wxASSERT( bmp && bmp->Ok() ) ;
75f0a06e 446
24cd6f82
SC
447 Init( (CGImageRef) bmp->CGImageCreate() , transform ) ;
448 }
0f4c3aa2 449
24cd6f82
SC
450 // ImagePattern takes ownership of CGImageRef passed in
451 ImagePattern( CGImageRef image , CGAffineTransform transform )
452 {
453 if ( image )
24cd6f82 454 CFRetain( image ) ;
97071cdb 455
24cd6f82
SC
456 Init( image , transform ) ;
457 }
0f4c3aa2 458
75f0a06e 459 virtual void Render( CGContextRef ctxRef )
24cd6f82
SC
460 {
461 if (m_image != NULL)
462 HIViewDrawCGImage( ctxRef, &m_imageBounds, m_image );
463 }
72ba915e 464
24cd6f82 465protected :
b21d67a0 466 void Init( CGImageRef image, CGAffineTransform transform )
24cd6f82
SC
467 {
468 m_image = image ;
469 if ( m_image )
470 {
bc78039c 471 m_imageBounds = CGRectMake( 0.0, 0.0, (CGFloat)CGImageGetWidth( m_image ), (CGFloat)CGImageGetHeight( m_image ) ) ;
0f4c3aa2
DS
472 m_patternRef = CGPatternCreate(
473 this , m_imageBounds, transform ,
474 m_imageBounds.size.width, m_imageBounds.size.height,
475 kCGPatternTilingNoDistortion, true , &wxMacCGPattern::ms_Callbacks ) ;
24cd6f82
SC
476 }
477 }
97071cdb 478
d3c7fc99 479 virtual ~ImagePattern()
24cd6f82
SC
480 {
481 if ( m_image )
482 CGImageRelease( m_image ) ;
483 }
97071cdb 484
0f4c3aa2
DS
485 CGImageRef m_image ;
486 CGRect m_imageBounds ;
24cd6f82 487} ;
72ba915e 488
24cd6f82 489class HatchPattern : public wxMacCGPattern
72ba915e 490{
24cd6f82 491public :
b21d67a0 492 HatchPattern( int hatchstyle, CGAffineTransform transform )
24cd6f82
SC
493 {
494 m_hatch = hatchstyle ;
495 m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 ) ;
0f4c3aa2
DS
496 m_patternRef = CGPatternCreate(
497 this , m_imageBounds, transform ,
498 m_imageBounds.size.width, m_imageBounds.size.height,
499 kCGPatternTilingNoDistortion, false , &wxMacCGPattern::ms_Callbacks ) ;
24cd6f82 500 }
0f4c3aa2 501
24cd6f82
SC
502 void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
503 {
504#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
505 if ( UMAGetSystemVersion() >= 0x1040 )
506 {
507 CGContextStrokeLineSegments( ctxRef , pts , count ) ;
508 }
509 else
510#endif
511 {
b21d67a0 512 CGContextBeginPath( ctxRef );
75f0a06e
DS
513 for (size_t i = 0; i < count; i += 2)
514 {
24cd6f82
SC
515 CGContextMoveToPoint(ctxRef, pts[i].x, pts[i].y);
516 CGContextAddLineToPoint(ctxRef, pts[i+1].x, pts[i+1].y);
517 }
518 CGContextStrokePath(ctxRef);
519 }
520 }
b21d67a0 521
75f0a06e 522 virtual void Render( CGContextRef ctxRef )
24cd6f82 523 {
97071cdb 524 switch ( m_hatch )
24cd6f82
SC
525 {
526 case wxBDIAGONAL_HATCH :
527 {
75f0a06e
DS
528 CGPoint pts[] =
529 {
0f4c3aa2 530 { 8.0 , 0.0 } , { 0.0 , 8.0 }
24cd6f82
SC
531 };
532 StrokeLineSegments( ctxRef , pts , 2 ) ;
533 }
534 break ;
97071cdb 535
24cd6f82
SC
536 case wxCROSSDIAG_HATCH :
537 {
75f0a06e
DS
538 CGPoint pts[] =
539 {
0f4c3aa2
DS
540 { 0.0 , 0.0 } , { 8.0 , 8.0 } ,
541 { 8.0 , 0.0 } , { 0.0 , 8.0 }
24cd6f82
SC
542 };
543 StrokeLineSegments( ctxRef , pts , 4 ) ;
544 }
545 break ;
97071cdb 546
24cd6f82
SC
547 case wxFDIAGONAL_HATCH :
548 {
75f0a06e
DS
549 CGPoint pts[] =
550 {
0f4c3aa2 551 { 0.0 , 0.0 } , { 8.0 , 8.0 }
24cd6f82
SC
552 };
553 StrokeLineSegments( ctxRef , pts , 2 ) ;
554 }
555 break ;
97071cdb 556
24cd6f82
SC
557 case wxCROSS_HATCH :
558 {
75f0a06e
DS
559 CGPoint pts[] =
560 {
0f4c3aa2
DS
561 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
562 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
24cd6f82
SC
563 };
564 StrokeLineSegments( ctxRef , pts , 4 ) ;
565 }
566 break ;
97071cdb 567
24cd6f82
SC
568 case wxHORIZONTAL_HATCH :
569 {
75f0a06e
DS
570 CGPoint pts[] =
571 {
0f4c3aa2 572 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
24cd6f82
SC
573 };
574 StrokeLineSegments( ctxRef , pts , 2 ) ;
575 }
576 break ;
97071cdb 577
24cd6f82
SC
578 case wxVERTICAL_HATCH :
579 {
75f0a06e
DS
580 CGPoint pts[] =
581 {
0f4c3aa2 582 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
24cd6f82
SC
583 };
584 StrokeLineSegments( ctxRef , pts , 2 ) ;
585 }
586 break ;
75f0a06e
DS
587
588 default:
589 break;
24cd6f82
SC
590 }
591 }
0f4c3aa2 592
24cd6f82 593protected :
d3c7fc99 594 virtual ~HatchPattern() {}
97071cdb 595
24cd6f82 596 CGRect m_imageBounds ;
b21d67a0 597 int m_hatch ;
0f4c3aa2 598};
72ba915e 599
b21d67a0
DS
600#pragma mark -
601
20b69855
SC
602void wxMacCGContext::SetPen( const wxPen &pen )
603{
cb4b0966
SC
604 m_pen = pen ;
605 if ( m_cgContext == NULL )
606 return ;
75f0a06e 607
20b69855
SC
608 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
609 bool stroke = pen.GetStyle() != wxTRANSPARENT ;
0f4c3aa2 610
20b69855 611#if 0
0f4c3aa2 612 // we can benchmark performance; should go into a setting eventually
20b69855
SC
613 CGContextSetShouldAntialias( m_cgContext , false ) ;
614#endif
75f0a06e 615
613a24f7
SC
616 if ( fill | stroke )
617 {
75f0a06e 618 // set up brushes
613a24f7
SC
619 m_mode = kCGPathFill ; // just a default
620
613a24f7
SC
621 if ( stroke )
622 {
83b445a6
SC
623 CGContextSetRGBStrokeColor( m_cgContext , pen.GetColour().Red() / 255.0 , pen.GetColour().Green() / 255.0 ,
624 pen.GetColour().Blue() / 255.0 , pen.GetColour().Alpha() / 255.0 ) ;
24cd6f82 625
0f4c3aa2 626 // TODO: * m_dc->m_scaleX
bc78039c 627 CGFloat penWidth = pen.GetWidth();
24cd6f82
SC
628 if (penWidth <= 0.0)
629 penWidth = 0.1;
630 CGContextSetLineWidth( m_cgContext , penWidth ) ;
0f4c3aa2 631
613a24f7 632 CGLineCap cap ;
97071cdb 633 switch ( pen.GetCap() )
613a24f7
SC
634 {
635 case wxCAP_ROUND :
636 cap = kCGLineCapRound ;
637 break ;
75f0a06e 638
613a24f7
SC
639 case wxCAP_PROJECTING :
640 cap = kCGLineCapSquare ;
641 break ;
75f0a06e 642
613a24f7
SC
643 case wxCAP_BUTT :
644 cap = kCGLineCapButt ;
645 break ;
75f0a06e 646
613a24f7
SC
647 default :
648 cap = kCGLineCapButt ;
649 break ;
650 }
613a24f7
SC
651
652 CGLineJoin join ;
97071cdb 653 switch ( pen.GetJoin() )
613a24f7
SC
654 {
655 case wxJOIN_BEVEL :
656 join = kCGLineJoinBevel ;
657 break ;
75f0a06e 658
613a24f7
SC
659 case wxJOIN_MITER :
660 join = kCGLineJoinMiter ;
661 break ;
75f0a06e 662
613a24f7
SC
663 case wxJOIN_ROUND :
664 join = kCGLineJoinRound ;
665 break ;
75f0a06e 666
613a24f7
SC
667 default :
668 join = kCGLineJoinMiter ;
0f4c3aa2 669 break;
613a24f7 670 }
613a24f7 671
613a24f7
SC
672 m_mode = kCGPathStroke ;
673 int count = 0 ;
0f4c3aa2 674
bc78039c
SC
675 const CGFloat *lengths = NULL ;
676 CGFloat *userLengths = NULL ;
72ba915e 677
bc78039c 678 const CGFloat dashUnit = penWidth < 1.0 ? 1.0 : penWidth;
0f4c3aa2 679
bc78039c
SC
680 const CGFloat dotted[] = { dashUnit , dashUnit + 2.0 };
681 const CGFloat short_dashed[] = { 9.0 , 6.0 };
682 const CGFloat dashed[] = { 19.0 , 9.0 };
683 const CGFloat dotted_dashed[] = { 9.0 , 6.0 , 3.0 , 3.0 };
72ba915e 684
97071cdb 685 switch ( pen.GetStyle() )
613a24f7
SC
686 {
687 case wxSOLID :
688 break ;
97071cdb 689
613a24f7 690 case wxDOT :
613a24f7
SC
691 lengths = dotted ;
692 count = WXSIZEOF(dotted);
693 break ;
97071cdb 694
613a24f7 695 case wxLONG_DASH :
613a24f7
SC
696 lengths = dashed ;
697 count = WXSIZEOF(dashed) ;
698 break ;
97071cdb 699
613a24f7 700 case wxSHORT_DASH :
613a24f7
SC
701 lengths = short_dashed ;
702 count = WXSIZEOF(short_dashed) ;
703 break ;
97071cdb 704
613a24f7 705 case wxDOT_DASH :
613a24f7
SC
706 lengths = dotted_dashed ;
707 count = WXSIZEOF(dotted_dashed);
708 break ;
97071cdb 709
613a24f7
SC
710 case wxUSER_DASH :
711 wxDash *dashes ;
20b69855 712 count = pen.GetDashes( &dashes ) ;
72ba915e 713 if ((dashes != NULL) && (count > 0))
613a24f7 714 {
bc78039c 715 userLengths = new CGFloat[count] ;
ec4a2b5d 716 for ( int i = 0 ; i < count ; ++i )
72ba915e 717 {
46bed958 718 userLengths[i] = dashes[i] * dashUnit ;
24cd6f82
SC
719
720 if ( i % 2 == 1 && userLengths[i] < dashUnit + 2.0 )
721 userLengths[i] = dashUnit + 2.0 ;
722 else if ( i % 2 == 0 && userLengths[i] < dashUnit )
723 userLengths[i] = dashUnit ;
72ba915e 724 }
613a24f7
SC
725 }
726 lengths = userLengths ;
727 break ;
97071cdb 728
24cd6f82
SC
729 case wxSTIPPLE :
730 {
bc78039c 731 CGFloat alphaArray[1] = { 1.0 } ;
24cd6f82 732 wxBitmap* bmp = pen.GetStipple() ;
0f4c3aa2 733 if ( bmp && bmp->Ok() )
24cd6f82
SC
734 {
735 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) ) ;
736 CGContextSetStrokeColorSpace( m_cgContext , patternSpace ) ;
737 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
738 CGContextSetStrokePattern( m_cgContext, pattern , alphaArray ) ;
739 }
740 }
741 break ;
97071cdb 742
613a24f7 743 default :
24cd6f82
SC
744 {
745 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) ) ;
746 CGContextSetStrokeColorSpace( m_cgContext , patternSpace ) ;
747 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( pen.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
0f4c3aa2 748
83b445a6
SC
749 CGFloat colorArray[4] = { pen.GetColour().Red() / 255.0 , pen.GetColour().Green() / 255.0 ,
750 pen.GetColour().Blue() / 255.0 , pen.GetColour().Alpha() / 255.0 } ;
0f4c3aa2 751
24cd6f82
SC
752 CGContextSetStrokePattern( m_cgContext, pattern , colorArray ) ;
753 }
0f4c3aa2 754 break ;
613a24f7
SC
755 }
756
72ba915e
SC
757 if ((lengths != NULL) && (count > 0))
758 {
72ba915e 759 CGContextSetLineDash( m_cgContext , 0 , lengths , count ) ;
24cd6f82
SC
760 // force the line cap, otherwise we get artifacts (overlaps) and just solid lines
761 cap = kCGLineCapButt ;
72ba915e 762 }
0f4c3aa2 763 else
72ba915e
SC
764 {
765 CGContextSetLineDash( m_cgContext , 0 , NULL , 0 ) ;
766 }
97071cdb 767
24cd6f82 768 CGContextSetLineCap( m_cgContext , cap ) ;
75f0a06e 769 CGContextSetLineJoin( m_cgContext , join ) ;
72ba915e
SC
770
771 delete[] userLengths ;
613a24f7 772 }
97071cdb 773
613a24f7 774 if ( fill && stroke )
613a24f7 775 m_mode = kCGPathFillStroke ;
613a24f7
SC
776 }
777}
72ba915e 778
20b69855
SC
779void wxMacCGContext::SetBrush( const wxBrush &brush )
780{
cb4b0966
SC
781 m_brush = brush ;
782 if ( m_cgContext == NULL )
783 return ;
784
20b69855
SC
785 bool fill = brush.GetStyle() != wxTRANSPARENT ;
786 bool stroke = m_pen.GetStyle() != wxTRANSPARENT ;
613a24f7 787
20b69855
SC
788#if 0
789 // we can benchmark performance, should go into a setting later
790 CGContextSetShouldAntialias( m_cgContext , false ) ;
791#endif
72ba915e 792
20b69855
SC
793 if ( fill | stroke )
794 {
20b69855
SC
795 // setup brushes
796 m_mode = kCGPathFill ; // just a default
797
798 if ( fill )
799 {
24cd6f82 800 if ( brush.GetStyle() == wxSOLID )
72ba915e 801 {
83b445a6
SC
802 CGContextSetRGBFillColor( m_cgContext , brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
803 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 ) ;
24cd6f82
SC
804 }
805 else if ( brush.IsHatch() )
806 {
807 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) ) ;
808 CGContextSetFillColorSpace( m_cgContext , patternSpace ) ;
809 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( brush.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
810
83b445a6
SC
811 CGFloat colorArray[4] = { brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
812 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 } ;
0f4c3aa2 813
24cd6f82
SC
814 CGContextSetFillPattern( m_cgContext, pattern , colorArray ) ;
815 }
816 else
817 {
818 // now brush is a bitmap
bc78039c 819 CGFloat alphaArray[1] = { 1.0 } ;
24cd6f82 820 wxBitmap* bmp = brush.GetStipple() ;
0f4c3aa2 821 if ( bmp && bmp->Ok() )
72ba915e 822 {
24cd6f82
SC
823 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) ) ;
824 CGContextSetFillColorSpace( m_cgContext , patternSpace ) ;
825 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
826 CGContextSetFillPattern( m_cgContext, pattern , alphaArray ) ;
72ba915e
SC
827 }
828 }
75f0a06e 829
20b69855
SC
830 m_mode = kCGPathFill ;
831 }
97071cdb 832
20b69855 833 if ( fill && stroke )
20b69855 834 m_mode = kCGPathFillStroke ;
75f0a06e
DS
835 else if ( stroke )
836 m_mode = kCGPathStroke ;
20b69855
SC
837 }
838}
839
ded83b1a 840void wxMacCGContext::DrawText( const wxString &str, wxCoord x, wxCoord y, double angle )
613a24f7 841{
ded83b1a
SC
842 OSStatus status = noErr ;
843 ATSUTextLayout atsuLayout ;
844 UniCharCount chars = str.length() ;
845 UniChar* ubuf = NULL ;
613a24f7 846
ded83b1a
SC
847#if SIZEOF_WCHAR_T == 4
848 wxMBConvUTF16 converter ;
849#if wxUSE_UNICODE
850 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
851 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
852 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
853#else
854 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
855 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
856 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
857 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
858#endif
859 chars = unicharlen / 2 ;
860#else
861#if wxUSE_UNICODE
862 ubuf = (UniChar*) str.wc_str() ;
863#else
864 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
865 chars = wxWcslen( wchar.data() ) ;
866 ubuf = (UniChar*) wchar.data() ;
867#endif
868#endif
869
870 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
871 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
872
873 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
874
875 status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
876 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
877
878 int iAngle = int( angle );
879 if ( abs(iAngle) > 0 )
613a24f7 880 {
ded83b1a
SC
881 Fixed atsuAngle = IntToFixed( iAngle ) ;
882 ATSUAttributeTag atsuTags[] =
883 {
884 kATSULineRotationTag ,
885 } ;
886 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
887 {
888 sizeof( Fixed ) ,
889 } ;
890 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
891 {
892 &atsuAngle ,
893 } ;
894 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
895 atsuTags, atsuSizes, atsuValues ) ;
613a24f7 896 }
97071cdb 897
ded83b1a
SC
898 {
899 ATSUAttributeTag atsuTags[] =
900 {
901 kATSUCGContextTag ,
902 } ;
903 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
904 {
905 sizeof( CGContextRef ) ,
906 } ;
907 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
908 {
909 &m_cgContext ,
910 } ;
911 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
912 atsuTags, atsuSizes, atsuValues ) ;
913 }
ec4a2b5d 914
ded83b1a
SC
915 ATSUTextMeasurement textBefore, textAfter ;
916 ATSUTextMeasurement ascent, descent ;
ec4a2b5d 917
ded83b1a
SC
918 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
919 &textBefore , &textAfter, &ascent , &descent );
613a24f7 920
ded83b1a 921 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
eb1a7cf9 922
ded83b1a
SC
923 Rect rect ;
924/*
925 // TODO
926 if ( m_backgroundMode == wxSOLID )
927 {
928 wxGraphicPath* path = m_graphicContext->CreatePath() ;
929 path->MoveToPoint( drawX , drawY ) ;
930 path->AddLineToPoint(
931 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ,
932 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) ) ;
933 path->AddLineToPoint(
934 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
935 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ) ;
936 path->AddLineToPoint(
937 (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
938 (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ) ;
24cd6f82 939
ded83b1a
SC
940 m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
941 delete path ;
942 }
943*/
944 x += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
945 y += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
20b69855 946
ded83b1a
SC
947 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
948 IntToFixed(x) , IntToFixed(y) , &rect );
949 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
20b69855 950
ded83b1a
SC
951 CGContextSaveGState(m_cgContext);
952 CGContextTranslateCTM(m_cgContext, x, y);
953 CGContextScaleCTM(m_cgContext, 1, -1);
954 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
955 IntToFixed(0) , IntToFixed(0) );
613a24f7 956
ded83b1a 957 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
613a24f7 958
ded83b1a 959 CGContextRestoreGState(m_cgContext) ;
20b69855 960
ded83b1a 961 ::ATSUDisposeTextLayout(atsuLayout);
613a24f7 962
ded83b1a
SC
963#if SIZEOF_WCHAR_T == 4
964 free( ubuf ) ;
965#endif
966}
967
968void wxMacCGContext::GetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
969 wxCoord *descent, wxCoord *externalLeading ) const
613a24f7 970{
ded83b1a 971 wxCHECK_RET( m_macATSUIStyle != NULL, wxT("wxDC(cg)::DoGetTextExtent - no valid font set") ) ;
75f0a06e 972
ded83b1a
SC
973 OSStatus status = noErr ;
974
975 ATSUTextLayout atsuLayout ;
976 UniCharCount chars = str.length() ;
977 UniChar* ubuf = NULL ;
20b69855 978
ded83b1a
SC
979#if SIZEOF_WCHAR_T == 4
980 wxMBConvUTF16 converter ;
981#if wxUSE_UNICODE
982 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
983 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
984 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
985#else
986 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
987 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
988 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
989 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
990#endif
991 chars = unicharlen / 2 ;
992#else
993#if wxUSE_UNICODE
994 ubuf = (UniChar*) str.wc_str() ;
995#else
996 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
997 chars = wxWcslen( wchar.data() ) ;
998 ubuf = (UniChar*) wchar.data() ;
999#endif
1000#endif
613a24f7 1001
ded83b1a
SC
1002 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1003 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
20b69855 1004
ded83b1a 1005 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
20b69855 1006
ded83b1a
SC
1007 ATSUTextMeasurement textBefore, textAfter ;
1008 ATSUTextMeasurement textAscent, textDescent ;
1009
1010 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1011 &textBefore , &textAfter, &textAscent , &textDescent );
1012
1013 if ( height )
1014 *height = FixedToInt(textAscent + textDescent) ;
1015 if ( descent )
1016 *descent = FixedToInt(textDescent) ;
1017 if ( externalLeading )
1018 *externalLeading = 0 ;
1019 if ( width )
1020 *width = FixedToInt(textAfter - textBefore) ;
1021
1022 ::ATSUDisposeTextLayout(atsuLayout);
613a24f7
SC
1023}
1024
ded83b1a 1025void wxMacCGContext::GetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
613a24f7 1026{
ded83b1a
SC
1027 widths.Empty();
1028 widths.Add(0, text.length());
75f0a06e 1029
ded83b1a
SC
1030 if (text.empty())
1031 return ;
b014adcc 1032
ded83b1a
SC
1033 ATSUTextLayout atsuLayout ;
1034 UniCharCount chars = text.length() ;
1035 UniChar* ubuf = NULL ;
1036
1037#if SIZEOF_WCHAR_T == 4
1038 wxMBConvUTF16 converter ;
1039#if wxUSE_UNICODE
1040 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
1041 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1042 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
1043#else
1044 const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1045 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1046 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1047 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1048#endif
1049 chars = unicharlen / 2 ;
1050#else
1051#if wxUSE_UNICODE
1052 ubuf = (UniChar*) text.wc_str() ;
1053#else
1054 wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1055 chars = wxWcslen( wchar.data() ) ;
1056 ubuf = (UniChar*) wchar.data() ;
1057#endif
1058#endif
1059
1060 OSStatus status;
1061 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1062 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1063
1064 for ( int pos = 0; pos < (int)chars; pos ++ )
1065 {
1066 unsigned long actualNumberOfBounds = 0;
1067 ATSTrapezoid glyphBounds;
1068
1069 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1070 OSStatus result;
1071 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
1072 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1073 if (result != noErr || actualNumberOfBounds != 1 )
1074 return ;
1075
1076 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
1077 //unsigned char uch = s[i];
1078 }
1079
1080 ::ATSUDisposeTextLayout(atsuLayout);
1081}
1082
1083void wxMacCGContext::SetFont( const wxFont &font )
1084{
1085 if ( m_macATSUIStyle )
1086 {
1087 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1088 m_macATSUIStyle = NULL ;
1089 }
1090
1091 if ( font.Ok() )
1092 {
1093 OSStatus status ;
1094
1095 status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
1096
1097 wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") ) ;
1098
1099 // we need the scale here ...
1100
1101 Fixed atsuSize = IntToFixed( int( /*m_scaleY*/ 1 * font.MacGetFontSize()) ) ;
1102 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColor.GetPixel() ) ;
1103 ATSUAttributeTag atsuTags[] =
1104 {
1105 kATSUSizeTag ,
1106 kATSUColorTag ,
1107 } ;
1108 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1109 {
1110 sizeof( Fixed ) ,
1111 sizeof( RGBColor ) ,
1112 } ;
1113 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1114 {
1115 &atsuSize ,
1116 &atsuColor ,
1117 } ;
1118
1119 status = ::ATSUSetAttributes(
1120 (ATSUStyle)m_macATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) ,
1121 atsuTags, atsuSizes, atsuValues);
1122
1123 wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") ) ;
1124 }
1125}
1126
1127
1128#pragma mark -
1129
1130wxDC::wxDC()
1131{
1132 m_ok = false ;
1133 m_colour = true;
1134 m_mm_to_pix_x = mm2pt;
1135 m_mm_to_pix_y = mm2pt;
1136
1137 m_externalDeviceOriginX = 0;
1138 m_externalDeviceOriginY = 0;
1139 m_logicalScaleX = 1.0;
1140 m_logicalScaleY = 1.0;
1141 m_userScaleX = 1.0;
1142 m_userScaleY = 1.0;
1143 m_scaleX = 1.0;
1144 m_scaleY = 1.0;
1145 m_needComputeScaleX =
1146 m_needComputeScaleY = false;
1147
1148 m_macPort = 0 ;
1149 m_macLocalOrigin.x =
1150 m_macLocalOrigin.y = 0 ;
1151
1152 m_pen = *wxBLACK_PEN;
1153 m_font = *wxNORMAL_FONT;
1154 m_brush = *wxWHITE_BRUSH;
1155
1156 m_macATSUIStyle = NULL ;
1157 m_graphicContext = NULL ;
1158}
1159
1160wxDC::~wxDC()
1161{
1162 if ( m_macATSUIStyle )
1163 {
1164 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1165 m_macATSUIStyle = NULL ;
1166 }
1167
1168 delete m_graphicContext ;
1169}
1170
1171void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
1172{
1173 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawBitmap - invalid DC") );
1174 wxCHECK_RET( bmp.Ok(), wxT("wxDC(cg)::DoDrawBitmap - invalid bitmap") );
1175
1176 wxCoord xx = XLOG2DEVMAC(x);
1177 wxCoord yy = YLOG2DEVMAC(y);
1178 wxCoord w = bmp.GetWidth();
1179 wxCoord h = bmp.GetHeight();
1180 wxCoord ww = XLOG2DEVREL(w);
1181 wxCoord hh = YLOG2DEVREL(h);
1182
1183 m_graphicContext->DrawBitmap( bmp, xx , yy , ww , hh ) ;
1184}
1185
1186void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
1187{
1188 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawIcon - invalid DC") );
1189 wxCHECK_RET( icon.Ok(), wxT("wxDC(cg)::DoDrawIcon - invalid icon") );
1190
1191 wxCoord xx = XLOG2DEVMAC(x);
1192 wxCoord yy = YLOG2DEVMAC(y);
1193 wxCoord w = icon.GetWidth();
1194 wxCoord h = icon.GetHeight();
1195 wxCoord ww = XLOG2DEVREL(w);
1196 wxCoord hh = YLOG2DEVREL(h);
1197
1198 m_graphicContext->DrawIcon( icon , xx, yy, ww, hh ) ;
1199}
1200
1201void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1202{
1203 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoSetClippingRegion - invalid DC") );
1204
1205 wxCoord xx, yy, ww, hh;
1206 xx = XLOG2DEVMAC(x);
1207 yy = YLOG2DEVMAC(y);
1208 ww = XLOG2DEVREL(width);
1209 hh = YLOG2DEVREL(height);
1210
1211 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
b21d67a0 1212 CGRect clipRect = CGRectMake( xx , yy , ww, hh ) ;
b014adcc
SC
1213 CGContextClipToRect( cgContext , clipRect ) ;
1214
20b69855
SC
1215// SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
1216// SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
75f0a06e 1217
97071cdb 1218 if ( m_clipping )
613a24f7 1219 {
b21d67a0
DS
1220 m_clipX1 = wxMax( m_clipX1, xx );
1221 m_clipY1 = wxMax( m_clipY1, yy );
1222 m_clipX2 = wxMin( m_clipX2, (xx + ww) );
1223 m_clipY2 = wxMin( m_clipY2, (yy + hh) );
613a24f7
SC
1224 }
1225 else
1226 {
97071cdb 1227 m_clipping = true;
b21d67a0 1228
613a24f7
SC
1229 m_clipX1 = xx;
1230 m_clipY1 = yy;
1231 m_clipX2 = xx + ww;
1232 m_clipY2 = yy + hh;
1233 }
75f0a06e 1234
b21d67a0 1235 // TODO: as soon as we don't reset the context for each operation anymore
613a24f7
SC
1236 // we have to update the context as well
1237}
1238
eb1a7cf9 1239void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
613a24f7 1240{
b21d67a0
DS
1241 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoSetClippingRegionAsRegion - invalid DC") );
1242
613a24f7
SC
1243 if (region.Empty())
1244 {
1245 DestroyClippingRegion();
1246 return;
1247 }
97071cdb 1248
613a24f7
SC
1249 wxCoord x, y, w, h;
1250 region.GetBox( x, y, w, h );
1251 wxCoord xx, yy, ww, hh;
1252 xx = XLOG2DEVMAC(x);
1253 yy = YLOG2DEVMAC(y);
1254 ww = XLOG2DEVREL(w);
1255 hh = YLOG2DEVREL(h);
75f0a06e 1256
613a24f7
SC
1257 // if we have a scaling that we cannot map onto native regions
1258 // we must use the box
1259 if ( ww != w || hh != h )
1260 {
1261 wxDC::DoSetClippingRegion( x, y, w, h );
1262 }
1263 else
1264 {
75f0a06e 1265#if 0
613a24f7
SC
1266 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
1267 if ( xx != x || yy != y )
613a24f7 1268 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
b21d67a0 1269 SectRgn( (RgnHandle)m_macCurrentClipRgn , (RgnHandle)m_macBoundaryClipRgn , (RgnHandle)m_macCurrentClipRgn ) ;
75f0a06e
DS
1270#endif
1271
97071cdb 1272 if ( m_clipping )
613a24f7 1273 {
b21d67a0
DS
1274 m_clipX1 = wxMax( m_clipX1, xx );
1275 m_clipY1 = wxMax( m_clipY1, yy );
1276 m_clipX2 = wxMin( m_clipX2, (xx + ww) );
1277 m_clipY2 = wxMin( m_clipY2, (yy + hh) );
613a24f7
SC
1278 }
1279 else
1280 {
97071cdb 1281 m_clipping = true;
b21d67a0 1282
613a24f7
SC
1283 m_clipX1 = xx;
1284 m_clipY1 = yy;
1285 m_clipX2 = xx + ww;
1286 m_clipY2 = yy + hh;
1287 }
1288 }
1289}
1290
1291void wxDC::DestroyClippingRegion()
1292{
20b69855 1293// CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
b21d67a0 1294
b60f5ca5 1295 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
0f4c3aa2 1296 CGContextRestoreGState( cgContext );
b21d67a0
DS
1297 CGContextSaveGState( cgContext );
1298
0e71e845
SC
1299 m_graphicContext->SetPen( m_pen ) ;
1300 m_graphicContext->SetBrush( m_brush ) ;
b21d67a0 1301
97071cdb 1302 m_clipping = false;
613a24f7
SC
1303}
1304
1305void wxDC::DoGetSizeMM( int* width, int* height ) const
1306{
75f0a06e
DS
1307 int w = 0, h = 0;
1308
613a24f7 1309 GetSize( &w, &h );
75f0a06e
DS
1310 if (width)
1311 *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) );
1312 if (height)
1313 *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) );
613a24f7
SC
1314}
1315
1316void wxDC::SetTextForeground( const wxColour &col )
1317{
b21d67a0 1318 wxCHECK_RET( Ok(), wxT("wxDC(cg)::SetTextForeground - invalid DC") );
75f0a06e 1319
20b69855
SC
1320 if ( col != m_textForegroundColour )
1321 {
1322 m_textForegroundColour = col;
ded83b1a 1323 m_graphicContext->SetTextColor( col ) ;
20b69855 1324 }
613a24f7
SC
1325}
1326
1327void wxDC::SetTextBackground( const wxColour &col )
1328{
b21d67a0 1329 wxCHECK_RET( Ok(), wxT("wxDC(cg)::SetTextBackground - invalid DC") );
75f0a06e 1330
613a24f7 1331 m_textBackgroundColour = col;
613a24f7
SC
1332}
1333
1334void wxDC::SetMapMode( int mode )
1335{
1336 switch (mode)
1337 {
1338 case wxMM_TWIPS:
75f0a06e 1339 SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y );
613a24f7 1340 break;
97071cdb 1341
613a24f7 1342 case wxMM_POINTS:
75f0a06e 1343 SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y );
613a24f7 1344 break;
97071cdb 1345
613a24f7
SC
1346 case wxMM_METRIC:
1347 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1348 break;
97071cdb 1349
613a24f7 1350 case wxMM_LOMETRIC:
75f0a06e 1351 SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 );
613a24f7 1352 break;
97071cdb 1353
613a24f7 1354 case wxMM_TEXT:
97071cdb 1355 default:
613a24f7
SC
1356 SetLogicalScale( 1.0, 1.0 );
1357 break;
1358 }
97071cdb 1359
613a24f7
SC
1360 if (mode != wxMM_TEXT)
1361 {
97071cdb
DS
1362 m_needComputeScaleX =
1363 m_needComputeScaleY = true;
613a24f7
SC
1364 }
1365}
1366
1367void wxDC::SetUserScale( double x, double y )
1368{
1369 // allow negative ? -> no
1370 m_userScaleX = x;
1371 m_userScaleY = y;
1372 ComputeScaleAndOrigin();
1373}
1374
1375void wxDC::SetLogicalScale( double x, double y )
1376{
1377 // allow negative ?
1378 m_logicalScaleX = x;
1379 m_logicalScaleY = y;
1380 ComputeScaleAndOrigin();
1381}
1382
1383void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
1384{
1385 m_logicalOriginX = x * m_signX; // is this still correct ?
1386 m_logicalOriginY = y * m_signY;
1387 ComputeScaleAndOrigin();
1388}
1389
1390void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1391{
1392 m_externalDeviceOriginX = x;
1393 m_externalDeviceOriginY = y;
1394 ComputeScaleAndOrigin();
1395}
1396
1397void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1398{
1399 m_signX = (xLeftRight ? 1 : -1);
b21d67a0 1400 m_signY = (yBottomUp ? -1 : 1);
613a24f7
SC
1401 ComputeScaleAndOrigin();
1402}
1403
1404wxSize wxDC::GetPPI() const
1405{
1406 return wxSize(72, 72);
1407}
1408
1409int wxDC::GetDepth() const
1410{
0f4c3aa2 1411 return 32;
613a24f7
SC
1412}
1413
1414void wxDC::ComputeScaleAndOrigin()
1415{
1416 // CMB: copy scale to see if it changes
1417 double origScaleX = m_scaleX;
1418 double origScaleY = m_scaleY;
1419 m_scaleX = m_logicalScaleX * m_userScaleX;
1420 m_scaleY = m_logicalScaleY * m_userScaleY;
24cd6f82
SC
1421 m_deviceOriginX = m_externalDeviceOriginX;
1422 m_deviceOriginY = m_externalDeviceOriginY;
97071cdb 1423
613a24f7
SC
1424 // CMB: if scale has changed call SetPen to recalulate the line width
1425 if (m_scaleX != origScaleX || m_scaleY != origScaleY)
1426 {
1427 // this is a bit artificial, but we need to force wxDC to think
1428 // the pen has changed
75f0a06e 1429 wxPen pen( GetPen() );
97071cdb 1430
613a24f7 1431 m_pen = wxNullPen;
0f4c3aa2 1432 SetPen( pen );
613a24f7
SC
1433 }
1434}
1435
b21d67a0 1436void wxDC::SetPalette( const wxPalette& palette )
613a24f7
SC
1437{
1438}
1439
b21d67a0 1440void wxDC::SetBackgroundMode( int mode )
613a24f7
SC
1441{
1442 m_backgroundMode = mode ;
1443}
1444
b21d67a0 1445void wxDC::SetFont( const wxFont &font )
613a24f7
SC
1446{
1447 m_font = font;
ded83b1a
SC
1448 if ( m_graphicContext )
1449 m_graphicContext->SetFont( font ) ;
613a24f7
SC
1450}
1451
b21d67a0 1452void wxDC::SetPen( const wxPen &pen )
613a24f7
SC
1453{
1454 if ( m_pen == pen )
1455 return ;
97071cdb 1456
613a24f7 1457 m_pen = pen;
20b69855
SC
1458 if ( m_graphicContext )
1459 {
24cd6f82
SC
1460 if ( m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT )
1461 {
1462 m_graphicContext->SetPen( m_pen ) ;
1463 }
1464 else
1465 {
1466 // we have to compensate for moved device origins etc. otherwise patterned pens are standing still
1467 // eg when using a wxScrollWindow and scrolling around
0f4c3aa2
DS
1468 int origX = XLOG2DEVMAC( 0 ) ;
1469 int origY = YLOG2DEVMAC( 0 ) ;
ded83b1a 1470 m_graphicContext->Translate( origX , origY ) ;
24cd6f82 1471 m_graphicContext->SetPen( m_pen ) ;
ded83b1a 1472 m_graphicContext->Translate( -origX , -origY ) ;
24cd6f82 1473 }
20b69855 1474 }
613a24f7
SC
1475}
1476
b21d67a0 1477void wxDC::SetBrush( const wxBrush &brush )
613a24f7
SC
1478{
1479 if (m_brush == brush)
1480 return;
97071cdb 1481
613a24f7 1482 m_brush = brush;
20b69855
SC
1483 if ( m_graphicContext )
1484 {
24cd6f82
SC
1485 if ( brush.GetStyle() == wxSOLID || brush.GetStyle() == wxTRANSPARENT )
1486 {
1487 m_graphicContext->SetBrush( m_brush ) ;
1488 }
1489 else
1490 {
1491 // we have to compensate for moved device origins etc. otherwise patterned brushes are standing still
1492 // eg when using a wxScrollWindow and scrolling around
24cd6f82
SC
1493 int origX = XLOG2DEVMAC(0) ;
1494 int origY = YLOG2DEVMAC(0) ;
ded83b1a 1495 m_graphicContext->Translate( origX , origY ) ;
24cd6f82 1496 m_graphicContext->SetBrush( m_brush ) ;
ded83b1a 1497 m_graphicContext->Translate( -origX , -origY ) ;
24cd6f82 1498 }
20b69855 1499 }
613a24f7
SC
1500}
1501
b21d67a0 1502void wxDC::SetBackground( const wxBrush &brush )
613a24f7
SC
1503{
1504 if (m_backgroundBrush == brush)
1505 return;
0f4c3aa2 1506
613a24f7
SC
1507 m_backgroundBrush = brush;
1508 if (!m_backgroundBrush.Ok())
1509 return;
613a24f7
SC
1510}
1511
b21d67a0 1512void wxDC::SetLogicalFunction( int function )
613a24f7
SC
1513{
1514 if (m_logicalFunction == function)
1515 return;
97071cdb 1516
613a24f7 1517 m_logicalFunction = function ;
01b5ab33
SC
1518#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
1519 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1520 if ( m_logicalFunction == wxCOPY )
1521 CGContextSetBlendMode( cgContext, kCGBlendModeNormal ) ;
1522 else if ( m_logicalFunction == wxINVERT )
1523 CGContextSetBlendMode( cgContext, kCGBlendModeExclusion ) ;
1524 else
1525 CGContextSetBlendMode( cgContext, kCGBlendModeNormal ) ;
1526#endif
613a24f7
SC
1527}
1528
1529extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
1530 const wxColour & col, int style);
1531
1532bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
1533 const wxColour& col, int style)
1534{
1535 return wxDoFloodFill(this, x, y, col, style);
1536}
1537
b21d67a0 1538bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
613a24f7 1539{
b21d67a0 1540 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::DoGetPixel - invalid DC") );
75f0a06e 1541
880f5369
SC
1542 wxMacPortSaver helper((CGrafPtr)m_macPort) ;
1543 RGBColor colour;
75f0a06e
DS
1544
1545 // NB: GetCPixel is a deprecated QD call, and a slow one at that
0f4c3aa2
DS
1546 GetCPixel(
1547 XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x,
880f5369 1548 YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
75f0a06e
DS
1549
1550 // convert from Mac colour to wx
1551 col->Set( colour.red >> 8, colour.green >> 8, colour.blue >> 8 );
97071cdb 1552
880f5369 1553 return true ;
613a24f7
SC
1554}
1555
b21d67a0 1556void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
613a24f7 1557{
b21d67a0
DS
1558 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawLine - invalid DC") );
1559
01b5ab33 1560#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
08c8555e
SC
1561 if ( m_logicalFunction != wxCOPY )
1562 return ;
0f4c3aa2 1563#endif
b21d67a0 1564
613a24f7
SC
1565 wxCoord xx1 = XLOG2DEVMAC(x1) ;
1566 wxCoord yy1 = YLOG2DEVMAC(y1) ;
1567 wxCoord xx2 = XLOG2DEVMAC(x2) ;
1568 wxCoord yy2 = YLOG2DEVMAC(y2) ;
1569
20b69855 1570 wxGraphicPath* path = m_graphicContext->CreatePath() ;
b21d67a0 1571 path->MoveToPoint( xx1, yy1 ) ;
20b69855
SC
1572 path->AddLineToPoint( xx2 , yy2 ) ;
1573 path->CloseSubpath() ;
1574 m_graphicContext->StrokePath( path ) ;
1575 delete path ;
613a24f7
SC
1576
1577 CalcBoundingBox(x1, y1);
1578 CalcBoundingBox(x2, y2);
1579}
1580
b21d67a0 1581void wxDC::DoCrossHair( wxCoord x, wxCoord y )
613a24f7 1582{
b21d67a0 1583 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoCrossHair - invalid DC") );
613a24f7 1584
08c8555e
SC
1585 if ( m_logicalFunction != wxCOPY )
1586 return ;
0f4c3aa2 1587
b21d67a0
DS
1588 int w = 0, h = 0;
1589
613a24f7
SC
1590 GetSize( &w, &h );
1591 wxCoord xx = XLOG2DEVMAC(x);
1592 wxCoord yy = YLOG2DEVMAC(y);
1593
20b69855 1594 wxGraphicPath* path = m_graphicContext->CreatePath() ;
b21d67a0 1595 path->MoveToPoint( XLOG2DEVMAC(0), yy ) ;
20b69855
SC
1596 path->AddLineToPoint( XLOG2DEVMAC(w), yy ) ;
1597 path->CloseSubpath() ;
1598 path->MoveToPoint( xx, YLOG2DEVMAC(0) ) ;
1599 path->AddLineToPoint( xx, YLOG2DEVMAC(h) ) ;
1600 path->CloseSubpath() ;
1601 m_graphicContext->StrokePath( path ) ;
1602 delete path ;
613a24f7
SC
1603
1604 CalcBoundingBox(x, y);
b21d67a0 1605 CalcBoundingBox(x + w, y + h);
613a24f7
SC
1606}
1607
b21d67a0 1608void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
613a24f7
SC
1609 wxCoord x2, wxCoord y2,
1610 wxCoord xc, wxCoord yc )
1611{
b21d67a0 1612 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawArc - invalid DC") );
08c8555e
SC
1613
1614 if ( m_logicalFunction != wxCOPY )
1615 return ;
1616
613a24f7
SC
1617 wxCoord xx1 = XLOG2DEVMAC(x1);
1618 wxCoord yy1 = YLOG2DEVMAC(y1);
1619 wxCoord xx2 = XLOG2DEVMAC(x2);
1620 wxCoord yy2 = YLOG2DEVMAC(y2);
1621 wxCoord xxc = XLOG2DEVMAC(xc);
1622 wxCoord yyc = YLOG2DEVMAC(yc);
75f0a06e 1623
613a24f7
SC
1624 double dx = xx1 - xxc;
1625 double dy = yy1 - yyc;
b21d67a0 1626 double radius = sqrt((double)(dx * dx + dy * dy));
75f0a06e 1627 wxCoord rad = (wxCoord)radius;
72ba915e 1628 double sa, ea;
613a24f7
SC
1629 if (xx1 == xx2 && yy1 == yy2)
1630 {
72ba915e
SC
1631 sa = 0.0;
1632 ea = 360.0;
613a24f7
SC
1633 }
1634 else if (radius == 0.0)
1635 {
72ba915e 1636 sa = ea = 0.0;
613a24f7
SC
1637 }
1638 else
1639 {
72ba915e 1640 sa = (xx1 - xxc == 0) ?
613a24f7 1641 (yy1 - yyc < 0) ? 90.0 : -90.0 :
b21d67a0 1642 -atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG;
72ba915e 1643 ea = (xx2 - xxc == 0) ?
613a24f7 1644 (yy2 - yyc < 0) ? 90.0 : -90.0 :
b21d67a0 1645 -atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG;
613a24f7 1646 }
72ba915e
SC
1647
1648 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
ded83b1a
SC
1649
1650 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1651 m_graphicContext->PushState() ;
1652 m_graphicContext->Translate( xxc, yyc ) ;
1653 m_graphicContext->Scale( 1, -1 ) ;
72ba915e 1654 if ( fill )
ded83b1a
SC
1655 path->MoveToPoint( 0, 0 ) ;
1656 path->AddArc( 0, 0, rad , DegToRad(sa) , DegToRad(ea), false ) ;
72ba915e 1657 if ( fill )
ded83b1a
SC
1658 path->AddLineToPoint( 0, 0 ) ;
1659 m_graphicContext->DrawPath( path ) ;
1660 m_graphicContext->PopState() ;
1661 delete path ;
613a24f7
SC
1662}
1663
b21d67a0 1664void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
613a24f7
SC
1665 double sa, double ea )
1666{
b21d67a0 1667 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawEllipticArc - invalid DC") );
20b69855 1668
08c8555e
SC
1669 if ( m_logicalFunction != wxCOPY )
1670 return ;
1671
613a24f7
SC
1672 wxCoord xx = XLOG2DEVMAC(x);
1673 wxCoord yy = YLOG2DEVMAC(y);
1674 wxCoord ww = m_signX * XLOG2DEVREL(w);
1675 wxCoord hh = m_signY * YLOG2DEVREL(h);
75f0a06e 1676
613a24f7 1677 // handle -ve width and/or height
75f0a06e
DS
1678 if (ww < 0)
1679 {
1680 ww = -ww;
1681 xx = xx - ww;
1682 }
1683 if (hh < 0)
1684 {
1685 hh = -hh;
1686 yy = yy - hh;
1687 }
72ba915e
SC
1688
1689 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
1690
ded83b1a
SC
1691 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1692 m_graphicContext->PushState() ;
1693 m_graphicContext->Translate( xx + ww / 2, yy + hh / 2 ) ;
1694 m_graphicContext->Scale( 1 * ww / 2 , -1 * hh / 2 ) ;
72ba915e 1695 if ( fill )
ded83b1a
SC
1696 path->MoveToPoint( 0, 0 ) ;
1697 path->AddArc( 0, 0, 1 , DegToRad(sa) , DegToRad(ea), false ) ;
72ba915e 1698 if ( fill )
ded83b1a
SC
1699 path->AddLineToPoint( 0, 0 ) ;
1700 m_graphicContext->DrawPath( path ) ;
1701 m_graphicContext->PopState() ;
1702 delete path ;
613a24f7
SC
1703}
1704
b21d67a0 1705void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
613a24f7 1706{
b21d67a0 1707 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawPoint - invalid DC") );
75f0a06e 1708
613a24f7
SC
1709 DoDrawLine( x , y , x + 1 , y + 1 ) ;
1710}
1711
b21d67a0 1712void wxDC::DoDrawLines(int n, wxPoint points[],
613a24f7
SC
1713 wxCoord xoffset, wxCoord yoffset)
1714{
b21d67a0 1715 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawLines - invalid DC") );
75f0a06e 1716
01b5ab33 1717#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
08c8555e
SC
1718 if ( m_logicalFunction != wxCOPY )
1719 return ;
0f4c3aa2 1720#endif
08c8555e 1721
613a24f7
SC
1722 wxCoord x1, x2 , y1 , y2 ;
1723 x1 = XLOG2DEVMAC(points[0].x + xoffset);
1724 y1 = YLOG2DEVMAC(points[0].y + yoffset);
20b69855
SC
1725 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1726 path->MoveToPoint( x1 , y1 ) ;
613a24f7
SC
1727 for (int i = 1; i < n; i++)
1728 {
1729 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1730 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1731
20b69855 1732 path->AddLineToPoint( x2 , y2 ) ;
613a24f7 1733 }
97071cdb 1734
20b69855
SC
1735 m_graphicContext->StrokePath( path ) ;
1736 delete path ;
613a24f7
SC
1737}
1738
e828c96a
SC
1739#if wxUSE_SPLINES
1740void wxDC::DoDrawSpline(wxList *points)
1741{
b21d67a0
DS
1742 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawSpline - invalid DC") );
1743
e828c96a
SC
1744 if ( m_logicalFunction != wxCOPY )
1745 return ;
0f4c3aa2 1746
e828c96a 1747 wxGraphicPath* path = m_graphicContext->CreatePath() ;
0f4c3aa2 1748
e828c96a
SC
1749 wxList::compatibility_iterator node = points->GetFirst();
1750 if (node == wxList::compatibility_iterator())
1751 // empty list
1752 return;
0f4c3aa2 1753
e828c96a 1754 wxPoint *p = (wxPoint *)node->GetData();
0f4c3aa2 1755
e828c96a
SC
1756 wxCoord x1 = p->x;
1757 wxCoord y1 = p->y;
0f4c3aa2 1758
e828c96a
SC
1759 node = node->GetNext();
1760 p = (wxPoint *)node->GetData();
0f4c3aa2 1761
e828c96a
SC
1762 wxCoord x2 = p->x;
1763 wxCoord y2 = p->y;
1764 wxCoord cx1 = ( x1 + x2 ) / 2;
1765 wxCoord cy1 = ( y1 + y2 ) / 2;
0f4c3aa2 1766
de8e2d31
SC
1767 path->MoveToPoint( XLOG2DEVMAC( x1 ) , YLOG2DEVMAC( y1 ) ) ;
1768 path->AddLineToPoint( XLOG2DEVMAC( cx1 ) , YLOG2DEVMAC( cy1 ) ) ;
0f4c3aa2 1769
e828c96a
SC
1770#if !wxUSE_STL
1771 while ((node = node->GetNext()) != NULL)
1772#else
1773 while ((node = node->GetNext()))
1774#endif // !wxUSE_STL
1775 {
1776 p = (wxPoint *)node->GetData();
1777 x1 = x2;
1778 y1 = y2;
1779 x2 = p->x;
1780 y2 = p->y;
1781 wxCoord cx4 = (x1 + x2) / 2;
1782 wxCoord cy4 = (y1 + y2) / 2;
b21d67a0 1783
0f4c3aa2 1784 path->AddQuadCurveToPoint(
de8e2d31
SC
1785 XLOG2DEVMAC( x1 ) , YLOG2DEVMAC( y1 ) ,
1786 XLOG2DEVMAC( cx4 ) , YLOG2DEVMAC( cy4 ) ) ;
b21d67a0 1787
e828c96a
SC
1788 cx1 = cx4;
1789 cy1 = cy4;
1790 }
0f4c3aa2 1791
de8e2d31 1792 path->AddLineToPoint( XLOG2DEVMAC( x2 ) , YLOG2DEVMAC( y2 ) ) ;
0f4c3aa2 1793
e828c96a
SC
1794 m_graphicContext->StrokePath( path ) ;
1795 delete path ;
1796}
1797#endif
1798
b21d67a0 1799void wxDC::DoDrawPolygon( int n, wxPoint points[],
613a24f7
SC
1800 wxCoord xoffset, wxCoord yoffset,
1801 int fillStyle )
1802{
b21d67a0 1803 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawPolygon - invalid DC") );
75f0a06e
DS
1804
1805 if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
613a24f7 1806 return ;
08c8555e
SC
1807 if ( m_logicalFunction != wxCOPY )
1808 return ;
1809
75f0a06e 1810 wxCoord x1, x2 , y1 , y2 ;
613a24f7
SC
1811 x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1812 y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
0f4c3aa2 1813
20b69855
SC
1814 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1815 path->MoveToPoint( x1 , y1 ) ;
613a24f7
SC
1816 for (int i = 1; i < n; i++)
1817 {
1818 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1819 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1820
20b69855 1821 path->AddLineToPoint( x2 , y2 ) ;
613a24f7 1822 }
97071cdb 1823
613a24f7 1824 if ( x1 != x2 || y1 != y2 )
b21d67a0 1825 path->AddLineToPoint( x1, y1 ) ;
97071cdb 1826
20b69855
SC
1827 path->CloseSubpath() ;
1828 m_graphicContext->DrawPath( path , fillStyle ) ;
75f0a06e 1829
20b69855 1830 delete path ;
613a24f7
SC
1831}
1832
1833void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1834{
b21d67a0 1835 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawRectangle - invalid DC") );
08c8555e
SC
1836
1837 if ( m_logicalFunction != wxCOPY )
1838 return ;
1839
613a24f7
SC
1840 wxCoord xx = XLOG2DEVMAC(x);
1841 wxCoord yy = YLOG2DEVMAC(y);
1842 wxCoord ww = m_signX * XLOG2DEVREL(width);
1843 wxCoord hh = m_signY * YLOG2DEVREL(height);
75f0a06e 1844
613a24f7
SC
1845 // CMB: draw nothing if transformed w or h is 0
1846 if (ww == 0 || hh == 0)
1847 return;
97071cdb 1848
613a24f7
SC
1849 // CMB: handle -ve width and/or height
1850 if (ww < 0)
1851 {
1852 ww = -ww;
1853 xx = xx - ww;
1854 }
1855 if (hh < 0)
1856 {
1857 hh = -hh;
1858 yy = yy - hh;
1859 }
97071cdb 1860
20b69855 1861 wxGraphicPath* path = m_graphicContext->CreatePath() ;
24cd6f82 1862 path->AddRectangle( xx , yy , ww , hh ) ;
20b69855
SC
1863 m_graphicContext->DrawPath( path ) ;
1864 delete path ;
613a24f7
SC
1865}
1866
b21d67a0 1867void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
613a24f7
SC
1868 wxCoord width, wxCoord height,
1869 double radius)
1870{
b21d67a0 1871 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawRoundedRectangle - invalid DC") );
08c8555e
SC
1872
1873 if ( m_logicalFunction != wxCOPY )
1874 return ;
1875
613a24f7
SC
1876 if (radius < 0.0)
1877 radius = - radius * ((width < height) ? width : height);
1878 wxCoord xx = XLOG2DEVMAC(x);
1879 wxCoord yy = YLOG2DEVMAC(y);
1880 wxCoord ww = m_signX * XLOG2DEVREL(width);
1881 wxCoord hh = m_signY * YLOG2DEVREL(height);
75f0a06e 1882
613a24f7
SC
1883 // CMB: draw nothing if transformed w or h is 0
1884 if (ww == 0 || hh == 0)
1885 return;
97071cdb 1886
613a24f7
SC
1887 // CMB: handle -ve width and/or height
1888 if (ww < 0)
1889 {
1890 ww = -ww;
1891 xx = xx - ww;
1892 }
1893 if (hh < 0)
1894 {
1895 hh = -hh;
1896 yy = yy - hh;
1897 }
97071cdb 1898
ded83b1a
SC
1899 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1900 if ( radius == 0)
1901 {
1902 path->AddRectangle( xx , yy , ww , hh ) ;
1903 m_graphicContext->DrawPath( path ) ;
1904 }
1905 else
1906 {
1907 m_graphicContext->PushState() ;
1908 m_graphicContext->Translate( xx , yy ) ;
1909 m_graphicContext->Scale( radius , radius ) ;
1910 double fw = ww / radius ;
1911 double fh = hh / radius;
1912 path->MoveToPoint(fw, fh / 2);
1913 path->AddArcToPoint(fw, fh, fw / 2, fh, 1);
1914 path->AddArcToPoint(0, fh, 0, fh / 2, 1);
1915 path->AddArcToPoint(0, 0, fw / 2, 0, 1);
1916 path->AddArcToPoint(fw, 0, fw, fh / 2, 1);
1917 path->CloseSubpath();
1918 m_graphicContext->DrawPath( path ) ;
1919 m_graphicContext->PopState() ;
1920 }
1921 delete path ;
613a24f7
SC
1922}
1923
b21d67a0 1924void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
613a24f7 1925{
b21d67a0 1926 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawEllipse - invalid DC") );
08c8555e
SC
1927
1928 if ( m_logicalFunction != wxCOPY )
1929 return ;
1930
613a24f7
SC
1931 wxCoord xx = XLOG2DEVMAC(x);
1932 wxCoord yy = YLOG2DEVMAC(y);
1933 wxCoord ww = m_signX * XLOG2DEVREL(width);
1934 wxCoord hh = m_signY * YLOG2DEVREL(height);
0f4c3aa2 1935
613a24f7
SC
1936 // CMB: draw nothing if transformed w or h is 0
1937 if (ww == 0 || hh == 0)
1938 return;
97071cdb 1939
613a24f7
SC
1940 // CMB: handle -ve width and/or height
1941 if (ww < 0)
1942 {
1943 ww = -ww;
1944 xx = xx - ww;
1945 }
1946 if (hh < 0)
1947 {
1948 hh = -hh;
1949 yy = yy - hh;
1950 }
ded83b1a
SC
1951
1952 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1953 m_graphicContext->PushState() ;
1954 m_graphicContext->Translate(xx + ww / 2, yy + hh / 2);
1955 m_graphicContext->Scale(ww / 2 , hh / 2);
1956 path->AddArc( 0, 0, 1, 0 , 2 * M_PI , false ) ;
1957 m_graphicContext->DrawPath( path ) ;
1958 m_graphicContext->PopState() ;
1959 delete path ;
613a24f7
SC
1960}
1961
0f4c3aa2 1962bool wxDC::CanDrawBitmap() const
613a24f7
SC
1963{
1964 return true ;
1965}
1966
0f4c3aa2
DS
1967bool wxDC::DoBlit(
1968 wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1969 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1970 wxCoord xsrcMask, wxCoord ysrcMask )
613a24f7 1971{
b21d67a0
DS
1972 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::DoBlit - invalid DC") );
1973 wxCHECK_MSG( source->Ok(), false, wxT("wxDC(cg)::DoBlit - invalid source DC") );
75f0a06e 1974
613a24f7 1975 if ( logical_func == wxNO_OP )
97071cdb
DS
1976 return true ;
1977
613a24f7
SC
1978 if (xsrcMask == -1 && ysrcMask == -1)
1979 {
97071cdb
DS
1980 xsrcMask = xsrc;
1981 ysrcMask = ysrc;
613a24f7 1982 }
20b69855 1983
68654a82 1984 wxCoord yysrc = source->YLOG2DEVMAC(ysrc) ;
ec4a2b5d
DS
1985 wxCoord xxsrc = source->XLOG2DEVMAC(xsrc) ;
1986 wxCoord wwsrc = source->XLOG2DEVREL(width) ;
68654a82 1987 wxCoord hhsrc = source->YLOG2DEVREL(height) ;
0f4c3aa2 1988
68654a82
SC
1989 wxCoord yydest = YLOG2DEVMAC(ydest) ;
1990 wxCoord xxdest = XLOG2DEVMAC(xdest) ;
ec4a2b5d 1991 wxCoord wwdest = XLOG2DEVREL(width) ;
68654a82 1992 wxCoord hhdest = YLOG2DEVREL(height) ;
0f4c3aa2 1993
20b69855 1994 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
a8f234d2 1995 if ( memdc && logical_func == wxCOPY )
613a24f7 1996 {
20b69855 1997 wxBitmap blit = memdc->GetSelectedObject() ;
b21d67a0 1998
20b69855
SC
1999 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
2000
20b69855
SC
2001 wxCoord bmpwidth = blit.GetWidth();
2002 wxCoord bmpheight = blit.GetHeight();
0f4c3aa2 2003
68654a82
SC
2004 if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc )
2005 {
2006 wwsrc = wxMin( wwsrc , bmpwidth - xxsrc ) ;
2007 hhsrc = wxMin( hhsrc , bmpheight - yysrc ) ;
2008 if ( wwsrc > 0 && hhsrc > 0 )
2009 {
2010 if ( xxsrc >= 0 && yysrc >= 0 )
2011 {
2012 wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc ) ;
ded83b1a 2013 // TODO we perhaps could add a DrawSubBitmap call to dc for performance reasons
68654a82
SC
2014 blit = blit.GetSubBitmap( subrect ) ;
2015 }
2016 else
2017 {
2018 // in this case we'd probably have to adjust the different coordinates, but
2019 // we have to find out proper contract first
2020 blit = wxNullBitmap ;
2021 }
2022 }
2023 else
2024 {
2025 blit = wxNullBitmap ;
2026 }
2027 }
97071cdb 2028
68654a82 2029 if ( blit.Ok() )
613a24f7 2030 {
ded83b1a 2031 m_graphicContext->DrawBitmap( blit, xxdest , yydest , wwdest , hhdest ) ;
613a24f7 2032 }
20b69855
SC
2033 }
2034 else
2035 {
ded83b1a
SC
2036 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
2037 return false ;
613a24f7 2038 }
97071cdb
DS
2039
2040 return true;
613a24f7
SC
2041}
2042
b21d67a0 2043void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
613a24f7
SC
2044 double angle)
2045{
b21d67a0 2046 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawRotatedText - invalid DC") );
ded83b1a 2047// wxCHECK_RET( m_macATSUIStyle != NULL, wxT("wxDC(cg)::DoDrawRotatedText - no valid font set") );
613a24f7 2048
e4db172a 2049 if ( str.length() == 0 )
613a24f7 2050 return ;
08c8555e
SC
2051 if ( m_logicalFunction != wxCOPY )
2052 return ;
2053
613a24f7
SC
2054 int drawX = XLOG2DEVMAC(x) ;
2055 int drawY = YLOG2DEVMAC(y) ;
2056
ded83b1a 2057 m_graphicContext->DrawText( str, drawX ,drawY , angle ) ;
613a24f7
SC
2058}
2059
b21d67a0 2060void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
613a24f7 2061{
b21d67a0 2062 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoDrawText - invalid DC") );
75f0a06e 2063
613a24f7
SC
2064 DoDrawRotatedText( strtext , x , y , 0.0 ) ;
2065}
2066
b21d67a0 2067bool wxDC::CanGetTextExtent() const
613a24f7 2068{
b21d67a0 2069 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::CanGetTextExtent - invalid DC") );
75f0a06e 2070
613a24f7
SC
2071 return true ;
2072}
2073
b21d67a0 2074void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
613a24f7
SC
2075 wxCoord *descent, wxCoord *externalLeading ,
2076 wxFont *theFont ) const
2077{
b21d67a0 2078 wxCHECK_RET( Ok(), wxT("wxDC(cg)::DoGetTextExtent - invalid DC") );
75f0a06e 2079
613a24f7
SC
2080 wxFont formerFont = m_font ;
2081 if ( theFont )
2082 {
ded83b1a 2083 m_graphicContext->SetFont( *theFont ) ;
613a24f7
SC
2084 }
2085
ded83b1a
SC
2086 wxCoord h , d , e , w ;
2087
2088 m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ) ;
0f4c3aa2 2089
613a24f7 2090 if ( height )
ded83b1a 2091 *height = YDEV2LOGREL( h ) ;
613a24f7 2092 if ( descent )
ded83b1a 2093 *descent =YDEV2LOGREL( d);
613a24f7 2094 if ( externalLeading )
ded83b1a 2095 *externalLeading = YDEV2LOGREL( e);
613a24f7 2096 if ( width )
ded83b1a 2097 *width = XDEV2LOGREL( w ) ;
b21d67a0 2098
613a24f7
SC
2099 if ( theFont )
2100 {
ded83b1a 2101 m_graphicContext->SetFont( m_font ) ;
613a24f7
SC
2102 }
2103}
2104
613a24f7
SC
2105bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2106{
b21d67a0 2107 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::DoGetPartialTextExtents - invalid DC") );
613a24f7 2108
ded83b1a
SC
2109 m_graphicContext->GetPartialTextExtents( text, widths ) ;
2110 for ( size_t i = 0 ; i < widths.GetCount() ; ++i )
2111 widths[i] = XDEV2LOGREL( widths[i] );
764e6694 2112
764e6694 2113 return true;
613a24f7
SC
2114}
2115
b21d67a0 2116wxCoord wxDC::GetCharWidth(void) const
613a24f7
SC
2117{
2118 wxCoord width ;
b21d67a0 2119 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
75f0a06e 2120
613a24f7
SC
2121 return width ;
2122}
2123
b21d67a0 2124wxCoord wxDC::GetCharHeight(void) const
613a24f7
SC
2125{
2126 wxCoord height ;
b21d67a0 2127 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
75f0a06e 2128
613a24f7
SC
2129 return height ;
2130}
2131
b21d67a0 2132void wxDC::Clear(void)
613a24f7 2133{
b21d67a0 2134 wxCHECK_RET( Ok(), wxT("wxDC(cg)::Clear - invalid DC") );
613a24f7 2135
75f0a06e 2136 if (m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
ec4a2b5d 2137 {
b014adcc 2138 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
b60f5ca5 2139 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
b21d67a0 2140 switch ( m_backgroundBrush.MacGetBrushKind() )
613a24f7
SC
2141 {
2142 case kwxMacBrushTheme :
2143 {
a63b4755
SC
2144#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
2145 if ( HIThemeSetFill != 0 )
2146 {
72ba915e 2147 HIThemeSetFill( m_backgroundBrush.MacGetTheme(), NULL, cg, kHIThemeOrientationNormal );
a63b4755
SC
2148 CGContextFillRect(cg, rect);
2149
2150 }
2151 else
2152#endif
2153 {
75f0a06e 2154 RGBColor color;
72ba915e 2155 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme(), 32, true, &color );
bc78039c
SC
2156 CGContextSetRGBFillColor( cg, (CGFloat) color.red / 65536,
2157 (CGFloat) color.green / 65536, (CGFloat) color.blue / 65536, 1 );
97071cdb 2158 CGContextFillRect( cg, rect );
a63b4755 2159 }
72ba915e 2160
a63b4755
SC
2161 // reset to normal value
2162 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
72ba915e 2163 CGContextSetRGBFillColor( cg, col.red / 65536.0, col.green / 65536.0, col.blue / 65536.0, 1.0 );
613a24f7 2164 }
97071cdb
DS
2165 break ;
2166
613a24f7
SC
2167 case kwxMacBrushThemeBackground :
2168 {
a63b4755 2169 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
75f0a06e 2170
b014adcc 2171#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1688bb38 2172 if ( UMAGetSystemVersion() >= 0x1030 )
b014adcc
SC
2173 {
2174 HIThemeBackgroundDrawInfo drawInfo ;
2175 drawInfo.version = 0 ;
2176 drawInfo.state = kThemeStateActive ;
ec4a2b5d 2177 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground( NULL ) ;
b014adcc 2178 if ( drawInfo.kind == kThemeBackgroundMetal )
ec4a2b5d
DS
2179 {
2180 HIThemeDrawBackground( &rect, &drawInfo, cg, kHIThemeOrientationNormal ) ;
2181 HIThemeApplyBackground( &rect, &drawInfo, cg, kHIThemeOrientationNormal ) ;
2182 }
b014adcc
SC
2183 }
2184#endif
613a24f7 2185 }
97071cdb
DS
2186 break ;
2187
613a24f7 2188 case kwxMacBrushColour :
97071cdb 2189 {
ec4a2b5d
DS
2190 // FIXME: doesn't correctly render stippled brushes !!
2191 // FIXME: should this be replaced by ::SetBrush() ??
2192
97071cdb
DS
2193 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
2194 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
2195 CGContextFillRect(cg, rect);
613a24f7 2196
97071cdb
DS
2197 // reset to normal value
2198 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
2199 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
2200 }
2201 break ;
2202
75f0a06e
DS
2203 default :
2204 wxFAIL_MSG( wxT("unknown brush kind") ) ;
97071cdb 2205 break ;
613a24f7
SC
2206 }
2207 }
2208}
2209
eb1a7cf9
DS
2210#pragma mark -
2211
613a24f7
SC
2212// ---------------------------------------------------------------------------
2213// coordinates transformations
2214// ---------------------------------------------------------------------------
2215
2216wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2217{
2218 return ((wxDC *)this)->XDEV2LOG(x);
2219}
2220
2221wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2222{
2223 return ((wxDC *)this)->YDEV2LOG(y);
2224}
2225
2226wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2227{
2228 return ((wxDC *)this)->XDEV2LOGREL(x);
2229}
2230
2231wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2232{
2233 return ((wxDC *)this)->YDEV2LOGREL(y);
2234}
2235
2236wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2237{
2238 return ((wxDC *)this)->XLOG2DEV(x);
2239}
2240
2241wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2242{
2243 return ((wxDC *)this)->YLOG2DEV(y);
2244}
2245
2246wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2247{
2248 return ((wxDC *)this)->XLOG2DEVREL(x);
2249}
2250
2251wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2252{
2253 return ((wxDC *)this)->YLOG2DEVREL(y);
2254}
20b69855
SC
2255
2256#endif // wxMAC_USE_CORE_GRAPHICS