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