]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/dccg.cpp
255a315b60732d6bf9af24d3c81915db1d76b7a3
[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 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
910 wxMacPortSaver helper((CGrafPtr)m_macPort) ;
911 RGBColor colour;
912 GetCPixel(
913 XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x,
914 YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
915 // Convert from Mac colour to wx
916 col->Set( colour.red >> 8,
917 colour.green >> 8,
918 colour.blue >> 8);
919 return true ;
920 }
921
922 void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
923 {
924 wxCHECK_RET(Ok(), wxT("Invalid DC"));
925
926 wxCoord xx1 = XLOG2DEVMAC(x1) ;
927 wxCoord yy1 = YLOG2DEVMAC(y1) ;
928 wxCoord xx2 = XLOG2DEVMAC(x2) ;
929 wxCoord yy2 = YLOG2DEVMAC(y2) ;
930
931 wxGraphicPath* path = m_graphicContext->CreatePath() ;
932 path->MoveToPoint( xx1 , yy1 ) ;
933 path->AddLineToPoint( xx2 , yy2 ) ;
934 path->CloseSubpath() ;
935 m_graphicContext->StrokePath( path ) ;
936 delete path ;
937
938 CalcBoundingBox(x1, y1);
939 CalcBoundingBox(x2, y2);
940 }
941
942 void wxDC::DoCrossHair( wxCoord x, wxCoord y )
943 {
944 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
945
946
947 int w = 0;
948 int h = 0;
949 GetSize( &w, &h );
950 wxCoord xx = XLOG2DEVMAC(x);
951 wxCoord yy = YLOG2DEVMAC(y);
952
953 wxGraphicPath* path = m_graphicContext->CreatePath() ;
954 path->MoveToPoint( XLOG2DEVMAC(0), yy ) ;
955 path->AddLineToPoint( XLOG2DEVMAC(w), yy ) ;
956 path->CloseSubpath() ;
957 path->MoveToPoint( xx, YLOG2DEVMAC(0) ) ;
958 path->AddLineToPoint( xx, YLOG2DEVMAC(h) ) ;
959 path->CloseSubpath() ;
960 m_graphicContext->StrokePath( path ) ;
961 delete path ;
962
963 CalcBoundingBox(x, y);
964 CalcBoundingBox(x+w, y+h);
965 }
966
967 /*
968 * To draw arcs properly the angles need to be converted from the WX style:
969 * Angles start on the +ve X axis and go anti-clockwise (As you would draw on
970 * a normal axis on paper).
971 * TO
972 * the Mac style:
973 * Angles start on the +ve y axis and go clockwise.
974 */
975
976 static double wxConvertWXangleToMACangle(double angle)
977 {
978 double newAngle = 90 - angle ;
979 if ( newAngle < 0 )
980 newAngle += 360 ;
981 return newAngle ;
982 }
983
984 void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
985 wxCoord x2, wxCoord y2,
986 wxCoord xc, wxCoord yc )
987 {
988 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
989 wxCoord xx1 = XLOG2DEVMAC(x1);
990 wxCoord yy1 = YLOG2DEVMAC(y1);
991 wxCoord xx2 = XLOG2DEVMAC(x2);
992 wxCoord yy2 = YLOG2DEVMAC(y2);
993 wxCoord xxc = XLOG2DEVMAC(xc);
994 wxCoord yyc = YLOG2DEVMAC(yc);
995 double dx = xx1 - xxc;
996 double dy = yy1 - yyc;
997 double radius = sqrt((double)(dx*dx+dy*dy));
998 wxCoord rad = (wxCoord)radius;
999 double radius1, radius2;
1000 if (xx1 == xx2 && yy1 == yy2)
1001 {
1002 radius1 = 0.0;
1003 radius2 = 360.0;
1004 }
1005 else if (radius == 0.0)
1006 {
1007 radius1 = radius2 = 0.0;
1008 }
1009 else
1010 {
1011 radius1 = (xx1 - xxc == 0) ?
1012 (yy1 - yyc < 0) ? 90.0 : -90.0 :
1013 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
1014 radius2 = (xx2 - xxc == 0) ?
1015 (yy2 - yyc < 0) ? 90.0 : -90.0 :
1016 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
1017 }
1018 wxCoord alpha2 = wxCoord(radius2 - radius1);
1019 wxCoord alpha1 = wxCoord(wxConvertWXangleToMACangle(radius1));
1020 if( (xx1 > xx2) || (yy1 > yy2) ) {
1021 alpha2 *= -1;
1022 }
1023 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1024 CGContextRef ctx = mctx->GetNativeContext() ;
1025 AddEllipticArcToPath( ctx , CGPointMake( xxc , yyc ) , rad , rad , alpha1 , alpha2 ) ;
1026 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1027 }
1028
1029 void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1030 double sa, double ea )
1031 {
1032 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
1033
1034 double angle = sa - ea; // Order important Mac in opposite direction to wx
1035 // we have to make sure that the filling is always counter-clockwise
1036 if ( angle > 0 )
1037 angle -= 360 ;
1038 wxCoord xx = XLOG2DEVMAC(x);
1039 wxCoord yy = YLOG2DEVMAC(y);
1040 wxCoord ww = m_signX * XLOG2DEVREL(w);
1041 wxCoord hh = m_signY * YLOG2DEVREL(h);
1042 // handle -ve width and/or height
1043 if (ww < 0) { ww = -ww; xx = xx - ww; }
1044 if (hh < 0) { hh = -hh; yy = yy - hh; }
1045 sa = wxConvertWXangleToMACangle(sa);
1046 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1047 CGContextRef ctx = mctx->GetNativeContext() ;
1048 AddEllipticArcToPath( ctx , CGPointMake( xx + ww / 2 , yy + hh / 2 ) , ww / 2 , hh / 2 , sa , angle) ;
1049 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1050 }
1051
1052 void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
1053 {
1054 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1055 DoDrawLine( x , y , x + 1 , y + 1 ) ;
1056 }
1057
1058 void wxDC::DoDrawLines(int n, wxPoint points[],
1059 wxCoord xoffset, wxCoord yoffset)
1060 {
1061 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1062
1063 wxCoord x1, x2 , y1 , y2 ;
1064 x1 = XLOG2DEVMAC(points[0].x + xoffset);
1065 y1 = YLOG2DEVMAC(points[0].y + yoffset);
1066 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1067 path->MoveToPoint( x1 , y1 ) ;
1068 for (int i = 1; i < n; i++)
1069 {
1070 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1071 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1072
1073 path->AddLineToPoint( x2 , y2 ) ;
1074 }
1075 m_graphicContext->StrokePath( path ) ;
1076 delete path ;
1077 }
1078
1079 void wxDC::DoDrawPolygon(int n, wxPoint points[],
1080 wxCoord xoffset, wxCoord yoffset,
1081 int fillStyle )
1082 {
1083 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1084 wxCoord x1, x2 , y1 , y2 ;
1085 if ( n== 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
1086 return ;
1087
1088 x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1089 y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
1090
1091 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1092 path->MoveToPoint( x1 , y1 ) ;
1093 for (int i = 1; i < n; i++)
1094 {
1095 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1096 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1097
1098 path->AddLineToPoint( x2 , y2 ) ;
1099 }
1100 if ( x1 != x2 || y1 != y2 )
1101 {
1102 path->AddLineToPoint( x1,y1 ) ;
1103 }
1104 path->CloseSubpath() ;
1105 m_graphicContext->DrawPath( path , fillStyle ) ;
1106 delete path ;
1107 }
1108
1109 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1110 {
1111 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1112 wxCoord xx = XLOG2DEVMAC(x);
1113 wxCoord yy = YLOG2DEVMAC(y);
1114 wxCoord ww = m_signX * XLOG2DEVREL(width);
1115 wxCoord hh = m_signY * YLOG2DEVREL(height);
1116 // CMB: draw nothing if transformed w or h is 0
1117 if (ww == 0 || hh == 0)
1118 return;
1119 // CMB: handle -ve width and/or height
1120 if (ww < 0)
1121 {
1122 ww = -ww;
1123 xx = xx - ww;
1124 }
1125 if (hh < 0)
1126 {
1127 hh = -hh;
1128 yy = yy - hh;
1129 }
1130 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1131 path->AddRectangle(xx ,yy , ww , hh ) ;
1132 m_graphicContext->DrawPath( path ) ;
1133 delete path ;
1134 }
1135
1136 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1137 wxCoord width, wxCoord height,
1138 double radius)
1139 {
1140 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1141 if (radius < 0.0)
1142 radius = - radius * ((width < height) ? width : height);
1143 wxCoord xx = XLOG2DEVMAC(x);
1144 wxCoord yy = YLOG2DEVMAC(y);
1145 wxCoord ww = m_signX * XLOG2DEVREL(width);
1146 wxCoord hh = m_signY * YLOG2DEVREL(height);
1147 // CMB: draw nothing if transformed w or h is 0
1148 if (ww == 0 || hh == 0)
1149 return;
1150 // CMB: handle -ve width and/or height
1151 if (ww < 0)
1152 {
1153 ww = -ww;
1154 xx = xx - ww;
1155 }
1156 if (hh < 0)
1157 {
1158 hh = -hh;
1159 yy = yy - hh;
1160 }
1161 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1162 CGContextRef ctx = mctx->GetNativeContext() ;
1163 AddRoundedRectToPath( ctx , CGRectMake( xx , yy , ww , hh ) , 16 ,16 ) ;
1164 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1165 }
1166
1167 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1168 {
1169 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1170 wxCoord xx = XLOG2DEVMAC(x);
1171 wxCoord yy = YLOG2DEVMAC(y);
1172 wxCoord ww = m_signX * XLOG2DEVREL(width);
1173 wxCoord hh = m_signY * YLOG2DEVREL(height);
1174 // CMB: draw nothing if transformed w or h is 0
1175 if (ww == 0 || hh == 0)
1176 return;
1177 // CMB: handle -ve width and/or height
1178 if (ww < 0)
1179 {
1180 ww = -ww;
1181 xx = xx - ww;
1182 }
1183 if (hh < 0)
1184 {
1185 hh = -hh;
1186 yy = yy - hh;
1187 }
1188
1189 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1190 CGContextRef ctx = mctx->GetNativeContext() ;
1191 if ( width == height )
1192 {
1193 CGContextBeginPath(ctx);
1194 CGContextAddArc(ctx ,
1195 xx + ww / 2,
1196 yy + hh / 2,
1197 ww / 2,
1198 0,
1199 2 * M_PI,
1200 0 ) ;
1201 CGContextClosePath(ctx);
1202
1203 CGContextDrawPath( ctx , kCGPathFillStroke ) ;
1204 }
1205 else
1206 {
1207 AddEllipticArcToPath( ctx , CGPointMake( xx + ww / 2 , yy + hh / 2 ) , ww / 2 , hh / 2 , 0 , 360) ;
1208 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
1209 }
1210 }
1211
1212 bool wxDC::CanDrawBitmap(void) const
1213 {
1214 return true ;
1215 }
1216
1217 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1218 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1219 wxCoord xsrcMask, wxCoord ysrcMask )
1220 {
1221 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1222 wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1223 if ( logical_func == wxNO_OP )
1224 return TRUE ;
1225 if (xsrcMask == -1 && ysrcMask == -1)
1226 {
1227 xsrcMask = xsrc; ysrcMask = ysrc;
1228 }
1229
1230 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
1231 if ( memdc )
1232 {
1233 wxBitmap blit = memdc->GetSelectedObject() ;
1234 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
1235
1236 wxCoord xxdest = XLOG2DEVMAC(xdest);
1237 wxCoord yydest = YLOG2DEVMAC(ydest);
1238 wxCoord ww = XLOG2DEVREL(width);
1239 wxCoord hh = YLOG2DEVREL(height);
1240
1241 wxCoord bmpwidth = blit.GetWidth();
1242 wxCoord bmpheight = blit.GetHeight();
1243
1244 if ( xsrc != 0 || ysrc != 0 || bmpwidth != width || bmpheight != height )
1245 {
1246 wxRect subrect( xsrc, ysrc, width , height ) ;
1247 blit = blit.GetSubBitmap( subrect ) ;
1248 }
1249
1250 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1251 CGImageRef image = (CGImageRef)( blit.CGImageCreate() ) ;
1252 HIRect r = CGRectMake( xxdest , yydest , ww , hh ) ;
1253 HIViewDrawCGImage( cg , &r , image ) ;
1254 CGImageRelease( image ) ;
1255
1256 }
1257 else
1258 {
1259 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
1260 }
1261 return TRUE;
1262 }
1263
1264 void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1265 double angle)
1266 {
1267 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1268
1269 if ( str.Length() == 0 )
1270 return ;
1271
1272 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1273
1274 OSStatus status = noErr ;
1275 ATSUTextLayout atsuLayout ;
1276 UniCharCount chars = str.Length() ;
1277 UniChar* ubuf = NULL ;
1278 #if SIZEOF_WCHAR_T == 4
1279 wxMBConvUTF16BE converter ;
1280 #if wxUSE_UNICODE
1281 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1282 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1283 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1284 #else
1285 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1286 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1287 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1288 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1289 #endif
1290 chars = unicharlen / 2 ;
1291 #else
1292 #if wxUSE_UNICODE
1293 ubuf = (UniChar*) str.wc_str() ;
1294 #else
1295 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1296 chars = wxWcslen( wchar.data() ) ;
1297 ubuf = (UniChar*) wchar.data() ;
1298 #endif
1299 #endif
1300
1301 int drawX = XLOG2DEVMAC(x) ;
1302 int drawY = YLOG2DEVMAC(y) ;
1303
1304 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1305 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1306
1307 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1308 int iAngle = int( angle );
1309
1310
1311
1312 if ( abs(iAngle) > 0 )
1313 {
1314 Fixed atsuAngle = IntToFixed( iAngle ) ;
1315 ATSUAttributeTag atsuTags[] =
1316 {
1317 kATSULineRotationTag ,
1318 } ;
1319 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1320 {
1321 sizeof( Fixed ) ,
1322 } ;
1323 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1324 {
1325 &atsuAngle ,
1326 } ;
1327 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1328 atsuTags, atsuSizes, atsuValues ) ;
1329 }
1330 {
1331 CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1332 ATSUAttributeTag atsuTags[] =
1333 {
1334 kATSUCGContextTag ,
1335 } ;
1336 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1337 {
1338 sizeof( CGContextRef ) ,
1339 } ;
1340 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1341 {
1342 &cgContext ,
1343 } ;
1344 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1345 atsuTags, atsuSizes, atsuValues ) ;
1346 }
1347
1348 ATSUTextMeasurement textBefore ;
1349 ATSUTextMeasurement textAfter ;
1350 ATSUTextMeasurement ascent ;
1351 ATSUTextMeasurement descent ;
1352
1353 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1354 &textBefore , &textAfter, &ascent , &descent );
1355 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1356
1357 Rect rect ;
1358
1359 if ( m_backgroundMode == wxSOLID )
1360 {
1361 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1362 path->MoveToPoint(
1363 drawX ,
1364 drawY ) ;
1365 path->AddLineToPoint(
1366 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent)) ,
1367 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent)) ) ;
1368 path->AddLineToPoint(
1369 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1370 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1371 path->AddLineToPoint(
1372 (int) (drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1373 (int) (drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
1374
1375 m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
1376 delete path ;
1377 }
1378
1379 drawX += (int)(sin(angle/RAD2DEG) * FixedToInt(ascent));
1380 drawY += (int)(cos(angle/RAD2DEG) * FixedToInt(ascent));
1381
1382 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1383 IntToFixed(drawX) , IntToFixed(drawY) , &rect );
1384 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1385
1386 CGContextSaveGState(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext());
1387 CGContextTranslateCTM(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext(), drawX, drawY);
1388 CGContextScaleCTM(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext(), 1, -1);
1389 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1390 IntToFixed(0) , IntToFixed(0) );
1391 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1392 CGContextRestoreGState( dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ) ;
1393
1394 CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
1395 CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
1396
1397 ::ATSUDisposeTextLayout(atsuLayout);
1398 #if SIZEOF_WCHAR_T == 4
1399 free( ubuf ) ;
1400 #endif
1401 }
1402
1403 void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
1404 {
1405 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1406 DoDrawRotatedText( strtext , x , y , 0.0 ) ;
1407 }
1408
1409 bool wxDC::CanGetTextExtent() const
1410 {
1411 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1412 return true ;
1413 }
1414
1415 void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1416 wxCoord *descent, wxCoord *externalLeading ,
1417 wxFont *theFont ) const
1418 {
1419 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1420 wxFont formerFont = m_font ;
1421 if ( theFont )
1422 {
1423 // work around the constness
1424 *((wxFont*)(&m_font)) = *theFont ;
1425 MacInstallFont() ;
1426 }
1427
1428 if ( str.Length() == 0 )
1429 return ;
1430
1431 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1432
1433 OSStatus status = noErr ;
1434 ATSUTextLayout atsuLayout ;
1435 UniCharCount chars = str.Length() ;
1436 UniChar* ubuf = NULL ;
1437 #if SIZEOF_WCHAR_T == 4
1438 wxMBConvUTF16BE converter ;
1439 #if wxUSE_UNICODE
1440 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1441 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1442 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1443 #else
1444 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1445 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1446 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1447 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1448 #endif
1449 chars = unicharlen / 2 ;
1450 #else
1451 #if wxUSE_UNICODE
1452 ubuf = (UniChar*) str.wc_str() ;
1453 #else
1454 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1455 chars = wxWcslen( wchar.data() ) ;
1456 ubuf = (UniChar*) wchar.data() ;
1457 #endif
1458 #endif
1459
1460
1461 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1462 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1463
1464 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1465
1466 ATSUTextMeasurement textBefore ;
1467 ATSUTextMeasurement textAfter ;
1468 ATSUTextMeasurement textAscent ;
1469 ATSUTextMeasurement textDescent ;
1470
1471 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1472 &textBefore , &textAfter, &textAscent , &textDescent );
1473
1474 if ( height )
1475 *height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
1476 if ( descent )
1477 *descent =YDEV2LOGREL( FixedToInt(textDescent) );
1478 if ( externalLeading )
1479 *externalLeading = 0 ;
1480 if ( width )
1481 *width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
1482
1483 ::ATSUDisposeTextLayout(atsuLayout);
1484 #if SIZEOF_WCHAR_T == 4
1485 free( ubuf ) ;
1486 #endif
1487 if ( theFont )
1488 {
1489 // work around the constness
1490 *((wxFont*)(&m_font)) = formerFont ;
1491 MacInstallFont() ;
1492 }
1493 }
1494
1495
1496 bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1497 {
1498 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1499
1500 widths.Empty();
1501 widths.Add(0, text.Length());
1502
1503 if (text.Length() == 0)
1504 return false;
1505
1506 ATSUTextLayout atsuLayout ;
1507 UniCharCount chars = text.Length() ;
1508 UniChar* ubuf = NULL ;
1509 #if SIZEOF_WCHAR_T == 4
1510 wxMBConvUTF16BE converter ;
1511 #if wxUSE_UNICODE
1512 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
1513 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1514 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
1515 #else
1516 const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1517 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1518 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1519 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1520 #endif
1521 chars = unicharlen / 2 ;
1522 #else
1523 #if wxUSE_UNICODE
1524 ubuf = (UniChar*) text.wc_str() ;
1525 #else
1526 wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1527 chars = wxWcslen( wchar.data() ) ;
1528 ubuf = (UniChar*) wchar.data() ;
1529 #endif
1530 #endif
1531
1532 OSStatus status;
1533 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1534 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1535
1536 for ( int pos = 0; pos < chars; pos ++ ) {
1537 unsigned long actualNumberOfBounds = 0;
1538 ATSTrapezoid glyphBounds;
1539
1540 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1541 OSStatus result;
1542 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1543 if (result != noErr || actualNumberOfBounds != 1 )
1544 {
1545 return false;
1546 }
1547
1548 widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
1549 //unsigned char uch = s[i];
1550
1551 }
1552 ::ATSUDisposeTextLayout(atsuLayout);
1553 return true;
1554 }
1555
1556 wxCoord wxDC::GetCharWidth(void) const
1557 {
1558 wxCoord width ;
1559 DoGetTextExtent(wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
1560 return width ;
1561 }
1562
1563 wxCoord wxDC::GetCharHeight(void) const
1564 {
1565 wxCoord height ;
1566 DoGetTextExtent(wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
1567 return height ;
1568 }
1569
1570 void wxDC::Clear(void)
1571 {
1572 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1573
1574 if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
1575 {
1576 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
1577 CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
1578 switch( m_backgroundBrush.MacGetBrushKind() )
1579 {
1580 case kwxMacBrushTheme :
1581 {
1582 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1583 if ( HIThemeSetFill != 0 )
1584 {
1585 HIThemeSetFill( m_backgroundBrush.MacGetTheme() , cg ) ;
1586 CGContextFillRect(cg, rect);
1587
1588 }
1589 else
1590 #endif
1591 {
1592 RGBColor color;
1593 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme() , 32, true, &color );
1594 CGContextSetRGBFillColor( cg , (float) color.red / 65536,
1595 (float) color.green / 65536, (float) color.blue / 65536, 1 );
1596 CGContextFillRect( cg, rect );
1597 }
1598 // reset to normal value
1599 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1600 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1601 }
1602 break ;
1603 case kwxMacBrushThemeBackground :
1604 {
1605 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
1606 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1607 if ( HIThemeDrawBackground != 0 )
1608 {
1609 HIThemeBackgroundDrawInfo drawInfo ;
1610 drawInfo.version = 0 ;
1611 drawInfo.state = kThemeStateActive ;
1612 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
1613 if ( drawInfo.kind == kThemeBackgroundMetal )
1614 HIThemeDrawBackground( &rect , &drawInfo, cg ,
1615 kHIThemeOrientationNormal) ;
1616 HIThemeApplyBackground( &rect , &drawInfo, cg ,
1617 kHIThemeOrientationNormal) ;
1618 }
1619 else
1620 #endif
1621 {
1622 }
1623 }
1624 break ;
1625 case kwxMacBrushColour :
1626 {
1627 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
1628 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1629 CGContextFillRect(cg, rect);
1630
1631 // reset to normal value
1632 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
1633 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
1634 }
1635 break ;
1636 }
1637 }
1638 }
1639
1640 void wxDC::MacInstallFont() const
1641 {
1642 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1643
1644 if( m_macATSUIStyle )
1645 {
1646 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
1647 m_macATSUIStyle = NULL ;
1648 }
1649
1650 OSStatus status = noErr ;
1651 status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
1652 wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
1653
1654 Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
1655 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel() ) ;
1656 ATSUAttributeTag atsuTags[] =
1657 {
1658 kATSUSizeTag ,
1659 kATSUColorTag ,
1660 } ;
1661 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1662 {
1663 sizeof( Fixed ) ,
1664 sizeof( RGBColor ) ,
1665 } ;
1666 // Boolean kTrue = true ;
1667 // Boolean kFalse = false ;
1668
1669 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
1670 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1671 {
1672 &atsuSize ,
1673 &atsuColor ,
1674 } ;
1675 status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
1676 atsuTags, atsuSizes, atsuValues);
1677
1678 wxASSERT_MSG( status == noErr , wxT("couldn't Modify ATSU style") ) ;
1679 }
1680
1681 // ---------------------------------------------------------------------------
1682 // coordinates transformations
1683 // ---------------------------------------------------------------------------
1684
1685 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1686 {
1687 return ((wxDC *)this)->XDEV2LOG(x);
1688 }
1689
1690 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1691 {
1692 return ((wxDC *)this)->YDEV2LOG(y);
1693 }
1694
1695 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1696 {
1697 return ((wxDC *)this)->XDEV2LOGREL(x);
1698 }
1699
1700 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1701 {
1702 return ((wxDC *)this)->YDEV2LOGREL(y);
1703 }
1704
1705 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1706 {
1707 return ((wxDC *)this)->XLOG2DEV(x);
1708 }
1709
1710 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1711 {
1712 return ((wxDC *)this)->YLOG2DEV(y);
1713 }
1714
1715 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1716 {
1717 return ((wxDC *)this)->XLOG2DEVREL(x);
1718 }
1719
1720 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1721 {
1722 return ((wxDC *)this)->YLOG2DEVREL(y);
1723 }
1724
1725 #endif // wxMAC_USE_CORE_GRAPHICS
1726