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