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