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