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