]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/dccg.cpp
Replaced SOCKLEN_T by WX_SOCKLEN_T to resolve conflict with AIX system headers.
[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"
613a24f7 37
613a24f7 38IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
613a24f7
SC
39
40//-----------------------------------------------------------------------------
41// constants
42//-----------------------------------------------------------------------------
43
44#if !defined( __DARWIN__ ) || defined(__MWERKS__)
45#ifndef M_PI
46const double M_PI = 3.14159265358979 ;
47#endif
48#endif
49const double RAD2DEG = 180.0 / M_PI;
50const short kEmulatedMode = -1 ;
51const short kUnsupportedMode = -2 ;
52
53extern TECObjectRef s_TECNativeCToUnicode ;
54
20b69855
SC
55// TODO Update
56// The text ctrl implementation still needs that for the non hiview implementation
613a24f7
SC
57
58wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
59 wxMacPortSaver( (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) )
60{
61 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
62 m_formerClip = NewRgn() ;
63 m_newClip = NewRgn() ;
64 GetClip( m_formerClip ) ;
65
66 if ( win )
67 {
bcbbfab8
SC
68 // guard against half constructed objects, this just leads to a empty clip
69 if( win->GetPeer() )
70 {
71 int x = 0 , y = 0;
72 win->MacWindowToRootWindow( &x,&y ) ;
73 // get area including focus rect
74 CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
75 if ( !EmptyRgn( m_newClip ) )
76 OffsetRgn( m_newClip , x , y ) ;
77 }
613a24f7
SC
78
79 SetClip( m_newClip ) ;
80 }
81}
82
83wxMacWindowClipper::~wxMacWindowClipper()
84{
85 SetPort( m_newPort ) ;
86 SetClip( m_formerClip ) ;
87 DisposeRgn( m_newClip ) ;
88 DisposeRgn( m_formerClip ) ;
89}
90
91wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
92 wxMacWindowClipper( win )
93{
94 // the port is already set at this point
95 m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
96 GetThemeDrawingState( &m_themeDrawingState ) ;
97}
98
99wxMacWindowStateSaver::~wxMacWindowStateSaver()
100{
101 SetPort( m_newPort ) ;
102 SetThemeDrawingState( m_themeDrawingState , true ) ;
103}
104
a8f234d2
SC
105// minimal implementation only used for appearance drawing < 10.3
106
107wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
108 m_ph( (GrafPtr) dc->m_macPort )
109{
110 wxASSERT( dc->Ok() ) ;
111 m_dc = dc ;
112// dc->MacSetupPort(&m_ph) ;
113}
114wxMacPortSetter::~wxMacPortSetter()
115{
116// m_dc->MacCleanupPort(&m_ph) ;
117}
118
613a24f7
SC
119//-----------------------------------------------------------------------------
120// Local functions
121//-----------------------------------------------------------------------------
20b69855 122
613a24f7
SC
123static inline double dmin(double a, double b) { return a < b ? a : b; }
124static inline double dmax(double a, double b) { return a > b ? a : b; }
125static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
126
127//-----------------------------------------------------------------------------
20b69855
SC
128// device context implementation
129//
130// more and more of the dc functionality should be implemented by calling
131// the appropricate wxMacCGContext, but we will have to do that step by step
132// also coordinate conversions should be moved to native matrix ops
613a24f7 133//-----------------------------------------------------------------------------
613a24f7 134
20b69855 135wxMacCGPath::wxMacCGPath()
613a24f7 136{
20b69855 137 m_path = CGPathCreateMutable() ;
613a24f7
SC
138}
139
20b69855 140wxMacCGPath::~wxMacCGPath()
613a24f7 141{
20b69855
SC
142 CGPathRelease( m_path ) ;
143}
613a24f7 144
20b69855
SC
145// Starts a new subpath at
146void wxMacCGPath::MoveToPoint( wxCoord x1 , wxCoord y1 )
147{
148 CGPathMoveToPoint( m_path , NULL , x1 , y1 ) ;
149}
613a24f7 150
20b69855
SC
151void wxMacCGPath::AddLineToPoint( wxCoord x1 , wxCoord y1 )
152{
153 CGPathAddLineToPoint( m_path , NULL , x1 , y1 ) ;
154}
613a24f7 155
20b69855 156void wxMacCGPath::AddRectangle( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
613a24f7 157{
20b69855
SC
158 CGRect cgRect = { { x , y } , { w , h } } ;
159 CGPathAddRect( m_path , NULL , cgRect ) ;
160}
613a24f7 161
20b69855
SC
162void wxMacCGPath::AddCircle( wxCoord x, wxCoord y , wxCoord r )
163{
164 CGPathAddArc( m_path , NULL , x , y , r , 0.0 , 2 * M_PI , true ) ;
165}
613a24f7 166
20b69855
SC
167// closes the current subpath
168void wxMacCGPath::CloseSubpath()
169{
170 CGPathCloseSubpath( m_path ) ;
171}
613a24f7 172
20b69855 173CGPathRef wxMacCGPath::GetPath() const
613a24f7 174{
20b69855
SC
175 return m_path ;
176}
177
b014adcc
SC
178// we always stock two context states, one at entry, the other one after
179// changing to HI Graphics orientation (this one is used for getting back clippings etc)
613a24f7 180
20b69855
SC
181wxMacCGContext::wxMacCGContext( CGrafPtr port )
182{
183 m_qdPort = port ;
cb4b0966 184 m_cgContext = NULL ;
20b69855
SC
185}
186
187wxMacCGContext::wxMacCGContext( CGContextRef cgcontext )
188{
189 m_qdPort = NULL ;
190 m_cgContext = cgcontext ;
b014adcc
SC
191 CGContextSaveGState( m_cgContext ) ;
192 CGContextSaveGState( m_cgContext ) ;
20b69855
SC
193}
194
195wxMacCGContext::wxMacCGContext()
196{
197 m_qdPort = NULL ;
198 m_cgContext = NULL ;
199}
613a24f7 200
20b69855
SC
201wxMacCGContext::~wxMacCGContext()
202{
b014adcc
SC
203 if ( m_cgContext )
204 {
68654a82 205 CGContextSynchronize( m_cgContext ) ;
b014adcc
SC
206 CGContextRestoreGState( m_cgContext ) ;
207 CGContextRestoreGState( m_cgContext ) ;
208 }
20b69855 209 if ( m_qdPort )
68654a82 210 CGContextRelease( m_cgContext ) ;
20b69855
SC
211}
212
213
214void wxMacCGContext::Clip( const wxRegion &region )
215{
216// ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn ) ;
217}
218
219void wxMacCGContext::StrokePath( const wxGraphicPath *p )
220{
221 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
20b69855 222 CGContextAddPath( m_cgContext , path->GetPath() ) ;
20b69855
SC
223 CGContextStrokePath( m_cgContext ) ;
224}
225
226void wxMacCGContext::DrawPath( const wxGraphicPath *p , int fillStyle )
227{
228 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
229 CGPathDrawingMode mode = m_mode ;
230 if ( fillStyle == wxODDEVEN_RULE )
231 {
232 if ( mode == kCGPathFill )
233 mode = kCGPathEOFill ;
234 else if ( mode == kCGPathFillStroke )
235 mode = kCGPathEOFillStroke ;
236 }
20b69855 237 CGContextAddPath( m_cgContext , path->GetPath() ) ;
20b69855 238 CGContextDrawPath( m_cgContext , mode ) ;
613a24f7
SC
239}
240
20b69855 241void wxMacCGContext::FillPath( const wxGraphicPath *p , const wxColor &fillColor , int fillStyle )
613a24f7 242{
20b69855
SC
243 const wxMacCGPath* path = dynamic_cast< const wxMacCGPath*>( p ) ;
244 CGContextSaveGState( m_cgContext ) ;
245
246 RGBColor col = MAC_WXCOLORREF( fillColor.GetPixel() ) ;
247 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
248 CGPathDrawingMode mode = kCGPathFill ;
249
250 if ( fillStyle == wxODDEVEN_RULE )
251 mode = kCGPathEOFill ;
252
253 CGContextBeginPath( m_cgContext ) ;
254 CGContextAddPath( m_cgContext , path->GetPath() ) ;
255 CGContextClosePath( m_cgContext ) ;
256 CGContextDrawPath( m_cgContext , mode ) ;
257
258 CGContextRestoreGState( m_cgContext ) ;
259}
613a24f7 260
cb4b0966
SC
261wxGraphicPath* wxMacCGContext::CreatePath()
262{
cb4b0966
SC
263 // make sure that we now have a real cgref, before doing
264 // anything with paths
a63b4755
SC
265 CGContextRef cg = GetNativeContext() ;
266 cg = NULL ;
cb4b0966
SC
267 return new wxMacCGPath() ;
268}
269
270// in case we only got a QDPort only create a cgref now
271
272CGContextRef wxMacCGContext::GetNativeContext()
273{
274 if( m_cgContext == NULL )
275 {
276 Rect bounds ;
277 GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
68654a82 278 OSStatus status = CreateCGContextForPort((CGrafPtr) m_qdPort , &m_cgContext) ;
b014adcc 279 CGContextSaveGState( m_cgContext ) ;
cb4b0966
SC
280
281 wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
282 CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
283 CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
284
b014adcc 285 CGContextSaveGState( m_cgContext ) ;
cb4b0966
SC
286 SetPen( m_pen ) ;
287 SetBrush( m_brush ) ;
288 }
289 return m_cgContext ;
290}
291
292void wxMacCGContext::SetNativeContext( CGContextRef cg )
293{
0e71e845
SC
294 // we allow either setting or clearing but not replacing
295 wxASSERT( m_cgContext == NULL || cg == NULL ) ;
296 if ( cg )
297 CGContextSaveGState( cg ) ;
cb4b0966
SC
298 m_cgContext = cg ;
299}
20b69855 300
72ba915e
SC
301#pragma mark -
302
303// Experimental support for dashes and patterned brushes
304// uncomment the following lines to enable it
305
306// #define _NEW_GC_DASHES_
307// #define _NEW_GC_SUPPORT_
308
309#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
310#define kCGColorSpaceGenericRGB CFSTR("kCGColorSpaceGenericRGB")
311#endif
312
313void EstablishPatternColorSpace(
314 CGContextRef ctxRef,
315 bool useMultibit,
316 bool useFill )
317{
318 CGColorSpaceRef baseSpace, patternSpace;
319
320 if (ctxRef == NULL)
321 return;
322
323 baseSpace = NULL;
324 patternSpace = NULL;
325
326 if (useMultibit)
327 {
328 patternSpace = CGColorSpaceCreatePattern( NULL );
329
330 if (useFill)
331 CGContextSetFillColorSpace( ctxRef, patternSpace );
332 else
333 CGContextSetStrokeColorSpace( ctxRef, patternSpace );
334 }
335 else
336 {
337 baseSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
338 patternSpace = CGColorSpaceCreatePattern( baseSpace );
339
340 if (useFill)
341 CGContextSetFillColorSpace( ctxRef, patternSpace );
342 else
343 CGContextSetStrokeColorSpace( ctxRef, patternSpace );
344 }
345
346 // NB: the context owns these now, and this code is finished with them
347 if (patternSpace != NULL)
348 CGColorSpaceRelease( patternSpace );
349 if (baseSpace != NULL)
350 CGColorSpaceRelease( baseSpace );
351}
352
353void ImagePatternRender(
354 void *info,
355 CGContextRef ctxRef )
356{
357 if (ctxRef == NULL)
358 return;
359
360 CGImageRef imageRef = (CGImageRef)info;
361 if (imageRef != NULL)
362 {
363 CGRect boundsR = CGRectMake( 0.0, 0.0, (float)CGImageGetWidth( imageRef ), (float)CGImageGetHeight( imageRef ) );
364 CGContextDrawImage( ctxRef, boundsR, imageRef );
365 }
366}
367
368void ImagePatternDispose(
369 void *info )
370{
371 CGImageRef imageRef = (CGImageRef)info;
372 if (imageRef != NULL)
373 CGImageRelease( imageRef );
374}
375
376// specifies the struct version value and the callback functions for draw and release
377static const CGPatternCallbacks sImagePatternCallback = { 0, &ImagePatternRender, &ImagePatternDispose };
378
379long CreatePatternFromBitmap(
380 CGPatternRef *patternRef,
381 const wxBitmap *rasterInfo,
382 bool useMultibit )
383{
384 CGRect boundsR;
385 CGImageRef imageRef;
386 long errorStatus, widthV, heightV, depthV;
387
388 if (patternRef == NULL)
389 return (-1);
390
391 *patternRef = NULL;
392 imageRef = NULL;
393 errorStatus = 0;
394
395 if ((rasterInfo == NULL) || !rasterInfo->Ok())
396 errorStatus = (-2);
397
398 if (errorStatus == 0)
399 {
400 // build a usable bounding CGRect from the wxBitmap's bounds wxRect
401 widthV = rasterInfo->GetWidth();
402 heightV = rasterInfo->GetHeight();
403 if ((widthV <= 0) || (heightV <= 0))
404 errorStatus = (-3);
405 }
406
407 if (errorStatus == 0)
408 {
409 depthV = rasterInfo->GetDepth();
410// isColored = (depthV > 1);
411
412 // FIXME: this is often <= 0 - why???
413// if (depthV <= 1)
414// errorStatus = (-4);
415 }
416
417 if (errorStatus == 0)
418 {
419 imageRef = (CGImageRef)(rasterInfo->CGImageCreate());
420 if (imageRef == NULL)
421 errorStatus = (-5);
422 }
423
424 if (errorStatus == 0)
425 {
426 // FIXME: switch when this routine belongs to a DC class...
427 boundsR = CGRectMake( 0.0, 0.0, (float)widthV, (float)heightV );
428// boundsR = CGRectMake( 0.0, 0.0, (float)XLOG2DEVREL( widthV ), (float)XLOG2DEVREL( heightV ) );
429
430 *patternRef = CGPatternCreate(
431 (void*)imageRef,
432 boundsR,
433 CGAffineTransformIdentity,
434 boundsR.size.width,
435 boundsR.size.height,
436 kCGPatternTilingNoDistortion,
437 (int)useMultibit,
438 &sImagePatternCallback );
439
440 if (*patternRef == (CGPatternRef)NULL)
441 errorStatus = (-6);
442 }
443
444 return errorStatus;
445}
446
447long CreatePatternFromDashes(
448 CGPatternRef *patternRef,
449 const wxDash *sourceDash,
450 int count,
451 bool useMultibit )
452{
453 long errorStatus;
454
455 if (patternRef == NULL)
456 return (-1);
457
458 *patternRef = NULL;
459 if ((sourceDash == NULL) || (count <= 0))
460 return (-2);
461
462 wxBitmap dashBits( (char*)sourceDash, 8, count, 1 );
463 errorStatus = CreatePatternFromBitmap( patternRef, &dashBits, useMultibit );
464
465 return errorStatus;
466}
467
468long CreatePatternFromBrush(
469 CGPatternRef *patternRef,
470 const wxBrush &sourceBrush,
471 bool useMultibit )
472{
473 long errorStatus;
474
475 if (patternRef == NULL)
476 return (-1);
477
478 *patternRef = NULL;
479 errorStatus = CreatePatternFromBitmap( patternRef, sourceBrush.GetStipple(), useMultibit );
480
481 return errorStatus;
482}
483
484long CreatePatternFromPen(
485 CGPatternRef *patternRef,
486 const wxPen &sourcePen,
487 bool useMultibit )
488{
489 long errorStatus;
490
491 if (patternRef == NULL)
492 return (-1);
493
494 *patternRef = NULL;
495 errorStatus = CreatePatternFromBitmap( patternRef, sourcePen.GetStipple(), useMultibit );
496
497 return errorStatus;
498}
499
500// ------------
501#pragma mark -
502
503// FIXME: the NEW_GC_SUPPORT part this routine is unfinished and needs lots of work !!
504//
20b69855
SC
505void wxMacCGContext::SetPen( const wxPen &pen )
506{
cb4b0966
SC
507 m_pen = pen ;
508 if ( m_cgContext == NULL )
509 return ;
20b69855
SC
510 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
511 bool stroke = pen.GetStyle() != wxTRANSPARENT ;
cb4b0966 512
20b69855
SC
513#if 0
514 // we can benchmark performance, should go into a setting later
515 CGContextSetShouldAntialias( m_cgContext , false ) ;
516#endif
613a24f7
SC
517 if ( fill | stroke )
518 {
613a24f7
SC
519 // setup brushes
520 m_mode = kCGPathFill ; // just a default
521
522 if ( fill )
523 {
613a24f7
SC
524 m_mode = kCGPathFill ;
525 }
526 if ( stroke )
527 {
72ba915e
SC
528#if defined(_NEW_GC_SUPPORT_)
529 // new candidate
530 {
531 CGPatternRef patternRef;
532 float alphaArray[1];
533 long result;
534 bool hasSetPattern, useMultibit;
535
536 hasSetPattern = false;
537 useMultibit = true;
538 result = CreatePatternFromPen( &patternRef, pen, useMultibit );
539 if (result == 0)
540 {
541 EstablishPatternColorSpace( m_cgContext, useMultibit, false );
542
543 alphaArray[0] = 1.0;
544 CGContextSetStrokePattern( m_cgContext, patternRef, alphaArray );
545 CGPatternRelease( patternRef );
546
547 hasSetPattern = true;
548
549//wxLogDebug( wxT("CreatePatternFromPen succeeded!") );
550 }
551
552 // NB: the (-2) result is from wxPen instances that don't have a stipple wxBitmap
553 if (result < (-2))
554 wxLogDebug( wxT("CreatePatternFromPen failed: result [%ld]"), result );
555
556 if (!hasSetPattern)
557 {
558 RGBColor col;
559
560#if 1
561 col = MAC_WXCOLORREF( pen.GetColour().GetPixel() );
562#else
563 GetThemeBrushAsColor( pen.MacGetTheme(), 32, true, &col );
564#endif
565
566 CGContextSetRGBStrokeColor(
567 m_cgContext, (float) col.red / 65536.0,
568 (float) col.green / 65536.0, (float) col.blue / 65536.0, 1.0 );
569 }
570 }
571
572#else
573 // original implementation
20b69855 574 RGBColor col = MAC_WXCOLORREF( pen.GetColour().GetPixel() ) ;
613a24f7 575 CGContextSetRGBStrokeColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
72ba915e 576#endif
613a24f7
SC
577
578 CGLineCap cap ;
20b69855 579 switch( pen.GetCap() )
613a24f7
SC
580 {
581 case wxCAP_ROUND :
582 cap = kCGLineCapRound ;
583 break ;
584 case wxCAP_PROJECTING :
585 cap = kCGLineCapSquare ;
586 break ;
587 case wxCAP_BUTT :
588 cap = kCGLineCapButt ;
589 break ;
590 default :
591 cap = kCGLineCapButt ;
592 break ;
593 }
594 CGContextSetLineCap( m_cgContext , cap ) ;
595
596 CGLineJoin join ;
20b69855 597 switch( pen.GetJoin() )
613a24f7
SC
598 {
599 case wxJOIN_BEVEL :
600 join = kCGLineJoinBevel ;
601 break ;
602 case wxJOIN_MITER :
603 join = kCGLineJoinMiter ;
604 break ;
605 case wxJOIN_ROUND :
606 join = kCGLineJoinRound ;
607 break ;
608 default :
609 join = kCGLineJoinMiter ;
610 break;
611 }
612 CGContextSetLineJoin( m_cgContext , join ) ;
613
72ba915e
SC
614 /* TODO * m_dc->m_scaleX */
615 float penWidth = pen.GetWidth();
616 if (penWidth <= 0.0)
617 penWidth = 0.1;
618 CGContextSetLineWidth( m_cgContext , penWidth ) ;
613a24f7
SC
619
620 m_mode = kCGPathStroke ;
621 int count = 0 ;
72ba915e
SC
622
623#if defined(_NEW_GC_DASHES_)
624 const char *dashData = NULL ;
625 char *userDashData = NULL ;
626 float alphaArray[1];
627
628 const char dotted[] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 };
629 const char dashed[] = { 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 };
630 const char short_dashed[] = { 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 };
631 const char dotted_dashed[] = { 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00 };
632
633 switch (pen.GetStyle())
634 {
635 case wxSOLID:
636 // default, undashed pen
637 break;
638
639 case wxDOT:
640 dashData = dotted;
641 count = WXSIZEOF(dotted);
642 break;
643 case wxLONG_DASH:
644 dashData = dashed;
645 count = WXSIZEOF(dashed);
646 break;
647 case wxSHORT_DASH:
648 dashData = short_dashed;
649 count = WXSIZEOF(short_dashed);
650 break;
651 case wxDOT_DASH:
652 dashData = dotted_dashed;
653 count = WXSIZEOF(dotted_dashed);
654 break;
655 case wxUSER_DASH:
656 count = pen.GetDashes( (wxDash**)&userDashData );
657 dashData = userDashData;
658 break;
659
660 default :
661 break;
662 }
663
664 if ((dashData != NULL) && (count > 0))
665 {
666 CGPatternRef patternRef;
667 RGBColor col;
668 long result;
669 bool useMultibit;
670
671 useMultibit = true;
672 result = CreatePatternFromDashes( &patternRef, (const wxDash*)dashData, count, useMultibit );
673 if (result == 0)
674 {
675 col = MAC_WXCOLORREF( pen.GetColour().GetPixel() );
676 CGContextSetRGBStrokeColor(
677 m_cgContext, (float) col.red / 65536.0,
678 (float) col.green / 65536.0, (float) col.blue / 65536.0, 1.0 );
679
680 EstablishPatternColorSpace( m_cgContext, useMultibit, false );
681
682 alphaArray[0] = 1.0;
683 CGContextSetStrokePattern( m_cgContext, patternRef, alphaArray );
684 CGPatternRelease( patternRef );
685 }
686
687 if (result != 0)
688 wxLogDebug( wxT("CreatePatternFromDashes failed: result [%ld]"), result );
689 }
690#else
613a24f7
SC
691 const float *lengths = NULL ;
692 float *userLengths = NULL ;
693
20b69855
SC
694 const float dotted[] = { 3 , 3 };
695 const float dashed[] = { 19 , 9 };
696 const float short_dashed[] = { 9 , 6 };
697 const float dotted_dashed[] = { 9 , 6 , 3 , 3 };
698
699 switch( pen.GetStyle() )
613a24f7
SC
700 {
701 case wxSOLID :
702 break ;
703 case wxDOT :
613a24f7
SC
704 lengths = dotted ;
705 count = WXSIZEOF(dotted);
706 break ;
707 case wxLONG_DASH :
613a24f7
SC
708 lengths = dashed ;
709 count = WXSIZEOF(dashed) ;
710 break ;
711 case wxSHORT_DASH :
613a24f7
SC
712 lengths = short_dashed ;
713 count = WXSIZEOF(short_dashed) ;
714 break ;
715 case wxDOT_DASH :
613a24f7
SC
716 lengths = dotted_dashed ;
717 count = WXSIZEOF(dotted_dashed);
718 break ;
719 case wxUSER_DASH :
720 wxDash *dashes ;
20b69855 721 count = pen.GetDashes( &dashes ) ;
72ba915e 722 if ((dashes != NULL) && (count > 0))
613a24f7
SC
723 {
724 userLengths = new float[count] ;
725 for( int i = 0 ; i < count ; ++i )
72ba915e
SC
726 {
727 userLengths[i] = (float)dashes[i] ;
728 if (userLengths[i] <= 0.0)
729 {
730 userLengths[i] = 1.0;
731// wxLogDebug( wxT("wxMacCGContext::SetPen - bad dash length[%d] [%.2f]"), i, (float)dashes[i] );
732 }
733 }
613a24f7
SC
734 }
735 lengths = userLengths ;
736 break ;
737 default :
738 break ;
739 }
740
72ba915e
SC
741 if ((lengths != NULL) && (count > 0))
742 {
743 // we need to change the cap, otherwise everything overlaps
744 // and we get solid lines
745 CGContextSetLineDash( m_cgContext , 0 , lengths , count ) ;
613a24f7 746 CGContextSetLineCap( m_cgContext , kCGLineCapButt ) ;
72ba915e
SC
747 }
748 else
749 {
750 CGContextSetLineDash( m_cgContext , 0 , NULL , 0 ) ;
751 }
752
753 delete[] userLengths ;
754#endif
613a24f7
SC
755 }
756 if ( fill && stroke )
757 {
758 m_mode = kCGPathFillStroke ;
759 }
613a24f7
SC
760 }
761}
72ba915e 762
20b69855
SC
763void wxMacCGContext::SetBrush( const wxBrush &brush )
764{
cb4b0966
SC
765 m_brush = brush ;
766 if ( m_cgContext == NULL )
767 return ;
768
20b69855
SC
769 bool fill = brush.GetStyle() != wxTRANSPARENT ;
770 bool stroke = m_pen.GetStyle() != wxTRANSPARENT ;
613a24f7 771
20b69855
SC
772#if 0
773 // we can benchmark performance, should go into a setting later
774 CGContextSetShouldAntialias( m_cgContext , false ) ;
775#endif
72ba915e 776
20b69855
SC
777 if ( fill | stroke )
778 {
20b69855
SC
779 // setup brushes
780 m_mode = kCGPathFill ; // just a default
781
782 if ( fill )
783 {
72ba915e
SC
784#if defined(_NEW_GC_SUPPORT_)
785 // new candidate
786 {
787 CGPatternRef patternRef;
788 float alphaArray[1];
789 long result;
790 bool hasSetPattern, useMultibit;
791
792 hasSetPattern = false;
793 useMultibit = true;
794 result = CreatePatternFromBrush( &patternRef, brush, useMultibit );
795 if (result == 0)
796 {
797 EstablishPatternColorSpace( m_cgContext, useMultibit, true );
798
799 alphaArray[0] = 1.0;
800 CGContextSetFillPattern( m_cgContext, patternRef, alphaArray );
801 CGPatternRelease( patternRef );
802
803 hasSetPattern = true;
804
805//wxLogDebug( wxT("CreatePatternFromBrush succeeded!") );
806 }
807
808 // NB: the (-2) result is from wxBrush instances that don't have a stipple wxBitmap
809 if (result < (-2))
810 wxLogDebug( wxT("CreatePatternFromBrush failed: result [%ld]"), result );
811
812 if (!hasSetPattern)
813 {
814 RGBColor col;
815
816#if 1
817 col = MAC_WXCOLORREF( brush.GetColour().GetPixel() );
818#else
819 GetThemeBrushAsColor( brush.MacGetTheme(), 32, true, &col );
820#endif
821
822 CGContextSetRGBFillColor(
823 m_cgContext, (float) col.red / 65536.0,
824 (float) col.green / 65536.0, (float) col.blue / 65536.0, 1.0 );
825 }
826 }
827
828#else
829 // original implementation
20b69855
SC
830 RGBColor col = MAC_WXCOLORREF( brush.GetColour().GetPixel() ) ;
831 CGContextSetRGBFillColor( m_cgContext , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
72ba915e
SC
832#endif
833
20b69855
SC
834 m_mode = kCGPathFill ;
835 }
836 if ( stroke )
837 {
838 m_mode = kCGPathStroke ;
839 }
840 if ( fill && stroke )
841 {
842 m_mode = kCGPathFillStroke ;
843 }
20b69855
SC
844 }
845}
846
613a24f7
SC
847void AddEllipticArcToPath(CGContextRef c, CGPoint center, float a, float b, float fromDegree , float toDegree )
848{
849 CGContextSaveGState(c);
850 CGContextTranslateCTM(c, center.x, center.y);
851 CGContextScaleCTM(c, a, b);
852 CGContextMoveToPoint(c, 1, 0);
853 CGContextAddArc(c, 0, 0, 1, DegToRad(fromDegree), DegToRad(toDegree), 0);
854 CGContextClosePath(c);
855 CGContextRestoreGState(c);
856}
857
858void AddRoundedRectToPath(CGContextRef c, CGRect rect, float ovalWidth,
859 float ovalHeight)
860{
861 float fw, fh;
862 if (ovalWidth == 0 || ovalHeight == 0)
863 {
864 CGContextAddRect(c, rect);
865 return;
866 }
867 CGContextSaveGState(c);
868 CGContextTranslateCTM(c, CGRectGetMinX(rect), CGRectGetMinY(rect));
869 CGContextScaleCTM(c, ovalWidth, ovalHeight);
870 fw = CGRectGetWidth(rect) / ovalWidth;
871 fh = CGRectGetHeight(rect) / ovalHeight;
872 CGContextMoveToPoint(c, fw, fh/2);
873 CGContextAddArcToPoint(c, fw, fh, fw/2, fh, 1);
874 CGContextAddArcToPoint(c, 0, fh, 0, fh/2, 1);
875 CGContextAddArcToPoint(c, 0, 0, fw/2, 0, 1);
876 CGContextAddArcToPoint(c, fw, 0, fw, fh/2, 1);
877 CGContextClosePath(c);
878 CGContextRestoreGState(c);
879}
880
881wxDC::wxDC()
882{
883 m_ok = FALSE;
884 m_colour = TRUE;
885 m_mm_to_pix_x = mm2pt;
886 m_mm_to_pix_y = mm2pt;
887 m_internalDeviceOriginX = 0;
888 m_internalDeviceOriginY = 0;
889 m_externalDeviceOriginX = 0;
890 m_externalDeviceOriginY = 0;
891 m_logicalScaleX = 1.0;
892 m_logicalScaleY = 1.0;
893 m_userScaleX = 1.0;
894 m_userScaleY = 1.0;
895 m_scaleX = 1.0;
896 m_scaleY = 1.0;
897 m_needComputeScaleX = FALSE;
898 m_needComputeScaleY = FALSE;
20b69855 899
613a24f7 900 m_ok = FALSE ;
a63b4755 901 m_macPort = 0 ;
613a24f7 902 m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
20b69855 903
613a24f7
SC
904 m_pen = *wxBLACK_PEN;
905 m_font = *wxNORMAL_FONT;
906 m_brush = *wxWHITE_BRUSH;
613a24f7 907
20b69855 908 m_macATSUIStyle = NULL ;
613a24f7 909
20b69855 910 m_graphicContext = NULL ;
613a24f7
SC
911}
912
20b69855 913wxDC::~wxDC(void)
613a24f7 914{
613a24f7
SC
915 if( m_macATSUIStyle )
916 {
917 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
918 m_macATSUIStyle = NULL ;
919 }
20b69855
SC
920
921 delete m_graphicContext ;
613a24f7
SC
922}
923
924void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
925{
20b69855
SC
926 wxCHECK_RET( Ok(), wxT("invalid window dc") );
927 wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") );
928 wxCoord xx = XLOG2DEVMAC(x);
929 wxCoord yy = YLOG2DEVMAC(y);
930 wxCoord w = bmp.GetWidth();
931 wxCoord h = bmp.GetHeight();
932 wxCoord ww = XLOG2DEVREL(w);
933 wxCoord hh = YLOG2DEVREL(h);
934
b60f5ca5 935 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
20b69855
SC
936 CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ) ;
937 HIRect r = CGRectMake( xx , yy , ww , hh ) ;
938 HIViewDrawCGImage( cg , &r , image ) ;
939 CGImageRelease( image ) ;
613a24f7
SC
940}
941
942void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
943{
944 wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon"));
945 wxCHECK_RET(icon.Ok(), wxT("Invalid icon wxDC::DoDrawIcon"));
20b69855
SC
946
947 wxCoord xx = XLOG2DEVMAC(x);
948 wxCoord yy = YLOG2DEVMAC(y);
949 wxCoord w = icon.GetWidth();
950 wxCoord h = icon.GetHeight();
951 wxCoord ww = XLOG2DEVREL(w);
952 wxCoord hh = YLOG2DEVREL(h);
953
b60f5ca5 954 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
20b69855
SC
955 CGRect r = CGRectMake( 00 , 00 , ww , hh ) ;
956 CGContextSaveGState(cg);
957 CGContextTranslateCTM(cg, xx , yy + hh );
958 CGContextScaleCTM(cg, 1, -1);
959 PlotIconRefInContext( cg , &r , kAlignNone , kTransformNone ,
960 NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
961 CGContextRestoreGState( cg ) ;
613a24f7
SC
962}
963
964void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
965{
966 wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC"));
967 wxCoord xx, yy, ww, hh;
968 xx = XLOG2DEVMAC(x);
969 yy = YLOG2DEVMAC(y);
970 ww = XLOG2DEVREL(width);
971 hh = YLOG2DEVREL(height);
b014adcc 972
b60f5ca5 973 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
b014adcc
SC
974 CGRect clipRect = CGRectMake( xx ,yy , ww, hh ) ;
975 CGContextClipToRect( cgContext , clipRect ) ;
976
20b69855
SC
977// SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
978// SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
613a24f7
SC
979 if( m_clipping )
980 {
981 m_clipX1 = wxMax( m_clipX1 , xx );
982 m_clipY1 = wxMax( m_clipY1 , yy );
983 m_clipX2 = wxMin( m_clipX2, (xx + ww));
984 m_clipY2 = wxMin( m_clipY2, (yy + hh));
985 }
986 else
987 {
988 m_clipping = TRUE;
989 m_clipX1 = xx;
990 m_clipY1 = yy;
991 m_clipX2 = xx + ww;
992 m_clipY2 = yy + hh;
993 }
994 // TODO as soon as we don't reset the context for each operation anymore
995 // we have to update the context as well
996}
997
998void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
999{
1000 wxCHECK_RET( Ok(), wxT("invalid window dc") ) ;
1001 if (region.Empty())
1002 {
1003 DestroyClippingRegion();
1004 return;
1005 }
1006 wxCoord x, y, w, h;
1007 region.GetBox( x, y, w, h );
1008 wxCoord xx, yy, ww, hh;
1009 xx = XLOG2DEVMAC(x);
1010 yy = YLOG2DEVMAC(y);
1011 ww = XLOG2DEVREL(w);
1012 hh = YLOG2DEVREL(h);
1013 // if we have a scaling that we cannot map onto native regions
1014 // we must use the box
1015 if ( ww != w || hh != h )
1016 {
1017 wxDC::DoSetClippingRegion( x, y, w, h );
1018 }
1019 else
1020 {
20b69855 1021 /*
613a24f7
SC
1022 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
1023 if ( xx != x || yy != y )
1024 {
1025 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
1026 }
1027 SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
20b69855 1028 */
613a24f7
SC
1029 if( m_clipping )
1030 {
1031 m_clipX1 = wxMax( m_clipX1 , xx );
1032 m_clipY1 = wxMax( m_clipY1 , yy );
1033 m_clipX2 = wxMin( m_clipX2, (xx + ww));
1034 m_clipY2 = wxMin( m_clipY2, (yy + hh));
1035 }
1036 else
1037 {
1038 m_clipping = TRUE;
1039 m_clipX1 = xx;
1040 m_clipY1 = yy;
1041 m_clipX2 = xx + ww;
1042 m_clipY2 = yy + hh;
1043 }
1044 }
1045}
1046
1047void wxDC::DestroyClippingRegion()
1048{
20b69855 1049// CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
b60f5ca5 1050 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
b014adcc
SC
1051 CGContextRestoreGState( cgContext );
1052 CGContextSaveGState( cgContext );
0e71e845
SC
1053 m_graphicContext->SetPen( m_pen ) ;
1054 m_graphicContext->SetBrush( m_brush ) ;
613a24f7
SC
1055 m_clipping = FALSE;
1056}
1057
1058void wxDC::DoGetSizeMM( int* width, int* height ) const
1059{
1060 int w = 0;
1061 int h = 0;
1062 GetSize( &w, &h );
1063 *width = long( double(w) / (m_scaleX*m_mm_to_pix_x) );
1064 *height = long( double(h) / (m_scaleY*m_mm_to_pix_y) );
1065}
1066
1067void wxDC::SetTextForeground( const wxColour &col )
1068{
1069 wxCHECK_RET(Ok(), wxT("Invalid DC"));
20b69855
SC
1070 if ( col != m_textForegroundColour )
1071 {
1072 m_textForegroundColour = col;
1073 MacInstallFont() ;
1074 }
613a24f7
SC
1075}
1076
1077void wxDC::SetTextBackground( const wxColour &col )
1078{
1079 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1080 m_textBackgroundColour = col;
613a24f7
SC
1081}
1082
1083void wxDC::SetMapMode( int mode )
1084{
1085 switch (mode)
1086 {
1087 case wxMM_TWIPS:
1088 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1089 break;
1090 case wxMM_POINTS:
1091 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1092 break;
1093 case wxMM_METRIC:
1094 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1095 break;
1096 case wxMM_LOMETRIC:
1097 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1098 break;
1099 default:
1100 case wxMM_TEXT:
1101 SetLogicalScale( 1.0, 1.0 );
1102 break;
1103 }
1104 if (mode != wxMM_TEXT)
1105 {
1106 m_needComputeScaleX = TRUE;
1107 m_needComputeScaleY = TRUE;
1108 }
1109}
1110
1111void wxDC::SetUserScale( double x, double y )
1112{
1113 // allow negative ? -> no
1114 m_userScaleX = x;
1115 m_userScaleY = y;
1116 ComputeScaleAndOrigin();
1117}
1118
1119void wxDC::SetLogicalScale( double x, double y )
1120{
1121 // allow negative ?
1122 m_logicalScaleX = x;
1123 m_logicalScaleY = y;
1124 ComputeScaleAndOrigin();
1125}
1126
1127void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
1128{
1129 m_logicalOriginX = x * m_signX; // is this still correct ?
1130 m_logicalOriginY = y * m_signY;
1131 ComputeScaleAndOrigin();
1132}
1133
1134void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1135{
1136 m_externalDeviceOriginX = x;
1137 m_externalDeviceOriginY = y;
1138 ComputeScaleAndOrigin();
1139}
1140
1141void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1142{
1143 m_signX = (xLeftRight ? 1 : -1);
1144 m_signY = (yBottomUp ? -1 : 1);
1145 ComputeScaleAndOrigin();
1146}
1147
1148wxSize wxDC::GetPPI() const
1149{
1150 return wxSize(72, 72);
1151}
1152
1153int wxDC::GetDepth() const
1154{
20b69855 1155 return 32 ;
613a24f7
SC
1156}
1157
1158void wxDC::ComputeScaleAndOrigin()
1159{
1160 // CMB: copy scale to see if it changes
1161 double origScaleX = m_scaleX;
1162 double origScaleY = m_scaleY;
1163 m_scaleX = m_logicalScaleX * m_userScaleX;
1164 m_scaleY = m_logicalScaleY * m_userScaleY;
1165 m_deviceOriginX = m_internalDeviceOriginX + m_externalDeviceOriginX;
1166 m_deviceOriginY = m_internalDeviceOriginY + m_externalDeviceOriginY;
1167 // CMB: if scale has changed call SetPen to recalulate the line width
1168 if (m_scaleX != origScaleX || m_scaleY != origScaleY)
1169 {
1170 // this is a bit artificial, but we need to force wxDC to think
1171 // the pen has changed
1172 wxPen pen(GetPen());
1173 m_pen = wxNullPen;
1174 SetPen(pen);
1175 }
1176}
1177
1178void wxDC::SetPalette( const wxPalette& palette )
1179{
1180}
1181
1182void wxDC::SetBackgroundMode( int mode )
1183{
1184 m_backgroundMode = mode ;
1185}
1186
1187void wxDC::SetFont( const wxFont &font )
1188{
1189 m_font = font;
20b69855 1190 MacInstallFont() ;
613a24f7
SC
1191}
1192
1193void wxDC::SetPen( const wxPen &pen )
1194{
1195 if ( m_pen == pen )
1196 return ;
1197 m_pen = pen;
20b69855
SC
1198 if ( m_graphicContext )
1199 {
1200 m_graphicContext->SetPen( m_pen ) ;
1201 }
613a24f7
SC
1202}
1203
1204void wxDC::SetBrush( const wxBrush &brush )
1205{
1206 if (m_brush == brush)
1207 return;
1208 m_brush = brush;
20b69855
SC
1209 if ( m_graphicContext )
1210 {
1211 m_graphicContext->SetBrush( m_brush ) ;
1212 }
613a24f7
SC
1213}
1214
1215void wxDC::SetBackground( const wxBrush &brush )
1216{
1217 if (m_backgroundBrush == brush)
1218 return;
1219 m_backgroundBrush = brush;
1220 if (!m_backgroundBrush.Ok())
1221 return;
613a24f7
SC
1222}
1223
1224void wxDC::SetLogicalFunction( int function )
1225{
1226 if (m_logicalFunction == function)
1227 return;
1228 m_logicalFunction = function ;
613a24f7
SC
1229}
1230
1231extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
1232 const wxColour & col, int style);
1233
1234bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
1235 const wxColour& col, int style)
1236{
1237 return wxDoFloodFill(this, x, y, col, style);
1238}
1239
1240bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
1241{
1242 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
880f5369
SC
1243 wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") );
1244 wxMacPortSaver helper((CGrafPtr)m_macPort) ;
1245 RGBColor colour;
1246 GetCPixel(
1247 XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x,
1248 YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
1249 // Convert from Mac colour to wx
1250 col->Set( colour.red >> 8,
1251 colour.green >> 8,
1252 colour.blue >> 8);
1253 return true ;
613a24f7
SC
1254}
1255
1256void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
1257{
1258 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1259
08c8555e
SC
1260 if ( m_logicalFunction != wxCOPY )
1261 return ;
1262
613a24f7
SC
1263 wxCoord xx1 = XLOG2DEVMAC(x1) ;
1264 wxCoord yy1 = YLOG2DEVMAC(y1) ;
1265 wxCoord xx2 = XLOG2DEVMAC(x2) ;
1266 wxCoord yy2 = YLOG2DEVMAC(y2) ;
1267
20b69855
SC
1268 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1269 path->MoveToPoint( xx1 , yy1 ) ;
1270 path->AddLineToPoint( xx2 , yy2 ) ;
1271 path->CloseSubpath() ;
1272 m_graphicContext->StrokePath( path ) ;
1273 delete path ;
613a24f7
SC
1274
1275 CalcBoundingBox(x1, y1);
1276 CalcBoundingBox(x2, y2);
1277}
1278
1279void wxDC::DoCrossHair( wxCoord x, wxCoord y )
1280{
1281 wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") );
1282
08c8555e
SC
1283 if ( m_logicalFunction != wxCOPY )
1284 return ;
613a24f7
SC
1285
1286 int w = 0;
1287 int h = 0;
1288 GetSize( &w, &h );
1289 wxCoord xx = XLOG2DEVMAC(x);
1290 wxCoord yy = YLOG2DEVMAC(y);
1291
20b69855
SC
1292 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1293 path->MoveToPoint( XLOG2DEVMAC(0), yy ) ;
1294 path->AddLineToPoint( XLOG2DEVMAC(w), yy ) ;
1295 path->CloseSubpath() ;
1296 path->MoveToPoint( xx, YLOG2DEVMAC(0) ) ;
1297 path->AddLineToPoint( xx, YLOG2DEVMAC(h) ) ;
1298 path->CloseSubpath() ;
1299 m_graphicContext->StrokePath( path ) ;
1300 delete path ;
613a24f7
SC
1301
1302 CalcBoundingBox(x, y);
1303 CalcBoundingBox(x+w, y+h);
1304}
1305
613a24f7
SC
1306void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
1307 wxCoord x2, wxCoord y2,
1308 wxCoord xc, wxCoord yc )
1309{
1310 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC"));
08c8555e
SC
1311
1312 if ( m_logicalFunction != wxCOPY )
1313 return ;
1314
613a24f7
SC
1315 wxCoord xx1 = XLOG2DEVMAC(x1);
1316 wxCoord yy1 = YLOG2DEVMAC(y1);
1317 wxCoord xx2 = XLOG2DEVMAC(x2);
1318 wxCoord yy2 = YLOG2DEVMAC(y2);
1319 wxCoord xxc = XLOG2DEVMAC(xc);
1320 wxCoord yyc = YLOG2DEVMAC(yc);
1321 double dx = xx1 - xxc;
1322 double dy = yy1 - yyc;
1323 double radius = sqrt((double)(dx*dx+dy*dy));
1324 wxCoord rad = (wxCoord)radius;
72ba915e 1325 double sa, ea;
613a24f7
SC
1326 if (xx1 == xx2 && yy1 == yy2)
1327 {
72ba915e
SC
1328 sa = 0.0;
1329 ea = 360.0;
613a24f7
SC
1330 }
1331 else if (radius == 0.0)
1332 {
72ba915e 1333 sa = ea = 0.0;
613a24f7
SC
1334 }
1335 else
1336 {
72ba915e 1337 sa = (xx1 - xxc == 0) ?
613a24f7
SC
1338 (yy1 - yyc < 0) ? 90.0 : -90.0 :
1339 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
72ba915e 1340 ea = (xx2 - xxc == 0) ?
613a24f7
SC
1341 (yy2 - yyc < 0) ? 90.0 : -90.0 :
1342 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
1343 }
72ba915e
SC
1344
1345 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
20b69855
SC
1346 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1347 CGContextRef ctx = mctx->GetNativeContext() ;
72ba915e
SC
1348 CGContextSaveGState( ctx ) ;
1349 CGContextTranslateCTM( ctx, xxc , yyc );
1350 CGContextScaleCTM( ctx , 1 , -1 ) ;
1351 if ( fill )
1352 CGContextMoveToPoint( ctx , 0 , 0 ) ;
1353 CGContextAddArc( ctx, 0, 0 , rad , DegToRad(sa), DegToRad(ea), 0);
1354 if ( fill )
1355 CGContextAddLineToPoint( ctx , 0 , 0 ) ;
1356 CGContextRestoreGState( ctx ) ;
20b69855 1357 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
613a24f7
SC
1358}
1359
1360void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1361 double sa, double ea )
1362{
1363 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC"));
20b69855 1364
08c8555e
SC
1365 if ( m_logicalFunction != wxCOPY )
1366 return ;
1367
613a24f7
SC
1368 wxCoord xx = XLOG2DEVMAC(x);
1369 wxCoord yy = YLOG2DEVMAC(y);
1370 wxCoord ww = m_signX * XLOG2DEVREL(w);
1371 wxCoord hh = m_signY * YLOG2DEVREL(h);
1372 // handle -ve width and/or height
1373 if (ww < 0) { ww = -ww; xx = xx - ww; }
1374 if (hh < 0) { hh = -hh; yy = yy - hh; }
72ba915e
SC
1375
1376 bool fill = m_brush.GetStyle() != wxTRANSPARENT ;
1377
20b69855
SC
1378 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1379 CGContextRef ctx = mctx->GetNativeContext() ;
72ba915e
SC
1380
1381 CGContextSaveGState( ctx ) ;
1382 CGContextTranslateCTM( ctx, xx + ww / 2, yy + hh / 2);
1383 CGContextScaleCTM( ctx , 1 * ww / 2 , -1 * hh / 2 ) ;
1384 if ( fill )
1385 CGContextMoveToPoint( ctx , 0 , 0 ) ;
1386 CGContextAddArc( ctx, 0, 0, 1, DegToRad(sa), DegToRad(ea), 0);
1387 if ( fill )
1388 CGContextAddLineToPoint( ctx , 0 , 0 ) ;
1389 CGContextRestoreGState( ctx ) ;
1390 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
613a24f7
SC
1391}
1392
1393void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
1394{
1395 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1396 DoDrawLine( x , y , x + 1 , y + 1 ) ;
1397}
1398
1399void wxDC::DoDrawLines(int n, wxPoint points[],
1400 wxCoord xoffset, wxCoord yoffset)
1401{
1402 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1403
08c8555e
SC
1404 if ( m_logicalFunction != wxCOPY )
1405 return ;
1406
613a24f7
SC
1407 wxCoord x1, x2 , y1 , y2 ;
1408 x1 = XLOG2DEVMAC(points[0].x + xoffset);
1409 y1 = YLOG2DEVMAC(points[0].y + yoffset);
20b69855
SC
1410 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1411 path->MoveToPoint( x1 , y1 ) ;
613a24f7
SC
1412 for (int i = 1; i < n; i++)
1413 {
1414 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1415 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1416
20b69855 1417 path->AddLineToPoint( x2 , y2 ) ;
613a24f7 1418 }
20b69855
SC
1419 m_graphicContext->StrokePath( path ) ;
1420 delete path ;
613a24f7
SC
1421}
1422
1423void wxDC::DoDrawPolygon(int n, wxPoint points[],
1424 wxCoord xoffset, wxCoord yoffset,
1425 int fillStyle )
1426{
1427 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1428 wxCoord x1, x2 , y1 , y2 ;
1429 if ( n== 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
1430 return ;
1431
08c8555e
SC
1432 if ( m_logicalFunction != wxCOPY )
1433 return ;
1434
613a24f7
SC
1435 x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1436 y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
1437
20b69855
SC
1438 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1439 path->MoveToPoint( x1 , y1 ) ;
613a24f7
SC
1440 for (int i = 1; i < n; i++)
1441 {
1442 x2 = XLOG2DEVMAC(points[i].x + xoffset);
1443 y2 = YLOG2DEVMAC(points[i].y + yoffset);
1444
20b69855 1445 path->AddLineToPoint( x2 , y2 ) ;
613a24f7
SC
1446 }
1447 if ( x1 != x2 || y1 != y2 )
1448 {
20b69855 1449 path->AddLineToPoint( x1,y1 ) ;
613a24f7 1450 }
20b69855
SC
1451 path->CloseSubpath() ;
1452 m_graphicContext->DrawPath( path , fillStyle ) ;
1453 delete path ;
613a24f7
SC
1454}
1455
1456void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1457{
1458 wxCHECK_RET(Ok(), wxT("Invalid DC"));
08c8555e
SC
1459
1460 if ( m_logicalFunction != wxCOPY )
1461 return ;
1462
613a24f7
SC
1463 wxCoord xx = XLOG2DEVMAC(x);
1464 wxCoord yy = YLOG2DEVMAC(y);
1465 wxCoord ww = m_signX * XLOG2DEVREL(width);
1466 wxCoord hh = m_signY * YLOG2DEVREL(height);
1467 // CMB: draw nothing if transformed w or h is 0
1468 if (ww == 0 || hh == 0)
1469 return;
1470 // CMB: handle -ve width and/or height
1471 if (ww < 0)
1472 {
1473 ww = -ww;
1474 xx = xx - ww;
1475 }
1476 if (hh < 0)
1477 {
1478 hh = -hh;
1479 yy = yy - hh;
1480 }
20b69855
SC
1481 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1482 path->AddRectangle(xx ,yy , ww , hh ) ;
20b69855
SC
1483 m_graphicContext->DrawPath( path ) ;
1484 delete path ;
613a24f7
SC
1485}
1486
1487void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1488 wxCoord width, wxCoord height,
1489 double radius)
1490{
1491 wxCHECK_RET(Ok(), wxT("Invalid DC"));
08c8555e
SC
1492
1493 if ( m_logicalFunction != wxCOPY )
1494 return ;
1495
1496
613a24f7
SC
1497 if (radius < 0.0)
1498 radius = - radius * ((width < height) ? width : height);
1499 wxCoord xx = XLOG2DEVMAC(x);
1500 wxCoord yy = YLOG2DEVMAC(y);
1501 wxCoord ww = m_signX * XLOG2DEVREL(width);
1502 wxCoord hh = m_signY * YLOG2DEVREL(height);
1503 // CMB: draw nothing if transformed w or h is 0
1504 if (ww == 0 || hh == 0)
1505 return;
1506 // CMB: handle -ve width and/or height
1507 if (ww < 0)
1508 {
1509 ww = -ww;
1510 xx = xx - ww;
1511 }
1512 if (hh < 0)
1513 {
1514 hh = -hh;
1515 yy = yy - hh;
1516 }
20b69855
SC
1517 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1518 CGContextRef ctx = mctx->GetNativeContext() ;
1519 AddRoundedRectToPath( ctx , CGRectMake( xx , yy , ww , hh ) , 16 ,16 ) ;
1520 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
613a24f7
SC
1521}
1522
1523void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1524{
1525 wxCHECK_RET(Ok(), wxT("Invalid DC"));
08c8555e
SC
1526
1527 if ( m_logicalFunction != wxCOPY )
1528 return ;
1529
613a24f7
SC
1530 wxCoord xx = XLOG2DEVMAC(x);
1531 wxCoord yy = YLOG2DEVMAC(y);
1532 wxCoord ww = m_signX * XLOG2DEVREL(width);
1533 wxCoord hh = m_signY * YLOG2DEVREL(height);
1534 // CMB: draw nothing if transformed w or h is 0
1535 if (ww == 0 || hh == 0)
1536 return;
1537 // CMB: handle -ve width and/or height
1538 if (ww < 0)
1539 {
1540 ww = -ww;
1541 xx = xx - ww;
1542 }
1543 if (hh < 0)
1544 {
1545 hh = -hh;
1546 yy = yy - hh;
1547 }
20b69855
SC
1548
1549 wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
1550 CGContextRef ctx = mctx->GetNativeContext() ;
72ba915e
SC
1551 CGContextSaveGState( ctx ) ;
1552 CGContextTranslateCTM( ctx, xx + ww / 2, yy + hh / 2);
1553 CGContextScaleCTM( ctx , ww / 2 , hh / 2 ) ;
1554 CGContextAddArc( ctx, 0, 0, 1, 0 , 2*M_PI , 0);
1555 CGContextRestoreGState( ctx ) ;
1556 CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
613a24f7
SC
1557}
1558
1559bool wxDC::CanDrawBitmap(void) const
1560{
1561 return true ;
1562}
1563
1564bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1565 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1566 wxCoord xsrcMask, wxCoord ysrcMask )
1567{
1568 wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc"));
1569 wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit Illegal source DC"));
1570 if ( logical_func == wxNO_OP )
1571 return TRUE ;
1572 if (xsrcMask == -1 && ysrcMask == -1)
1573 {
1574 xsrcMask = xsrc; ysrcMask = ysrc;
1575 }
20b69855 1576
68654a82
SC
1577 wxCoord yysrc = source->YLOG2DEVMAC(ysrc) ;
1578 wxCoord xxsrc = source->XLOG2DEVMAC(xsrc) ;
1579 wxCoord wwsrc = source->XLOG2DEVREL(width ) ;
1580 wxCoord hhsrc = source->YLOG2DEVREL(height) ;
1581
1582 wxCoord yydest = YLOG2DEVMAC(ydest) ;
1583 wxCoord xxdest = XLOG2DEVMAC(xdest) ;
1584 wxCoord wwdest = XLOG2DEVREL(width ) ;
1585 wxCoord hhdest = YLOG2DEVREL(height) ;
1586
20b69855 1587 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
a8f234d2 1588 if ( memdc && logical_func == wxCOPY )
613a24f7 1589 {
20b69855
SC
1590 wxBitmap blit = memdc->GetSelectedObject() ;
1591 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
1592
20b69855
SC
1593 wxCoord bmpwidth = blit.GetWidth();
1594 wxCoord bmpheight = blit.GetHeight();
1595
68654a82
SC
1596 if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc )
1597 {
1598 wwsrc = wxMin( wwsrc , bmpwidth - xxsrc ) ;
1599 hhsrc = wxMin( hhsrc , bmpheight - yysrc ) ;
1600 if ( wwsrc > 0 && hhsrc > 0 )
1601 {
1602 if ( xxsrc >= 0 && yysrc >= 0 )
1603 {
1604 wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc ) ;
1605 blit = blit.GetSubBitmap( subrect ) ;
1606 }
1607 else
1608 {
1609 // in this case we'd probably have to adjust the different coordinates, but
1610 // we have to find out proper contract first
1611 blit = wxNullBitmap ;
1612 }
1613 }
1614 else
1615 {
1616 blit = wxNullBitmap ;
1617 }
1618 }
1619 if ( blit.Ok() )
613a24f7 1620 {
b60f5ca5 1621 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
68654a82
SC
1622 CGImageRef image = (CGImageRef)( blit.CGImageCreate() ) ;
1623 HIRect r = CGRectMake( xxdest , yydest , wwdest , hhdest ) ;
1624 HIViewDrawCGImage( cg , &r , image ) ;
1625 CGImageRelease( image ) ;
613a24f7 1626 }
20b69855
SC
1627
1628 }
1629 else
1630 {
68654a82 1631 /*
bc8f7aee 1632 CGContextRef cg = (wxMacCGContext*)(source->GetGraphicContext())->GetNativeContext() ;
68654a82
SC
1633 void *data = CGBitmapContextGetData( cg ) ;
1634 */
a8f234d2 1635 return FALSE ; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
613a24f7 1636 }
613a24f7
SC
1637 return TRUE;
1638}
1639
613a24f7
SC
1640void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1641 double angle)
1642{
1643 wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") );
1644
1645 if ( str.Length() == 0 )
1646 return ;
1647
08c8555e
SC
1648 if ( m_logicalFunction != wxCOPY )
1649 return ;
1650
20b69855
SC
1651 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1652
613a24f7
SC
1653 OSStatus status = noErr ;
1654 ATSUTextLayout atsuLayout ;
1655 UniCharCount chars = str.Length() ;
1656 UniChar* ubuf = NULL ;
1657#if SIZEOF_WCHAR_T == 4
d9d488cf 1658 wxMBConvUTF16 converter ;
613a24f7
SC
1659#if wxUSE_UNICODE
1660 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1661 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1662 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1663#else
1664 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1665 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1666 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1667 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1668#endif
1669 chars = unicharlen / 2 ;
1670#else
1671#if wxUSE_UNICODE
1672 ubuf = (UniChar*) str.wc_str() ;
1673#else
1674 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1675 chars = wxWcslen( wchar.data() ) ;
1676 ubuf = (UniChar*) wchar.data() ;
1677#endif
1678#endif
1679
1680 int drawX = XLOG2DEVMAC(x) ;
1681 int drawY = YLOG2DEVMAC(y) ;
1682
613a24f7
SC
1683 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1684 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1685
1686 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
613a24f7 1687
28dd2407
SC
1688 status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
1689 wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
613a24f7 1690
28dd2407 1691 int iAngle = int( angle );
613a24f7
SC
1692 if ( abs(iAngle) > 0 )
1693 {
1694 Fixed atsuAngle = IntToFixed( iAngle ) ;
1695 ATSUAttributeTag atsuTags[] =
1696 {
1697 kATSULineRotationTag ,
1698 } ;
1699 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1700 {
1701 sizeof( Fixed ) ,
1702 } ;
1703 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1704 {
1705 &atsuAngle ,
1706 } ;
1707 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1708 atsuTags, atsuSizes, atsuValues ) ;
1709 }
1710 {
b60f5ca5 1711 CGContextRef cgContext = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
613a24f7
SC
1712 ATSUAttributeTag atsuTags[] =
1713 {
1714 kATSUCGContextTag ,
1715 } ;
1716 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1717 {
1718 sizeof( CGContextRef ) ,
1719 } ;
1720 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1721 {
1722 &cgContext ,
1723 } ;
1724 status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag),
1725 atsuTags, atsuSizes, atsuValues ) ;
1726 }
1727
1728 ATSUTextMeasurement textBefore ;
1729 ATSUTextMeasurement textAfter ;
1730 ATSUTextMeasurement ascent ;
1731 ATSUTextMeasurement descent ;
1732
1733 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1734 &textBefore , &textAfter, &ascent , &descent );
1735 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1736
1737 Rect rect ;
1738
1739 if ( m_backgroundMode == wxSOLID )
1740 {
20b69855
SC
1741 wxGraphicPath* path = m_graphicContext->CreatePath() ;
1742 path->MoveToPoint(
613a24f7
SC
1743 drawX ,
1744 drawY ) ;
20b69855 1745 path->AddLineToPoint(
6cac01a6
RN
1746 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent)) ,
1747 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent)) ) ;
20b69855 1748 path->AddLineToPoint(
6cac01a6
RN
1749 (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1750 (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
20b69855 1751 path->AddLineToPoint(
6cac01a6
RN
1752 (int) (drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
1753 (int) (drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
613a24f7 1754
20b69855
SC
1755 m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
1756 delete path ;
613a24f7
SC
1757 }
1758
1759 drawX += (int)(sin(angle/RAD2DEG) * FixedToInt(ascent));
1760 drawY += (int)(cos(angle/RAD2DEG) * FixedToInt(ascent));
20b69855 1761
613a24f7
SC
1762 status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1763 IntToFixed(drawX) , IntToFixed(drawY) , &rect );
1764 wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1765
b60f5ca5
SC
1766 CGContextSaveGState(((wxMacCGContext*)(m_graphicContext))->GetNativeContext());
1767 CGContextTranslateCTM(((wxMacCGContext*)(m_graphicContext))->GetNativeContext(), drawX, drawY);
1768 CGContextScaleCTM(((wxMacCGContext*)(m_graphicContext))->GetNativeContext(), 1, -1);
613a24f7
SC
1769 status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1770 IntToFixed(0) , IntToFixed(0) );
1771 wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
b60f5ca5 1772 CGContextRestoreGState( ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ) ;
613a24f7
SC
1773
1774 CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
1775 CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
1776
1777 ::ATSUDisposeTextLayout(atsuLayout);
1778#if SIZEOF_WCHAR_T == 4
1779 free( ubuf ) ;
1780#endif
613a24f7
SC
1781}
1782
1783void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
1784{
1785 wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC"));
1786 DoDrawRotatedText( strtext , x , y , 0.0 ) ;
1787}
1788
1789bool wxDC::CanGetTextExtent() const
1790{
1791 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1792 return true ;
1793}
1794
1795void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1796 wxCoord *descent, wxCoord *externalLeading ,
1797 wxFont *theFont ) const
1798{
1799 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1800 wxFont formerFont = m_font ;
1801 if ( theFont )
1802 {
1803 // work around the constness
1804 *((wxFont*)(&m_font)) = *theFont ;
20b69855 1805 MacInstallFont() ;
613a24f7
SC
1806 }
1807
613a24f7
SC
1808 if ( str.Length() == 0 )
1809 return ;
1810
20b69855
SC
1811 wxCHECK_RET( m_macATSUIStyle != NULL , wxT("No valid font set") ) ;
1812
613a24f7
SC
1813 OSStatus status = noErr ;
1814 ATSUTextLayout atsuLayout ;
1815 UniCharCount chars = str.Length() ;
1816 UniChar* ubuf = NULL ;
1817#if SIZEOF_WCHAR_T == 4
d9d488cf 1818 wxMBConvUTF16 converter ;
613a24f7
SC
1819#if wxUSE_UNICODE
1820 size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
1821 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1822 converter.WC2MB( (char*) ubuf , str.wc_str(), unicharlen + 2 ) ;
1823#else
1824 const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1825 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1826 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1827 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1828#endif
1829 chars = unicharlen / 2 ;
1830#else
1831#if wxUSE_UNICODE
1832 ubuf = (UniChar*) str.wc_str() ;
1833#else
1834 wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
1835 chars = wxWcslen( wchar.data() ) ;
1836 ubuf = (UniChar*) wchar.data() ;
1837#endif
1838#endif
1839
613a24f7
SC
1840
1841 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1842 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1843
1844 wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1845
1846 ATSUTextMeasurement textBefore ;
1847 ATSUTextMeasurement textAfter ;
1848 ATSUTextMeasurement textAscent ;
1849 ATSUTextMeasurement textDescent ;
1850
1851 status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1852 &textBefore , &textAfter, &textAscent , &textDescent );
1853
1854 if ( height )
1855 *height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
1856 if ( descent )
1857 *descent =YDEV2LOGREL( FixedToInt(textDescent) );
1858 if ( externalLeading )
1859 *externalLeading = 0 ;
1860 if ( width )
1861 *width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
1862
1863 ::ATSUDisposeTextLayout(atsuLayout);
1864#if SIZEOF_WCHAR_T == 4
1865 free( ubuf ) ;
1866#endif
1867 if ( theFont )
1868 {
1869 // work around the constness
1870 *((wxFont*)(&m_font)) = formerFont ;
20b69855 1871 MacInstallFont() ;
613a24f7
SC
1872 }
1873}
1874
1875
1876bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1877{
1878 wxCHECK_MSG(Ok(), false, wxT("Invalid DC"));
1879
1880 widths.Empty();
1881 widths.Add(0, text.Length());
1882
1883 if (text.Length() == 0)
1884 return false;
1885
764e6694
KO
1886 ATSUTextLayout atsuLayout ;
1887 UniCharCount chars = text.Length() ;
1888 UniChar* ubuf = NULL ;
1889#if SIZEOF_WCHAR_T == 4
d9d488cf 1890 wxMBConvUTF16 converter ;
764e6694
KO
1891#if wxUSE_UNICODE
1892 size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
1893 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1894 converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
1895#else
1896 const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1897 size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
1898 ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
1899 converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
1900#endif
1901 chars = unicharlen / 2 ;
1902#else
1903#if wxUSE_UNICODE
1904 ubuf = (UniChar*) text.wc_str() ;
1905#else
1906 wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
1907 chars = wxWcslen( wchar.data() ) ;
1908 ubuf = (UniChar*) wchar.data() ;
1909#endif
1910#endif
1911
1912 OSStatus status;
1913 status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
1914 &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1915
72ba915e 1916 for ( int pos = 0; pos < (int)chars; pos ++ ) {
764e6694
KO
1917 unsigned long actualNumberOfBounds = 0;
1918 ATSTrapezoid glyphBounds;
1919
1920 // We get a single bound, since the text should only require one. If it requires more, there is an issue
1921 OSStatus result;
1922 result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
1923 if (result != noErr || actualNumberOfBounds != 1 )
1924 {
1925 return false;
1926 }
1927
1928 widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
1929 //unsigned char uch = s[i];
1930
1931 }
1932 ::ATSUDisposeTextLayout(atsuLayout);
1933 return true;
613a24f7
SC
1934}
1935
613a24f7
SC
1936wxCoord wxDC::GetCharWidth(void) const
1937{
1938 wxCoord width ;
1939 DoGetTextExtent(wxT("g") , &width , NULL , NULL , NULL , NULL ) ;
1940 return width ;
1941}
1942
1943wxCoord wxDC::GetCharHeight(void) const
1944{
1945 wxCoord height ;
1946 DoGetTextExtent(wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
1947 return height ;
1948}
1949
1950void wxDC::Clear(void)
1951{
1952 wxCHECK_RET(Ok(), wxT("Invalid DC"));
1953
1954 if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
1955 {
b014adcc 1956 HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
b60f5ca5 1957 CGContextRef cg = ((wxMacCGContext*)(m_graphicContext))->GetNativeContext() ;
613a24f7
SC
1958 switch( m_backgroundBrush.MacGetBrushKind() )
1959 {
1960 case kwxMacBrushTheme :
1961 {
a63b4755
SC
1962#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1963 if ( HIThemeSetFill != 0 )
1964 {
72ba915e 1965 HIThemeSetFill( m_backgroundBrush.MacGetTheme(), NULL, cg, kHIThemeOrientationNormal );
a63b4755
SC
1966 CGContextFillRect(cg, rect);
1967
1968 }
1969 else
1970#endif
1971 {
1972 RGBColor color;
72ba915e
SC
1973 GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme(), 32, true, &color );
1974 CGContextSetRGBFillColor( cg, (float) color.red / 65536,
a63b4755
SC
1975 (float) color.green / 65536, (float) color.blue / 65536, 1 );
1976 CGContextFillRect( cg, rect );
1977 }
72ba915e 1978
a63b4755
SC
1979 // reset to normal value
1980 RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
72ba915e 1981 CGContextSetRGBFillColor( cg, col.red / 65536.0, col.green / 65536.0, col.blue / 65536.0, 1.0 );
613a24f7
SC
1982 }
1983 break ;
1984 case kwxMacBrushThemeBackground :
1985 {
a63b4755 1986 wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
b014adcc 1987#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1688bb38 1988 if ( UMAGetSystemVersion() >= 0x1030 )
b014adcc
SC
1989 {
1990 HIThemeBackgroundDrawInfo drawInfo ;
1991 drawInfo.version = 0 ;
1992 drawInfo.state = kThemeStateActive ;
1993 drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
1994 if ( drawInfo.kind == kThemeBackgroundMetal )
a63b4755 1995 HIThemeDrawBackground( &rect , &drawInfo, cg ,
b014adcc 1996 kHIThemeOrientationNormal) ;
a63b4755 1997 HIThemeApplyBackground( &rect , &drawInfo, cg ,
b014adcc
SC
1998 kHIThemeOrientationNormal) ;
1999 }
a63b4755 2000 else
b014adcc 2001#endif
a63b4755
SC
2002 {
2003 }
613a24f7
SC
2004 }
2005 break ;
2006 case kwxMacBrushColour :
2007 {
2008 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
a63b4755
SC
2009 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
2010 CGContextFillRect(cg, rect);
613a24f7
SC
2011
2012 // reset to normal value
2013 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
a63b4755 2014 CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
613a24f7
SC
2015 }
2016 break ;
2017 }
2018 }
2019}
2020
2021void wxDC::MacInstallFont() const
2022{
2023 wxCHECK_RET(Ok(), wxT("Invalid DC"));
2024
20b69855 2025 if( m_macATSUIStyle )
613a24f7 2026 {
20b69855
SC
2027 ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
2028 m_macATSUIStyle = NULL ;
613a24f7 2029 }
20b69855 2030
68654a82 2031 if ( m_font.Ok() )
613a24f7 2032 {
68654a82
SC
2033 OSStatus status = noErr ;
2034 status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
2035 wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
20b69855 2036
68654a82
SC
2037 Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
2038 RGBColor atsuColor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel() ) ;
2039 ATSUAttributeTag atsuTags[] =
2040 {
2041 kATSUSizeTag ,
2042 kATSUColorTag ,
2043 } ;
2044 ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
2045 {
2046 sizeof( Fixed ) ,
2047 sizeof( RGBColor ) ,
2048 } ;
2049 // Boolean kTrue = true ;
2050 // Boolean kFalse = false ;
613a24f7 2051
68654a82
SC
2052 // ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal;
2053 ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
2054 {
2055 &atsuSize ,
2056 &atsuColor ,
2057 } ;
2058 status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
2059 atsuTags, atsuSizes, atsuValues);
2060
2061 wxASSERT_MSG( status == noErr , wxT("couldn't Modify ATSU style") ) ;
2062 }
613a24f7
SC
2063}
2064
2065// ---------------------------------------------------------------------------
2066// coordinates transformations
2067// ---------------------------------------------------------------------------
2068
2069wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2070{
2071 return ((wxDC *)this)->XDEV2LOG(x);
2072}
2073
2074wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2075{
2076 return ((wxDC *)this)->YDEV2LOG(y);
2077}
2078
2079wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2080{
2081 return ((wxDC *)this)->XDEV2LOGREL(x);
2082}
2083
2084wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2085{
2086 return ((wxDC *)this)->YDEV2LOGREL(y);
2087}
2088
2089wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2090{
2091 return ((wxDC *)this)->XLOG2DEV(x);
2092}
2093
2094wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2095{
2096 return ((wxDC *)this)->YLOG2DEV(y);
2097}
2098
2099wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2100{
2101 return ((wxDC *)this)->XLOG2DEVREL(x);
2102}
2103
2104wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2105{
2106 return ((wxDC *)this)->YLOG2DEVREL(y);
2107}
20b69855
SC
2108
2109#endif // wxMAC_USE_CORE_GRAPHICS
2110