]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dccg.cpp
Added missing URL attribute testing
[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/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
43 typedef float CGFloat ;
44 #endif
45
46 //-----------------------------------------------------------------------------
47 // constants
48 //-----------------------------------------------------------------------------
49
50 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
51 #ifndef M_PI
52 const double M_PI = 3.14159265358979 ;
53 #endif
54 #endif
55
56 static 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 //
63 wxMacWindowClipper::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
89 wxMacWindowClipper::~wxMacWindowClipper()
90 {
91 SetPort( m_newPort ) ;
92 SetClip( m_formerClip ) ;
93 DisposeRgn( m_newClip ) ;
94 DisposeRgn( m_formerClip ) ;
95 }
96
97 wxMacWindowStateSaver::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
105 wxMacWindowStateSaver::~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
114 wxMacPortSetter::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
123 wxMacPortSetter::~wxMacPortSetter()
124 {
125 // m_dc->MacCleanupPort(&m_ph) ;
126 }
127
128 #endif
129
130 #endif
131
132 //-----------------------------------------------------------------------------
133 // Local functions
134 //-----------------------------------------------------------------------------
135
136 static 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
156 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
157
158 wxMacCGPath::wxMacCGPath()
159 {
160 m_path = CGPathCreateMutable() ;
161 }
162
163 wxMacCGPath::~wxMacCGPath()
164 {
165 CGPathRelease( m_path ) ;
166 }
167
168 // opens (starts) a new subpath
169 void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
170 {
171 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
172 }
173
174 void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
175 {
176 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
177 }
178
179 void wxMacCGPath::AddQuadCurveToPoint( wxCoord cx1, wxCoord cy1, wxCoord x1, wxCoord y1 )
180 {
181 CGPathAddQuadCurveToPoint( m_path , NULL , cx1 , cy1 , x1 , y1 );
182 }
183
184 void 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
190 void 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
196 void wxMacCGPath::CloseSubpath()
197 {
198 CGPathCloseSubpath( m_path ) ;
199 }
200
201 CGPathRef wxMacCGPath::GetPath() const
202 {
203 return m_path ;
204 }
205
206 void 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
211 void 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
220 wxMacCGContext::wxMacCGContext( CGrafPtr port )
221 {
222 m_qdPort = port ;
223 m_cgContext = NULL ;
224 m_mode = kCGPathFill;
225 m_macATSUIStyle = NULL ;
226 }
227
228 wxMacCGContext::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
238 wxMacCGContext::wxMacCGContext()
239 {
240 m_qdPort = NULL ;
241 m_cgContext = NULL ;
242 m_mode = kCGPathFill;
243 m_macATSUIStyle = NULL ;
244 }
245
246 wxMacCGContext::~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
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
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
288 void 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
319 void 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
339 wxGraphicPath* 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
351 CGContextRef 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
376 void 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
386 void wxMacCGContext::Translate( wxCoord dx , wxCoord dy )
387 {
388 CGContextTranslateCTM( m_cgContext, dx, dy );
389 }
390
391 void wxMacCGContext::Scale( wxCoord xScale , wxCoord yScale )
392 {
393 CGContextScaleCTM( m_cgContext , xScale , yScale ) ;
394 }
395
396 void 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
414 void 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
425 void wxMacCGContext::PushState()
426 {
427 CGContextSaveGState( m_cgContext );
428 }
429
430 void wxMacCGContext::PopState()
431 {
432 CGContextRestoreGState( m_cgContext );
433 }
434
435 void 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
445 class wxMacCGPattern
446 {
447 public :
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
455 protected :
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
480 const CGPatternCallbacks wxMacCGPattern::ms_Callbacks = { 0, &wxMacCGPattern::_Render, &wxMacCGPattern::_Dispose };
481
482 class ImagePattern : public wxMacCGPattern
483 {
484 public :
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
507 protected :
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
531 class HatchPattern : public wxMacCGPattern
532 {
533 public :
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
635 protected :
636 virtual ~HatchPattern() {}
637
638 CGRect m_imageBounds ;
639 int m_hatch ;
640 };
641
642 #pragma mark -
643
644 void 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
821 void 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
882 void 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
1010 void 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
1067 void 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
1124 void 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
1171 wxDC::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
1201 wxDC::~wxDC()
1202 {
1203 if ( m_macATSUIStyle )
1204 {
1205 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1206 m_macATSUIStyle = NULL ;
1207 }
1208
1209 delete m_graphicContext ;
1210 }
1211
1212 void 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
1238 void 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
1253 void 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
1291 void 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
1336 void 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
1348 void 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
1359 void 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
1372 void wxDC::SetTextBackground( const wxColour &col )
1373 {
1374 wxCHECK_RET( Ok(), wxT("wxDC(cg)::SetTextBackground - invalid DC") );
1375
1376 m_textBackgroundColour = col;
1377 }
1378
1379 void 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
1412 void wxDC::SetUserScale( double x, double y )
1413 {
1414 // allow negative ? -> no
1415 m_userScaleX = x;
1416 m_userScaleY = y;
1417 ComputeScaleAndOrigin();
1418 }
1419
1420 void wxDC::SetLogicalScale( double x, double y )
1421 {
1422 // allow negative ?
1423 m_logicalScaleX = x;
1424 m_logicalScaleY = y;
1425 ComputeScaleAndOrigin();
1426 }
1427
1428 void 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
1435 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1436 {
1437 m_externalDeviceOriginX = x;
1438 m_externalDeviceOriginY = y;
1439 ComputeScaleAndOrigin();
1440 }
1441
1442 void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1443 {
1444 m_signX = (xLeftRight ? 1 : -1);
1445 m_signY = (yBottomUp ? -1 : 1);
1446 ComputeScaleAndOrigin();
1447 }
1448
1449 wxSize wxDC::GetPPI() const
1450 {
1451 return wxSize(72, 72);
1452 }
1453
1454 int wxDC::GetDepth() const
1455 {
1456 return 32;
1457 }
1458
1459 void 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
1481 void wxDC::SetPalette( const wxPalette& palette )
1482 {
1483 }
1484
1485 void wxDC::SetBackgroundMode( int mode )
1486 {
1487 m_backgroundMode = mode ;
1488 }
1489
1490 void wxDC::SetFont( const wxFont &font )
1491 {
1492 m_font = font;
1493 if ( m_graphicContext )
1494 m_graphicContext->SetFont( font ) ;
1495 }
1496
1497 void 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
1522 void 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
1547 void 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
1557 void 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
1574 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
1575 const wxColour & col, int style);
1576
1577 bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
1578 const wxColour& col, int style)
1579 {
1580 return wxDoFloodFill(this, x, y, col, style);
1581 }
1582
1583 bool 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
1601 void 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
1626 void 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
1653 void 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
1709 void 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
1750 void 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
1757 void 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
1785 void 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
1844 void 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
1878 void 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
1925 void 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
1976 void 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
2014 bool wxDC::CanDrawBitmap() const
2015 {
2016 return true ;
2017 }
2018
2019 bool 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
2030 bool 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
2109 void 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
2126 void 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
2133 bool wxDC::CanGetTextExtent() const
2134 {
2135 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::CanGetTextExtent - invalid DC") );
2136
2137 return true ;
2138 }
2139
2140 void 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
2170 bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2171 {
2172 wxCHECK_MSG( Ok(), false, wxT("wxDC(cg)::DoGetPartialTextExtents - invalid DC") );
2173
2174 m_graphicContext->GetPartialTextExtents( text, widths ) ;
2175 for ( size_t i = 0 ; i < widths.GetCount() ; ++i )
2176 widths[i] = XDEV2LOGREL( widths[i] );
2177
2178 return true;
2179 }
2180
2181 wxCoord wxDC::GetCharWidth(void) const
2182 {
2183 wxCoord width ;
2184 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
2185
2186 return width ;
2187 }
2188
2189 wxCoord wxDC::GetCharHeight(void) const
2190 {
2191 wxCoord height ;
2192 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
2193
2194 return height ;
2195 }
2196
2197 void wxDC::Clear(void)
2198 {
2199 wxCHECK_RET( Ok(), wxT("wxDC(cg)::Clear - invalid DC") );
2200
2201 if (m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
2202 {
2203 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
2204 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
2205 switch ( m_backgroundBrush.MacGetBrushKind() )
2206 {
2207 case kwxMacBrushTheme :
2208 {
2209 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
2210 if ( HIThemeSetFill != 0 )
2211 {
2212 HIThemeSetFill( m_backgroundBrush.MacGetTheme(), NULL, cg, kHIThemeOrientationNormal );
2213 CGContextFillRect(cg, rect);
2214
2215 }
2216 else
2217 #endif
2218 {
2219 RGBColor color;
2220 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme(), 32, true, &color );
2221 CGContextSetRGBFillColor( cg, (CGFloat) color.red / 65536,
2222 (CGFloat) color.green / 65536, (CGFloat) color.blue / 65536, 1 );
2223 CGContextFillRect( cg, rect );
2224 }
2225
2226 // reset to normal value
2227 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
2228 CGContextSetRGBFillColor( cg, col.red / 65536.0, col.green / 65536.0, col.blue / 65536.0, 1.0 );
2229 }
2230 break ;
2231
2232 case kwxMacBrushThemeBackground :
2233 {
2234 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
2235
2236 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
2237 if ( UMAGetSystemVersion() >= 0x1030 )
2238 {
2239 HIThemeBackgroundDrawInfo drawInfo ;
2240 drawInfo.version = 0 ;
2241 drawInfo.state = kThemeStateActive ;
2242 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground( NULL ) ;
2243 if ( drawInfo.kind == kThemeBackgroundMetal )
2244 {
2245 HIThemeDrawBackground( &rect, &drawInfo, cg, kHIThemeOrientationNormal ) ;
2246 HIThemeApplyBackground( &rect, &drawInfo, cg, kHIThemeOrientationNormal ) ;
2247 }
2248 }
2249 #endif
2250 }
2251 break ;
2252
2253 case kwxMacBrushColour :
2254 {
2255 // FIXME: doesn't correctly render stippled brushes !!
2256 // FIXME: should this be replaced by ::SetBrush() ??
2257
2258 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
2259 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
2260 CGContextFillRect(cg, rect);
2261
2262 // reset to normal value
2263 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
2264 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
2265 }
2266 break ;
2267
2268 default :
2269 wxFAIL_MSG( wxT("unknown brush kind") ) ;
2270 break ;
2271 }
2272 }
2273 }
2274
2275 #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
2301 wxCoord wxDC::DeviceToLogicalX(wxCoord x) const
2302 {
2303 return wxRound((double)(x - m_deviceOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
2304 }
2305
2306 wxCoord wxDC::DeviceToLogicalY(wxCoord y) const
2307 {
2308 return wxRound((double)(y - m_deviceOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
2309 }
2310
2311 wxCoord wxDC::DeviceToLogicalXRel(wxCoord x) const
2312 {
2313 return wxRound((double)(x) / m_scaleX);
2314 }
2315
2316 wxCoord wxDC::DeviceToLogicalYRel(wxCoord y) const
2317 {
2318 return wxRound((double)(y) / m_scaleY);
2319 }
2320
2321 wxCoord wxDC::LogicalToDeviceX(wxCoord x) const
2322 {
2323 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX;
2324 }
2325
2326 wxCoord wxDC::LogicalToDeviceY(wxCoord y) const
2327 {
2328 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY;
2329 }
2330
2331 wxCoord wxDC::LogicalToDeviceXRel(wxCoord x) const
2332 {
2333 return wxRound((double)(x) * m_scaleX);
2334 }
2335
2336 wxCoord wxDC::LogicalToDeviceYRel(wxCoord y) const
2337 {
2338 return wxRound((double)(y) * m_scaleY);
2339 }
2340 */ // TODO
2341 #endif // wxMAC_USE_CORE_GRAPHICS