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