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