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