]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dccg.cpp
switching to IconRefs for menu bitmaps
[wxWidgets.git] / src / mac / carbon / dccg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dc.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 #ifdef __GNUG__
13 #pragma implementation "dc.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #include "wx/dc.h"
19
20 #if wxMAC_USE_CORE_GRAPHICS
21
22 #include "wx/app.h"
23 #include "wx/mac/uma.h"
24 #include "wx/dcmemory.h"
25 #include "wx/dcprint.h"
26 #include "wx/region.h"
27 #include "wx/image.h"
28 #include "wx/log.h"
29
30
31 #if __MSL__ >= 0x6000
32 #include "math.h"
33 using namespace std ;
34 #endif
35
36 #include "wx/mac/private.h"
37 #include <ATSUnicode.h>
38 #include <TextCommon.h>
39 #include <TextEncodingConverter.h>
40 #include <FixMath.h>
41 #include <CGContext.h>
42
43 #if !USE_SHARED_LIBRARY
44 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
45 #endif
46
47 //-----------------------------------------------------------------------------
48 // constants
49 //-----------------------------------------------------------------------------
50
51 #if !defined( __DARWIN__ ) || defined(__MWERKS__)
52 #ifndef M_PI
53 const double M_PI = 3.14159265358979 ;
54 #endif
55 #endif
56 const double RAD2DEG = 180.0 / M_PI;
57 const short kEmulatedMode = -1 ;
58 const short kUnsupportedMode = -2 ;
59
60 extern TECObjectRef s_TECNativeCToUnicode ;
61
62 // TODO Update
63 // The text ctrl implementation still needs that for the non hiview implementation
64
65 wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
66 wxMacPortSaver( (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) )
67 {
68 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
69 m_formerClip = NewRgn() ;
70 m_newClip = NewRgn() ;
71 GetClip( m_formerClip ) ;
72
73 if ( win )
74 {
75 int x = 0 , y = 0;
76 win->MacWindowToRootWindow( &x,&y ) ;
77 // get area including focus rect
78 CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
79 if ( !EmptyRgn( m_newClip ) )
80 OffsetRgn( m_newClip , x , y ) ;
81
82 SetClip( m_newClip ) ;
83 }
84 }
85
86 wxMacWindowClipper::~wxMacWindowClipper()
87 {
88 SetPort( m_newPort ) ;
89 SetClip( m_formerClip ) ;
90 DisposeRgn( m_newClip ) ;
91 DisposeRgn( m_formerClip ) ;
92 }
93
94 wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
95 wxMacWindowClipper( win )
96 {
97 // the port is already set at this point
98 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
99 GetThemeDrawingState( &m_themeDrawingState ) ;
100 }
101
102 wxMacWindowStateSaver::~wxMacWindowStateSaver()
103 {
104 SetPort( m_newPort ) ;
105 SetThemeDrawingState( m_themeDrawingState , true ) ;
106 }
107
108 // minimal implementation only used for appearance drawing < 10.3
109
110 wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
111 m_ph( (GrafPtr) dc->m_macPort )
112 {
113 wxASSERT( dc->Ok() ) ;
114 m_dc = dc ;
115 // dc->MacSetupPort(&m_ph) ;
116 }
117 wxMacPortSetter::~wxMacPortSetter()
118 {
119 // m_dc->MacCleanupPort(&m_ph) ;
120 }
121
122 //-----------------------------------------------------------------------------
123 // Local functions
124 //-----------------------------------------------------------------------------
125
126 static inline double dmin(double a, double b) { return a < b ? a : b; }
127 static inline double dmax(double a, double b) { return a > b ? a : b; }
128 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
129
130 //-----------------------------------------------------------------------------
131 // device context implementation
132 //
133 // more and more of the dc functionality should be implemented by calling
134 // the appropricate wxMacCGContext, but we will have to do that step by step
135 // also coordinate conversions should be moved to native matrix ops
136 //-----------------------------------------------------------------------------
137
138 wxMacCGPath::wxMacCGPath()
139 {
140 m_path = CGPathCreateMutable() ;
141 }
142
143 wxMacCGPath::~wxMacCGPath()
144 {
145 CGPathRelease( m_path ) ;
146 }
147
148 // Starts a new subpath at
149 void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
150 {
151 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
152 }
153
154 void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
155 {
156 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
157 }
158
159 void wxMacCGPath::AddRectangle( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
160 {
161 CGRect cgRect = { { x , y } , { w , h } } ;
162 CGPathAddRect( m_path , NULL , cgRect ) ;
163 }
164
165 void wxMacCGPath::AddCircle( wxCoord x, wxCoord y , wxCoord r )
166 {
167 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true ) ;
168 }
169
170 // closes the current subpath
171 void wxMacCGPath::CloseSubpath()
172 {
173 CGPathCloseSubpath( m_path ) ;
174 }
175
176 CGPathRef wxMacCGPath::GetPath() const
177 {
178 return m_path ;
179 }
180
181 // we always stock two context states, one at entry, the other one after
182 // changing to HI Graphics orientation (this one is used for getting back clippings etc)
183
184 wxMacCGContext::wxMacCGContext( CGrafPtr port )
185 {
186 m_qdPort = port ;
187 m_cgContext = NULL ;
188 }
189
190 wxMacCGContext::wxMacCGContext( CGContextRef cgcontext )
191 {
192 m_qdPort = NULL ;
193 m_cgContext = cgcontext ;
194 CGContextSaveGState( m_cgContext ) ;
195 CGContextSaveGState( m_cgContext ) ;
196 }
197
198 wxMacCGContext::wxMacCGContext()
199 {
200 m_qdPort = NULL ;
201 m_cgContext = NULL ;
202 }
203
204 wxMacCGContext::~wxMacCGContext()
205 {
206 if ( m_cgContext )
207 {
208 CGContextRestoreGState( m_cgContext ) ;
209 CGContextRestoreGState( m_cgContext ) ;
210 }
211 if ( m_qdPort )
212 QDEndCGContext( m_qdPort , &m_cgContext ) ;
213 }
214
215
216 void wxMacCGContext::Clip( const wxRegion &region )
217 {
218 // ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
219 }
220
221 void wxMacCGContext::StrokePath( const wxGraphicPath *p )
222 {
223 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
224 CGContextBeginPath( m_cgContext ) ;
225 CGContextAddPath( m_cgContext , path->GetPath() ) ;
226 CGContextClosePath( m_cgContext ) ;
227 CGContextStrokePath( m_cgContext ) ;
228 }
229
230 void wxMacCGContext::DrawPath( const wxGraphicPath *p , int fillStyle )
231 {
232 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
233 CGPathDrawingMode mode = m_mode ;
234 if ( fillStyle == wxODDEVEN_RULE )
235 {
236 if ( mode == kCGPathFill )
237 mode = kCGPathEOFill ;
238 else if ( mode == kCGPathFillStroke )
239 mode = kCGPathEOFillStroke ;
240 }
241 CGContextBeginPath( m_cgContext ) ;
242 CGContextAddPath( m_cgContext , path->GetPath() ) ;
243 CGContextClosePath( m_cgContext ) ;
244 CGContextDrawPath( m_cgContext , mode ) ;
245 }
246
247 void wxMacCGContext::FillPath( const wxGraphicPath *p , const wxColor &fillColor , int fillStyle )
248 {
249 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
250 CGContextSaveGState( m_cgContext ) ;
251
252 RGBColor col = MAC_WXCOLORREF( fillColor.GetPixel() ) ;
253 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
254 CGPathDrawingMode mode = kCGPathFill ;
255
256 if ( fillStyle == wxODDEVEN_RULE )
257 mode = kCGPathEOFill ;
258
259 CGContextBeginPath( m_cgContext ) ;
260 CGContextAddPath( m_cgContext , path->GetPath() ) ;
261 CGContextClosePath( m_cgContext ) ;
262 CGContextDrawPath( m_cgContext , mode ) ;
263
264 CGContextRestoreGState( m_cgContext ) ;
265 }
266
267 wxGraphicPath* wxMacCGContext::CreatePath()
268 {
269 // make sure that we now have a real cgref, before doing
270 // anything with paths
271 CGContextRef cg = GetNativeContext() ;
272 cg = NULL ;
273 return new wxMacCGPath() ;
274 }
275
276 // in case we only got a QDPort only create a cgref now
277
278 CGContextRef wxMacCGContext::GetNativeContext()
279 {
280 if( m_cgContext == NULL )
281 {
282 Rect bounds ;
283 GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
284 OSStatus status = QDBeginCGContext( (CGrafPtr) m_qdPort , &m_cgContext ) ;
285 CGContextSaveGState( m_cgContext ) ;
286
287 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
288 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
289 CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
290
291 CGContextSaveGState( m_cgContext ) ;
292 SetPen( m_pen ) ;
293 SetBrush( m_brush ) ;
294 }
295 return m_cgContext ;
296 }
297
298 void wxMacCGContext::SetNativeContext( CGContextRef cg )
299 {
300 wxASSERT( m_cgContext == NULL ) ;
301 m_cgContext = cg ;
302 CGContextSaveGState( m_cgContext ) ;
303 }
304
305 void wxMacCGContext::SetPen( const wxPen &pen )
306 {
307 m_pen = pen ;
308 if ( m_cgContext == NULL )
309 return ;
310 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
311 bool stroke = pen.GetStyle() != wxTRANSPARENT ;
312
313 #if 0
314 // we can benchmark performance, should go into a setting later
315 CGContextSetShouldAntialias( m_cgContext , false ) ;
316 #endif
317 if ( fill | stroke )
318 {
319 // setup brushes
320 m_mode = kCGPathFill ; // just a default
321
322 if ( fill )
323 {
324 m_mode = kCGPathFill ;
325 }
326 if ( stroke )
327 {
328 RGBColor col = MAC_WXCOLORREF( pen.GetColour().GetPixel() ) ;
329 CGContextSetRGBStrokeColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
330
331 CGLineCap cap ;
332 switch( pen.GetCap() )
333 {
334 case wxCAP_ROUND :
335 cap = kCGLineCapRound ;
336 break ;
337 case wxCAP_PROJECTING :
338 cap = kCGLineCapSquare ;
339 break ;
340 case wxCAP_BUTT :
341 cap = kCGLineCapButt ;
342 break ;
343 default :
344 cap = kCGLineCapButt ;
345 break ;
346 }
347 CGContextSetLineCap( m_cgContext , cap ) ;
348
349 CGLineJoin join ;
350 switch( pen.GetJoin() )
351 {
352 case wxJOIN_BEVEL :
353 join = kCGLineJoinBevel ;
354 break ;
355 case wxJOIN_MITER :
356 join = kCGLineJoinMiter ;
357 break ;
358 case wxJOIN_ROUND :
359 join = kCGLineJoinRound ;
360 break ;
361 default :
362 join = kCGLineJoinMiter ;
363 break;
364 }
365 CGContextSetLineJoin( m_cgContext , join ) ;
366
367 CGContextSetLineWidth( m_cgContext , pen.GetWidth() == 0 ? 0.1 : pen.GetWidth() /* TODO * m_dc->m_scaleX */ ) ;
368
369 m_mode = kCGPathStroke ;
370 int count = 0 ;
371 const float *lengths = NULL ;
372 float *userLengths = NULL ;
373
374 const float dotted[] = { 3 , 3 };
375 const float dashed[] = { 19 , 9 };
376 const float short_dashed[] = { 9 , 6 };
377 const float dotted_dashed[] = { 9 , 6 , 3 , 3 };
378
379 switch( pen.GetStyle() )
380 {
381 case wxSOLID :
382 break ;
383 case wxDOT :
384 lengths = dotted ;
385 count = WXSIZEOF(dotted);
386 break ;
387 case wxLONG_DASH :
388 lengths = dashed ;
389 count = WXSIZEOF(dashed) ;
390 break ;
391 case wxSHORT_DASH :
392 lengths = short_dashed ;
393 count = WXSIZEOF(short_dashed) ;
394 break ;
395 case wxDOT_DASH :
396 lengths = dotted_dashed ;
397 count = WXSIZEOF(dotted_dashed);
398 break ;
399 case wxUSER_DASH :
400 wxDash *dashes ;
401 count = pen.GetDashes( &dashes ) ;
402 if ( count >0 )
403 {
404 userLengths = new float[count] ;
405 for( int i = 0 ; i < count ; ++i )
406 userLengths[i] = dashes[i] ;
407 }
408 lengths = userLengths ;
409 break ;
410 default :
411 break ;
412 }
413
414 CGContextSetLineDash( m_cgContext , 0 , lengths , count ) ;
415 delete[] userLengths ;
416 // we need to change the cap, otherwise everything overlaps
417 // and we get solid lines
418 if ( count > 0 )
419 CGContextSetLineCap( m_cgContext , kCGLineCapButt ) ;
420 }
421 if ( fill && stroke )
422 {
423 m_mode = kCGPathFillStroke ;
424 }
425
426 }
427 }
428 void wxMacCGContext::SetBrush( const wxBrush &brush )
429 {
430 m_brush = brush ;
431 if ( m_cgContext == NULL )
432 return ;
433
434 bool fill = brush.GetStyle() != wxTRANSPARENT ;
435 bool stroke = m_pen.GetStyle() != wxTRANSPARENT ;
436
437 #if 0
438 // we can benchmark performance, should go into a setting later
439 CGContextSetShouldAntialias( m_cgContext , false ) ;
440 #endif
441 if ( fill | stroke )
442 {
443
444 // setup brushes
445 m_mode = kCGPathFill ; // just a default
446
447 if ( fill )
448 {
449 RGBColor col = MAC_WXCOLORREF( brush.GetColour().GetPixel() ) ;
450 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
451 m_mode = kCGPathFill ;
452 }
453 if ( stroke )
454 {
455 m_mode = kCGPathStroke ;
456 }
457 if ( fill && stroke )
458 {
459 m_mode = kCGPathFillStroke ;
460 }
461
462 }
463 }
464
465 // snippets from Sketch Sample from Apple :
466
467 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
468 /*
469 This function locates, opens, and returns the profile reference for the calibrated
470 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
471 with the profile reference this function returns.
472 */
473 CMProfileRef wxMacOpenGenericProfile(void)
474 {
475 static CMProfileRef cachedRGBProfileRef = NULL;
476
477 // we only create the profile reference once
478 if (cachedRGBProfileRef == NULL)
479 {
480 CMProfileLocation loc;
481
482 loc.locType = cmPathBasedProfile;
483 strcpy(loc.u.pathLoc.path, kGenericRGBProfilePathStr);
484
485 verify_noerr( CMOpenProfile(&cachedRGBProfileRef, &loc) );
486 }
487
488 if (cachedRGBProfileRef)
489 {
490 // clone the profile reference so that the caller has their own reference, not our cached one
491 CMCloneProfileRef(cachedRGBProfileRef);
492 }
493
494 return cachedRGBProfileRef;
495 }
496
497 /*
498 Return the generic RGB color space. This is a 'get' function and the caller should
499 not release the returned value unless the caller retains it first. Usually callers
500 of this routine will immediately use the returned colorspace with CoreGraphics
501 so they typically do not need to retain it themselves.
502
503 This function creates the generic RGB color space once and hangs onto it so it can
504 return it whenever this function is called.
505 */
506
507 CGColorSpaceRef wxMacGetGenericRGBColorSpace()
508 {
509 static CGColorSpaceRef genericRGBColorSpace = NULL;
510
511 if (genericRGBColorSpace == NULL)
512 {
513 CMProfileRef genericRGBProfile = wxMacOpenGenericProfile();
514
515 if (genericRGBProfile)
516 {
517 genericRGBColorSpace = CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile);
518 wxASSERT_MSG( genericRGBColorSpace != NULL, wxT("couldn't create the generic RGB color space") ) ;
519
520 // we opened the profile so it is up to us to close it
521 CMCloseProfile(genericRGBProfile);
522 }
523 }
524 return genericRGBColorSpace;
525 }
526
527 void AddEllipticArcToPath(CGContextRef c, CGPoint center, float a, float b, float fromDegree , float toDegree )
528 {
529 CGContextSaveGState(c);
530 CGContextTranslateCTM(c, center.x, center.y);
531 CGContextScaleCTM(c, a, b);
532 CGContextMoveToPoint(c, 1, 0);
533 CGContextAddArc(c, 0, 0, 1, DegToRad(fromDegree), DegToRad(toDegree), 0);
534 CGContextClosePath(c);
535 CGContextRestoreGState(c);
536 }
537
538 void AddRoundedRectToPath(CGContextRef c, CGRect rect, float ovalWidth,
539 float ovalHeight)
540 {
541 float fw, fh;
542 if (ovalWidth == 0 || ovalHeight == 0)
543 {
544 CGContextAddRect(c, rect);
545 return;
546 }
547 CGContextSaveGState(c);
548 CGContextTranslateCTM(c, CGRectGetMinX(rect), CGRectGetMinY(rect));
549 CGContextScaleCTM(c, ovalWidth, ovalHeight);
550 fw = CGRectGetWidth(rect) / ovalWidth;
551 fh = CGRectGetHeight(rect) / ovalHeight;
552 CGContextMoveToPoint(c, fw, fh/2);
553 CGContextAddArcToPoint(c, fw, fh, fw/2, fh, 1);
554 CGContextAddArcToPoint(c, 0, fh, 0, fh/2, 1);
555 CGContextAddArcToPoint(c, 0, 0, fw/2, 0, 1);
556 CGContextAddArcToPoint(c, fw, 0, fw, fh/2, 1);
557 CGContextClosePath(c);
558 CGContextRestoreGState(c);
559 }
560
561 wxDC::wxDC()
562 {
563 m_ok = FALSE;
564 m_colour = TRUE;
565 m_mm_to_pix_x = mm2pt;
566 m_mm_to_pix_y = mm2pt;
567 m_internalDeviceOriginX = 0;
568 m_internalDeviceOriginY = 0;
569 m_externalDeviceOriginX = 0;
570 m_externalDeviceOriginY = 0;
571 m_logicalScaleX = 1.0;
572 m_logicalScaleY = 1.0;
573 m_userScaleX = 1.0;
574 m_userScaleY = 1.0;
575 m_scaleX = 1.0;
576 m_scaleY = 1.0;
577 m_needComputeScaleX = FALSE;
578 m_needComputeScaleY = FALSE;
579
580 m_ok = FALSE ;
581 m_macPort = 0 ;
582 m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
583
584 m_pen = *wxBLACK_PEN;
585 m_font = *wxNORMAL_FONT;
586 m_brush = *wxWHITE_BRUSH;
587
588 m_macATSUIStyle = NULL ;
589
590 m_graphicContext = NULL ;
591 }
592
593 wxDC::~wxDC(void)
594 {
595 if( m_macATSUIStyle )
596 {
597 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
598 m_macATSUIStyle = NULL ;
599 }
600
601 delete m_graphicContext ;
602 }
603
604 void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
605 {
606 wxCHECK_RET( Ok(), wxT("invalid window dc") );
607 wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") );
608 wxCoord xx = XLOG2DEVMAC(x);
609 wxCoord yy = YLOG2DEVMAC(y);
610 wxCoord w = bmp.GetWidth();
611 wxCoord h = bmp.GetHeight();
612 wxCoord ww = XLOG2DEVREL(w);
613 wxCoord hh = YLOG2DEVREL(h);
614
615 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
616 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ) ;
617 HIRect r = CGRectMake( xx , yy , ww , hh ) ;
618 HIViewDrawCGImage( cg , &r , image ) ;
619 CGImageRelease( image ) ;
620 }
621
622 void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
623 {
624 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
625 wxCHECK_RET(icon.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
626
627 wxCoord xx = XLOG2DEVMAC(x);
628 wxCoord yy = YLOG2DEVMAC(y);
629 wxCoord w = icon.GetWidth();
630 wxCoord h = icon.GetHeight();
631 wxCoord ww = XLOG2DEVREL(w);
632 wxCoord hh = YLOG2DEVREL(h);
633
634 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
635 CGRect r = CGRectMake( 00 , 00 , ww , hh ) ;
636 CGContextSaveGState(cg);
637 CGContextTranslateCTM(cg, xx , yy + hh );
638 CGContextScaleCTM(cg, 1, -1);
639 PlotIconRefInContext( cg , &r , kAlignNone , kTransformNone ,
640 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
641 CGContextRestoreGState( cg ) ;
642 }
643
644 void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
645 {
646 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
647 wxCoord xx, yy, ww, hh;
648 xx = XLOG2DEVMAC(x);
649 yy = YLOG2DEVMAC(y);
650 ww = XLOG2DEVREL(width);
651 hh = YLOG2DEVREL(height);
652
653 CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
654 CGRect clipRect = CGRectMake( xx ,yy , ww, hh ) ;
655 CGContextClipToRect( cgContext , clipRect ) ;
656
657 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
658 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
659 if( m_clipping )
660 {
661 m_clipX1 = wxMax( m_clipX1 , xx );
662 m_clipY1 = wxMax( m_clipY1 , yy );
663 m_clipX2 = wxMin( m_clipX2, (xx + ww));
664 m_clipY2 = wxMin( m_clipY2, (yy + hh));
665 }
666 else
667 {
668 m_clipping = TRUE;
669 m_clipX1 = xx;
670 m_clipY1 = yy;
671 m_clipX2 = xx + ww;
672 m_clipY2 = yy + hh;
673 }
674 // TODO as soon as we don't reset the context for each operation anymore
675 // we have to update the context as well
676 }
677
678 void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
679 {
680 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
681 if (region.Empty())
682 {
683 DestroyClippingRegion();
684 return;
685 }
686 wxCoord x, y, w, h;
687 region.GetBox( x, y, w, h );
688 wxCoord xx, yy, ww, hh;
689 xx = XLOG2DEVMAC(x);
690 yy = YLOG2DEVMAC(y);
691 ww = XLOG2DEVREL(w);
692 hh = YLOG2DEVREL(h);
693 // if we have a scaling that we cannot map onto native regions
694 // we must use the box
695 if ( ww != w || hh != h )
696 {
697 wxDC::DoSetClippingRegion( x, y, w, h );
698 }
699 else
700 {
701 /*
702 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
703 if ( xx != x || yy != y )
704 {
705 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
706 }
707 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
708 */
709 if( m_clipping )
710 {
711 m_clipX1 = wxMax( m_clipX1 , xx );
712 m_clipY1 = wxMax( m_clipY1 , yy );
713 m_clipX2 = wxMin( m_clipX2, (xx + ww));
714 m_clipY2 = wxMin( m_clipY2, (yy + hh));
715 }
716 else
717 {
718 m_clipping = TRUE;
719 m_clipX1 = xx;
720 m_clipY1 = yy;
721 m_clipX2 = xx + ww;
722 m_clipY2 = yy + hh;
723 }
724 }
725 }
726
727 void wxDC::DestroyClippingRegion()
728 {
729 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
730 CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
731 CGContextRestoreGState( cgContext );
732 CGContextSaveGState( cgContext );
733 SetPen( m_pen ) ;
734 SetBrush( m_brush ) ;
735 m_clipping = FALSE;
736 }
737
738 void wxDC::DoGetSizeMM( int* width, int* height ) const
739 {
740 int w = 0;
741 int h = 0;
742 GetSize( &w, &h );
743 *width = long( double(w) / (m_scaleX*m_mm_to_pix_x) );
744 *height = long( double(h) / (m_scaleY*m_mm_to_pix_y) );
745 }
746
747 void wxDC::SetTextForeground( const wxColour &col )
748 {
749 wxCHECK_RET(Ok(), wxT("Invalid DC"));
750 if ( col != m_textForegroundColour )
751 {
752 m_textForegroundColour = col;
753 MacInstallFont() ;
754 }
755 }
756
757 void wxDC::SetTextBackground( const wxColour &col )
758 {
759 wxCHECK_RET(Ok(), wxT("Invalid DC"));
760 m_textBackgroundColour = col;
761 }
762
763 void wxDC::SetMapMode( int mode )
764 {
765 switch (mode)
766 {
767 case wxMM_TWIPS:
768 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
769 break;
770 case wxMM_POINTS:
771 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
772 break;
773 case wxMM_METRIC:
774 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
775 break;
776 case wxMM_LOMETRIC:
777 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
778 break;
779 default:
780 case wxMM_TEXT:
781 SetLogicalScale( 1.0, 1.0 );
782 break;
783 }
784 if (mode != wxMM_TEXT)
785 {
786 m_needComputeScaleX = TRUE;
787 m_needComputeScaleY = TRUE;
788 }
789 }
790
791 void wxDC::SetUserScale( double x, double y )
792 {
793 // allow negative ? -> no
794 m_userScaleX = x;
795 m_userScaleY = y;
796 ComputeScaleAndOrigin();
797 }
798
799 void wxDC::SetLogicalScale( double x, double y )
800 {
801 // allow negative ?
802 m_logicalScaleX = x;
803 m_logicalScaleY = y;
804 ComputeScaleAndOrigin();
805 }
806
807 void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
808 {
809 m_logicalOriginX = x * m_signX; // is this still correct ?
810 m_logicalOriginY = y * m_signY;
811 ComputeScaleAndOrigin();
812 }
813
814 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
815 {
816 m_externalDeviceOriginX = x;
817 m_externalDeviceOriginY = y;
818 ComputeScaleAndOrigin();
819 }
820
821 void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
822 {
823 m_signX = (xLeftRight ? 1 : -1);
824 m_signY = (yBottomUp ? -1 : 1);
825 ComputeScaleAndOrigin();
826 }
827
828 wxSize wxDC::GetPPI() const
829 {
830 return wxSize(72, 72);
831 }
832
833 int wxDC::GetDepth() const
834 {
835 return 32 ;
836 }
837
838 void wxDC::ComputeScaleAndOrigin()
839 {
840 // CMB: copy scale to see if it changes
841 double origScaleX = m_scaleX;
842 double origScaleY = m_scaleY;
843 m_scaleX = m_logicalScaleX * m_userScaleX;
844 m_scaleY = m_logicalScaleY * m_userScaleY;
845 m_deviceOriginX = m_internalDeviceOriginX + m_externalDeviceOriginX;
846 m_deviceOriginY = m_internalDeviceOriginY + m_externalDeviceOriginY;
847 // CMB: if scale has changed call SetPen to recalulate the line width
848 if (m_scaleX != origScaleX || m_scaleY != origScaleY)
849 {
850 // this is a bit artificial, but we need to force wxDC to think
851 // the pen has changed
852 wxPen pen(GetPen());
853 m_pen = wxNullPen;
854 SetPen(pen);
855 }
856 }
857
858 void wxDC::SetPalette( const wxPalette& palette )
859 {
860 }
861
862 void wxDC::SetBackgroundMode( int mode )
863 {
864 m_backgroundMode = mode ;
865 }
866
867 void wxDC::SetFont( const wxFont &font )
868 {
869 m_font = font;
870 MacInstallFont() ;
871 }
872
873 void wxDC::SetPen( const wxPen &pen )
874 {
875 if ( m_pen == pen )
876 return ;
877 m_pen = pen;
878 if ( m_graphicContext )
879 {
880 m_graphicContext->SetPen( m_pen ) ;
881 }
882 }
883
884 void wxDC::SetBrush( const wxBrush &brush )
885 {
886 if (m_brush == brush)
887 return;
888 m_brush = brush;
889 if ( m_graphicContext )
890 {
891 m_graphicContext->SetBrush( m_brush ) ;
892 }
893 }
894
895 void wxDC::SetBackground( const wxBrush &brush )
896 {
897 if (m_backgroundBrush == brush)
898 return;
899 m_backgroundBrush = brush;
900 if (!m_backgroundBrush.Ok())
901 return;
902 }
903
904 void wxDC::SetLogicalFunction( int function )
905 {
906 if (m_logicalFunction == function)
907 return;
908 m_logicalFunction = function ;
909 }
910
911 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
912 const wxColour & col, int style);
913
914 bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
915 const wxColour& col, int style)
916 {
917 return wxDoFloodFill(this, x, y, col, style);
918 }
919
920 bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
921 {
922 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
923 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
924 wxMacPortSaver helper((CGrafPtr)m_macPort) ;
925 RGBColor colour;
926 GetCPixel(
927 XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x,
928 YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
929 // Convert from Mac colour to wx
930 col->Set( colour.red >> 8,
931 colour.green >> 8,
932 colour.blue >> 8);
933 return true ;
934 }
935
936 void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
937 {
938 wxCHECK_RET(Ok(), wxT("Invalid DC"));
939
940 wxCoord xx1 = XLOG2DEVMAC(x1) ;
941 wxCoord yy1 = YLOG2DEVMAC(y1) ;
942 wxCoord xx2 = XLOG2DEVMAC(x2) ;
943 wxCoord yy2 = YLOG2DEVMAC(y2) ;
944
945 wxGraphicPath* path = m_graphicContext->CreatePath() ;
946 path->MoveToPoint( xx1 , yy1 ) ;
947 path->AddLineToPoint( xx2 , yy2 ) ;
948 path->CloseSubpath() ;
949 m_graphicContext->StrokePath( path ) ;
950 delete path ;
951
952 CalcBoundingBox(x1, y1);
953 CalcBoundingBox(x2, y2);
954 }
955
956 void wxDC::DoCrossHair( wxCoord x, wxCoord y )
957 {
958 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
959
960
961 int w = 0;
962 int h = 0;
963 GetSize( &w, &h );
964 wxCoord xx = XLOG2DEVMAC(x);
965 wxCoord yy = YLOG2DEVMAC(y);
966
967 wxGraphicPath* path = m_graphicContext->CreatePath() ;
968 path->MoveToPoint( XLOG2DEVMAC(0), yy ) ;
969 path->AddLineToPoint( XLOG2DEVMAC(w), yy ) ;
970 path->CloseSubpath() ;
971 path->MoveToPoint( xx, YLOG2DEVMAC(0) ) ;
972 path->AddLineToPoint( xx, YLOG2DEVMAC(h) ) ;
973 path->CloseSubpath() ;
974 m_graphicContext->StrokePath( path ) ;
975 delete path ;
976
977 CalcBoundingBox(x, y);
978 CalcBoundingBox(x+w, y+h);
979 }
980
981 /*
982 * To draw arcs properly the angles need to be converted from the WX style:
983 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
984 * a normal axis on paper).
985 * TO
986 * the Mac style:
987 * Angles start on the +ve y axis and go clockwise.
988 */
989
990 static double wxConvertWXangleToMACangle(double angle)
991 {
992 double newAngle = 90 - angle ;
993 if ( newAngle < 0 )
994 newAngle += 360 ;
995 return newAngle ;
996 }
997
998 void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
999 wxCoord x2, wxCoord y2,
1000 wxCoord xc, wxCoord yc )
1001 {
1002 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
1003 wxCoord xx1 = XLOG2DEVMAC(x1);
1004 wxCoord yy1 = YLOG2DEVMAC(y1);
1005 wxCoord xx2 = XLOG2DEVMAC(x2);
1006 wxCoord yy2 = YLOG2DEVMAC(y2);
1007 wxCoord xxc = XLOG2DEVMAC(xc);
1008 wxCoord yyc = YLOG2DEVMAC(yc);
1009 double dx = xx1 - xxc;
1010 double dy = yy1 - yyc;
1011 double radius = sqrt((double)(dx*dx+dy*dy));
1012 wxCoord rad = (wxCoord)radius;
1013 double radius1, radius2;
1014 if (xx1 == xx2 && yy1 == yy2)
1015 {
1016 radius1 = 0.0;
1017 radius2 = 360.0;
1018 }
1019 else if (radius == 0.0)
1020 {
1021 radius1 = radius2 = 0.0;
1022 }
1023 else
1024 {
1025 radius1 = (xx1 - xxc == 0) ?
1026 (yy1 - yyc < 0) ? 90.0 : -90.0 :
1027 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
1028 radius2 = (xx2 - xxc == 0) ?
1029 (yy2 - yyc < 0) ? 90.0 : -90.0 :
1030 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
1031 }
1032 wxCoord alpha2 = wxCoord(radius2 - radius1);
1033 wxCoord alpha1 = wxCoord(wxConvertWXangleToMACangle(radius1));
1034 if( (xx1 > xx2) || (yy1 > yy2) ) {
1035 alpha2 *= -1;
1036 }
1037 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1038 CGContextRef ctx = mctx->GetNativeContext() ;
1039 AddEllipticArcToPath( ctx , CGPointMake( xxc , yyc ) , rad , rad , alpha1 , alpha2 ) ;
1040 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1041 }
1042
1043 void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1044 double sa, double ea )
1045 {
1046 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1047
1048 double angle = sa - ea; // Order important Mac in opposite direction to wx
1049 // we have to make sure that the filling is always counter-clockwise
1050 if ( angle > 0 )
1051 angle -= 360 ;
1052 wxCoord xx = XLOG2DEVMAC(x);
1053 wxCoord yy = YLOG2DEVMAC(y);
1054 wxCoord ww = m_signX * XLOG2DEVREL(w);
1055 wxCoord hh = m_signY * YLOG2DEVREL(h);
1056 // handle -ve width and/or height
1057 if (ww < 0) { ww = -ww; xx = xx - ww; }
1058 if (hh < 0) { hh = -hh; yy = yy - hh; }
1059 sa = wxConvertWXangleToMACangle(sa);
1060 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1061 CGContextRef ctx = mctx->GetNativeContext() ;
1062 AddEllipticArcToPath( ctx , CGPointMake( xx + ww / 2 , yy + hh / 2 ) , ww / 2 , hh / 2 , sa , angle) ;
1063 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1064 }
1065
1066 void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
1067 {
1068 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1069 DoDrawLine( x , y , x + 1 , y + 1 ) ;
1070 }
1071
1072 void wxDC::DoDrawLines(int n, wxPoint points[],
1073 wxCoord xoffset, wxCoord yoffset)
1074 {
1075 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1076
1077 wxCoord x1, x2 , y1 , y2 ;
1078 x1 = XLOG2DEVMAC(points[0].x + xoffset);
1079 y1 = YLOG2DEVMAC(points[0].y + yoffset);
1080 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1081 path->MoveToPoint( x1 , y1 ) ;
1082 for (int i = 1; i < n; i++)
1083 {
1084 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1085 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1086
1087 path->AddLineToPoint( x2 , y2 ) ;
1088 }
1089 m_graphicContext->StrokePath( path ) ;
1090 delete path ;
1091 }
1092
1093 void wxDC::DoDrawPolygon(int n, wxPoint points[],
1094 wxCoord xoffset, wxCoord yoffset,
1095 int fillStyle )
1096 {
1097 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1098 wxCoord x1, x2 , y1 , y2 ;
1099 if ( n== 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
1100 return ;
1101
1102 x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1103 y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
1104
1105 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1106 path->MoveToPoint( x1 , y1 ) ;
1107 for (int i = 1; i < n; i++)
1108 {
1109 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1110 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1111
1112 path->AddLineToPoint( x2 , y2 ) ;
1113 }
1114 if ( x1 != x2 || y1 != y2 )
1115 {
1116 path->AddLineToPoint( x1,y1 ) ;
1117 }
1118 path->CloseSubpath() ;
1119 m_graphicContext->DrawPath( path , fillStyle ) ;
1120 delete path ;
1121 }
1122
1123 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1124 {
1125 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1126 wxCoord xx = XLOG2DEVMAC(x);
1127 wxCoord yy = YLOG2DEVMAC(y);
1128 wxCoord ww = m_signX * XLOG2DEVREL(width);
1129 wxCoord hh = m_signY * YLOG2DEVREL(height);
1130 // CMB: draw nothing if transformed w or h is 0
1131 if (ww == 0 || hh == 0)
1132 return;
1133 // CMB: handle -ve width and/or height
1134 if (ww < 0)
1135 {
1136 ww = -ww;
1137 xx = xx - ww;
1138 }
1139 if (hh < 0)
1140 {
1141 hh = -hh;
1142 yy = yy - hh;
1143 }
1144 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1145 path->AddRectangle(xx ,yy , ww , hh ) ;
1146 m_graphicContext->DrawPath( path ) ;
1147 delete path ;
1148 }
1149
1150 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1151 wxCoord width, wxCoord height,
1152 double radius)
1153 {
1154 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1155 if (radius < 0.0)
1156 radius = - radius * ((width < height) ? width : height);
1157 wxCoord xx = XLOG2DEVMAC(x);
1158 wxCoord yy = YLOG2DEVMAC(y);
1159 wxCoord ww = m_signX * XLOG2DEVREL(width);
1160 wxCoord hh = m_signY * YLOG2DEVREL(height);
1161 // CMB: draw nothing if transformed w or h is 0
1162 if (ww == 0 || hh == 0)
1163 return;
1164 // CMB: handle -ve width and/or height
1165 if (ww < 0)
1166 {
1167 ww = -ww;
1168 xx = xx - ww;
1169 }
1170 if (hh < 0)
1171 {
1172 hh = -hh;
1173 yy = yy - hh;
1174 }
1175 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1176 CGContextRef ctx = mctx->GetNativeContext() ;
1177 AddRoundedRectToPath( ctx , CGRectMake( xx , yy , ww , hh ) , 16 ,16 ) ;
1178 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1179 }
1180
1181 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1182 {
1183 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1184 wxCoord xx = XLOG2DEVMAC(x);
1185 wxCoord yy = YLOG2DEVMAC(y);
1186 wxCoord ww = m_signX * XLOG2DEVREL(width);
1187 wxCoord hh = m_signY * YLOG2DEVREL(height);
1188 // CMB: draw nothing if transformed w or h is 0
1189 if (ww == 0 || hh == 0)
1190 return;
1191 // CMB: handle -ve width and/or height
1192 if (ww < 0)
1193 {
1194 ww = -ww;
1195 xx = xx - ww;
1196 }
1197 if (hh < 0)
1198 {
1199 hh = -hh;
1200 yy = yy - hh;
1201 }
1202
1203 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1204 CGContextRef ctx = mctx->GetNativeContext() ;
1205 if ( width == height )
1206 {
1207 CGContextBeginPath(ctx);
1208 CGContextAddArc(ctx ,
1209 xx + ww / 2,
1210 yy + hh / 2,
1211 ww / 2,
1212 0,
1213 2 * M_PI,
1214 0 ) ;
1215 CGContextClosePath(ctx);
1216
1217 CGContextDrawPath( ctx , kCGPathFillStroke ) ;
1218 }
1219 else
1220 {
1221 AddEllipticArcToPath( ctx , CGPointMake( xx + ww / 2 , yy + hh / 2 ) , ww / 2 , hh / 2 , 0 , 360) ;
1222 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1223 }
1224 }
1225
1226 bool wxDC::CanDrawBitmap(void) const
1227 {
1228 return true ;
1229 }
1230
1231 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1232 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1233 wxCoord xsrcMask, wxCoord ysrcMask )
1234 {
1235 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1236 wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1237 if ( logical_func == wxNO_OP )
1238 return TRUE ;
1239 if (xsrcMask == -1 && ysrcMask == -1)
1240 {
1241 xsrcMask = xsrc; ysrcMask = ysrc;
1242 }
1243
1244 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
1245 if ( memdc && logical_func == wxCOPY )
1246 {
1247 wxBitmap blit = memdc->GetSelectedObject() ;
1248 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
1249
1250 wxCoord xxdest = XLOG2DEVMAC(xdest);
1251 wxCoord yydest = YLOG2DEVMAC(ydest);
1252 wxCoord ww = XLOG2DEVREL(width);
1253 wxCoord hh = YLOG2DEVREL(height);
1254
1255 wxCoord bmpwidth = blit.GetWidth();
1256 wxCoord bmpheight = blit.GetHeight();
1257
1258 if ( xsrc != 0 || ysrc != 0 || bmpwidth != width || bmpheight != height )
1259 {
1260 wxRect subrect( xsrc, ysrc, width , height ) ;
1261 blit = blit.GetSubBitmap( subrect ) ;
1262 }
1263
1264 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1265 CGImageRef image = (CGImageRef)( blit.CGImageCreate() ) ;
1266 HIRect r = CGRectMake( xxdest , yydest , ww , hh ) ;
1267 HIViewDrawCGImage( cg , &r , image ) ;
1268 CGImageRelease( image ) ;
1269
1270 }
1271 else
1272 {
1273 return FALSE ; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1274 }
1275 return TRUE;
1276 }
1277
1278 void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1279 double angle)
1280 {
1281 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1282
1283 if ( str.Length() == 0 )
1284 return ;
1285
1286 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1287
1288 OSStatus status = noErr ;
1289 ATSUTextLayout atsuLayout ;
1290 UniCharCount chars = str.Length() ;
1291 UniChar* ubuf = NULL ;
1292 #if SIZEOF_WCHAR_T == 4
1293 wxMBConvUTF16BE converter ;
1294 #if wxUSE_UNICODE
1295 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1296 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1297 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1298 #else
1299 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1300 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1301 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1302 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1303 #endif
1304 chars = unicharlen / 2 ;
1305 #else
1306 #if wxUSE_UNICODE
1307 ubuf = (UniChar*) str.wc_str() ;
1308 #else
1309 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1310 chars = wxWcslen( wchar.data() ) ;
1311 ubuf = (UniChar*) wchar.data() ;
1312 #endif
1313 #endif
1314
1315 int drawX = XLOG2DEVMAC(x) ;
1316 int drawY = YLOG2DEVMAC(y) ;
1317
1318 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1319 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1320
1321 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1322 int iAngle = int( angle );
1323
1324
1325
1326 if ( abs(iAngle) > 0 )
1327 {
1328 Fixed atsuAngle = IntToFixed( iAngle ) ;
1329 ATSUAttributeTag atsuTags[] =
1330 {
1331 kATSULineRotationTag ,
1332 } ;
1333 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1334 {
1335 sizeof( Fixed ) ,
1336 } ;
1337 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1338 {
1339 &atsuAngle ,
1340 } ;
1341 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1342 atsuTags, atsuSizes, atsuValues ) ;
1343 }
1344 {
1345 CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1346 ATSUAttributeTag atsuTags[] =
1347 {
1348 kATSUCGContextTag ,
1349 } ;
1350 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1351 {
1352 sizeof( CGContextRef ) ,
1353 } ;
1354 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1355 {
1356 &cgContext ,
1357 } ;
1358 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1359 atsuTags, atsuSizes, atsuValues ) ;
1360 }
1361
1362 ATSUTextMeasurement textBefore ;
1363 ATSUTextMeasurement textAfter ;
1364 ATSUTextMeasurement ascent ;
1365 ATSUTextMeasurement descent ;
1366
1367 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1368 &textBefore , &textAfter, &ascent , &descent );
1369 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1370
1371 Rect rect ;
1372
1373 if ( m_backgroundMode == wxSOLID )
1374 {
1375 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1376 path->MoveToPoint(
1377 drawX ,
1378 drawY ) ;
1379 path->AddLineToPoint(
1380 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent)) ,
1381 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent)) ) ;
1382 path->AddLineToPoint(
1383 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1384 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1385 path->AddLineToPoint(
1386 (int) (drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1387 (int) (drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1388
1389 m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
1390 delete path ;
1391 }
1392
1393 drawX += (int)(sin(angle/RAD2DEG) * FixedToInt(ascent));
1394 drawY += (int)(cos(angle/RAD2DEG) * FixedToInt(ascent));
1395
1396 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1397 IntToFixed(drawX) , IntToFixed(drawY) , &rect );
1398 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1399
1400 CGContextSaveGState(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext());
1401 CGContextTranslateCTM(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext(), drawX, drawY);
1402 CGContextScaleCTM(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext(), 1, -1);
1403 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1404 IntToFixed(0) , IntToFixed(0) );
1405 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1406 CGContextRestoreGState( dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ) ;
1407
1408 CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
1409 CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
1410
1411 ::ATSUDisposeTextLayout(atsuLayout);
1412 #if SIZEOF_WCHAR_T == 4
1413 free( ubuf ) ;
1414 #endif
1415 }
1416
1417 void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
1418 {
1419 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1420 DoDrawRotatedText( strtext , x , y , 0.0 ) ;
1421 }
1422
1423 bool wxDC::CanGetTextExtent() const
1424 {
1425 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1426 return true ;
1427 }
1428
1429 void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1430 wxCoord *descent, wxCoord *externalLeading ,
1431 wxFont *theFont ) const
1432 {
1433 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1434 wxFont formerFont = m_font ;
1435 if ( theFont )
1436 {
1437 // work around the constness
1438 *((wxFont*)(&m_font)) = *theFont ;
1439 MacInstallFont() ;
1440 }
1441
1442 if ( str.Length() == 0 )
1443 return ;
1444
1445 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1446
1447 OSStatus status = noErr ;
1448 ATSUTextLayout atsuLayout ;
1449 UniCharCount chars = str.Length() ;
1450 UniChar* ubuf = NULL ;
1451 #if SIZEOF_WCHAR_T == 4
1452 wxMBConvUTF16BE converter ;
1453 #if wxUSE_UNICODE
1454 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1455 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1456 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1457 #else
1458 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1459 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1460 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1461 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1462 #endif
1463 chars = unicharlen / 2 ;
1464 #else
1465 #if wxUSE_UNICODE
1466 ubuf = (UniChar*) str.wc_str() ;
1467 #else
1468 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1469 chars = wxWcslen( wchar.data() ) ;
1470 ubuf = (UniChar*) wchar.data() ;
1471 #endif
1472 #endif
1473
1474
1475 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1476 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1477
1478 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1479
1480 ATSUTextMeasurement textBefore ;
1481 ATSUTextMeasurement textAfter ;
1482 ATSUTextMeasurement textAscent ;
1483 ATSUTextMeasurement textDescent ;
1484
1485 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1486 &textBefore , &textAfter, &textAscent , &textDescent );
1487
1488 if ( height )
1489 *height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
1490 if ( descent )
1491 *descent =YDEV2LOGREL( FixedToInt(textDescent) );
1492 if ( externalLeading )
1493 *externalLeading = 0 ;
1494 if ( width )
1495 *width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
1496
1497 ::ATSUDisposeTextLayout(atsuLayout);
1498 #if SIZEOF_WCHAR_T == 4
1499 free( ubuf ) ;
1500 #endif
1501 if ( theFont )
1502 {
1503 // work around the constness
1504 *((wxFont*)(&m_font)) = formerFont ;
1505 MacInstallFont() ;
1506 }
1507 }
1508
1509
1510 bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1511 {
1512 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1513
1514 widths.Empty();
1515 widths.Add(0, text.Length());
1516
1517 if (text.Length() == 0)
1518 return false;
1519
1520 ATSUTextLayout atsuLayout ;
1521 UniCharCount chars = text.Length() ;
1522 UniChar* ubuf = NULL ;
1523 #if SIZEOF_WCHAR_T == 4
1524 wxMBConvUTF16BE converter ;
1525 #if wxUSE_UNICODE
1526 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
1527 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1528 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
1529 #else
1530 const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1531 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1532 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1533 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1534 #endif
1535 chars = unicharlen / 2 ;
1536 #else
1537 #if wxUSE_UNICODE
1538 ubuf = (UniChar*) text.wc_str() ;
1539 #else
1540 wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1541 chars = wxWcslen( wchar.data() ) ;
1542 ubuf = (UniChar*) wchar.data() ;
1543 #endif
1544 #endif
1545
1546 OSStatus status;
1547 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1548 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1549
1550 for ( int pos = 0; pos < chars; pos ++ ) {
1551 unsigned long actualNumberOfBounds = 0;
1552 ATSTrapezoid glyphBounds;
1553
1554 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1555 OSStatus result;
1556 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1557 if (result != noErr || actualNumberOfBounds != 1 )
1558 {
1559 return false;
1560 }
1561
1562 widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
1563 //unsigned char uch = s[i];
1564
1565 }
1566 ::ATSUDisposeTextLayout(atsuLayout);
1567 return true;
1568 }
1569
1570 wxCoord wxDC::GetCharWidth(void) const
1571 {
1572 wxCoord width ;
1573 DoGetTextExtent(wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
1574 return width ;
1575 }
1576
1577 wxCoord wxDC::GetCharHeight(void) const
1578 {
1579 wxCoord height ;
1580 DoGetTextExtent(wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
1581 return height ;
1582 }
1583
1584 void wxDC::Clear(void)
1585 {
1586 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1587
1588 if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
1589 {
1590 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1591 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1592 switch( m_backgroundBrush.MacGetBrushKind() )
1593 {
1594 case kwxMacBrushTheme :
1595 {
1596 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1597 if ( HIThemeSetFill != 0 )
1598 {
1599 HIThemeSetFill( m_backgroundBrush.MacGetTheme() , cg ) ;
1600 CGContextFillRect(cg, rect);
1601
1602 }
1603 else
1604 #endif
1605 {
1606 RGBColor color;
1607 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme() , 32, true, &color );
1608 CGContextSetRGBFillColor( cg , (float) color.red / 65536,
1609 (float) color.green / 65536, (float) color.blue / 65536, 1 );
1610 CGContextFillRect( cg, rect );
1611 }
1612 // reset to normal value
1613 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1614 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1615 }
1616 break ;
1617 case kwxMacBrushThemeBackground :
1618 {
1619 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1620 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1621 if ( HIThemeDrawBackground != 0 )
1622 {
1623 HIThemeBackgroundDrawInfo drawInfo ;
1624 drawInfo.version = 0 ;
1625 drawInfo.state = kThemeStateActive ;
1626 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
1627 if ( drawInfo.kind == kThemeBackgroundMetal )
1628 HIThemeDrawBackground( &rect , &drawInfo, cg ,
1629 kHIThemeOrientationNormal) ;
1630 HIThemeApplyBackground( &rect , &drawInfo, cg ,
1631 kHIThemeOrientationNormal) ;
1632 }
1633 else
1634 #endif
1635 {
1636 }
1637 }
1638 break ;
1639 case kwxMacBrushColour :
1640 {
1641 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
1642 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1643 CGContextFillRect(cg, rect);
1644
1645 // reset to normal value
1646 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1647 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1648 }
1649 break ;
1650 }
1651 }
1652 }
1653
1654 void wxDC::MacInstallFont() const
1655 {
1656 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1657
1658 if( m_macATSUIStyle )
1659 {
1660 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1661 m_macATSUIStyle = NULL ;
1662 }
1663
1664 OSStatus status = noErr ;
1665 status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
1666 wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
1667
1668 Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
1669 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel() ) ;
1670 ATSUAttributeTag atsuTags[] =
1671 {
1672 kATSUSizeTag ,
1673 kATSUColorTag ,
1674 } ;
1675 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1676 {
1677 sizeof( Fixed ) ,
1678 sizeof( RGBColor ) ,
1679 } ;
1680 // Boolean kTrue = true ;
1681 // Boolean kFalse = false ;
1682
1683 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1684 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1685 {
1686 &atsuSize ,
1687 &atsuColor ,
1688 } ;
1689 status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
1690 atsuTags, atsuSizes, atsuValues);
1691
1692 wxASSERT_MSG( status == noErr , wxT("couldn't Modify ATSU style") ) ;
1693 }
1694
1695 // ---------------------------------------------------------------------------
1696 // coordinates transformations
1697 // ---------------------------------------------------------------------------
1698
1699 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1700 {
1701 return ((wxDC *)this)->XDEV2LOG(x);
1702 }
1703
1704 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1705 {
1706 return ((wxDC *)this)->YDEV2LOG(y);
1707 }
1708
1709 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1710 {
1711 return ((wxDC *)this)->XDEV2LOGREL(x);
1712 }
1713
1714 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1715 {
1716 return ((wxDC *)this)->YDEV2LOGREL(y);
1717 }
1718
1719 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1720 {
1721 return ((wxDC *)this)->XLOG2DEV(x);
1722 }
1723
1724 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1725 {
1726 return ((wxDC *)this)->YLOG2DEV(y);
1727 }
1728
1729 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1730 {
1731 return ((wxDC *)this)->XLOG2DEVREL(x);
1732 }
1733
1734 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1735 {
1736 return ((wxDC *)this)->YLOG2DEVREL(y);
1737 }
1738
1739 #endif // wxMAC_USE_CORE_GRAPHICS
1740