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