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