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