]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/graphics.cpp
switching things to ref counting
[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
b7b40adb
SC
701class WXDLLIMPEXP_CORE wxMacCoreGraphicsMatrix : public wxGraphicsMatrix
702{
703public :
704 wxMacCoreGraphicsMatrix() ;
705
706 wxMacCoreGraphicsMatrix(wxGraphicsRenderer* renderer, wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
707 wxDouble tx=0.0, wxDouble ty=0.0) ;
708
709 virtual ~wxMacCoreGraphicsMatrix() ;
710
711 virtual wxGraphicsMatrix *Clone() const ;
712
713 // concatenates the matrix
714 virtual void Concat( const wxGraphicsMatrix *t );
715
716 // copies the passed in matrix
717 virtual void Copy( const wxGraphicsMatrix *t );
718
719 // sets the matrix to the respective values
720 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
721 wxDouble tx=0.0, wxDouble ty=0.0);
722
723 // makes this the inverse matrix
724 virtual void Invert();
725
726 // returns true if the elements of the transformation matrix are equal ?
727 virtual bool IsEqual( const wxGraphicsMatrix* t) const ;
728
729 // return true if this is the identity matrix
730 virtual bool IsIdentity();
731
50581042 732 //
b7b40adb 733 // transformation
50581042
SC
734 //
735
b7b40adb
SC
736 // add the translation to this matrix
737 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 738
b7b40adb
SC
739 // add the scale to this matrix
740 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 741
b7b40adb
SC
742 // add the rotation to this matrix (radians)
743 virtual void Rotate( wxDouble angle );
744
50581042 745 //
b7b40adb 746 // apply the transforms
50581042 747 //
b7b40adb
SC
748
749 // applies that matrix to the point
750 virtual void TransformPoint( wxDouble *x, wxDouble *y );
751
752 // applies the matrix except for translations
753 virtual void TransformDistance( wxDouble *dx, wxDouble *dy );
754
755 // returns the native representation
756 virtual void * GetNativeMatrix() const;
757
758private :
759 CGAffineTransform m_matrix;
50581042 760
b7b40adb
SC
761 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsMatrix)
762} ;
50581042 763
50581042 764//-----------------------------------------------------------------------------
b7b40adb 765// wxMacCoreGraphicsMatrix implementation
50581042
SC
766//-----------------------------------------------------------------------------
767
b7b40adb 768IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsMatrix, wxGraphicsMatrix)
50581042 769
b7b40adb
SC
770wxMacCoreGraphicsMatrix::wxMacCoreGraphicsMatrix() : wxGraphicsMatrix(NULL)
771{
772 wxLogDebug(wxT("Illegal Constructor called"));
773}
50581042 774
b7b40adb
SC
775wxMacCoreGraphicsMatrix::wxMacCoreGraphicsMatrix(wxGraphicsRenderer* renderer, wxDouble a, wxDouble b, wxDouble c, wxDouble d,
776 wxDouble tx, wxDouble ty) : wxGraphicsMatrix(renderer)
777{
778 m_matrix = CGAffineTransformMake(a,b,c,d,tx,ty);
779}
eec960fa 780
b7b40adb 781wxMacCoreGraphicsMatrix::~wxMacCoreGraphicsMatrix()
50581042 782{
50581042
SC
783}
784
b7b40adb 785wxGraphicsMatrix *wxMacCoreGraphicsMatrix::Clone() const
50581042 786{
b7b40adb
SC
787 wxMacCoreGraphicsMatrix* m = new wxMacCoreGraphicsMatrix(GetRenderer()) ;
788 m->m_matrix = m_matrix ;
789 return m;
790}
791
792// concatenates the matrix
793void wxMacCoreGraphicsMatrix::Concat( const wxGraphicsMatrix *t )
794{
795 m_matrix = CGAffineTransformConcat(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()) );
796}
797
798// copies the passed in matrix
799void wxMacCoreGraphicsMatrix::Copy( const wxGraphicsMatrix *t )
800{
801 m_matrix = *((CGAffineTransform*) t->GetNativeMatrix());
802}
803
804// sets the matrix to the respective values
805void wxMacCoreGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
806 wxDouble tx, wxDouble ty)
807{
808 m_matrix = CGAffineTransformMake(a,b,c,d,tx,ty);
50581042
SC
809}
810
b7b40adb
SC
811// makes this the inverse matrix
812void wxMacCoreGraphicsMatrix::Invert()
1056ddcf 813{
b7b40adb 814 m_matrix = CGAffineTransformInvert( m_matrix );
eec960fa
SC
815}
816
b7b40adb
SC
817// returns true if the elements of the transformation matrix are equal ?
818bool wxMacCoreGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const
eec960fa 819{
2701ef7e
SC
820 const CGAffineTransform* tm = (CGAffineTransform*) t->GetNativeMatrix();
821 return (
822 m_matrix.a == tm->a &&
823 m_matrix.b == tm->b &&
824 m_matrix.c == tm->c &&
825 m_matrix.d == tm->d &&
826 m_matrix.tx == tm->tx &&
827 m_matrix.ty == tm->ty ) ;
828
b7b40adb 829 return CGAffineTransformEqualToTransform(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()));
1056ddcf
SC
830}
831
b7b40adb
SC
832// return true if this is the identity matrix
833bool wxMacCoreGraphicsMatrix::IsIdentity()
50581042 834{
2701ef7e
SC
835 return ( m_matrix.a == 1 && m_matrix.d == 1 &&
836 m_matrix.b == 0 && m_matrix.d == 0 && m_matrix.tx == 0 && m_matrix.ty == 0);
50581042
SC
837}
838
b7b40adb
SC
839//
840// transformation
841//
842
843// add the translation to this matrix
844void wxMacCoreGraphicsMatrix::Translate( wxDouble dx , wxDouble dy )
50581042 845{
b7b40adb
SC
846 m_matrix = CGAffineTransformTranslate( m_matrix, dx, dy);
847}
50581042 848
b7b40adb
SC
849// add the scale to this matrix
850void wxMacCoreGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale )
851{
852 m_matrix = CGAffineTransformScale( m_matrix, xScale, yScale);
50581042
SC
853}
854
b7b40adb
SC
855// add the rotation to this matrix (radians)
856void wxMacCoreGraphicsMatrix::Rotate( wxDouble angle )
eec960fa 857{
b7b40adb 858 m_matrix = CGAffineTransformRotate( m_matrix, angle);
eec960fa
SC
859}
860
b7b40adb
SC
861//
862// apply the transforms
863//
eec960fa 864
b7b40adb
SC
865// applies that matrix to the point
866void wxMacCoreGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y )
50581042 867{
2701ef7e 868 CGPoint pt = CGPointApplyAffineTransform( CGPointMake(*x,*y), m_matrix);
b7b40adb 869
2701ef7e
SC
870 *x = pt.x;
871 *y = pt.y;
1056ddcf
SC
872}
873
b7b40adb
SC
874// applies the matrix except for translations
875void wxMacCoreGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy )
1056ddcf 876{
2701ef7e
SC
877 CGSize sz = CGSizeApplyAffineTransform( CGSizeMake(*dx,*dy) , m_matrix );
878 *dx = sz.width;
879 *dy = sz.height;
b7b40adb
SC
880}
881
882// returns the native representation
883void * wxMacCoreGraphicsMatrix::GetNativeMatrix() const
1056ddcf 884{
b7b40adb 885 return (void*) &m_matrix;
50581042
SC
886}
887
b7b40adb
SC
888//
889// Graphics Path
890//
891
892//-----------------------------------------------------------------------------
893// wxMacCoreGraphicsPath declaration
894//-----------------------------------------------------------------------------
895
896class WXDLLEXPORT wxMacCoreGraphicsPath : public wxGraphicsPath
50581042 897{
b7b40adb
SC
898public :
899 wxMacCoreGraphicsPath( wxGraphicsRenderer* renderer, CGMutablePathRef path = NULL);
900
901 wxMacCoreGraphicsPath();
902
903 ~wxMacCoreGraphicsPath();
1056ddcf 904
b7b40adb 905 virtual wxGraphicsPath *Clone() const;
1056ddcf 906
b7b40adb
SC
907 // begins a new subpath at (x,y)
908 virtual void MoveToPoint( wxDouble x, wxDouble y );
1056ddcf 909
b7b40adb
SC
910 // adds a straight line from the current point to (x,y)
911 virtual void AddLineToPoint( wxDouble x, wxDouble y );
912
913 // adds a cubic Bezier curve from the current point, using two control points and an end point
914 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
915
916 // closes the current sub-path
917 virtual void CloseSubpath();
918
919 // gets the last point of the current path, (0,0) if not yet set
920 virtual void GetCurrentPoint( wxDouble& x, wxDouble&y);
921
922 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
923 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise );
924
925 //
926 // These are convenience functions which - if not available natively will be assembled
927 // using the primitives from above
928 //
929
930 // adds a quadratic Bezier curve from the current point, using a control point and an end point
931 virtual void AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y );
932
933 // appends a rectangle as a new closed subpath
934 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
935
936 // appends an ellipsis as a new closed subpath fitting the passed rectangle
937 virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r );
938
939 // 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)
940 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
941
942 // adds another path
943 virtual void AddPath( const wxGraphicsPath* path );
944
945 // returns the native path
946 virtual void * GetNativePath() const { return m_path; }
947
948 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
949 virtual void UnGetNativePath(void *p) {}
950
951 // transforms each point of this path by the matrix
952 virtual void Transform( wxGraphicsMatrix* matrix );
953
954 // gets the bounding box enclosing all points (possibly including control points)
955 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *y);
956
957 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE);
958 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsPath)
959private :
960 CGMutablePathRef m_path;
961};
962
963//-----------------------------------------------------------------------------
964// wxMacCoreGraphicsPath implementation
965//-----------------------------------------------------------------------------
966
967IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsPath, wxGraphicsPath)
968
969wxMacCoreGraphicsPath::wxMacCoreGraphicsPath() : wxGraphicsPath(NULL)
970{
971 wxLogDebug(wxT("Illegal Constructor called"));
972}
973
974
975wxMacCoreGraphicsPath::wxMacCoreGraphicsPath( wxGraphicsRenderer* renderer, CGMutablePathRef path) : wxGraphicsPath(renderer)
976{
977 if ( path )
978 m_path = path;
979 else
980 m_path = CGPathCreateMutable();
50581042
SC
981}
982
b7b40adb 983wxMacCoreGraphicsPath::~wxMacCoreGraphicsPath()
50581042 984{
b7b40adb
SC
985 CGPathRelease( m_path );
986}
50581042 987
b7b40adb
SC
988wxGraphicsPath* wxMacCoreGraphicsPath::Clone() const
989{
990 wxMacCoreGraphicsPath* clone = new wxMacCoreGraphicsPath(GetRenderer(),CGPathCreateMutableCopy(m_path));
991 return clone ;
992}
1056ddcf 993
1056ddcf 994
b7b40adb
SC
995// opens (starts) a new subpath
996void wxMacCoreGraphicsPath::MoveToPoint( wxDouble x1 , wxDouble y1 )
997{
998 CGPathMoveToPoint( m_path , NULL , x1 , y1 );
999}
1056ddcf 1000
b7b40adb
SC
1001void wxMacCoreGraphicsPath::AddLineToPoint( wxDouble x1 , wxDouble y1 )
1002{
1003 CGPathAddLineToPoint( m_path , NULL , x1 , y1 );
50581042
SC
1004}
1005
b7b40adb 1006void wxMacCoreGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
50581042 1007{
b7b40adb 1008 CGPathAddCurveToPoint( m_path , NULL , cx1 , cy1 , cx2, cy2, x , y );
50581042
SC
1009}
1010
b7b40adb 1011void wxMacCoreGraphicsPath::AddQuadCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble x, wxDouble y )
50581042 1012{
b7b40adb 1013 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x , y );
50581042
SC
1014}
1015
b7b40adb 1016void wxMacCoreGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
50581042 1017{
b7b40adb
SC
1018 CGRect cgRect = { { x , y } , { w , h } };
1019 CGPathAddRect( m_path , NULL , cgRect );
1020}
50581042 1021
b7b40adb
SC
1022void wxMacCoreGraphicsPath::AddCircle( wxDouble x, wxDouble y , wxDouble r )
1023{
1024 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true );
50581042
SC
1025}
1026
b7b40adb
SC
1027// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
1028void wxMacCoreGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise )
50581042 1029{
b7b40adb
SC
1030 // inverse direction as we the 'normal' state is a y axis pointing down, ie mirrored to the standard core graphics setup
1031 CGPathAddArc( m_path, NULL , x, y, r, startAngle, endAngle, !clockwise);
50581042
SC
1032}
1033
b7b40adb 1034void wxMacCoreGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
50581042 1035{
b7b40adb 1036 CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
50581042
SC
1037}
1038
b7b40adb 1039void wxMacCoreGraphicsPath::AddPath( const wxGraphicsPath* path )
50581042 1040{
b7b40adb 1041 CGPathAddPath( m_path , NULL, (CGPathRef) path->GetNativePath() );
50581042
SC
1042}
1043
b7b40adb
SC
1044// closes the current subpath
1045void wxMacCoreGraphicsPath::CloseSubpath()
50581042 1046{
b7b40adb 1047 CGPathCloseSubpath( m_path );
50581042
SC
1048}
1049
b7b40adb
SC
1050// gets the last point of the current path, (0,0) if not yet set
1051void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
50581042 1052{
b7b40adb
SC
1053 CGPoint p = CGPathGetCurrentPoint( m_path );
1054 x = p.x;
1055 y = p.y;
50581042
SC
1056}
1057
b7b40adb
SC
1058// transforms each point of this path by the matrix
1059void wxMacCoreGraphicsPath::Transform( wxGraphicsMatrix* matrix )
50581042 1060{
b7b40adb
SC
1061 CGMutablePathRef p = CGPathCreateMutable() ;
1062 CGPathAddPath( p, (CGAffineTransform*) matrix->GetNativeMatrix() , m_path );
1063 CGPathRelease( m_path );
1064 m_path = p;
50581042
SC
1065}
1066
b7b40adb
SC
1067// gets the bounding box enclosing all points (possibly including control points)
1068void wxMacCoreGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h)
50581042 1069{
b7b40adb
SC
1070 CGRect bounds = CGPathGetBoundingBox( m_path ) ;
1071 *x = bounds.origin.x;
1072 *y = bounds.origin.y;
1073 *w = bounds.size.width;
1074 *h = bounds.size.height;
50581042
SC
1075}
1076
b7b40adb 1077bool wxMacCoreGraphicsPath::Contains( wxDouble x, wxDouble y, int fillStyle)
50581042 1078{
b7b40adb 1079 return CGPathContainsPoint( m_path, NULL, CGPointMake(x,y), fillStyle == wxODDEVEN_RULE );
50581042
SC
1080}
1081
50581042 1082
b7b40adb
SC
1083//
1084// Graphics Pen
1085//
50581042 1086
b7b40adb
SC
1087//-----------------------------------------------------------------------------
1088// wxMacCoreGraphicsPen declaration
1089//-----------------------------------------------------------------------------
50581042 1090
50581042 1091
b7b40adb
SC
1092//
1093// Graphics Context
1094//
50581042 1095
b7b40adb
SC
1096//-----------------------------------------------------------------------------
1097// wxMacCoreGraphicsContext declaration
1098//-----------------------------------------------------------------------------
1099
1100class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
1101{
1102public:
1103 wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext );
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();
50581042 1114
b7b40adb 1115 void Init();
50581042 1116
b7b40adb
SC
1117 // push the current state of the context, ie the transformation matrix on a stack
1118 virtual void PushState();
50581042 1119
b7b40adb
SC
1120 // pops a stored state from the stack
1121 virtual void PopState();
50581042 1122
b7b40adb
SC
1123 // clips drawings to the region
1124 virtual void Clip( const wxRegion &region );
50581042 1125
b7b40adb
SC
1126 // clips drawings to the rect
1127 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
1128
1129 // resets the clipping to original extent
1130 virtual void ResetClip();
50581042 1131
b7b40adb
SC
1132 virtual void * GetNativeContext();
1133
1134 //
1135 // transformation
1136 //
1137
1138 // translate
1139 virtual void Translate( wxDouble dx , wxDouble dy );
50581042 1140
b7b40adb
SC
1141 // scale
1142 virtual void Scale( wxDouble xScale , wxDouble yScale );
50581042 1143
b7b40adb
SC
1144 // rotate (radians)
1145 virtual void Rotate( wxDouble angle );
50581042 1146
b7b40adb
SC
1147 // concatenates this transform with the current transform of this context
1148 virtual void ConcatTransform( const wxGraphicsMatrix* matrix );
50581042 1149
b7b40adb
SC
1150 // sets the transform of this context
1151 virtual void SetTransform( const wxGraphicsMatrix* matrix );
50581042 1152
b7b40adb
SC
1153 // gets the matrix of this context
1154 virtual void GetTransform( wxGraphicsMatrix* matrix );
1155 //
1156 // setting the paint
1157 //
1158
b7b40adb
SC
1159 // strokes along a path with the current pen
1160 virtual void StrokePath( const wxGraphicsPath *path );
50581042 1161
b7b40adb
SC
1162 // fills a path with the current brush
1163 virtual void FillPath( const wxGraphicsPath *path, int fillStyle = wxWINDING_RULE );
50581042 1164
b7b40adb
SC
1165 // draws a path by first filling and then stroking
1166 virtual void DrawPath( const wxGraphicsPath *path, int fillStyle = wxWINDING_RULE );
1167
1168 virtual bool ShouldOffset() const
50581042 1169 {
b7b40adb 1170 int penwidth = 0 ;
a26b7ab2 1171 if ( !m_pen.IsNull() )
50581042 1172 {
a26b7ab2 1173 penwidth = ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->GetWidth();
b7b40adb
SC
1174 if ( penwidth == 0 )
1175 penwidth = 1;
50581042 1176 }
b7b40adb 1177 return ( penwidth % 2 ) == 1;
50581042 1178 }
b7b40adb
SC
1179 //
1180 // text
1181 //
1182
1183 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y );
50581042 1184
b7b40adb 1185 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
50581042 1186
b7b40adb
SC
1187 virtual void GetTextExtent( const wxString &text, wxDouble *width, wxDouble *height,
1188 wxDouble *descent, wxDouble *externalLeading ) const;
50581042 1189
b7b40adb 1190 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
50581042 1191
b7b40adb
SC
1192 //
1193 // image support
1194 //
50581042 1195
b7b40adb 1196 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1197
b7b40adb 1198 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
50581042 1199
b7b40adb
SC
1200 void SetNativeContext( CGContextRef cg );
1201
1202 DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
1203 DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
50581042 1204
b7b40adb
SC
1205private:
1206 void EnsureIsValid();
50581042 1207
b7b40adb
SC
1208 CGContextRef m_cgContext;
1209 WindowRef m_windowRef;
1210 int m_originX;
1211 int m_originY;
1212 wxMacCFRefHolder<HIShapeRef> m_clipRgn;
1213 bool m_releaseContext;
50581042
SC
1214};
1215
b7b40adb
SC
1216//-----------------------------------------------------------------------------
1217// device context implementation
1218//
1219// more and more of the dc functionality should be implemented by calling
1220// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step
1221// also coordinate conversions should be moved to native matrix ops
1222//-----------------------------------------------------------------------------
50581042 1223
b7b40adb
SC
1224// we always stock two context states, one at entry, to be able to preserve the
1225// state we were called with, the other one after changing to HI Graphics orientation
1226// (this one is used for getting back clippings etc)
50581042 1227
b7b40adb
SC
1228//-----------------------------------------------------------------------------
1229// wxMacCoreGraphicsContext implementation
1230//-----------------------------------------------------------------------------
50581042 1231
b7b40adb 1232IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
50581042 1233
b7b40adb
SC
1234void wxMacCoreGraphicsContext::Init()
1235{
1236 m_cgContext = NULL;
1237 m_releaseContext = false;
1238 m_windowRef = NULL;
1239 m_originX = 0;
1240 m_originY = 0;
1241 HIRect r = CGRectMake(0,0,0,0);
1242 m_clipRgn.Set(HIShapeCreateWithRect(&r));
1243}
50581042 1244
b7b40adb
SC
1245wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext ) : wxGraphicsContext(renderer)
1246{
1247 Init();
1248 m_cgContext = cgcontext;
1249 // FIXME: This check is needed because currently we need to use a DC/GraphicsContext
1250 // in order to get font properties, like wxFont::GetPixelSize, but since we don't have
1251 // a native window attached to use, I create a wxGraphicsContext with a NULL CGContextRef
1252 // for this one operation.
1253
1254 // When wxFont::GetPixelSize on Mac no longer needs a graphics context, this check
1255 // can be removed.
1256 if (m_cgContext)
1257 {
1258 CGContextSaveGState( m_cgContext );
1259 CGContextSaveGState( m_cgContext );
1260 }
1261}
50581042 1262
b7b40adb
SC
1263wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer)
1264{
1265 Init();
1266 m_windowRef = window;
1267}
50581042 1268
b7b40adb
SC
1269wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ): wxGraphicsContext(renderer)
1270{
1271 Init();
1272 m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
1273 m_originX = m_originY = 0;
1274 window->MacWindowToRootWindow( &m_originX , &m_originY );
1275}
50581042 1276
b7b40adb
SC
1277wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
1278{
1279 Init();
1280}
50581042 1281
b7b40adb
SC
1282wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
1283{
1284 Init();
1285 wxLogDebug(wxT("Illegal Constructor called"));
1286}
50581042 1287
b7b40adb
SC
1288wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
1289{
b7b40adb
SC
1290 if ( m_cgContext )
1291 {
1292 // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
1293 CGContextRestoreGState( m_cgContext );
1294 CGContextRestoreGState( m_cgContext );
1295 }
50581042 1296
b7b40adb
SC
1297 if ( m_releaseContext )
1298 QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
1299}
50581042 1300
b7b40adb
SC
1301void wxMacCoreGraphicsContext::EnsureIsValid()
1302{
1303 if ( !m_cgContext )
1304 {
1305 OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
1306 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
1307 Rect bounds;
1308 GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
1309 CGContextSaveGState( m_cgContext );
1310 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top );
1311 CGContextScaleCTM( m_cgContext , 1 , -1 );
1312 CGContextTranslateCTM( m_cgContext, m_originX, m_originY );
1313 CGContextSaveGState( m_cgContext );
1314 m_releaseContext = true;
1315 if ( !HIShapeIsEmpty(m_clipRgn) )
1316 {
1317 HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext );
1318 CGContextClip( m_cgContext );
1319 }
1320 }
1321}
50581042 1322
50581042 1323
b7b40adb
SC
1324void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
1325{
1326 if( m_cgContext )
1327 {
1328 HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
1329 HIShapeReplacePathInCGContext( shape, m_cgContext );
1330 CGContextClip( m_cgContext );
1331 CFRelease( shape );
1332 }
1333 else
1334 {
1335 m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
1336 }
1337}
50581042 1338
b7b40adb
SC
1339// clips drawings to the rect
1340void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1341{
1342 HIRect r = CGRectMake( x , y , w , h );
1343 if ( m_cgContext )
1344 {
1345 CGContextClipToRect( m_cgContext, r );
1346 }
1347 else
1348 {
1349 m_clipRgn.Set(HIShapeCreateWithRect(&r));
1350 }
1351}
1352
1353 // resets the clipping to original extent
1354void wxMacCoreGraphicsContext::ResetClip()
1355{
1356 if ( m_cgContext )
1357 {
1358 CGContextRestoreGState( m_cgContext );
1359 CGContextSaveGState( m_cgContext );
1360 }
1361 else
1362 {
1363 HIRect r = CGRectMake(0,0,0,0);
1364 m_clipRgn.Set(HIShapeCreateWithRect(&r));
1365 }
1366}
50581042 1367
b7b40adb
SC
1368void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *path )
1369{
a26b7ab2 1370 if ( m_pen.IsNull() )
b7b40adb 1371 return ;
50581042 1372
b7b40adb
SC
1373 EnsureIsValid();
1374
1375 bool offset = ShouldOffset();
1376 if ( offset )
1377 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
50581042 1378
a26b7ab2 1379 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
b7b40adb
SC
1380 CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
1381 CGContextStrokePath( m_cgContext );
50581042 1382
b7b40adb
SC
1383 if ( offset )
1384 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
1385}
50581042 1386
b7b40adb
SC
1387void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *path , int fillStyle )
1388{
a26b7ab2 1389 if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1390 {
1391 // when using shading, we cannot draw pen and brush at the same time
1392 // revert to the base implementation of first filling and then stroking
1393 wxGraphicsContext::DrawPath( path, fillStyle );
1394 return;
1395 }
1396
1397 CGPathDrawingMode mode = kCGPathFill ;
a26b7ab2 1398 if ( m_brush.IsNull() )
b7b40adb 1399 {
a26b7ab2 1400 if ( m_pen.IsNull() )
b7b40adb
SC
1401 return;
1402 else
1403 mode = kCGPathStroke;
1404 }
1405 else
1406 {
a26b7ab2 1407 if ( m_pen.IsNull() )
b7b40adb
SC
1408 {
1409 if ( fillStyle == wxODDEVEN_RULE )
1410 mode = kCGPathEOFill;
1411 else
1412 mode = kCGPathFill;
1413 }
1414 else
1415 {
1416 if ( fillStyle == wxODDEVEN_RULE )
1417 mode = kCGPathEOFillStroke;
1418 else
1419 mode = kCGPathFillStroke;
1420 }
1421 }
1422
1423 EnsureIsValid();
50581042 1424
a26b7ab2
SC
1425 if ( !m_brush.IsNull() )
1426 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
1427 if ( !m_pen.IsNull() )
1428 ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
50581042 1429
b7b40adb
SC
1430 bool offset = ShouldOffset();
1431
1432 if ( offset )
1433 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
50581042 1434
b7b40adb
SC
1435 CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
1436 CGContextDrawPath( m_cgContext , mode );
50581042 1437
b7b40adb
SC
1438 if ( offset )
1439 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
1440}
50581042 1441
b7b40adb
SC
1442void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *path , int fillStyle )
1443{
a26b7ab2 1444 if ( m_brush.IsNull() )
b7b40adb
SC
1445 return;
1446
1447 EnsureIsValid();
1448
a26b7ab2 1449 if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
b7b40adb
SC
1450 {
1451 CGContextSaveGState( m_cgContext );
1452 CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
1453 CGContextClip( m_cgContext );
a26b7ab2 1454 CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() );
b7b40adb
SC
1455 CGContextRestoreGState( m_cgContext);
1456 }
1457 else
1458 {
a26b7ab2 1459 ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
b7b40adb
SC
1460 CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
1461 if ( fillStyle == wxODDEVEN_RULE )
1462 CGContextEOFillPath( m_cgContext );
1463 else
1464 CGContextFillPath( m_cgContext );
50581042
SC
1465 }
1466}
1467
b7b40adb 1468void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
50581042 1469{
b7b40adb
SC
1470 // we allow either setting or clearing but not replacing
1471 wxASSERT( m_cgContext == NULL || cg == NULL );
50581042 1472
b7b40adb
SC
1473 if ( cg )
1474 CGContextSaveGState( cg );
1475 m_cgContext = cg;
1476}
50581042 1477
b7b40adb
SC
1478void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy )
1479{
1480 EnsureIsValid();
1481
1482 CGContextTranslateCTM( m_cgContext, dx, dy );
1483}
50581042 1484
b7b40adb
SC
1485void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
1486{
1487 EnsureIsValid();
1488
1489 CGContextScaleCTM( m_cgContext , xScale , yScale );
1490}
50581042 1491
b7b40adb
SC
1492void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
1493{
1494 EnsureIsValid();
1495
1496 CGContextRotateCTM( m_cgContext , angle );
1497}
50581042 1498
b7b40adb
SC
1499void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1500{
1501 EnsureIsValid();
1502
1503 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() );
1504 HIRect r = CGRectMake( x , y , w , h );
1505 HIViewDrawCGImage( m_cgContext , &r , image );
1506 CGImageRelease( image );
1507}
50581042 1508
b7b40adb
SC
1509void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1510{
1511 EnsureIsValid();
1512
1513 CGRect r = CGRectMake( 00 , 00 , w , h );
1514 CGContextSaveGState( m_cgContext );
1515 CGContextTranslateCTM( m_cgContext, x , y + h );
1516 CGContextScaleCTM( m_cgContext, 1, -1 );
1517 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
1518 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
1519 CGContextRestoreGState( m_cgContext );
1520}
50581042 1521
b7b40adb
SC
1522void wxMacCoreGraphicsContext::PushState()
1523{
1524 EnsureIsValid();
1525
1526 CGContextSaveGState( m_cgContext );
1527}
50581042 1528
b7b40adb
SC
1529void wxMacCoreGraphicsContext::PopState()
1530{
1531 EnsureIsValid();
1532
1533 CGContextRestoreGState( m_cgContext );
50581042
SC
1534}
1535
50581042
SC
1536void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1537{
1538 DrawText(str, x, y, 0.0);
1539}
1540
38af4365 1541void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
50581042 1542{
a26b7ab2 1543 if ( m_font.IsNull() )
b7b40adb
SC
1544 return;
1545
1546 EnsureIsValid();
1547
50581042
SC
1548 OSStatus status = noErr;
1549 ATSUTextLayout atsuLayout;
1550 UniCharCount chars = str.length();
1551 UniChar* ubuf = NULL;
1552
1553#if SIZEOF_WCHAR_T == 4
1554 wxMBConvUTF16 converter;
1555#if wxUSE_UNICODE
1556 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
1557 ubuf = (UniChar*) malloc( unicharlen + 2 );
1558 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
1559#else
1560 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1561 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1562 ubuf = (UniChar*) malloc( unicharlen + 2 );
1563 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1564#endif
1565 chars = unicharlen / 2;
1566#else
1567#if wxUSE_UNICODE
1568 ubuf = (UniChar*) str.wc_str();
1569#else
1570 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1571 chars = wxWcslen( wchar.data() );
1572 ubuf = (UniChar*) wchar.data();
1573#endif
1574#endif
1575
a26b7ab2 1576 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
50581042 1577 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1578 &chars , &style , &atsuLayout );
50581042
SC
1579
1580 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1581
1582 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
1583 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1584
1585 int iAngle = int( angle * RAD2DEG );
1586 if ( abs(iAngle) > 0 )
1587 {
1588 Fixed atsuAngle = IntToFixed( iAngle );
1589 ATSUAttributeTag atsuTags[] =
1590 {
1591 kATSULineRotationTag ,
1592 };
1593 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1594 {
1595 sizeof( Fixed ) ,
1596 };
1597 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1598 {
1599 &atsuAngle ,
1600 };
1601 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1602 atsuTags, atsuSizes, atsuValues );
1603 }
1604
1605 {
1606 ATSUAttributeTag atsuTags[] =
1607 {
1608 kATSUCGContextTag ,
1609 };
1610 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1611 {
1612 sizeof( CGContextRef ) ,
1613 };
1614 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1615 {
1616 &m_cgContext ,
1617 };
1618 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1619 atsuTags, atsuSizes, atsuValues );
1620 }
1621
1622 ATSUTextMeasurement textBefore, textAfter;
1623 ATSUTextMeasurement ascent, descent;
1624
1625 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1626 &textBefore , &textAfter, &ascent , &descent );
1627
1628 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1629
1630 Rect rect;
1631/*
1632 // TODO
1633 if ( m_backgroundMode == wxSOLID )
1634 {
1635 wxGraphicsPath* path = m_graphicContext->CreatePath();
1636 path->MoveToPoint( drawX , drawY );
1637 path->AddLineToPoint(
1638 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ,
1639 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) );
1640 path->AddLineToPoint(
1641 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1642 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1643 path->AddLineToPoint(
1644 (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1645 (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1646
1647 m_graphicContext->FillPath( path , m_textBackgroundColour );
1648 delete path;
1649 }
1650*/
1651 x += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
1652 y += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
1653
1654 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1655 IntToFixed(x) , IntToFixed(y) , &rect );
1656 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1657
1658 CGContextSaveGState(m_cgContext);
1659 CGContextTranslateCTM(m_cgContext, x, y);
1660 CGContextScaleCTM(m_cgContext, 1, -1);
1661 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1662 IntToFixed(0) , IntToFixed(0) );
1663
1664 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1665
1666 CGContextRestoreGState(m_cgContext);
1667
1668 ::ATSUDisposeTextLayout(atsuLayout);
1669
1670#if SIZEOF_WCHAR_T == 4
1671 free( ubuf );
1672#endif
1673}
1674
1675void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1676 wxDouble *descent, wxDouble *externalLeading ) const
1677{
a26b7ab2 1678 wxCHECK_RET( !m_font.IsNull(), wxT("wxDC(cg)::DoGetTextExtent - no valid font set") );
50581042
SC
1679
1680 OSStatus status = noErr;
1681
1682 ATSUTextLayout atsuLayout;
1683 UniCharCount chars = str.length();
1684 UniChar* ubuf = NULL;
1685
1686#if SIZEOF_WCHAR_T == 4
1687 wxMBConvUTF16 converter;
1688#if wxUSE_UNICODE
1689 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
1690 ubuf = (UniChar*) malloc( unicharlen + 2 );
1691 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
1692#else
1693 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1694 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1695 ubuf = (UniChar*) malloc( unicharlen + 2 );
1696 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1697#endif
1698 chars = unicharlen / 2;
1699#else
1700#if wxUSE_UNICODE
1701 ubuf = (UniChar*) str.wc_str();
1702#else
1703 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1704 chars = wxWcslen( wchar.data() );
1705 ubuf = (UniChar*) wchar.data();
1706#endif
1707#endif
1708
a26b7ab2 1709 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
50581042 1710 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1711 &chars , &style , &atsuLayout );
50581042
SC
1712
1713 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1714
1715 ATSUTextMeasurement textBefore, textAfter;
1716 ATSUTextMeasurement textAscent, textDescent;
1717
1718 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1719 &textBefore , &textAfter, &textAscent , &textDescent );
1720
1721 if ( height )
1722 *height = FixedToInt(textAscent + textDescent);
1723 if ( descent )
1724 *descent = FixedToInt(textDescent);
1725 if ( externalLeading )
1726 *externalLeading = 0;
1727 if ( width )
1728 *width = FixedToInt(textAfter - textBefore);
1729
1730 ::ATSUDisposeTextLayout(atsuLayout);
1731}
1732
1733void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1734{
1735 widths.Empty();
1736 widths.Add(0, text.length());
1737
1738 if (text.empty())
1739 return;
1740
1741 ATSUTextLayout atsuLayout;
1742 UniCharCount chars = text.length();
1743 UniChar* ubuf = NULL;
1744
1745#if SIZEOF_WCHAR_T == 4
1746 wxMBConvUTF16 converter;
1747#if wxUSE_UNICODE
1748 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 );
1749 ubuf = (UniChar*) malloc( unicharlen + 2 );
1750 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 );
1751#else
1752 const wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1753 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1754 ubuf = (UniChar*) malloc( unicharlen + 2 );
1755 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1756#endif
1757 chars = unicharlen / 2;
1758#else
1759#if wxUSE_UNICODE
1760 ubuf = (UniChar*) text.wc_str();
1761#else
1762 wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1763 chars = wxWcslen( wchar.data() );
1764 ubuf = (UniChar*) wchar.data();
1765#endif
1766#endif
1767
a26b7ab2 1768 ATSUStyle style = (((wxMacCoreGraphicsFontData*)m_font.GetRefData())->GetATSUStyle());
83b96a06 1769 ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
b7b40adb 1770 &chars , &style , &atsuLayout );
50581042
SC
1771
1772 for ( int pos = 0; pos < (int)chars; pos ++ )
1773 {
1774 unsigned long actualNumberOfBounds = 0;
1775 ATSTrapezoid glyphBounds;
1776
1777 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1778 OSStatus result;
1779 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
1780 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1781 if (result != noErr || actualNumberOfBounds != 1 )
1782 return;
1783
1784 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
1785 //unsigned char uch = s[i];
1786 }
1787
1788 ::ATSUDisposeTextLayout(atsuLayout);
1789}
1790
b7b40adb 1791void * wxMacCoreGraphicsContext::GetNativeContext()
50581042 1792{
b7b40adb
SC
1793 return m_cgContext;
1794}
50581042 1795
b7b40adb
SC
1796// concatenates this transform with the current transform of this context
1797void wxMacCoreGraphicsContext::ConcatTransform( const wxGraphicsMatrix* matrix )
1798{
1799}
50581042 1800
b7b40adb
SC
1801// sets the transform of this context
1802void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix* matrix )
1803{
1804}
50581042 1805
b7b40adb
SC
1806// gets the matrix of this context
1807void wxMacCoreGraphicsContext::GetTransform( wxGraphicsMatrix* matrix )
1808{
1809}
50581042 1810
b7b40adb
SC
1811//
1812// Renderer
1813//
50581042 1814
b7b40adb
SC
1815//-----------------------------------------------------------------------------
1816// wxMacCoreGraphicsRenderer declaration
1817//-----------------------------------------------------------------------------
50581042 1818
b7b40adb
SC
1819class WXDLLIMPEXP_CORE wxMacCoreGraphicsRenderer : public wxGraphicsRenderer
1820{
1821public :
1822 wxMacCoreGraphicsRenderer() {}
50581042 1823
b7b40adb
SC
1824 virtual ~wxMacCoreGraphicsRenderer() {}
1825
1826 // Context
1827
1828 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1829
1830 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1831
1832 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1833
1834 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1835
1836 // Path
1837
1838 virtual wxGraphicsPath * CreatePath();
1839
1840 // Matrix
1841
1842 virtual wxGraphicsMatrix * CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
1843 wxDouble tx=0.0, wxDouble ty=0.0);
1844
1845
a26b7ab2 1846 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
b7b40adb 1847
a26b7ab2 1848 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
b7b40adb
SC
1849
1850 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
a26b7ab2 1851 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb
SC
1852 const wxColour&c1, const wxColour&c2) ;
1853
1854 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1855 // with radius r and color cColor
a26b7ab2 1856 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
b7b40adb
SC
1857 const wxColour &oColor, const wxColour &cColor) ;
1858
1859 // sets the font
a26b7ab2 1860 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
b7b40adb
SC
1861
1862private :
1863 DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsRenderer)
1864} ;
1865
1866//-----------------------------------------------------------------------------
1867// wxMacCoreGraphicsRenderer implementation
1868//-----------------------------------------------------------------------------
1869
1870IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsRenderer,wxGraphicsRenderer)
1871
1872static wxMacCoreGraphicsRenderer gs_MacCoreGraphicsRenderer;
1873
1874wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1875{
1876 return &gs_MacCoreGraphicsRenderer;
50581042
SC
1877}
1878
b7b40adb
SC
1879wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc)
1880{
1881 return new wxMacCoreGraphicsContext(this,(CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
1882}
1883
1884wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context )
1885{
1886 return new wxMacCoreGraphicsContext(this,(CGContextRef)context);
1887}
1888
1889
1890wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( void * window )
1891{
1892 return new wxMacCoreGraphicsContext(this,(WindowRef)window);
1893}
1894
1895wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( wxWindow* window )
1896{
1897 return new wxMacCoreGraphicsContext(this, window );
1898}
1899
1900// Path
1901
1902wxGraphicsPath * wxMacCoreGraphicsRenderer::CreatePath()
1903{
1904 return new wxMacCoreGraphicsPath( this );
1905}
1906
1907
1908// Matrix
1909
1910wxGraphicsMatrix * wxMacCoreGraphicsRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1911 wxDouble tx, wxDouble ty)
1912
1056ddcf 1913{
b7b40adb
SC
1914 wxMacCoreGraphicsMatrix* m = new wxMacCoreGraphicsMatrix( this );
1915 m->Set( a,b,c,d,tx,ty ) ;
1916 return m;
1917}
1918
a26b7ab2 1919wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen)
b7b40adb
SC
1920{
1921 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
a26b7ab2 1922 return wxNullGraphicsPen;
b7b40adb 1923 else
a26b7ab2
SC
1924 {
1925 wxGraphicsPen p;
1926 p.SetRefData(new wxMacCoreGraphicsPenData( this, pen ));
1927 return p;
1928 }
1056ddcf
SC
1929}
1930
a26b7ab2 1931wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush )
50581042 1932{
b7b40adb 1933 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
a26b7ab2 1934 return wxNullGraphicsBrush;
b7b40adb 1935 else
a26b7ab2
SC
1936 {
1937 wxGraphicsBrush p;
1938 p.SetRefData(new wxMacCoreGraphicsBrushData( this, brush ));
1939 return p;
1940 }
50581042
SC
1941}
1942
b7b40adb 1943// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
a26b7ab2 1944wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
b7b40adb 1945 const wxColour&c1, const wxColour&c2)
1056ddcf 1946{
a26b7ab2
SC
1947 wxGraphicsBrush p;
1948 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
1949 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1950 p.SetRefData(d);
1951 return p;
1056ddcf
SC
1952}
1953
b7b40adb
SC
1954// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1955// with radius r and color cColor
a26b7ab2 1956wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
b7b40adb 1957 const wxColour &oColor, const wxColour &cColor)
1056ddcf 1958{
a26b7ab2
SC
1959 wxGraphicsBrush p;
1960 wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this );
1961 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1962 p.SetRefData(d);
1963 return p;
1056ddcf
SC
1964}
1965
b7b40adb 1966// sets the font
a26b7ab2 1967wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const wxColour &col )
513b47e9 1968{
b7b40adb 1969 if ( font.Ok() )
a26b7ab2
SC
1970 {
1971 wxGraphicsFont p;
1972 p.SetRefData(new wxMacCoreGraphicsFontData( this , font, col ));
1973 return p;
1974 }
b7b40adb 1975 else
a26b7ab2 1976 return wxNullGraphicsFont;
513b47e9
SC
1977}
1978
b7b40adb
SC
1979
1980
50581042 1981#endif // wxMAC_USE_CORE_GRAPHICS