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