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