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