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