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