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