1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/mac/carbon/dc.cpp
3// Purpose:     wxDC class
4// Author:      Stefan Csomor
5// Modified by:
6// Created:     01/02/97
7// RCS-ID:      $Id: dc.cpp 53401 2008-04-28 13:46:11Z JS $
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#ifndef WX_PRECOMP
19    #include "wx/log.h"
20    #include "wx/app.h"
21    #include "wx/dcmemory.h"
22    #include "wx/dcprint.h"
23    #include "wx/region.h"
24    #include "wx/image.h"
25#endif
26
27#include "wx/mac/uma.h"
28
29#ifdef __MSL__
30    #if __MSL__ >= 0x6000
31        namespace std {}
32        using namespace std ;
33    #endif
34#endif
35
36#include "wx/mac/private.h"
37#ifndef __DARWIN__
38#include <ATSUnicode.h>
39#include <TextCommon.h>
40#include <TextEncodingConverter.h>
41#endif
42
43
44// set to 0 if problems arise
45#define wxMAC_EXPERIMENTAL_DC 1
46
47
48IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
49
50//-----------------------------------------------------------------------------
51// constants
52//-----------------------------------------------------------------------------
53
54const double RAD2DEG  = 180.0 / M_PI;
55const short kEmulatedMode = -1 ;
56const short kUnsupportedMode = -2 ;
57
58wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
59    m_ph( (GrafPtr) dc->m_macPort )
60{
61    wxASSERT( dc->Ok() ) ;
62    m_dc = dc ;
63    dc->MacSetupPort(&m_ph) ;
64}
65
66wxMacPortSetter::~wxMacPortSetter()
67{
68    m_dc->MacCleanupPort(&m_ph) ;
69}
70
71#if wxMAC_EXPERIMENTAL_DC
72class wxMacFastPortSetter
73{
74public :
75    wxMacFastPortSetter( const wxDC *dc )
76    {
77        wxASSERT( dc->Ok() ) ;
78        m_swapped = QDSwapPort( (GrafPtr) dc->m_macPort , &m_oldPort ) ;
79        m_clipRgn = NewRgn() ;
80        GetClip( m_clipRgn ) ;
81        m_dc = dc ;
82        dc->MacSetupPort( NULL ) ;
83    }
84
85    ~wxMacFastPortSetter()
86    {
87        // SetPort( (GrafPtr) m_dc->m_macPort ) ;
88        SetClip( m_clipRgn ) ;
89        if ( m_swapped )
90            SetPort( m_oldPort ) ;
91        m_dc->MacCleanupPort( NULL ) ;
92        DisposeRgn( m_clipRgn ) ;
93    }
94
95private :
96    bool m_swapped ;
97    RgnHandle m_clipRgn ;
98    GrafPtr m_oldPort ;
99    const wxDC*   m_dc ;
100} ;
101
102#else
103typedef wxMacPortSetter wxMacFastPortSetter ;
104#endif
105
106wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
107    wxMacPortSaver( (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) )
108{
109    m_newPort =(GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
110    m_formerClip = NewRgn() ;
111    m_newClip = NewRgn() ;
112    GetClip( m_formerClip ) ;
113
114    if ( win )
115    {
116        // guard against half constructed objects, this just leads to a empty clip
117        if ( win->GetPeer() )
118        {
119            int x = 0 , y = 0;
120            win->MacWindowToRootWindow( &x, &y ) ;
121
122            // get area including focus rect
123            CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip ) ;
124            if ( !EmptyRgn( m_newClip ) )
125                OffsetRgn( m_newClip , x , y ) ;
126        }
127
128        SetClip( m_newClip ) ;
129    }
130}
131
132wxMacWindowClipper::~wxMacWindowClipper()
133{
134    SetPort( m_newPort ) ;
135    SetClip( m_formerClip ) ;
136    DisposeRgn( m_newClip ) ;
137    DisposeRgn( m_formerClip ) ;
138}
139
140wxMacWindowStateSaver::wxMacWindowStateSaver( const wxWindow* win ) :
141    wxMacWindowClipper( win )
142{
143    // the port is already set at this point
144    m_newPort = (GrafPtr) GetWindowPort((WindowRef) win->MacGetTopLevelWindowRef()) ;
145    GetThemeDrawingState( &m_themeDrawingState ) ;
146}
147
148wxMacWindowStateSaver::~wxMacWindowStateSaver()
149{
150    SetPort( m_newPort ) ;
151    SetThemeDrawingState( m_themeDrawingState , true ) ;
152}
153
154//-----------------------------------------------------------------------------
155// wxDC
156//-----------------------------------------------------------------------------
157// this function emulates all wx colour manipulations, used to verify the implementation
158// by setting the mode in the blitting functions to kEmulatedMode
159void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor ) ;
160
161void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor )
162{
163    switch ( logical_func )
164    {
165        case wxAND:        // src AND dst
166            dstColor.red = dstColor.red & srcColor.red ;
167            dstColor.green = dstColor.green & srcColor.green ;
168            dstColor.blue = dstColor.blue & srcColor.blue ;
169            break ;
170
171        case wxAND_INVERT: // (NOT src) AND dst
172            dstColor.red = dstColor.red & ~srcColor.red ;
173            dstColor.green = dstColor.green & ~srcColor.green ;
174            dstColor.blue = dstColor.blue & ~srcColor.blue ;
175            break ;
176
177        case wxAND_REVERSE:// src AND (NOT dst)
178            dstColor.red = ~dstColor.red & srcColor.red ;
179            dstColor.green = ~dstColor.green & srcColor.green ;
180            dstColor.blue = ~dstColor.blue & srcColor.blue ;
181            break ;
182
183        case wxCLEAR:      // 0
184            dstColor.red = 0 ;
185            dstColor.green = 0 ;
186            dstColor.blue = 0 ;
187            break ;
188
189        case wxCOPY:       // src
190            dstColor.red = srcColor.red ;
191            dstColor.green = srcColor.green ;
192            dstColor.blue = srcColor.blue ;
193            break ;
194
195        case wxEQUIV:      // (NOT src) XOR dst
196            dstColor.red = dstColor.red ^ ~srcColor.red ;
197            dstColor.green = dstColor.green ^ ~srcColor.green ;
198            dstColor.blue = dstColor.blue ^ ~srcColor.blue ;
199            break ;
200
201        case wxINVERT:     // NOT dst
202            dstColor.red = ~dstColor.red ;
203            dstColor.green = ~dstColor.green ;
204            dstColor.blue = ~dstColor.blue ;
205            break ;
206
207        case wxNAND:       // (NOT src) OR (NOT dst)
208            dstColor.red = ~dstColor.red | ~srcColor.red ;
209            dstColor.green = ~dstColor.green | ~srcColor.green ;
210            dstColor.blue = ~dstColor.blue | ~srcColor.blue ;
211            break ;
212
213        case wxNOR:        // (NOT src) AND (NOT dst)
214            dstColor.red = ~dstColor.red & ~srcColor.red ;
215            dstColor.green = ~dstColor.green & ~srcColor.green ;
216            dstColor.blue = ~dstColor.blue & ~srcColor.blue ;
217            break ;
218
219        case wxOR:         // src OR dst
220            dstColor.red = dstColor.red | srcColor.red ;
221            dstColor.green = dstColor.green | srcColor.green ;
222            dstColor.blue = dstColor.blue | srcColor.blue ;
223            break ;
224
225        case wxOR_INVERT:  // (NOT src) OR dst
226            dstColor.red = dstColor.red | ~srcColor.red ;
227            dstColor.green = dstColor.green | ~srcColor.green ;
228            dstColor.blue = dstColor.blue | ~srcColor.blue ;
229            break ;
230
231        case wxOR_REVERSE: // src OR (NOT dst)
232            dstColor.red = ~dstColor.red | srcColor.red ;
233            dstColor.green = ~dstColor.green | srcColor.green ;
234            dstColor.blue = ~dstColor.blue | srcColor.blue ;
235            break ;
236
237        case wxSET:        // 1
238            dstColor.red = 0xFFFF ;
239            dstColor.green = 0xFFFF ;
240            dstColor.blue = 0xFFFF ;
241            break ;
242
243        case wxSRC_INVERT: // (NOT src)
244            dstColor.red = ~srcColor.red ;
245            dstColor.green = ~srcColor.green ;
246            dstColor.blue = ~srcColor.blue ;
247            break ;
248
249        case wxXOR:        // src XOR dst
250            dstColor.red = dstColor.red ^ srcColor.red ;
251            dstColor.green = dstColor.green ^ srcColor.green ;
252            dstColor.blue = dstColor.blue ^ srcColor.blue ;
253            break ;
254
255        case wxNO_OP:      // dst
256        default:
257            break ;
258    }
259}
260
261wxDC::wxDC()
262{
263    m_ok = false;
264    m_colour = true;
265    m_mm_to_pix_x = mm2pt;
266    m_mm_to_pix_y = mm2pt;
267    m_internalDeviceOriginX = 0;
268    m_internalDeviceOriginY = 0;
269    m_externalDeviceOriginX = 0;
270    m_externalDeviceOriginY = 0;
271    m_logicalScaleX = 1.0;
272    m_logicalScaleY = 1.0;
273    m_userScaleX = 1.0;
274    m_userScaleY = 1.0;
275    m_scaleX = 1.0;
276    m_scaleY = 1.0;
277    m_needComputeScaleX = false;
278    m_needComputeScaleY = false;
279    m_macPort = NULL ;
280    m_macMask = NULL ;
281    m_macFontInstalled = false ;
282    m_macBrushInstalled = false ;
283    m_macPenInstalled = false ;
284    m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
285    m_macBoundaryClipRgn = NewRgn() ;
286    m_macCurrentClipRgn = NewRgn() ;
287    SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , -32000 , -32000 , 32000 , 32000 ) ;
288    SetRectRgn( (RgnHandle) m_macCurrentClipRgn , -32000 , -32000 , 32000 , 32000 ) ;
289    m_pen = *wxBLACK_PEN;
290    m_font = *wxNORMAL_FONT;
291    m_brush = *wxWHITE_BRUSH;
292
293#ifdef __WXDEBUG__
294    // needed to debug possible errors with two active drawing methods at the same time on
295    // the same DC
296    m_macCurrentPortStateHelper = NULL ;
297#endif
298
299    m_macATSUIStyle = NULL ;
300    m_macAliasWasEnabled = false;
301    m_macForegroundPixMap = NULL ;
302    m_macBackgroundPixMap = NULL ;
303}
304
305wxDC::~wxDC(void)
306{
307    DisposeRgn( (RgnHandle) m_macBoundaryClipRgn ) ;
308    DisposeRgn( (RgnHandle) m_macCurrentClipRgn ) ;
309}
310
311void wxDC::MacSetupPort(wxMacPortStateHelper* help) const
312{
313#ifdef __WXDEBUG__
314    wxASSERT( m_macCurrentPortStateHelper == NULL ) ;
315    m_macCurrentPortStateHelper = help ;
316#endif
317
318    SetClip( (RgnHandle) m_macCurrentClipRgn);
319
320#if ! wxMAC_EXPERIMENTAL_DC
321    m_macFontInstalled = false ;
322    m_macBrushInstalled = false ;
323    m_macPenInstalled = false ;
324#endif
325}
326
327void wxDC::MacCleanupPort(wxMacPortStateHelper* help) const
328{
329#ifdef __WXDEBUG__
330    wxASSERT( m_macCurrentPortStateHelper == help ) ;
331    m_macCurrentPortStateHelper = NULL ;
332#endif
333
334    if ( m_macATSUIStyle )
335    {
336        ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle);
337        m_macATSUIStyle = NULL ;
338    }
339
340    if ( m_macAliasWasEnabled )
341    {
342        SetAntiAliasedTextEnabled(m_macFormerAliasState, m_macFormerAliasSize);
343        m_macAliasWasEnabled = false ;
344    }
345
346    if ( m_macForegroundPixMap )
347    {
348        Pattern blackColor ;
349        ::PenPat(GetQDGlobalsBlack(&blackColor));
350        DisposePixPat( (PixPatHandle) m_macForegroundPixMap ) ;
351        m_macForegroundPixMap = NULL ;
352    }
353
354    if ( m_macBackgroundPixMap )
355    {
356        Pattern whiteColor ;
357        ::BackPat(GetQDGlobalsWhite(&whiteColor));
358        DisposePixPat( (PixPatHandle) m_macBackgroundPixMap ) ;
359        m_macBackgroundPixMap = NULL ;
360    }
361}
362
363void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
364{
365     wxCHECK_RET( Ok(), wxT("wxDC::DoDrawBitmap - invalid DC") );
366     wxCHECK_RET( bmp.Ok(), wxT("wxDC::DoDrawBitmap - invalid bitmap") );
367
368     wxMacFastPortSetter helper(this) ;
369     wxCoord xx = XLOG2DEVMAC(x);
370     wxCoord yy = YLOG2DEVMAC(y);
371     wxCoord w = bmp.GetWidth();
372     wxCoord h = bmp.GetHeight();
373     wxCoord ww = XLOG2DEVREL(w);
374     wxCoord hh = YLOG2DEVREL(h);
375
376     // Set up drawing mode
377     short  mode = (m_logicalFunction == wxCOPY ? srcCopy :
378                    //m_logicalFunction == wxCLEAR ? WHITENESS :
379                    //m_logicalFunction == wxSET ? BLACKNESS :
380                    m_logicalFunction == wxINVERT ? hilite :
381                   //m_logicalFunction == wxAND ? MERGECOPY :
382                    m_logicalFunction == wxOR ? srcOr :
383                    m_logicalFunction == wxSRC_INVERT ? notSrcCopy :
384                    m_logicalFunction == wxXOR ? srcXor :
385                    m_logicalFunction == wxOR_REVERSE ? notSrcOr :
386                    //m_logicalFunction == wxAND_REVERSE ? SRCERASE :
387                    //m_logicalFunction == wxSRC_OR ? srcOr :
388                    //m_logicalFunction == wxSRC_AND ? SRCAND :
389                    srcCopy );
390
391     GWorldPtr maskworld = NULL ;
392     GWorldPtr bmapworld = MAC_WXHBITMAP( bmp.GetHBITMAP((WXHBITMAP*)&maskworld) );
393     PixMapHandle bmappixels ;
394
395     // Set foreground and background colours (for bitmaps depth = 1)
396     if (bmp.GetDepth() == 1)
397     {
398         RGBColor fore = MAC_WXCOLORREF(m_textForegroundColour.GetPixel());
399         RGBColor back = MAC_WXCOLORREF(m_textBackgroundColour.GetPixel());
400         RGBForeColor(&fore);
401         RGBBackColor(&back);
402     }
403     else
404     {
405         RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF } ;
406         RGBColor black = { 0, 0, 0 } ;
407         RGBForeColor( &black ) ;
408         RGBBackColor( &white ) ;
409     }
410     bmappixels = GetGWorldPixMap( bmapworld ) ;
411
412     wxCHECK_RET(LockPixels(bmappixels),
413                 wxT("wxDC::DoDrawBitmap - failed to lock pixels"));
414
415     Rect source = { 0, 0, h, w };
416     Rect dest   = { yy, xx, yy + hh, xx + ww };
417     if ( useMask && maskworld )
418     {
419         if ( LockPixels(GetGWorldPixMap(MAC_WXHBITMAP(maskworld))))
420         {
421             CopyDeepMask
422                 (
423                  GetPortBitMapForCopyBits(bmapworld),
424                  GetPortBitMapForCopyBits(MAC_WXHBITMAP(maskworld)),
425                  GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ),
426                  &source, &source, &dest, mode, NULL
427                  );
428             UnlockPixels(GetGWorldPixMap(MAC_WXHBITMAP(maskworld)));
429         }
430     }
431     else
432     {
433         CopyBits( GetPortBitMapForCopyBits( bmapworld ),
434                   GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ),
435                   &source, &dest, mode, NULL ) ;
436     }
437     UnlockPixels( bmappixels ) ;
438
439     m_macPenInstalled = false ;
440     m_macBrushInstalled = false ;
441     m_macFontInstalled = false ;
442}
443
444void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
445{
446    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawIcon - invalid DC"));
447    wxCHECK_RET(icon.Ok(), wxT("wxDC::DoDrawIcon - invalid icon"));
448
449    wxMacFastPortSetter helper(this) ;
450
451    wxCoord xx = XLOG2DEVMAC(x);
452    wxCoord yy = YLOG2DEVMAC(y);
453    wxCoord w = icon.GetWidth();
454    wxCoord h = icon.GetHeight();
455    wxCoord ww = XLOG2DEVREL(w);
456    wxCoord hh = YLOG2DEVREL(h);
457
458    Rect r = { yy , xx, yy + hh, xx + ww } ;
459    PlotIconRef( &r , kAlignNone , kTransformNone , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ) ;
460}
461
462void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
463{
464    wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion - invalid DC"));
465
466    wxCoord xx, yy, ww, hh;
467    xx = XLOG2DEVMAC(x);
468    yy = YLOG2DEVMAC(y);
469    ww = XLOG2DEVREL(width);
470    hh = YLOG2DEVREL(height);
471
472    SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
473    SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
474    if ( m_clipping )
475    {
476        m_clipX1 = wxMax( m_clipX1 , xx );
477        m_clipY1 = wxMax( m_clipY1 , yy );
478        m_clipX2 = wxMin( m_clipX2, (xx + ww) );
479        m_clipY2 = wxMin( m_clipY2, (yy + hh) );
480    }
481    else
482    {
483        m_clipping = true;
484        m_clipX1 = xx;
485        m_clipY1 = yy;
486        m_clipX2 = xx + ww;
487        m_clipY2 = yy + hh;
488    }
489}
490
491void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region )
492{
493    wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegionAsRegion - invalid DC"));
494
495    wxMacFastPortSetter helper(this) ;
496    wxCoord x, y, w, h;
497    region.GetBox( x, y, w, h );
498    wxCoord xx, yy, ww, hh;
499    xx = XLOG2DEVMAC(x);
500    yy = YLOG2DEVMAC(y);
501    ww = XLOG2DEVREL(w);
502    hh = YLOG2DEVREL(h);
503
504    // if we have a scaling that we cannot map onto native regions
505    // we must use the box
506    if ( ww != w || hh != h )
507    {
508        wxDC::DoSetClippingRegion( x, y, w, h );
509    }
510    else
511    {
512        CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ;
513        if ( xx != x || yy != y )
514            OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ;
515
516        SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
517        if ( m_clipping )
518        {
519            m_clipX1 = wxMax( m_clipX1 , xx );
520            m_clipY1 = wxMax( m_clipY1 , yy );
521            m_clipX2 = wxMin( m_clipX2, (xx + ww) );
522            m_clipY2 = wxMin( m_clipY2, (yy + hh) );
523        }
524        else
525        {
526            m_clipping = true;
527            m_clipX1 = xx;
528            m_clipY1 = yy;
529            m_clipX2 = xx + ww;
530            m_clipY2 = yy + hh;
531        }
532    }
533}
534
535void wxDC::DestroyClippingRegion()
536{
537    wxMacFastPortSetter helper(this) ;
538
539    CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
540    ResetClipping();
541}
542
543void wxDC::DoGetSizeMM( int* width, int* height ) const
544{
545    int w = 0, h = 0;
546
547    GetSize( &w, &h );
548    if (width)
549        *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) );
550    if (height)
551        *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) );
552}
553
554void wxDC::SetTextForeground( const wxColour &col )
555{
556    wxCHECK_RET(Ok(), wxT("wxDC::SetTextForeground - invalid DC"));
557
558    m_textForegroundColour = col;
559    m_macFontInstalled = false ;
560}
561
562void wxDC::SetTextBackground( const wxColour &col )
563{
564    wxCHECK_RET(Ok(), wxT("wxDC::SetTextBackground - invalid DC"));
565
566    m_textBackgroundColour = col;
567    m_macFontInstalled = false ;
568}
569
570void wxDC::SetMapMode( int mode )
571{
572    switch (mode)
573    {
574    case wxMM_TWIPS:
575        SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y );
576        break;
577
578    case wxMM_POINTS:
579        SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y );
580        break;
581
582    case wxMM_METRIC:
583        SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
584        break;
585
586    case wxMM_LOMETRIC:
587        SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 );
588        break;
589
590    default:
591    case wxMM_TEXT:
592        SetLogicalScale( 1.0, 1.0 );
593        break;
594    }
595
596    if (mode != wxMM_TEXT)
597    {
598        m_needComputeScaleX = true;
599        m_needComputeScaleY = true;
600    }
601}
602
603void wxDC::SetUserScale( double x, double y )
604{
605    // allow negative ? -> no
606    m_userScaleX = x;
607    m_userScaleY = y;
608    ComputeScaleAndOrigin();
609}
610
611void wxDC::SetLogicalScale( double x, double y )
612{
613    // allow negative ?
614    m_logicalScaleX = x;
615    m_logicalScaleY = y;
616    ComputeScaleAndOrigin();
617}
618
619void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
620{
621    // is this still correct ?
622    m_logicalOriginX = x * m_signX;
623    m_logicalOriginY = y * m_signY;
624    ComputeScaleAndOrigin();
625}
626
627void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
628{
629    m_externalDeviceOriginX = x;
630    m_externalDeviceOriginY = y;
631    ComputeScaleAndOrigin();
632}
633
634void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
635{
636    m_signX = (xLeftRight ?  1 : -1);
637    m_signY = (yBottomUp  ? -1 :  1);
638    ComputeScaleAndOrigin();
639}
640
641wxSize wxDC::GetPPI() const
642{
643    return wxSize(72, 72);
644}
645
646int wxDC::GetDepth() const
647{
648    if ( IsPortColor( (CGrafPtr) m_macPort ) )
649        return ( (**GetPortPixMap( (CGrafPtr) m_macPort)).pixelSize ) ;
650
651    return 1 ;
652}
653
654void wxDC::ComputeScaleAndOrigin()
655{
656    // CMB: copy scale to see if it changes
657    double origScaleX = m_scaleX;
658    double origScaleY = m_scaleY;
659    m_scaleX = m_logicalScaleX * m_userScaleX;
660    m_scaleY = m_logicalScaleY * m_userScaleY;
661    m_deviceOriginX = m_internalDeviceOriginX + m_externalDeviceOriginX;
662    m_deviceOriginY = m_internalDeviceOriginY + m_externalDeviceOriginY;
663
664    // CMB: if scale has changed call SetPen to recalulate the line width
665    if (m_scaleX != origScaleX || m_scaleY != origScaleY)
666    {
667        // this is a bit artificial, but we need to force wxDC to think
668        // the pen has changed
669        wxPen pen(GetPen());
670        m_pen = wxNullPen;
671        SetPen(pen);
672    }
673}
674
675void wxDC::SetPalette( const wxPalette& palette )
676{
677}
678
679void wxDC::SetBackgroundMode( int mode )
680{
681    m_backgroundMode = mode ;
682}
683
684void wxDC::SetFont( const wxFont &font )
685{
686    m_font = font;
687    m_macFontInstalled = false ;
688}
689
690void wxDC::SetPen( const wxPen &pen )
691{
692    if ( m_pen == pen )
693        return ;
694
695    m_pen = pen;
696    m_macPenInstalled = false ;
697}
698
699void wxDC::SetBrush( const wxBrush &brush )
700{
701    if (m_brush == brush)
702        return;
703
704    m_brush = brush;
705    m_macBrushInstalled = false ;
706}
707
708void wxDC::SetBackground( const wxBrush &brush )
709{
710    if (m_backgroundBrush == brush)
711        return;
712
713    m_backgroundBrush = brush;
714    if (m_backgroundBrush.Ok())
715        m_macBrushInstalled = false ;
716}
717
718void wxDC::SetLogicalFunction( int function )
719{
720    if (m_logicalFunction == function)
721        return;
722
723    m_logicalFunction = function ;
724    m_macFontInstalled = false ;
725    m_macBrushInstalled = false ;
726    m_macPenInstalled = false ;
727}
728
729extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
730                          const wxColour & col, int style);
731
732bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
733                       const wxColour& col, int style)
734{
735    return wxDoFloodFill(this, x, y, col, style);
736}
737
738bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
739{
740    wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel - invalid DC") );
741
742    wxMacFastPortSetter helper(this) ;
743
744    // NOTE: Get/SetCPixel are slow!
745    RGBColor colour;
746    GetCPixel( XLOG2DEVMAC(x), YLOG2DEVMAC(y), &colour );
747
748    // convert from Mac colour to wx
749    col->Set( colour.red >> 8, colour.green >> 8, colour.blue >> 8);
750
751    return true ;
752}
753
754void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
755{
756    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawLine - invalid DC"));
757
758    wxMacFastPortSetter helper(this) ;
759
760    if (m_pen.GetStyle() != wxTRANSPARENT)
761    {
762        MacInstallPen() ;
763        wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 :
764            m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2;
765        wxCoord xx1 = XLOG2DEVMAC(x1) - offset;
766        wxCoord yy1 = YLOG2DEVMAC(y1) - offset;
767        wxCoord xx2 = XLOG2DEVMAC(x2) - offset;
768        wxCoord yy2 = YLOG2DEVMAC(y2) - offset;
769
770        if ((m_pen.GetCap() == wxCAP_ROUND) &&
771            (m_pen.GetWidth() <= 1))
772        {
773            // Implement LAST_NOT for MAC at least for
774            // orthogonal lines. RR.
775            if (xx1 == xx2)
776            {
777                if (yy1 < yy2)
778                    yy2--;
779                if (yy1 > yy2)
780                    yy2++;
781            }
782
783            if (yy1 == yy2)
784            {
785                if (xx1 < xx2)
786                    xx2--;
787                if (xx1 > xx2)
788                    xx2++;
789            }
790        }
791
792        ::MoveTo(xx1, yy1);
793        ::LineTo(xx2, yy2);
794    }
795}
796
797void wxDC::DoCrossHair( wxCoord x, wxCoord y )
798{
799    wxCHECK_RET(Ok(), wxT("wxDC::DoCrossHair - invalid DC"));
800
801    wxMacFastPortSetter helper(this) ;
802
803    if (m_pen.GetStyle() != wxTRANSPARENT)
804    {
805        int w = 0, h = 0;
806
807        GetSize( &w, &h );
808        wxCoord xx = XLOG2DEVMAC(x);
809        wxCoord yy = YLOG2DEVMAC(y);
810
811        MacInstallPen();
812        ::MoveTo( XLOG2DEVMAC(0), yy );
813        ::LineTo( XLOG2DEVMAC(w), yy );
814        ::MoveTo( xx, YLOG2DEVMAC(0) );
815        ::LineTo( xx, YLOG2DEVMAC(h) );
816        CalcBoundingBox(x, y);
817        CalcBoundingBox(x + w, y + h);
818    }
819}
820
821/*
822* To draw arcs properly the angles need to be converted from the WX style:
823* Angles start on the +ve X axis and go anti-clockwise (As you would draw on
824* a normal axis on paper).
825* TO
826* the Mac style:
827* Angles start on the +ve y axis and go clockwise.
828*/
829
830static double wxConvertWXangleToMACangle(double angle)
831{
832    double newAngle = 90 - angle ;
833
834    while ( newAngle > 360 )
835        newAngle -= 360 ;
836    while ( newAngle < 0 )
837        newAngle += 360 ;
838
839    return newAngle ;
840}
841
842void wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
843                      wxCoord x2, wxCoord y2,
844                      wxCoord xc, wxCoord yc )
845{
846    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc - invalid DC"));
847
848    wxMacFastPortSetter helper(this) ;
849
850    wxCoord xx1 = XLOG2DEVMAC(x1);
851    wxCoord yy1 = YLOG2DEVMAC(y1);
852    wxCoord xx2 = XLOG2DEVMAC(x2);
853    wxCoord yy2 = YLOG2DEVMAC(y2);
854    wxCoord xxc = XLOG2DEVMAC(xc);
855    wxCoord yyc = YLOG2DEVMAC(yc);
856
857    double dx = xx1 - xxc;
858    double dy = yy1 - yyc;
859    double radius = sqrt((double)(dx * dx + dy * dy));
860    wxCoord rad = (wxCoord)radius;
861    double radius1, radius2;
862
863    if (xx1 == xx2 && yy1 == yy2)
864    {
865        radius1 = 0.0;
866        radius2 = 360.0;
867    }
868    else if (radius == 0.0)
869    {
870        radius1 = radius2 = 0.0;
871    }
872    else
873    {
874        radius1 = (xx1 - xxc == 0) ?
875            (yy1 - yyc < 0) ? 90.0 : -90.0 :
876        -atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG;
877        radius2 = (xx2 - xxc == 0) ?
878            (yy2 - yyc < 0) ? 90.0 : -90.0 :
879        -atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG;
880    }
881
882    wxCoord alpha2 = wxCoord(radius2 - radius1);
883    wxCoord alpha1 = wxCoord(wxConvertWXangleToMACangle(radius1));
884    while ( alpha2 < 0 )
885        alpha2 += 360 ;
886    alpha2 = -alpha2 ;
887    Rect r = { yyc - rad, xxc - rad, yyc + rad, xxc + rad };
888
889    if (m_brush.GetStyle() != wxTRANSPARENT)
890    {
891        MacInstallBrush();
892        PaintArc(&r, alpha1, alpha2);
893    }
894
895    if (m_pen.GetStyle() != wxTRANSPARENT)
896    {
897        MacInstallPen();
898        FrameArc(&r, alpha1, alpha2);
899    }
900}
901
902void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
903                              double sa, double ea )
904{
905    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc - invalid DC"));
906    wxMacFastPortSetter helper(this) ;
907    Rect r;
908
909    // Order important Mac in opposite direction to wx
910    // we have to make sure that the filling is always counter-clockwise
911    double angle = sa - ea;
912    if ( angle > 0 )
913        angle -= 360 ;
914
915    wxCoord xx = XLOG2DEVMAC(x);
916    wxCoord yy = YLOG2DEVMAC(y);
917    wxCoord ww = m_signX * XLOG2DEVREL(w);
918    wxCoord hh = m_signY * YLOG2DEVREL(h);
919
920    // handle -ve width and/or height
921    if (ww < 0)
922    {
923        ww = -ww;
924        xx = xx - ww;
925    }
926
927    if (hh < 0)
928    {
929        hh = -hh;
930        yy = yy - hh;
931    }
932
933    sa = wxConvertWXangleToMACangle(sa);
934    r.top    = yy;
935    r.left   = xx;
936    r.bottom = yy + hh;
937    r.right  = xx + ww;
938
939    if (m_brush.GetStyle() != wxTRANSPARENT)
940    {
941        MacInstallBrush();
942        PaintArc(&r, (short)sa, (short)angle);
943    }
944
945    if (m_pen.GetStyle() != wxTRANSPARENT)
946    {
947        MacInstallPen();
948        FrameArc(&r, (short)sa, (short)angle);
949    }
950}
951
952void wxDC::DoDrawPoint( wxCoord x, wxCoord y )
953{
954    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawPoint - invalid DC"));
955
956    wxMacFastPortSetter helper(this) ;
957
958    if (m_pen.GetStyle() != wxTRANSPARENT)
959    {
960        wxCoord xx1 = XLOG2DEVMAC(x);
961        wxCoord yy1 = YLOG2DEVMAC(y);
962        RGBColor pencolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel());
963
964        // NOTE: Get/SetCPixel are slow!
965        ::SetCPixel( xx1, yy1, &pencolor) ;
966        CalcBoundingBox(x, y);
967    }
968}
969
970void wxDC::DoDrawLines(int n, wxPoint points[],
971                        wxCoord xoffset, wxCoord yoffset)
972{
973    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawLines - invalid DC"));
974
975    if (m_pen.GetStyle() == wxTRANSPARENT)
976        return;
977
978    wxMacFastPortSetter helper(this) ;
979
980    MacInstallPen() ;
981    wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 :
982    m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2 ;
983
984    wxCoord x1, x2 , y1 , y2 ;
985    x1 = XLOG2DEVMAC(points[0].x + xoffset);
986    y1 = YLOG2DEVMAC(points[0].y + yoffset);
987
988    ::MoveTo( x1 - offset, y1 - offset );
989    for (int i = 0; i < n-1; i++)
990    {
991        x2 = XLOG2DEVMAC(points[i + 1].x + xoffset);
992        y2 = YLOG2DEVMAC(points[i + 1].y + yoffset);
993        ::LineTo( x2 - offset, y2 - offset );
994    }
995}
996
997void wxDC::DoDrawPolygon(int n, wxPoint points[],
998                          wxCoord xoffset, wxCoord yoffset,
999                          int fillStyle )
1000{
1001    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawPolygon - invalid DC"));
1002
1003    if ( m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT )
1004        return ;
1005
1006    wxMacFastPortSetter helper(this) ;
1007
1008    wxCoord x1, x2 , y1 , y2 ;
1009    PolyHandle polygon = OpenPoly();
1010    x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset);
1011    y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset);
1012
1013    ::MoveTo(x1, y1);
1014    for (int i = 1; i < n; i++)
1015    {
1016        x2 = XLOG2DEVMAC(points[i].x + xoffset);
1017        y2 = YLOG2DEVMAC(points[i].y + yoffset);
1018        ::LineTo(x2, y2);
1019    }
1020
1021    // close the polyline if necessary
1022    if ( x1 != x2 || y1 != y2 )
1023        ::LineTo( x1, y1 ) ;
1024    ClosePoly();
1025
1026    if (m_brush.GetStyle() != wxTRANSPARENT)
1027    {
1028        MacInstallBrush();
1029        ::PaintPoly( polygon );
1030    }
1031
1032    if (m_pen.GetStyle() != wxTRANSPARENT)
1033    {
1034        MacInstallPen() ;
1035        ::FramePoly( polygon ) ;
1036    }
1037
1038    KillPoly( polygon );
1039}
1040
1041void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1042{
1043    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawRectangle - invalid DC"));
1044
1045    wxMacFastPortSetter helper(this) ;
1046
1047    wxCoord xx = XLOG2DEVMAC(x);
1048    wxCoord yy = YLOG2DEVMAC(y);
1049    wxCoord ww = m_signX * XLOG2DEVREL(width);
1050    wxCoord hh = m_signY * YLOG2DEVREL(height);
1051
1052    // CMB: draw nothing if transformed w or h is 0
1053    if (ww == 0 || hh == 0)
1054        return;
1055
1056    // CMB: handle -ve width and/or height
1057    if (ww < 0)
1058    {
1059        ww = -ww;
1060        xx = xx - ww;
1061    }
1062
1063    if (hh < 0)
1064    {
1065        hh = -hh;
1066        yy = yy - hh;
1067    }
1068
1069    Rect rect = { yy , xx , yy + hh , xx + ww } ;
1070
1071    if (m_brush.GetStyle() != wxTRANSPARENT)
1072    {
1073        MacInstallBrush() ;
1074        ::PaintRect( &rect ) ;
1075    }
1076
1077    if (m_pen.GetStyle() != wxTRANSPARENT)
1078    {
1079        MacInstallPen() ;
1080        ::FrameRect( &rect ) ;
1081    }
1082}
1083
1084void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1085                                   wxCoord width, wxCoord height,
1086                                   double radius)
1087{
1088    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawRoundedRectangle - invalid DC"));
1089
1090    wxMacFastPortSetter helper(this) ;
1091    if (radius < 0.0)
1092        radius = - radius * ((width < height) ? width : height);
1093    wxCoord xx = XLOG2DEVMAC(x);
1094    wxCoord yy = YLOG2DEVMAC(y);
1095    wxCoord ww = m_signX * XLOG2DEVREL(width);
1096    wxCoord hh = m_signY * YLOG2DEVREL(height);
1097
1098    // CMB: draw nothing if transformed w or h is 0
1099    if (ww == 0 || hh == 0)
1100        return;
1101
1102    // CMB: handle -ve width and/or height
1103    if (ww < 0)
1104    {
1105        ww = -ww;
1106        xx = xx - ww;
1107    }
1108
1109    if (hh < 0)
1110    {
1111        hh = -hh;
1112        yy = yy - hh;
1113    }
1114
1115    Rect rect = { yy , xx , yy + hh , xx + ww } ;
1116
1117    if (m_brush.GetStyle() != wxTRANSPARENT)
1118    {
1119        MacInstallBrush() ;
1120        ::PaintRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ;
1121    }
1122
1123    if (m_pen.GetStyle() != wxTRANSPARENT)
1124    {
1125        MacInstallPen() ;
1126        ::FrameRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ;
1127    }
1128}
1129
1130void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1131{
1132    wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllipse - invalid DC"));
1133
1134    wxMacFastPortSetter helper(this) ;
1135
1136    wxCoord xx = XLOG2DEVMAC(x);
1137    wxCoord yy = YLOG2DEVMAC(y);
1138    wxCoord ww = m_signX * XLOG2DEVREL(width);
1139    wxCoord hh = m_signY * YLOG2DEVREL(height);
1140
1141    // CMB: draw nothing if transformed w or h is 0
1142    if (ww == 0 || hh == 0)
1143        return;
1144
1145    // CMB: handle -ve width and/or height
1146    if (ww < 0)
1147    {
1148        ww = -ww;
1149        xx = xx - ww;
1150    }
1151
1152    if (hh < 0)
1153    {
1154        hh = -hh;
1155        yy = yy - hh;
1156    }
1157
1158    Rect rect = { yy , xx , yy + hh , xx + ww } ;
1159
1160    if (m_brush.GetStyle() != wxTRANSPARENT)
1161    {
1162        MacInstallBrush() ;
1163        ::PaintOval( &rect ) ;
1164    }
1165
1166    if (m_pen.GetStyle() != wxTRANSPARENT)
1167    {
1168        MacInstallPen() ;
1169        ::FrameOval( &rect ) ;
1170    }
1171}
1172
1173bool wxDC::CanDrawBitmap(void) const
1174{
1175    return true ;
1176}
1177
1178bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1179                   wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1180                   wxCoord xsrcMask, wxCoord ysrcMask )
1181{
1182    wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit - invalid DC"));
1183    wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit - invalid source DC"));
1184
1185    if ( logical_func == wxNO_OP )
1186        return true ;
1187
1188    if (xsrcMask == -1 && ysrcMask == -1)
1189    {
1190        xsrcMask = xsrc;
1191        ysrcMask = ysrc;
1192    }
1193
1194    // correct the parameter in case this dc does not have a mask at all
1195    if ( useMask && !source->m_macMask )
1196        useMask = false ;
1197
1198    Rect srcrect , dstrect ;
1199    srcrect.top = source->YLOG2DEVMAC(ysrc) ;
1200    srcrect.left = source->XLOG2DEVMAC(xsrc)  ;
1201    srcrect.right = source->XLOG2DEVMAC(xsrc + width ) ;
1202    srcrect.bottom = source->YLOG2DEVMAC(ysrc + height) ;
1203    dstrect.top = YLOG2DEVMAC(ydest) ;
1204    dstrect.left = XLOG2DEVMAC(xdest) ;
1205    dstrect.bottom = YLOG2DEVMAC(ydest + height )  ;
1206    dstrect.right = XLOG2DEVMAC(xdest + width ) ;
1207    short mode = kUnsupportedMode ;
1208    bool invertDestinationFirst = false ;
1209
1210    switch ( logical_func )
1211    {
1212    case wxAND:        // src AND dst
1213        mode = adMin ; // ok
1214        break ;
1215
1216    case wxAND_INVERT: // (NOT src) AND dst
1217        mode = notSrcOr  ; // ok
1218        break ;
1219
1220    case wxAND_REVERSE:// src AND (NOT dst)
1221        invertDestinationFirst = true ;
1222        mode = srcOr ;
1223        break ;
1224
1225    case wxCLEAR:      // 0
1226        mode = kEmulatedMode ;
1227        break ;
1228
1229    case wxCOPY:       // src
1230        mode = srcCopy ; // ok
1231        break ;
1232
1233    case wxEQUIV:      // (NOT src) XOR dst
1234        mode = srcXor ; // ok
1235        break ;
1236
1237    case wxINVERT:     // NOT dst
1238        mode = kEmulatedMode ; //or hilite ;
1239        break ;
1240
1241    case wxNAND:       // (NOT src) OR (NOT dst)
1242        invertDestinationFirst = true ;
1243        mode = srcBic ;
1244        break ;
1245
1246    case wxNOR:        // (NOT src) AND (NOT dst)
1247        invertDestinationFirst = true ;
1248        mode = notSrcOr ;
1249        break ;
1250
1251    case wxNO_OP:      // dst
1252        mode = kEmulatedMode ; // this has already been handled upon entry
1253        break ;
1254
1255    case wxOR:         // src OR dst
1256        mode = notSrcBic ;
1257        break ;
1258
1259    case wxOR_INVERT:  // (NOT src) OR dst
1260        mode = srcBic ;
1261        break ;
1262
1263    case wxOR_REVERSE: // src OR (NOT dst)
1264        invertDestinationFirst = true ;
1265        mode = notSrcBic ;
1266        break ;
1267
1268    case wxSET:        // 1
1269        mode = kEmulatedMode ;
1270        break ;
1271
1272    case wxSRC_INVERT: // (NOT src)
1273        mode = notSrcCopy ; // ok
1274        break ;
1275
1276    case wxXOR:        // src XOR dst
1277        mode = notSrcXor ; // ok
1278        break ;
1279
1280    default :
1281        break ;
1282    }
1283
1284    if ( mode == kUnsupportedMode )
1285    {
1286        wxFAIL_MSG(wxT("unsupported blitting mode" ));
1287
1288        return false ;
1289    }
1290
1291    CGrafPtr            sourcePort = (CGrafPtr) source->m_macPort ;
1292    PixMapHandle    bmappixels =  GetGWorldPixMap( sourcePort ) ;
1293    if ( LockPixels(bmappixels) )
1294    {
1295        wxMacFastPortSetter helper(this) ;
1296
1297        if ( source->GetDepth() == 1 )
1298        {
1299            RGBForeColor( &MAC_WXCOLORREF(m_textForegroundColour.GetPixel()) ) ;
1300            RGBBackColor( &MAC_WXCOLORREF(m_textBackgroundColour.GetPixel()) ) ;
1301        }
1302        else
1303        {
1304            // the modes need this, otherwise we'll end up having really nice colors...
1305            RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF } ;
1306            RGBColor black = { 0, 0, 0 } ;
1307
1308            RGBForeColor( &black ) ;
1309            RGBBackColor( &white ) ;
1310        }
1311
1312        if ( useMask && source->m_macMask )
1313        {
1314            if ( mode == srcCopy )
1315            {
1316                if ( LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) )
1317                {
1318                    CopyMask( GetPortBitMapForCopyBits( sourcePort ) ,
1319                        GetPortBitMapForCopyBits( MAC_WXHBITMAP(source->m_macMask) ) ,
1320                        GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
1321                        &srcrect, &srcrect , &dstrect ) ;
1322                    UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) )  ) ;
1323                }
1324            }
1325            else
1326            {
1327                RgnHandle clipRgn = NewRgn() ;
1328                LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
1329                BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
1330                UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ;
1331                OffsetRgn( clipRgn , -srcrect.left + dstrect.left, -srcrect.top +  dstrect.top ) ;
1332
1333                if ( mode == kEmulatedMode )
1334                {
1335                    Pattern pat ;
1336
1337                    ::PenPat(GetQDGlobalsBlack(&pat));
1338                    if ( logical_func == wxSET )
1339                    {
1340                        RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ;
1341                        ::RGBForeColor( &col  ) ;
1342                        ::PaintRgn( clipRgn ) ;
1343                    }
1344                    else if ( logical_func == wxCLEAR )
1345                    {
1346                        RGBColor col= { 0x0000, 0x0000, 0x0000 } ;
1347                        ::RGBForeColor( &col  ) ;
1348                        ::PaintRgn( clipRgn ) ;
1349                    }
1350                    else if ( logical_func == wxINVERT )
1351                    {
1352                        MacInvertRgn( clipRgn ) ;
1353                    }
1354                    else
1355                    {
1356                        for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y )
1357                        {
1358                            for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x )
1359                            {
1360                                Point dstPoint = { dstrect.top + y , dstrect.left + x } ;
1361                                Point srcPoint = { srcrect.top + y , srcrect.left + x } ;
1362                                if ( PtInRgn( dstPoint , clipRgn ) )
1363                                {
1364                                    RGBColor srcColor, dstColor ;
1365
1366                                    // NOTE: Get/SetCPixel are slow!
1367                                    SetPort( (GrafPtr) sourcePort ) ;
1368                                    GetCPixel( srcPoint.h , srcPoint.v , &srcColor ) ;
1369                                    SetPort( (GrafPtr) m_macPort ) ;
1370                                    GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
1371                                    wxMacCalculateColour( logical_func , srcColor , dstColor ) ;
1372                                    SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
1373                                }
1374                            }
1375                        }
1376                    }
1377                }
1378                else
1379                {
1380                    if ( invertDestinationFirst )
1381                        MacInvertRgn( clipRgn ) ;
1382
1383                    CopyBits( GetPortBitMapForCopyBits( sourcePort ) ,
1384                        GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
1385                        &srcrect, &dstrect, mode, clipRgn ) ;
1386                }
1387
1388                DisposeRgn( clipRgn ) ;
1389            }
1390        }
1391        else
1392        {
1393            RgnHandle clipRgn = NewRgn() ;
1394            SetRectRgn( clipRgn , dstrect.left , dstrect.top , dstrect.right , dstrect.bottom ) ;
1395
1396            if ( mode == kEmulatedMode )
1397            {
1398                Pattern pat ;
1399
1400                ::PenPat(GetQDGlobalsBlack(&pat));
1401                if ( logical_func == wxSET )
1402                {
1403                    RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ;
1404                    ::RGBForeColor( &col  ) ;
1405                    ::PaintRgn( clipRgn ) ;
1406                }
1407                else if ( logical_func == wxCLEAR )
1408                {
1409                    RGBColor col = { 0x0000, 0x0000, 0x0000 } ;
1410
1411                    ::RGBForeColor( &col  ) ;
1412                    ::PaintRgn( clipRgn ) ;
1413                }
1414                else if ( logical_func == wxINVERT )
1415                {
1416                    MacInvertRgn( clipRgn ) ;
1417                }
1418                else
1419                {
1420                    for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y )
1421                    {
1422                        for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x )
1423                        {
1424                            Point dstPoint = { dstrect.top + y , dstrect.left + x } ;
1425                            Point srcPoint = { srcrect.top + y , srcrect.left + x } ;
1426                            {
1427                                RGBColor srcColor, dstColor ;
1428
1429                                // NOTE: Get/SetCPixel are slow!
1430                                SetPort( (GrafPtr) sourcePort ) ;
1431                                GetCPixel( srcPoint.h , srcPoint.v , &srcColor) ;
1432                                SetPort( (GrafPtr) m_macPort ) ;
1433                                GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
1434                                wxMacCalculateColour( logical_func , srcColor , dstColor ) ;
1435                                SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ;
1436                            }
1437                        }
1438                    }
1439                }
1440            }
1441            else
1442            {
1443                if ( invertDestinationFirst )
1444                    MacInvertRgn( clipRgn ) ;
1445
1446                CopyBits( GetPortBitMapForCopyBits( sourcePort ) ,
1447                    GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) ,
1448                    &srcrect, &dstrect, mode, NULL ) ;
1449            }
1450
1451            DisposeRgn( clipRgn ) ;
1452        }
1453
1454        UnlockPixels( bmappixels ) ;
1455    }
1456
1457    m_macPenInstalled = false ;
1458    m_macBrushInstalled = false ;
1459    m_macFontInstalled = false ;
1460
1461    return true;
1462}
1463
1464void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1465                              double angle)
1466{
1467    wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText - invalid DC") );
1468
1469    if ( str.empty() )
1470        return ;
1471
1472    wxMacFastPortSetter helper(this) ;
1473    MacInstallFont() ;
1474
1475    OSStatus status = noErr ;
1476    ATSUTextLayout atsuLayout ;
1477
1478    wxMacUniCharBuffer unibuf( str ) ;
1479    UniCharCount chars = unibuf.GetChars() ;
1480
1481    status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
1482        &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1483
1484    wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") );
1485
1486    status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
1487    wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1488
1489    int iAngle = int( angle );
1490    int drawX = XLOG2DEVMAC(x) ;
1491    int drawY = YLOG2DEVMAC(y) ;
1492
1493    ATSUTextMeasurement textBefore, textAfter ;
1494    ATSUTextMeasurement ascent, descent ;
1495
1496    ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
1497
1498    if (m_font.GetNoAntiAliasing())
1499    {
1500        layoutOptions |= kATSLineNoAntiAliasing ;
1501    }
1502
1503    Fixed atsuAngle = IntToFixed( iAngle ) ;
1504
1505    ATSUAttributeTag atsuTags[] =
1506    {
1507        kATSULineLayoutOptionsTag ,
1508        kATSULineRotationTag ,
1509    } ;
1510
1511    ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1512    {
1513        sizeof( ATSLineLayoutOptions ) ,
1514        sizeof( Fixed ) ,
1515    } ;
1516
1517    ATSUAttributeValuePtr    atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1518    {
1519        &layoutOptions ,
1520        &atsuAngle ,
1521    } ;
1522
1523    status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) - ( abs(iAngle) > 0.001 ? 0 : 1),
1524            atsuTags, atsuSizes, atsuValues ) ;
1525
1526    status = ::ATSUMeasureText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1527        &textBefore , &textAfter, &ascent , &descent );
1528    wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1529
1530    if ( m_backgroundMode == wxSOLID )
1531    {
1532        // background painting must be done by hand, cannot be done by ATSUI
1533        wxCoord x2 , y2 ;
1534        PolyHandle polygon = OpenPoly();
1535
1536        ::MoveTo(drawX, drawY);
1537
1538        x2 = (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent)) ;
1539        y2 = (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent)) ;
1540        ::LineTo(x2, y2);
1541
1542        x2 = (int) (drawX + sin(angle / RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ;
1543        y2 = (int) (drawY + cos(angle / RAD2DEG) * FixedToInt(ascent + descent) - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ;
1544        ::LineTo(x2, y2);
1545
1546        x2 = (int) (drawX + cos(angle / RAD2DEG) * FixedToInt(textAfter)) ;
1547        y2 = (int) (drawY - sin(angle / RAD2DEG) * FixedToInt(textAfter)) ;
1548        ::LineTo(x2, y2);
1549
1550        ::LineTo( drawX, drawY) ;
1551        ClosePoly();
1552
1553        ::ErasePoly( polygon );
1554        KillPoly( polygon );
1555    }
1556
1557    drawX += (int)(sin(angle / RAD2DEG) * FixedToInt(ascent));
1558    drawY += (int)(cos(angle / RAD2DEG) * FixedToInt(ascent));
1559    status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1560        IntToFixed(drawX) , IntToFixed(drawY) );
1561
1562    wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") );
1563
1564    Rect rect ;
1565    status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1566        IntToFixed(drawX) , IntToFixed(drawY) , &rect );
1567    wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") );
1568
1569    OffsetRect( &rect , -m_macLocalOrigin.x , -m_macLocalOrigin.y ) ;
1570    CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) );
1571    CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) );
1572    ::ATSUDisposeTextLayout(atsuLayout);
1573}
1574
1575void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y)
1576{
1577    DoDrawRotatedText( strtext , x , y , 0) ;
1578}
1579
1580bool wxDC::CanGetTextExtent() const
1581{
1582    wxCHECK_MSG(Ok(), false, wxT("wxDC::CanGetTextExtent - invalid DC"));
1583
1584    return true ;
1585}
1586
1587
1588void wxDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1589                            wxCoord *descent, wxCoord *externalLeading ,
1590                            wxFont *theFont ) const
1591{
1592    wxCHECK_RET(Ok(), wxT("wxDC::DoGetTextExtent - invalid DC"));
1593
1594    wxMacFastPortSetter helper(this) ;
1595    wxFont formerFont = m_font ;
1596    if ( theFont )
1597    {
1598        // work around the constness
1599        *((wxFont*)(&m_font)) = *theFont ;
1600    }
1601
1602    MacInstallFont() ;
1603
1604    OSStatus status = noErr ;
1605    ATSUTextLayout atsuLayout ;
1606
1607    wxMacUniCharBuffer unibuf( str ) ;
1608    UniCharCount chars = unibuf.GetChars() ;
1609
1610    status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
1611        &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1612
1613    wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1614
1615    status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
1616    wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1617
1618    ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
1619
1620    if (m_font.GetNoAntiAliasing())
1621    {
1622        layoutOptions |= kATSLineNoAntiAliasing ;
1623    }
1624
1625    ATSUAttributeTag atsuTags[] =
1626    {
1627        kATSULineLayoutOptionsTag ,
1628    } ;
1629
1630    ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1631    {
1632        sizeof( ATSLineLayoutOptions ) ,
1633    } ;
1634
1635    ATSUAttributeValuePtr    atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1636    {
1637        &layoutOptions ,
1638    } ;
1639
1640    status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
1641            atsuTags, atsuSizes, atsuValues ) ;
1642
1643    ATSUTextMeasurement textBefore, textAfter ;
1644    ATSUTextMeasurement textAscent, textDescent ;
1645
1646    status = ::ATSUGetUnjustifiedBounds( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd,
1647        &textBefore , &textAfter, &textAscent , &textDescent );
1648
1649    if ( height )
1650        *height = YDEV2LOGREL( FixedToInt(textAscent + textDescent) ) ;
1651    if ( descent )
1652        *descent =YDEV2LOGREL( FixedToInt(textDescent) );
1653    if ( externalLeading )
1654        *externalLeading = 0 ;
1655    if ( width )
1656        *width = XDEV2LOGREL( FixedToInt(textAfter - textBefore) ) ;
1657
1658    ::ATSUDisposeTextLayout(atsuLayout);
1659
1660
1661    if ( theFont )
1662    {
1663        // work around the constness
1664        *((wxFont*)(&m_font)) = formerFont ;
1665        m_macFontInstalled = false ;
1666    }
1667}
1668
1669bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1670{
1671    wxCHECK_MSG(Ok(), false, wxT("wxDC::DoGetPartialTextExtents - invalid DC"));
1672
1673    widths.Empty();
1674    widths.Add(0, text.length());
1675
1676    if (text.length() == 0)
1677        return false;
1678
1679    wxMacFastPortSetter helper(this) ;
1680    MacInstallFont() ;
1681
1682    OSStatus status = noErr ;
1683    ATSUTextLayout atsuLayout ;
1684
1685    wxMacUniCharBuffer unibuf( text ) ;
1686    UniCharCount chars = unibuf.GetChars() ;
1687
1688    status = ::ATSUCreateTextLayoutWithTextPtr( unibuf.GetBuffer() , 0 , chars , chars , 1 ,
1689        &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
1690
1691    wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the text") );
1692
1693    status = ::ATSUSetTransientFontMatching( atsuLayout , true ) ;
1694    wxASSERT_MSG( status == noErr , wxT("couldn't setup transient font matching") );
1695
1696    ATSLineLayoutOptions layoutOptions = kATSLineNoLayoutOptions ;
1697
1698    if (m_font.GetNoAntiAliasing())
1699    {
1700        layoutOptions |= kATSLineNoAntiAliasing ;
1701    }
1702
1703    ATSUAttributeTag atsuTags[] =
1704    {
1705        kATSULineLayoutOptionsTag ,
1706    } ;
1707
1708    ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1709    {
1710        sizeof( ATSLineLayoutOptions ) ,
1711    } ;
1712
1713    ATSUAttributeValuePtr    atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1714    {
1715        &layoutOptions ,
1716    } ;
1717
1718    status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
1719            atsuTags, atsuSizes, atsuValues ) ;
1720
1721    ATSLayoutRecord *layoutRecords;
1722    ItemCount glyphCount = 0;
1723
1724    // Get the glyph extents
1725    OSStatus err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(atsuLayout,
1726                                                        0,
1727                                                        kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
1728                                                        (void **)
1729                                                        &layoutRecords,
1730                                                        &glyphCount);
1731    wxASSERT(glyphCount == (text.length()+1));
1732
1733    if (glyphCount == (text.length()+1))
1734    {
1735        for ( int pos = 1; pos < (int)glyphCount ; pos ++ )
1736        {
1737            widths[pos-1] = XDEV2LOGREL(FixedToInt( layoutRecords[pos].realPos ));
1738        }
1739    }
1740
1741    ::ATSUDirectReleaseLayoutDataArrayPtr(NULL,
1742                                        kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
1743                                        (void **) &layoutRecords);
1744
1745    ::ATSUDisposeTextLayout(atsuLayout);
1746
1747    return err != noErr;
1748}
1749
1750wxCoord wxDC::GetCharWidth(void) const
1751{
1752    wxCoord width = 0 ;
1753    DoGetTextExtent( wxT("g"), &width , NULL , NULL , NULL , NULL ) ;
1754    return width ;
1755}
1756
1757wxCoord wxDC::GetCharHeight(void) const
1758{
1759    wxCoord height ;
1760    DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ) ;
1761    return height ;
1762}
1763
1764void wxDC::Clear(void)
1765{
1766    wxCHECK_RET(Ok(), wxT("wxDC::Clear - invalid DC"));
1767
1768    wxMacFastPortSetter helper(this) ;
1769    Rect rect = { -31000 , -31000 , 31000 , 31000 } ;
1770
1771    if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
1772    {
1773        ::PenNormal() ;
1774        MacSetupBackgroundForCurrentPort( m_backgroundBrush ) ;
1775        ::EraseRect( &rect ) ;
1776    }
1777}
1778
1779void wxDC::MacInstallFont() const
1780{
1781    wxCHECK_RET(Ok(), wxT("Invalid DC"));
1782
1783    //    if ( m_macFontInstalled )
1784    //        return ;
1785
1786    Pattern blackColor ;
1787    MacSetupBackgroundForCurrentPort(m_backgroundBrush) ;
1788    if ( m_backgroundMode != wxTRANSPARENT )
1789    {
1790        Pattern whiteColor ;
1791        ::BackPat(GetQDGlobalsWhite(&whiteColor));
1792    }
1793
1794    wxASSERT( m_font.Ok() ) ;
1795
1796    ::TextFont( m_font.MacGetFontNum() ) ;
1797    ::TextSize( (short)(m_scaleY * m_font.MacGetFontSize()) ) ;
1798    ::TextFace( m_font.MacGetFontStyle() ) ;
1799    m_macFontInstalled = true ;
1800    m_macBrushInstalled = false ;
1801    m_macPenInstalled = false ;
1802    RGBColor forecolor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel());
1803    RGBColor backcolor = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel());
1804    ::RGBForeColor( &forecolor );
1805    ::RGBBackColor( &backcolor );
1806
1807    // TODO:
1808    short mode = patCopy ;
1809    switch ( m_logicalFunction )
1810    {
1811    case wxCOPY:       // src
1812        mode = patCopy ;
1813        break ;
1814
1815    case wxINVERT:     // NOT dst
1816        ::PenPat(GetQDGlobalsBlack(&blackColor));
1817        mode = patXor ;
1818        break ;
1819
1820    case wxXOR:        // src XOR dst
1821        mode = patXor ;
1822        break ;
1823
1824    case wxOR_REVERSE: // src OR (NOT dst)
1825        mode = notPatOr ;
1826        break ;
1827
1828    case wxSRC_INVERT: // (NOT src)
1829        mode = notPatCopy ;
1830        break ;
1831
1832    case wxAND: // src AND dst
1833        mode = adMin ;
1834        break ;
1835
1836    // TODO: unsupported
1837    case wxCLEAR:      // 0
1838    case wxAND_REVERSE:// src AND (NOT dst)
1839    case wxAND_INVERT: // (NOT src) AND dst
1840    case wxNO_OP:      // dst
1841    case wxNOR:        // (NOT src) AND (NOT dst)
1842    case wxEQUIV:      // (NOT src) XOR dst
1843    case wxOR_INVERT:  // (NOT src) OR dst
1844    case wxNAND:       // (NOT src) OR (NOT dst)
1845    case wxOR:         // src OR dst
1846    case wxSET:        // 1
1847        //        case wxSRC_OR:     // source _bitmap_ OR destination
1848        //        case wxSRC_AND:     // source _bitmap_ AND destination
1849        break ;
1850
1851    default:
1852        break ;
1853    }
1854
1855    ::PenMode( mode ) ;
1856    OSStatus status = noErr ;
1857    status = ATSUCreateAndCopyStyle( (ATSUStyle) m_font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle ) ;
1858    wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ;
1859
1860    Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.MacGetFontSize()) ) ;
1861    ATSUAttributeTag atsuTags[] =
1862    {
1863            kATSUSizeTag ,
1864    } ;
1865    ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1866    {
1867            sizeof( Fixed ) ,
1868    } ;
1869    ATSUAttributeValuePtr    atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] =
1870    {
1871            &atsuSize ,
1872    } ;
1873
1874    status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) ,
1875        atsuTags, atsuSizes, atsuValues);
1876
1877    wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") ) ;
1878}
1879
1880Pattern gPatterns[] =
1881{
1882    // hatch patterns
1883    { { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } } ,
1884    { { 0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80 } } ,
1885    { { 0x80 , 0x40 , 0x20 , 0x10 , 0x08 , 0x04 , 0x02 , 0x01 } } ,
1886    { { 0x10 , 0x10 , 0x10 , 0xFF , 0x10 , 0x10 , 0x10 , 0x10 } } ,
1887    { { 0x00 , 0x00 , 0x00 , 0xFF , 0x00 , 0x00 , 0x00 , 0x00 } } ,
1888    { { 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 } } ,
1889    { { 0x81 , 0x42 , 0x24 , 0x18 , 0x18 , 0x24 , 0x42 , 0x81 } } ,
1890
1891    // dash patterns
1892    { { 0xCC , 0x99 , 0x33 , 0x66 , 0xCC , 0x99 , 0x33 , 0x66 } } , // DOT
1893    { { 0xFE , 0xFD , 0xFB , 0xF7 , 0xEF , 0xDF , 0xBF , 0x7F } } , // LONG_DASH
1894    { { 0xEE , 0xDD , 0xBB , 0x77 , 0xEE , 0xDD , 0xBB , 0x77 } } , // SHORT_DASH
1895    { { 0xDE , 0xBD , 0x7B , 0xF6 , 0xED , 0xDB , 0xB7 , 0x6F } } , // DOT_DASH
1896} ;
1897
1898static void wxMacGetPattern(int penStyle, Pattern *pattern)
1899{
1900    int index = 0;  // solid pattern by default
1901    switch (penStyle)
1902    {
1903        // hatches
1904        case wxBDIAGONAL_HATCH:     index = 1; break;
1905        case wxFDIAGONAL_HATCH:     index = 2; break;
1906        case wxCROSS_HATCH:         index = 3; break;
1907        case wxHORIZONTAL_HATCH:    index = 4; break;
1908        case wxVERTICAL_HATCH:      index = 5; break;
1909        case wxCROSSDIAG_HATCH:     index = 6; break;
1910
1911        // dashes
1912        case wxDOT:                 index = 7; break;
1913        case wxLONG_DASH:           index = 8; break;
1914        case wxSHORT_DASH:          index = 9; break;
1915        case wxDOT_DASH:            index = 10; break;
1916
1917        default:
1918            break;
1919    }
1920
1921    *pattern = gPatterns[index];
1922}
1923
1924void wxDC::MacInstallPen() const
1925{
1926    wxCHECK_RET(Ok(), wxT("wxDC::MacInstallPen - invalid DC"));
1927
1928    //Pattern     blackColor;
1929    //    if ( m_macPenInstalled )
1930    //        return ;
1931
1932    RGBColor forecolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel());
1933    RGBColor backcolor = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel());
1934    ::RGBForeColor( &forecolor );
1935    ::RGBBackColor( &backcolor );
1936    ::PenNormal() ;
1937
1938    // null means only one pixel, at whatever resolution
1939    int penWidth = (int) (m_pen.GetWidth() * m_scaleX) ;
1940    if ( penWidth == 0 )
1941        penWidth = 1 ;
1942    ::PenSize(penWidth, penWidth);
1943
1944    Pattern pat;
1945    int penStyle = m_pen.GetStyle();
1946    if (penStyle == wxUSER_DASH)
1947    {
1948        // FIXME: there should be exactly 8 items in the dash
1949        wxDash* dash ;
1950        int number = m_pen.GetDashes(&dash) ;
1951        int index = 0;
1952        for ( int i = 0 ; i < 8 ; ++i )
1953        {
1954            pat.pat[i] = dash[index] ;
1955            if (index < number - 1)
1956                index++;
1957        }
1958    }
1959    else
1960    {
1961        wxMacGetPattern(penStyle, &pat);
1962    }
1963    ::PenPat(&pat);
1964
1965    // TODO:
1966    short mode = patCopy ;
1967    switch ( m_logicalFunction )
1968    {
1969    case wxCOPY:       // only foreground color, leave background (thus not patCopy)
1970        mode = patOr ;
1971        break ;
1972
1973    case wxINVERT:     // NOT dst
1974        //            ::PenPat(GetQDGlobalsBlack(&blackColor));
1975        mode = patXor ;
1976        break ;
1977
1978    case wxXOR:        // src XOR dst
1979        mode = patXor ;
1980        break ;
1981
1982    case wxOR_REVERSE: // src OR (NOT dst)
1983        mode = notPatOr ;
1984        break ;
1985
1986    case wxSRC_INVERT: // (NOT src)
1987        mode = notPatCopy ;
1988        break ;
1989
1990    case wxAND: // src AND dst
1991        mode = adMin ;
1992        break ;
1993
1994    // TODO: unsupported
1995    case wxCLEAR:      // 0
1996    case wxAND_REVERSE:// src AND (NOT dst)
1997    case wxAND_INVERT: // (NOT src) AND dst
1998    case wxNO_OP:      // dst
1999    case wxNOR:        // (NOT src) AND (NOT dst)
2000    case wxEQUIV:      // (NOT src) XOR dst
2001    case wxOR_INVERT:  // (NOT src) OR dst
2002    case wxNAND:       // (NOT src) OR (NOT dst)
2003    case wxOR:         // src OR dst
2004    case wxSET:        // 1
2005        //        case wxSRC_OR:     // source _bitmap_ OR destination
2006        //        case wxSRC_AND:     // source _bitmap_ AND destination
2007        break ;
2008
2009    default:
2010        break ;
2011    }
2012
2013    ::PenMode( mode ) ;
2014    m_macPenInstalled = true ;
2015    m_macBrushInstalled = false ;
2016    m_macFontInstalled = false ;
2017}
2018
2019void wxDC::MacSetupBackgroundForCurrentPort(const wxBrush& background )
2020{
2021    Pattern whiteColor ;
2022
2023    if ( background.Ok() )
2024    {
2025        switch ( background.MacGetBrushKind() )
2026        {
2027            case kwxMacBrushTheme :
2028                ::SetThemeBackground( background.MacGetTheme() , wxDisplayDepth() , true ) ;
2029                break ;
2030
2031            case kwxMacBrushThemeBackground :
2032            {
2033                Rect extent ;
2034                ThemeBackgroundKind bg = background.MacGetThemeBackground( &extent ) ;
2035                ::ApplyThemeBackground( bg , &extent, kThemeStateActive , wxDisplayDepth() , true ) ;
2036            }
2037                break ;
2038
2039            case kwxMacBrushColour :
2040            {
2041                ::RGBBackColor( &MAC_WXCOLORREF( background.GetColour().GetPixel()) );
2042                int brushStyle = background.GetStyle();
2043                if (brushStyle == wxSOLID)
2044                    ::BackPat(GetQDGlobalsWhite(&whiteColor));
2045                else if (background.IsHatch())
2046                {
2047                    Pattern pat ;
2048                    wxMacGetPattern(brushStyle, &pat);
2049                    ::BackPat(&pat);
2050                }
2051                else
2052                {
2053                    ::BackPat(GetQDGlobalsWhite(&whiteColor));
2054                }
2055            }
2056                break ;
2057
2058            default:
2059                break ;
2060        }
2061    }
2062}
2063
2064void wxDC::MacInstallBrush() const
2065{
2066    wxCHECK_RET(Ok(), wxT("Invalid DC"));
2067
2068    //    if ( m_macBrushInstalled )
2069    //        return ;
2070
2071    Pattern     blackColor ;
2072    bool backgroundTransparent = (GetBackgroundMode() == wxTRANSPARENT) ;
2073    ::RGBForeColor( &MAC_WXCOLORREF( m_brush.GetColour().GetPixel()) );
2074    ::RGBBackColor( &MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) );
2075
2076    int brushStyle = m_brush.GetStyle();
2077    if (brushStyle == wxSOLID)
2078    {
2079        switch ( m_brush.MacGetBrushKind() )
2080        {
2081            case kwxMacBrushTheme :
2082                {
2083                    Pattern whiteColor ;
2084                    ::BackPat(GetQDGlobalsWhite(&whiteColor));
2085                    ::SetThemePen( m_brush.MacGetTheme() , wxDisplayDepth() , true ) ;
2086                }
2087            break ;
2088
2089            default :
2090                ::PenPat(GetQDGlobalsBlack(&blackColor));
2091                break ;
2092
2093        }
2094    }
2095    else if (m_brush.IsHatch())
2096    {
2097        Pattern pat ;
2098
2099        wxMacGetPattern(brushStyle, &pat);
2100        ::PenPat(&pat);
2101    }
2102    else if ( m_brush.GetStyle() == wxSTIPPLE || m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
2103    {
2104        // we force this in order to be compliant with wxMSW
2105        backgroundTransparent = false ;
2106
2107        // for these the text fore (and back for MASK_OPAQUE) colors are used
2108        wxBitmap* bitmap = m_brush.GetStipple() ;
2109        int width = bitmap->GetWidth() ;
2110        int height = bitmap->GetHeight() ;
2111        GWorldPtr gw = NULL ;
2112
2113        if ( m_brush.GetStyle() == wxSTIPPLE )
2114            gw = MAC_WXHBITMAP(bitmap->GetHBITMAP(NULL))  ;
2115        else
2116            gw = MAC_WXHBITMAP(bitmap->GetMask()->GetHBITMAP()) ;
2117
2118        PixMapHandle gwpixmaphandle = GetGWorldPixMap( gw ) ;
2119        LockPixels( gwpixmaphandle ) ;
2120        bool isMonochrome = !IsPortColor( gw ) ;
2121        if ( !isMonochrome )
2122        {
2123            if ( (**gwpixmaphandle).pixelSize == 1 )
2124                isMonochrome = true ;
2125        }
2126
2127        if ( isMonochrome && width == 8 && height == 8 )
2128        {
2129            ::RGBForeColor( &MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) );
2130            ::RGBForeColor( &MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) );
2131            BitMap* gwbitmap = (BitMap*) *gwpixmaphandle ; // since the color depth is 1 it is a BitMap
2132            UInt8 *gwbits = (UInt8*) gwbitmap->baseAddr ;
2133            int alignment = gwbitmap->rowBytes & 0x7FFF ;
2134            Pattern pat ;
2135
2136            for ( int i = 0 ; i < 8 ; ++i )
2137            {
2138                pat.pat[i] = gwbits[i * alignment + 0] ;
2139            }
2140
2141            UnlockPixels( GetGWorldPixMap( gw ) ) ;
2142            ::PenPat( &pat ) ;
2143        }
2144        else
2145        {
2146            // this will be the code to handle power of 2 patterns, we will have to arrive at a nice
2147            // caching scheme before putting this into production
2148            Handle      image;
2149            long        imageSize;
2150
2151            PixPatHandle pixpat = NewPixPat() ;
2152            CopyPixMap(gwpixmaphandle, (**pixpat).patMap);
2153            imageSize = GetPixRowBytes((**pixpat).patMap) *
2154                ((**(**pixpat).patMap).bounds.bottom -
2155                (**(**pixpat).patMap).bounds.top);
2156            PtrToHand( (**gwpixmaphandle).baseAddr, &image, imageSize );
2157            (**pixpat).patData = image;
2158
2159            if ( isMonochrome )
2160            {
2161                CTabHandle ctable = ((**((**pixpat).patMap)).pmTable) ;
2162                ColorSpecPtr ctspec = (ColorSpecPtr) &(**ctable).ctTable ;
2163                if ( ctspec[0].rgb.red == 0x0000 )
2164                {
2165                    ctspec[1].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ;
2166                    ctspec[0].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ;
2167                }
2168                else
2169                {
2170                    ctspec[0].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ;
2171                    ctspec[1].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ;
2172                }
2173                ::CTabChanged( ctable ) ;
2174            }
2175
2176            ::PenPixPat(pixpat);
2177            m_macForegroundPixMap = pixpat ;
2178        }
2179
2180        UnlockPixels( gwpixmaphandle ) ;
2181    }
2182    else
2183    {
2184        ::PenPat(GetQDGlobalsBlack(&blackColor));
2185    }
2186
2187    short mode = patCopy ;
2188    switch ( m_logicalFunction )
2189    {
2190    case wxCOPY:       // src
2191        if ( backgroundTransparent )
2192            mode = patOr ;
2193        else
2194            mode = patCopy ;
2195        break ;
2196
2197    case wxINVERT:     // NOT dst
2198        if ( !backgroundTransparent )
2199            ::PenPat(GetQDGlobalsBlack(&blackColor));
2200        mode = patXor ;
2201        break ;
2202
2203    case wxXOR:        // src XOR dst
2204        mode = patXor ;
2205        break ;
2206
2207    case wxOR_REVERSE: // src OR (NOT dst)
2208        mode = notPatOr ;
2209        break ;
2210
2211    case wxSRC_INVERT: // (NOT src)
2212        mode = notPatCopy ;
2213        break ;
2214
2215    case wxAND: // src AND dst
2216        mode = adMin ;
2217        break ;
2218
2219    // TODO: unsupported
2220    case wxCLEAR:      // 0
2221    case wxAND_REVERSE:// src AND (NOT dst)
2222    case wxAND_INVERT: // (NOT src) AND dst
2223    case wxNO_OP:      // dst
2224    case wxNOR:        // (NOT src) AND (NOT dst)
2225    case wxEQUIV:      // (NOT src) XOR dst
2226    case wxOR_INVERT:  // (NOT src) OR dst
2227    case wxNAND:       // (NOT src) OR (NOT dst)
2228    case wxOR:         // src OR dst
2229    case wxSET:        // 1
2230        //        case wxSRC_OR:     // source _bitmap_ OR destination
2231        //        case wxSRC_AND:     // source _bitmap_ AND destination
2232        break ;
2233
2234    default:
2235        break ;
2236    }
2237
2238    ::PenMode( mode ) ;
2239    m_macBrushInstalled = true ;
2240    m_macPenInstalled = false ;
2241    m_macFontInstalled = false ;
2242}
2243
2244// ---------------------------------------------------------------------------
2245// coordinates transformations
2246// ---------------------------------------------------------------------------
2247
2248wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2249{
2250    return ((wxDC *)this)->XDEV2LOG(x);
2251}
2252
2253wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2254{
2255    return ((wxDC *)this)->YDEV2LOG(y);
2256}
2257
2258wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2259{
2260    return ((wxDC *)this)->XDEV2LOGREL(x);
2261}
2262
2263wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2264{
2265    return ((wxDC *)this)->YDEV2LOGREL(y);
2266}
2267
2268wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2269{
2270    return ((wxDC *)this)->XLOG2DEV(x);
2271}
2272
2273wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2274{
2275    return ((wxDC *)this)->YLOG2DEV(y);
2276}
2277
2278wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2279{
2280    return ((wxDC *)this)->XLOG2DEVREL(x);
2281}
2282
2283wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2284{
2285    return ((wxDC *)this)->YLOG2DEVREL(y);
2286}
2287
2288#endif // !wxMAC_USE_CORE_GRAPHICS
2289