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