]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/graphics.cpp
paint event handling fixes and wxClientDC implementation for osx-cocoa
[wxWidgets.git] / src / osx / carbon / graphics.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/dccg.cpp
3 // Purpose: wxDC class
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/graphics.h"
15 #include "wx/private/graphics.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/dcclient.h"
19 #include "wx/dcmemory.h"
20 #include "wx/dcprint.h"
21 #include "wx/log.h"
22 #include "wx/region.h"
23 #include "wx/image.h"
24 #include "wx/icon.h"
25 #endif
26
27
28 #ifdef __MSL__
29 #if __MSL__ >= 0x6000
30 #include "math.h"
31 // in case our functions were defined outside std, we make it known all the same
32 namespace std { }
33 using namespace std;
34 #endif
35 #endif
36
37 #ifdef __WXMAC__
38 #include "wx/osx/private.h"
39 #include "wx/osx/dcprint.h"
40 #include "wx/osx/dcclient.h"
41 #include "wx/osx/dcmemory.h"
42 #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
57 CGColorSpaceRef 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
69 int 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
80 extern CGContextRef wxOSXGetContextFromCurrentNSContext() ;
81 extern void wxOSXLockFocus( WXWidget view) ;
82 extern void wxOSXUnlockFocus( WXWidget view) ;
83 #endif
84
85
86 //-----------------------------------------------------------------------------
87 // constants
88 //-----------------------------------------------------------------------------
89
90 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
91 #ifndef M_PI
92 const double M_PI = 3.14159265358979;
93 #endif
94 #endif
95
96 static 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
105 OSStatus 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
124 CGColorRef 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
147 CTFontRef 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
160 class wxMacCoreGraphicsPattern
161 {
162 public :
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
170 protected :
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
195 const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCoreGraphicsPattern::_Render, &wxMacCoreGraphicsPattern::_Dispose };
196
197 class ImagePattern : public wxMacCoreGraphicsPattern
198 {
199 public :
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
223 protected :
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
247 class HatchPattern : public wxMacCoreGraphicsPattern
248 {
249 public :
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
336 protected :
337 virtual ~HatchPattern() {}
338
339 CGRect m_imageBounds;
340 int m_hatch;
341 };
342
343 class wxMacCoreGraphicsPenData : public wxGraphicsObjectRefData
344 {
345 public:
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
353 protected :
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
371 wxMacCoreGraphicsPenData::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
508 wxMacCoreGraphicsPenData::~wxMacCoreGraphicsPenData()
509 {
510 delete[] m_userLengths;
511 delete[] m_patternColorComponents;
512 }
513
514 void 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
524 void 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
555 static 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
567 wxBitmap 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
571 class 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
589 wxMacCoreGraphicsColour::~wxMacCoreGraphicsColour()
590 {
591 delete[] m_patternColorComponents;
592 }
593
594 void wxMacCoreGraphicsColour::Init()
595 {
596 m_isPattern = false;
597 m_patternColorComponents = NULL;
598 }
599
600 void 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
615 wxMacCoreGraphicsColour::wxMacCoreGraphicsColour()
616 {
617 Init();
618 }
619
620 wxMacCoreGraphicsColour::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
654 class wxMacCoreGraphicsBrushData : public wxGraphicsObjectRefData
655 {
656 public:
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; }
669 protected:
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
682 wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer )
683 {
684 Init();
685 }
686
687 void 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
696 void 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
705 wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush &brush) : wxGraphicsObjectRefData( renderer ),
706 m_cgColor( brush )
707 {
708 Init();
709
710 }
711
712 wxMacCoreGraphicsBrushData::~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
723 void wxMacCoreGraphicsBrushData::Init()
724 {
725 m_gradientFunction = NULL;
726 m_shading = NULL;
727 m_gradientComponents = NULL;
728 m_isShading = false;
729 }
730
731 void 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
745 void 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
755 CGFunctionRef 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
783 extern UIFont* CreateUIFont( const wxFont& font );
784 extern void DrawTextInContext( CGContextRef context, CGPoint where, UIFont *font, NSString* text );
785 extern CGSize MeasureTextInContext( UIFont *font, NSString* text );
786
787 #endif
788
789 class wxMacCoreGraphicsFontData : public wxGraphicsObjectRefData
790 {
791 public:
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
807 private :
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
821 wxMacCoreGraphicsFontData::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
870 wxMacCoreGraphicsFontData::~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
886 class wxMacCoreGraphicsBitmapData : public wxGraphicsObjectRefData
887 {
888 public:
889 wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap, bool monochrome );
890 ~wxMacCoreGraphicsBitmapData();
891
892 virtual CGImageRef GetBitmap() { return m_bitmap; }
893 bool IsMonochrome() { return m_monochrome; }
894 private :
895 CGImageRef m_bitmap;
896 bool m_monochrome;
897 };
898
899 wxMacCoreGraphicsBitmapData::wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap, bool monochrome ) : wxGraphicsObjectRefData( renderer ),
900 m_bitmap(bitmap), m_monochrome(monochrome)
901 {
902 }
903
904 wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData()
905 {
906 CGImageRelease( m_bitmap );
907 }
908
909 //
910 // Graphics Matrix
911 //
912
913 //-----------------------------------------------------------------------------
914 // wxMacCoreGraphicsMatrix declaration
915 //-----------------------------------------------------------------------------
916
917 class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrixData : public wxGraphicsMatrixData
918 {
919 public :
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
972 private :
973 CGAffineTransform m_matrix;
974 } ;
975
976 //-----------------------------------------------------------------------------
977 // wxMacCoreGraphicsMatrix implementation
978 //-----------------------------------------------------------------------------
979
980 wxMacCoreGraphicsMatrixData::wxMacCoreGraphicsMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
981 {
982 }
983
984 wxMacCoreGraphicsMatrixData::~wxMacCoreGraphicsMatrixData()
985 {
986 }
987
988 wxGraphicsObjectRefData *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
996 void 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
1002 void 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
1009 void 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
1021 void wxMacCoreGraphicsMatrixData::Invert()
1022 {
1023 m_matrix = CGAffineTransformInvert( m_matrix );
1024 }
1025
1026 // returns true if the elements of the transformation matrix are equal ?
1027 bool 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
1033 bool 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
1044 void 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
1050 void 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)
1056 void 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
1066 void 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
1075 void 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
1083 void * wxMacCoreGraphicsMatrixData::GetNativeMatrix() const
1084 {
1085 return (void*) &m_matrix;
1086 }
1087
1088 //
1089 // Graphics Path
1090 //
1091
1092 //-----------------------------------------------------------------------------
1093 // wxMacCoreGraphicsPath declaration
1094 //-----------------------------------------------------------------------------
1095
1096 class WXDLLEXPORT wxMacCoreGraphicsPathData : public wxGraphicsPathData
1097 {
1098 public :
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;
1156 private :
1157 CGMutablePathRef m_path;
1158 };
1159
1160 //-----------------------------------------------------------------------------
1161 // wxMacCoreGraphicsPath implementation
1162 //-----------------------------------------------------------------------------
1163
1164 wxMacCoreGraphicsPathData::wxMacCoreGraphicsPathData( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPathData(renderer)
1165 {
1166 if ( path )
1167 m_path = path;
1168 else
1169 m_path = CGPathCreateMutable();
1170 }
1171
1172 wxMacCoreGraphicsPathData::~wxMacCoreGraphicsPathData()
1173 {
1174 CGPathRelease( m_path );
1175 }
1176
1177 wxGraphicsObjectRefData* 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
1185 void wxMacCoreGraphicsPathData::MoveToPoint( wxDouble x1 , wxDouble y1 )
1186 {
1187 CGPathMoveToPoint( m_path , NULL , (CGFloat) x1 , (CGFloat) y1 );
1188 }
1189
1190 void wxMacCoreGraphicsPathData::AddLineToPoint( wxDouble x1 , wxDouble y1 )
1191 {
1192 CGPathAddLineToPoint( m_path , NULL , (CGFloat) x1 , (CGFloat) y1 );
1193 }
1194
1195 void 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
1200 void 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
1205 void 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
1211 void 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
1217 void 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
1223 void 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
1228 void wxMacCoreGraphicsPathData::AddPath( const wxGraphicsPathData* path )
1229 {
1230 CGPathAddPath( m_path , NULL, (CGPathRef) path->GetNativePath() );
1231 }
1232
1233 // closes the current subpath
1234 void wxMacCoreGraphicsPathData::CloseSubpath()
1235 {
1236 CGPathCloseSubpath( m_path );
1237 }
1238
1239 // gets the last point of the current path, (0,0) if not yet set
1240 void 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
1248 void 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)
1257 void 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
1266 bool 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
1279 class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
1280 {
1281 public:
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
1393 private:
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
1431 IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
1432
1433 class wxQuartzOffsetHelper
1434 {
1435 public :
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 }
1448 public :
1449 CGContextRef m_cg;
1450 bool m_offset;
1451 } ;
1452
1453 void 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
1467 wxMacCoreGraphicsContext::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
1476 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer)
1477 {
1478 Init();
1479 m_windowRef = window;
1480 }
1481 #endif
1482
1483 wxMacCoreGraphicsContext::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
1516 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
1517 {
1518 Init();
1519 }
1520
1521 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
1522 {
1523 Init();
1524 wxLogDebug(wxT("Illegal Constructor called"));
1525 }
1526
1527 wxMacCoreGraphicsContext::~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
1538 void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height)
1539 {
1540 *width = m_width;
1541 *height = m_height;
1542 }
1543
1544
1545 void 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
1558 void wxMacCoreGraphicsContext::EndPage()
1559 {
1560 CGContextEndPage(m_cgContext);
1561 }
1562
1563 void wxMacCoreGraphicsContext::Flush()
1564 {
1565 CGContextFlush(m_cgContext);
1566 }
1567
1568 void 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
1627 bool 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
1689 void 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
1724 void 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
1746 void 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
1771 void 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
1785 void 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
1834 void 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
1860 void 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
1904 void 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
1912 void 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
1920 void 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
1928 void 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
1934 void 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
1971 void 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
1986 void wxMacCoreGraphicsContext::PushState()
1987 {
1988 EnsureIsValid();
1989
1990 CGContextSaveGState( m_cgContext );
1991 }
1992
1993 void wxMacCoreGraphicsContext::PopState()
1994 {
1995 EnsureIsValid();
1996
1997 CGContextRestoreGState( m_cgContext );
1998 }
1999
2000 void 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
2056 void 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
2161 void 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
2263 void 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
2361 void * wxMacCoreGraphicsContext::GetNativeContext()
2362 {
2363 return m_cgContext;
2364 }
2365
2366 // concatenates this transform with the current transform of this context
2367 void 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
2376 void 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
2392 wxGraphicsMatrix 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
2408 class WXDLLIMPEXP_CORE wxMacCoreGraphicsRenderer : public wxGraphicsRenderer
2409 {
2410 public :
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 ) ;
2462 private :
2463 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsRenderer)
2464 } ;
2465
2466 //-----------------------------------------------------------------------------
2467 // wxMacCoreGraphicsRenderer implementation
2468 //-----------------------------------------------------------------------------
2469
2470 IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsRenderer,wxGraphicsRenderer)
2471
2472 static wxMacCoreGraphicsRenderer gs_MacCoreGraphicsRenderer;
2473
2474 wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
2475 {
2476 return &gs_MacCoreGraphicsRenderer;
2477 }
2478
2479 wxGraphicsContext * 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
2499 wxGraphicsContext * 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
2516 wxGraphicsContext * 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
2533 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
2534 {
2535 return new wxMacCoreGraphicsContext(this,(CGContextRef)context);
2536 }
2537
2538 wxGraphicsContext * 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
2547 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
2548 {
2549 return new wxMacCoreGraphicsContext(this, window );
2550 }
2551
2552 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateMeasuringContext()
2553 {
2554 return new wxMacCoreGraphicsContext(this);
2555 }
2556
2557 // Path
2558
2559 wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
2560 {
2561 wxGraphicsPath m;
2562 m.SetRefData( new wxMacCoreGraphicsPathData(this));
2563 return m;
2564 }
2565
2566
2567 // Matrix
2568
2569 wxGraphicsMatrix 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
2579 wxGraphicsPen 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
2591 wxGraphicsBrush 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
2603 wxGraphicsBitmap 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
2617 wxGraphicsBitmap 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
2633 wxGraphicsBrush 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
2645 wxGraphicsBrush 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
2656 wxGraphicsFont 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
2674 size_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
2684 void wxMacReleaseCFDataProviderCallback(void *info,
2685 const void *WXUNUSED(data),
2686 size_t WXUNUSED(count))
2687 {
2688 if ( info )
2689 CFRelease( (CFDataRef) info );
2690 }
2691
2692 void wxMacReleaseCFDataConsumerCallback( void *info )
2693 {
2694 if ( info )
2695 CFRelease( (CFDataRef) info );
2696 }
2697
2698 CGDataProviderRef wxMacCGDataProviderCreateWithCFData( CFDataRef data )
2699 {
2700 if ( data == NULL )
2701 return NULL;
2702
2703 return CGDataProviderCreateWithCFData( data );
2704 }
2705
2706 CGDataConsumerRef wxMacCGDataConsumerCreateWithCFData( CFMutableDataRef data )
2707 {
2708 if ( data == NULL )
2709 return NULL;
2710
2711 return CGDataConsumerCreateWithCFData( data );
2712 }
2713
2714 void
2715 wxMacReleaseMemoryBufferProviderCallback(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
2726 CGDataProviderRef 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 }