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