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