]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dccg.cpp
wx..._EX_METAL styles support
[wxWidgets.git] / src / mac / carbon / dccg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dc.cpp
3 // Purpose: wxDC class
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/dc.h"
15
16 #if wxMAC_USE_CORE_GRAPHICS
17
18 #include "wx/app.h"
19 #include "wx/mac/uma.h"
20 #include "wx/dcmemory.h"
21 #include "wx/dcprint.h"
22 #include "wx/region.h"
23 #include "wx/image.h"
24 #include "wx/log.h"
25
26
27 #ifdef __MSL__
28 #if __MSL__ >= 0x6000
29 #include "math.h"
30 using namespace std ;
31 #endif
32 #endif
33
34 #include "wx/mac/private.h"
35
36 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
37
38 //-----------------------------------------------------------------------------
39 // constants
40 //-----------------------------------------------------------------------------
41
42 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
43 #ifndef M_PI
44 const double M_PI = 3.14159265358979 ;
45 #endif
46 #endif
47 const double RAD2DEG = 180.0 / M_PI;
48 const short kEmulatedMode = -1 ;
49 const short kUnsupportedMode = -2 ;
50
51 extern TECObjectRef s_TECNativeCToUnicode ;
52
53 // TODO Update
54 // The text ctrl implementation still needs that for the non hiview implementation
55
56 wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
57 wxMacPortSaver( (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) )
58 {
59 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
60 m_formerClip = NewRgn() ;
61 m_newClip = NewRgn() ;
62 GetClip( m_formerClip ) ;
63
64 if ( win )
65 {
66 // guard against half constructed objects, this just leads to a empty clip
67 if( win->GetPeer() )
68 {
69 int x = 0 , y = 0;
70 win->MacWindowToRootWindow( &x,&y ) ;
71 // get area including focus rect
72 CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
73 if ( !EmptyRgn( m_newClip ) )
74 OffsetRgn( m_newClip , x , y ) ;
75 }
76
77 SetClip( m_newClip ) ;
78 }
79 }
80
81 wxMacWindowClipper::~wxMacWindowClipper()
82 {
83 SetPort( m_newPort ) ;
84 SetClip( m_formerClip ) ;
85 DisposeRgn( m_newClip ) ;
86 DisposeRgn( m_formerClip ) ;
87 }
88
89 wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
90 wxMacWindowClipper( win )
91 {
92 // the port is already set at this point
93 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
94 GetThemeDrawingState( &m_themeDrawingState ) ;
95 }
96
97 wxMacWindowStateSaver::~wxMacWindowStateSaver()
98 {
99 SetPort( m_newPort ) ;
100 SetThemeDrawingState( m_themeDrawingState , true ) ;
101 }
102
103 // minimal implementation only used for appearance drawing < 10.3
104
105 wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
106 m_ph( (GrafPtr) dc->m_macPort )
107 {
108 wxASSERT( dc->Ok() ) ;
109 m_dc = dc ;
110 // dc->MacSetupPort(&m_ph) ;
111 }
112 wxMacPortSetter::~wxMacPortSetter()
113 {
114 // m_dc->MacCleanupPort(&m_ph) ;
115 }
116
117 //-----------------------------------------------------------------------------
118 // Local functions
119 //-----------------------------------------------------------------------------
120
121 static inline double dmin(double a, double b) { return a < b ? a : b; }
122 static inline double dmax(double a, double b) { return a > b ? a : b; }
123 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
124
125 //-----------------------------------------------------------------------------
126 // device context implementation
127 //
128 // more and more of the dc functionality should be implemented by calling
129 // the appropricate wxMacCGContext, but we will have to do that step by step
130 // also coordinate conversions should be moved to native matrix ops
131 //-----------------------------------------------------------------------------
132
133 // we always stock two context states, one at entry, to be able to preserve the
134 // state we were called with, the other one after changing to HI Graphics orientation
135 // (this one is used for getting back clippings etc)
136
137 wxMacCGPath::wxMacCGPath()
138 {
139 m_path = CGPathCreateMutable() ;
140 }
141
142 wxMacCGPath::~wxMacCGPath()
143 {
144 CGPathRelease( m_path ) ;
145 }
146
147 // Starts a new subpath at
148 void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
149 {
150 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
151 }
152
153 void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
154 {
155 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
156 }
157
158 void wxMacCGPath::AddQuadCurveToPoint( wxCoord cx1, wxCoord cy1, wxCoord x1, wxCoord y1 )
159 {
160 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x1 , y1 );
161 }
162
163 void wxMacCGPath::AddRectangle( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
164 {
165 CGRect cgRect = { { x , y } , { w , h } } ;
166 CGPathAddRect( m_path , NULL , cgRect ) ;
167 }
168
169 void wxMacCGPath::AddCircle( wxCoord x, wxCoord y , wxCoord r )
170 {
171 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true ) ;
172 }
173
174 // closes the current subpath
175 void wxMacCGPath::CloseSubpath()
176 {
177 CGPathCloseSubpath( m_path ) ;
178 }
179
180 CGPathRef wxMacCGPath::GetPath() const
181 {
182 return m_path ;
183 }
184
185 wxMacCGContext::wxMacCGContext( CGrafPtr port )
186 {
187 m_qdPort = port ;
188 m_cgContext = NULL ;
189 }
190
191 wxMacCGContext::wxMacCGContext( CGContextRef cgcontext )
192 {
193 m_qdPort = NULL ;
194 m_cgContext = cgcontext ;
195 CGContextSaveGState( m_cgContext ) ;
196 CGContextSaveGState( m_cgContext ) ;
197 }
198
199 wxMacCGContext::wxMacCGContext()
200 {
201 m_qdPort = NULL ;
202 m_cgContext = NULL ;
203 }
204
205 wxMacCGContext::~wxMacCGContext()
206 {
207 if ( m_cgContext )
208 {
209 CGContextSynchronize( m_cgContext ) ;
210 CGContextRestoreGState( m_cgContext ) ;
211 CGContextRestoreGState( m_cgContext ) ;
212 }
213 if ( m_qdPort )
214 CGContextRelease( m_cgContext ) ;
215 }
216
217
218 void wxMacCGContext::Clip( const wxRegion &region )
219 {
220 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
221 }
222
223 void wxMacCGContext::StrokePath( const wxGraphicPath *p )
224 {
225 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
226 CGContextAddPath( m_cgContext , path->GetPath() ) ;
227 CGContextStrokePath( m_cgContext ) ;
228 }
229
230 void wxMacCGContext::DrawPath( const wxGraphicPath *p , int fillStyle )
231 {
232 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
233 CGPathDrawingMode mode = m_mode ;
234 if ( fillStyle == wxODDEVEN_RULE )
235 {
236 if ( mode == kCGPathFill )
237 mode = kCGPathEOFill ;
238 else if ( mode == kCGPathFillStroke )
239 mode = kCGPathEOFillStroke ;
240 }
241 CGContextAddPath( m_cgContext , path->GetPath() ) ;
242 CGContextDrawPath( m_cgContext , mode ) ;
243 }
244
245 void wxMacCGContext::FillPath( const wxGraphicPath *p , const wxColor &fillColor , int fillStyle )
246 {
247 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
248 CGContextSaveGState( m_cgContext ) ;
249
250 RGBColor col = MAC_WXCOLORREF( fillColor.GetPixel() ) ;
251 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
252 CGPathDrawingMode mode = kCGPathFill ;
253
254 if ( fillStyle == wxODDEVEN_RULE )
255 mode = kCGPathEOFill ;
256
257 CGContextBeginPath( m_cgContext ) ;
258 CGContextAddPath( m_cgContext , path->GetPath() ) ;
259 CGContextClosePath( m_cgContext ) ;
260 CGContextDrawPath( m_cgContext , mode ) ;
261
262 CGContextRestoreGState( m_cgContext ) ;
263 }
264
265 wxGraphicPath* wxMacCGContext::CreatePath()
266 {
267 // make sure that we now have a real cgref, before doing
268 // anything with paths
269 CGContextRef cg = GetNativeContext() ;
270 cg = NULL ;
271 return new wxMacCGPath() ;
272 }
273
274 // in case we only got a QDPort only create a cgref now
275
276 CGContextRef wxMacCGContext::GetNativeContext()
277 {
278 if( m_cgContext == NULL )
279 {
280 Rect bounds ;
281 GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
282 OSStatus status = CreateCGContextForPort((CGrafPtr) m_qdPort , &m_cgContext) ;
283 CGContextSaveGState( m_cgContext ) ;
284
285 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
286 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
287 CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
288
289 CGContextSaveGState( m_cgContext ) ;
290 SetPen( m_pen ) ;
291 SetBrush( m_brush ) ;
292 }
293 return m_cgContext ;
294 }
295
296 void wxMacCGContext::SetNativeContext( CGContextRef cg )
297 {
298 // we allow either setting or clearing but not replacing
299 wxASSERT( m_cgContext == NULL || cg == NULL ) ;
300 if ( cg )
301 CGContextSaveGState( cg ) ;
302 m_cgContext = cg ;
303 }
304
305 #pragma mark -
306
307 // wrapper class for a CGPattern, always allocate on heap, never call destructor
308
309 class wxMacCGPattern
310 {
311 public :
312 wxMacCGPattern()
313 {
314 }
315
316 // is guaranteed to be called only with a non-Null CGContextRef
317 virtual void Render( CGContextRef ctxRef ) = 0 ;
318
319 operator CGPatternRef() const { return m_patternRef ; }
320 protected :
321 virtual ~wxMacCGPattern()
322 {
323 // as this is called only when our m_patternRef is been released, don't release
324 // it again
325 }
326
327 static void _Render( void *info, CGContextRef ctxRef )
328 {
329 wxMacCGPattern* self = (wxMacCGPattern*) info ;
330 if ( self && ctxRef )
331 self->Render( ctxRef ) ;
332 }
333
334 static void _Dispose( void *info )
335 {
336 wxMacCGPattern* self = (wxMacCGPattern*) info ;
337 delete self ;
338 }
339
340 CGPatternRef m_patternRef ;
341
342 static const CGPatternCallbacks ms_Callbacks ;
343 } ;
344
345 const CGPatternCallbacks wxMacCGPattern::ms_Callbacks = { 0, &wxMacCGPattern::_Render, &wxMacCGPattern::_Dispose };
346
347 class ImagePattern : public wxMacCGPattern
348 {
349 public :
350 ImagePattern( const wxBitmap* bmp , CGAffineTransform transform )
351 {
352 wxASSERT( bmp && bmp->Ok() ) ;
353 Init( (CGImageRef) bmp->CGImageCreate() , transform ) ;
354 }
355
356 // ImagePattern takes ownership of CGImageRef passed in
357 ImagePattern( CGImageRef image , CGAffineTransform transform )
358 {
359 if ( image )
360 {
361 CFRetain( image ) ;
362 }
363 Init( image , transform ) ;
364 }
365
366 virtual void Render( CGContextRef ctxRef )
367 {
368 if (m_image != NULL)
369 HIViewDrawCGImage( ctxRef, &m_imageBounds, m_image );
370 }
371
372 protected :
373 void Init( CGImageRef image , CGAffineTransform transform )
374 {
375 m_image = image ;
376 if ( m_image )
377 {
378 m_imageBounds = CGRectMake( 0.0, 0.0, (float)CGImageGetWidth( m_image ), (float)CGImageGetHeight( m_image ) ) ;
379 m_patternRef = CGPatternCreate( this , m_imageBounds, transform ,
380 m_imageBounds.size.width, m_imageBounds.size.height,
381 kCGPatternTilingNoDistortion, true , &wxMacCGPattern::ms_Callbacks ) ;
382 }
383 }
384
385 ~ImagePattern()
386 {
387 if ( m_image )
388 CGImageRelease( m_image ) ;
389 }
390 CGImageRef m_image ;
391 CGRect m_imageBounds ;
392 } ;
393
394 class HatchPattern : public wxMacCGPattern
395 {
396 public :
397 HatchPattern( int hatchstyle , CGAffineTransform transform )
398 {
399 m_hatch = hatchstyle ;
400 m_imageBounds = CGRectMake( 0.0, 0.0, 8.0 , 8.0 ) ;
401 m_patternRef = CGPatternCreate( this , m_imageBounds, transform ,
402 m_imageBounds.size.width, m_imageBounds.size.height,
403 kCGPatternTilingNoDistortion, false , &wxMacCGPattern::ms_Callbacks ) ;
404 }
405
406 void StrokeLineSegments( CGContextRef ctxRef , const CGPoint pts[] , size_t count )
407 {
408 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
409 if ( UMAGetSystemVersion() >= 0x1040 )
410 {
411 CGContextStrokeLineSegments( ctxRef , pts , count ) ;
412 }
413 else
414 #endif
415 {
416 CGContextBeginPath (ctxRef);
417 for (size_t i = 0; i < count; i += 2) {
418 CGContextMoveToPoint(ctxRef, pts[i].x, pts[i].y);
419 CGContextAddLineToPoint(ctxRef, pts[i+1].x, pts[i+1].y);
420 }
421 CGContextStrokePath(ctxRef);
422 }
423 }
424
425 virtual void Render( CGContextRef ctxRef )
426 {
427 switch( m_hatch )
428 {
429 case wxBDIAGONAL_HATCH :
430 {
431 CGPoint pts[] = {
432 { 8.0 , 0.0 } , { 0.0 , 8.0 }
433 };
434 StrokeLineSegments( ctxRef , pts , 2 ) ;
435 }
436 break ;
437 case wxCROSSDIAG_HATCH :
438 {
439 CGPoint pts[] = {
440 { 0.0 , 0.0 } , { 8.0 , 8.0 } ,
441 { 8.0 , 0.0 } , { 0.0 , 8.0 }
442 };
443 StrokeLineSegments( ctxRef , pts , 4 ) ;
444 }
445 break ;
446 case wxFDIAGONAL_HATCH :
447 {
448 CGPoint pts[] = {
449 { 0.0 , 0.0 } , { 8.0 , 8.0 }
450 };
451 StrokeLineSegments( ctxRef , pts , 2 ) ;
452 }
453 break ;
454 case wxCROSS_HATCH :
455 {
456 CGPoint pts[] = {
457 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
458 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
459 };
460 StrokeLineSegments( ctxRef , pts , 4 ) ;
461 }
462 break ;
463 case wxHORIZONTAL_HATCH :
464 {
465 CGPoint pts[] = {
466 { 0.0 , 4.0 } , { 8.0 , 4.0 } ,
467 };
468 StrokeLineSegments( ctxRef , pts , 2 ) ;
469 }
470 break ;
471 case wxVERTICAL_HATCH :
472 {
473 CGPoint pts[] = {
474 { 4.0 , 0.0 } , { 4.0 , 8.0 } ,
475 };
476 StrokeLineSegments( ctxRef , pts , 2 ) ;
477 }
478 break ;
479 }
480 }
481
482 protected :
483 ~HatchPattern()
484 {
485 }
486 int m_hatch ;
487 CGRect m_imageBounds ;
488 } ;
489
490 void wxMacCGContext::SetPen( const wxPen &pen )
491 {
492 m_pen = pen ;
493 if ( m_cgContext == NULL )
494 return ;
495 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
496 bool stroke = pen.GetStyle() != wxTRANSPARENT ;
497
498 #if 0
499 // we can benchmark performance, should go into a setting later
500 CGContextSetShouldAntialias( m_cgContext , false ) ;
501 #endif
502 if ( fill | stroke )
503 {
504 // setup brushes
505 m_mode = kCGPathFill ; // just a default
506
507 if ( fill )
508 {
509 m_mode = kCGPathFill ;
510 }
511 if ( stroke )
512 {
513 RGBColor col = MAC_WXCOLORREF( pen.GetColour().GetPixel() ) ;
514 CGContextSetRGBStrokeColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
515
516 /* TODO * m_dc->m_scaleX */
517 float penWidth = pen.GetWidth();
518 if (penWidth <= 0.0)
519 penWidth = 0.1;
520 CGContextSetLineWidth( m_cgContext , penWidth ) ;
521
522 CGLineCap cap ;
523 switch( pen.GetCap() )
524 {
525 case wxCAP_ROUND :
526 cap = kCGLineCapRound ;
527 break ;
528 case wxCAP_PROJECTING :
529 cap = kCGLineCapSquare ;
530 break ;
531 case wxCAP_BUTT :
532 cap = kCGLineCapButt ;
533 break ;
534 default :
535 cap = kCGLineCapButt ;
536 break ;
537 }
538
539 CGLineJoin join ;
540 switch( pen.GetJoin() )
541 {
542 case wxJOIN_BEVEL :
543 join = kCGLineJoinBevel ;
544 break ;
545 case wxJOIN_MITER :
546 join = kCGLineJoinMiter ;
547 break ;
548 case wxJOIN_ROUND :
549 join = kCGLineJoinRound ;
550 break ;
551 default :
552 join = kCGLineJoinMiter ;
553 break;
554 }
555 CGContextSetLineJoin( m_cgContext , join ) ;
556
557 m_mode = kCGPathStroke ;
558 int count = 0 ;
559
560 const float *lengths = NULL ;
561 float *userLengths = NULL ;
562
563 int dashUnit = ( penWidth < 1.0 ) ? 1.0 : penWidth;
564
565 const float dotted[] = { dashUnit , dashUnit + 2.0 };
566 const float short_dashed[] = { 9.0 , 6.0 };
567 const float dashed[] = { 19.0 , 9.0 };
568 const float dotted_dashed[] = { 9.0 , 6.0 , 3.0 , 3.0 };
569
570
571 switch( pen.GetStyle() )
572 {
573 case wxSOLID :
574 break ;
575 case wxDOT :
576 lengths = dotted ;
577 count = WXSIZEOF(dotted);
578 break ;
579 case wxLONG_DASH :
580 lengths = dashed ;
581 count = WXSIZEOF(dashed) ;
582 break ;
583 case wxSHORT_DASH :
584 lengths = short_dashed ;
585 count = WXSIZEOF(short_dashed) ;
586 break ;
587 case wxDOT_DASH :
588 lengths = dotted_dashed ;
589 count = WXSIZEOF(dotted_dashed);
590 break ;
591 case wxUSER_DASH :
592 wxDash *dashes ;
593 count = pen.GetDashes( &dashes ) ;
594 if ((dashes != NULL) && (count > 0))
595 {
596 userLengths = new float[count] ;
597 for( int i = 0 ; i < count ; ++i )
598 {
599 userLengths[i] = (float)dashes[i] * dashUnit ;
600
601 if ( i % 2 == 1 && userLengths[i] < dashUnit + 2.0 )
602 userLengths[i] = dashUnit + 2.0 ;
603 else if ( i % 2 == 0 && userLengths[i] < dashUnit )
604 userLengths[i] = dashUnit ;
605 }
606 }
607 lengths = userLengths ;
608 break ;
609 case wxSTIPPLE :
610 {
611 float alphaArray[1] = { 1.0 } ;
612 wxBitmap* bmp = pen.GetStipple() ;
613 if ( bmp && bmp->Ok() )
614 {
615 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) ) ;
616 CGContextSetStrokeColorSpace( m_cgContext , patternSpace ) ;
617 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
618 CGContextSetStrokePattern( m_cgContext, pattern , alphaArray ) ;
619 }
620 }
621 break ;
622 default :
623 {
624 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) ) ;
625 CGContextSetStrokeColorSpace( m_cgContext , patternSpace ) ;
626 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( pen.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
627
628 RGBColor col = MAC_WXCOLORREF( pen.GetColour().GetPixel() ) ;
629 float colorArray[4] = { col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 } ;
630
631 CGContextSetStrokePattern( m_cgContext, pattern , colorArray ) ;
632 }
633 break ;
634 }
635
636 if ((lengths != NULL) && (count > 0))
637 {
638 CGContextSetLineDash( m_cgContext , 0 , lengths , count ) ;
639 // force the line cap, otherwise we get artifacts (overlaps) and just solid lines
640 cap = kCGLineCapButt ;
641 }
642 else
643 {
644 CGContextSetLineDash( m_cgContext , 0 , NULL , 0 ) ;
645 }
646 CGContextSetLineCap( m_cgContext , cap ) ;
647
648 delete[] userLengths ;
649 }
650 if ( fill && stroke )
651 {
652 m_mode = kCGPathFillStroke ;
653 }
654 }
655 }
656
657 void wxMacCGContext::SetBrush( const wxBrush &brush )
658 {
659 m_brush = brush ;
660 if ( m_cgContext == NULL )
661 return ;
662
663 bool fill = brush.GetStyle() != wxTRANSPARENT ;
664 bool stroke = m_pen.GetStyle() != wxTRANSPARENT ;
665
666 #if 0
667 // we can benchmark performance, should go into a setting later
668 CGContextSetShouldAntialias( m_cgContext , false ) ;
669 #endif
670
671 if ( fill | stroke )
672 {
673 // setup brushes
674 m_mode = kCGPathFill ; // just a default
675
676 if ( fill )
677 {
678 if ( brush.GetStyle() == wxSOLID )
679 {
680 RGBColor col = MAC_WXCOLORREF( brush.GetColour().GetPixel() ) ;
681 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
682 }
683 else if ( brush.IsHatch() )
684 {
685 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( wxMacGetGenericRGBColorSpace() ) ) ;
686 CGContextSetFillColorSpace( m_cgContext , patternSpace ) ;
687 wxMacCFRefHolder<CGPatternRef> pattern( *( new HatchPattern( brush.GetStyle() , CGContextGetCTM( m_cgContext ) ) ) );
688
689 RGBColor col = MAC_WXCOLORREF( brush.GetColour().GetPixel() ) ;
690 float colorArray[4] = { col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 } ;
691
692 CGContextSetFillPattern( m_cgContext, pattern , colorArray ) ;
693 }
694 else
695 {
696 // now brush is a bitmap
697 float alphaArray[1] = { 1.0 } ;
698 wxBitmap* bmp = brush.GetStipple() ;
699 if ( bmp && bmp->Ok() )
700 {
701 wxMacCFRefHolder<CGColorSpaceRef> patternSpace( CGColorSpaceCreatePattern( NULL ) ) ;
702 CGContextSetFillColorSpace( m_cgContext , patternSpace ) ;
703 wxMacCFRefHolder<CGPatternRef> pattern( *( new ImagePattern( bmp , CGContextGetCTM( m_cgContext ) ) ) );
704 CGContextSetFillPattern( m_cgContext, pattern , alphaArray ) ;
705 }
706 }
707 m_mode = kCGPathFill ;
708 }
709 if ( stroke )
710 {
711 m_mode = kCGPathStroke ;
712 }
713 if ( fill && stroke )
714 {
715 m_mode = kCGPathFillStroke ;
716 }
717 }
718 }
719
720 void AddEllipticArcToPath(CGContextRef c, CGPoint center, float a, float b, float fromDegree , float toDegree )
721 {
722 CGContextSaveGState(c);
723 CGContextTranslateCTM(c, center.x, center.y);
724 CGContextScaleCTM(c, a, b);
725 CGContextMoveToPoint(c, 1, 0);
726 CGContextAddArc(c, 0, 0, 1, DegToRad(fromDegree), DegToRad(toDegree), 0);
727 CGContextClosePath(c);
728 CGContextRestoreGState(c);
729 }
730
731 void AddRoundedRectToPath(CGContextRef c, CGRect rect, float ovalWidth,
732 float ovalHeight)
733 {
734 float fw, fh;
735 if (ovalWidth == 0 || ovalHeight == 0)
736 {
737 CGContextAddRect(c, rect);
738 return;
739 }
740 CGContextSaveGState(c);
741 CGContextTranslateCTM(c, CGRectGetMinX(rect), CGRectGetMinY(rect));
742 CGContextScaleCTM(c, ovalWidth, ovalHeight);
743 fw = CGRectGetWidth(rect) / ovalWidth;
744 fh = CGRectGetHeight(rect) / ovalHeight;
745 CGContextMoveToPoint(c, fw, fh/2);
746 CGContextAddArcToPoint(c, fw, fh, fw/2, fh, 1);
747 CGContextAddArcToPoint(c, 0, fh, 0, fh/2, 1);
748 CGContextAddArcToPoint(c, 0, 0, fw/2, 0, 1);
749 CGContextAddArcToPoint(c, fw, 0, fw, fh/2, 1);
750 CGContextClosePath(c);
751 CGContextRestoreGState(c);
752 }
753
754 wxDC::wxDC()
755 {
756 m_ok = FALSE;
757 m_colour = TRUE;
758 m_mm_to_pix_x = mm2pt;
759 m_mm_to_pix_y = mm2pt;
760
761 m_externalDeviceOriginX = 0;
762 m_externalDeviceOriginY = 0;
763 m_logicalScaleX = 1.0;
764 m_logicalScaleY = 1.0;
765 m_userScaleX = 1.0;
766 m_userScaleY = 1.0;
767 m_scaleX = 1.0;
768 m_scaleY = 1.0;
769 m_needComputeScaleX = FALSE;
770 m_needComputeScaleY = FALSE;
771
772 m_ok = FALSE ;
773 m_macPort = 0 ;
774 m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
775
776 m_pen = *wxBLACK_PEN;
777 m_font = *wxNORMAL_FONT;
778 m_brush = *wxWHITE_BRUSH;
779
780 m_macATSUIStyle = NULL ;
781
782 m_graphicContext = NULL ;
783 }
784
785 wxDC::~wxDC(void)
786 {
787 if( m_macATSUIStyle )
788 {
789 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
790 m_macATSUIStyle = NULL ;
791 }
792
793 delete m_graphicContext ;
794 }
795
796 void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
797 {
798 wxCHECK_RET( Ok(), wxT("invalid window dc") );
799 wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") );
800 wxCoord xx = XLOG2DEVMAC(x);
801 wxCoord yy = YLOG2DEVMAC(y);
802 wxCoord w = bmp.GetWidth();
803 wxCoord h = bmp.GetHeight();
804 wxCoord ww = XLOG2DEVREL(w);
805 wxCoord hh = YLOG2DEVREL(h);
806
807 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
808 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ) ;
809 HIRect r = CGRectMake( xx , yy , ww , hh ) ;
810 HIViewDrawCGImage( cg , &r , image ) ;
811 CGImageRelease( image ) ;
812 }
813
814 void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
815 {
816 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
817 wxCHECK_RET(icon.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
818
819 wxCoord xx = XLOG2DEVMAC(x);
820 wxCoord yy = YLOG2DEVMAC(y);
821 wxCoord w = icon.GetWidth();
822 wxCoord h = icon.GetHeight();
823 wxCoord ww = XLOG2DEVREL(w);
824 wxCoord hh = YLOG2DEVREL(h);
825
826 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
827 CGRect r = CGRectMake( 00 , 00 , ww , hh ) ;
828 CGContextSaveGState(cg);
829 CGContextTranslateCTM(cg, xx , yy + hh );
830 CGContextScaleCTM(cg, 1, -1);
831 PlotIconRefInContext( cg , &r , kAlignNone , kTransformNone ,
832 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
833 CGContextRestoreGState( cg ) ;
834 }
835
836 void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
837 {
838 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
839 wxCoord xx, yy, ww, hh;
840 xx = XLOG2DEVMAC(x);
841 yy = YLOG2DEVMAC(y);
842 ww = XLOG2DEVREL(width);
843 hh = YLOG2DEVREL(height);
844
845 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
846 CGRect clipRect = CGRectMake( xx ,yy , ww, hh ) ;
847 CGContextClipToRect( cgContext , clipRect ) ;
848
849 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
850 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
851 if( m_clipping )
852 {
853 m_clipX1 = wxMax( m_clipX1 , xx );
854 m_clipY1 = wxMax( m_clipY1 , yy );
855 m_clipX2 = wxMin( m_clipX2, (xx + ww));
856 m_clipY2 = wxMin( m_clipY2, (yy + hh));
857 }
858 else
859 {
860 m_clipping = TRUE;
861 m_clipX1 = xx;
862 m_clipY1 = yy;
863 m_clipX2 = xx + ww;
864 m_clipY2 = yy + hh;
865 }
866 // TODO as soon as we don't reset the context for each operation anymore
867 // we have to update the context as well
868 }
869
870 void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
871 {
872 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
873 if (region.Empty())
874 {
875 DestroyClippingRegion();
876 return;
877 }
878 wxCoord x, y, w, h;
879 region.GetBox( x, y, w, h );
880 wxCoord xx, yy, ww, hh;
881 xx = XLOG2DEVMAC(x);
882 yy = YLOG2DEVMAC(y);
883 ww = XLOG2DEVREL(w);
884 hh = YLOG2DEVREL(h);
885 // if we have a scaling that we cannot map onto native regions
886 // we must use the box
887 if ( ww != w || hh != h )
888 {
889 wxDC::DoSetClippingRegion( x, y, w, h );
890 }
891 else
892 {
893 /*
894 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
895 if ( xx != x || yy != y )
896 {
897 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
898 }
899 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
900 */
901 if( m_clipping )
902 {
903 m_clipX1 = wxMax( m_clipX1 , xx );
904 m_clipY1 = wxMax( m_clipY1 , yy );
905 m_clipX2 = wxMin( m_clipX2, (xx + ww));
906 m_clipY2 = wxMin( m_clipY2, (yy + hh));
907 }
908 else
909 {
910 m_clipping = TRUE;
911 m_clipX1 = xx;
912 m_clipY1 = yy;
913 m_clipX2 = xx + ww;
914 m_clipY2 = yy + hh;
915 }
916 }
917 }
918
919 void wxDC::DestroyClippingRegion()
920 {
921 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
922 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
923 CGContextRestoreGState( cgContext );
924 CGContextSaveGState( cgContext );
925 m_graphicContext->SetPen( m_pen ) ;
926 m_graphicContext->SetBrush( m_brush ) ;
927 m_clipping = FALSE;
928 }
929
930 void wxDC::DoGetSizeMM( int* width, int* height ) const
931 {
932 int w = 0;
933 int h = 0;
934 GetSize( &w, &h );
935 *width = long( double(w) / (m_scaleX*m_mm_to_pix_x) );
936 *height = long( double(h) / (m_scaleY*m_mm_to_pix_y) );
937 }
938
939 void wxDC::SetTextForeground( const wxColour &col )
940 {
941 wxCHECK_RET(Ok(), wxT("Invalid DC"));
942 if ( col != m_textForegroundColour )
943 {
944 m_textForegroundColour = col;
945 MacInstallFont() ;
946 }
947 }
948
949 void wxDC::SetTextBackground( const wxColour &col )
950 {
951 wxCHECK_RET(Ok(), wxT("Invalid DC"));
952 m_textBackgroundColour = col;
953 }
954
955 void wxDC::SetMapMode( int mode )
956 {
957 switch (mode)
958 {
959 case wxMM_TWIPS:
960 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
961 break;
962 case wxMM_POINTS:
963 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
964 break;
965 case wxMM_METRIC:
966 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
967 break;
968 case wxMM_LOMETRIC:
969 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
970 break;
971 default:
972 case wxMM_TEXT:
973 SetLogicalScale( 1.0, 1.0 );
974 break;
975 }
976 if (mode != wxMM_TEXT)
977 {
978 m_needComputeScaleX = TRUE;
979 m_needComputeScaleY = TRUE;
980 }
981 }
982
983 void wxDC::SetUserScale( double x, double y )
984 {
985 // allow negative ? -> no
986 m_userScaleX = x;
987 m_userScaleY = y;
988 ComputeScaleAndOrigin();
989 }
990
991 void wxDC::SetLogicalScale( double x, double y )
992 {
993 // allow negative ?
994 m_logicalScaleX = x;
995 m_logicalScaleY = y;
996 ComputeScaleAndOrigin();
997 }
998
999 void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
1000 {
1001 m_logicalOriginX = x * m_signX; // is this still correct ?
1002 m_logicalOriginY = y * m_signY;
1003 ComputeScaleAndOrigin();
1004 }
1005
1006 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1007 {
1008 m_externalDeviceOriginX = x;
1009 m_externalDeviceOriginY = y;
1010 ComputeScaleAndOrigin();
1011 }
1012
1013 void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1014 {
1015 m_signX = (xLeftRight ? 1 : -1);
1016 m_signY = (yBottomUp ? -1 : 1);
1017 ComputeScaleAndOrigin();
1018 }
1019
1020 wxSize wxDC::GetPPI() const
1021 {
1022 return wxSize(72, 72);
1023 }
1024
1025 int wxDC::GetDepth() const
1026 {
1027 return 32 ;
1028 }
1029
1030 void wxDC::ComputeScaleAndOrigin()
1031 {
1032 // CMB: copy scale to see if it changes
1033 double origScaleX = m_scaleX;
1034 double origScaleY = m_scaleY;
1035 m_scaleX = m_logicalScaleX * m_userScaleX;
1036 m_scaleY = m_logicalScaleY * m_userScaleY;
1037 m_deviceOriginX = m_externalDeviceOriginX;
1038 m_deviceOriginY = m_externalDeviceOriginY;
1039 // CMB: if scale has changed call SetPen to recalulate the line width
1040 if (m_scaleX != origScaleX || m_scaleY != origScaleY)
1041 {
1042 // this is a bit artificial, but we need to force wxDC to think
1043 // the pen has changed
1044 wxPen pen(GetPen());
1045 m_pen = wxNullPen;
1046 SetPen(pen);
1047 }
1048 }
1049
1050 void wxDC::SetPalette( const wxPalette& palette )
1051 {
1052 }
1053
1054 void wxDC::SetBackgroundMode( int mode )
1055 {
1056 m_backgroundMode = mode ;
1057 }
1058
1059 void wxDC::SetFont( const wxFont &font )
1060 {
1061 m_font = font;
1062 MacInstallFont() ;
1063 }
1064
1065 void wxDC::SetPen( const wxPen &pen )
1066 {
1067 if ( m_pen == pen )
1068 return ;
1069 m_pen = pen;
1070 if ( m_graphicContext )
1071 {
1072 if ( m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT )
1073 {
1074 m_graphicContext->SetPen( m_pen ) ;
1075 }
1076 else
1077 {
1078 // we have to compensate for moved device origins etc. otherwise patterned pens are standing still
1079 // eg when using a wxScrollWindow and scrolling around
1080 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1081 int origX = XLOG2DEVMAC(0) ;
1082 int origY = YLOG2DEVMAC(0) ;
1083 CGContextTranslateCTM (cgContext,origX,origY);
1084 m_graphicContext->SetPen( m_pen ) ;
1085 CGContextTranslateCTM (cgContext,-origX,-origY);
1086 }
1087 }
1088 }
1089
1090 void wxDC::SetBrush( const wxBrush &brush )
1091 {
1092 if (m_brush == brush)
1093 return;
1094 m_brush = brush;
1095 if ( m_graphicContext )
1096 {
1097 if ( brush.GetStyle() == wxSOLID || brush.GetStyle() == wxTRANSPARENT )
1098 {
1099 m_graphicContext->SetBrush( m_brush ) ;
1100 }
1101 else
1102 {
1103 // we have to compensate for moved device origins etc. otherwise patterned brushes are standing still
1104 // eg when using a wxScrollWindow and scrolling around
1105 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1106 int origX = XLOG2DEVMAC(0) ;
1107 int origY = YLOG2DEVMAC(0) ;
1108 CGContextTranslateCTM (cgContext,origX,origY);
1109 m_graphicContext->SetBrush( m_brush ) ;
1110 CGContextTranslateCTM (cgContext,-origX,-origY);
1111 }
1112 }
1113 }
1114
1115 void wxDC::SetBackground( const wxBrush &brush )
1116 {
1117 if (m_backgroundBrush == brush)
1118 return;
1119 m_backgroundBrush = brush;
1120 if (!m_backgroundBrush.Ok())
1121 return;
1122 }
1123
1124 void wxDC::SetLogicalFunction( int function )
1125 {
1126 if (m_logicalFunction == function)
1127 return;
1128 m_logicalFunction = function ;
1129 }
1130
1131 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
1132 const wxColour & col, int style);
1133
1134 bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
1135 const wxColour& col, int style)
1136 {
1137 return wxDoFloodFill(this, x, y, col, style);
1138 }
1139
1140 bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
1141 {
1142 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
1143 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
1144 wxMacPortSaver helper((CGrafPtr)m_macPort) ;
1145 RGBColor colour;
1146 GetCPixel(
1147 XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x,
1148 YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
1149 // Convert from Mac colour to wx
1150 col->Set( colour.red >> 8,
1151 colour.green >> 8,
1152 colour.blue >> 8);
1153 return true ;
1154 }
1155
1156 void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
1157 {
1158 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1159
1160 if ( m_logicalFunction != wxCOPY )
1161 return ;
1162
1163 wxCoord xx1 = XLOG2DEVMAC(x1) ;
1164 wxCoord yy1 = YLOG2DEVMAC(y1) ;
1165 wxCoord xx2 = XLOG2DEVMAC(x2) ;
1166 wxCoord yy2 = YLOG2DEVMAC(y2) ;
1167
1168 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1169 path->MoveToPoint( xx1 , yy1 ) ;
1170 path->AddLineToPoint( xx2 , yy2 ) ;
1171 path->CloseSubpath() ;
1172 m_graphicContext->StrokePath( path ) ;
1173 delete path ;
1174
1175 CalcBoundingBox(x1, y1);
1176 CalcBoundingBox(x2, y2);
1177 }
1178
1179 void wxDC::DoCrossHair( wxCoord x, wxCoord y )
1180 {
1181 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
1182
1183 if ( m_logicalFunction != wxCOPY )
1184 return ;
1185
1186 int w = 0;
1187 int h = 0;
1188 GetSize( &w, &h );
1189 wxCoord xx = XLOG2DEVMAC(x);
1190 wxCoord yy = YLOG2DEVMAC(y);
1191
1192 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1193 path->MoveToPoint( XLOG2DEVMAC(0), yy ) ;
1194 path->AddLineToPoint( XLOG2DEVMAC(w), yy ) ;
1195 path->CloseSubpath() ;
1196 path->MoveToPoint( xx, YLOG2DEVMAC(0) ) ;
1197 path->AddLineToPoint( xx, YLOG2DEVMAC(h) ) ;
1198 path->CloseSubpath() ;
1199 m_graphicContext->StrokePath( path ) ;
1200 delete path ;
1201
1202 CalcBoundingBox(x, y);
1203 CalcBoundingBox(x+w, y+h);
1204 }
1205
1206 void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
1207 wxCoord x2, wxCoord y2,
1208 wxCoord xc, wxCoord yc )
1209 {
1210 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1211
1212 if ( m_logicalFunction != wxCOPY )
1213 return ;
1214
1215 wxCoord xx1 = XLOG2DEVMAC(x1);
1216 wxCoord yy1 = YLOG2DEVMAC(y1);
1217 wxCoord xx2 = XLOG2DEVMAC(x2);
1218 wxCoord yy2 = YLOG2DEVMAC(y2);
1219 wxCoord xxc = XLOG2DEVMAC(xc);
1220 wxCoord yyc = YLOG2DEVMAC(yc);
1221 double dx = xx1 - xxc;
1222 double dy = yy1 - yyc;
1223 double radius = sqrt((double)(dx*dx+dy*dy));
1224 wxCoord rad = (wxCoord)radius;
1225 double sa, ea;
1226 if (xx1 == xx2 && yy1 == yy2)
1227 {
1228 sa = 0.0;
1229 ea = 360.0;
1230 }
1231 else if (radius == 0.0)
1232 {
1233 sa = ea = 0.0;
1234 }
1235 else
1236 {
1237 sa = (xx1 - xxc == 0) ?
1238 (yy1 - yyc < 0) ? 90.0 : -90.0 :
1239 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
1240 ea = (xx2 - xxc == 0) ?
1241 (yy2 - yyc < 0) ? 90.0 : -90.0 :
1242 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
1243 }
1244
1245 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
1246 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1247 CGContextRef ctx = mctx->GetNativeContext() ;
1248 CGContextSaveGState( ctx ) ;
1249 CGContextTranslateCTM( ctx, xxc , yyc );
1250 CGContextScaleCTM( ctx , 1 , -1 ) ;
1251 if ( fill )
1252 CGContextMoveToPoint( ctx , 0 , 0 ) ;
1253 CGContextAddArc( ctx, 0, 0 , rad , DegToRad(sa), DegToRad(ea), 0);
1254 if ( fill )
1255 CGContextAddLineToPoint( ctx , 0 , 0 ) ;
1256 CGContextRestoreGState( ctx ) ;
1257 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1258 }
1259
1260 void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1261 double sa, double ea )
1262 {
1263 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1264
1265 if ( m_logicalFunction != wxCOPY )
1266 return ;
1267
1268 wxCoord xx = XLOG2DEVMAC(x);
1269 wxCoord yy = YLOG2DEVMAC(y);
1270 wxCoord ww = m_signX * XLOG2DEVREL(w);
1271 wxCoord hh = m_signY * YLOG2DEVREL(h);
1272 // handle -ve width and/or height
1273 if (ww < 0) { ww = -ww; xx = xx - ww; }
1274 if (hh < 0) { hh = -hh; yy = yy - hh; }
1275
1276 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
1277
1278 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1279 CGContextRef ctx = mctx->GetNativeContext() ;
1280
1281 CGContextSaveGState( ctx ) ;
1282 CGContextTranslateCTM( ctx, xx + ww / 2, yy + hh / 2);
1283 CGContextScaleCTM( ctx , 1 * ww / 2 , -1 * hh / 2 ) ;
1284 if ( fill )
1285 CGContextMoveToPoint( ctx , 0 , 0 ) ;
1286 CGContextAddArc( ctx, 0, 0, 1, DegToRad(sa), DegToRad(ea), 0);
1287 if ( fill )
1288 CGContextAddLineToPoint( ctx , 0 , 0 ) ;
1289 CGContextRestoreGState( ctx ) ;
1290 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1291 }
1292
1293 void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
1294 {
1295 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1296 DoDrawLine( x , y , x + 1 , y + 1 ) ;
1297 }
1298
1299 void wxDC::DoDrawLines(int n, wxPoint points[],
1300 wxCoord xoffset, wxCoord yoffset)
1301 {
1302 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1303
1304 if ( m_logicalFunction != wxCOPY )
1305 return ;
1306
1307 wxCoord x1, x2 , y1 , y2 ;
1308 x1 = XLOG2DEVMAC(points[0].x + xoffset);
1309 y1 = YLOG2DEVMAC(points[0].y + yoffset);
1310 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1311 path->MoveToPoint( x1 , y1 ) ;
1312 for (int i = 1; i < n; i++)
1313 {
1314 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1315 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1316
1317 path->AddLineToPoint( x2 , y2 ) ;
1318 }
1319 m_graphicContext->StrokePath( path ) ;
1320 delete path ;
1321 }
1322
1323 #if wxUSE_SPLINES
1324 void wxDC::DoDrawSpline(wxList *points)
1325 {
1326 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1327
1328 if ( m_logicalFunction != wxCOPY )
1329 return ;
1330
1331 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1332
1333 wxList::compatibility_iterator node = points->GetFirst();
1334 if (node == wxList::compatibility_iterator())
1335 // empty list
1336 return;
1337
1338 wxPoint *p = (wxPoint *)node->GetData();
1339
1340 wxCoord x1 = p->x;
1341 wxCoord y1 = p->y;
1342
1343 node = node->GetNext();
1344 p = (wxPoint *)node->GetData();
1345
1346 wxCoord x2 = p->x;
1347 wxCoord y2 = p->y;
1348 wxCoord cx1 = ( x1 + x2 ) / 2;
1349 wxCoord cy1 = ( y1 + y2 ) / 2;
1350
1351 path->MoveToPoint( XLOG2DEVMAC( x1 ) , XLOG2DEVMAC( y1 ) ) ;
1352 path->AddLineToPoint( XLOG2DEVMAC( cx1 ) , XLOG2DEVMAC( cy1 ) ) ;
1353
1354 #if !wxUSE_STL
1355 while ((node = node->GetNext()) != NULL)
1356 #else
1357 while ((node = node->GetNext()))
1358 #endif // !wxUSE_STL
1359 {
1360 p = (wxPoint *)node->GetData();
1361 x1 = x2;
1362 y1 = y2;
1363 x2 = p->x;
1364 y2 = p->y;
1365 wxCoord cx4 = (x1 + x2) / 2;
1366 wxCoord cy4 = (y1 + y2) / 2;
1367
1368 path->AddQuadCurveToPoint( XLOG2DEVMAC( x1 ) , XLOG2DEVMAC( y1 ) ,
1369 XLOG2DEVMAC( cx4 ) , XLOG2DEVMAC( cy4 ) ) ;
1370
1371 cx1 = cx4;
1372 cy1 = cy4;
1373 }
1374
1375 path->AddLineToPoint( XLOG2DEVMAC( x2 ) , XLOG2DEVMAC( y2 ) ) ;
1376
1377 m_graphicContext->StrokePath( path ) ;
1378 delete path ;
1379 }
1380 #endif
1381
1382 void wxDC::DoDrawPolygon(int n, wxPoint points[],
1383 wxCoord xoffset, wxCoord yoffset,
1384 int fillStyle )
1385 {
1386 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1387 wxCoord x1, x2 , y1 , y2 ;
1388 if ( n== 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
1389 return ;
1390
1391 if ( m_logicalFunction != wxCOPY )
1392 return ;
1393
1394 x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1395 y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
1396
1397 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1398 path->MoveToPoint( x1 , y1 ) ;
1399 for (int i = 1; i < n; i++)
1400 {
1401 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1402 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1403
1404 path->AddLineToPoint( x2 , y2 ) ;
1405 }
1406 if ( x1 != x2 || y1 != y2 )
1407 {
1408 path->AddLineToPoint( x1,y1 ) ;
1409 }
1410 path->CloseSubpath() ;
1411 m_graphicContext->DrawPath( path , fillStyle ) ;
1412 delete path ;
1413 }
1414
1415 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1416 {
1417 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1418
1419 if ( m_logicalFunction != wxCOPY )
1420 return ;
1421
1422 wxCoord xx = XLOG2DEVMAC(x);
1423 wxCoord yy = YLOG2DEVMAC(y);
1424 wxCoord ww = m_signX * XLOG2DEVREL(width);
1425 wxCoord hh = m_signY * YLOG2DEVREL(height);
1426 // CMB: draw nothing if transformed w or h is 0
1427 if (ww == 0 || hh == 0)
1428 return;
1429 // CMB: handle -ve width and/or height
1430 if (ww < 0)
1431 {
1432 ww = -ww;
1433 xx = xx - ww;
1434 }
1435 if (hh < 0)
1436 {
1437 hh = -hh;
1438 yy = yy - hh;
1439 }
1440 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1441 path->AddRectangle( xx , yy , ww , hh ) ;
1442 m_graphicContext->DrawPath( path ) ;
1443 delete path ;
1444 }
1445
1446 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1447 wxCoord width, wxCoord height,
1448 double radius)
1449 {
1450 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1451
1452 if ( m_logicalFunction != wxCOPY )
1453 return ;
1454
1455
1456 if (radius < 0.0)
1457 radius = - radius * ((width < height) ? width : height);
1458 wxCoord xx = XLOG2DEVMAC(x);
1459 wxCoord yy = YLOG2DEVMAC(y);
1460 wxCoord ww = m_signX * XLOG2DEVREL(width);
1461 wxCoord hh = m_signY * YLOG2DEVREL(height);
1462 // CMB: draw nothing if transformed w or h is 0
1463 if (ww == 0 || hh == 0)
1464 return;
1465 // CMB: handle -ve width and/or height
1466 if (ww < 0)
1467 {
1468 ww = -ww;
1469 xx = xx - ww;
1470 }
1471 if (hh < 0)
1472 {
1473 hh = -hh;
1474 yy = yy - hh;
1475 }
1476 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1477 CGContextRef ctx = mctx->GetNativeContext() ;
1478 AddRoundedRectToPath( ctx , CGRectMake( xx , yy , ww , hh ) , 16 ,16 ) ;
1479 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1480 }
1481
1482 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1483 {
1484 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1485
1486 if ( m_logicalFunction != wxCOPY )
1487 return ;
1488
1489 wxCoord xx = XLOG2DEVMAC(x);
1490 wxCoord yy = YLOG2DEVMAC(y);
1491 wxCoord ww = m_signX * XLOG2DEVREL(width);
1492 wxCoord hh = m_signY * YLOG2DEVREL(height);
1493 // CMB: draw nothing if transformed w or h is 0
1494 if (ww == 0 || hh == 0)
1495 return;
1496 // CMB: handle -ve width and/or height
1497 if (ww < 0)
1498 {
1499 ww = -ww;
1500 xx = xx - ww;
1501 }
1502 if (hh < 0)
1503 {
1504 hh = -hh;
1505 yy = yy - hh;
1506 }
1507
1508 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1509 CGContextRef ctx = mctx->GetNativeContext() ;
1510 CGContextSaveGState( ctx ) ;
1511 CGContextTranslateCTM( ctx, xx + ww / 2, yy + hh / 2);
1512 CGContextScaleCTM( ctx , ww / 2 , hh / 2 ) ;
1513 CGContextAddArc( ctx, 0, 0, 1, 0 , 2*M_PI , 0);
1514 CGContextRestoreGState( ctx ) ;
1515 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1516 }
1517
1518 bool wxDC::CanDrawBitmap(void) const
1519 {
1520 return true ;
1521 }
1522
1523 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1524 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1525 wxCoord xsrcMask, wxCoord ysrcMask )
1526 {
1527 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1528 wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1529 if ( logical_func == wxNO_OP )
1530 return TRUE ;
1531 if (xsrcMask == -1 && ysrcMask == -1)
1532 {
1533 xsrcMask = xsrc; ysrcMask = ysrc;
1534 }
1535
1536 wxCoord yysrc = source->YLOG2DEVMAC(ysrc) ;
1537 wxCoord xxsrc = source->XLOG2DEVMAC(xsrc) ;
1538 wxCoord wwsrc = source->XLOG2DEVREL(width ) ;
1539 wxCoord hhsrc = source->YLOG2DEVREL(height) ;
1540
1541 wxCoord yydest = YLOG2DEVMAC(ydest) ;
1542 wxCoord xxdest = XLOG2DEVMAC(xdest) ;
1543 wxCoord wwdest = XLOG2DEVREL(width ) ;
1544 wxCoord hhdest = YLOG2DEVREL(height) ;
1545
1546 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
1547 if ( memdc && logical_func == wxCOPY )
1548 {
1549 wxBitmap blit = memdc->GetSelectedObject() ;
1550 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
1551
1552 wxCoord bmpwidth = blit.GetWidth();
1553 wxCoord bmpheight = blit.GetHeight();
1554
1555 if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc )
1556 {
1557 wwsrc = wxMin( wwsrc , bmpwidth - xxsrc ) ;
1558 hhsrc = wxMin( hhsrc , bmpheight - yysrc ) ;
1559 if ( wwsrc > 0 && hhsrc > 0 )
1560 {
1561 if ( xxsrc >= 0 && yysrc >= 0 )
1562 {
1563 wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc ) ;
1564 blit = blit.GetSubBitmap( subrect ) ;
1565 }
1566 else
1567 {
1568 // in this case we'd probably have to adjust the different coordinates, but
1569 // we have to find out proper contract first
1570 blit = wxNullBitmap ;
1571 }
1572 }
1573 else
1574 {
1575 blit = wxNullBitmap ;
1576 }
1577 }
1578 if ( blit.Ok() )
1579 {
1580 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1581 CGImageRef image = (CGImageRef)( blit.CGImageCreate() ) ;
1582 HIRect r = CGRectMake( xxdest , yydest , wwdest , hhdest ) ;
1583 HIViewDrawCGImage( cg , &r , image ) ;
1584 CGImageRelease( image ) ;
1585 }
1586
1587 }
1588 else
1589 {
1590 /*
1591 CGContextRef cg = (wxMacCGContext*)(source->GetGraphicContext())->GetNativeContext() ;
1592 void *data = CGBitmapContextGetData( cg ) ;
1593 */
1594 return FALSE ; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1595 }
1596 return TRUE;
1597 }
1598
1599 void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1600 double angle)
1601 {
1602 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1603
1604 if ( str.Length() == 0 )
1605 return ;
1606
1607 if ( m_logicalFunction != wxCOPY )
1608 return ;
1609
1610 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1611
1612 OSStatus status = noErr ;
1613 ATSUTextLayout atsuLayout ;
1614 UniCharCount chars = str.Length() ;
1615 UniChar* ubuf = NULL ;
1616 #if SIZEOF_WCHAR_T == 4
1617 wxMBConvUTF16 converter ;
1618 #if wxUSE_UNICODE
1619 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1620 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1621 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1622 #else
1623 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1624 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1625 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1626 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1627 #endif
1628 chars = unicharlen / 2 ;
1629 #else
1630 #if wxUSE_UNICODE
1631 ubuf = (UniChar*) str.wc_str() ;
1632 #else
1633 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1634 chars = wxWcslen( wchar.data() ) ;
1635 ubuf = (UniChar*) wchar.data() ;
1636 #endif
1637 #endif
1638
1639 int drawX = XLOG2DEVMAC(x) ;
1640 int drawY = YLOG2DEVMAC(y) ;
1641
1642 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1643 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1644
1645 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1646
1647 status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
1648 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1649
1650 int iAngle = int( angle );
1651 if ( abs(iAngle) > 0 )
1652 {
1653 Fixed atsuAngle = IntToFixed( iAngle ) ;
1654 ATSUAttributeTag atsuTags[] =
1655 {
1656 kATSULineRotationTag ,
1657 } ;
1658 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1659 {
1660 sizeof( Fixed ) ,
1661 } ;
1662 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1663 {
1664 &atsuAngle ,
1665 } ;
1666 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1667 atsuTags, atsuSizes, atsuValues ) ;
1668 }
1669 {
1670 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1671 ATSUAttributeTag atsuTags[] =
1672 {
1673 kATSUCGContextTag ,
1674 } ;
1675 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1676 {
1677 sizeof( CGContextRef ) ,
1678 } ;
1679 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1680 {
1681 &cgContext ,
1682 } ;
1683 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1684 atsuTags, atsuSizes, atsuValues ) ;
1685 }
1686
1687 ATSUTextMeasurement textBefore ;
1688 ATSUTextMeasurement textAfter ;
1689 ATSUTextMeasurement ascent ;
1690 ATSUTextMeasurement descent ;
1691
1692 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1693 &textBefore , &textAfter, &ascent , &descent );
1694 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1695
1696 Rect rect ;
1697
1698 if ( m_backgroundMode == wxSOLID )
1699 {
1700 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1701 path->MoveToPoint(
1702 drawX ,
1703 drawY ) ;
1704 path->AddLineToPoint(
1705 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent)) ,
1706 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent)) ) ;
1707 path->AddLineToPoint(
1708 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1709 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1710 path->AddLineToPoint(
1711 (int) (drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1712 (int) (drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1713
1714 m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
1715 delete path ;
1716 }
1717
1718 drawX += (int)(sin(angle/RAD2DEG) * FixedToInt(ascent));
1719 drawY += (int)(cos(angle/RAD2DEG) * FixedToInt(ascent));
1720
1721 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1722 IntToFixed(drawX) , IntToFixed(drawY) , &rect );
1723 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1724
1725 CGContextSaveGState(((wxMacCGContext*)(m_graphicContext))->GetNativeContext());
1726 CGContextTranslateCTM(((wxMacCGContext*)(m_graphicContext))->GetNativeContext(), drawX, drawY);
1727 CGContextScaleCTM(((wxMacCGContext*)(m_graphicContext))->GetNativeContext(), 1, -1);
1728 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1729 IntToFixed(0) , IntToFixed(0) );
1730 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1731 CGContextRestoreGState( ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ) ;
1732
1733 CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
1734 CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
1735
1736 ::ATSUDisposeTextLayout(atsuLayout);
1737 #if SIZEOF_WCHAR_T == 4
1738 free( ubuf ) ;
1739 #endif
1740 }
1741
1742 void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
1743 {
1744 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1745 DoDrawRotatedText( strtext , x , y , 0.0 ) ;
1746 }
1747
1748 bool wxDC::CanGetTextExtent() const
1749 {
1750 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1751 return true ;
1752 }
1753
1754 void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1755 wxCoord *descent, wxCoord *externalLeading ,
1756 wxFont *theFont ) const
1757 {
1758 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1759 wxFont formerFont = m_font ;
1760 if ( theFont )
1761 {
1762 // work around the constness
1763 *((wxFont*)(&m_font)) = *theFont ;
1764 MacInstallFont() ;
1765 }
1766
1767 if ( str.Length() == 0 )
1768 return ;
1769
1770 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1771
1772 OSStatus status = noErr ;
1773 ATSUTextLayout atsuLayout ;
1774 UniCharCount chars = str.Length() ;
1775 UniChar* ubuf = NULL ;
1776 #if SIZEOF_WCHAR_T == 4
1777 wxMBConvUTF16 converter ;
1778 #if wxUSE_UNICODE
1779 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1780 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1781 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1782 #else
1783 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1784 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1785 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1786 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1787 #endif
1788 chars = unicharlen / 2 ;
1789 #else
1790 #if wxUSE_UNICODE
1791 ubuf = (UniChar*) str.wc_str() ;
1792 #else
1793 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1794 chars = wxWcslen( wchar.data() ) ;
1795 ubuf = (UniChar*) wchar.data() ;
1796 #endif
1797 #endif
1798
1799
1800 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1801 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1802
1803 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1804
1805 ATSUTextMeasurement textBefore ;
1806 ATSUTextMeasurement textAfter ;
1807 ATSUTextMeasurement textAscent ;
1808 ATSUTextMeasurement textDescent ;
1809
1810 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1811 &textBefore , &textAfter, &textAscent , &textDescent );
1812
1813 if ( height )
1814 *height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
1815 if ( descent )
1816 *descent =YDEV2LOGREL( FixedToInt(textDescent) );
1817 if ( externalLeading )
1818 *externalLeading = 0 ;
1819 if ( width )
1820 *width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
1821
1822 ::ATSUDisposeTextLayout(atsuLayout);
1823 #if SIZEOF_WCHAR_T == 4
1824 free( ubuf ) ;
1825 #endif
1826 if ( theFont )
1827 {
1828 // work around the constness
1829 *((wxFont*)(&m_font)) = formerFont ;
1830 MacInstallFont() ;
1831 }
1832 }
1833
1834
1835 bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1836 {
1837 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1838
1839 widths.Empty();
1840 widths.Add(0, text.Length());
1841
1842 if (text.Length() == 0)
1843 return false;
1844
1845 ATSUTextLayout atsuLayout ;
1846 UniCharCount chars = text.Length() ;
1847 UniChar* ubuf = NULL ;
1848 #if SIZEOF_WCHAR_T == 4
1849 wxMBConvUTF16 converter ;
1850 #if wxUSE_UNICODE
1851 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
1852 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1853 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
1854 #else
1855 const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1856 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1857 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1858 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1859 #endif
1860 chars = unicharlen / 2 ;
1861 #else
1862 #if wxUSE_UNICODE
1863 ubuf = (UniChar*) text.wc_str() ;
1864 #else
1865 wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1866 chars = wxWcslen( wchar.data() ) ;
1867 ubuf = (UniChar*) wchar.data() ;
1868 #endif
1869 #endif
1870
1871 OSStatus status;
1872 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1873 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1874
1875 for ( int pos = 0; pos < (int)chars; pos ++ ) {
1876 unsigned long actualNumberOfBounds = 0;
1877 ATSTrapezoid glyphBounds;
1878
1879 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1880 OSStatus result;
1881 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1882 if (result != noErr || actualNumberOfBounds != 1 )
1883 {
1884 return false;
1885 }
1886
1887 widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
1888 //unsigned char uch = s[i];
1889
1890 }
1891 ::ATSUDisposeTextLayout(atsuLayout);
1892 return true;
1893 }
1894
1895 wxCoord wxDC::GetCharWidth(void) const
1896 {
1897 wxCoord width ;
1898 DoGetTextExtent(wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
1899 return width ;
1900 }
1901
1902 wxCoord wxDC::GetCharHeight(void) const
1903 {
1904 wxCoord height ;
1905 DoGetTextExtent(wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
1906 return height ;
1907 }
1908
1909 void wxDC::Clear(void)
1910 {
1911 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1912
1913 if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
1914 {
1915 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1916 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
1917 switch( m_backgroundBrush.MacGetBrushKind() )
1918 {
1919 case kwxMacBrushTheme :
1920 {
1921 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1922 if ( HIThemeSetFill != 0 )
1923 {
1924 HIThemeSetFill( m_backgroundBrush.MacGetTheme(), NULL, cg, kHIThemeOrientationNormal );
1925 CGContextFillRect(cg, rect);
1926
1927 }
1928 else
1929 #endif
1930 {
1931 RGBColor color;
1932 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme(), 32, true, &color );
1933 CGContextSetRGBFillColor( cg, (float) color.red / 65536,
1934 (float) color.green / 65536, (float) color.blue / 65536, 1 );
1935 CGContextFillRect( cg, rect );
1936 }
1937
1938 // reset to normal value
1939 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1940 CGContextSetRGBFillColor( cg, col.red / 65536.0, col.green / 65536.0, col.blue / 65536.0, 1.0 );
1941 }
1942 break ;
1943 case kwxMacBrushThemeBackground :
1944 {
1945 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1946 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1947 if ( UMAGetSystemVersion() >= 0x1030 )
1948 {
1949 HIThemeBackgroundDrawInfo drawInfo ;
1950 drawInfo.version = 0 ;
1951 drawInfo.state = kThemeStateActive ;
1952 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
1953 if ( drawInfo.kind == kThemeBackgroundMetal )
1954 HIThemeDrawBackground( &rect , &drawInfo, cg ,
1955 kHIThemeOrientationNormal) ;
1956 HIThemeApplyBackground( &rect , &drawInfo, cg ,
1957 kHIThemeOrientationNormal) ;
1958 }
1959 else
1960 #endif
1961 {
1962 }
1963 }
1964 break ;
1965 case kwxMacBrushColour :
1966 {
1967 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
1968 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1969 CGContextFillRect(cg, rect);
1970
1971 // reset to normal value
1972 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1973 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1974 }
1975 break ;
1976 }
1977 }
1978 }
1979
1980 void wxDC::MacInstallFont() const
1981 {
1982 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1983
1984 if( m_macATSUIStyle )
1985 {
1986 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1987 m_macATSUIStyle = NULL ;
1988 }
1989
1990 if ( m_font.Ok() )
1991 {
1992 OSStatus status = noErr ;
1993 status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
1994 wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
1995
1996 Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
1997 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel() ) ;
1998 ATSUAttributeTag atsuTags[] =
1999 {
2000 kATSUSizeTag ,
2001 kATSUColorTag ,
2002 } ;
2003 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
2004 {
2005 sizeof( Fixed ) ,
2006 sizeof( RGBColor ) ,
2007 } ;
2008 // Boolean kTrue = true ;
2009 // Boolean kFalse = false ;
2010
2011 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
2012 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
2013 {
2014 &atsuSize ,
2015 &atsuColor ,
2016 } ;
2017 status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
2018 atsuTags, atsuSizes, atsuValues);
2019
2020 wxASSERT_MSG( status == noErr , wxT("couldn't Modify ATSU style") ) ;
2021 }
2022 }
2023
2024 // ---------------------------------------------------------------------------
2025 // coordinates transformations
2026 // ---------------------------------------------------------------------------
2027
2028 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2029 {
2030 return ((wxDC *)this)->XDEV2LOG(x);
2031 }
2032
2033 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2034 {
2035 return ((wxDC *)this)->YDEV2LOG(y);
2036 }
2037
2038 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2039 {
2040 return ((wxDC *)this)->XDEV2LOGREL(x);
2041 }
2042
2043 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2044 {
2045 return ((wxDC *)this)->YDEV2LOGREL(y);
2046 }
2047
2048 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2049 {
2050 return ((wxDC *)this)->XLOG2DEV(x);
2051 }
2052
2053 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2054 {
2055 return ((wxDC *)this)->YLOG2DEV(y);
2056 }
2057
2058 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2059 {
2060 return ((wxDC *)this)->XLOG2DEVREL(x);
2061 }
2062
2063 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2064 {
2065 return ((wxDC *)this)->YLOG2DEVREL(y);
2066 }
2067
2068 #endif // wxMAC_USE_CORE_GRAPHICS
2069