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