]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/graphics.cpp
Fixed port name used in #ifdef.
[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
SC
18#ifndef WX_PRECOMP
19 #include "wx/log.h"
50581042 20 #include "wx/region.h"
50581042
SC
21#endif
22
23#include "wx/mac/uma.h"
24
50581042
SC
25#ifdef __MSL__
26 #if __MSL__ >= 0x6000
27 #include "math.h"
28 // in case our functions were defined outside std, we make it known all the same
29 namespace std { }
30 using namespace std;
31 #endif
32#endif
33
34#include "wx/mac/private.h"
35
36#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
37typedef float CGFloat;
38#endif
39
40//
41// Graphics Path
42//
43
44class WXDLLEXPORT wxMacCoreGraphicsPath : public wxGraphicsPath
45{
46 DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath)
47public :
48 wxMacCoreGraphicsPath();
49 ~wxMacCoreGraphicsPath();
50
51 // begins a new subpath at (x,y)
52 virtual void MoveToPoint( wxDouble x, wxDouble y );
53
54 // adds a straight line from the current point to (x,y)
55 virtual void AddLineToPoint( wxDouble x, wxDouble y );
56
57 // adds a cubic Bezier curve from the current point, using two control points and an end point
58 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
59
60 // closes the current sub-path
61 virtual void CloseSubpath();
62
63 // gets the last point of the current path, (0,0) if not yet set
64 virtual void GetCurrentPoint( wxDouble& x, wxDouble&y);
65
66 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
67 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise );
68
69 //
70 // These are convenience functions which - if not available natively will be assembled
71 // using the primitives from above
72 //
73
74 // adds a quadratic Bezier curve from the current point, using a control point and an end point
75 virtual void AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y );
76
77 // appends a rectangle as a new closed subpath
78 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
79
80 // appends an ellipsis as a new closed subpath fitting the passed rectangle
81 virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r );
82
83 // 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)
84 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
85
86 CGPathRef GetPath() const;
87private :
88 CGMutablePathRef m_path;
89};
90
91wxMacCoreGraphicsPath::wxMacCoreGraphicsPath()
92{
93 m_path = CGPathCreateMutable();
94}
95
96wxMacCoreGraphicsPath::~wxMacCoreGraphicsPath()
97{
98 CGPathRelease( m_path );
99}
100
101// opens (starts) a new subpath
102void wxMacCoreGraphicsPath::MoveToPoint( wxDouble x1 , wxDouble y1 )
103{
104 CGPathMoveToPoint( m_path , NULL , x1 , y1 );
105}
106
107void wxMacCoreGraphicsPath::AddLineToPoint( wxDouble x1 , wxDouble y1 )
108{
109 CGPathAddLineToPoint( m_path , NULL , x1 , y1 );
110}
111
112void wxMacCoreGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
113{
114 CGPathAddCurveToPoint( m_path , NULL , cx1 , cy1 , cx2, cy2, x , y );
115}
116
117void wxMacCoreGraphicsPath::AddQuadCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble x, wxDouble y )
118{
119 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x , y );
120}
121
122void wxMacCoreGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
123{
124 CGRect cgRect = { { x , y } , { w , h } };
125 CGPathAddRect( m_path , NULL , cgRect );
126}
127
128void wxMacCoreGraphicsPath::AddCircle( wxDouble x, wxDouble y , wxDouble r )
129{
130 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true );
131}
132
133// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
134void wxMacCoreGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise )
135{
a798c64c
SC
136 // inverse direction as we the 'normal' state is a y axis pointing down, ie mirrored to the standard core graphics setup
137 CGPathAddArc( m_path, NULL , x, y, r, startAngle, endAngle, !clockwise);
50581042
SC
138}
139
140void wxMacCoreGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
141{
142 CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
143}
144
145// closes the current subpath
146void wxMacCoreGraphicsPath::CloseSubpath()
147{
148 CGPathCloseSubpath( m_path );
149}
150
151CGPathRef wxMacCoreGraphicsPath::GetPath() const
152{
153 return m_path;
154}
155
156// gets the last point of the current path, (0,0) if not yet set
157void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
158{
159 CGPoint p = CGPathGetCurrentPoint( m_path );
160 x = p.x;
161 y = p.y;
162}
163
164//
165// Graphics Context
166//
167
168class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
169{
170 DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
171
172public:
50581042
SC
173 wxMacCoreGraphicsContext( CGContextRef cgcontext );
174
1056ddcf
SC
175 wxMacCoreGraphicsContext( WindowRef window );
176
50581042
SC
177 wxMacCoreGraphicsContext();
178
179 ~wxMacCoreGraphicsContext();
180
1056ddcf 181 void Init();
50581042
SC
182
183 // creates a path instance that corresponds to the type of graphics context, ie GDIPlus, cairo, CoreGraphics ...
184 virtual wxGraphicsPath * CreatePath();
185
186 // push the current state of the context, ie the transformation matrix on a stack
187 virtual void PushState();
188
189 // pops a stored state from the stack
190 virtual void PopState();
191
192 // clips drawings to the region
193 virtual void Clip( const wxRegion &region );
194
1056ddcf
SC
195 // clips drawings to the rect
196 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
197
198 // resets the clipping to original extent
199 virtual void ResetClip();
200
201 virtual void * GetNativeContext();
202
50581042
SC
203 //
204 // transformation
205 //
206
207 // translate
208 virtual void Translate( wxDouble dx , wxDouble dy );
209
210 // scale
211 virtual void Scale( wxDouble xScale , wxDouble yScale );
212
213 // rotate (radians)
214 virtual void Rotate( wxDouble angle );
215
216 //
217 // setting the paint
218 //
219
220 // sets the pan
221 virtual void SetPen( const wxPen &pen );
222
223 // sets the brush for filling
224 virtual void SetBrush( const wxBrush &brush );
225
226 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
227 virtual void SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
228 const wxColour&c1, const wxColour&c2);
229
230 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
231 // with radius r and color cColor
232 virtual void SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
233 const wxColour &oColor, const wxColour &cColor);
234
235 // sets the font
236 virtual void SetFont( const wxFont &font );
237
238 // sets the text color
239 virtual void SetTextColor( const wxColour &col );
240
241 // strokes along a path with the current pen
242 virtual void StrokePath( const wxGraphicsPath *path );
243
244 // fills a path with the current brush
245 virtual void FillPath( const wxGraphicsPath *path, int fillStyle = wxWINDING_RULE );
246
247 // draws a path by first filling and then stroking
248 virtual void DrawPath( const wxGraphicsPath *path, int fillStyle = wxWINDING_RULE );
249
250 //
251 // text
252 //
253
254 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y );
255
256 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
257
258 virtual void GetTextExtent( const wxString &text, wxDouble *width, wxDouble *height,
259 wxDouble *descent, wxDouble *externalLeading ) const;
260
261 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
262
263 //
264 // image support
265 //
266
267 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
268
269 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
270
50581042
SC
271 void SetNativeContext( CGContextRef cg );
272 CGPathDrawingMode GetDrawingMode() const { return m_mode; }
273
274private:
275 CGContextRef m_cgContext;
1056ddcf
SC
276 WindowRef m_windowRef;
277 bool m_releaseContext;
50581042
SC
278 CGPathDrawingMode m_mode;
279 ATSUStyle m_macATSUIStyle;
280 wxPen m_pen;
281 wxBrush m_brush;
1056ddcf 282 wxFont m_font;
50581042
SC
283 wxColor m_textForegroundColor;
284};
285
286//-----------------------------------------------------------------------------
287// constants
288//-----------------------------------------------------------------------------
289
290#if !defined( __DARWIN__ ) || defined(__MWERKS__)
291#ifndef M_PI
292const double M_PI = 3.14159265358979;
293#endif
294#endif
295
83b96a06 296static const double RAD2DEG = 180.0 / M_PI;
50581042
SC
297
298//-----------------------------------------------------------------------------
299// device context implementation
300//
301// more and more of the dc functionality should be implemented by calling
302// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step
303// also coordinate conversions should be moved to native matrix ops
304//-----------------------------------------------------------------------------
305
306// we always stock two context states, one at entry, to be able to preserve the
307// state we were called with, the other one after changing to HI Graphics orientation
308// (this one is used for getting back clippings etc)
309
310//-----------------------------------------------------------------------------
311// wxGraphicsPath implementation
312//-----------------------------------------------------------------------------
313
314//-----------------------------------------------------------------------------
315// wxGraphicsContext implementation
316//-----------------------------------------------------------------------------
317
1056ddcf 318void wxMacCoreGraphicsContext::Init()
50581042 319{
50581042
SC
320 m_cgContext = NULL;
321 m_mode = kCGPathFill;
322 m_macATSUIStyle = NULL;
1056ddcf 323 m_releaseContext = false;
50581042
SC
324}
325
326wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGContextRef cgcontext )
327{
1056ddcf
SC
328 Init();
329 m_cgContext = cgcontext;
50581042
SC
330 CGContextSaveGState( m_cgContext );
331 CGContextSaveGState( m_cgContext );
332}
333
1056ddcf
SC
334wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( WindowRef window )
335{
336 Init();
337 m_windowRef = window;
338 OSStatus status = QDBeginCGContext( GetWindowPort( window ) , &m_cgContext );
339 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
340 Rect bounds;
341 GetWindowBounds( window, kWindowContentRgn, &bounds );
342 CGContextSaveGState( m_cgContext );
343 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top );
344 CGContextScaleCTM( m_cgContext , 1 , -1 );
345 CGContextSaveGState( m_cgContext );
346 m_releaseContext = true;
347}
348
50581042
SC
349wxMacCoreGraphicsContext::wxMacCoreGraphicsContext()
350{
1056ddcf 351 Init();
50581042
SC
352}
353
354wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
355{
356 if ( m_cgContext )
357 {
358 CGContextSynchronize( m_cgContext );
359 CGContextRestoreGState( m_cgContext );
360 CGContextRestoreGState( m_cgContext );
361 }
362
1056ddcf
SC
363 if ( m_releaseContext )
364 QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
50581042
SC
365}
366
367void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
368{
1056ddcf
SC
369 HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
370 HIShapeReplacePathInCGContext( shape, m_cgContext );
371 CGContextClip( m_cgContext );
372 CFRelease( shape );
373}
374
375// clips drawings to the rect
376void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
377{
378 HIRect r = CGRectMake( x , y , w , h );
379 CGContextClipToRect( m_cgContext, r );
380}
381
382 // resets the clipping to original extent
383void wxMacCoreGraphicsContext::ResetClip()
384{
385 CGContextRestoreGState( m_cgContext );
386 CGContextSaveGState( m_cgContext );
50581042
SC
387}
388
389void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *p )
390{
391 const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
1056ddcf
SC
392 int width = m_pen.GetWidth();
393 if ( width == 0 )
394 width = 1 ;
395 if ( m_pen.GetStyle() == wxTRANSPARENT )
396 width = 0 ;
397
398 bool offset = ( width % 2 ) == 1 ;
399
400 if ( offset )
401 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
402
50581042
SC
403 CGContextAddPath( m_cgContext , path->GetPath() );
404 CGContextStrokePath( m_cgContext );
1056ddcf
SC
405
406 if ( offset )
407 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
50581042
SC
408}
409
410void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle )
411{
412 const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
413 CGPathDrawingMode mode = m_mode;
414
415 if ( fillStyle == wxODDEVEN_RULE )
416 {
417 if ( mode == kCGPathFill )
418 mode = kCGPathEOFill;
419 else if ( mode == kCGPathFillStroke )
420 mode = kCGPathEOFillStroke;
421 }
422
1056ddcf
SC
423 int width = m_pen.GetWidth();
424 if ( width == 0 )
425 width = 1 ;
426 if ( m_pen.GetStyle() == wxTRANSPARENT )
427 width = 0 ;
428
429 bool offset = ( width % 2 ) == 1 ;
430
431 if ( offset )
432 CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
433
50581042
SC
434 CGContextAddPath( m_cgContext , path->GetPath() );
435 CGContextDrawPath( m_cgContext , mode );
1056ddcf
SC
436
437 if ( offset )
438 CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
50581042
SC
439}
440
441void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle )
442{
443 const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
444
445 CGContextAddPath( m_cgContext , path->GetPath() );
446 if ( fillStyle == wxODDEVEN_RULE )
447 CGContextEOFillPath( m_cgContext );
448 else
449 CGContextFillPath( m_cgContext );
450}
451
452wxGraphicsPath* wxMacCoreGraphicsContext::CreatePath()
453{
50581042
SC
454 return new wxMacCoreGraphicsPath();
455}
456
50581042
SC
457void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
458{
459 // we allow either setting or clearing but not replacing
460 wxASSERT( m_cgContext == NULL || cg == NULL );
461
462 if ( cg )
463 CGContextSaveGState( cg );
464 m_cgContext = cg;
465}
466
467void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy )
468{
469 CGContextTranslateCTM( m_cgContext, dx, dy );
470}
471
472void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
473{
474 CGContextScaleCTM( m_cgContext , xScale , yScale );
475}
476
477void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
478{
479 CGContextRotateCTM( m_cgContext , angle );
480}
481
482void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
483{
484 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() );
485 HIRect r = CGRectMake( x , y , w , h );
486 HIViewDrawCGImage( m_cgContext , &r , image );
487 CGImageRelease( image );
488}
489
490void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
491{
492 CGRect r = CGRectMake( 00 , 00 , w , h );
493 CGContextSaveGState( m_cgContext );
494 CGContextTranslateCTM( m_cgContext, x , y + h );
495 CGContextScaleCTM( m_cgContext, 1, -1 );
496 PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
497 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
498 CGContextRestoreGState( m_cgContext );
499}
500
501void wxMacCoreGraphicsContext::PushState()
502{
503 CGContextSaveGState( m_cgContext );
504}
505
506void wxMacCoreGraphicsContext::PopState()
507{
508 CGContextRestoreGState( m_cgContext );
509}
510
511void wxMacCoreGraphicsContext::SetTextColor( const wxColour &col )
512{
513 m_textForegroundColor = col;
1056ddcf
SC
514 // to recreate the native font after color change
515 SetFont( m_font );
50581042
SC
516}
517
518#pragma mark -
519#pragma mark wxMacCoreGraphicsPattern, ImagePattern, HatchPattern classes
520
521// CGPattern wrapper class: always allocate on heap, never call destructor
522
523class wxMacCoreGraphicsPattern
524{
525public :
526 wxMacCoreGraphicsPattern() {}
527
528 // is guaranteed to be called only with a non-Null CGContextRef
529 virtual void Render( CGContextRef ctxRef ) = 0;
530
531 operator CGPatternRef() const { return m_patternRef; }
532
533protected :
534 virtual ~wxMacCoreGraphicsPattern()
535 {
536 // as this is called only when the m_patternRef is been released;
537 // don't release it again
538 }
539
540 static void _Render( void *info, CGContextRef ctxRef )
541 {
542 wxMacCoreGraphicsPattern* self = (wxMacCoreGraphicsPattern*) info;
543 if ( self && ctxRef )
544 self->Render( ctxRef );
545 }
546
547 static void _Dispose( void *info )
548 {
549 wxMacCoreGraphicsPattern* self = (wxMacCoreGraphicsPattern*) info;
550 delete self;
551 }
552
553 CGPatternRef m_patternRef;
554
555 static const CGPatternCallbacks ms_Callbacks;
556};
557
558const CGPatternCallbacks wxMacCoreGraphicsPattern::ms_Callbacks = { 0, &wxMacCoreGraphicsPattern::_Render, &wxMacCoreGraphicsPattern::_Dispose };
559
560class ImagePattern : public wxMacCoreGraphicsPattern
561{
562public :
83b96a06 563 ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform )
50581042
SC
564 {
565 wxASSERT( bmp && bmp->Ok() );
566
567 Init( (CGImageRef) bmp->CGImageCreate() , transform );
568 }
569
570 // ImagePattern takes ownership of CGImageRef passed in
83b96a06 571 ImagePattern( CGImageRef image , const CGAffineTransform& transform )
50581042
SC
572 {
573 if ( image )
574 CFRetain( image );
575
576 Init( image , transform );
577 }
578
579 virtual void Render( CGContextRef ctxRef )
580 {
581 if (m_image != NULL)
582 HIViewDrawCGImage( ctxRef, &m_imageBounds, m_image );
583 }
584
585protected :
83b96a06 586 void Init( CGImageRef image, const CGAffineTransform& transform )
50581042
SC
587 {
588 m_image = image;
589 if ( m_image )
590 {
591 m_imageBounds = CGRectMake( 0.0, 0.0, (CGFloat)CGImageGetWidth( m_image ), (CGFloat)CGImageGetHeight( m_image ) );
592 m_patternRef = CGPatternCreate(
593 this , m_imageBounds, transform ,
594 m_imageBounds.size.width, m_imageBounds.size.height,
595 kCGPatternTilingNoDistortion, true , &wxMacCoreGraphicsPattern::ms_Callbacks );
596 }
597 }
598
599 virtual ~ImagePattern()
600 {
601 if ( m_image )
602 CGImageRelease( m_image );
603 }
604
605 CGImageRef m_image;
606 CGRect m_imageBounds;
607};
608
609class HatchPattern : public wxMacCoreGraphicsPattern
610{
611public :
83b96a06 612 HatchPattern( int hatchstyle, const CGAffineTransform& transform )
50581042
SC
613 {
614 m_hatch = hatchstyle;
615 m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 );
616 m_patternRef = CGPatternCreate(
617 this , m_imageBounds, transform ,
618 m_imageBounds.size.width, m_imageBounds.size.height,
619 kCGPatternTilingNoDistortion, false , &wxMacCoreGraphicsPattern::ms_Callbacks );
620 }
621
622 void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
623 {
624#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
625 if ( UMAGetSystemVersion() >= 0x1040 )
626 {
627 CGContextStrokeLineSegments( ctxRef , pts , count );
628 }
629 else
630#endif
631 {
632 CGContextBeginPath( ctxRef );
633 for (size_t i = 0; i < count; i += 2)
634 {
635 CGContextMoveToPoint(ctxRef, pts[i].x, pts[i].y);
636 CGContextAddLineToPoint(ctxRef, pts[i+1].x, pts[i+1].y);
637 }
638 CGContextStrokePath(ctxRef);
639 }
640 }
641
642 virtual void Render( CGContextRef ctxRef )
643 {
644 switch ( m_hatch )
645 {
646 case wxBDIAGONAL_HATCH :
647 {
648 CGPoint pts[] =
649 {
650 { 8.0 , 0.0 } , { 0.0 , 8.0 }
651 };
652 StrokeLineSegments( ctxRef , pts , 2 );
653 }
654 break;
655
656 case wxCROSSDIAG_HATCH :
657 {
658 CGPoint pts[] =
659 {
660 { 0.0 , 0.0 } , { 8.0 , 8.0 } ,
661 { 8.0 , 0.0 } , { 0.0 , 8.0 }
662 };
663 StrokeLineSegments( ctxRef , pts , 4 );
664 }
665 break;
666
667 case wxFDIAGONAL_HATCH :
668 {
669 CGPoint pts[] =
670 {
671 { 0.0 , 0.0 } , { 8.0 , 8.0 }
672 };
673 StrokeLineSegments( ctxRef , pts , 2 );
674 }
675 break;
676
677 case wxCROSS_HATCH :
678 {
679 CGPoint pts[] =
680 {
681 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
682 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
683 };
684 StrokeLineSegments( ctxRef , pts , 4 );
685 }
686 break;
687
688 case wxHORIZONTAL_HATCH :
689 {
690 CGPoint pts[] =
691 {
692 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
693 };
694 StrokeLineSegments( ctxRef , pts , 2 );
695 }
696 break;
697
698 case wxVERTICAL_HATCH :
699 {
700 CGPoint pts[] =
701 {
702 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
703 };
704 StrokeLineSegments( ctxRef , pts , 2 );
705 }
706 break;
707
708 default:
709 break;
710 }
711 }
712
713protected :
714 virtual ~HatchPattern() {}
715
716 CGRect m_imageBounds;
717 int m_hatch;
718};
719
720#pragma mark -
721
722void wxMacCoreGraphicsContext::SetPen( const wxPen &pen )
723{
724 m_pen = pen;
725 if ( m_cgContext == NULL )
726 return;
727
728 bool fill = m_brush.GetStyle() != wxTRANSPARENT;
729 bool stroke = pen.GetStyle() != wxTRANSPARENT;
730
731#if 0
732 // we can benchmark performance; should go into a setting eventually
733 CGContextSetShouldAntialias( m_cgContext , false );
734#endif
735
83b96a06 736 if ( fill || stroke )
50581042
SC
737 {
738 // set up brushes
739 m_mode = kCGPathFill; // just a default
740
741 if ( stroke )
742 {
743 CGContextSetRGBStrokeColor( m_cgContext , pen.GetColour().Red() / 255.0 , pen.GetColour().Green() / 255.0 ,
744 pen.GetColour().Blue() / 255.0 , pen.GetColour().Alpha() / 255.0 );
745
746 // TODO: * m_dc->m_scaleX
747 CGFloat penWidth = pen.GetWidth();
748 if (penWidth <= 0.0)
749 penWidth = 0.1;
750 CGContextSetLineWidth( m_cgContext , penWidth );
751
752 CGLineCap cap;
753 switch ( pen.GetCap() )
754 {
755 case wxCAP_ROUND :
756 cap = kCGLineCapRound;
757 break;
758
759 case wxCAP_PROJECTING :
760 cap = kCGLineCapSquare;
761 break;
762
763 case wxCAP_BUTT :
764 cap = kCGLineCapButt;
765 break;
766
767 default :
768 cap = kCGLineCapButt;
769 break;
770 }
771
772 CGLineJoin join;
773 switch ( pen.GetJoin() )
774 {
775 case wxJOIN_BEVEL :
776 join = kCGLineJoinBevel;
777 break;
778
779 case wxJOIN_MITER :
780 join = kCGLineJoinMiter;
781 break;
782
783 case wxJOIN_ROUND :
784 join = kCGLineJoinRound;
785 break;
786
787 default :
788 join = kCGLineJoinMiter;
789 break;
790 }
791
792 m_mode = kCGPathStroke;
793 int count = 0;
794
795 const CGFloat *lengths = NULL;
796 CGFloat *userLengths = NULL;
797
798 const CGFloat dashUnit = penWidth < 1.0 ? 1.0 : penWidth;
799
800 const CGFloat dotted[] = { dashUnit , dashUnit + 2.0 };
801 const CGFloat short_dashed[] = { 9.0 , 6.0 };
802 const CGFloat dashed[] = { 19.0 , 9.0 };
803 const CGFloat dotted_dashed[] = { 9.0 , 6.0 , 3.0 , 3.0 };
804
805 switch ( pen.GetStyle() )
806 {
807 case wxSOLID :
808 break;
809
810 case wxDOT :
811 lengths = dotted;
812 count = WXSIZEOF(dotted);
813 break;
814
815 case wxLONG_DASH :
816 lengths = dashed;
817 count = WXSIZEOF(dashed);
818 break;
819
820 case wxSHORT_DASH :
821 lengths = short_dashed;
822 count = WXSIZEOF(short_dashed);
823 break;
824
825 case wxDOT_DASH :
826 lengths = dotted_dashed;
827 count = WXSIZEOF(dotted_dashed);
828 break;
829
830 case wxUSER_DASH :
831 wxDash *dashes;
832 count = pen.GetDashes( &dashes );
833 if ((dashes != NULL) && (count > 0))
834 {
835 userLengths = new CGFloat[count];
836 for ( int i = 0; i < count; ++i )
837 {
838 userLengths[i] = dashes[i] * dashUnit;
839
840 if ( i % 2 == 1 && userLengths[i] < dashUnit + 2.0 )
841 userLengths[i] = dashUnit + 2.0;
842 else if ( i % 2 == 0 && userLengths[i] < dashUnit )
843 userLengths[i] = dashUnit;
844 }
845 }
846 lengths = userLengths;
847 break;
848
849 case wxSTIPPLE :
850 {
851 CGFloat alphaArray[1] = { 1.0 };
852 wxBitmap* bmp = pen.GetStipple();
853 if ( bmp && bmp->Ok() )
854 {
855 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) );
856 CGContextSetStrokeColorSpace( m_cgContext , patternSpace );
857 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
858 CGContextSetStrokePattern( m_cgContext, pattern , alphaArray );
859 }
860 }
861 break;
862
863 default :
864 {
865 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
866 CGContextSetStrokeColorSpace( m_cgContext , patternSpace );
867 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( pen.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
868
869 CGFloat colorArray[4] = { pen.GetColour().Red() / 255.0 , pen.GetColour().Green() / 255.0 ,
870 pen.GetColour().Blue() / 255.0 , pen.GetColour().Alpha() / 255.0 };
871
872 CGContextSetStrokePattern( m_cgContext, pattern , colorArray );
873 }
874 break;
875 }
876
877 if ((lengths != NULL) && (count > 0))
878 {
879 CGContextSetLineDash( m_cgContext , 0 , lengths , count );
880 // force the line cap, otherwise we get artifacts (overlaps) and just solid lines
881 cap = kCGLineCapButt;
882 }
883 else
884 {
885 CGContextSetLineDash( m_cgContext , 0 , NULL , 0 );
886 }
887
888 CGContextSetLineCap( m_cgContext , cap );
889 CGContextSetLineJoin( m_cgContext , join );
890
891 delete[] userLengths;
892 }
893
894 if ( fill && stroke )
895 m_mode = kCGPathFillStroke;
896 }
897}
898
899void wxMacCoreGraphicsContext::SetBrush( const wxBrush &brush )
900{
901 m_brush = brush;
902 if ( m_cgContext == NULL )
903 return;
904
905 bool fill = brush.GetStyle() != wxTRANSPARENT;
906 bool stroke = m_pen.GetStyle() != wxTRANSPARENT;
907
908#if 0
909 // we can benchmark performance, should go into a setting later
910 CGContextSetShouldAntialias( m_cgContext , false );
911#endif
912
83b96a06 913 if ( fill || stroke )
50581042
SC
914 {
915 // setup brushes
916 m_mode = kCGPathFill; // just a default
917
918 if ( fill )
919 {
920 if ( brush.GetStyle() == wxSOLID )
921 {
922 CGContextSetRGBFillColor( m_cgContext , brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
923 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 );
924 }
925 else if ( brush.IsHatch() )
926 {
927 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) );
928 CGContextSetFillColorSpace( m_cgContext , patternSpace );
929 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( brush.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
930
931 CGFloat colorArray[4] = { brush.GetColour().Red() / 255.0 , brush.GetColour().Green() / 255.0 ,
932 brush.GetColour().Blue() / 255.0 , brush.GetColour().Alpha() / 255.0 };
933
934 CGContextSetFillPattern( m_cgContext, pattern , colorArray );
935 }
936 else
937 {
938 // now brush is a bitmap
939 CGFloat alphaArray[1] = { 1.0 };
940 wxBitmap* bmp = brush.GetStipple();
941 if ( bmp && bmp->Ok() )
942 {
943 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) );
944 CGContextSetFillColorSpace( m_cgContext , patternSpace );
945 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
946 CGContextSetFillPattern( m_cgContext, pattern , alphaArray );
947 }
948 }
949
950 m_mode = kCGPathFill;
951 }
952
953 if ( fill && stroke )
954 m_mode = kCGPathFillStroke;
955 else if ( stroke )
956 m_mode = kCGPathStroke;
957 }
958}
959
960// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
961void wxMacCoreGraphicsContext::SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
962 const wxColour&c1, const wxColour&c2)
963{
964}
965
966// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
967// with radius r and color cColor
968void wxMacCoreGraphicsContext::SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
969 const wxColour &oColor, const wxColour &cColor)
970{
971}
972
973
974void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
975{
976 DrawText(str, x, y, 0.0);
977}
978
38af4365 979void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
50581042
SC
980{
981 OSStatus status = noErr;
982 ATSUTextLayout atsuLayout;
983 UniCharCount chars = str.length();
984 UniChar* ubuf = NULL;
985
986#if SIZEOF_WCHAR_T == 4
987 wxMBConvUTF16 converter;
988#if wxUSE_UNICODE
989 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
990 ubuf = (UniChar*) malloc( unicharlen + 2 );
991 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
992#else
993 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
994 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
995 ubuf = (UniChar*) malloc( unicharlen + 2 );
996 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
997#endif
998 chars = unicharlen / 2;
999#else
1000#if wxUSE_UNICODE
1001 ubuf = (UniChar*) str.wc_str();
1002#else
1003 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1004 chars = wxWcslen( wchar.data() );
1005 ubuf = (UniChar*) wchar.data();
1006#endif
1007#endif
1008
1009 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1010 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout );
1011
1012 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1013
1014 status = ::ATSUSetTransientFontMatching( atsuLayout , true );
1015 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1016
1017 int iAngle = int( angle * RAD2DEG );
1018 if ( abs(iAngle) > 0 )
1019 {
1020 Fixed atsuAngle = IntToFixed( iAngle );
1021 ATSUAttributeTag atsuTags[] =
1022 {
1023 kATSULineRotationTag ,
1024 };
1025 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1026 {
1027 sizeof( Fixed ) ,
1028 };
1029 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1030 {
1031 &atsuAngle ,
1032 };
1033 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1034 atsuTags, atsuSizes, atsuValues );
1035 }
1036
1037 {
1038 ATSUAttributeTag atsuTags[] =
1039 {
1040 kATSUCGContextTag ,
1041 };
1042 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1043 {
1044 sizeof( CGContextRef ) ,
1045 };
1046 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1047 {
1048 &m_cgContext ,
1049 };
1050 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag),
1051 atsuTags, atsuSizes, atsuValues );
1052 }
1053
1054 ATSUTextMeasurement textBefore, textAfter;
1055 ATSUTextMeasurement ascent, descent;
1056
1057 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1058 &textBefore , &textAfter, &ascent , &descent );
1059
1060 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1061
1062 Rect rect;
1063/*
1064 // TODO
1065 if ( m_backgroundMode == wxSOLID )
1066 {
1067 wxGraphicsPath* path = m_graphicContext->CreatePath();
1068 path->MoveToPoint( drawX , drawY );
1069 path->AddLineToPoint(
1070 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ,
1071 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) );
1072 path->AddLineToPoint(
1073 (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1074 (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1075 path->AddLineToPoint(
1076 (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ,
1077 (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) );
1078
1079 m_graphicContext->FillPath( path , m_textBackgroundColour );
1080 delete path;
1081 }
1082*/
1083 x += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
1084 y += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
1085
1086 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1087 IntToFixed(x) , IntToFixed(y) , &rect );
1088 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1089
1090 CGContextSaveGState(m_cgContext);
1091 CGContextTranslateCTM(m_cgContext, x, y);
1092 CGContextScaleCTM(m_cgContext, 1, -1);
1093 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1094 IntToFixed(0) , IntToFixed(0) );
1095
1096 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1097
1098 CGContextRestoreGState(m_cgContext);
1099
1100 ::ATSUDisposeTextLayout(atsuLayout);
1101
1102#if SIZEOF_WCHAR_T == 4
1103 free( ubuf );
1104#endif
1105}
1106
1107void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1108 wxDouble *descent, wxDouble *externalLeading ) const
1109{
1110 wxCHECK_RET( m_macATSUIStyle != NULL, wxT("wxDC(cg)::DoGetTextExtent - no valid font set") );
1111
1112 OSStatus status = noErr;
1113
1114 ATSUTextLayout atsuLayout;
1115 UniCharCount chars = str.length();
1116 UniChar* ubuf = NULL;
1117
1118#if SIZEOF_WCHAR_T == 4
1119 wxMBConvUTF16 converter;
1120#if wxUSE_UNICODE
1121 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 );
1122 ubuf = (UniChar*) malloc( unicharlen + 2 );
1123 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 );
1124#else
1125 const wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1126 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1127 ubuf = (UniChar*) malloc( unicharlen + 2 );
1128 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1129#endif
1130 chars = unicharlen / 2;
1131#else
1132#if wxUSE_UNICODE
1133 ubuf = (UniChar*) str.wc_str();
1134#else
1135 wxWCharBuffer wchar = str.wc_str( wxConvLocal );
1136 chars = wxWcslen( wchar.data() );
1137 ubuf = (UniChar*) wchar.data();
1138#endif
1139#endif
1140
1141 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1142 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout );
1143
1144 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1145
1146 ATSUTextMeasurement textBefore, textAfter;
1147 ATSUTextMeasurement textAscent, textDescent;
1148
1149 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1150 &textBefore , &textAfter, &textAscent , &textDescent );
1151
1152 if ( height )
1153 *height = FixedToInt(textAscent + textDescent);
1154 if ( descent )
1155 *descent = FixedToInt(textDescent);
1156 if ( externalLeading )
1157 *externalLeading = 0;
1158 if ( width )
1159 *width = FixedToInt(textAfter - textBefore);
1160
1161 ::ATSUDisposeTextLayout(atsuLayout);
1162}
1163
1164void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1165{
1166 widths.Empty();
1167 widths.Add(0, text.length());
1168
1169 if (text.empty())
1170 return;
1171
1172 ATSUTextLayout atsuLayout;
1173 UniCharCount chars = text.length();
1174 UniChar* ubuf = NULL;
1175
1176#if SIZEOF_WCHAR_T == 4
1177 wxMBConvUTF16 converter;
1178#if wxUSE_UNICODE
1179 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 );
1180 ubuf = (UniChar*) malloc( unicharlen + 2 );
1181 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 );
1182#else
1183 const wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1184 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 );
1185 ubuf = (UniChar*) malloc( unicharlen + 2 );
1186 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 );
1187#endif
1188 chars = unicharlen / 2;
1189#else
1190#if wxUSE_UNICODE
1191 ubuf = (UniChar*) text.wc_str();
1192#else
1193 wxWCharBuffer wchar = text.wc_str( wxConvLocal );
1194 chars = wxWcslen( wchar.data() );
1195 ubuf = (UniChar*) wchar.data();
1196#endif
1197#endif
1198
83b96a06 1199 ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
50581042
SC
1200 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout );
1201
1202 for ( int pos = 0; pos < (int)chars; pos ++ )
1203 {
1204 unsigned long actualNumberOfBounds = 0;
1205 ATSTrapezoid glyphBounds;
1206
1207 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1208 OSStatus result;
1209 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1,
1210 kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1211 if (result != noErr || actualNumberOfBounds != 1 )
1212 return;
1213
1214 widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );
1215 //unsigned char uch = s[i];
1216 }
1217
1218 ::ATSUDisposeTextLayout(atsuLayout);
1219}
1220
1221void wxMacCoreGraphicsContext::SetFont( const wxFont &font )
1222{
1223 if ( m_macATSUIStyle )
1224 {
1225 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1226 m_macATSUIStyle = NULL;
1227 }
1228
1229 if ( font.Ok() )
1230 {
1056ddcf 1231 m_font = font ;
50581042
SC
1232 OSStatus status;
1233
1234 status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle );
1235
1236 wxASSERT_MSG( status == noErr, wxT("couldn't create ATSU style") );
1237
1238 // we need the scale here ...
1239
1240 Fixed atsuSize = IntToFixed( int( /*m_scaleY*/ 1 * font.MacGetFontSize()) );
1241 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColor.GetPixel() );
1242 ATSUAttributeTag atsuTags[] =
1243 {
1244 kATSUSizeTag ,
1245 kATSUColorTag ,
1246 };
1247 ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1248 {
1249 sizeof( Fixed ) ,
1250 sizeof( RGBColor ) ,
1251 };
1252 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] =
1253 {
1254 &atsuSize ,
1255 &atsuColor ,
1256 };
1257
1258 status = ::ATSUSetAttributes(
1259 (ATSUStyle)m_macATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) ,
1260 atsuTags, atsuSizes, atsuValues);
1261
1262 wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") );
1263 }
1264}
1265
1056ddcf
SC
1266void * wxMacCoreGraphicsContext::GetNativeContext()
1267{
1268 return m_cgContext;
1269}
1270
50581042
SC
1271wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc )
1272{
1273 return new wxMacCoreGraphicsContext((CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
1274}
1275
1056ddcf
SC
1276wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
1277{
7471064e
SC
1278 wxGraphicsContext* ctx = new wxMacCoreGraphicsContext( (WindowRef) window->MacGetTopLevelWindowRef() );
1279 CGContextRef cg = (CGContextRef) ctx->GetNativeContext() ;
1280 CGContextRestoreGState( cg );
1281 int x , y;
1282 x = y = 0;
1283 window->MacWindowToRootWindow( &x , &y );
1284 CGContextTranslateCTM( cg, x, y );
1285 CGContextSaveGState( cg );
1286 return ctx;
1287
1056ddcf
SC
1288}
1289
1290wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
1291{
1292 return new wxMacCoreGraphicsContext((CGContextRef)context);
1293}
1294
513b47e9
SC
1295wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window )
1296{
1297 return new wxMacCoreGraphicsContext((WindowRef)window);
1298}
1299
50581042 1300#endif // wxMAC_USE_CORE_GRAPHICS