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