]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/graphics.cpp
document On{Open,Save}Document()
[wxWidgets.git] / src / mac / carbon / graphics.cpp
CommitLineData
50581042
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/mac/carbon/dccg.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
12#include "wx/wxprec.h"
13
83b96a06 14#include "wx/graphics.h"
a6ab887b 15#include "wx/private/graphics.h"
83b96a06 16
50581042 17#ifndef WX_PRECOMP
cc5de8fe 18 #include "wx/dcclient.h"
d9485f89 19 #include "wx/dcmemory.h"
50581042 20 #include "wx/log.h"
50581042 21 #include "wx/region.h"
6239ee05 22 #include "wx/image.h"
fb9cc37f 23 #include "wx/icon.h"
50581042
SC
24#endif
25
50581042
SC
26#ifdef __MSL__
27 #if __MSL__ >= 0x6000
28 #include "math.h"
29 // in case our functions were defined outside std, we make it known all the same
30 namespace std { }
31 using namespace std;
32 #endif
33#endif
34
5252d9e4
SC
35#ifdef __WXMAC__
36 #include "wx/mac/uma.h"
37#else
38 #include "CoreServices/CoreServices.h"
39 #include "ApplicationServices/ApplicationServices.h"
40 #include "wx/mac/corefoundation/cfstring.h"
41 #include "wx/cocoa/dcclient.h"
42#endif
43
44#ifdef __WXCOCOA__
45
46CGColorSpaceRef wxMacGetGenericRGBColorSpace()
47{
48 static wxCFRef<CGColorSpaceRef> genericRGBColorSpace;
49
50 if (genericRGBColorSpace == NULL)
51 {
52 genericRGBColorSpace.reset( CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB ) );
53 }
54
55 return genericRGBColorSpace;
56}
57
58int UMAGetSystemVersion()
59{
60 return 0x1050;
61}
62
63
64#define wxMAC_USE_CORE_TEXT 1
65
66#endif
50581042 67
eec960fa
SC
68//-----------------------------------------------------------------------------
69// constants
70//-----------------------------------------------------------------------------
71
72#if !defined( __DARWIN__ ) || defined(__MWERKS__)
73#ifndef M_PI
74const double M_PI = 3.14159265358979;
75#endif
76#endif
77
78static const double RAD2DEG = 180.0 / M_PI;
79
50581042 80//
b7b40adb 81// Pen, Brushes and Fonts
50581042
SC
82//
83
b7b40adb
SC
84#pragma mark -
85#pragma mark wxMacCoreGraphicsPattern, ImagePattern, HatchPattern classes
86
276ee533
SC
87OSStatus wxMacDrawCGImage(
88 CGContextRef inContext,
5252d9e4 89 const CGRect * inBounds,
947f3b35 90 CGImageRef inImage)
276ee533 91{
947f3b35 92#if defined( __LP64__ ) || defined(__WXCOCOA__)
276ee533
SC
93 // todo flip
94 CGContextDrawImage(inContext, *inBounds, inImage );
1bd568fa 95 return noErr;
276ee533 96#else
1bd568fa 97 return HIViewDrawCGImage( inContext, inBounds, inImage );
276ee533
SC
98#endif
99}
100
5252d9e4
SC
101CGColorRef wxMacCreateCGColor( const wxColour& col )
102{
103 CGColorRef retval = 0;
104#ifdef __WXMAC__
105 retval = col.CreateCGColor();
106#else
107// TODO add conversion NSColor - CGColorRef (obj-c)
108#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
109 if ( CGColorCreateGenericRGB )
110 retval = CGColorCreateGenericRGB( col.Red() / 255.0 , col.Green() / 255.0, col.Blue() / 255.0, col.Alpha() / 255.0 );
111 else
112#endif
113 {
947f3b35 114 CGFloat components[4] = { col.Red() / 255.0, col.Green() / 255.0, col.Blue() / 255.0, col.Alpha() / 255.0 } ;
5252d9e4
SC
115 retval = CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ;
116 }
117
118#endif
119 return retval;
120}
121
122#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && defined(wxMAC_USE_CORE_TEXT)
123
124CTFontRef wxMacCreateCTFont( const wxFont& font )
125{
126#ifdef __WXMAC__
127 return wxCFRetain((CTFontRef) font.MacGetCTFont());
128#else
129 return CTFontCreateWithName( wxCFStringRef( font.GetFaceName(), wxLocale::GetSystemEncoding() ) , font.GetPointSize() , NULL );
130#endif
131}
132
133#endif
134
b7b40adb
SC
135// CGPattern wrapper class: always allocate on heap, never call destructor
136
137class wxMacCoreGraphicsPattern
50581042 138{
50581042 139public :
b7b40adb 140 wxMacCoreGraphicsPattern() {}
50581042 141
b7b40adb
SC
142 // is guaranteed to be called only with a non-Null CGContextRef
143 virtual void Render( CGContextRef ctxRef ) = 0;
50581042 144
b7b40adb 145 operator CGPatternRef() const { return m_patternRef; }
50581042 146
b7b40adb
SC
147protected :
148 virtual ~wxMacCoreGraphicsPattern()
149 {
150 // as this is called only when the m_patternRef is been released;
151 // don't release it again
152 }
50581042 153
b7b40adb
SC
154 static void _Render( void *info, CGContextRef ctxRef )
155 {
156 wxMacCoreGraphicsPattern* self = (wxMacCoreGraphicsPattern*) info;
157 if ( self && ctxRef )
158 self->Render( ctxRef );
159 }
50581042 160
b7b40adb
SC
161 static void _Dispose( void *info )
162 {
163 wxMacCoreGraphicsPattern* self = (wxMacCoreGraphicsPattern*) info;
164 delete self;
165 }
50581042 166
b7b40adb 167 CGPatternRef m_patternRef;
50581042 168
b7b40adb
SC
169 static const CGPatternCallbacks ms_Callbacks;
170};
50581042 171
b7b40adb 172const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCoreGraphicsPattern::_Render, &wxMacCoreGraphicsPattern::_Dispose };
50581042 173
b7b40adb
SC
174class ImagePattern : public wxMacCoreGraphicsPattern
175{
176public :
177 ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform )
178 {
179 wxASSERT( bmp && bmp->Ok() );
5252d9e4 180#ifdef __WXMAC__
968c951f 181 Init( (CGImageRef) bmp->CreateCGImage() , transform );
5252d9e4 182#endif
b7b40adb 183 }
50581042 184
b7b40adb
SC
185 // ImagePattern takes ownership of CGImageRef passed in
186 ImagePattern( CGImageRef image , const CGAffineTransform& transform )
187 {
188 if ( image )
189 CFRetain( image );
190
191 Init( image , transform );
192 }
193
194 virtual void Render( CGContextRef ctxRef )
195 {
196 if (m_image != NULL)
276ee533 197 wxMacDrawCGImage( ctxRef, &m_imageBounds, m_image );
b7b40adb
SC
198 }
199
200protected :
201 void Init( CGImageRef image, const CGAffineTransform& transform )
202 {
203 m_image = image;
204 if ( m_image )
205 {
206 m_imageBounds = CGRectMake( 0.0, 0.0, (CGFloat)CGImageGetWidth( m_image ), (CGFloat)CGImageGetHeight( m_image ) );
207 m_patternRef = CGPatternCreate(
208 this , m_imageBounds, transform ,
209 m_imageBounds.size.width, m_imageBounds.size.height,
210 kCGPatternTilingNoDistortion, true , &wxMacCoreGraphicsPattern::ms_Callbacks );
211 }
212 }
213
214 virtual ~ImagePattern()
215 {
216 if ( m_image )
217 CGImageRelease( m_image );
218 }
219
220 CGImageRef m_image;
221 CGRect m_imageBounds;
222};
223
224class HatchPattern : public wxMacCoreGraphicsPattern
225{
226public :
227 HatchPattern( int hatchstyle, const CGAffineTransform& transform )
228 {
229 m_hatch = hatchstyle;
230 m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 );
231 m_patternRef = CGPatternCreate(
232 this , m_imageBounds, transform ,
233 m_imageBounds.size.width, m_imageBounds.size.height,
234 kCGPatternTilingNoDistortion, false , &wxMacCoreGraphicsPattern::ms_Callbacks );
235 }
236
237 void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
238 {
e1673e52 239 CGContextStrokeLineSegments( ctxRef , pts , count );
b7b40adb
SC
240 }
241
242 virtual void Render( CGContextRef ctxRef )
243 {
244 switch ( m_hatch )
245 {
246 case wxBDIAGONAL_HATCH :
247 {
248 CGPoint pts[] =
249 {
250 { 8.0 , 0.0 } , { 0.0 , 8.0 }
251 };
252 StrokeLineSegments( ctxRef , pts , 2 );
253 }
254 break;
255
256 case wxCROSSDIAG_HATCH :
257 {
258 CGPoint pts[] =
259 {
260 { 0.0 , 0.0 } , { 8.0 , 8.0 } ,
261 { 8.0 , 0.0 } , { 0.0 , 8.0 }
262 };
263 StrokeLineSegments( ctxRef , pts , 4 );
264 }
265 break;
266
267 case wxFDIAGONAL_HATCH :
268 {
269 CGPoint pts[] =
270 {
271 { 0.0 , 0.0 } , { 8.0 , 8.0 }
272 };
273 StrokeLineSegments( ctxRef , pts , 2 );
274 }
275 break;
276
277 case wxCROSS_HATCH :
278 {
279 CGPoint pts[] =
280 {
281 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
282 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
283 };
284 StrokeLineSegments( ctxRef , pts , 4 );
285 }
286 break;
287
288 case wxHORIZONTAL_HATCH :
289 {
290 CGPoint pts[] =
291 {
292 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
293 };
294 StrokeLineSegments( ctxRef , pts , 2 );
295 }
296 break;
297
298 case wxVERTICAL_HATCH :
299 {
300 CGPoint pts[] =
301 {
302 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
303 };
304 StrokeLineSegments( ctxRef , pts , 2 );
305 }
306 break;
307
308 default:
309 break;
310 }
311 }
312
313protected :
314 virtual ~HatchPattern() {}
315
316 CGRect m_imageBounds;
317 int m_hatch;
318};
319
a26b7ab2 320class wxMacCoreGraphicsPenData : public wxGraphicsObjectRefData
b7b40adb
SC
321{
322public:
a26b7ab2
SC
323 wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
324 ~wxMacCoreGraphicsPenData();
783d8bdf 325
b7b40adb
SC
326 void Init();
327 virtual void Apply( wxGraphicsContext* context );
328 virtual wxDouble GetWidth() { return m_width; }
783d8bdf 329
b7b40adb
SC
330protected :
331 CGLineCap m_cap;
7a7697aa
SC
332 wxCFRef<CGColorRef> m_color;
333 wxCFRef<CGColorSpaceRef> m_colorSpace;
b7b40adb
SC
334
335 CGLineJoin m_join;
336 CGFloat m_width;
783d8bdf 337
b7b40adb
SC
338 int m_count;
339 const CGFloat *m_lengths;
340 CGFloat *m_userLengths;
eec960fa 341
b7b40adb
SC
342
343 bool m_isPattern;
7a7697aa 344 wxCFRef<CGPatternRef> m_pattern;
b7b40adb 345 CGFloat* m_patternColorComponents;
50581042
SC
346};
347
a26b7ab2
SC
348wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) :
349 wxGraphicsObjectRefData( renderer )
50581042 350{
b7b40adb 351 Init();
783d8bdf 352
5252d9e4 353 m_color.reset( wxMacCreateCGColor( pen.GetColour() ) ) ;
b7b40adb
SC
354
355 // TODO: * m_dc->m_scaleX
356 m_width = pen.GetWidth();
357 if (m_width <= 0.0)
358 m_width = 0.1;
359
360 switch ( pen.GetCap() )
361 {
362 case wxCAP_ROUND :
363 m_cap = kCGLineCapRound;
364 break;
365
366 case wxCAP_PROJECTING :
367 m_cap = kCGLineCapSquare;
368 break;
369
370 case wxCAP_BUTT :
371 m_cap = kCGLineCapButt;
372 break;
373
374 default :
375 m_cap = kCGLineCapButt;
376 break;
377 }
378
379 switch ( pen.GetJoin() )
380 {
381 case wxJOIN_BEVEL :
382 m_join = kCGLineJoinBevel;
383 break;
384
385 case wxJOIN_MITER :
386 m_join = kCGLineJoinMiter;
387 break;
388
389 case wxJOIN_ROUND :
390 m_join = kCGLineJoinRound;
391 break;
392
393 default :
394 m_join = kCGLineJoinMiter;
395 break;
396 }
397
398 const CGFloat dashUnit = m_width < 1.0 ? 1.0 : m_width;
399
400 const CGFloat dotted[] = { dashUnit , dashUnit + 2.0 };
401 static const CGFloat short_dashed[] = { 9.0 , 6.0 };
402 static const CGFloat dashed[] = { 19.0 , 9.0 };
403 static const CGFloat dotted_dashed[] = { 9.0 , 6.0 , 3.0 , 3.0 };
404
405 switch ( pen.GetStyle() )
406 {
407 case wxSOLID :
408 break;
409
410 case wxDOT :
411 m_count = WXSIZEOF(dotted);
412 m_userLengths = new CGFloat[ m_count ] ;
413 memcpy( m_userLengths, dotted, sizeof(dotted) );
414 m_lengths = m_userLengths;
415 break;
416
417 case wxLONG_DASH :
418 m_count = WXSIZEOF(dashed);
419 m_lengths = dashed;
420 break;
421
422 case wxSHORT_DASH :
423 m_count = WXSIZEOF(short_dashed);
424 m_lengths = short_dashed;
425 break;
426
427 case wxDOT_DASH :
428 m_count = WXSIZEOF(dotted_dashed);
429 m_lengths = dotted_dashed;
430 break;
431
432 case wxUSER_DASH :
433 wxDash *dashes;
434 m_count = pen.GetDashes( &dashes );
435 if ((dashes != NULL) && (m_count > 0))
436 {
437 m_userLengths = new CGFloat[m_count];
438 for ( int i = 0; i < m_count; ++i )
439 {
440 m_userLengths[i] = dashes[i] * dashUnit;
441
442 if ( i % 2 == 1 && m_userLengths[i] < dashUnit + 2.0 )
443 m_userLengths[i] = dashUnit + 2.0;
444 else if ( i % 2 == 0 && m_userLengths[i] < dashUnit )
445 m_userLengths[i] = dashUnit;
446 }
447 }
448 m_lengths = m_userLengths;
449 break;
450
451 case wxSTIPPLE :
452 {
453 wxBitmap* bmp = pen.GetStipple();
454 if ( bmp && bmp->Ok() )
455 {
7a7697aa
SC
456 m_colorSpace.reset( CGColorSpaceCreatePattern( NULL ) );
457 m_pattern.reset( (CGPatternRef) *( new ImagePattern( bmp , CGAffineTransformMakeScale( 1,-1 ) ) ) );
b7b40adb
SC
458 m_patternColorComponents = new CGFloat[1] ;
459 m_patternColorComponents[0] = 1.0;
460 m_isPattern = true;
461 }
462 }
463 break;
464
465 default :
466 {
467 m_isPattern = true;
7a7697aa
SC
468 m_colorSpace.reset( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
469 m_pattern.reset( (CGPatternRef) *( new HatchPattern( pen.GetStyle() , CGAffineTransformMakeScale( 1,-1 ) ) ) );
b7b40adb
SC
470 m_patternColorComponents = new CGFloat[4] ;
471 m_patternColorComponents[0] = pen.GetColour().Red() / 255.0;
472 m_patternColorComponents[1] = pen.GetColour().Green() / 255.0;
473 m_patternColorComponents[2] = pen.GetColour().Blue() / 255.0;
474 m_patternColorComponents[3] = pen.GetColour().Alpha() / 255.0;
475 }
476 break;
477 }
478 if ((m_lengths != NULL) && (m_count > 0))
479 {
480 // force the line cap, otherwise we get artifacts (overlaps) and just solid lines
481 m_cap = kCGLineCapButt;
482 }
50581042
SC
483}
484
a26b7ab2 485wxMacCoreGraphicsPenData::~wxMacCoreGraphicsPenData()
50581042 486{
b7b40adb
SC
487 delete[] m_userLengths;
488 delete[] m_patternColorComponents;
50581042
SC
489}
490
a26b7ab2 491void wxMacCoreGraphicsPenData::Init()
50581042 492{
b7b40adb
SC
493 m_lengths = NULL;
494 m_userLengths = NULL;
783d8bdf 495 m_width = 0;
b7b40adb
SC
496 m_count = 0;
497 m_patternColorComponents = NULL;
498 m_isPattern = false;
50581042
SC
499}
500
a26b7ab2 501void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context )
50581042 502{
b7b40adb
SC
503 CGContextRef cg = (CGContextRef) context->GetNativeContext();
504 CGContextSetLineWidth( cg , m_width );
505 CGContextSetLineJoin( cg , m_join );
506
507 CGContextSetLineDash( cg , 0 , m_lengths , m_count );
508 CGContextSetLineCap( cg , m_cap );
509
510 if ( m_isPattern )
511 {
74b357dd
SC
512 CGAffineTransform matrix = CGContextGetCTM( cg );
513 CGContextSetPatternPhase( cg, CGSizeMake(matrix.tx, matrix.ty) );
b7b40adb
SC
514 CGContextSetStrokeColorSpace( cg , m_colorSpace );
515 CGContextSetStrokePattern( cg, m_pattern , m_patternColorComponents );
516 }
517 else
518 {
277ccdaf
SC
519 if ( context->GetLogicalFunction() == wxINVERT || context->GetLogicalFunction() == wxXOR )
520 {
521 CGContextSetRGBStrokeColor( cg , 1.0, 1.0 , 1.0, 1.0 );
522 }
523 else
524 CGContextSetStrokeColorWithColor( cg , m_color );
b7b40adb 525 }
50581042
SC
526}
527
b7b40adb
SC
528//
529// Brush
530//
531
6239ee05
SC
532static const char *gs_stripedback_xpm[] = {
533/* columns rows colors chars-per-pixel */
534"4 4 2 1",
535". c #F0F0F0",
536"X c #ECECEC",
537/* pixels */
538"....",
539"....",
540"XXXX",
541"XXXX"
b7b40adb
SC
542};
543
6239ee05
SC
544wxBitmap gs_stripedback_bmp( wxImage( (const char* const* ) gs_stripedback_xpm ), -1 ) ;
545
a01d9a25
SC
546// make sure we all use one class for all conversions from wx to native colour
547
548class wxMacCoreGraphicsColour
549{
550 public:
551 wxMacCoreGraphicsColour();
552 wxMacCoreGraphicsColour(const wxBrush &brush);
553 ~wxMacCoreGraphicsColour();
947f3b35 554
a01d9a25
SC
555 void Apply( CGContextRef cgContext );
556 protected:
557 void Init();
7a7697aa
SC
558 wxCFRef<CGColorRef> m_color;
559 wxCFRef<CGColorSpaceRef> m_colorSpace;
947f3b35 560
a01d9a25 561 bool m_isPattern;
7a7697aa 562 wxCFRef<CGPatternRef> m_pattern;
a01d9a25
SC
563 CGFloat* m_patternColorComponents;
564} ;
565
6239ee05 566wxMacCoreGraphicsColour::~wxMacCoreGraphicsColour()
50581042 567{
6239ee05 568 delete[] m_patternColorComponents;
50581042
SC
569}
570
6239ee05 571void wxMacCoreGraphicsColour::Init()
50581042 572{
6239ee05
SC
573 m_isPattern = false;
574 m_patternColorComponents = NULL;
b7b40adb 575}
783d8bdf 576
6239ee05 577void wxMacCoreGraphicsColour::Apply( CGContextRef cgContext )
b7b40adb 578{
6239ee05
SC
579 if ( m_isPattern )
580 {
581 CGAffineTransform matrix = CGContextGetCTM( cgContext );
582 CGContextSetPatternPhase( cgContext, CGSizeMake(matrix.tx, matrix.ty) );
583 CGContextSetFillColorSpace( cgContext , m_colorSpace );
584 CGContextSetFillPattern( cgContext, m_pattern , m_patternColorComponents );
585 }
586 else
587 {
588 CGContextSetFillColorWithColor( cgContext, m_color );
589 }
b7b40adb 590}
783d8bdf 591
947f3b35 592wxMacCoreGraphicsColour::wxMacCoreGraphicsColour()
b7b40adb
SC
593{
594 Init();
6239ee05 595}
783d8bdf 596
6239ee05
SC
597wxMacCoreGraphicsColour::wxMacCoreGraphicsColour( const wxBrush &brush )
598{
599 Init();
b7b40adb
SC
600 if ( brush.GetStyle() == wxSOLID )
601 {
5252d9e4 602 m_color.reset( wxMacCreateCGColor( brush.GetColour() ));
b7b40adb
SC
603 }
604 else if ( brush.IsHatch() )
605 {
606 m_isPattern = true;
7a7697aa
SC
607 m_colorSpace.reset( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
608 m_pattern.reset( (CGPatternRef) *( new HatchPattern( brush.GetStyle() , CGAffineTransformMakeScale( 1,-1 ) ) ) );
b7b40adb
SC
609
610 m_patternColorComponents = new CGFloat[4] ;
611 m_patternColorComponents[0] = brush.GetColour().Red() / 255.0;
612 m_patternColorComponents[1] = brush.GetColour().Green() / 255.0;
613 m_patternColorComponents[2] = brush.GetColour().Blue() / 255.0;
614 m_patternColorComponents[3] = brush.GetColour().Alpha() / 255.0;
615 }
616 else
617 {
618 // now brush is a bitmap
619 wxBitmap* bmp = brush.GetStipple();
620 if ( bmp && bmp->Ok() )
621 {
783d8bdf 622 m_isPattern = true;
b7b40adb
SC
623 m_patternColorComponents = new CGFloat[1] ;
624 m_patternColorComponents[0] = 1.0;
7a7697aa
SC
625 m_colorSpace.reset( CGColorSpaceCreatePattern( NULL ) );
626 m_pattern.reset( (CGPatternRef) *( new ImagePattern( bmp , CGAffineTransformMakeScale( 1,-1 ) ) ) );
b7b40adb
SC
627 }
628 }
50581042
SC
629}
630
6239ee05
SC
631class wxMacCoreGraphicsBrushData : public wxGraphicsObjectRefData
632{
633public:
634 wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer );
635 wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
636 ~wxMacCoreGraphicsBrushData ();
637
638 virtual void Apply( wxGraphicsContext* context );
639 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
640 const wxColour&c1, const wxColour&c2 );
641 void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
642 const wxColour &oColor, const wxColour &cColor );
643
644 virtual bool IsShading() { return m_isShading; }
645 CGShadingRef GetShading() { return m_shading; }
646protected:
647 CGFunctionRef CreateGradientFunction( const wxColour& c1, const wxColour& c2 );
648 static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out);
649 virtual void Init();
650
651 wxMacCoreGraphicsColour m_cgColor;
652
653 bool m_isShading;
654 CGFunctionRef m_gradientFunction;
655 CGShadingRef m_shading;
656 CGFloat *m_gradientComponents;
657};
658
659wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer )
660{
661 Init();
662}
663
664void wxMacCoreGraphicsBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
665 const wxColour&c1, const wxColour&c2 )
666{
667 m_gradientFunction = CreateGradientFunction( c1, c2 );
668 m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), CGPointMake(x1,y1), CGPointMake(x2,y2), m_gradientFunction, true, true ) ;
669 m_isShading = true ;
670}
671
672void wxMacCoreGraphicsBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
673 const wxColour &oColor, const wxColour &cColor )
674{
675 m_gradientFunction = CreateGradientFunction( oColor, cColor );
676 m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake(xo,yo), 0, CGPointMake(xc,yc), radius, m_gradientFunction, true, true ) ;
677 m_isShading = true ;
678}
679
680wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : wxGraphicsObjectRefData( renderer ),
681 m_cgColor( brush )
682{
683 Init();
684
685}
686
a26b7ab2 687wxMacCoreGraphicsBrushData::~wxMacCoreGraphicsBrushData()
50581042 688{
b7b40adb
SC
689 if ( m_shading )
690 CGShadingRelease(m_shading);
783d8bdf 691
b7b40adb
SC
692 if( m_gradientFunction )
693 CGFunctionRelease(m_gradientFunction);
783d8bdf 694
b7b40adb 695 delete[] m_gradientComponents;
50581042
SC
696}
697
a26b7ab2 698void wxMacCoreGraphicsBrushData::Init()
50581042 699{
b7b40adb
SC
700 m_gradientFunction = NULL;
701 m_shading = NULL;
b7b40adb
SC
702 m_gradientComponents = NULL;
703 m_isShading = false;
50581042
SC
704}
705
a26b7ab2 706void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context )
50581042 707{
b7b40adb 708 CGContextRef cg = (CGContextRef) context->GetNativeContext();
783d8bdf 709
b7b40adb 710 if ( m_isShading )
783d8bdf 711 {
74b357dd 712 // nothing to set as shades are processed by clipping using the path and filling
b7b40adb
SC
713 }
714 else
715 {
6239ee05 716 m_cgColor.Apply( cg );
b7b40adb 717 }
50581042
SC
718}
719
a26b7ab2 720void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)
50581042 721{
b7b40adb
SC
722 CGFloat* colors = (CGFloat*) info ;
723 CGFloat f = *in;
724 for( int i = 0 ; i < 4 ; ++i )
725 {
726 out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f;
727 }
50581042
SC
728}
729
a26b7ab2 730CGFunctionRef wxMacCoreGraphicsBrushData::CreateGradientFunction( const wxColour& c1, const wxColour& c2 )
50581042 731{
b7b40adb
SC
732 static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL };
733 static const CGFloat input_value_range [2] = { 0, 1 };
734 static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
735 m_gradientComponents = new CGFloat[8] ;
736 m_gradientComponents[0] = c1.Red() / 255.0;
737 m_gradientComponents[1] = c1.Green() / 255.0;
738 m_gradientComponents[2] = c1.Blue() / 255.0;
739 m_gradientComponents[3] = c1.Alpha() / 255.0;
740 m_gradientComponents[4] = c2.Red() / 255.0;
741 m_gradientComponents[5] = c2.Green() / 255.0;
742 m_gradientComponents[6] = c2.Blue() / 255.0;
743 m_gradientComponents[7] = c2.Alpha() / 255.0;
744
783d8bdf
VZ
745 return CGFunctionCreate ( m_gradientComponents, 1,
746 input_value_range,
747 4,
b7b40adb 748 output_value_ranges,
783d8bdf 749 &callbacks);
50581042
SC
750}
751
752//
b7b40adb 753// Font
50581042
SC
754//
755
a26b7ab2 756class wxMacCoreGraphicsFontData : public wxGraphicsObjectRefData
50581042 757{
50581042 758public:
a26b7ab2
SC
759 wxMacCoreGraphicsFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
760 ~wxMacCoreGraphicsFontData();
783d8bdf 761
c07e1e2c 762#if wxMAC_USE_ATSU_TEXT
b7b40adb 763 virtual ATSUStyle GetATSUStyle() { return m_macATSUIStyle; }
c07e1e2c
SC
764#endif
765#if wxMAC_USE_CORE_TEXT
766 CTFontRef GetCTFont() const { return m_ctFont ; }
767#endif
768 wxColour GetColour() const { return m_colour ; }
947f3b35 769
c07e1e2c 770 bool GetUnderlined() const { return m_underlined ; }
b7b40adb 771private :
c07e1e2c
SC
772 wxColour m_colour;
773 bool m_underlined;
774#if wxMAC_USE_ATSU_TEXT
b7b40adb 775 ATSUStyle m_macATSUIStyle;
c07e1e2c
SC
776#endif
777#if wxMAC_USE_CORE_TEXT
778 wxCFRef< CTFontRef > m_ctFont;
779#endif
b7b40adb 780};
50581042 781
a26b7ab2 782wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col) : wxGraphicsObjectRefData( renderer )
b7b40adb 783{
c07e1e2c
SC
784 m_colour = col;
785 m_underlined = font.GetUnderlined();
783d8bdf 786
d2d8b4db 787#if wxMAC_USE_CORE_TEXT
5252d9e4 788 m_ctFont.reset( wxMacCreateCTFont( font ) );
c07e1e2c
SC
789#endif
790#if wxMAC_USE_ATSU_TEXT
e773889d
SC
791 OSStatus status = noErr;
792 m_macATSUIStyle = NULL;
50581042 793
b7b40adb 794 status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , &m_macATSUIStyle );
50581042 795
b7b40adb 796 wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") );
50581042 797
b7b40adb 798 // we need the scale here ...
50581042 799
b7b40adb 800 Fixed atsuSize = IntToFixed( int( 1 * font.MacGetFontSize()) );
276ee533
SC
801 RGBColor atsuColor ;
802 col.GetRGBColor( &atsuColor );
b7b40adb
SC
803 ATSUAttributeTag atsuTags[] =
804 {
805 kATSUSizeTag ,
806 kATSUColorTag ,
807 };
808 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
809 {
810 sizeof( Fixed ) ,
811 sizeof( RGBColor ) ,
812 };
813 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
814 {
815 &atsuSize ,
816 &atsuColor ,
817 };
50581042 818
b7b40adb
SC
819 status = ::ATSUSetAttributes(
820 m_macATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) ,
821 atsuTags, atsuSizes, atsuValues);
50581042 822
b7b40adb 823 wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") );
c07e1e2c 824#endif
0fa6a0ac 825#if wxMAC_USE_CG_TEXT
1bd568fa 826#endif
b7b40adb 827}
50581042 828
a26b7ab2 829wxMacCoreGraphicsFontData::~wxMacCoreGraphicsFontData()
b7b40adb 830{
d2d8b4db 831#if wxMAC_USE_CORE_TEXT
c07e1e2c
SC
832#endif
833#if wxMAC_USE_ATSU_TEXT
b7b40adb
SC
834 if ( m_macATSUIStyle )
835 {
836 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
837 m_macATSUIStyle = NULL;
838 }
c07e1e2c 839#endif
0fa6a0ac 840#if wxMAC_USE_CG_TEXT
1bd568fa 841#endif
b7b40adb 842}
50581042 843
5252d9e4
SC
844class wxMacCoreGraphicsBitmapData : public wxGraphicsObjectRefData
845{
846public:
847 wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap );
848 ~wxMacCoreGraphicsBitmapData();
849
850 virtual CGImageRef GetBitmap() { return m_bitmap; }
851private :
852 CGImageRef m_bitmap;
853};
854
855wxMacCoreGraphicsBitmapData::wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap ) : wxGraphicsObjectRefData( renderer )
856{
857 m_bitmap = bitmap;
858}
859
860wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData()
861{
862 CGImageRelease( m_bitmap );
863}
864
b7b40adb
SC
865//
866// Graphics Matrix
867//
50581042 868
b7b40adb
SC
869//-----------------------------------------------------------------------------
870// wxMacCoreGraphicsMatrix declaration
871//-----------------------------------------------------------------------------
50581042 872
e3ff3591 873class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData
b7b40adb
SC
874{
875public :
783d8bdf
VZ
876 wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) ;
877
878 virtual ~wxMacCoreGraphicsMatrixData() ;
879
e3ff3591 880 virtual wxGraphicsObjectRefData *Clone() const ;
b7b40adb 881
783d8bdf
VZ
882 // concatenates the matrix
883 virtual void Concat( const wxGraphicsMatrixData *t );
884
885 // sets the matrix to the respective values
886 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
887 wxDouble tx=0.0, wxDouble ty=0.0);
888
248802d0
RD
889 // gets the component valuess of the matrix
890 virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL,
891 wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
947f3b35 892
783d8bdf
VZ
893 // makes this the inverse matrix
894 virtual void Invert();
895
896 // returns true if the elements of the transformation matrix are equal ?
e3ff3591 897 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
783d8bdf
VZ
898
899 // return true if this is the identity matrix
900 virtual bool IsIdentity() const;
901
50581042 902 //
b7b40adb 903 // transformation
50581042 904 //
783d8bdf 905
b7b40adb
SC
906 // add the translation to this matrix
907 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 908
b7b40adb
SC
909 // add the scale to this matrix
910 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 911
b7b40adb 912 // add the rotation to this matrix (radians)
783d8bdf
VZ
913 virtual void Rotate( wxDouble angle );
914
50581042 915 //
b7b40adb 916 // apply the transforms
50581042 917 //
783d8bdf
VZ
918
919 // applies that matrix to the point
920 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
921
922 // applies the matrix except for translations
923 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
924
925 // returns the native representation
926 virtual void * GetNativeMatrix() const;
927
b7b40adb
SC
928private :
929 CGAffineTransform m_matrix;
b7b40adb 930} ;
50581042 931
50581042 932//-----------------------------------------------------------------------------
b7b40adb 933// wxMacCoreGraphicsMatrix implementation
50581042
SC
934//-----------------------------------------------------------------------------
935
e3ff3591 936wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
b7b40adb 937{
b7b40adb 938}
eec960fa 939
783d8bdf 940wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData()
50581042 941{
50581042
SC
942}
943
783d8bdf 944wxGraphicsObjectRefData *wxMacCoreGraphicsMatrixData::Clone() const
50581042 945{
e3ff3591 946 wxMacCoreGraphicsMatrixData* m = new wxMacCoreGraphicsMatrixData(GetRenderer()) ;
b7b40adb
SC
947 m->m_matrix = m_matrix ;
948 return m;
949}
950
951// concatenates the matrix
783d8bdf 952void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t )
b7b40adb
SC
953{
954 m_matrix = CGAffineTransformConcat(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()) );
955}
956
b7b40adb 957// sets the matrix to the respective values
783d8bdf
VZ
958void wxMacCoreGraphicsMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
959 wxDouble tx, wxDouble ty)
b7b40adb
SC
960{
961 m_matrix = CGAffineTransformMake(a,b,c,d,tx,ty);
50581042
SC
962}
963
248802d0
RD
964// gets the component valuess of the matrix
965void wxMacCoreGraphicsMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c,
966 wxDouble* d, wxDouble* tx, wxDouble* ty) const
967{
968 if (a) *a = m_matrix.a;
969 if (b) *b = m_matrix.b;
970 if (c) *c = m_matrix.c;
971 if (d) *d = m_matrix.d;
972 if (tx) *tx= m_matrix.tx;
973 if (ty) *ty= m_matrix.ty;
974}
975
b7b40adb 976// makes this the inverse matrix
783d8bdf 977void wxMacCoreGraphicsMatrixData::Invert()
1056ddcf 978{
b7b40adb 979 m_matrix = CGAffineTransformInvert( m_matrix );
eec960fa
SC
980}
981
b7b40adb 982// returns true if the elements of the transformation matrix are equal ?
783d8bdf 983bool wxMacCoreGraphicsMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
eec960fa 984{
e1673e52 985 return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()));
1056ddcf
SC
986}
987
b7b40adb 988// return true if this is the identity matrix
e3ff3591 989bool wxMacCoreGraphicsMatrixData::IsIdentity() const
50581042 990{
2701ef7e
SC
991 return ( m_matrix.a == 1 && m_matrix.d == 1 &&
992 m_matrix.b == 0 && m_matrix.d == 0 && m_matrix.tx == 0 && m_matrix.ty == 0);
50581042
SC
993}
994
b7b40adb
SC
995//
996// transformation
997//
998
999// add the translation to this matrix
783d8bdf 1000void wxMacCoreGraphicsMatrixData::Translate( wxDouble dx , wxDouble dy )
50581042 1001{
b7b40adb
SC
1002 m_matrix = CGAffineTransformTranslate( m_matrix, dx, dy);
1003}
50581042 1004
b7b40adb 1005// add the scale to this matrix
783d8bdf 1006void wxMacCoreGraphicsMatrixData::Scale( wxDouble xScale , wxDouble yScale )
b7b40adb
SC
1007{
1008 m_matrix = CGAffineTransformScale( m_matrix, xScale, yScale);
50581042
SC
1009}
1010
b7b40adb 1011// add the rotation to this matrix (radians)
783d8bdf 1012void wxMacCoreGraphicsMatrixData::Rotate( wxDouble angle )
eec960fa 1013{
b7b40adb 1014 m_matrix = CGAffineTransformRotate( m_matrix, angle);
eec960fa
SC
1015}
1016
b7b40adb
SC
1017//
1018// apply the transforms
1019//
eec960fa 1020
b7b40adb 1021// applies that matrix to the point
e3ff3591 1022void wxMacCoreGraphicsMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
50581042 1023{
2701ef7e 1024 CGPoint pt = CGPointApplyAffineTransform( CGPointMake(*x,*y), m_matrix);
783d8bdf 1025
2701ef7e
SC
1026 *x = pt.x;
1027 *y = pt.y;
1056ddcf
SC
1028}
1029
b7b40adb 1030// applies the matrix except for translations
e3ff3591 1031void wxMacCoreGraphicsMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
1056ddcf 1032{
2701ef7e
SC
1033 CGSize sz = CGSizeApplyAffineTransform( CGSizeMake(*dx,*dy) , m_matrix );
1034 *dx = sz.width;
1035 *dy = sz.height;
b7b40adb
SC
1036}
1037
1038// returns the native representation
783d8bdf 1039void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const
1056ddcf 1040{
b7b40adb 1041 return (void*) &m_matrix;
50581042
SC
1042}
1043
b7b40adb
SC
1044//
1045// Graphics Path
1046//
1047
1048//-----------------------------------------------------------------------------
1049// wxMacCoreGraphicsPath declaration
1050//-----------------------------------------------------------------------------
1051
e3ff3591 1052class WXDLLEXPORT wxMacCoreGraphicsPathData : public wxGraphicsPathData
50581042 1053{
b7b40adb 1054public :
e3ff3591 1055 wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path = NULL);
783d8bdf 1056
e3ff3591 1057 ~wxMacCoreGraphicsPathData();
1056ddcf 1058
e3ff3591 1059 virtual wxGraphicsObjectRefData *Clone() const;
1056ddcf 1060
b7b40adb
SC
1061 // begins a new subpath at (x,y)
1062 virtual void MoveToPoint( wxDouble x, wxDouble y );
1056ddcf 1063
783d8bdf 1064 // adds a straight line from the current point to (x,y)
b7b40adb
SC
1065 virtual void AddLineToPoint( wxDouble x, wxDouble y );
1066
1067 // adds a cubic Bezier curve from the current point, using two control points and an end point
1068 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
1069
1070 // closes the current sub-path
1071 virtual void CloseSubpath();
1072
1073 // gets the last point of the current path, (0,0) if not yet set
e3ff3591 1074 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
b7b40adb
SC
1075
1076 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
1077 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise );
1078
1079 //
783d8bdf 1080 // These are convenience functions which - if not available natively will be assembled
b7b40adb
SC
1081 // using the primitives from above
1082 //
1083
1084 // adds a quadratic Bezier curve from the current point, using a control point and an end point
1085 virtual void AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y );
1086
783d8bdf 1087 // appends a rectangle as a new closed subpath
b7b40adb
SC
1088 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
1089
1090 // appends an ellipsis as a new closed subpath fitting the passed rectangle
1091 virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r );
1092
1093 // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
1094 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
1095
783d8bdf
VZ
1096 // adds another path
1097 virtual void AddPath( const wxGraphicsPathData* path );
1098
1099 // returns the native path
1100 virtual void * GetNativePath() const { return m_path; }
1101
1102 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
89954433 1103 virtual void UnGetNativePath(void *WXUNUSED(p)) const {}
783d8bdf
VZ
1104
1105 // transforms each point of this path by the matrix
1106 virtual void Transform( const wxGraphicsMatrixData* matrix );
1107
1108 // gets the bounding box enclosing all points (possibly including control points)
1109 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *y) const;
1110
1111 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const;
b7b40adb
SC
1112private :
1113 CGMutablePathRef m_path;
1114};
1115
1116//-----------------------------------------------------------------------------
1117// wxMacCoreGraphicsPath implementation
1118//-----------------------------------------------------------------------------
1119
e3ff3591 1120wxMacCoreGraphicsPathData::wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPathData(renderer)
b7b40adb 1121{
783d8bdf
VZ
1122 if ( path )
1123 m_path = path;
1124 else
1125 m_path = CGPathCreateMutable();
50581042
SC
1126}
1127
e3ff3591 1128wxMacCoreGraphicsPathData::~wxMacCoreGraphicsPathData()
50581042 1129{
b7b40adb
SC
1130 CGPathRelease( m_path );
1131}
50581042 1132
783d8bdf 1133wxGraphicsObjectRefData* wxMacCoreGraphicsPathData::Clone() const
b7b40adb 1134{
783d8bdf
VZ
1135 wxMacCoreGraphicsPathData* clone = new wxMacCoreGraphicsPathData(GetRenderer(),CGPathCreateMutableCopy(m_path));
1136 return clone ;
b7b40adb 1137}
1056ddcf 1138
1056ddcf 1139
b7b40adb 1140// opens (starts) a new subpath
e3ff3591 1141void wxMacCoreGraphicsPathData::MoveToPoint( wxDouble x1 , wxDouble y1 )
b7b40adb
SC
1142{
1143 CGPathMoveToPoint( m_path , NULL , x1 , y1 );
1144}
1056ddcf 1145
e3ff3591 1146void wxMacCoreGraphicsPathData::AddLineToPoint( wxDouble x1 , wxDouble y1 )
b7b40adb
SC
1147{
1148 CGPathAddLineToPoint( m_path , NULL , x1 , y1 );
50581042
SC
1149}
1150
e3ff3591 1151void wxMacCoreGraphicsPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
50581042 1152{
b7b40adb 1153 CGPathAddCurveToPoint( m_path , NULL , cx1 , cy1 , cx2, cy2, x , y );
50581042
SC
1154}
1155
e3ff3591 1156void wxMacCoreGraphicsPathData::AddQuadCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble x, wxDouble y )
50581042 1157{
b7b40adb 1158 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x , y );
50581042
SC
1159}
1160
e3ff3591 1161void wxMacCoreGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
50581042 1162{
b7b40adb
SC
1163 CGRect cgRect = { { x , y } , { w , h } };
1164 CGPathAddRect( m_path , NULL , cgRect );
1165}
50581042 1166
e3ff3591 1167void wxMacCoreGraphicsPathData::AddCircle( wxDouble x, wxDouble y , wxDouble r )
b7b40adb
SC
1168{
1169 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true );
50581042
SC
1170}
1171
b7b40adb 1172// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
e3ff3591 1173void wxMacCoreGraphicsPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise )
50581042 1174{
b7b40adb 1175 // inverse direction as we the 'normal' state is a y axis pointing down, ie mirrored to the standard core graphics setup
783d8bdf 1176 CGPathAddArc( m_path, NULL , x, y, r, startAngle, endAngle, !clockwise);
50581042
SC
1177}
1178
e3ff3591 1179void wxMacCoreGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
50581042 1180{
783d8bdf 1181 CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
50581042
SC
1182}
1183
e3ff3591 1184void wxMacCoreGraphicsPathData::AddPath( const wxGraphicsPathData* path )
50581042 1185{
783d8bdf 1186 CGPathAddPath( m_path , NULL, (CGPathRef) path->GetNativePath() );
50581042
SC
1187}
1188
b7b40adb 1189// closes the current subpath
e3ff3591 1190void wxMacCoreGraphicsPathData::CloseSubpath()
50581042 1191{
b7b40adb 1192 CGPathCloseSubpath( m_path );
50581042
SC
1193}
1194
b7b40adb 1195// gets the last point of the current path, (0,0) if not yet set
e3ff3591 1196void wxMacCoreGraphicsPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
50581042 1197{
b7b40adb 1198 CGPoint p = CGPathGetCurrentPoint( m_path );
e3ff3591
SC
1199 *x = p.x;
1200 *y = p.y;
50581042
SC
1201}
1202
b7b40adb 1203// transforms each point of this path by the matrix
e3ff3591 1204void wxMacCoreGraphicsPathData::Transform( const wxGraphicsMatrixData* matrix )
50581042 1205{
783d8bdf
VZ
1206 CGMutablePathRef p = CGPathCreateMutable() ;
1207 CGPathAddPath( p, (CGAffineTransform*) matrix->GetNativeMatrix() , m_path );
1208 CGPathRelease( m_path );
1209 m_path = p;
50581042
SC
1210}
1211
b7b40adb 1212// gets the bounding box enclosing all points (possibly including control points)
e3ff3591 1213void wxMacCoreGraphicsPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
50581042 1214{
783d8bdf
VZ
1215 CGRect bounds = CGPathGetBoundingBox( m_path ) ;
1216 *x = bounds.origin.x;
1217 *y = bounds.origin.y;
1218 *w = bounds.size.width;
1219 *h = bounds.size.height;
50581042
SC
1220}
1221
e3ff3591 1222bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, int fillStyle) const
50581042 1223{
e1673e52 1224 return CGPathContainsPoint( m_path, NULL, CGPointMake(x,y), fillStyle == wxODDEVEN_RULE );
50581042
SC
1225}
1226
b7b40adb
SC
1227//
1228// Graphics Context
1229//
50581042 1230
b7b40adb
SC
1231//-----------------------------------------------------------------------------
1232// wxMacCoreGraphicsContext declaration
1233//-----------------------------------------------------------------------------
1234
1235class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
1236{
1237public:
6239ee05 1238 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width = 0, wxDouble height = 0 );
783d8bdf 1239
b7b40adb 1240 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window );
783d8bdf 1241
b7b40adb 1242 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window );
783d8bdf 1243
b7b40adb 1244 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer);
783d8bdf 1245
b7b40adb 1246 wxMacCoreGraphicsContext();
783d8bdf 1247
b7b40adb 1248 ~wxMacCoreGraphicsContext();
50581042 1249
783d8bdf 1250 void Init();
50581042 1251
6239ee05
SC
1252 // returns the size of the graphics context in device coordinates
1253 virtual void GetSize( wxDouble* width, wxDouble* height);
1254
1255 virtual void StartPage( wxDouble width, wxDouble height );
947f3b35 1256
6239ee05
SC
1257 virtual void EndPage();
1258
1259 virtual void Flush();
1260
b7b40adb
SC
1261 // push the current state of the context, ie the transformation matrix on a stack
1262 virtual void PushState();
50581042 1263
b7b40adb
SC
1264 // pops a stored state from the stack
1265 virtual void PopState();
50581042 1266
b7b40adb
SC
1267 // clips drawings to the region
1268 virtual void Clip( const wxRegion &region );
50581042 1269
b7b40adb
SC
1270 // clips drawings to the rect
1271 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
783d8bdf 1272
b7b40adb
SC
1273 // resets the clipping to original extent
1274 virtual void ResetClip();
50581042 1275
b7b40adb 1276 virtual void * GetNativeContext();
783d8bdf 1277
277ccdaf 1278 bool SetLogicalFunction( int function );
b7b40adb
SC
1279 //
1280 // transformation
1281 //
783d8bdf 1282
b7b40adb
SC
1283 // translate
1284 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 1285
b7b40adb
SC
1286 // scale
1287 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 1288
b7b40adb
SC
1289 // rotate (radians)
1290 virtual void Rotate( wxDouble angle );
50581042 1291
783d8bdf
VZ
1292 // concatenates this transform with the current transform of this context
1293 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
50581042 1294
783d8bdf
VZ
1295 // sets the transform of this context
1296 virtual void SetTransform( const wxGraphicsMatrix& matrix );
50581042 1297
783d8bdf
VZ
1298 // gets the matrix of this context
1299 virtual wxGraphicsMatrix GetTransform() const;
b7b40adb
SC
1300 //
1301 // setting the paint
1302 //
783d8bdf 1303
b7b40adb 1304 // strokes along a path with the current pen
e3ff3591 1305 virtual void StrokePath( const wxGraphicsPath &path );
50581042 1306
b7b40adb 1307 // fills a path with the current brush
e3ff3591 1308 virtual void FillPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE );
50581042 1309
b7b40adb 1310 // draws a path by first filling and then stroking
e3ff3591 1311 virtual void DrawPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE );
b7b40adb
SC
1312
1313 virtual bool ShouldOffset() const
947f3b35 1314 {
b7b40adb 1315 int penwidth = 0 ;
a26b7ab2 1316 if ( !m_pen.IsNull() )
50581042 1317 {
783d8bdf 1318 penwidth = (int)((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->GetWidth();
b7b40adb
SC
1319 if ( penwidth == 0 )
1320 penwidth = 1;
50581042 1321 }
783d8bdf 1322 return ( penwidth % 2 ) == 1;
50581042 1323 }
b7b40adb
SC
1324 //
1325 // text
1326 //
783d8bdf 1327
b7b40adb 1328 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y );
50581042 1329
b7b40adb 1330 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
50581042 1331
b7b40adb
SC
1332 virtual void GetTextExtent( const wxString &text, wxDouble *width, wxDouble *height,
1333 wxDouble *descent, wxDouble *externalLeading ) const;
50581042 1334
b7b40adb 1335 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
50581042 1336
b7b40adb
SC
1337 //
1338 // image support
1339 //
50581042 1340
b7b40adb 1341 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1342
5252d9e4
SC
1343 virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
1344
b7b40adb 1345 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1346
b7b40adb 1347 void SetNativeContext( CGContextRef cg );
783d8bdf 1348
b7b40adb
SC
1349 DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
1350 DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
50581042 1351
b7b40adb
SC
1352private:
1353 void EnsureIsValid();
783d8bdf 1354
b7b40adb 1355 CGContextRef m_cgContext;
783d8bdf
VZ
1356 WindowRef m_windowRef;
1357 bool m_releaseContext;
549be226 1358 CGAffineTransform m_windowTransform;
6239ee05
SC
1359 wxDouble m_width;
1360 wxDouble m_height;
783d8bdf 1361
7a7697aa 1362 wxCFRef<HIShapeRef> m_clipRgn;
50581042
SC
1363};
1364
b7b40adb
SC
1365//-----------------------------------------------------------------------------
1366// device context implementation
1367//
1368// more and more of the dc functionality should be implemented by calling
1369// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step
1370// also coordinate conversions should be moved to native matrix ops
1371//-----------------------------------------------------------------------------
50581042 1372
b7b40adb
SC
1373// we always stock two context states, one at entry, to be able to preserve the
1374// state we were called with, the other one after changing to HI Graphics orientation
1375// (this one is used for getting back clippings etc)
50581042 1376
b7b40adb
SC
1377//-----------------------------------------------------------------------------
1378// wxMacCoreGraphicsContext implementation
1379//-----------------------------------------------------------------------------
50581042 1380
b7b40adb 1381IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
50581042 1382
6239ee05
SC
1383class wxQuartzOffsetHelper
1384{
1385public :
1386 wxQuartzOffsetHelper( CGContextRef cg , bool offset )
1387 {
1388 m_cg = cg;
1389 m_offset = offset;
1390 if ( m_offset )
1391 CGContextTranslateCTM( m_cg, 0.5, 0.5 );
1392 }
1393 ~wxQuartzOffsetHelper( )
1394 {
1395 if ( m_offset )
1396 CGContextTranslateCTM( m_cg, -0.5, -0.5 );
1397 }
1398public :
1399 CGContextRef m_cg;
1400 bool m_offset;
1401} ;
1402
b7b40adb
SC
1403void wxMacCoreGraphicsContext::Init()
1404{
1405 m_cgContext = NULL;
783d8bdf 1406 m_releaseContext = false;
b7b40adb 1407 m_windowRef = NULL;
6239ee05
SC
1408 m_width = 0;
1409 m_height = 0;
5252d9e4 1410 CGRect r = CGRectMake(0,0,0,0);
7a7697aa 1411 m_clipRgn.reset(HIShapeCreateWithRect(&r));
b7b40adb 1412}
50581042 1413
6239ee05 1414wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer)
b7b40adb 1415{
783d8bdf 1416 Init();
549be226 1417 SetNativeContext(cgcontext);
6239ee05
SC
1418 m_width = width;
1419 m_height = height;
b7b40adb 1420}
50581042 1421
b7b40adb
SC
1422wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer)
1423{
783d8bdf
VZ
1424 Init();
1425 m_windowRef = window;
b7b40adb 1426}
50581042 1427
b7b40adb
SC
1428wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ): wxGraphicsContext(renderer)
1429{
783d8bdf 1430 Init();
5252d9e4 1431
549be226
SC
1432 int originX , originY;
1433 originX = originY = 0;
549be226 1434
1bd568fa 1435 Rect bounds = { 0,0,0,0 };
5252d9e4 1436#if defined( __LP64__ ) || defined(__WXCOCOA__)
1bd568fa 1437#else
5252d9e4
SC
1438 m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
1439 window->MacWindowToRootWindow( &originX , &originY );
1bd568fa
SC
1440 GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
1441#endif
549be226
SC
1442 m_windowTransform = CGAffineTransformMakeTranslation( 0 , bounds.bottom - bounds.top );
1443 m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 );
1444 m_windowTransform = CGAffineTransformTranslate( m_windowTransform, originX, originY ) ;
b7b40adb 1445}
50581042 1446
b7b40adb
SC
1447wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
1448{
783d8bdf 1449 Init();
b7b40adb 1450}
50581042 1451
b7b40adb
SC
1452wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
1453{
783d8bdf 1454 Init();
b7b40adb
SC
1455 wxLogDebug(wxT("Illegal Constructor called"));
1456}
50581042 1457
b7b40adb
SC
1458wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
1459{
549be226 1460 SetNativeContext(NULL);
b7b40adb 1461}
50581042 1462
6239ee05
SC
1463void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height)
1464{
1465 *width = m_width;
1466 *height = m_height;
1467}
1468
1469
1470void wxMacCoreGraphicsContext::StartPage( wxDouble width, wxDouble height )
1471{
1472 CGRect r;
1473 if ( width != 0 && height != 0)
1474 r = CGRectMake( 0 , 0 , width , height );
1475 else
1476 r = CGRectMake( 0 , 0 , m_width , m_height );
947f3b35 1477
6239ee05
SC
1478 CGContextBeginPage(m_cgContext, &r );
1479// CGContextTranslateCTM( m_cgContext , 0 , height == 0 ? m_height : height );
1480// CGContextScaleCTM( m_cgContext , 1 , -1 );
1481}
947f3b35 1482
6239ee05
SC
1483void wxMacCoreGraphicsContext::EndPage()
1484{
1485 CGContextEndPage(m_cgContext);
1486}
1487
1488void wxMacCoreGraphicsContext::Flush()
1489{
1490 CGContextFlush(m_cgContext);
1491}
1492
b7b40adb
SC
1493void wxMacCoreGraphicsContext::EnsureIsValid()
1494{
783d8bdf
VZ
1495 if ( !m_cgContext )
1496 {
947f3b35 1497 OSStatus status =
5252d9e4 1498#if ! ( defined( __LP64__ ) || defined(__WXCOCOA__) )
6239ee05
SC
1499 QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
1500#else
1501 paramErr;
1502#endif
947f3b35
VZ
1503 if ( status != noErr )
1504 {
1505 wxFAIL_MSG("Cannot nest wxDCs on the same window");
1506 }
549be226
SC
1507
1508 CGContextConcatCTM( m_cgContext, m_windowTransform );
947f3b35
VZ
1509 CGContextSaveGState( m_cgContext );
1510 m_releaseContext = true;
1511 if ( !HIShapeIsEmpty(m_clipRgn) )
1512 {
1acf0e5c 1513 // the clip region is in device coordinates, so we convert this again to user coordinates
7a7697aa 1514 wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
1acf0e5c
SC
1515 CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
1516 HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
947f3b35
VZ
1517 HIShapeReplacePathInCGContext( hishape, m_cgContext );
1518 CGContextClip( m_cgContext );
1519 }
1520 CGContextSaveGState( m_cgContext );
1521 }
b7b40adb 1522}
50581042 1523
6239ee05
SC
1524// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes)
1525
277ccdaf
SC
1526bool wxMacCoreGraphicsContext::SetLogicalFunction( int function )
1527{
1528 if (m_logicalFunction == function)
1529 return true;
1530
1531 EnsureIsValid();
947f3b35 1532
277ccdaf 1533 bool retval = false;
dbe4a80c
SC
1534 bool shouldAntiAlias = true;
1535 CGBlendMode mode = kCGBlendModeNormal;
947f3b35 1536
5252d9e4 1537#if defined(__WXMAC__) && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 )
dbe4a80c 1538 if ( UMAGetSystemVersion() >= 0x1050 )
277ccdaf
SC
1539 {
1540 retval = true;
dbe4a80c
SC
1541 switch ( function )
1542 {
1543 // TODO find best corresponding porter duff modes
1544 case wxCOPY :
1545 mode = kCGBlendModeCopy;
1546 break;
1547 case wxCLEAR :
1548 mode = kCGBlendModeClear;
1549 break;
1550 case wxXOR :
1551 mode = kCGBlendModeXOR;
1552 shouldAntiAlias = false;
947f3b35 1553 break;
dbe4a80c
SC
1554 default :
1555 retval = false;
1556 break;
1557 }
277ccdaf 1558 }
dbe4a80c
SC
1559 else
1560#endif
277ccdaf 1561 {
dbe4a80c
SC
1562 if ( function == wxCOPY )
1563 {
1564 retval = true;
1565 }
1566 else if ( function == wxINVERT || function == wxXOR )
1567 {
1568 // change color to white
1569 mode = kCGBlendModeExclusion;
1570 shouldAntiAlias = false;
1571 retval = true;
1572 }
277ccdaf 1573 }
947f3b35 1574
277ccdaf 1575 if (retval)
dbe4a80c 1576 {
277ccdaf 1577 m_logicalFunction = function;
dbe4a80c
SC
1578 CGContextSetBlendMode( m_cgContext, mode );
1579 CGContextSetShouldAntialias(m_cgContext, shouldAntiAlias);
1580 }
277ccdaf
SC
1581 return retval ;
1582}
50581042 1583
b7b40adb
SC
1584void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
1585{
5252d9e4 1586#ifdef __WXMAC__
783d8bdf
VZ
1587 if( m_cgContext )
1588 {
82c126e5 1589 HIShapeReplacePathInCGContext( region.GetWXHRGN() , m_cgContext );
783d8bdf 1590 CGContextClip( m_cgContext );
783d8bdf
VZ
1591 }
1592 else
1593 {
1acf0e5c
SC
1594 // this offsetting to device coords is not really correct, but since we cannot apply affine transforms
1595 // to regions we try at least to have correct translations
82c126e5 1596 HIMutableShapeRef mutableShape = HIShapeCreateMutableCopy( region.GetWXHRGN() );
947f3b35 1597
1acf0e5c
SC
1598 CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero, m_windowTransform );
1599 HIShapeOffset( mutableShape, transformedOrigin.x, transformedOrigin.y );
7a7697aa 1600 m_clipRgn.reset(mutableShape);
783d8bdf 1601 }
5252d9e4 1602#endif
b7b40adb 1603}
50581042 1604
b7b40adb
SC
1605// clips drawings to the rect
1606void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1607{
5252d9e4 1608 CGRect r = CGRectMake( x , y , w , h );
783d8bdf
VZ
1609 if ( m_cgContext )
1610 {
1611 CGContextClipToRect( m_cgContext, r );
1612 }
1613 else
1614 {
947f3b35 1615 // the clipping itself must be stored as device coordinates, otherwise
1acf0e5c
SC
1616 // we cannot apply it back correctly
1617 r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform );
7a7697aa 1618 m_clipRgn.reset(HIShapeCreateWithRect(&r));
783d8bdf
VZ
1619 }
1620}
1621
1622 // resets the clipping to original extent
b7b40adb
SC
1623void wxMacCoreGraphicsContext::ResetClip()
1624{
783d8bdf
VZ
1625 if ( m_cgContext )
1626 {
a7868cdf
SC
1627 // there is no way for clearing the clip, we can only revert to the stored
1628 // state, but then we have to make sure everything else is NOT restored
1629 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
783d8bdf
VZ
1630 CGContextRestoreGState( m_cgContext );
1631 CGContextSaveGState( m_cgContext );
a7868cdf
SC
1632 CGAffineTransform transformNew = CGContextGetCTM( m_cgContext );
1633 transformNew = CGAffineTransformInvert( transformNew ) ;
1634 CGContextConcatCTM( m_cgContext, transformNew);
1635 CGContextConcatCTM( m_cgContext, transform);
783d8bdf
VZ
1636 }
1637 else
1638 {
5252d9e4 1639 CGRect r = CGRectMake(0,0,0,0);
7a7697aa 1640 m_clipRgn.reset(HIShapeCreateWithRect(&r));
783d8bdf 1641 }
b7b40adb 1642}
50581042 1643
e3ff3591 1644void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
b7b40adb 1645{
a26b7ab2 1646 if ( m_pen.IsNull() )
b7b40adb 1647 return ;
50581042 1648
783d8bdf
VZ
1649 EnsureIsValid();
1650
6239ee05 1651 wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
50581042 1652
a26b7ab2 1653 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
e3ff3591 1654 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1655 CGContextStrokePath( m_cgContext );
b7b40adb 1656}
50581042 1657
e3ff3591 1658void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillStyle )
783d8bdf 1659{
a26b7ab2 1660 if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1661 {
1662 // when using shading, we cannot draw pen and brush at the same time
1663 // revert to the base implementation of first filling and then stroking
1664 wxGraphicsContext::DrawPath( path, fillStyle );
1665 return;
1666 }
783d8bdf 1667
b7b40adb 1668 CGPathDrawingMode mode = kCGPathFill ;
a26b7ab2 1669 if ( m_brush.IsNull() )
b7b40adb 1670 {
a26b7ab2 1671 if ( m_pen.IsNull() )
b7b40adb
SC
1672 return;
1673 else
1674 mode = kCGPathStroke;
1675 }
1676 else
1677 {
a26b7ab2 1678 if ( m_pen.IsNull() )
b7b40adb
SC
1679 {
1680 if ( fillStyle == wxODDEVEN_RULE )
1681 mode = kCGPathEOFill;
1682 else
1683 mode = kCGPathFill;
1684 }
1685 else
1686 {
1687 if ( fillStyle == wxODDEVEN_RULE )
1688 mode = kCGPathEOFillStroke;
1689 else
1690 mode = kCGPathFillStroke;
1691 }
1692 }
783d8bdf
VZ
1693
1694 EnsureIsValid();
50581042 1695
a26b7ab2
SC
1696 if ( !m_brush.IsNull() )
1697 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1698 if ( !m_pen.IsNull() )
1699 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
50581042 1700
6239ee05 1701 wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
50581042 1702
e3ff3591 1703 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1704 CGContextDrawPath( m_cgContext , mode );
b7b40adb 1705}
50581042 1706
e3ff3591 1707void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , int fillStyle )
b7b40adb 1708{
a26b7ab2 1709 if ( m_brush.IsNull() )
b7b40adb 1710 return;
783d8bdf
VZ
1711
1712 EnsureIsValid();
1713
a26b7ab2 1714 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1715 {
1716 CGContextSaveGState( m_cgContext );
e3ff3591 1717 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1718 CGContextClip( m_cgContext );
a26b7ab2 1719 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
b7b40adb
SC
1720 CGContextRestoreGState( m_cgContext);
1721 }
1722 else
783d8bdf 1723 {
a26b7ab2 1724 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
e3ff3591 1725 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb
SC
1726 if ( fillStyle == wxODDEVEN_RULE )
1727 CGContextEOFillPath( m_cgContext );
1728 else
1729 CGContextFillPath( m_cgContext );
50581042
SC
1730 }
1731}
1732
b7b40adb 1733void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
50581042 1734{
b7b40adb
SC
1735 // we allow either setting or clearing but not replacing
1736 wxASSERT( m_cgContext == NULL || cg == NULL );
50581042 1737
549be226
SC
1738 if ( m_cgContext )
1739 {
1740 // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
1741 CGContextRestoreGState( m_cgContext );
1742 CGContextRestoreGState( m_cgContext );
1743 if ( m_releaseContext )
6239ee05 1744 {
5252d9e4 1745#if ! ( defined( __LP64__ ) || defined(__WXCOCOA__) )
549be226 1746 QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
6239ee05
SC
1747#endif
1748 }
549be226
SC
1749 else
1750 CGContextRelease(m_cgContext);
1751 }
1752
1753
b7b40adb 1754 m_cgContext = cg;
549be226
SC
1755
1756 // FIXME: This check is needed because currently we need to use a DC/GraphicsContext
783d8bdf 1757 // in order to get font properties, like wxFont::GetPixelSize, but since we don't have
549be226
SC
1758 // a native window attached to use, I create a wxGraphicsContext with a NULL CGContextRef
1759 // for this one operation.
783d8bdf 1760
549be226 1761 // When wxFont::GetPixelSize on Mac no longer needs a graphics context, this check
783d8bdf 1762 // can be removed.
549be226
SC
1763 if (m_cgContext)
1764 {
1765 CGContextRetain(m_cgContext);
1766 CGContextSaveGState( m_cgContext );
5252d9e4 1767 CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity );
549be226 1768 CGContextSaveGState( m_cgContext );
783d8bdf 1769 m_releaseContext = false;
549be226 1770 }
b7b40adb 1771}
50581042 1772
783d8bdf 1773void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy )
b7b40adb 1774{
783d8bdf 1775 if ( m_cgContext )
549be226
SC
1776 CGContextTranslateCTM( m_cgContext, dx, dy );
1777 else
1778 m_windowTransform = CGAffineTransformTranslate(m_windowTransform,dx,dy);
b7b40adb 1779}
50581042 1780
b7b40adb
SC
1781void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
1782{
783d8bdf 1783 if ( m_cgContext )
549be226
SC
1784 CGContextScaleCTM( m_cgContext , xScale , yScale );
1785 else
1786 m_windowTransform = CGAffineTransformScale(m_windowTransform,xScale,yScale);
b7b40adb 1787}
50581042 1788
b7b40adb
SC
1789void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
1790{
783d8bdf 1791 if ( m_cgContext )
549be226
SC
1792 CGContextRotateCTM( m_cgContext , angle );
1793 else
1794 m_windowTransform = CGAffineTransformRotate(m_windowTransform,angle);
b7b40adb 1795}
50581042 1796
783d8bdf 1797void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
b7b40adb 1798{
5252d9e4
SC
1799 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
1800 DrawBitmap(bitmap, x, y, w, h);
1801}
783d8bdf 1802
5252d9e4
SC
1803void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1804{
1805 EnsureIsValid();
1806#ifdef __WXMAC__
1807 CGImageRef image = static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData())->GetBitmap();
1808 CGRect r = CGRectMake( x , y , w , h );
1809 // if ( bmp.GetDepth() == 1 )
5f547a58
SC
1810 {
1811 // is is a mask, the '1' in the mask tell where to draw the current brush
1812 if ( !m_brush.IsNull() )
1813 {
1814 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
1815 {
1816 // TODO clip to mask
1817 /*
1818 CGContextSaveGState( m_cgContext );
1819 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1820 CGContextClip( m_cgContext );
1821 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
1822 CGContextRestoreGState( m_cgContext);
1823 */
1824 }
1825 else
1826 {
1827 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
276ee533 1828 wxMacDrawCGImage( m_cgContext , &r , image );
5f547a58
SC
1829 }
1830 }
1831 }
5252d9e4 1832 /*
5f547a58
SC
1833 else
1834 {
276ee533 1835 wxMacDrawCGImage( m_cgContext , &r , image );
5f547a58 1836 }
b7b40adb 1837 CGImageRelease( image );
5252d9e4
SC
1838 */
1839#endif
b7b40adb 1840}
50581042 1841
783d8bdf 1842void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
b7b40adb 1843{
783d8bdf
VZ
1844 EnsureIsValid();
1845
b7b40adb
SC
1846 CGRect r = CGRectMake( 00 , 00 , w , h );
1847 CGContextSaveGState( m_cgContext );
1848 CGContextTranslateCTM( m_cgContext, x , y + h );
1849 CGContextScaleCTM( m_cgContext, 1, -1 );
5252d9e4 1850#ifdef __WXMAC__
b7b40adb
SC
1851 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
1852 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
5252d9e4 1853#endif
b7b40adb
SC
1854 CGContextRestoreGState( m_cgContext );
1855}
50581042 1856
b7b40adb
SC
1857void wxMacCoreGraphicsContext::PushState()
1858{
783d8bdf
VZ
1859 EnsureIsValid();
1860
b7b40adb
SC
1861 CGContextSaveGState( m_cgContext );
1862}
50581042 1863
783d8bdf 1864void wxMacCoreGraphicsContext::PopState()
b7b40adb 1865{
783d8bdf
VZ
1866 EnsureIsValid();
1867
b7b40adb 1868 CGContextRestoreGState( m_cgContext );
50581042
SC
1869}
1870
783d8bdf 1871void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
50581042 1872{
1bd568fa
SC
1873 if ( m_font.IsNull() )
1874 return;
947f3b35 1875
1bd568fa 1876 EnsureIsValid();
d2d8b4db 1877#if wxMAC_USE_CORE_TEXT
c07e1e2c
SC
1878 if ( UMAGetSystemVersion() >= 0x1050 )
1879 {
1880 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
dbe4a80c 1881 wxCFStringRef text(str, wxLocale::GetSystemEncoding() );
c07e1e2c 1882 CTFontRef font = fref->GetCTFont();
5252d9e4 1883 CGColorRef col = wxMacCreateCGColor( fref->GetColour() );
c07e1e2c 1884 CTUnderlineStyle ustyle = fref->GetUnderlined() ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone ;
947f3b35 1885 wxCFRef<CFNumberRef> underlined( CFNumberCreate(NULL, kCFNumberSInt32Type, &ustyle) );
a6ab887b 1886 CFStringRef keys[] = { kCTFontAttributeName , kCTForegroundColorAttributeName, kCTUnderlineStyleAttributeName };
c07e1e2c 1887 CFTypeRef values[] = { font, col, underlined };
947f3b35 1888 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
c07e1e2c
SC
1889 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
1890 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
1891 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
947f3b35 1892
c07e1e2c 1893 y += CTFontGetAscent(font);
947f3b35 1894
c07e1e2c
SC
1895 CGContextSaveGState(m_cgContext);
1896 CGContextTranslateCTM(m_cgContext, x, y);
1897 CGContextScaleCTM(m_cgContext, 1, -1);
1898 CGContextSetTextPosition(m_cgContext, 0, 0);
1899 CTLineDraw( line, m_cgContext );
1900 CGContextRestoreGState(m_cgContext);
5252d9e4 1901 CFRelease( col );
c07e1e2c
SC
1902 return;
1903 }
1904#endif
1905#if wxMAC_USE_ATSU_TEXT
1906 {
1907 DrawText(str, x, y, 0.0);
1908 return;
1909 }
1910#endif
0fa6a0ac 1911#if wxMAC_USE_CG_TEXT
1bd568fa
SC
1912 // TODO core graphics text implementation here
1913#endif
50581042
SC
1914}
1915
783d8bdf 1916void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
50581042 1917{
a26b7ab2 1918 if ( m_font.IsNull() )
b7b40adb 1919 return;
783d8bdf
VZ
1920
1921 EnsureIsValid();
d2d8b4db 1922#if wxMAC_USE_CORE_TEXT
c07e1e2c
SC
1923 if ( UMAGetSystemVersion() >= 0x1050 )
1924 {
1925 // default implementation takes care of rotation and calls non rotated DrawText afterwards
1926 wxGraphicsContext::DrawText( str, x, y, angle );
1927 return;
1928 }
1929#endif
1930#if wxMAC_USE_ATSU_TEXT
1931 {
1932 OSStatus status = noErr;
1933 ATSUTextLayout atsuLayout;
dbe4a80c
SC
1934 wxMacUniCharBuffer unibuf( str );
1935 UniCharCount chars = unibuf.GetChars();
1936
c07e1e2c 1937 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
dbe4a80c 1938 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
c07e1e2c 1939 &chars , &style , &atsuLayout );
947f3b35 1940
c07e1e2c 1941 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
947f3b35 1942
c07e1e2c
SC
1943 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
1944 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
947f3b35 1945
c07e1e2c
SC
1946 int iAngle = int( angle * RAD2DEG );
1947 if ( abs(iAngle) > 0 )
50581042 1948 {
c07e1e2c
SC
1949 Fixed atsuAngle = IntToFixed( iAngle );
1950 ATSUAttributeTag atsuTags[] =
1951 {
1952 kATSULineRotationTag ,
1953 };
1954 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1955 {
1956 sizeof( Fixed ) ,
1957 };
1958 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1959 {
1960 &atsuAngle ,
1961 };
1962 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1963 atsuTags, atsuSizes, atsuValues );
1964 }
947f3b35 1965
50581042 1966 {
c07e1e2c
SC
1967 ATSUAttributeTag atsuTags[] =
1968 {
1969 kATSUCGContextTag ,
1970 };
1971 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1972 {
1973 sizeof( CGContextRef ) ,
1974 };
1975 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1976 {
1977 &m_cgContext ,
1978 };
1979 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1980 atsuTags, atsuSizes, atsuValues );
1981 }
947f3b35 1982
c07e1e2c
SC
1983 ATSUTextMeasurement textBefore, textAfter;
1984 ATSUTextMeasurement ascent, descent;
947f3b35 1985
c07e1e2c
SC
1986 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1987 &textBefore , &textAfter, &ascent , &descent );
947f3b35 1988
c07e1e2c 1989 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
947f3b35 1990
c07e1e2c
SC
1991 Rect rect;
1992 x += (int)(sin(angle) * FixedToInt(ascent));
1993 y += (int)(cos(angle) * FixedToInt(ascent));
947f3b35 1994
c07e1e2c
SC
1995 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1996 IntToFixed(x) , IntToFixed(y) , &rect );
1997 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
947f3b35 1998
c07e1e2c
SC
1999 CGContextSaveGState(m_cgContext);
2000 CGContextTranslateCTM(m_cgContext, x, y);
2001 CGContextScaleCTM(m_cgContext, 1, -1);
2002 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
2003 IntToFixed(0) , IntToFixed(0) );
947f3b35 2004
c07e1e2c 2005 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
947f3b35 2006
c07e1e2c 2007 CGContextRestoreGState(m_cgContext);
947f3b35 2008
c07e1e2c 2009 ::ATSUDisposeTextLayout(atsuLayout);
947f3b35 2010
c07e1e2c
SC
2011 return;
2012 }
2013#endif
0fa6a0ac 2014#if wxMAC_USE_CG_TEXT
1bd568fa
SC
2015 // default implementation takes care of rotation and calls non rotated DrawText afterwards
2016 wxGraphicsContext::DrawText( str, x, y, angle );
2017#endif
50581042 2018}
783d8bdf 2019
50581042
SC
2020void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
2021 wxDouble *descent, wxDouble *externalLeading ) const
2022{
a26b7ab2 2023 wxCHECK_RET( !m_font.IsNull(), wxT("wxDC(cg)::DoGetTextExtent - no valid font set") );
50581042 2024
6239ee05
SC
2025 if ( width )
2026 *width = 0;
2027 if ( height )
2028 *height = 0;
2029 if ( descent )
2030 *descent = 0;
2031 if ( externalLeading )
2032 *externalLeading = 0;
947f3b35 2033
6239ee05
SC
2034 if (str.empty())
2035 return;
2036
d2d8b4db 2037#if wxMAC_USE_CORE_TEXT
c07e1e2c
SC
2038 if ( UMAGetSystemVersion() >= 0x1050 )
2039 {
2040 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
2041 CTFontRef font = fref->GetCTFont();
2042
dbe4a80c 2043 wxCFStringRef text(str, wxLocale::GetSystemEncoding() );
c07e1e2c
SC
2044 CFStringRef keys[] = { kCTFontAttributeName };
2045 CFTypeRef values[] = { font };
947f3b35 2046 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
c07e1e2c
SC
2047 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
2048 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
2049 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
947f3b35 2050
c07e1e2c 2051 CGFloat w, a, d, l;
947f3b35 2052
c07e1e2c 2053 w = CTLineGetTypographicBounds(line, &a, &d, &l) ;
947f3b35 2054
c07e1e2c
SC
2055 if ( height )
2056 *height = a+d+l;
2057 if ( descent )
2058 *descent = d;
2059 if ( externalLeading )
2060 *externalLeading = l;
2061 if ( width )
2062 *width = w;
2063 return;
2064 }
2065#endif
2066#if wxMAC_USE_ATSU_TEXT
2067 {
2068 OSStatus status = noErr;
947f3b35 2069
c07e1e2c 2070 ATSUTextLayout atsuLayout;
dbe4a80c
SC
2071 wxMacUniCharBuffer unibuf( str );
2072 UniCharCount chars = unibuf.GetChars();
947f3b35 2073
c07e1e2c 2074 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
dbe4a80c 2075 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
c07e1e2c 2076 &chars , &style , &atsuLayout );
947f3b35 2077
c07e1e2c 2078 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
947f3b35 2079
eb61203f
SC
2080 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
2081 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
2082
c07e1e2c
SC
2083 ATSUTextMeasurement textBefore, textAfter;
2084 ATSUTextMeasurement textAscent, textDescent;
947f3b35 2085
c07e1e2c
SC
2086 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
2087 &textBefore , &textAfter, &textAscent , &textDescent );
947f3b35 2088
c07e1e2c
SC
2089 if ( height )
2090 *height = FixedToInt(textAscent + textDescent);
2091 if ( descent )
2092 *descent = FixedToInt(textDescent);
2093 if ( externalLeading )
2094 *externalLeading = 0;
2095 if ( width )
2096 *width = FixedToInt(textAfter - textBefore);
947f3b35 2097
c07e1e2c 2098 ::ATSUDisposeTextLayout(atsuLayout);
dbe4a80c 2099
c07e1e2c
SC
2100 return;
2101 }
b9d495a0 2102#endif
0fa6a0ac 2103#if wxMAC_USE_CG_TEXT
1bd568fa
SC
2104 // TODO core graphics text implementation here
2105#endif
50581042
SC
2106}
2107
783d8bdf 2108void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
50581042
SC
2109{
2110 widths.Empty();
2111 widths.Add(0, text.length());
2112
2113 if (text.empty())
2114 return;
2115
d2d8b4db 2116#if wxMAC_USE_CORE_TEXT
c07e1e2c
SC
2117 {
2118 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
2119 CTFontRef font = fref->GetCTFont();
947f3b35 2120
dbe4a80c 2121 wxCFStringRef t(text, wxLocale::GetSystemEncoding() );
c07e1e2c
SC
2122 CFStringRef keys[] = { kCTFontAttributeName };
2123 CFTypeRef values[] = { font };
947f3b35 2124 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
c07e1e2c
SC
2125 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
2126 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, t, attributes) );
2127 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
947f3b35 2128
c07e1e2c
SC
2129 int chars = text.length();
2130 for ( int pos = 0; pos < (int)chars; pos ++ )
2131 {
2132 widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL )+0.5;
2133 }
947f3b35 2134
c07e1e2c
SC
2135 return;
2136 }
2137#endif
2138#if wxMAC_USE_ATSU_TEXT
2139 {
eb61203f 2140 OSStatus status = noErr;
c07e1e2c 2141 ATSUTextLayout atsuLayout;
dbe4a80c
SC
2142 wxMacUniCharBuffer unibuf( text );
2143 UniCharCount chars = unibuf.GetChars();
947f3b35 2144
c07e1e2c 2145 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
eb61203f 2146 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
c07e1e2c 2147 &chars , &style , &atsuLayout );
947f3b35 2148
eb61203f 2149 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
947f3b35 2150
eb61203f
SC
2151 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
2152 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
2153
c07e1e2c
SC
2154 for ( int pos = 0; pos < (int)chars; pos ++ )
2155 {
2156 unsigned long actualNumberOfBounds = 0;
2157 ATSTrapezoid glyphBounds;
947f3b35 2158
c07e1e2c
SC
2159 // We get a single bound, since the text should only require one. If it requires more, there is an issue
2160 OSStatus result;
2161 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
2162 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
2163 if (result != noErr || actualNumberOfBounds != 1 )
2164 return;
947f3b35 2165
c07e1e2c
SC
2166 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
2167 //unsigned char uch = s[i];
2168 }
947f3b35 2169
c07e1e2c 2170 ::ATSUDisposeTextLayout(atsuLayout);
c07e1e2c 2171 }
b9d495a0 2172#endif
0fa6a0ac 2173#if wxMAC_USE_CG_TEXT
1bd568fa
SC
2174 // TODO core graphics text implementation here
2175#endif
50581042
SC
2176}
2177
783d8bdf 2178void * wxMacCoreGraphicsContext::GetNativeContext()
50581042 2179{
783d8bdf 2180 return m_cgContext;
b7b40adb 2181}
50581042 2182
b7b40adb 2183// concatenates this transform with the current transform of this context
e3ff3591 2184void wxMacCoreGraphicsContext::ConcatTransform( const wxGraphicsMatrix& matrix )
b7b40adb 2185{
549be226
SC
2186 if ( m_cgContext )
2187 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
2188 else
2189 m_windowTransform = CGAffineTransformConcat(m_windowTransform, *(CGAffineTransform*) matrix.GetNativeMatrix());
b7b40adb 2190}
50581042 2191
b7b40adb 2192// sets the transform of this context
e3ff3591 2193void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix& matrix )
b7b40adb 2194{
549be226
SC
2195 if ( m_cgContext )
2196 {
2197 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
2198 transform = CGAffineTransformInvert( transform ) ;
2199 CGContextConcatCTM( m_cgContext, transform);
2200 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
2201 }
2202 else
2203 {
2204 m_windowTransform = *(CGAffineTransform*) matrix.GetNativeMatrix();
2205 }
b7b40adb 2206}
50581042 2207
b7b40adb 2208// gets the matrix of this context
e3ff3591 2209wxGraphicsMatrix wxMacCoreGraphicsContext::GetTransform() const
b7b40adb 2210{
daa6105f 2211 wxGraphicsMatrix m = CreateMatrix();
549be226
SC
2212 *((CGAffineTransform*) m.GetNativeMatrix()) = ( m_cgContext == NULL ? m_windowTransform :
2213 CGContextGetCTM( m_cgContext ));
daa6105f 2214 return m;
b7b40adb 2215}
50581042 2216
b7b40adb
SC
2217//
2218// Renderer
2219//
50581042 2220
b7b40adb
SC
2221//-----------------------------------------------------------------------------
2222// wxMacCoreGraphicsRenderer declaration
2223//-----------------------------------------------------------------------------
50581042 2224
b7b40adb
SC
2225class WXDLLIMPEXP_CORE wxMacCoreGraphicsRenderer : public wxGraphicsRenderer
2226{
2227public :
2228 wxMacCoreGraphicsRenderer() {}
50581042 2229
b7b40adb
SC
2230 virtual ~wxMacCoreGraphicsRenderer() {}
2231
783d8bdf
VZ
2232 // Context
2233
2234 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
888dde65 2235 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
b7b40adb 2236
783d8bdf 2237 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
b7b40adb 2238
783d8bdf 2239 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
b7b40adb 2240
783d8bdf 2241 virtual wxGraphicsContext * CreateContext( wxWindow* window );
947f3b35 2242
ad667945 2243 virtual wxGraphicsContext * CreateMeasuringContext();
783d8bdf
VZ
2244
2245 // Path
b7b40adb 2246
e3ff3591 2247 virtual wxGraphicsPath CreatePath();
b7b40adb 2248
783d8bdf
VZ
2249 // Matrix
2250
2251 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
2252 wxDouble tx=0.0, wxDouble ty=0.0);
b7b40adb
SC
2253
2254
a26b7ab2 2255 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
783d8bdf 2256
a26b7ab2 2257 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
783d8bdf 2258
b7b40adb 2259 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
783d8bdf 2260 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb
SC
2261 const wxColour&c1, const wxColour&c2) ;
2262
783d8bdf 2263 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
b7b40adb 2264 // with radius r and color cColor
a26b7ab2 2265 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
b7b40adb
SC
2266 const wxColour &oColor, const wxColour &cColor) ;
2267
2268 // sets the font
a26b7ab2 2269 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
b7b40adb 2270
5252d9e4
SC
2271 // create a native bitmap representation
2272 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) ;
947f3b35 2273
5252d9e4
SC
2274 // create a native bitmap representation
2275 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
b7b40adb
SC
2276private :
2277 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsRenderer)
2278} ;
2279
2280//-----------------------------------------------------------------------------
2281// wxMacCoreGraphicsRenderer implementation
2282//-----------------------------------------------------------------------------
2283
2284IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsRenderer,wxGraphicsRenderer)
2285
2286static wxMacCoreGraphicsRenderer gs_MacCoreGraphicsRenderer;
2287
2288wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
2289{
783d8bdf 2290 return &gs_MacCoreGraphicsRenderer;
50581042
SC
2291}
2292
5252d9e4
SC
2293#ifdef __WXCOCOA__
2294extern CGContextRef wxMacGetContextFromCurrentNSContext() ;
2295#endif
2296
888dde65 2297wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc )
b7b40adb 2298{
888dde65
RR
2299 const wxDCImpl* impl = dc.GetImpl();
2300 wxWindowDCImpl *win_impl = wxDynamicCast( impl, wxWindowDCImpl );
2301 if (win_impl)
5252d9e4
SC
2302 {
2303 int w, h;
2304 win_impl->GetSize( &w, &h );
2305 CGContextRef cgctx = 0;
2306#ifdef __WXMAC__
2307 cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef());
2308#else
2309 cgctx = wxMacGetContextFromCurrentNSContext() ;
2310#endif
2311 return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h );
2312 }
888dde65
RR
2313 return NULL;
2314}
2315
2316wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC& dc )
2317{
5252d9e4 2318#ifdef __WXMAC__
888dde65
RR
2319 const wxDCImpl* impl = dc.GetImpl();
2320 wxMemoryDCImpl *mem_impl = wxDynamicCast( impl, wxMemoryDCImpl );
2321 if (mem_impl)
5252d9e4
SC
2322 {
2323 int w, h;
2324 mem_impl->GetSize( &w, &h );
947f3b35 2325 return new wxMacCoreGraphicsContext( this,
5252d9e4
SC
2326 (CGContextRef)(mem_impl->GetGraphicsContext()->GetNativeContext()), (wxDouble) w, (wxDouble) h );
2327 }
2328#endif
888dde65 2329 return NULL;
b7b40adb
SC
2330}
2331
2332wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
2333{
2334 return new wxMacCoreGraphicsContext(this,(CGContextRef)context);
2335}
2336
2337
2338wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( void * window )
2339{
2340 return new wxMacCoreGraphicsContext(this,(WindowRef)window);
2341}
2342
2343wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
2344{
783d8bdf 2345 return new wxMacCoreGraphicsContext(this, window );
b7b40adb
SC
2346}
2347
ad667945
SC
2348wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateMeasuringContext()
2349{
2350 return new wxMacCoreGraphicsContext(this);
2351}
2352
b7b40adb
SC
2353// Path
2354
e3ff3591 2355wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
b7b40adb 2356{
e3ff3591
SC
2357 wxGraphicsPath m;
2358 m.SetRefData( new wxMacCoreGraphicsPathData(this));
2359 return m;
b7b40adb
SC
2360}
2361
2362
2363// Matrix
2364
783d8bdf
VZ
2365wxGraphicsMatrix wxMacCoreGraphicsRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
2366 wxDouble tx, wxDouble ty)
1056ddcf 2367{
e3ff3591
SC
2368 wxGraphicsMatrix m;
2369 wxMacCoreGraphicsMatrixData* data = new wxMacCoreGraphicsMatrixData( this );
2370 data->Set( a,b,c,d,tx,ty ) ;
2371 m.SetRefData(data);
b7b40adb
SC
2372 return m;
2373}
2374
783d8bdf 2375wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen)
b7b40adb
SC
2376{
2377 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
a26b7ab2 2378 return wxNullGraphicsPen;
b7b40adb 2379 else
a26b7ab2
SC
2380 {
2381 wxGraphicsPen p;
2382 p.SetRefData(new wxMacCoreGraphicsPenData( this, pen ));
2383 return p;
2384 }
1056ddcf
SC
2385}
2386
783d8bdf 2387wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush )
50581042 2388{
b7b40adb 2389 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
a26b7ab2 2390 return wxNullGraphicsBrush;
b7b40adb 2391 else
a26b7ab2
SC
2392 {
2393 wxGraphicsBrush p;
2394 p.SetRefData(new wxMacCoreGraphicsBrushData( this, brush ));
2395 return p;
2396 }
50581042
SC
2397}
2398
5252d9e4
SC
2399wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmap( const wxBitmap& bmp )
2400{
2401 if ( bmp.Ok() )
2402 {
2403 wxGraphicsBitmap p;
2404#ifdef __WXMAC__
2405 p.SetRefData(new wxMacCoreGraphicsBitmapData( this , bmp.CreateCGImage() ) );
2406#endif
2407 return p;
2408 }
2409 else
2410 return wxNullGraphicsBitmap;
2411}
2412
947f3b35 2413wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateSubBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
5252d9e4
SC
2414{
2415 CGImageRef img = static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData())->GetBitmap();
2416 if ( img )
2417 {
2418 wxGraphicsBitmap p;
2419 CGImageRef subimg = CGImageCreateWithImageInRect(img,CGRectMake( x , y , w , h ));
2420 p.SetRefData(new wxMacCoreGraphicsBitmapData( this , subimg ) );
2421 return p;
2422 }
2423 else
2424 return wxNullGraphicsBitmap;
2425}
2426
b7b40adb 2427// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
783d8bdf
VZ
2428wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
2429 const wxColour&c1, const wxColour&c2)
1056ddcf 2430{
a26b7ab2
SC
2431 wxGraphicsBrush p;
2432 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
2433 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
2434 p.SetRefData(d);
2435 return p;
1056ddcf
SC
2436}
2437
783d8bdf 2438// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
b7b40adb 2439// with radius r and color cColor
a26b7ab2 2440wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
783d8bdf 2441 const wxColour &oColor, const wxColour &cColor)
1056ddcf 2442{
a26b7ab2
SC
2443 wxGraphicsBrush p;
2444 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
2445 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
2446 p.SetRefData(d);
2447 return p;
1056ddcf
SC
2448}
2449
b7b40adb 2450// sets the font
783d8bdf 2451wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const wxColour &col )
513b47e9 2452{
b7b40adb 2453 if ( font.Ok() )
783d8bdf 2454 {
a26b7ab2
SC
2455 wxGraphicsFont p;
2456 p.SetRefData(new wxMacCoreGraphicsFontData( this , font, col ));
2457 return p;
2458 }
b7b40adb 2459 else
a26b7ab2 2460 return wxNullGraphicsFont;
513b47e9
SC
2461}
2462
fb728ebb
SC
2463//
2464// CoreGraphics Helper Methods
2465//
2466
2467// Data Providers and Consumers
2468
2469size_t UMAPutBytesCFRefCallback( void *info, const void *bytes, size_t count )
2470{
2471 CFMutableDataRef data = (CFMutableDataRef) info;
2472 if ( data )
2473 {
2474 CFDataAppendBytes( data, (const UInt8*) bytes, count );
2475 }
2476 return count;
2477}
2478
2479void wxMacReleaseCFDataProviderCallback(void *info,
2480 const void *WXUNUSED(data),
2481 size_t WXUNUSED(count))
2482{
2483 if ( info )
2484 CFRelease( (CFDataRef) info );
2485}
2486
2487void wxMacReleaseCFDataConsumerCallback( void *info )
2488{
2489 if ( info )
2490 CFRelease( (CFDataRef) info );
2491}
2492
2493CGDataProviderRef wxMacCGDataProviderCreateWithCFData( CFDataRef data )
2494{
2495 if ( data == NULL )
2496 return NULL;
2497
2498 return CGDataProviderCreateWithCFData( data );
2499}
2500
2501CGDataConsumerRef wxMacCGDataConsumerCreateWithCFData( CFMutableDataRef data )
2502{
2503 if ( data == NULL )
2504 return NULL;
2505
2506 return CGDataConsumerCreateWithCFData( data );
2507}
2508
947f3b35
VZ
2509void
2510wxMacReleaseMemoryBufferProviderCallback(void *info,
2511 const void * WXUNUSED_UNLESS_DEBUG(data),
2512 size_t WXUNUSED(size))
fb728ebb
SC
2513{
2514 wxMemoryBuffer* membuf = (wxMemoryBuffer*) info ;
2515
2516 wxASSERT( data == membuf->GetData() ) ;
2517
2518 delete membuf ;
2519}
2520
2521CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf )
2522{
2523 wxMemoryBuffer* b = new wxMemoryBuffer( buf );
2524 if ( b->GetDataLen() == 0 )
2525 return NULL;
947f3b35 2526
fb728ebb
SC
2527 return CGDataProviderCreateWithData( b , (const void *) b->GetData() , b->GetDataLen() ,
2528 wxMacReleaseMemoryBufferProviderCallback );
947f3b35 2529}