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