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