]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/graphics.cpp
pen.h depends from brush.h in compat mode
[wxWidgets.git] / src / mac / carbon / graphics.cpp
... / ...
CommitLineData
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
46CGColorSpaceRef 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
58int 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
74const double M_PI = 3.14159265358979;
75#endif
76#endif
77
78static 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
87OSStatus 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
101CGColorRef 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
124CTFontRef 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
137class wxMacCoreGraphicsPattern
138{
139public :
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
147protected :
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
172const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCoreGraphicsPattern::_Render, &wxMacCoreGraphicsPattern::_Dispose };
173
174class ImagePattern : public wxMacCoreGraphicsPattern
175{
176public :
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
200protected :
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
224class HatchPattern : public wxMacCoreGraphicsPattern
225{
226public :
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
313protected :
314 virtual ~HatchPattern() {}
315
316 CGRect m_imageBounds;
317 int m_hatch;
318};
319
320class wxMacCoreGraphicsPenData : public wxGraphicsObjectRefData
321{
322public:
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
330protected :
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
348wxMacCoreGraphicsPenData::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
485wxMacCoreGraphicsPenData::~wxMacCoreGraphicsPenData()
486{
487 delete[] m_userLengths;
488 delete[] m_patternColorComponents;
489}
490
491void 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
501void 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
532static 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
544wxBitmap 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
548class 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
566wxMacCoreGraphicsColour::~wxMacCoreGraphicsColour()
567{
568 delete[] m_patternColorComponents;
569}
570
571void wxMacCoreGraphicsColour::Init()
572{
573 m_isPattern = false;
574 m_patternColorComponents = NULL;
575}
576
577void 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
592wxMacCoreGraphicsColour::wxMacCoreGraphicsColour()
593{
594 Init();
595}
596
597wxMacCoreGraphicsColour::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
631class wxMacCoreGraphicsBrushData : public wxGraphicsObjectRefData
632{
633public:
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; }
646protected:
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
659wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer )
660{
661 Init();
662}
663
664void 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
672void 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
680wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : wxGraphicsObjectRefData( renderer ),
681 m_cgColor( brush )
682{
683 Init();
684
685}
686
687wxMacCoreGraphicsBrushData::~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
698void wxMacCoreGraphicsBrushData::Init()
699{
700 m_gradientFunction = NULL;
701 m_shading = NULL;
702 m_gradientComponents = NULL;
703 m_isShading = false;
704}
705
706void 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
720void 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
730CGFunctionRef 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
756class wxMacCoreGraphicsFontData : public wxGraphicsObjectRefData
757{
758public:
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 ; }
771private :
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
782wxMacCoreGraphicsFontData::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
829wxMacCoreGraphicsFontData::~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
844class wxMacCoreGraphicsBitmapData : public wxGraphicsObjectRefData
845{
846public:
847 wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap );
848 ~wxMacCoreGraphicsBitmapData();
849
850 virtual CGImageRef GetBitmap() { return m_bitmap; }
851private :
852 CGImageRef m_bitmap;
853};
854
855wxMacCoreGraphicsBitmapData::wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap ) : wxGraphicsObjectRefData( renderer )
856{
857 m_bitmap = bitmap;
858}
859
860wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData()
861{
862 CGImageRelease( m_bitmap );
863}
864
865//
866// Graphics Matrix
867//
868
869//-----------------------------------------------------------------------------
870// wxMacCoreGraphicsMatrix declaration
871//-----------------------------------------------------------------------------
872
873class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData
874{
875public :
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
928private :
929 CGAffineTransform m_matrix;
930} ;
931
932//-----------------------------------------------------------------------------
933// wxMacCoreGraphicsMatrix implementation
934//-----------------------------------------------------------------------------
935
936wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
937{
938}
939
940wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData()
941{
942}
943
944wxGraphicsObjectRefData *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
952void 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
958void 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
965void 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
977void wxMacCoreGraphicsMatrixData::Invert()
978{
979 m_matrix = CGAffineTransformInvert( m_matrix );
980}
981
982// returns true if the elements of the transformation matrix are equal ?
983bool 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
989bool 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
1000void wxMacCoreGraphicsMatrixData::Translate( wxDouble dx , wxDouble dy )
1001{
1002 m_matrix = CGAffineTransformTranslate( m_matrix, dx, dy);
1003}
1004
1005// add the scale to this matrix
1006void 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)
1012void 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
1022void 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
1031void 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
1039void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const
1040{
1041 return (void*) &m_matrix;
1042}
1043
1044//
1045// Graphics Path
1046//
1047
1048//-----------------------------------------------------------------------------
1049// wxMacCoreGraphicsPath declaration
1050//-----------------------------------------------------------------------------
1051
1052class WXDLLEXPORT wxMacCoreGraphicsPathData : public wxGraphicsPathData
1053{
1054public :
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;
1112private :
1113 CGMutablePathRef m_path;
1114};
1115
1116//-----------------------------------------------------------------------------
1117// wxMacCoreGraphicsPath implementation
1118//-----------------------------------------------------------------------------
1119
1120wxMacCoreGraphicsPathData::wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPathData(renderer)
1121{
1122 if ( path )
1123 m_path = path;
1124 else
1125 m_path = CGPathCreateMutable();
1126}
1127
1128wxMacCoreGraphicsPathData::~wxMacCoreGraphicsPathData()
1129{
1130 CGPathRelease( m_path );
1131}
1132
1133wxGraphicsObjectRefData* 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
1141void wxMacCoreGraphicsPathData::MoveToPoint( wxDouble x1 , wxDouble y1 )
1142{
1143 CGPathMoveToPoint( m_path , NULL , x1 , y1 );
1144}
1145
1146void wxMacCoreGraphicsPathData::AddLineToPoint( wxDouble x1 , wxDouble y1 )
1147{
1148 CGPathAddLineToPoint( m_path , NULL , x1 , y1 );
1149}
1150
1151void 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
1156void wxMacCoreGraphicsPathData::AddQuadCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble x, wxDouble y )
1157{
1158 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x , y );
1159}
1160
1161void 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
1167void 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
1173void 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
1179void 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
1184void wxMacCoreGraphicsPathData::AddPath( const wxGraphicsPathData* path )
1185{
1186 CGPathAddPath( m_path , NULL, (CGPathRef) path->GetNativePath() );
1187}
1188
1189// closes the current subpath
1190void wxMacCoreGraphicsPathData::CloseSubpath()
1191{
1192 CGPathCloseSubpath( m_path );
1193}
1194
1195// gets the last point of the current path, (0,0) if not yet set
1196void 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
1204void 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)
1213void 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
1222bool 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
1235class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
1236{
1237public:
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
1352private:
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
1381IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
1382
1383class wxQuartzOffsetHelper
1384{
1385public :
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 }
1398public :
1399 CGContextRef m_cg;
1400 bool m_offset;
1401} ;
1402
1403void 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
1414wxMacCoreGraphicsContext::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
1422wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer)
1423{
1424 Init();
1425 m_windowRef = window;
1426}
1427
1428wxMacCoreGraphicsContext::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
1447wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
1448{
1449 Init();
1450}
1451
1452wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
1453{
1454 Init();
1455 wxLogDebug(wxT("Illegal Constructor called"));
1456}
1457
1458wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
1459{
1460 SetNativeContext(NULL);
1461}
1462
1463void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height)
1464{
1465 *width = m_width;
1466 *height = m_height;
1467}
1468
1469
1470void 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
1483void wxMacCoreGraphicsContext::EndPage()
1484{
1485 CGContextEndPage(m_cgContext);
1486}
1487
1488void wxMacCoreGraphicsContext::Flush()
1489{
1490 CGContextFlush(m_cgContext);
1491}
1492
1493void 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 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
1504
1505 CGContextConcatCTM( m_cgContext, m_windowTransform );
1506 CGContextSaveGState( m_cgContext );
1507 m_releaseContext = true;
1508 if ( !HIShapeIsEmpty(m_clipRgn) )
1509 {
1510 // the clip region is in device coordinates, so we convert this again to user coordinates
1511 wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
1512 CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
1513 HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
1514 HIShapeReplacePathInCGContext( hishape, m_cgContext );
1515 CGContextClip( m_cgContext );
1516 }
1517 CGContextSaveGState( m_cgContext );
1518 }
1519}
1520
1521// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes)
1522
1523bool wxMacCoreGraphicsContext::SetLogicalFunction( int function )
1524{
1525 if (m_logicalFunction == function)
1526 return true;
1527
1528 EnsureIsValid();
1529
1530 bool retval = false;
1531 bool shouldAntiAlias = true;
1532 CGBlendMode mode = kCGBlendModeNormal;
1533
1534#if defined(__WXMAC__) && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 )
1535 if ( UMAGetSystemVersion() >= 0x1050 )
1536 {
1537 retval = true;
1538 switch ( function )
1539 {
1540 // TODO find best corresponding porter duff modes
1541 case wxCOPY :
1542 mode = kCGBlendModeCopy;
1543 break;
1544 case wxCLEAR :
1545 mode = kCGBlendModeClear;
1546 break;
1547 case wxXOR :
1548 mode = kCGBlendModeXOR;
1549 shouldAntiAlias = false;
1550 break;
1551 default :
1552 retval = false;
1553 break;
1554 }
1555 }
1556 else
1557#endif
1558 {
1559 if ( function == wxCOPY )
1560 {
1561 retval = true;
1562 }
1563 else if ( function == wxINVERT || function == wxXOR )
1564 {
1565 // change color to white
1566 mode = kCGBlendModeExclusion;
1567 shouldAntiAlias = false;
1568 retval = true;
1569 }
1570 }
1571
1572 if (retval)
1573 {
1574 m_logicalFunction = function;
1575 CGContextSetBlendMode( m_cgContext, mode );
1576 CGContextSetShouldAntialias(m_cgContext, shouldAntiAlias);
1577 }
1578 return retval ;
1579}
1580
1581void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
1582{
1583#ifdef __WXMAC__
1584 if( m_cgContext )
1585 {
1586 HIShapeReplacePathInCGContext( region.GetWXHRGN() , m_cgContext );
1587 CGContextClip( m_cgContext );
1588 }
1589 else
1590 {
1591 // this offsetting to device coords is not really correct, but since we cannot apply affine transforms
1592 // to regions we try at least to have correct translations
1593 HIMutableShapeRef mutableShape = HIShapeCreateMutableCopy( region.GetWXHRGN() );
1594
1595 CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero, m_windowTransform );
1596 HIShapeOffset( mutableShape, transformedOrigin.x, transformedOrigin.y );
1597 m_clipRgn.reset(mutableShape);
1598 }
1599#endif
1600}
1601
1602// clips drawings to the rect
1603void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1604{
1605 CGRect r = CGRectMake( x , y , w , h );
1606 if ( m_cgContext )
1607 {
1608 CGContextClipToRect( m_cgContext, r );
1609 }
1610 else
1611 {
1612 // the clipping itself must be stored as device coordinates, otherwise
1613 // we cannot apply it back correctly
1614 r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform );
1615 m_clipRgn.reset(HIShapeCreateWithRect(&r));
1616 }
1617}
1618
1619 // resets the clipping to original extent
1620void wxMacCoreGraphicsContext::ResetClip()
1621{
1622 if ( m_cgContext )
1623 {
1624 // there is no way for clearing the clip, we can only revert to the stored
1625 // state, but then we have to make sure everything else is NOT restored
1626 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
1627 CGContextRestoreGState( m_cgContext );
1628 CGContextSaveGState( m_cgContext );
1629 CGAffineTransform transformNew = CGContextGetCTM( m_cgContext );
1630 transformNew = CGAffineTransformInvert( transformNew ) ;
1631 CGContextConcatCTM( m_cgContext, transformNew);
1632 CGContextConcatCTM( m_cgContext, transform);
1633 }
1634 else
1635 {
1636 CGRect r = CGRectMake(0,0,0,0);
1637 m_clipRgn.reset(HIShapeCreateWithRect(&r));
1638 }
1639}
1640
1641void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
1642{
1643 if ( m_pen.IsNull() )
1644 return ;
1645
1646 EnsureIsValid();
1647
1648 wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
1649
1650 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
1651 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1652 CGContextStrokePath( m_cgContext );
1653}
1654
1655void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillStyle )
1656{
1657 if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
1658 {
1659 // when using shading, we cannot draw pen and brush at the same time
1660 // revert to the base implementation of first filling and then stroking
1661 wxGraphicsContext::DrawPath( path, fillStyle );
1662 return;
1663 }
1664
1665 CGPathDrawingMode mode = kCGPathFill ;
1666 if ( m_brush.IsNull() )
1667 {
1668 if ( m_pen.IsNull() )
1669 return;
1670 else
1671 mode = kCGPathStroke;
1672 }
1673 else
1674 {
1675 if ( m_pen.IsNull() )
1676 {
1677 if ( fillStyle == wxODDEVEN_RULE )
1678 mode = kCGPathEOFill;
1679 else
1680 mode = kCGPathFill;
1681 }
1682 else
1683 {
1684 if ( fillStyle == wxODDEVEN_RULE )
1685 mode = kCGPathEOFillStroke;
1686 else
1687 mode = kCGPathFillStroke;
1688 }
1689 }
1690
1691 EnsureIsValid();
1692
1693 if ( !m_brush.IsNull() )
1694 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1695 if ( !m_pen.IsNull() )
1696 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
1697
1698 wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
1699
1700 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1701 CGContextDrawPath( m_cgContext , mode );
1702}
1703
1704void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , int fillStyle )
1705{
1706 if ( m_brush.IsNull() )
1707 return;
1708
1709 EnsureIsValid();
1710
1711 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
1712 {
1713 CGContextSaveGState( m_cgContext );
1714 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1715 CGContextClip( m_cgContext );
1716 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
1717 CGContextRestoreGState( m_cgContext);
1718 }
1719 else
1720 {
1721 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1722 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1723 if ( fillStyle == wxODDEVEN_RULE )
1724 CGContextEOFillPath( m_cgContext );
1725 else
1726 CGContextFillPath( m_cgContext );
1727 }
1728}
1729
1730void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
1731{
1732 // we allow either setting or clearing but not replacing
1733 wxASSERT( m_cgContext == NULL || cg == NULL );
1734
1735 if ( m_cgContext )
1736 {
1737 // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
1738 CGContextRestoreGState( m_cgContext );
1739 CGContextRestoreGState( m_cgContext );
1740 if ( m_releaseContext )
1741 {
1742#if ! ( defined( __LP64__ ) || defined(__WXCOCOA__) )
1743 QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
1744#endif
1745 }
1746 else
1747 CGContextRelease(m_cgContext);
1748 }
1749
1750
1751 m_cgContext = cg;
1752
1753 // FIXME: This check is needed because currently we need to use a DC/GraphicsContext
1754 // in order to get font properties, like wxFont::GetPixelSize, but since we don't have
1755 // a native window attached to use, I create a wxGraphicsContext with a NULL CGContextRef
1756 // for this one operation.
1757
1758 // When wxFont::GetPixelSize on Mac no longer needs a graphics context, this check
1759 // can be removed.
1760 if (m_cgContext)
1761 {
1762 CGContextRetain(m_cgContext);
1763 CGContextSaveGState( m_cgContext );
1764 CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity );
1765 CGContextSaveGState( m_cgContext );
1766 m_releaseContext = false;
1767 }
1768}
1769
1770void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy )
1771{
1772 if ( m_cgContext )
1773 CGContextTranslateCTM( m_cgContext, dx, dy );
1774 else
1775 m_windowTransform = CGAffineTransformTranslate(m_windowTransform,dx,dy);
1776}
1777
1778void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
1779{
1780 if ( m_cgContext )
1781 CGContextScaleCTM( m_cgContext , xScale , yScale );
1782 else
1783 m_windowTransform = CGAffineTransformScale(m_windowTransform,xScale,yScale);
1784}
1785
1786void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
1787{
1788 if ( m_cgContext )
1789 CGContextRotateCTM( m_cgContext , angle );
1790 else
1791 m_windowTransform = CGAffineTransformRotate(m_windowTransform,angle);
1792}
1793
1794void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1795{
1796 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
1797 DrawBitmap(bitmap, x, y, w, h);
1798}
1799
1800void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1801{
1802 EnsureIsValid();
1803#ifdef __WXMAC__
1804 CGImageRef image = static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData())->GetBitmap();
1805 CGRect r = CGRectMake( x , y , w , h );
1806 // if ( bmp.GetDepth() == 1 )
1807 {
1808 // is is a mask, the '1' in the mask tell where to draw the current brush
1809 if ( !m_brush.IsNull() )
1810 {
1811 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
1812 {
1813 // TODO clip to mask
1814 /*
1815 CGContextSaveGState( m_cgContext );
1816 CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
1817 CGContextClip( m_cgContext );
1818 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
1819 CGContextRestoreGState( m_cgContext);
1820 */
1821 }
1822 else
1823 {
1824 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1825 wxMacDrawCGImage( m_cgContext , &r , image );
1826 }
1827 }
1828 }
1829 /*
1830 else
1831 {
1832 wxMacDrawCGImage( m_cgContext , &r , image );
1833 }
1834 CGImageRelease( image );
1835 */
1836#endif
1837}
1838
1839void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1840{
1841 EnsureIsValid();
1842
1843 CGRect r = CGRectMake( 00 , 00 , w , h );
1844 CGContextSaveGState( m_cgContext );
1845 CGContextTranslateCTM( m_cgContext, x , y + h );
1846 CGContextScaleCTM( m_cgContext, 1, -1 );
1847#ifdef __WXMAC__
1848 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
1849 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
1850#endif
1851 CGContextRestoreGState( m_cgContext );
1852}
1853
1854void wxMacCoreGraphicsContext::PushState()
1855{
1856 EnsureIsValid();
1857
1858 CGContextSaveGState( m_cgContext );
1859}
1860
1861void wxMacCoreGraphicsContext::PopState()
1862{
1863 EnsureIsValid();
1864
1865 CGContextRestoreGState( m_cgContext );
1866}
1867
1868void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1869{
1870 if ( m_font.IsNull() )
1871 return;
1872
1873 EnsureIsValid();
1874#if wxMAC_USE_CORE_TEXT
1875 if ( UMAGetSystemVersion() >= 0x1050 )
1876 {
1877 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
1878 wxCFStringRef text(str, wxLocale::GetSystemEncoding() );
1879 CTFontRef font = fref->GetCTFont();
1880 CGColorRef col = wxMacCreateCGColor( fref->GetColour() );
1881 CTUnderlineStyle ustyle = fref->GetUnderlined() ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone ;
1882 wxCFRef<CFNumberRef> underlined( CFNumberCreate(NULL, kCFNumberSInt32Type, &ustyle) );
1883 CFStringRef keys[] = { kCTFontAttributeName , kCTForegroundColorAttributeName, kCTUnderlineStyleAttributeName };
1884 CFTypeRef values[] = { font, col, underlined };
1885 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
1886 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
1887 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
1888 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
1889
1890 y += CTFontGetAscent(font);
1891
1892 CGContextSaveGState(m_cgContext);
1893 CGContextTranslateCTM(m_cgContext, x, y);
1894 CGContextScaleCTM(m_cgContext, 1, -1);
1895 CGContextSetTextPosition(m_cgContext, 0, 0);
1896 CTLineDraw( line, m_cgContext );
1897 CGContextRestoreGState(m_cgContext);
1898 CFRelease( col );
1899 return;
1900 }
1901#endif
1902#if wxMAC_USE_ATSU_TEXT
1903 {
1904 DrawText(str, x, y, 0.0);
1905 return;
1906 }
1907#endif
1908#if wxMAC_USE_CG_TEXT
1909 // TODO core graphics text implementation here
1910#endif
1911}
1912
1913void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
1914{
1915 if ( m_font.IsNull() )
1916 return;
1917
1918 EnsureIsValid();
1919#if wxMAC_USE_CORE_TEXT
1920 if ( UMAGetSystemVersion() >= 0x1050 )
1921 {
1922 // default implementation takes care of rotation and calls non rotated DrawText afterwards
1923 wxGraphicsContext::DrawText( str, x, y, angle );
1924 return;
1925 }
1926#endif
1927#if wxMAC_USE_ATSU_TEXT
1928 {
1929 OSStatus status = noErr;
1930 ATSUTextLayout atsuLayout;
1931 wxMacUniCharBuffer unibuf( str );
1932 UniCharCount chars = unibuf.GetChars();
1933
1934 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
1935 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
1936 &chars , &style , &atsuLayout );
1937
1938 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1939
1940 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
1941 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1942
1943 int iAngle = int( angle * RAD2DEG );
1944 if ( abs(iAngle) > 0 )
1945 {
1946 Fixed atsuAngle = IntToFixed( iAngle );
1947 ATSUAttributeTag atsuTags[] =
1948 {
1949 kATSULineRotationTag ,
1950 };
1951 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1952 {
1953 sizeof( Fixed ) ,
1954 };
1955 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1956 {
1957 &atsuAngle ,
1958 };
1959 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1960 atsuTags, atsuSizes, atsuValues );
1961 }
1962
1963 {
1964 ATSUAttributeTag atsuTags[] =
1965 {
1966 kATSUCGContextTag ,
1967 };
1968 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1969 {
1970 sizeof( CGContextRef ) ,
1971 };
1972 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1973 {
1974 &m_cgContext ,
1975 };
1976 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1977 atsuTags, atsuSizes, atsuValues );
1978 }
1979
1980 ATSUTextMeasurement textBefore, textAfter;
1981 ATSUTextMeasurement ascent, descent;
1982
1983 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1984 &textBefore , &textAfter, &ascent , &descent );
1985
1986 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1987
1988 Rect rect;
1989 x += (int)(sin(angle) * FixedToInt(ascent));
1990 y += (int)(cos(angle) * FixedToInt(ascent));
1991
1992 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1993 IntToFixed(x) , IntToFixed(y) , &rect );
1994 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1995
1996 CGContextSaveGState(m_cgContext);
1997 CGContextTranslateCTM(m_cgContext, x, y);
1998 CGContextScaleCTM(m_cgContext, 1, -1);
1999 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
2000 IntToFixed(0) , IntToFixed(0) );
2001
2002 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
2003
2004 CGContextRestoreGState(m_cgContext);
2005
2006 ::ATSUDisposeTextLayout(atsuLayout);
2007
2008 return;
2009 }
2010#endif
2011#if wxMAC_USE_CG_TEXT
2012 // default implementation takes care of rotation and calls non rotated DrawText afterwards
2013 wxGraphicsContext::DrawText( str, x, y, angle );
2014#endif
2015}
2016
2017void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
2018 wxDouble *descent, wxDouble *externalLeading ) const
2019{
2020 wxCHECK_RET( !m_font.IsNull(), wxT("wxDC(cg)::DoGetTextExtent - no valid font set") );
2021
2022 if ( width )
2023 *width = 0;
2024 if ( height )
2025 *height = 0;
2026 if ( descent )
2027 *descent = 0;
2028 if ( externalLeading )
2029 *externalLeading = 0;
2030
2031 if (str.empty())
2032 return;
2033
2034#if wxMAC_USE_CORE_TEXT
2035 if ( UMAGetSystemVersion() >= 0x1050 )
2036 {
2037 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
2038 CTFontRef font = fref->GetCTFont();
2039
2040 wxCFStringRef text(str, wxLocale::GetSystemEncoding() );
2041 CFStringRef keys[] = { kCTFontAttributeName };
2042 CFTypeRef values[] = { font };
2043 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
2044 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
2045 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
2046 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
2047
2048 CGFloat w, a, d, l;
2049
2050 w = CTLineGetTypographicBounds(line, &a, &d, &l) ;
2051
2052 if ( height )
2053 *height = a+d+l;
2054 if ( descent )
2055 *descent = d;
2056 if ( externalLeading )
2057 *externalLeading = l;
2058 if ( width )
2059 *width = w;
2060 return;
2061 }
2062#endif
2063#if wxMAC_USE_ATSU_TEXT
2064 {
2065 OSStatus status = noErr;
2066
2067 ATSUTextLayout atsuLayout;
2068 wxMacUniCharBuffer unibuf( str );
2069 UniCharCount chars = unibuf.GetChars();
2070
2071 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
2072 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
2073 &chars , &style , &atsuLayout );
2074
2075 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
2076
2077 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
2078 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
2079
2080 ATSUTextMeasurement textBefore, textAfter;
2081 ATSUTextMeasurement textAscent, textDescent;
2082
2083 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
2084 &textBefore , &textAfter, &textAscent , &textDescent );
2085
2086 if ( height )
2087 *height = FixedToInt(textAscent + textDescent);
2088 if ( descent )
2089 *descent = FixedToInt(textDescent);
2090 if ( externalLeading )
2091 *externalLeading = 0;
2092 if ( width )
2093 *width = FixedToInt(textAfter - textBefore);
2094
2095 ::ATSUDisposeTextLayout(atsuLayout);
2096
2097 return;
2098 }
2099#endif
2100#if wxMAC_USE_CG_TEXT
2101 // TODO core graphics text implementation here
2102#endif
2103}
2104
2105void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
2106{
2107 widths.Empty();
2108 widths.Add(0, text.length());
2109
2110 if (text.empty())
2111 return;
2112
2113#if wxMAC_USE_CORE_TEXT
2114 {
2115 wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData();
2116 CTFontRef font = fref->GetCTFont();
2117
2118 wxCFStringRef t(text, wxLocale::GetSystemEncoding() );
2119 CFStringRef keys[] = { kCTFontAttributeName };
2120 CFTypeRef values[] = { font };
2121 wxCFRef<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
2122 WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
2123 wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, t, attributes) );
2124 wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
2125
2126 int chars = text.length();
2127 for ( int pos = 0; pos < (int)chars; pos ++ )
2128 {
2129 widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL )+0.5;
2130 }
2131
2132 return;
2133 }
2134#endif
2135#if wxMAC_USE_ATSU_TEXT
2136 {
2137 OSStatus status = noErr;
2138 ATSUTextLayout atsuLayout;
2139 wxMacUniCharBuffer unibuf( text );
2140 UniCharCount chars = unibuf.GetChars();
2141
2142 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
2143 status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
2144 &chars , &style , &atsuLayout );
2145
2146 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
2147
2148 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
2149 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
2150
2151 for ( int pos = 0; pos < (int)chars; pos ++ )
2152 {
2153 unsigned long actualNumberOfBounds = 0;
2154 ATSTrapezoid glyphBounds;
2155
2156 // We get a single bound, since the text should only require one. If it requires more, there is an issue
2157 OSStatus result;
2158 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
2159 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
2160 if (result != noErr || actualNumberOfBounds != 1 )
2161 return;
2162
2163 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
2164 //unsigned char uch = s[i];
2165 }
2166
2167 ::ATSUDisposeTextLayout(atsuLayout);
2168 }
2169#endif
2170#if wxMAC_USE_CG_TEXT
2171 // TODO core graphics text implementation here
2172#endif
2173}
2174
2175void * wxMacCoreGraphicsContext::GetNativeContext()
2176{
2177 return m_cgContext;
2178}
2179
2180// concatenates this transform with the current transform of this context
2181void wxMacCoreGraphicsContext::ConcatTransform( const wxGraphicsMatrix& matrix )
2182{
2183 if ( m_cgContext )
2184 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
2185 else
2186 m_windowTransform = CGAffineTransformConcat(m_windowTransform, *(CGAffineTransform*) matrix.GetNativeMatrix());
2187}
2188
2189// sets the transform of this context
2190void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix& matrix )
2191{
2192 if ( m_cgContext )
2193 {
2194 CGAffineTransform transform = CGContextGetCTM( m_cgContext );
2195 transform = CGAffineTransformInvert( transform ) ;
2196 CGContextConcatCTM( m_cgContext, transform);
2197 CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix());
2198 }
2199 else
2200 {
2201 m_windowTransform = *(CGAffineTransform*) matrix.GetNativeMatrix();
2202 }
2203}
2204
2205// gets the matrix of this context
2206wxGraphicsMatrix wxMacCoreGraphicsContext::GetTransform() const
2207{
2208 wxGraphicsMatrix m = CreateMatrix();
2209 *((CGAffineTransform*) m.GetNativeMatrix()) = ( m_cgContext == NULL ? m_windowTransform :
2210 CGContextGetCTM( m_cgContext ));
2211 return m;
2212}
2213
2214//
2215// Renderer
2216//
2217
2218//-----------------------------------------------------------------------------
2219// wxMacCoreGraphicsRenderer declaration
2220//-----------------------------------------------------------------------------
2221
2222class WXDLLIMPEXP_CORE wxMacCoreGraphicsRenderer : public wxGraphicsRenderer
2223{
2224public :
2225 wxMacCoreGraphicsRenderer() {}
2226
2227 virtual ~wxMacCoreGraphicsRenderer() {}
2228
2229 // Context
2230
2231 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
2232 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
2233
2234 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
2235
2236 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
2237
2238 virtual wxGraphicsContext * CreateContext( wxWindow* window );
2239
2240 virtual wxGraphicsContext * CreateMeasuringContext();
2241
2242 // Path
2243
2244 virtual wxGraphicsPath CreatePath();
2245
2246 // Matrix
2247
2248 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
2249 wxDouble tx=0.0, wxDouble ty=0.0);
2250
2251
2252 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
2253
2254 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
2255
2256 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
2257 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
2258 const wxColour&c1, const wxColour&c2) ;
2259
2260 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
2261 // with radius r and color cColor
2262 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
2263 const wxColour &oColor, const wxColour &cColor) ;
2264
2265 // sets the font
2266 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
2267
2268 // create a native bitmap representation
2269 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) ;
2270
2271 // create a native bitmap representation
2272 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
2273private :
2274 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsRenderer)
2275} ;
2276
2277//-----------------------------------------------------------------------------
2278// wxMacCoreGraphicsRenderer implementation
2279//-----------------------------------------------------------------------------
2280
2281IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsRenderer,wxGraphicsRenderer)
2282
2283static wxMacCoreGraphicsRenderer gs_MacCoreGraphicsRenderer;
2284
2285wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
2286{
2287 return &gs_MacCoreGraphicsRenderer;
2288}
2289
2290#ifdef __WXCOCOA__
2291extern CGContextRef wxMacGetContextFromCurrentNSContext() ;
2292#endif
2293
2294wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc )
2295{
2296 const wxDCImpl* impl = dc.GetImpl();
2297 wxWindowDCImpl *win_impl = wxDynamicCast( impl, wxWindowDCImpl );
2298 if (win_impl)
2299 {
2300 int w, h;
2301 win_impl->GetSize( &w, &h );
2302 CGContextRef cgctx = 0;
2303#ifdef __WXMAC__
2304 cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef());
2305#else
2306 cgctx = wxMacGetContextFromCurrentNSContext() ;
2307#endif
2308 return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h );
2309 }
2310 return NULL;
2311}
2312
2313wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC& dc )
2314{
2315#ifdef __WXMAC__
2316 const wxDCImpl* impl = dc.GetImpl();
2317 wxMemoryDCImpl *mem_impl = wxDynamicCast( impl, wxMemoryDCImpl );
2318 if (mem_impl)
2319 {
2320 int w, h;
2321 mem_impl->GetSize( &w, &h );
2322 return new wxMacCoreGraphicsContext( this,
2323 (CGContextRef)(mem_impl->GetGraphicsContext()->GetNativeContext()), (wxDouble) w, (wxDouble) h );
2324 }
2325#endif
2326 return NULL;
2327}
2328
2329wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
2330{
2331 return new wxMacCoreGraphicsContext(this,(CGContextRef)context);
2332}
2333
2334
2335wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( void * window )
2336{
2337 return new wxMacCoreGraphicsContext(this,(WindowRef)window);
2338}
2339
2340wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
2341{
2342 return new wxMacCoreGraphicsContext(this, window );
2343}
2344
2345wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateMeasuringContext()
2346{
2347 return new wxMacCoreGraphicsContext(this);
2348}
2349
2350// Path
2351
2352wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
2353{
2354 wxGraphicsPath m;
2355 m.SetRefData( new wxMacCoreGraphicsPathData(this));
2356 return m;
2357}
2358
2359
2360// Matrix
2361
2362wxGraphicsMatrix wxMacCoreGraphicsRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
2363 wxDouble tx, wxDouble ty)
2364{
2365 wxGraphicsMatrix m;
2366 wxMacCoreGraphicsMatrixData* data = new wxMacCoreGraphicsMatrixData( this );
2367 data->Set( a,b,c,d,tx,ty ) ;
2368 m.SetRefData(data);
2369 return m;
2370}
2371
2372wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen)
2373{
2374 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
2375 return wxNullGraphicsPen;
2376 else
2377 {
2378 wxGraphicsPen p;
2379 p.SetRefData(new wxMacCoreGraphicsPenData( this, pen ));
2380 return p;
2381 }
2382}
2383
2384wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush )
2385{
2386 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
2387 return wxNullGraphicsBrush;
2388 else
2389 {
2390 wxGraphicsBrush p;
2391 p.SetRefData(new wxMacCoreGraphicsBrushData( this, brush ));
2392 return p;
2393 }
2394}
2395
2396wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmap( const wxBitmap& bmp )
2397{
2398 if ( bmp.Ok() )
2399 {
2400 wxGraphicsBitmap p;
2401#ifdef __WXMAC__
2402 p.SetRefData(new wxMacCoreGraphicsBitmapData( this , bmp.CreateCGImage() ) );
2403#endif
2404 return p;
2405 }
2406 else
2407 return wxNullGraphicsBitmap;
2408}
2409
2410wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateSubBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2411{
2412 CGImageRef img = static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData())->GetBitmap();
2413 if ( img )
2414 {
2415 wxGraphicsBitmap p;
2416 CGImageRef subimg = CGImageCreateWithImageInRect(img,CGRectMake( x , y , w , h ));
2417 p.SetRefData(new wxMacCoreGraphicsBitmapData( this , subimg ) );
2418 return p;
2419 }
2420 else
2421 return wxNullGraphicsBitmap;
2422}
2423
2424// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
2425wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
2426 const wxColour&c1, const wxColour&c2)
2427{
2428 wxGraphicsBrush p;
2429 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
2430 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
2431 p.SetRefData(d);
2432 return p;
2433}
2434
2435// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
2436// with radius r and color cColor
2437wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
2438 const wxColour &oColor, const wxColour &cColor)
2439{
2440 wxGraphicsBrush p;
2441 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
2442 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
2443 p.SetRefData(d);
2444 return p;
2445}
2446
2447// sets the font
2448wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const wxColour &col )
2449{
2450 if ( font.Ok() )
2451 {
2452 wxGraphicsFont p;
2453 p.SetRefData(new wxMacCoreGraphicsFontData( this , font, col ));
2454 return p;
2455 }
2456 else
2457 return wxNullGraphicsFont;
2458}
2459
2460//
2461// CoreGraphics Helper Methods
2462//
2463
2464// Data Providers and Consumers
2465
2466size_t UMAPutBytesCFRefCallback( void *info, const void *bytes, size_t count )
2467{
2468 CFMutableDataRef data = (CFMutableDataRef) info;
2469 if ( data )
2470 {
2471 CFDataAppendBytes( data, (const UInt8*) bytes, count );
2472 }
2473 return count;
2474}
2475
2476void wxMacReleaseCFDataProviderCallback(void *info,
2477 const void *WXUNUSED(data),
2478 size_t WXUNUSED(count))
2479{
2480 if ( info )
2481 CFRelease( (CFDataRef) info );
2482}
2483
2484void wxMacReleaseCFDataConsumerCallback( void *info )
2485{
2486 if ( info )
2487 CFRelease( (CFDataRef) info );
2488}
2489
2490CGDataProviderRef wxMacCGDataProviderCreateWithCFData( CFDataRef data )
2491{
2492 if ( data == NULL )
2493 return NULL;
2494
2495 return CGDataProviderCreateWithCFData( data );
2496}
2497
2498CGDataConsumerRef wxMacCGDataConsumerCreateWithCFData( CFMutableDataRef data )
2499{
2500 if ( data == NULL )
2501 return NULL;
2502
2503 return CGDataConsumerCreateWithCFData( data );
2504}
2505
2506void wxMacReleaseMemoryBufferProviderCallback(void *info, const void *data, size_t WXUNUSED(size))
2507{
2508 wxMemoryBuffer* membuf = (wxMemoryBuffer*) info ;
2509
2510 wxASSERT( data == membuf->GetData() ) ;
2511
2512 delete membuf ;
2513}
2514
2515CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf )
2516{
2517 wxMemoryBuffer* b = new wxMemoryBuffer( buf );
2518 if ( b->GetDataLen() == 0 )
2519 return NULL;
2520
2521 return CGDataProviderCreateWithData( b , (const void *) b->GetData() , b->GetDataLen() ,
2522 wxMacReleaseMemoryBufferProviderCallback );
2523}