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