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