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