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