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