]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dccg.cpp
first stab at the selection iterator
[wxWidgets.git] / src / mac / carbon / dccg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/dccg.cpp
3 // Purpose: wxDC class
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/dc.h"
15
16 #if wxMAC_USE_CORE_GRAPHICS
17
18 #ifndef WX_PRECOMP
19 #include "wx/log.h"
20 #include "wx/app.h"
21 #include "wx/dcmemory.h"
22 #include "wx/dcprint.h"
23 #include "wx/region.h"
24 #include "wx/image.h"
25 #endif
26
27 #include "wx/mac/uma.h"
28
29
30 #ifdef __MSL__
31 #if __MSL__ >= 0x6000
32 #include "math.h"
33 // in case our functions were defined outside std, we make it known all the same
34 namespace std { }
35 using namespace std ;
36 #endif
37 #endif
38
39 #include "wx/mac/private.h"
40
41 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
42
43 #ifndef wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
44 #define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0
45 #endif
46
47 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
48 typedef float CGFloat ;
49 #endif
50
51 //-----------------------------------------------------------------------------
52 // constants
53 //-----------------------------------------------------------------------------
54
55 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
56 #ifndef M_PI
57 const double M_PI = 3.14159265358979 ;
58 #endif
59 #endif
60
61 const double RAD2DEG = 180.0 / M_PI;
62 const short kEmulatedMode = -1 ;
63 const short kUnsupportedMode = -2 ;
64
65 extern TECObjectRef s_TECNativeCToUnicode ;
66
67
68 // TODO: update
69 // The textctrl implementation still needs that (needs what?) for the non-HIView implementation
70 //
71 wxMacWindowClipper::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
97 wxMacWindowClipper::~wxMacWindowClipper()
98 {
99 SetPort( m_newPort ) ;
100 SetClip( m_formerClip ) ;
101 DisposeRgn( m_newClip ) ;
102 DisposeRgn( m_formerClip ) ;
103 }
104
105 wxMacWindowStateSaver::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
113 wxMacWindowStateSaver::~wxMacWindowStateSaver()
114 {
115 SetPort( m_newPort ) ;
116 SetThemeDrawingState( m_themeDrawingState , true ) ;
117 }
118
119 // minimal implementation only used for appearance drawing < 10.3
120
121 wxMacPortSetter::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
130 wxMacPortSetter::~wxMacPortSetter()
131 {
132 // m_dc->MacCleanupPort(&m_ph) ;
133 }
134
135 //-----------------------------------------------------------------------------
136 // Local functions
137 //-----------------------------------------------------------------------------
138
139 static inline double dmin(double a, double b) { return a < b ? a : b; }
140 static inline double dmax(double a, double b) { return a > b ? a : b; }
141 static 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
159 wxMacCGPath::wxMacCGPath()
160 {
161 m_path = CGPathCreateMutable() ;
162 }
163
164 wxMacCGPath::~wxMacCGPath()
165 {
166 CGPathRelease( m_path ) ;
167 }
168
169 // opens (starts) a new subpath
170 void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
171 {
172 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
173 }
174
175 void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
176 {
177 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
178 }
179
180 void wxMacCGPath::AddQuadCurveToPoint( wxCoord cx1, wxCoord cy1, wxCoord x1, wxCoord y1 )
181 {
182 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x1 , y1 );
183 }
184
185 void 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
191 void 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
197 void wxMacCGPath::CloseSubpath()
198 {
199 CGPathCloseSubpath( m_path ) ;
200 }
201
202 CGPathRef wxMacCGPath::GetPath() const
203 {
204 return m_path ;
205 }
206
207 void 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
212 void 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
221 wxMacCGContext::wxMacCGContext( CGrafPtr port )
222 {
223 m_qdPort = port ;
224 m_cgContext = NULL ;
225 m_mode = kCGPathFill;
226 m_macATSUIStyle = NULL ;
227 }
228
229 wxMacCGContext::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
239 wxMacCGContext::wxMacCGContext()
240 {
241 m_qdPort = NULL ;
242 m_cgContext = NULL ;
243 m_mode = kCGPathFill;
244 m_macATSUIStyle = NULL ;
245 }
246
247 wxMacCGContext::~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
261 void wxMacCGContext::Clip( const wxRegion &region )
262 {
263 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
264 }
265
266 void 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
273 void 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
290 void 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
310 wxGraphicPath* 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
322 CGContextRef 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
344 void 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
354 void wxMacCGContext::Translate( wxCoord dx , wxCoord dy )
355 {
356 CGContextTranslateCTM( m_cgContext, dx, dy );
357 }
358
359 void wxMacCGContext::Scale( wxCoord xScale , wxCoord yScale )
360 {
361 CGContextScaleCTM( m_cgContext , xScale , yScale ) ;
362 }
363
364 void 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
372 void 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
383 void wxMacCGContext::PushState()
384 {
385 CGContextSaveGState( m_cgContext );
386 }
387
388 void wxMacCGContext::PopState()
389 {
390 CGContextRestoreGState( m_cgContext );
391 }
392
393 void 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
403 class wxMacCGPattern
404 {
405 public :
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
413 protected :
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
438 const CGPatternCallbacks wxMacCGPattern::ms_Callbacks = { 0, &wxMacCGPattern::_Render, &wxMacCGPattern::_Dispose };
439
440 class ImagePattern : public wxMacCGPattern
441 {
442 public :
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
465 protected :
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
489 class HatchPattern : public wxMacCGPattern
490 {
491 public :
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
593 protected :
594 virtual ~HatchPattern() {}
595
596 CGRect m_imageBounds ;
597 int m_hatch ;
598 };
599
600 #pragma mark -
601
602 void 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
779 void 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
840 void 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
968 void 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
1025 void 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
1083 void 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
1130 wxDC::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
1160 wxDC::~wxDC()
1161 {
1162 if ( m_macATSUIStyle )
1163 {
1164 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1165 m_macATSUIStyle = NULL ;
1166 }
1167
1168 delete m_graphicContext ;
1169 }
1170
1171 void 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
1186 void 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
1201 void 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
1239 void 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
1291 void 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
1305 void 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
1316 void 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
1327 void wxDC::SetTextBackground( const wxColour &col )
1328 {
1329 wxCHECK_RET( Ok(), wxT("wxDC(cg)::SetTextBackground - invalid DC") );
1330
1331 m_textBackgroundColour = col;
1332 }
1333
1334 void 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
1367 void wxDC::SetUserScale( double x, double y )
1368 {
1369 // allow negative ? -> no
1370 m_userScaleX = x;
1371 m_userScaleY = y;
1372 ComputeScaleAndOrigin();
1373 }
1374
1375 void wxDC::SetLogicalScale( double x, double y )
1376 {
1377 // allow negative ?
1378 m_logicalScaleX = x;
1379 m_logicalScaleY = y;
1380 ComputeScaleAndOrigin();
1381 }
1382
1383 void 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
1390 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1391 {
1392 m_externalDeviceOriginX = x;
1393 m_externalDeviceOriginY = y;
1394 ComputeScaleAndOrigin();
1395 }
1396
1397 void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1398 {
1399 m_signX = (xLeftRight ? 1 : -1);
1400 m_signY = (yBottomUp ? -1 : 1);
1401 ComputeScaleAndOrigin();
1402 }
1403
1404 wxSize wxDC::GetPPI() const
1405 {
1406 return wxSize(72, 72);
1407 }
1408
1409 int wxDC::GetDepth() const
1410 {
1411 return 32;
1412 }
1413
1414 void 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
1436 void wxDC::SetPalette( const wxPalette& palette )
1437 {
1438 }
1439
1440 void wxDC::SetBackgroundMode( int mode )
1441 {
1442 m_backgroundMode = mode ;
1443 }
1444
1445 void wxDC::SetFont( const wxFont &font )
1446 {
1447 m_font = font;
1448 if ( m_graphicContext )
1449 m_graphicContext->SetFont( font ) ;
1450 }
1451
1452 void 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
1477 void 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
1502 void 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
1512 void 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
1529 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
1530 const wxColour & col, int style);
1531
1532 bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
1533 const wxColour& col, int style)
1534 {
1535 return wxDoFloodFill(this, x, y, col, style);
1536 }
1537
1538 bool 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
1556 void 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
1581 void 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
1608 void 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
1664 void 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
1705 void 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
1712 void 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
1740 void 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
1799 void 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
1833 void 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
1867 void 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
1924 void 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
1962 bool wxDC::CanDrawBitmap() const
1963 {
1964 return true ;
1965 }
1966
1967 bool 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
2043 void 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
2060 void 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
2067 bool wxDC::CanGetTextExtent() const
2068 {
2069 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::CanGetTextExtent - invalid DC") );
2070
2071 return true ;
2072 }
2073
2074 void 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
2105 bool 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
2116 wxCoord wxDC::GetCharWidth(void) const
2117 {
2118 wxCoord width ;
2119 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
2120
2121 return width ;
2122 }
2123
2124 wxCoord wxDC::GetCharHeight(void) const
2125 {
2126 wxCoord height ;
2127 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
2128
2129 return height ;
2130 }
2131
2132 void 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
2216 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2217 {
2218 return ((wxDC *)this)->XDEV2LOG(x);
2219 }
2220
2221 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2222 {
2223 return ((wxDC *)this)->YDEV2LOG(y);
2224 }
2225
2226 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2227 {
2228 return ((wxDC *)this)->XDEV2LOGREL(x);
2229 }
2230
2231 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2232 {
2233 return ((wxDC *)this)->YDEV2LOGREL(y);
2234 }
2235
2236 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2237 {
2238 return ((wxDC *)this)->XLOG2DEV(x);
2239 }
2240
2241 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2242 {
2243 return ((wxDC *)this)->YLOG2DEV(y);
2244 }
2245
2246 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2247 {
2248 return ((wxDC *)this)->XLOG2DEVREL(x);
2249 }
2250
2251 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2252 {
2253 return ((wxDC *)this)->YLOG2DEVREL(y);
2254 }
2255
2256 #endif // wxMAC_USE_CORE_GRAPHICS