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