]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/graphics.cpp
Explicitly forward non-command events along to the native control first.
[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 ) );
398 m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
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() ) );
410 m_pattern.Set( *( new HatchPattern( pen.GetStyle() , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
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 {
453 CGContextSetStrokeColorSpace( cg , m_colorSpace );
454 CGContextSetStrokePattern( cg, m_pattern , m_patternColorComponents );
455 }
456 else
457 {
458 CGContextSetStrokeColorWithColor( cg , m_color );
459 }
50581042
SC
460}
461
b7b40adb
SC
462//
463// Brush
464//
465
a26b7ab2 466class wxMacCoreGraphicsBrushData : public wxGraphicsObjectRefData
50581042 467{
b7b40adb 468public:
a26b7ab2
SC
469 wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer );
470 wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
471 ~wxMacCoreGraphicsBrushData ();
783d8bdf 472
b7b40adb 473 virtual void Apply( wxGraphicsContext* context );
783d8bdf 474 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb
SC
475 const wxColour&c1, const wxColour&c2 );
476 void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
477 const wxColour &oColor, const wxColour &cColor );
783d8bdf 478
b7b40adb
SC
479 virtual bool IsShading() { return m_isShading; }
480 CGShadingRef GetShading() { return m_shading; }
481protected:
482 CGFunctionRef CreateGradientFunction( const wxColour& c1, const wxColour& c2 );
483 static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out);
484 virtual void Init();
783d8bdf 485
b7b40adb
SC
486 wxMacCFRefHolder<CGColorRef> m_color;
487 wxMacCFRefHolder<CGColorSpaceRef> m_colorSpace;
488
489 bool m_isPattern;
490 wxMacCFRefHolder<CGPatternRef> m_pattern;
491 CGFloat* m_patternColorComponents;
783d8bdf 492
b7b40adb
SC
493 bool m_isShading;
494 CGFunctionRef m_gradientFunction;
495 CGShadingRef m_shading;
496 CGFloat *m_gradientComponents;
b7b40adb
SC
497};
498
a26b7ab2 499wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer )
50581042 500{
b7b40adb 501 Init();
50581042
SC
502}
503
783d8bdf 504void wxMacCoreGraphicsBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb 505 const wxColour&c1, const wxColour&c2 )
50581042 506{
b7b40adb
SC
507 m_gradientFunction = CreateGradientFunction( c1, c2 );
508 m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), CGPointMake(x1,y1), CGPointMake(x2,y2), m_gradientFunction, true, true ) ;
509 m_isShading = true ;
510}
783d8bdf 511
a26b7ab2 512void wxMacCoreGraphicsBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
b7b40adb
SC
513 const wxColour &oColor, const wxColour &cColor )
514{
515 m_gradientFunction = CreateGradientFunction( oColor, cColor );
516 m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake(xo,yo), 0, CGPointMake(xc,yc), radius, m_gradientFunction, true, true ) ;
517 m_isShading = true ;
518}
783d8bdf 519
a26b7ab2 520wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : wxGraphicsObjectRefData( renderer )
b7b40adb
SC
521{
522 Init();
783d8bdf 523
b7b40adb
SC
524 if ( brush.GetStyle() == wxSOLID )
525 {
783d8bdf 526 float components[4] = { brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
b7b40adb
SC
527 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 } ;
528 m_color.Set( CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ) ;
529 }
530 else if ( brush.IsHatch() )
531 {
532 m_isPattern = true;
533 m_colorSpace.Set( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
534 m_pattern.Set( *( new HatchPattern( brush.GetStyle() , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
535
536 m_patternColorComponents = new CGFloat[4] ;
537 m_patternColorComponents[0] = brush.GetColour().Red() / 255.0;
538 m_patternColorComponents[1] = brush.GetColour().Green() / 255.0;
539 m_patternColorComponents[2] = brush.GetColour().Blue() / 255.0;
540 m_patternColorComponents[3] = brush.GetColour().Alpha() / 255.0;
541 }
542 else
543 {
544 // now brush is a bitmap
545 wxBitmap* bmp = brush.GetStipple();
546 if ( bmp && bmp->Ok() )
547 {
783d8bdf 548 m_isPattern = true;
b7b40adb
SC
549 m_patternColorComponents = new CGFloat[1] ;
550 m_patternColorComponents[0] = 1.0;
551 m_colorSpace.Set( CGColorSpaceCreatePattern( NULL ) );
552 m_pattern.Set( *( new ImagePattern( bmp , CGAffineTransformMakeTranslation( 0,0 ) ) ) );
553 }
554 }
50581042
SC
555}
556
a26b7ab2 557wxMacCoreGraphicsBrushData::~wxMacCoreGraphicsBrushData()
50581042 558{
b7b40adb
SC
559 if ( m_shading )
560 CGShadingRelease(m_shading);
783d8bdf 561
b7b40adb
SC
562 if( m_gradientFunction )
563 CGFunctionRelease(m_gradientFunction);
783d8bdf 564
b7b40adb
SC
565 delete[] m_gradientComponents;
566 delete[] m_patternColorComponents;
50581042
SC
567}
568
a26b7ab2 569void wxMacCoreGraphicsBrushData::Init()
50581042 570{
b7b40adb
SC
571 m_patternColorComponents = NULL;
572 m_gradientFunction = NULL;
573 m_shading = NULL;
574 m_isPattern = false;
575 m_gradientComponents = NULL;
576 m_isShading = false;
50581042
SC
577}
578
a26b7ab2 579void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context )
50581042 580{
b7b40adb 581 CGContextRef cg = (CGContextRef) context->GetNativeContext();
783d8bdf 582
b7b40adb 583 if ( m_isShading )
783d8bdf 584 {
b7b40adb
SC
585 }
586 else
587 {
588 if ( m_isPattern )
589 {
590 CGContextSetFillColorSpace( cg , m_colorSpace );
591 CGContextSetFillPattern( cg, m_pattern , m_patternColorComponents );
592 }
593 else
594 {
595 CGContextSetFillColorWithColor( cg, m_color );
596 }
597 }
50581042
SC
598}
599
a26b7ab2 600void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)
50581042 601{
b7b40adb
SC
602 CGFloat* colors = (CGFloat*) info ;
603 CGFloat f = *in;
604 for( int i = 0 ; i < 4 ; ++i )
605 {
606 out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f;
607 }
50581042
SC
608}
609
a26b7ab2 610CGFunctionRef wxMacCoreGraphicsBrushData::CreateGradientFunction( const wxColour& c1, const wxColour& c2 )
50581042 611{
b7b40adb
SC
612 static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL };
613 static const CGFloat input_value_range [2] = { 0, 1 };
614 static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
615 m_gradientComponents = new CGFloat[8] ;
616 m_gradientComponents[0] = c1.Red() / 255.0;
617 m_gradientComponents[1] = c1.Green() / 255.0;
618 m_gradientComponents[2] = c1.Blue() / 255.0;
619 m_gradientComponents[3] = c1.Alpha() / 255.0;
620 m_gradientComponents[4] = c2.Red() / 255.0;
621 m_gradientComponents[5] = c2.Green() / 255.0;
622 m_gradientComponents[6] = c2.Blue() / 255.0;
623 m_gradientComponents[7] = c2.Alpha() / 255.0;
624
783d8bdf
VZ
625 return CGFunctionCreate ( m_gradientComponents, 1,
626 input_value_range,
627 4,
b7b40adb 628 output_value_ranges,
783d8bdf 629 &callbacks);
50581042
SC
630}
631
632//
b7b40adb 633// Font
50581042
SC
634//
635
a26b7ab2 636class wxMacCoreGraphicsFontData : public wxGraphicsObjectRefData
50581042 637{
50581042 638public:
a26b7ab2
SC
639 wxMacCoreGraphicsFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
640 ~wxMacCoreGraphicsFontData();
783d8bdf 641
b7b40adb
SC
642 virtual ATSUStyle GetATSUStyle() { return m_macATSUIStyle; }
643private :
644 ATSUStyle m_macATSUIStyle;
b7b40adb 645};
50581042 646
a26b7ab2 647wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col) : wxGraphicsObjectRefData( renderer )
b7b40adb
SC
648{
649 m_macATSUIStyle = NULL;
783d8bdf 650
b7b40adb 651 OSStatus status;
50581042 652
b7b40adb 653 status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , &m_macATSUIStyle );
50581042 654
b7b40adb 655 wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") );
50581042 656
b7b40adb 657 // we need the scale here ...
50581042 658
b7b40adb
SC
659 Fixed atsuSize = IntToFixed( int( 1 * font.MacGetFontSize()) );
660 RGBColor atsuColor = MAC_WXCOLORREF( col.GetPixel() );
661 ATSUAttributeTag atsuTags[] =
662 {
663 kATSUSizeTag ,
664 kATSUColorTag ,
665 };
666 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
667 {
668 sizeof( Fixed ) ,
669 sizeof( RGBColor ) ,
670 };
671 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
672 {
673 &atsuSize ,
674 &atsuColor ,
675 };
50581042 676
b7b40adb
SC
677 status = ::ATSUSetAttributes(
678 m_macATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) ,
679 atsuTags, atsuSizes, atsuValues);
50581042 680
b7b40adb
SC
681 wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") );
682}
50581042 683
a26b7ab2 684wxMacCoreGraphicsFontData::~wxMacCoreGraphicsFontData()
b7b40adb
SC
685{
686 if ( m_macATSUIStyle )
687 {
688 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
689 m_macATSUIStyle = NULL;
690 }
691}
50581042 692
b7b40adb
SC
693//
694// Graphics Matrix
695//
50581042 696
b7b40adb
SC
697//-----------------------------------------------------------------------------
698// wxMacCoreGraphicsMatrix declaration
699//-----------------------------------------------------------------------------
50581042 700
e3ff3591 701class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData
b7b40adb
SC
702{
703public :
783d8bdf
VZ
704 wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) ;
705
706 virtual ~wxMacCoreGraphicsMatrixData() ;
707
e3ff3591 708 virtual wxGraphicsObjectRefData *Clone() const ;
b7b40adb 709
783d8bdf
VZ
710 // concatenates the matrix
711 virtual void Concat( const wxGraphicsMatrixData *t );
712
713 // sets the matrix to the respective values
714 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
715 wxDouble tx=0.0, wxDouble ty=0.0);
716
717 // makes this the inverse matrix
718 virtual void Invert();
719
720 // returns true if the elements of the transformation matrix are equal ?
e3ff3591 721 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
783d8bdf
VZ
722
723 // return true if this is the identity matrix
724 virtual bool IsIdentity() const;
725
50581042 726 //
b7b40adb 727 // transformation
50581042 728 //
783d8bdf 729
b7b40adb
SC
730 // add the translation to this matrix
731 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 732
b7b40adb
SC
733 // add the scale to this matrix
734 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 735
b7b40adb 736 // add the rotation to this matrix (radians)
783d8bdf
VZ
737 virtual void Rotate( wxDouble angle );
738
50581042 739 //
b7b40adb 740 // apply the transforms
50581042 741 //
783d8bdf
VZ
742
743 // applies that matrix to the point
744 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
745
746 // applies the matrix except for translations
747 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
748
749 // returns the native representation
750 virtual void * GetNativeMatrix() const;
751
b7b40adb
SC
752private :
753 CGAffineTransform m_matrix;
b7b40adb 754} ;
50581042 755
50581042 756//-----------------------------------------------------------------------------
b7b40adb 757// wxMacCoreGraphicsMatrix implementation
50581042
SC
758//-----------------------------------------------------------------------------
759
e3ff3591 760wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
b7b40adb 761{
b7b40adb 762}
eec960fa 763
783d8bdf 764wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData()
50581042 765{
50581042
SC
766}
767
783d8bdf 768wxGraphicsObjectRefData *wxMacCoreGraphicsMatrixData::Clone() const
50581042 769{
e3ff3591 770 wxMacCoreGraphicsMatrixData* m = new wxMacCoreGraphicsMatrixData(GetRenderer()) ;
b7b40adb
SC
771 m->m_matrix = m_matrix ;
772 return m;
773}
774
775// concatenates the matrix
783d8bdf 776void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t )
b7b40adb
SC
777{
778 m_matrix = CGAffineTransformConcat(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()) );
779}
780
b7b40adb 781// sets the matrix to the respective values
783d8bdf
VZ
782void wxMacCoreGraphicsMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
783 wxDouble tx, wxDouble ty)
b7b40adb
SC
784{
785 m_matrix = CGAffineTransformMake(a,b,c,d,tx,ty);
50581042
SC
786}
787
b7b40adb 788// makes this the inverse matrix
783d8bdf 789void wxMacCoreGraphicsMatrixData::Invert()
1056ddcf 790{
b7b40adb 791 m_matrix = CGAffineTransformInvert( m_matrix );
eec960fa
SC
792}
793
b7b40adb 794// returns true if the elements of the transformation matrix are equal ?
783d8bdf 795bool wxMacCoreGraphicsMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
eec960fa 796{
2701ef7e 797 const CGAffineTransform* tm = (CGAffineTransform*) t->GetNativeMatrix();
23a3e8fb
SC
798#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
799 if ( CGAffineTransformEqualToTransform )
800 {
801 return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()));
802 }
803 else
804#endif
805 {
806 return (
807 m_matrix.a == tm->a &&
808 m_matrix.b == tm->b &&
809 m_matrix.c == tm->c &&
810 m_matrix.d == tm->d &&
811 m_matrix.tx == tm->tx &&
812 m_matrix.ty == tm->ty ) ;
813 }
1056ddcf
SC
814}
815
b7b40adb 816// return true if this is the identity matrix
e3ff3591 817bool wxMacCoreGraphicsMatrixData::IsIdentity() const
50581042 818{
2701ef7e
SC
819 return ( m_matrix.a == 1 && m_matrix.d == 1 &&
820 m_matrix.b == 0 && m_matrix.d == 0 && m_matrix.tx == 0 && m_matrix.ty == 0);
50581042
SC
821}
822
b7b40adb
SC
823//
824// transformation
825//
826
827// add the translation to this matrix
783d8bdf 828void wxMacCoreGraphicsMatrixData::Translate( wxDouble dx , wxDouble dy )
50581042 829{
b7b40adb
SC
830 m_matrix = CGAffineTransformTranslate( m_matrix, dx, dy);
831}
50581042 832
b7b40adb 833// add the scale to this matrix
783d8bdf 834void wxMacCoreGraphicsMatrixData::Scale( wxDouble xScale , wxDouble yScale )
b7b40adb
SC
835{
836 m_matrix = CGAffineTransformScale( m_matrix, xScale, yScale);
50581042
SC
837}
838
b7b40adb 839// add the rotation to this matrix (radians)
783d8bdf 840void wxMacCoreGraphicsMatrixData::Rotate( wxDouble angle )
eec960fa 841{
b7b40adb 842 m_matrix = CGAffineTransformRotate( m_matrix, angle);
eec960fa
SC
843}
844
b7b40adb
SC
845//
846// apply the transforms
847//
eec960fa 848
b7b40adb 849// applies that matrix to the point
e3ff3591 850void wxMacCoreGraphicsMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
50581042 851{
2701ef7e 852 CGPoint pt = CGPointApplyAffineTransform( CGPointMake(*x,*y), m_matrix);
783d8bdf 853
2701ef7e
SC
854 *x = pt.x;
855 *y = pt.y;
1056ddcf
SC
856}
857
b7b40adb 858// applies the matrix except for translations
e3ff3591 859void wxMacCoreGraphicsMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
1056ddcf 860{
2701ef7e
SC
861 CGSize sz = CGSizeApplyAffineTransform( CGSizeMake(*dx,*dy) , m_matrix );
862 *dx = sz.width;
863 *dy = sz.height;
b7b40adb
SC
864}
865
866// returns the native representation
783d8bdf 867void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const
1056ddcf 868{
b7b40adb 869 return (void*) &m_matrix;
50581042
SC
870}
871
b7b40adb
SC
872//
873// Graphics Path
874//
875
876//-----------------------------------------------------------------------------
877// wxMacCoreGraphicsPath declaration
878//-----------------------------------------------------------------------------
879
e3ff3591 880class WXDLLEXPORT wxMacCoreGraphicsPathData : public wxGraphicsPathData
50581042 881{
b7b40adb 882public :
e3ff3591 883 wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path = NULL);
783d8bdf 884
e3ff3591 885 ~wxMacCoreGraphicsPathData();
1056ddcf 886
e3ff3591 887 virtual wxGraphicsObjectRefData *Clone() const;
1056ddcf 888
b7b40adb
SC
889 // begins a new subpath at (x,y)
890 virtual void MoveToPoint( wxDouble x, wxDouble y );
1056ddcf 891
783d8bdf 892 // adds a straight line from the current point to (x,y)
b7b40adb
SC
893 virtual void AddLineToPoint( wxDouble x, wxDouble y );
894
895 // adds a cubic Bezier curve from the current point, using two control points and an end point
896 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
897
898 // closes the current sub-path
899 virtual void CloseSubpath();
900
901 // gets the last point of the current path, (0,0) if not yet set
e3ff3591 902 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
b7b40adb
SC
903
904 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
905 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise );
906
907 //
783d8bdf 908 // These are convenience functions which - if not available natively will be assembled
b7b40adb
SC
909 // using the primitives from above
910 //
911
912 // adds a quadratic Bezier curve from the current point, using a control point and an end point
913 virtual void AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y );
914
783d8bdf 915 // appends a rectangle as a new closed subpath
b7b40adb
SC
916 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
917
918 // appends an ellipsis as a new closed subpath fitting the passed rectangle
919 virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r );
920
921 // 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)
922 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
923
783d8bdf
VZ
924 // adds another path
925 virtual void AddPath( const wxGraphicsPathData* path );
926
927 // returns the native path
928 virtual void * GetNativePath() const { return m_path; }
929
930 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
931 virtual void UnGetNativePath(void *p) const {}
932
933 // transforms each point of this path by the matrix
934 virtual void Transform( const wxGraphicsMatrixData* matrix );
935
936 // gets the bounding box enclosing all points (possibly including control points)
937 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *y) const;
938
939 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const;
b7b40adb
SC
940private :
941 CGMutablePathRef m_path;
942};
943
944//-----------------------------------------------------------------------------
945// wxMacCoreGraphicsPath implementation
946//-----------------------------------------------------------------------------
947
e3ff3591 948wxMacCoreGraphicsPathData::wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPathData(renderer)
b7b40adb 949{
783d8bdf
VZ
950 if ( path )
951 m_path = path;
952 else
953 m_path = CGPathCreateMutable();
50581042
SC
954}
955
e3ff3591 956wxMacCoreGraphicsPathData::~wxMacCoreGraphicsPathData()
50581042 957{
b7b40adb
SC
958 CGPathRelease( m_path );
959}
50581042 960
783d8bdf 961wxGraphicsObjectRefData* wxMacCoreGraphicsPathData::Clone() const
b7b40adb 962{
783d8bdf
VZ
963 wxMacCoreGraphicsPathData* clone = new wxMacCoreGraphicsPathData(GetRenderer(),CGPathCreateMutableCopy(m_path));
964 return clone ;
b7b40adb 965}
1056ddcf 966
1056ddcf 967
b7b40adb 968// opens (starts) a new subpath
e3ff3591 969void wxMacCoreGraphicsPathData::MoveToPoint( wxDouble x1 , wxDouble y1 )
b7b40adb
SC
970{
971 CGPathMoveToPoint( m_path , NULL , x1 , y1 );
972}
1056ddcf 973
e3ff3591 974void wxMacCoreGraphicsPathData::AddLineToPoint( wxDouble x1 , wxDouble y1 )
b7b40adb
SC
975{
976 CGPathAddLineToPoint( m_path , NULL , x1 , y1 );
50581042
SC
977}
978
e3ff3591 979void wxMacCoreGraphicsPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
50581042 980{
b7b40adb 981 CGPathAddCurveToPoint( m_path , NULL , cx1 , cy1 , cx2, cy2, x , y );
50581042
SC
982}
983
e3ff3591 984void wxMacCoreGraphicsPathData::AddQuadCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble x, wxDouble y )
50581042 985{
b7b40adb 986 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x , y );
50581042
SC
987}
988
e3ff3591 989void wxMacCoreGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
50581042 990{
b7b40adb
SC
991 CGRect cgRect = { { x , y } , { w , h } };
992 CGPathAddRect( m_path , NULL , cgRect );
993}
50581042 994
e3ff3591 995void wxMacCoreGraphicsPathData::AddCircle( wxDouble x, wxDouble y , wxDouble r )
b7b40adb
SC
996{
997 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true );
50581042
SC
998}
999
b7b40adb 1000// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
e3ff3591 1001void wxMacCoreGraphicsPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise )
50581042 1002{
b7b40adb 1003 // inverse direction as we the 'normal' state is a y axis pointing down, ie mirrored to the standard core graphics setup
783d8bdf 1004 CGPathAddArc( m_path, NULL , x, y, r, startAngle, endAngle, !clockwise);
50581042
SC
1005}
1006
e3ff3591 1007void wxMacCoreGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
50581042 1008{
783d8bdf 1009 CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
50581042
SC
1010}
1011
e3ff3591 1012void wxMacCoreGraphicsPathData::AddPath( const wxGraphicsPathData* path )
50581042 1013{
783d8bdf 1014 CGPathAddPath( m_path , NULL, (CGPathRef) path->GetNativePath() );
50581042
SC
1015}
1016
b7b40adb 1017// closes the current subpath
e3ff3591 1018void wxMacCoreGraphicsPathData::CloseSubpath()
50581042 1019{
b7b40adb 1020 CGPathCloseSubpath( m_path );
50581042
SC
1021}
1022
b7b40adb 1023// gets the last point of the current path, (0,0) if not yet set
e3ff3591 1024void wxMacCoreGraphicsPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
50581042 1025{
b7b40adb 1026 CGPoint p = CGPathGetCurrentPoint( m_path );
e3ff3591
SC
1027 *x = p.x;
1028 *y = p.y;
50581042
SC
1029}
1030
b7b40adb 1031// transforms each point of this path by the matrix
e3ff3591 1032void wxMacCoreGraphicsPathData::Transform( const wxGraphicsMatrixData* matrix )
50581042 1033{
783d8bdf
VZ
1034 CGMutablePathRef p = CGPathCreateMutable() ;
1035 CGPathAddPath( p, (CGAffineTransform*) matrix->GetNativeMatrix() , m_path );
1036 CGPathRelease( m_path );
1037 m_path = p;
50581042
SC
1038}
1039
b7b40adb 1040// gets the bounding box enclosing all points (possibly including control points)
e3ff3591 1041void wxMacCoreGraphicsPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
50581042 1042{
783d8bdf
VZ
1043 CGRect bounds = CGPathGetBoundingBox( m_path ) ;
1044 *x = bounds.origin.x;
1045 *y = bounds.origin.y;
1046 *w = bounds.size.width;
1047 *h = bounds.size.height;
50581042
SC
1048}
1049
e3ff3591 1050bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, int fillStyle) const
50581042 1051{
23a3e8fb
SC
1052#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1053 if ( CGPathContainsPoint )
1054 {
1055 return CGPathContainsPoint( m_path, NULL, CGPointMake(x,y), fillStyle == wxODDEVEN_RULE );
1056 }
1057 else
1058#endif
1059 {
1060 // TODO : implementation for 10.3
1061 CGRect bounds = CGPathGetBoundingBox( m_path ) ;
1062 return CGRectContainsPoint( bounds, CGPointMake(x,y) ) == 1;
1063 }
50581042
SC
1064}
1065
b7b40adb
SC
1066//
1067// Graphics Context
1068//
50581042 1069
b7b40adb
SC
1070//-----------------------------------------------------------------------------
1071// wxMacCoreGraphicsContext declaration
1072//-----------------------------------------------------------------------------
1073
1074class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
1075{
1076public:
1077 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext );
783d8bdf 1078
b7b40adb 1079 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window );
783d8bdf 1080
b7b40adb 1081 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window );
783d8bdf 1082
b7b40adb 1083 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer);
783d8bdf 1084
b7b40adb 1085 wxMacCoreGraphicsContext();
783d8bdf 1086
b7b40adb 1087 ~wxMacCoreGraphicsContext();
50581042 1088
783d8bdf 1089 void Init();
50581042 1090
b7b40adb
SC
1091 // push the current state of the context, ie the transformation matrix on a stack
1092 virtual void PushState();
50581042 1093
b7b40adb
SC
1094 // pops a stored state from the stack
1095 virtual void PopState();
50581042 1096
b7b40adb
SC
1097 // clips drawings to the region
1098 virtual void Clip( const wxRegion &region );
50581042 1099
b7b40adb
SC
1100 // clips drawings to the rect
1101 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
783d8bdf 1102
b7b40adb
SC
1103 // resets the clipping to original extent
1104 virtual void ResetClip();
50581042 1105
b7b40adb 1106 virtual void * GetNativeContext();
783d8bdf 1107
b7b40adb
SC
1108 //
1109 // transformation
1110 //
783d8bdf 1111
b7b40adb
SC
1112 // translate
1113 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 1114
b7b40adb
SC
1115 // scale
1116 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 1117
b7b40adb
SC
1118 // rotate (radians)
1119 virtual void Rotate( wxDouble angle );
50581042 1120
783d8bdf
VZ
1121 // concatenates this transform with the current transform of this context
1122 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
50581042 1123
783d8bdf
VZ
1124 // sets the transform of this context
1125 virtual void SetTransform( const wxGraphicsMatrix& matrix );
50581042 1126
783d8bdf
VZ
1127 // gets the matrix of this context
1128 virtual wxGraphicsMatrix GetTransform() const;
b7b40adb
SC
1129 //
1130 // setting the paint
1131 //
783d8bdf 1132
b7b40adb 1133 // strokes along a path with the current pen
e3ff3591 1134 virtual void StrokePath( const wxGraphicsPath &path );
50581042 1135
b7b40adb 1136 // fills a path with the current brush
e3ff3591 1137 virtual void FillPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE );
50581042 1138
b7b40adb 1139 // draws a path by first filling and then stroking
e3ff3591 1140 virtual void DrawPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE );
b7b40adb
SC
1141
1142 virtual bool ShouldOffset() const
50581042 1143 {
b7b40adb 1144 int penwidth = 0 ;
a26b7ab2 1145 if ( !m_pen.IsNull() )
50581042 1146 {
783d8bdf 1147 penwidth = (int)((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->GetWidth();
b7b40adb
SC
1148 if ( penwidth == 0 )
1149 penwidth = 1;
50581042 1150 }
783d8bdf 1151 return ( penwidth % 2 ) == 1;
50581042 1152 }
b7b40adb
SC
1153 //
1154 // text
1155 //
783d8bdf 1156
b7b40adb 1157 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y );
50581042 1158
b7b40adb 1159 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
50581042 1160
b7b40adb
SC
1161 virtual void GetTextExtent( const wxString &text, wxDouble *width, wxDouble *height,
1162 wxDouble *descent, wxDouble *externalLeading ) const;
50581042 1163
b7b40adb 1164 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
50581042 1165
b7b40adb
SC
1166 //
1167 // image support
1168 //
50581042 1169
b7b40adb 1170 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1171
b7b40adb 1172 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1173
b7b40adb 1174 void SetNativeContext( CGContextRef cg );
783d8bdf 1175
b7b40adb
SC
1176 DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
1177 DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
50581042 1178
b7b40adb
SC
1179private:
1180 void EnsureIsValid();
783d8bdf 1181
b7b40adb 1182 CGContextRef m_cgContext;
783d8bdf
VZ
1183 WindowRef m_windowRef;
1184 bool m_releaseContext;
549be226 1185 CGAffineTransform m_windowTransform;
783d8bdf
VZ
1186
1187 wxMacCFRefHolder<HIShapeRef> m_clipRgn;
50581042
SC
1188};
1189
b7b40adb
SC
1190//-----------------------------------------------------------------------------
1191// device context implementation
1192//
1193// more and more of the dc functionality should be implemented by calling
1194// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step
1195// also coordinate conversions should be moved to native matrix ops
1196//-----------------------------------------------------------------------------
50581042 1197
b7b40adb
SC
1198// we always stock two context states, one at entry, to be able to preserve the
1199// state we were called with, the other one after changing to HI Graphics orientation
1200// (this one is used for getting back clippings etc)
50581042 1201
b7b40adb
SC
1202//-----------------------------------------------------------------------------
1203// wxMacCoreGraphicsContext implementation
1204//-----------------------------------------------------------------------------
50581042 1205
b7b40adb 1206IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
50581042 1207
b7b40adb
SC
1208void wxMacCoreGraphicsContext::Init()
1209{
1210 m_cgContext = NULL;
783d8bdf 1211 m_releaseContext = false;
b7b40adb 1212 m_windowRef = NULL;
549be226 1213
b7b40adb
SC
1214 HIRect r = CGRectMake(0,0,0,0);
1215 m_clipRgn.Set(HIShapeCreateWithRect(&r));
1216}
50581042 1217
b7b40adb
SC
1218wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext ) : wxGraphicsContext(renderer)
1219{
783d8bdf 1220 Init();
549be226 1221 SetNativeContext(cgcontext);
b7b40adb 1222}
50581042 1223
b7b40adb
SC
1224wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer)
1225{
783d8bdf
VZ
1226 Init();
1227 m_windowRef = window;
b7b40adb 1228}
50581042 1229
b7b40adb
SC
1230wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ): wxGraphicsContext(renderer)
1231{
783d8bdf
VZ
1232 Init();
1233 m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
549be226
SC
1234 int originX , originY;
1235 originX = originY = 0;
1236 window->MacWindowToRootWindow( &originX , &originY );
1237 Rect bounds;
1238 GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
1239
1240 m_windowTransform = CGAffineTransformMakeTranslation( 0 , bounds.bottom - bounds.top );
1241 m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 );
1242 m_windowTransform = CGAffineTransformTranslate( m_windowTransform, originX, originY ) ;
b7b40adb 1243}
50581042 1244
b7b40adb
SC
1245wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
1246{
783d8bdf 1247 Init();
b7b40adb 1248}
50581042 1249
b7b40adb
SC
1250wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
1251{
783d8bdf 1252 Init();
b7b40adb
SC
1253 wxLogDebug(wxT("Illegal Constructor called"));
1254}
50581042 1255
b7b40adb
SC
1256wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
1257{
549be226 1258 SetNativeContext(NULL);
b7b40adb 1259}
50581042 1260
b7b40adb
SC
1261void wxMacCoreGraphicsContext::EnsureIsValid()
1262{
783d8bdf
VZ
1263 if ( !m_cgContext )
1264 {
1265 OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
1266 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
549be226
SC
1267
1268 CGContextConcatCTM( m_cgContext, m_windowTransform );
69541a2e
SC
1269 CGContextSaveGState( m_cgContext );
1270 m_releaseContext = true;
1271 if ( !HIShapeIsEmpty(m_clipRgn) )
1272 {
1273 HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext );
1274 CGContextClip( m_cgContext );
1275 }
1276 CGContextSaveGState( m_cgContext );
1277 }
b7b40adb 1278}
50581042 1279
50581042 1280
b7b40adb
SC
1281void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
1282{
783d8bdf
VZ
1283 if( m_cgContext )
1284 {
1285 HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
1286 HIShapeReplacePathInCGContext( shape, m_cgContext );
1287 CGContextClip( m_cgContext );
1288 CFRelease( shape );
1289 }
1290 else
1291 {
1292 m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
1293 }
b7b40adb 1294}
50581042 1295
b7b40adb
SC
1296// clips drawings to the rect
1297void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1298{
783d8bdf
VZ
1299 HIRect r = CGRectMake( x , y , w , h );
1300 if ( m_cgContext )
1301 {
1302 CGContextClipToRect( m_cgContext, r );
1303 }
1304 else
1305 {
1306 m_clipRgn.Set(HIShapeCreateWithRect(&r));
1307 }
1308}
1309
1310 // resets the clipping to original extent
b7b40adb
SC
1311void wxMacCoreGraphicsContext::ResetClip()
1312{
783d8bdf
VZ
1313 if ( m_cgContext )
1314 {
a7868cdf
SC
1315 // there is no way for clearing the clip, we can only revert to the stored
1316 // state, but then we have to make sure everything else is NOT restored
1317 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
783d8bdf
VZ
1318 CGContextRestoreGState( m_cgContext );
1319 CGContextSaveGState( m_cgContext );
a7868cdf
SC
1320 CGAffineTransform transformNew = CGContextGetCTM( m_cgContext );
1321 transformNew = CGAffineTransformInvert( transformNew ) ;
1322 CGContextConcatCTM( m_cgContext, transformNew);
1323 CGContextConcatCTM( m_cgContext, transform);
783d8bdf
VZ
1324 }
1325 else
1326 {
b7b40adb
SC
1327 HIRect r = CGRectMake(0,0,0,0);
1328 m_clipRgn.Set(HIShapeCreateWithRect(&r));
783d8bdf 1329 }
b7b40adb 1330}
50581042 1331
e3ff3591 1332void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
b7b40adb 1333{
a26b7ab2 1334 if ( m_pen.IsNull() )
b7b40adb 1335 return ;
50581042 1336
783d8bdf
VZ
1337 EnsureIsValid();
1338
b7b40adb
SC
1339 bool offset = ShouldOffset();
1340 if ( offset )
1341 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
50581042 1342
a26b7ab2 1343 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
e3ff3591 1344 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1345 CGContextStrokePath( m_cgContext );
50581042 1346
b7b40adb
SC
1347 if ( offset )
1348 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
1349}
50581042 1350
e3ff3591 1351void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillStyle )
783d8bdf 1352{
a26b7ab2 1353 if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1354 {
1355 // when using shading, we cannot draw pen and brush at the same time
1356 // revert to the base implementation of first filling and then stroking
1357 wxGraphicsContext::DrawPath( path, fillStyle );
1358 return;
1359 }
783d8bdf 1360
b7b40adb 1361 CGPathDrawingMode mode = kCGPathFill ;
a26b7ab2 1362 if ( m_brush.IsNull() )
b7b40adb 1363 {
a26b7ab2 1364 if ( m_pen.IsNull() )
b7b40adb
SC
1365 return;
1366 else
1367 mode = kCGPathStroke;
1368 }
1369 else
1370 {
a26b7ab2 1371 if ( m_pen.IsNull() )
b7b40adb
SC
1372 {
1373 if ( fillStyle == wxODDEVEN_RULE )
1374 mode = kCGPathEOFill;
1375 else
1376 mode = kCGPathFill;
1377 }
1378 else
1379 {
1380 if ( fillStyle == wxODDEVEN_RULE )
1381 mode = kCGPathEOFillStroke;
1382 else
1383 mode = kCGPathFillStroke;
1384 }
1385 }
783d8bdf
VZ
1386
1387 EnsureIsValid();
50581042 1388
a26b7ab2
SC
1389 if ( !m_brush.IsNull() )
1390 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1391 if ( !m_pen.IsNull() )
1392 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
50581042 1393
b7b40adb 1394 bool offset = ShouldOffset();
783d8bdf 1395
b7b40adb
SC
1396 if ( offset )
1397 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
50581042 1398
e3ff3591 1399 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1400 CGContextDrawPath( m_cgContext , mode );
50581042 1401
b7b40adb
SC
1402 if ( offset )
1403 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
1404}
50581042 1405
e3ff3591 1406void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , int fillStyle )
b7b40adb 1407{
a26b7ab2 1408 if ( m_brush.IsNull() )
b7b40adb 1409 return;
783d8bdf
VZ
1410
1411 EnsureIsValid();
1412
a26b7ab2 1413 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1414 {
1415 CGContextSaveGState( m_cgContext );
e3ff3591 1416 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb 1417 CGContextClip( m_cgContext );
a26b7ab2 1418 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
b7b40adb
SC
1419 CGContextRestoreGState( m_cgContext);
1420 }
1421 else
783d8bdf 1422 {
a26b7ab2 1423 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
e3ff3591 1424 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
b7b40adb
SC
1425 if ( fillStyle == wxODDEVEN_RULE )
1426 CGContextEOFillPath( m_cgContext );
1427 else
1428 CGContextFillPath( m_cgContext );
50581042
SC
1429 }
1430}
1431
b7b40adb 1432void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
50581042 1433{
b7b40adb
SC
1434 // we allow either setting or clearing but not replacing
1435 wxASSERT( m_cgContext == NULL || cg == NULL );
50581042 1436
549be226
SC
1437 if ( m_cgContext )
1438 {
1439 // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
1440 CGContextRestoreGState( m_cgContext );
1441 CGContextRestoreGState( m_cgContext );
1442 if ( m_releaseContext )
1443 QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
1444 else
1445 CGContextRelease(m_cgContext);
1446 }
1447
1448
b7b40adb 1449 m_cgContext = cg;
549be226
SC
1450
1451 // FIXME: This check is needed because currently we need to use a DC/GraphicsContext
783d8bdf 1452 // in order to get font properties, like wxFont::GetPixelSize, but since we don't have
549be226
SC
1453 // a native window attached to use, I create a wxGraphicsContext with a NULL CGContextRef
1454 // for this one operation.
783d8bdf 1455
549be226 1456 // When wxFont::GetPixelSize on Mac no longer needs a graphics context, this check
783d8bdf 1457 // can be removed.
549be226
SC
1458 if (m_cgContext)
1459 {
1460 CGContextRetain(m_cgContext);
1461 CGContextSaveGState( m_cgContext );
1462 CGContextSaveGState( m_cgContext );
783d8bdf 1463 m_releaseContext = false;
549be226 1464 }
b7b40adb 1465}
50581042 1466
783d8bdf 1467void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy )
b7b40adb 1468{
783d8bdf 1469 if ( m_cgContext )
549be226
SC
1470 CGContextTranslateCTM( m_cgContext, dx, dy );
1471 else
1472 m_windowTransform = CGAffineTransformTranslate(m_windowTransform,dx,dy);
b7b40adb 1473}
50581042 1474
b7b40adb
SC
1475void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
1476{
783d8bdf 1477 if ( m_cgContext )
549be226
SC
1478 CGContextScaleCTM( m_cgContext , xScale , yScale );
1479 else
1480 m_windowTransform = CGAffineTransformScale(m_windowTransform,xScale,yScale);
b7b40adb 1481}
50581042 1482
b7b40adb
SC
1483void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
1484{
783d8bdf 1485 if ( m_cgContext )
549be226
SC
1486 CGContextRotateCTM( m_cgContext , angle );
1487 else
1488 m_windowTransform = CGAffineTransformRotate(m_windowTransform,angle);
b7b40adb 1489}
50581042 1490
783d8bdf 1491void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
b7b40adb 1492{
783d8bdf
VZ
1493 EnsureIsValid();
1494
b7b40adb
SC
1495 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() );
1496 HIRect r = CGRectMake( x , y , w , h );
1497 HIViewDrawCGImage( m_cgContext , &r , image );
1498 CGImageRelease( image );
1499}
50581042 1500
783d8bdf 1501void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
b7b40adb 1502{
783d8bdf
VZ
1503 EnsureIsValid();
1504
b7b40adb
SC
1505 CGRect r = CGRectMake( 00 , 00 , w , h );
1506 CGContextSaveGState( m_cgContext );
1507 CGContextTranslateCTM( m_cgContext, x , y + h );
1508 CGContextScaleCTM( m_cgContext, 1, -1 );
1509 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
1510 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
1511 CGContextRestoreGState( m_cgContext );
1512}
50581042 1513
b7b40adb
SC
1514void wxMacCoreGraphicsContext::PushState()
1515{
783d8bdf
VZ
1516 EnsureIsValid();
1517
b7b40adb
SC
1518 CGContextSaveGState( m_cgContext );
1519}
50581042 1520
783d8bdf 1521void wxMacCoreGraphicsContext::PopState()
b7b40adb 1522{
783d8bdf
VZ
1523 EnsureIsValid();
1524
b7b40adb 1525 CGContextRestoreGState( m_cgContext );
50581042
SC
1526}
1527
783d8bdf 1528void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
50581042
SC
1529{
1530 DrawText(str, x, y, 0.0);
1531}
1532
783d8bdf 1533void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
50581042 1534{
a26b7ab2 1535 if ( m_font.IsNull() )
b7b40adb 1536 return;
783d8bdf
VZ
1537
1538 EnsureIsValid();
1539
50581042
SC
1540 OSStatus status = noErr;
1541 ATSUTextLayout atsuLayout;
1542 UniCharCount chars = str.length();
1543 UniChar* ubuf = NULL;
1544
1545#if SIZEOF_WCHAR_T == 4
1546 wxMBConvUTF16 converter;
1547#if wxUSE_UNICODE
1548 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
1549 ubuf = (UniChar*) malloc( unicharlen + 2 );
1550 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
1551#else
1552 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1553 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1554 ubuf = (UniChar*) malloc( unicharlen + 2 );
1555 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1556#endif
1557 chars = unicharlen / 2;
1558#else
1559#if wxUSE_UNICODE
1560 ubuf = (UniChar*) str.wc_str();
1561#else
1562 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1563 chars = wxWcslen( wchar.data() );
1564 ubuf = (UniChar*) wchar.data();
1565#endif
1566#endif
1567
a26b7ab2 1568 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
50581042 1569 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1570 &chars , &style , &atsuLayout );
50581042
SC
1571
1572 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1573
1574 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
1575 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1576
1577 int iAngle = int( angle * RAD2DEG );
1578 if ( abs(iAngle) > 0 )
1579 {
1580 Fixed atsuAngle = IntToFixed( iAngle );
1581 ATSUAttributeTag atsuTags[] =
1582 {
1583 kATSULineRotationTag ,
1584 };
1585 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1586 {
1587 sizeof( Fixed ) ,
1588 };
1589 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1590 {
1591 &atsuAngle ,
1592 };
1593 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1594 atsuTags, atsuSizes, atsuValues );
1595 }
1596
1597 {
1598 ATSUAttributeTag atsuTags[] =
1599 {
1600 kATSUCGContextTag ,
1601 };
1602 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1603 {
1604 sizeof( CGContextRef ) ,
1605 };
1606 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1607 {
1608 &m_cgContext ,
1609 };
1610 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1611 atsuTags, atsuSizes, atsuValues );
1612 }
1613
1614 ATSUTextMeasurement textBefore, textAfter;
1615 ATSUTextMeasurement ascent, descent;
1616
1617 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1618 &textBefore , &textAfter, &ascent , &descent );
1619
1620 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1621
1622 Rect rect;
1623/*
1624 // TODO
1625 if ( m_backgroundMode == wxSOLID )
1626 {
1627 wxGraphicsPath* path = m_graphicContext->CreatePath();
1628 path->MoveToPoint( drawX , drawY );
1629 path->AddLineToPoint(
1630 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ,
1631 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) );
1632 path->AddLineToPoint(
1633 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1634 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1635 path->AddLineToPoint(
1636 (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1637 (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1638
1639 m_graphicContext->FillPath( path , m_textBackgroundColour );
1640 delete path;
1641 }
1642*/
1643 x += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
1644 y += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
1645
1646 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1647 IntToFixed(x) , IntToFixed(y) , &rect );
1648 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1649
1650 CGContextSaveGState(m_cgContext);
1651 CGContextTranslateCTM(m_cgContext, x, y);
1652 CGContextScaleCTM(m_cgContext, 1, -1);
1653 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1654 IntToFixed(0) , IntToFixed(0) );
1655
1656 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1657
1658 CGContextRestoreGState(m_cgContext);
1659
1660 ::ATSUDisposeTextLayout(atsuLayout);
1661
1662#if SIZEOF_WCHAR_T == 4
1663 free( ubuf );
1664#endif
1665}
783d8bdf 1666
50581042
SC
1667void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1668 wxDouble *descent, wxDouble *externalLeading ) const
1669{
a26b7ab2 1670 wxCHECK_RET( !m_font.IsNull(), wxT("wxDC(cg)::DoGetTextExtent - no valid font set") );
50581042
SC
1671
1672 OSStatus status = noErr;
783d8bdf 1673
50581042
SC
1674 ATSUTextLayout atsuLayout;
1675 UniCharCount chars = str.length();
1676 UniChar* ubuf = NULL;
1677
1678#if SIZEOF_WCHAR_T == 4
1679 wxMBConvUTF16 converter;
1680#if wxUSE_UNICODE
1681 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
1682 ubuf = (UniChar*) malloc( unicharlen + 2 );
1683 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
1684#else
1685 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1686 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1687 ubuf = (UniChar*) malloc( unicharlen + 2 );
1688 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1689#endif
1690 chars = unicharlen / 2;
1691#else
1692#if wxUSE_UNICODE
1693 ubuf = (UniChar*) str.wc_str();
1694#else
1695 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1696 chars = wxWcslen( wchar.data() );
1697 ubuf = (UniChar*) wchar.data();
1698#endif
1699#endif
1700
a26b7ab2 1701 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
50581042 1702 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1703 &chars , &style , &atsuLayout );
50581042
SC
1704
1705 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1706
1707 ATSUTextMeasurement textBefore, textAfter;
1708 ATSUTextMeasurement textAscent, textDescent;
1709
1710 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1711 &textBefore , &textAfter, &textAscent , &textDescent );
1712
1713 if ( height )
1714 *height = FixedToInt(textAscent + textDescent);
1715 if ( descent )
1716 *descent = FixedToInt(textDescent);
1717 if ( externalLeading )
1718 *externalLeading = 0;
1719 if ( width )
1720 *width = FixedToInt(textAfter - textBefore);
1721
1722 ::ATSUDisposeTextLayout(atsuLayout);
1723}
1724
783d8bdf 1725void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
50581042
SC
1726{
1727 widths.Empty();
1728 widths.Add(0, text.length());
1729
1730 if (text.empty())
1731 return;
1732
1733 ATSUTextLayout atsuLayout;
1734 UniCharCount chars = text.length();
1735 UniChar* ubuf = NULL;
1736
1737#if SIZEOF_WCHAR_T == 4
1738 wxMBConvUTF16 converter;
1739#if wxUSE_UNICODE
1740 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 );
1741 ubuf = (UniChar*) malloc( unicharlen + 2 );
1742 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 );
1743#else
1744 const wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1745 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1746 ubuf = (UniChar*) malloc( unicharlen + 2 );
1747 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1748#endif
1749 chars = unicharlen / 2;
1750#else
1751#if wxUSE_UNICODE
1752 ubuf = (UniChar*) text.wc_str();
1753#else
1754 wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1755 chars = wxWcslen( wchar.data() );
1756 ubuf = (UniChar*) wchar.data();
1757#endif
1758#endif
1759
a26b7ab2 1760 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
83b96a06 1761 ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1762 &chars , &style , &atsuLayout );
50581042
SC
1763
1764 for ( int pos = 0; pos < (int)chars; pos ++ )
1765 {
1766 unsigned long actualNumberOfBounds = 0;
1767 ATSTrapezoid glyphBounds;
1768
1769 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1770 OSStatus result;
1771 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
1772 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1773 if (result != noErr || actualNumberOfBounds != 1 )
1774 return;
1775
1776 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
1777 //unsigned char uch = s[i];
1778 }
1779
1780 ::ATSUDisposeTextLayout(atsuLayout);
1781}
1782
783d8bdf 1783void * wxMacCoreGraphicsContext::GetNativeContext()
50581042 1784{
783d8bdf 1785 return m_cgContext;
b7b40adb 1786}
50581042 1787
b7b40adb 1788// concatenates this transform with the current transform of this context
e3ff3591 1789void wxMacCoreGraphicsContext::ConcatTransform( const wxGraphicsMatrix& matrix )
b7b40adb 1790{
549be226
SC
1791 if ( m_cgContext )
1792 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
1793 else
1794 m_windowTransform = CGAffineTransformConcat(m_windowTransform, *(CGAffineTransform*) matrix.GetNativeMatrix());
b7b40adb 1795}
50581042 1796
b7b40adb 1797// sets the transform of this context
e3ff3591 1798void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix& matrix )
b7b40adb 1799{
549be226
SC
1800 if ( m_cgContext )
1801 {
1802 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
1803 transform = CGAffineTransformInvert( transform ) ;
1804 CGContextConcatCTM( m_cgContext, transform);
1805 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
1806 }
1807 else
1808 {
1809 m_windowTransform = *(CGAffineTransform*) matrix.GetNativeMatrix();
1810 }
b7b40adb 1811}
50581042 1812
b7b40adb 1813// gets the matrix of this context
e3ff3591 1814wxGraphicsMatrix wxMacCoreGraphicsContext::GetTransform() const
b7b40adb 1815{
daa6105f 1816 wxGraphicsMatrix m = CreateMatrix();
549be226
SC
1817 *((CGAffineTransform*) m.GetNativeMatrix()) = ( m_cgContext == NULL ? m_windowTransform :
1818 CGContextGetCTM( m_cgContext ));
daa6105f 1819 return m;
b7b40adb 1820}
50581042 1821
b7b40adb
SC
1822//
1823// Renderer
1824//
50581042 1825
b7b40adb
SC
1826//-----------------------------------------------------------------------------
1827// wxMacCoreGraphicsRenderer declaration
1828//-----------------------------------------------------------------------------
50581042 1829
b7b40adb
SC
1830class WXDLLIMPEXP_CORE wxMacCoreGraphicsRenderer : public wxGraphicsRenderer
1831{
1832public :
1833 wxMacCoreGraphicsRenderer() {}
50581042 1834
b7b40adb
SC
1835 virtual ~wxMacCoreGraphicsRenderer() {}
1836
783d8bdf
VZ
1837 // Context
1838
1839 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
b7b40adb 1840
783d8bdf 1841 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
b7b40adb 1842
783d8bdf 1843 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
b7b40adb 1844
783d8bdf
VZ
1845 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1846
1847 // Path
b7b40adb 1848
e3ff3591 1849 virtual wxGraphicsPath CreatePath();
b7b40adb 1850
783d8bdf
VZ
1851 // Matrix
1852
1853 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
1854 wxDouble tx=0.0, wxDouble ty=0.0);
b7b40adb
SC
1855
1856
a26b7ab2 1857 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
783d8bdf 1858
a26b7ab2 1859 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
783d8bdf 1860
b7b40adb 1861 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
783d8bdf 1862 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb
SC
1863 const wxColour&c1, const wxColour&c2) ;
1864
783d8bdf 1865 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
b7b40adb 1866 // with radius r and color cColor
a26b7ab2 1867 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
b7b40adb
SC
1868 const wxColour &oColor, const wxColour &cColor) ;
1869
1870 // sets the font
a26b7ab2 1871 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
b7b40adb
SC
1872
1873private :
1874 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsRenderer)
1875} ;
1876
1877//-----------------------------------------------------------------------------
1878// wxMacCoreGraphicsRenderer implementation
1879//-----------------------------------------------------------------------------
1880
1881IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsRenderer,wxGraphicsRenderer)
1882
1883static wxMacCoreGraphicsRenderer gs_MacCoreGraphicsRenderer;
1884
1885wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1886{
783d8bdf 1887 return &gs_MacCoreGraphicsRenderer;
50581042
SC
1888}
1889
b7b40adb
SC
1890wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc)
1891{
1892 return new wxMacCoreGraphicsContext(this,(CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
1893}
1894
1895wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
1896{
1897 return new wxMacCoreGraphicsContext(this,(CGContextRef)context);
1898}
1899
1900
1901wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( void * window )
1902{
1903 return new wxMacCoreGraphicsContext(this,(WindowRef)window);
1904}
1905
1906wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
1907{
783d8bdf 1908 return new wxMacCoreGraphicsContext(this, window );
b7b40adb
SC
1909}
1910
1911// Path
1912
e3ff3591 1913wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
b7b40adb 1914{
e3ff3591
SC
1915 wxGraphicsPath m;
1916 m.SetRefData( new wxMacCoreGraphicsPathData(this));
1917 return m;
b7b40adb
SC
1918}
1919
1920
1921// Matrix
1922
783d8bdf
VZ
1923wxGraphicsMatrix wxMacCoreGraphicsRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1924 wxDouble tx, wxDouble ty)
1056ddcf 1925{
e3ff3591
SC
1926 wxGraphicsMatrix m;
1927 wxMacCoreGraphicsMatrixData* data = new wxMacCoreGraphicsMatrixData( this );
1928 data->Set( a,b,c,d,tx,ty ) ;
1929 m.SetRefData(data);
b7b40adb
SC
1930 return m;
1931}
1932
783d8bdf 1933wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen)
b7b40adb
SC
1934{
1935 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
a26b7ab2 1936 return wxNullGraphicsPen;
b7b40adb 1937 else
a26b7ab2
SC
1938 {
1939 wxGraphicsPen p;
1940 p.SetRefData(new wxMacCoreGraphicsPenData( this, pen ));
1941 return p;
1942 }
1056ddcf
SC
1943}
1944
783d8bdf 1945wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush )
50581042 1946{
b7b40adb 1947 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
a26b7ab2 1948 return wxNullGraphicsBrush;
b7b40adb 1949 else
a26b7ab2
SC
1950 {
1951 wxGraphicsBrush p;
1952 p.SetRefData(new wxMacCoreGraphicsBrushData( this, brush ));
1953 return p;
1954 }
50581042
SC
1955}
1956
b7b40adb 1957// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
783d8bdf
VZ
1958wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1959 const wxColour&c1, const wxColour&c2)
1056ddcf 1960{
a26b7ab2
SC
1961 wxGraphicsBrush p;
1962 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
1963 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1964 p.SetRefData(d);
1965 return p;
1056ddcf
SC
1966}
1967
783d8bdf 1968// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
b7b40adb 1969// with radius r and color cColor
a26b7ab2 1970wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
783d8bdf 1971 const wxColour &oColor, const wxColour &cColor)
1056ddcf 1972{
a26b7ab2
SC
1973 wxGraphicsBrush p;
1974 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
1975 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1976 p.SetRefData(d);
1977 return p;
1056ddcf
SC
1978}
1979
b7b40adb 1980// sets the font
783d8bdf 1981wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const wxColour &col )
513b47e9 1982{
b7b40adb 1983 if ( font.Ok() )
783d8bdf 1984 {
a26b7ab2
SC
1985 wxGraphicsFont p;
1986 p.SetRefData(new wxMacCoreGraphicsFontData( this , font, col ));
1987 return p;
1988 }
b7b40adb 1989 else
a26b7ab2 1990 return wxNullGraphicsFont;
513b47e9
SC
1991}
1992
b7b40adb
SC
1993
1994
50581042 1995#endif // wxMAC_USE_CORE_GRAPHICS