1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/dc.cpp
3// Purpose:     wxDC class
4// Author:      David Webster
5// Modified by:
6// Created:     10/14/99
7// RCS-ID:      $Id: dc.cpp 51287 2008-01-19 14:10:36Z SN $
8// Copyright:   (c) David Webster
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifndef WX_PRECOMP
16    #include "wx/window.h"
17    #include "wx/dc.h"
18    #include "wx/utils.h"
19    #include "wx/dialog.h"
20    #include "wx/app.h"
21    #include "wx/bitmap.h"
22    #include "wx/dcmemory.h"
23    #include "wx/log.h"
24    #include "wx/icon.h"
25    #include "wx/msgdlg.h"
26    #include "wx/dcprint.h"
27    #include "wx/statusbr.h"
28    #include "wx/module.h"
29#endif
30
31#include <string.h>
32
33#include "wx/os2/private.h"
34
35IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
36
37//
38// wxWidgets uses the Microsoft convention that the origin is the UPPER left.
39// Native OS/2 however in the GPI and PM define the origin as the LOWER left.
40// In order to map OS/2 GPI/PM y coordinates to wxWidgets coordinates we must
41// perform the following transformation:
42//
43// Parent object height:     POBJHEIGHT
44// Desried origin:           WXORIGINY
45// Object to place's height: OBJHEIGHT
46//
47// To get the OS2 position from the wxWidgets one:
48//
49// OS2Y = POBJHEIGHT - (WXORIGINY + OBJHEIGHT)
50//
51// For OS/2 wxDC's we will always determine m_vRclPaint as the size of the
52// OS/2 Presentation Space associated with the device context.  y is the
53// desired application's y coordinate of the origin in wxWidgets space.
54// objy is the height of the object we are going to draw.
55//
56#define OS2Y(y, objy) ((m_vRclPaint.yTop - m_vRclPaint.yBottom) - (y + objy))
57
58// ---------------------------------------------------------------------------
59// constants
60// ---------------------------------------------------------------------------
61
62static const int VIEWPORT_EXTENT = 1000;
63
64static const int MM_POINTS = 9;
65static const int MM_METRIC = 10;
66
67// ---------------------------------------------------------------------------
68// private functions
69// ---------------------------------------------------------------------------
70
71// convert degrees to radians
72static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
73
74int SetTextColor(
75  HPS                               hPS
76, int                               nForegroundColour
77)
78{
79    CHARBUNDLE                      vCbnd;
80
81    vCbnd.lColor =  nForegroundColour;
82    ::GpiSetAttrs( hPS       // presentation-space handle
83                  ,PRIM_CHAR // Char primitive.
84                  ,CBB_COLOR // sets color.
85                  ,0         //
86                  ,&vCbnd    // buffer for attributes.
87                 );
88    return 0;
89}
90
91int QueryTextBkColor(
92  HPS                               hPS
93)
94{
95    CHARBUNDLE                      vCbnd;
96
97    ::GpiQueryAttrs( hPS            // presentation-space handle
98                    ,PRIM_CHAR      // Char primitive.
99                    ,CBB_BACK_COLOR // Background color.
100                    ,&vCbnd         // buffer for attributes.
101                   );
102    return vCbnd.lBackColor;
103}
104
105
106int SetTextBkColor(
107  HPS                               hPS
108, int                               nBackgroundColour
109)
110{
111    CHARBUNDLE                      vCbnd;
112    int                             rc;
113
114    rc =  QueryTextBkColor(hPS);
115
116    vCbnd.lBackColor = nBackgroundColour;
117    ::GpiSetAttrs(hPS,            // presentation-space handle
118                  PRIM_CHAR,      // Char primitive.
119                  CBB_BACK_COLOR, // sets color.
120                  0,
121                  &vCbnd          // buffer for attributes.
122                 );
123    return rc;
124}
125
126int SetBkMode(
127  HPS                               hPS
128, int                               nBackgroundMode
129)
130{
131    if(nBackgroundMode == wxTRANSPARENT)
132        ::GpiSetBackMix( hPS
133                        ,BM_LEAVEALONE
134                       );
135    else
136        // the background of the primitive takes  over whatever is underneath.
137        ::GpiSetBackMix( hPS
138                        ,BM_OVERPAINT
139                        );
140    return 0;
141}
142
143// ===========================================================================
144// implementation
145// ===========================================================================
146
147#if wxUSE_DC_CACHEING
148
149/*
150 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
151 * improve it in due course, either using arrays, or simply storing pointers to one
152 * entry for the bitmap, and two for the DCs. -- JACS
153 */
154
155// ---------------------------------------------------------------------------
156// wxDCCacheEntry
157// ---------------------------------------------------------------------------
158
159wxList wxDC::m_svBitmapCache;
160wxList wxDC::m_svDCCache;
161
162wxDCCacheEntry::wxDCCacheEntry(
163  WXHBITMAP                         hBitmap
164, int                               nWidth
165, int                               nHeight
166, int                               nDepth
167)
168{
169    m_hBitmap = hBitmap;
170    m_hPS     = NULLHANDLE;
171    m_nWidth  = nWidth;
172    m_nHeight = nHeight;
173    m_nDepth  = nDepth;
174} // end of wxDCCacheEntry::wxDCCacheEntry
175
176wxDCCacheEntry::wxDCCacheEntry(
177  HPS                               hPS
178, int                               nDepth
179)
180{
181    m_hBitmap = NULLHANDLE;
182    m_hPS     = hPS;
183    m_nWidth  = 0;
184    m_nHeight = 0;
185    m_nDepth  = nDepth;
186} // end of wxDCCacheEntry::wxDCCacheEntry
187
188wxDCCacheEntry::~wxDCCacheEntry()
189{
190    if (m_hBitmap)
191        ::GpiDeleteBitmap(m_hBitmap);
192    if (m_hPS)
193        ::GpiDestroyPS(m_hPS);
194} // end of wxDCCacheEntry::~wxDCCacheEntry
195
196wxDCCacheEntry* wxDC::FindBitmapInCache(
197  HPS                               hPS
198, int                               nWidth
199, int                               nHeight
200)
201{
202    int                             nDepth = 24; // we'll fix this later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
203    wxNode*                         pNode = m_svBitmapCache.First();
204    BITMAPINFOHEADER2               vBmpHdr;
205
206    while(pNode)
207    {
208        wxDCCacheEntry*             pEntry = (wxDCCacheEntry*)pNode->Data();
209
210        if (pEntry->m_nDepth == nDepth)
211        {
212            memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
213
214            if (pEntry->m_nWidth < nWidth || pEntry->m_nHeight < nHeight)
215            {
216                ::GpiDeleteBitmap((HBITMAP)pEntry->m_hBitmap);
217                vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
218                vBmpHdr.cx        = nWidth;
219                vBmpHdr.cy        = nHeight;
220                vBmpHdr.cPlanes   = 1;
221                vBmpHdr.cBitCount = (USHORT)nDepth;
222
223                pEntry->m_hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
224                                                                  ,&vBmpHdr
225                                                                  ,0L, NULL, NULL
226                                                                 );
227                if (!pEntry->m_hBitmap)
228                {
229                    wxLogLastError(wxT("CreateCompatibleBitmap"));
230                }
231                pEntry->m_nWidth  = nWidth;
232                pEntry->m_nHeight = nHeight;
233                return pEntry;
234            }
235            return pEntry;
236        }
237        pNode = pNode->Next();
238    }
239    memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
240    vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
241    vBmpHdr.cx        = nWidth;
242    vBmpHdr.cy        = nHeight;
243    vBmpHdr.cPlanes   = 1;
244    vBmpHdr.cBitCount = (USHORT)nDepth;
245
246    WXHBITMAP                       hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
247                                                                            ,&vBmpHdr
248                                                                            ,0L, NULL, NULL
249                                                                           );
250    if (!hBitmap)
251    {
252        wxLogLastError(wxT("CreateCompatibleBitmap"));
253    }
254    wxDCCacheEntry*                 pEntry = new wxDCCacheEntry( hBitmap
255                                                                ,nWidth
256                                                                ,nHeight
257                                                                ,nDepth
258                                                               );
259    AddToBitmapCache(pEntry);
260    return pEntry;
261} // end of FindBitmapInCache
262
263wxDCCacheEntry* wxDC::FindDCInCache(
264  wxDCCacheEntry*                   pNotThis
265, HPS                               hPS
266)
267{
268    int                             nDepth = 24; // we'll fix this up later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
269    wxNode*                         pNode = m_svDCCache.First();
270
271    while(pNode)
272    {
273        wxDCCacheEntry*             pEntry = (wxDCCacheEntry*)pNode->Data();
274
275        //
276        // Don't return the same one as we already have
277        //
278        if (!pNotThis || (pNotThis != pEntry))
279        {
280            if (pEntry->m_nDepth == nDepth)
281            {
282                return pEntry;
283            }
284        }
285        pNode = pNode->Next();
286    }
287    wxDCCacheEntry*                 pEntry = new wxDCCacheEntry( hPS
288                                                                ,nDepth
289                                                               );
290    AddToDCCache(pEntry);
291    return pEntry;
292} // end of wxDC::FindDCInCache
293
294void wxDC::AddToBitmapCache(
295  wxDCCacheEntry*                   pEntry
296)
297{
298    m_svBitmapCache.Append(pEntry);
299} // end of wxDC::AddToBitmapCache
300
301void wxDC::AddToDCCache(
302  wxDCCacheEntry*                   pEntry
303)
304{
305    m_svDCCache.Append(pEntry);
306} // end of wxDC::AddToDCCache
307
308void wxDC::ClearCache()
309{
310    m_svBitmapCache.DeleteContents(true);
311    m_svBitmapCache.Clear();
312    m_svBitmapCache.DeleteContents(false);
313    m_svDCCache.DeleteContents(true);
314    m_svDCCache.Clear();
315    m_svDCCache.DeleteContents(false);
316} // end of wxDC::ClearCache
317
318// Clean up cache at app exit
319class wxDCModule : public wxModule
320{
321public:
322    virtual bool OnInit() { return true; }
323    virtual void OnExit() { wxDC::ClearCache(); }
324
325private:
326    DECLARE_DYNAMIC_CLASS(wxDCModule)
327}; // end of CLASS wxDCModule
328
329IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
330
331#endif // ndef for wxUSE_DC_CACHEING
332
333// ---------------------------------------------------------------------------
334// wxDC
335// ---------------------------------------------------------------------------
336
337wxDC::wxDC(void)
338{
339    m_pCanvas      = NULL;
340
341    m_hOldBitmap   = 0;
342    m_hOldPen      = 0;
343    m_hOldBrush    = 0;
344    m_hOldFont     = 0;
345    m_hOldPalette  = 0;
346
347    m_bOwnsDC      = false;
348    m_hDC          = 0;
349    m_hOldPS       = NULL;
350    m_hPS          = NULL;
351    m_bIsPaintTime = false; // True at Paint Time
352
353    m_pen.SetColour(*wxBLACK);
354    m_brush.SetColour(*wxWHITE);
355
356} // end of wxDC::wxDC
357
358wxDC::~wxDC(void)
359{
360    if ( m_hDC != 0 )
361    {
362        SelectOldObjects(m_hDC);
363
364        // if we own the HDC, we delete it, otherwise we just release it
365
366        if (m_bOwnsDC)
367        {
368            if(m_hPS)
369            {
370                ::GpiAssociate(m_hPS, NULLHANDLE);
371                ::GpiDestroyPS(m_hPS);
372            }
373            m_hPS = NULLHANDLE;
374            ::DevCloseDC((HDC)m_hDC);
375        }
376        else
377        {
378            //
379            // Just Dissacociate, not destroy if we don't own the DC
380            //
381            if(m_hPS)
382            {
383                ::GpiAssociate(m_hPS, NULLHANDLE);
384            }
385        }
386    }
387} // end of wxDC::~wxDC
388
389// This will select current objects out of the DC,
390// which is what you have to do before deleting the
391// DC.
392void wxDC::SelectOldObjects(
393  WXHDC                             hPS
394)
395{
396    if (hPS)
397    {
398        if (m_hOldBitmap)
399        {
400            ::GpiSetBitmap(hPS, (HBITMAP) m_hOldBitmap);
401            if (m_vSelectedBitmap.Ok())
402            {
403                m_vSelectedBitmap.SetSelectedInto(NULL);
404            }
405        }
406        m_hOldBitmap = 0;
407        //
408        // OS/2 has no other native GDI objects to set in a PS/DC like windows
409        //
410        m_hOldPen = 0;
411        m_hOldBrush = 0;
412        m_hOldFont = 0;
413        m_hOldPalette = 0;
414    }
415
416    m_brush           = wxNullBrush;
417    m_pen             = wxNullPen;
418    m_palette         = wxNullPalette;
419    m_font            = wxNullFont;
420    m_backgroundBrush = wxNullBrush;
421    m_vSelectedBitmap = wxNullBitmap;
422} // end of wxDC::SelectOldObjects
423
424// ---------------------------------------------------------------------------
425// clipping
426// ---------------------------------------------------------------------------
427
428#define DO_SET_CLIPPING_BOX()                    \
429{                                                \
430    RECTL rect;                                  \
431                                                 \
432    ::GpiQueryClipBox(m_hPS, &rect);             \
433                                                 \
434    m_clipX1 = (wxCoord) XDEV2LOG(rect.xLeft);   \
435    m_clipY1 = (wxCoord) YDEV2LOG(rect.yTop);    \
436    m_clipX2 = (wxCoord) XDEV2LOG(rect.xRight);  \
437    m_clipY2 = (wxCoord) YDEV2LOG(rect.yBottom); \
438}
439
440void wxDC::DoSetClippingRegion(
441  wxCoord                           vX
442, wxCoord                           vY
443, wxCoord                           vWidth
444, wxCoord                           vHeight
445)
446{
447    RECTL                           vRect;
448
449    vY = OS2Y(vY,vHeight);
450    m_clipping    = true;
451    vRect.xLeft   = vX;
452    vRect.yTop    = vY + vHeight;
453    vRect.xRight  = vX + vWidth;
454    vRect.yBottom = vY;
455    ::GpiIntersectClipRectangle(m_hPS, &vRect);
456    DO_SET_CLIPPING_BOX()
457} // end of wxDC::DoSetClippingRegion
458
459void wxDC::DoSetClippingRegionAsRegion(
460  const wxRegion&                   rRegion
461)
462{
463     wxCHECK_RET(rRegion.GetHRGN(), wxT("invalid clipping region"));
464     HRGN                           hRgnOld;
465
466     m_clipping = true;
467     ::GpiSetClipRegion( m_hPS
468                        ,(HRGN)rRegion.GetHRGN()
469                        ,&hRgnOld
470                       );
471    DO_SET_CLIPPING_BOX()
472} // end of wxDC::DoSetClippingRegionAsRegion
473
474void wxDC::DestroyClippingRegion(void)
475{
476    if (m_clipping && m_hPS)
477    {
478         HRGN                       hRgnOld;
479         RECTL                      vRect;
480
481         // TODO: this should restore the previous clipped region
482         //       so that OnPaint processing works correctly, and
483         //       the update doesn't get destroyed after the first
484         //       DestroyClippingRegion
485         vRect.xLeft   = XLOG2DEV(0);
486         vRect.yTop    = YLOG2DEV(32000);
487         vRect.xRight  = XLOG2DEV(32000);
488         vRect.yBottom = YLOG2DEV(0);
489
490         HRGN                       hRgn = ::GpiCreateRegion(m_hPS, 1, &vRect);
491
492         ::GpiSetClipRegion(m_hPS, hRgn, &hRgnOld);
493     }
494    ResetClipping();
495} // end of wxDC::DestroyClippingRegion
496
497// ---------------------------------------------------------------------------
498// query capabilities
499// ---------------------------------------------------------------------------
500
501bool wxDC::CanDrawBitmap() const
502{
503    return true;
504}
505
506bool wxDC::CanGetTextExtent() const
507{
508    LONG                            lTechnology = 0L;
509
510    ::DevQueryCaps(GetHDC(), CAPS_TECHNOLOGY, 1L, &lTechnology);
511    return (lTechnology == CAPS_TECH_RASTER_DISPLAY) || (lTechnology == CAPS_TECH_RASTER_PRINTER);
512} // end of wxDC::CanGetTextExtent
513
514int wxDC::GetDepth() const
515{
516    LONG                            lCapsColorBitcount;
517    int                             nBitsPerPixel = 0;
518
519    if(::DevQueryCaps( GetHDC()
520                      ,CAPS_COLOR_BITCOUNT
521                      ,1L
522                      ,&lCapsColorBitcount
523                     ))
524    {
525        nBitsPerPixel = (int)lCapsColorBitcount;
526    }
527    return nBitsPerPixel;
528} // end of wxDC::GetDepth
529
530// ---------------------------------------------------------------------------
531// drawing
532// ---------------------------------------------------------------------------
533
534void wxDC::Clear()
535{
536    //
537    // If this is a canvas DC then just fill with the background color
538    // Otherwise purge the whole thing
539    //
540    if (m_pCanvas)
541    {
542        RECTL                       vRect;
543
544        ::GpiQueryClipBox(m_hPS, &vRect);
545        ::WinFillRect(m_hPS, &vRect, ::GpiQueryBackColor(m_hPS));
546    }
547    else
548    ::GpiErase(m_hPS);
549} // end of wxDC::Clear
550
551bool wxDC::DoFloodFill(
552  wxCoord                           vX
553, wxCoord                           vY
554, const wxColour&                   rCol
555, int                               nStyle
556)
557{
558    POINTL                          vPtlPos;
559    LONG                            lColor;
560    LONG                            lOptions;
561    LONG                            lHits;
562    bool                            bSuccess = false;
563
564    vPtlPos.x = vX;             // Loads x-coordinate
565    vPtlPos.y = OS2Y(vY,0);     // Loads y-coordinate
566    ::GpiMove(m_hPS, &vPtlPos); // Sets current position
567    lColor = rCol.GetPixel();
568    lOptions = FF_BOUNDARY;
569    if(wxFLOOD_SURFACE == nStyle)
570        lOptions = FF_SURFACE;
571
572    if ((lHits = ::GpiFloodFill(m_hPS, lOptions, lColor)) != GPI_ERROR)
573        bSuccess = true;
574
575    return bSuccess;
576} // end of wxDC::DoFloodFill
577
578bool wxDC::DoGetPixel(
579  wxCoord                           vX
580, wxCoord                           vY
581, wxColour*                         pCol
582) const
583{
584    POINTL                          vPoint;
585    LONG                            lColor;
586
587    vPoint.x = vX;
588    vPoint.y = OS2Y(vY,0);
589    lColor = ::GpiQueryPel(m_hPS, &vPoint);
590
591    //
592    // return the color of the pixel
593    //
594    if(pCol)
595        pCol->Set( GetRValue(lColor)
596                  ,GetGValue(lColor)
597                  ,GetBValue(lColor)
598                 );
599    return true;
600} // end of wxDC::DoGetPixel
601
602void wxDC::DoCrossHair(
603  wxCoord                           vX
604, wxCoord                           vY
605)
606{
607    vY = OS2Y(vY,0);
608
609    wxCoord                         vX1 = vX - VIEWPORT_EXTENT;
610    wxCoord                         vY1 = vY - VIEWPORT_EXTENT;
611    wxCoord                         vX2 = vX + VIEWPORT_EXTENT;
612    wxCoord                         vY2 = vY + VIEWPORT_EXTENT;
613    POINTL                          vPoint[4];
614
615    vPoint[0].x = vX1;
616    vPoint[0].y = vY;
617
618    vPoint[1].x = vX2;
619    vPoint[1].y = vY;
620
621    ::GpiMove(m_hPS, &vPoint[0]);
622    ::GpiLine(m_hPS, &vPoint[1]);
623
624    vPoint[2].x = vX;
625    vPoint[2].y = vY1;
626
627    vPoint[3].x = vX;
628    vPoint[3].y = vY2;
629
630    ::GpiMove(m_hPS, &vPoint[2]);
631    ::GpiLine(m_hPS, &vPoint[3]);
632    CalcBoundingBox(vX1, vY1);
633    CalcBoundingBox(vX2, vY2);
634} // end of wxDC::DoCrossHair
635
636void wxDC::DoDrawLine(
637  wxCoord                           vX1
638, wxCoord                           vY1
639, wxCoord                           vX2
640, wxCoord                           vY2
641)
642{
643    POINTL                          vPoint[2];
644    COLORREF                        vColor = 0x00ffffff;
645
646    //
647    // Might be a memory DC with no Paint rect.
648    //
649    if (!(m_vRclPaint.yTop == 0 &&
650          m_vRclPaint.yBottom == 0 &&
651          m_vRclPaint.xRight == 0 &&
652          m_vRclPaint.xLeft == 0))
653    {
654        vY1 = OS2Y(vY1,0);
655        vY2 = OS2Y(vY2,0);
656    }
657    else
658    {
659        if (m_vSelectedBitmap.Ok())
660        {
661            m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
662            m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
663            vY1 = OS2Y(vY1,0);
664            vY2 = OS2Y(vY2,0);
665        }
666    }
667    vPoint[0].x = vX1;
668    vPoint[0].y = vY1;
669    vPoint[1].x = vX2;
670    vPoint[1].y = vY2;
671    if (m_pen.Ok())
672    {
673        vColor = m_pen.GetColour().GetPixel();
674    }
675    ::GpiSetColor(m_hPS, vColor);
676    ::GpiMove(m_hPS, &vPoint[0]);
677    ::GpiLine(m_hPS, &vPoint[1]);
678    CalcBoundingBox(vX1, vY1);
679    CalcBoundingBox(vX2, vY2);
680} // end of wxDC::DoDrawLine
681
682//////////////////////////////////////////////////////////////////////////////
683// Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
684// and ending at (x2, y2). The current pen is used for the outline and the
685// current brush for filling the shape. The arc is drawn in an anticlockwise
686// direction from the start point to the end point.
687//////////////////////////////////////////////////////////////////////////////
688void wxDC::DoDrawArc(
689  wxCoord                           vX1
690, wxCoord                           vY1
691, wxCoord                           vX2
692, wxCoord                           vY2
693, wxCoord                           vXc
694, wxCoord                           vYc
695)
696{
697     POINTL                         vPtlPos;
698     POINTL                         vPtlArc[2]; // Structure for current position
699     double                         dRadius;
700     double                         dAngl1;
701     double                         dAngl2;
702     double                         dAnglmid;
703     wxCoord                        vXm;
704     wxCoord                        vYm;
705     ARCPARAMS                      vArcp; // Structure for arc parameters
706
707    if((vX1 == vXc && vY1 == vXc) || (vX2 == vXc && vY2 == vXc))
708        return; // Draw point ??
709    dRadius = 0.5 * ( hypot( (double)(vY1 - vYc)
710                            ,(double)(vX1 - vXc)
711                           ) +
712                      hypot( (double)(vY2 - vYc)
713                            ,(double)(vX2 - vXc)
714                           )
715                     );
716
717    dAngl1 = atan2( (double)(vY1 - vYc)
718                   ,(double)(vX1 - vXc)
719                  );
720    dAngl2 = atan2( (double)(vY2 - vYc)
721                   ,(double)(vX2 - vXc)
722                  );
723    if(dAngl2 < dAngl1)
724        dAngl2 += M_PI * 2;
725
726    //
727    // GpiPointArc can't draw full arc
728    //
729     if(dAngl2 == dAngl1 || (vX1 == vX2 && vY1 == vY2) )
730     {
731        //
732        // Medium point
733        //
734        dAnglmid = (dAngl1 + dAngl2)/2. + M_PI;
735        vXm      = (wxCoord)(vXc + dRadius * cos(dAnglmid));
736        vYm      = (wxCoord)(vYc + dRadius * sin(dAnglmid));
737        DoDrawArc( vX1, vY1
738                  ,vXm, vYm
739                  ,vXc, vYc
740                 );
741        DoDrawArc( vXm, vYm
742                  ,vX2, vY2
743                  ,vXc, vYc
744                 );
745        return;
746    }
747
748    //
749    // Medium point
750    //
751    dAnglmid = (dAngl1 + dAngl2)/2.;
752    vXm      = (wxCoord)(vXc + dRadius * cos(dAnglmid));
753    vYm      = (wxCoord)(vYc + dRadius * sin(dAnglmid));
754
755    //
756    // Ellipse main axis (r,q), (p,s) with center at (0,0) */
757    //
758    vArcp.lR = 0;
759    vArcp.lQ = 1;
760    vArcp.lP = 1;
761    vArcp.lS = 0;
762    ::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
763
764    vPtlPos.x = vX1; // Loads x-coordinate
765    vPtlPos.y = vY1; // Loads y-coordinate
766    ::GpiMove(m_hPS, &vPtlPos); // Sets current position
767    vPtlArc[0].x = vXm;
768    vPtlArc[0].y = vYm;
769    vPtlArc[1].x = vX2;
770    vPtlArc[1].y = vY2;
771    ::GpiPointArc(m_hPS, vPtlArc); // Draws the arc
772    CalcBoundingBox( (wxCoord)(vXc - dRadius)
773                    ,(wxCoord)(vYc - dRadius)
774                   );
775    CalcBoundingBox( (wxCoord)(vXc + dRadius)
776                    ,(wxCoord)(vYc + dRadius)
777                   );
778} // end of wxDC::DoDrawArc
779
780void wxDC::DoDrawCheckMark(
781  wxCoord                           vX1
782, wxCoord                           vY1
783, wxCoord                           vWidth
784, wxCoord                           vHeight
785)
786{
787    POINTL                          vPoint[2];
788
789    vY1 = OS2Y(vY1,vHeight);
790
791    vPoint[0].x = vX1;
792    vPoint[0].y = vY1;
793    vPoint[1].x = vX1 + vWidth;
794    vPoint[1].y = vY1 + vHeight;
795
796    ::GpiMove(m_hPS, &vPoint[0]);
797    ::GpiBox( m_hPS       // handle to a presentation space
798             ,DRO_OUTLINE // draw the box outline ? or ?
799             ,&vPoint[1]  // address of the corner
800             ,0L          // horizontal corner radius
801             ,0L          // vertical corner radius
802            );
803    if(vWidth > 4 && vHeight > 4)
804    {
805        int                         nTmp;
806
807        vPoint[0].x += 2; vPoint[0].y += 2;
808        vPoint[1].x -= 2; vPoint[1].y -= 2;
809        ::GpiMove(m_hPS, &vPoint[0]);
810        ::GpiLine(m_hPS, &vPoint[1]);
811        nTmp = vPoint[0].x;
812        vPoint[0].x = vPoint[1].x;
813        vPoint[1].x = nTmp;
814        ::GpiMove(m_hPS, &vPoint[0]);
815        ::GpiLine(m_hPS, &vPoint[1]);
816    }
817    CalcBoundingBox( vX1
818                    ,vY1
819                   );
820
821    wxCoord                         vX2 = vX1 + vWidth;
822    wxCoord                         vY2 = vY1 + vHeight;
823
824    CalcBoundingBox( vX2
825                    ,vY2
826                   );
827} // end of wxDC::DoDrawCheckMark
828
829void wxDC::DoDrawPoint(
830  wxCoord                           vX
831, wxCoord                           vY
832)
833{
834    POINTL                          vPoint;
835    COLORREF                        vColor = 0x00ffffff;
836
837    if (m_pen.Ok())
838    {
839        vColor = m_pen.GetColour().GetPixel();
840    }
841    ::GpiSetColor(m_hPS, vColor);
842    vPoint.x = vX;
843    vPoint.y = OS2Y(vY,0);
844    ::GpiSetPel(m_hPS, &vPoint);
845    CalcBoundingBox( vX
846                    ,vY
847                   );
848} // end of wxDC::DoDrawPoint
849
850void wxDC::DoDrawPolygon( int n,
851                          wxPoint vPoints[],
852                          wxCoord vXoffset,
853                          wxCoord vYoffset,
854                          int nFillStyle )
855{
856    ULONG     ulCount = 1;    // Number of polygons.
857    POLYGON   vPlgn;          // polygon.
858    ULONG     flOptions = 0L; // Drawing options.
859
860    //////////////////////////////////////////////////////////////////////////////
861    // This contains fields of option bits... to draw boundary lines as well as
862    // the area interior.
863    //
864    // Drawing boundary lines:
865    //   POLYGON_NOBOUNDARY              Does not draw boundary lines.
866    //   POLYGON_BOUNDARY                Draws boundary lines (the default).
867    //
868    // Construction of the area interior:
869    //   POLYGON_ALTERNATE               Constructs interior in alternate mode
870    //                                   (the default).
871    //   POLYGON_WINDING                 Constructs interior in winding mode.
872    //////////////////////////////////////////////////////////////////////////////
873
874    ULONG     flModel = POLYGON_INCL; // Drawing model.
875
876    //////////////////////////////////////////////////////////////////////////////
877    // Drawing model.
878    //   POLYGON_INCL  Fill is inclusive of bottom right (the default).
879    //   POLYGON_EXCL  Fill is exclusive of bottom right.
880    //       This is provided to aid migration from other graphics models.
881    //////////////////////////////////////////////////////////////////////////////
882
883    LONG      lHits = 0L; // Correlation/error indicator.
884    int       i;
885    int       nIsTRANSPARENT = 0;
886    LONG      lBorderColor = 0L;
887    LONG      lColor = 0L;
888
889    lBorderColor = m_pen.GetColour().GetPixel();
890    lColor       = m_brush.GetColour().GetPixel();
891    if(m_brush.GetStyle() == wxTRANSPARENT)
892        nIsTRANSPARENT = 1;
893
894    vPlgn.ulPoints = n;
895    vPlgn.aPointl = (POINTL*) calloc( n + 1
896                                     ,sizeof(POINTL)
897                                    ); // well, new will call malloc
898
899    for(i = 0; i < n; i++)
900    {
901        vPlgn.aPointl[i].x = vPoints[i].x+vXoffset;
902        vPlgn.aPointl[i].y = OS2Y(vPoints[i].y+vYoffset,0);
903    }
904    flOptions = POLYGON_BOUNDARY;
905    if(nFillStyle == wxWINDING_RULE)
906        flOptions |= POLYGON_WINDING;
907    else
908        flOptions |= POLYGON_ALTERNATE;
909
910    ::GpiSetColor(m_hPS, lBorderColor);
911    ::GpiMove(m_hPS, &vPlgn.aPointl[0]);
912    lHits = ::GpiPolygons(m_hPS, ulCount, &vPlgn, flOptions, flModel);
913    free(vPlgn.aPointl);
914} // end of wxDC::DoDrawPolygon
915
916void wxDC::DoDrawLines(
917  int                               n
918, wxPoint                           vPoints[]
919, wxCoord                           vXoffset
920, wxCoord                           vYoffset
921)
922{
923    POINTL                          vPoint;
924
925    if (vXoffset != 0L || vXoffset != 0L)
926    {
927        int                             i;
928
929        vPoint.x = vPoints[0].x + vXoffset;
930        vPoint.y = OS2Y(vPoints[0].y + vYoffset,0);
931        ::GpiMove(m_hPS, &vPoint);
932
933        LONG                            lBorderColor = m_pen.GetColour().GetPixel();
934
935        ::GpiSetColor(m_hPS, lBorderColor);
936        for(i = 1; i < n; i++)
937        {
938            vPoint.x = vPoints[i].x + vXoffset;
939            vPoint.y = OS2Y(vPoints[i].y + vYoffset,0);
940            ::GpiLine(m_hPS, &vPoint);
941        }
942    }
943    else
944    {
945        int                         i;
946
947        CalcBoundingBox( vPoints[0].x
948                        ,vPoints[0].y
949                       );
950        vPoint.x = vPoints[0].x;
951        vPoint.y = OS2Y(vPoints[0].y,0);
952        ::GpiMove(m_hPS, &vPoint);
953
954        for (i = 0; i < n; i++)
955        {
956            CalcBoundingBox( vPoints[i].x
957                            ,vPoints[i].y
958                           );
959            vPoint.x = vPoints[i].x;
960            vPoint.y = OS2Y(vPoints[i].y,0);
961            ::GpiLine(m_hPS, &vPoint);
962        }
963    }
964} // end of wxDC::DoDrawLines
965
966void wxDC::DoDrawRectangle(
967  wxCoord                           vX
968, wxCoord                           vY
969, wxCoord                           vWidth
970, wxCoord                           vHeight
971)
972{
973    POINTL                          vPoint[2];
974    LONG                            lControl;
975    LONG                            lColor;
976    LONG                            lBorderColor;
977    int                             nIsTRANSPARENT = 0;
978
979    //
980    // Might be a memory DC with no Paint rect.
981    //
982    if (!(m_vRclPaint.yTop == 0 &&
983          m_vRclPaint.yBottom == 0 &&
984          m_vRclPaint.xRight == 0 &&
985          m_vRclPaint.xLeft == 0))
986        vY = OS2Y(vY,vHeight);
987    else
988    {
989        if (m_vSelectedBitmap.Ok())
990        {
991            m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
992            m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
993            vY = OS2Y(vY,vHeight);
994        }
995    }
996
997    wxCoord                         vX2 = vX + vWidth;
998    wxCoord                         vY2 = vY + vHeight;
999
1000    vPoint[0].x = vX;
1001    vPoint[0].y = vY;
1002    vPoint[1].x = vX + vWidth - 1;
1003    vPoint[1].y = vY + vHeight - 1;
1004    ::GpiMove(m_hPS, &vPoint[0]);
1005    lColor       = m_brush.GetColour().GetPixel();
1006    lBorderColor = m_pen.GetColour().GetPixel();
1007    if (m_brush.GetStyle() == wxTRANSPARENT)
1008        nIsTRANSPARENT = 1;
1009    if(lColor == lBorderColor || nIsTRANSPARENT)
1010    {
1011        lControl = DRO_OUTLINEFILL; //DRO_FILL;
1012        if(m_brush.GetStyle() == wxTRANSPARENT)
1013            lControl = DRO_OUTLINE;
1014
1015        ::GpiSetColor(m_hPS, lBorderColor);
1016        ::GpiBox( m_hPS       // handle to a presentation space
1017                 ,lControl   // draw the box outline ? or ?
1018                 ,&vPoint[1]  // address of the corner
1019                 ,0L          // horizontal corner radius
1020                 ,0L          // vertical corner radius
1021                );
1022    }
1023    else
1024    {
1025        lControl = DRO_OUTLINE;
1026        ::GpiSetColor( m_hPS
1027                      ,lBorderColor
1028                     );
1029        ::GpiBox( m_hPS
1030                 ,lControl
1031                 ,&vPoint[1]
1032                 ,0L
1033                 ,0L
1034                );
1035        lControl = DRO_FILL;
1036        ::GpiSetColor( m_hPS
1037                      ,lColor
1038                     );
1039        vPoint[0].x = vX + 1;
1040        vPoint[0].y = vY + 1;
1041        vPoint[1].x = vX + vWidth - 2;
1042        vPoint[1].y = vY + vHeight - 2;
1043        ::GpiMove(m_hPS, &vPoint[0]);
1044        ::GpiBox( m_hPS
1045                 ,lControl
1046                 ,&vPoint[1]
1047                 ,0L
1048                 ,0L
1049                );
1050    }
1051    CalcBoundingBox(vX, vY);
1052    CalcBoundingBox(vX2, vY2);
1053} // end of wxDC::DoDrawRectangle
1054
1055void wxDC::DoDrawRoundedRectangle(
1056  wxCoord                           vX
1057, wxCoord                           vY
1058, wxCoord                           vWidth
1059, wxCoord                           vHeight
1060, double                            dRadius
1061)
1062{
1063    POINTL                          vPoint[2];
1064    LONG                            lControl;
1065    LONG                            lColor;
1066    LONG                            lBorderColor;
1067    int                             nIsTRANSPARENT = 0;
1068
1069    //
1070    // Might be a memory DC with no Paint rect.
1071    //
1072    if (!(m_vRclPaint.yTop == 0 &&
1073          m_vRclPaint.yBottom == 0 &&
1074          m_vRclPaint.xRight == 0 &&
1075          m_vRclPaint.xLeft == 0))
1076        vY = OS2Y(vY,vHeight);
1077    else
1078    {
1079        if (m_vSelectedBitmap.Ok())
1080        {
1081            m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
1082            m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
1083            vY = OS2Y(vY,vHeight);
1084        }
1085    }
1086
1087    wxCoord                         vX2 = (vX + vWidth);
1088    wxCoord                         vY2 = (vY + vHeight);
1089
1090    vPoint[0].x = vX;
1091    vPoint[0].y = vY;
1092    vPoint[1].x = vX + vWidth - 1;
1093    vPoint[1].y = vY + vHeight - 1;
1094    ::GpiMove(m_hPS, &vPoint[0]);
1095
1096    lColor       = m_brush.GetColour().GetPixel();
1097    lBorderColor = m_pen.GetColour().GetPixel();
1098    lControl = DRO_OUTLINEFILL; //DRO_FILL;
1099    if (m_brush.GetStyle() == wxTRANSPARENT)
1100        nIsTRANSPARENT = 1;
1101    if(lColor == lBorderColor || nIsTRANSPARENT)
1102    {
1103        lControl = DRO_OUTLINEFILL; //DRO_FILL;
1104        if(m_brush.GetStyle() == wxTRANSPARENT)
1105            lControl = DRO_OUTLINE;
1106
1107        ::GpiSetColor(m_hPS, lColor);
1108        ::GpiBox( m_hPS         // handle to a presentation space
1109                 ,lControl      // draw the box outline ? or ?
1110                 ,&vPoint[1]    // address of the corner
1111                 ,(LONG)dRadius // horizontal corner radius
1112                 ,(LONG)dRadius // vertical corner radius
1113                );
1114    }
1115    else
1116    {
1117        lControl = DRO_OUTLINE;
1118        ::GpiSetColor( m_hPS
1119                      ,lBorderColor
1120                     );
1121        ::GpiBox( m_hPS
1122                 ,lControl
1123                 ,&vPoint[1]
1124                 ,(LONG)dRadius
1125                 ,(LONG)dRadius
1126                );
1127        lControl = DRO_FILL;
1128        ::GpiSetColor( m_hPS
1129                      ,lColor
1130                     );
1131        vPoint[0].x = vX + 1;
1132        vPoint[0].y = vY + 1;
1133        vPoint[1].x = vX + vWidth - 2;
1134        vPoint[1].y = vY + vHeight - 2;
1135        ::GpiMove(m_hPS, &vPoint[0]);
1136        ::GpiBox( m_hPS
1137                 ,lControl
1138                 ,&vPoint[1]
1139                 ,(LONG)dRadius
1140                 ,(LONG)dRadius
1141                );
1142    }
1143
1144    CalcBoundingBox(vX, vY);
1145    CalcBoundingBox(vX2, vY2);
1146} // end of wxDC::DoDrawRoundedRectangle
1147
1148// Draw Ellipse within box (x,y) - (x+width, y+height)
1149void wxDC::DoDrawEllipse(
1150  wxCoord                           vX
1151, wxCoord                           vY
1152, wxCoord                           vWidth
1153, wxCoord                           vHeight
1154)
1155{
1156    POINTL                          vPtlPos; // Structure for current position
1157    FIXED                           vFxMult; // Multiplier for ellipse
1158    ARCPARAMS                       vArcp;   // Structure for arc parameters
1159
1160    vY = OS2Y(vY,vHeight);
1161
1162    vArcp.lR = 0;
1163    vArcp.lQ = vHeight/2;
1164    vArcp.lP = vWidth/2;
1165    vArcp.lS = 0;
1166    ::GpiSetArcParams( m_hPS
1167                      ,&vArcp
1168                     ); // Sets parameters to default
1169    vPtlPos.x = vX + vWidth/2;  // Loads x-coordinate
1170    vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
1171    ::GpiMove( m_hPS
1172              ,&vPtlPos
1173             ); // Sets current position
1174    vFxMult = MAKEFIXED(1, 0);             /* Sets multiplier            */
1175
1176    //
1177    // DRO_FILL, DRO_OTLINEFILL - where to get
1178    //
1179    ::GpiFullArc( m_hPS
1180                 ,DRO_OUTLINE
1181                 ,vFxMult
1182                ); // Draws full arc with center at current position
1183
1184    wxCoord                         vX2 = (vX + vWidth);
1185    wxCoord                         vY2 = (vY + vHeight);
1186
1187    CalcBoundingBox(vX, vY);
1188    CalcBoundingBox(vX2, vY2);
1189} // end of wxDC::DoDrawEllipse
1190
1191void wxDC::DoDrawEllipticArc(
1192  wxCoord                           vX
1193, wxCoord                           vY
1194, wxCoord                           vWidth
1195, wxCoord                           vHeight
1196, double                            dSa
1197, double                            dEa
1198)
1199{
1200    POINTL                          vPtlPos; // Structure for current position
1201    FIXED                           vFxMult; // Multiplier for ellipse
1202    ARCPARAMS                       vArcp;   // Structure for arc parameters
1203    FIXED                           vFSa;
1204    FIXED                           vFSweepa; // Start angle, sweep angle
1205    double                          dIntPart;
1206    double                          dFractPart;
1207
1208    vY = OS2Y(vY,vHeight);
1209
1210    dFractPart = modf(dSa,&dIntPart);
1211    vFSa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
1212    dFractPart = modf(dEa - dSa, &dIntPart);
1213    vFSweepa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
1214
1215    //
1216    // Ellipse main axis (r,q), (p,s) with center at (0,0)
1217    //
1218    vArcp.lR = 0;
1219    vArcp.lQ = vHeight/2;
1220    vArcp.lP = vWidth/2;
1221    vArcp.lS = 0;
1222    ::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
1223    vPtlPos.x = (wxCoord)(vX + vWidth/2  * (1. + cos(DegToRad(dSa)))); // Loads x-coordinate
1224    vPtlPos.y = (wxCoord)(vY + vHeight/2 * (1. + sin(DegToRad(dSa)))); // Loads y-coordinate
1225    ::GpiMove(m_hPS, &vPtlPos); // Sets current position
1226
1227    //
1228    // May be not to the center ?
1229    //
1230    vPtlPos.x = vX + vWidth/2 ; // Loads x-coordinate
1231    vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
1232    vFxMult = MAKEFIXED(1, 0);  // Sets multiplier
1233
1234    //
1235    // DRO_FILL, DRO_OTLINEFILL - where to get
1236    //
1237    ::GpiPartialArc( m_hPS
1238                    ,&vPtlPos
1239                    ,vFxMult
1240                    ,vFSa
1241                    ,vFSweepa
1242                   );
1243    wxCoord                         vX2 = (vX + vWidth);
1244    wxCoord                         vY2 = (vY + vHeight);
1245
1246    CalcBoundingBox(vX, vY);
1247    CalcBoundingBox(vX2, vY2);
1248} // end of wxDC::DoDrawEllipticArc
1249
1250void wxDC::DoDrawIcon(
1251  const wxIcon&                     rIcon
1252, wxCoord                           vX
1253, wxCoord                           vY
1254)
1255{
1256    //
1257    // Need to copy back into a bitmap.  ::WinDrawPointer uses device coords
1258    // and I don't feel like figuring those out for scrollable windows so
1259    // just convert to a bitmap then let the DoDrawBitmap routine display it
1260    //
1261    if (rIcon.IsXpm())
1262    {
1263        DoDrawBitmap(rIcon.GetXpmSrc(), vX, vY, true);
1264    }
1265    else
1266    {
1267        wxBitmap                        vBitmap(rIcon);
1268
1269        DoDrawBitmap(vBitmap, vX, vY, false);
1270    }
1271    CalcBoundingBox(vX, vY);
1272    CalcBoundingBox(vX + rIcon.GetWidth(), vY + rIcon.GetHeight());
1273} // end of wxDC::DoDrawIcon
1274
1275void wxDC::DoDrawBitmap(
1276  const wxBitmap&                   rBmp
1277, wxCoord                           vX
1278, wxCoord                           vY
1279, bool                              bUseMask
1280)
1281{
1282#if wxUSE_PRINTING_ARCHITECTURE
1283    if (!IsKindOf(CLASSINFO(wxPrinterDC)))
1284#endif
1285    {
1286        HBITMAP                         hBitmap =  (HBITMAP)rBmp.GetHBITMAP();
1287        HBITMAP                         hBitmapOld = NULLHANDLE;
1288        POINTL                          vPoint[4];
1289
1290        vY = OS2Y(vY,rBmp.GetHeight());
1291
1292        vPoint[0].x = vX;
1293        vPoint[0].y = vY + rBmp.GetHeight();
1294        vPoint[1].x = vX + rBmp.GetWidth();
1295        vPoint[1].y = vY;
1296        vPoint[2].x = 0;
1297        vPoint[2].y = 0;
1298        vPoint[3].x = rBmp.GetWidth();
1299        vPoint[3].y = rBmp.GetHeight();
1300        if (bUseMask)
1301        {
1302            wxMask*                     pMask = rBmp.GetMask();
1303
1304            if (pMask)
1305            {
1306                //
1307                // Need to imitate ::MaskBlt in windows.
1308                // 1) Extract the bits from from the bitmap.
1309                // 2) Extract the bits from the mask
1310                // 3) Using the mask bits do the following:
1311                //   A) If the mask byte is 00 leave the bitmap byte alone
1312                //   B) If the mask byte is FF copy the screen color into
1313                //      bitmap byte
1314                // 4) Create a new bitmap and set its bits to the above result
1315                // 5) Blit this to the screen PS
1316                //
1317                HBITMAP                 hMask = (HBITMAP)pMask->GetMaskBitmap();
1318                HBITMAP                 hOldMask   = NULLHANDLE;
1319                HBITMAP                 hOldBitmap = NULLHANDLE;
1320                HBITMAP                 hNewBitmap = NULLHANDLE;
1321                unsigned char*          pucBits;     // buffer that will contain the bitmap data
1322                unsigned char*          pucBitsMask; // buffer that will contain the mask data
1323                unsigned char*          pucData;     // pointer to use to traverse bitmap data
1324                unsigned char*          pucDataMask; // pointer to use to traverse mask data
1325                LONG                    lHits;
1326                ERRORID                 vError;
1327                wxString                sError;
1328
1329                //
1330                // The usual Memory context creation stuff
1331                //
1332                DEVOPENSTRUC                    vDop  = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1333                SIZEL                           vSize = {0, 0};
1334                HDC                             hDC   = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1335                HPS                             hPS   = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
1336
1337                //
1338                // The usual bitmap header stuff
1339                //
1340                BITMAPINFOHEADER2               vHeader;
1341                BITMAPINFO2                     vInfo;
1342
1343                memset(&vHeader, '\0', 16);
1344                vHeader.cbFix           = 16;
1345
1346                memset(&vInfo, '\0', 16);
1347                vInfo.cbFix           = 16;
1348                vInfo.cx              = (ULONG)rBmp.GetWidth();
1349                vInfo.cy              = (ULONG)rBmp.GetHeight();
1350                vInfo.cPlanes         = 1;
1351                vInfo.cBitCount       = 24; // Set to desired count going in
1352
1353                //
1354                // Create the buffers for data....all wxBitmaps are 24 bit internally
1355                //
1356                int                     nBytesPerLine = rBmp.GetWidth() * 3;
1357                int                     nSizeDWORD    = sizeof(DWORD);
1358                int                     nLineBoundary = nBytesPerLine % nSizeDWORD;
1359                int                     nPadding = 0;
1360                int                     i;
1361                int                     j;
1362                LONG                    lScans = 0L;
1363                LONG                    lColor = 0L;
1364
1365                //
1366                // Need to get a background color for mask blitting
1367                //
1368                if (IsKindOf(CLASSINFO(wxWindowDC)))
1369                {
1370                    wxWindowDC*             pWindowDC = wxDynamicCast(this, wxWindowDC);
1371
1372                    lColor = pWindowDC->m_pCanvas->GetBackgroundColour().GetPixel();
1373                }
1374                else if (GetBrush().Ok())
1375                    lColor = GetBrush().GetColour().GetPixel();
1376                else
1377                    lColor = m_textBackgroundColour.GetPixel();
1378
1379                //
1380                // Bitmap must be in a double-word aligned address so we may
1381                // have some padding to worry about
1382                //
1383                if (nLineBoundary > 0)
1384                {
1385                    nPadding     = nSizeDWORD - nLineBoundary;
1386                    nBytesPerLine += nPadding;
1387                }
1388                pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
1389                pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
1390                memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
1391                memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
1392
1393                //
1394                // Extract the bitmap and mask data
1395                //
1396                if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
1397                {
1398                    vError = ::WinGetLastError(vHabmain);
1399                    sError = wxPMErrorToStr(vError);
1400                }
1401                ::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
1402                vInfo.cBitCount = 24;
1403                if ((lScans = ::GpiQueryBitmapBits( hPS
1404                                                   ,0L
1405                                                   ,(LONG)rBmp.GetHeight()
1406                                                   ,(PBYTE)pucBits
1407                                                   ,&vInfo
1408                                                  )) == GPI_ALTERROR)
1409                {
1410                    vError = ::WinGetLastError(vHabmain);
1411                    sError = wxPMErrorToStr(vError);
1412                }
1413                if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
1414                {
1415                    vError = ::WinGetLastError(vHabmain);
1416                    sError = wxPMErrorToStr(vError);
1417                }
1418                ::GpiQueryBitmapInfoHeader(hMask, &vHeader);
1419                vInfo.cBitCount = 24;
1420                if ((lScans = ::GpiQueryBitmapBits( hPS
1421                                                   ,0L
1422                                                   ,(LONG)rBmp.GetHeight()
1423                                                   ,(PBYTE)pucBitsMask
1424                                                   ,&vInfo
1425                                                  )) == GPI_ALTERROR)
1426                {
1427                    vError = ::WinGetLastError(vHabmain);
1428                    sError = wxPMErrorToStr(vError);
1429                }
1430                if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
1431                {
1432                    vError = ::WinGetLastError(vHabmain);
1433                    sError = wxPMErrorToStr(vError);
1434                }
1435
1436                //
1437                // Now set the bytes(bits) according to the mask values
1438                // 3 bytes per pel...must handle one at a time
1439                //
1440                pucData     = pucBits;
1441                pucDataMask = pucBitsMask;
1442
1443                //
1444                // 16 bit kludge really only kinda works.  The mask gets applied
1445                // where needed but the original bitmap bits are dorked sometimes
1446                //
1447                bool                    bpp16 = (wxDisplayDepth() == 16);
1448
1449                for (i = 0; i < rBmp.GetHeight(); i++)
1450                {
1451                    for (j = 0; j < rBmp.GetWidth(); j++)
1452                    {
1453                        // Byte 1
1454                        if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
1455                            pucData++;
1456                        else if (*pucDataMask == 0xFF) // leave bitmap byte alone
1457                            pucData++;
1458                        else
1459                        {
1460                            *pucData = ((unsigned char)(lColor >> 16));
1461                            pucData++;
1462                        }
1463                        // Byte 2
1464                        if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
1465                            pucData++;
1466                        else if (*(pucDataMask + 1) == 0xFF) // leave bitmap byte alone
1467                            pucData++;
1468                        else
1469                        {
1470                            *pucData = ((unsigned char)(lColor >> 8));
1471                            pucData++;
1472                        }
1473
1474                        // Byte 3
1475                        if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
1476                            pucData++;
1477                        else if (*(pucDataMask + 2) == 0xFF) // leave bitmap byte alone
1478                            pucData++;
1479                        else
1480                        {
1481                            *pucData = ((unsigned char)lColor);
1482                            pucData++;
1483                        }
1484                        pucDataMask += 3;
1485                    }
1486                    for (j = 0; j < nPadding; j++)
1487                    {
1488                        pucData++;
1489                        pucDataMask++;
1490                    }
1491                }
1492                //
1493                // Create a new bitmap
1494                //
1495                vHeader.cx              = (ULONG)rBmp.GetWidth();
1496                vHeader.cy              = (ULONG)rBmp.GetHeight();
1497                vHeader.cPlanes         = 1L;
1498                vHeader.cBitCount       = 24;
1499                if ((hNewBitmap = ::GpiCreateBitmap( hPS
1500                                                    ,&vHeader
1501                                                    ,CBM_INIT
1502                                                    ,(PBYTE)pucBits
1503                                                    ,&vInfo
1504                                                   )) == GPI_ERROR)
1505                {
1506                    vError = ::WinGetLastError(vHabmain);
1507                    sError = wxPMErrorToStr(vError);
1508                }
1509
1510                //
1511                // Now blit it to the screen PS
1512                //
1513                if ((lHits = ::GpiWCBitBlt( (HPS)GetHPS()
1514                                           ,hNewBitmap
1515                                           ,4
1516                                           ,vPoint
1517                                           ,ROP_SRCCOPY
1518                                           ,BBO_IGNORE
1519                                          )) == GPI_ERROR)
1520                {
1521                    vError = ::WinGetLastError(vHabmain);
1522                    sError = wxPMErrorToStr(vError);
1523                }
1524
1525                //
1526                // Clean up
1527                //
1528                free(pucBits);
1529                free(pucBitsMask);
1530                ::GpiSetBitmap(hPS, NULLHANDLE);
1531                ::GpiDeleteBitmap(hNewBitmap);
1532                ::GpiDestroyPS(hPS);
1533                ::DevCloseDC(hDC);
1534            }
1535        }
1536        else
1537        {
1538            ULONG                       lOldForeGround = ::GpiQueryColor((HPS)GetHPS());
1539            ULONG                       lOldBackGround = ::GpiQueryBackColor((HPS)GetHPS());
1540
1541            if (m_textForegroundColour.Ok())
1542            {
1543                ::GpiSetColor( (HPS)GetHPS()
1544                               ,m_textForegroundColour.GetPixel()
1545                              );
1546            }
1547            if (m_textBackgroundColour.Ok())
1548            {
1549                ::GpiSetBackColor( (HPS)GetHPS()
1550                                  ,m_textBackgroundColour.GetPixel()
1551                                 );
1552            }
1553            //
1554            // Need to alter bits in a mono bitmap to match the new
1555            // background-foreground if it is different.
1556            //
1557            if (rBmp.IsMono() &&
1558               ((m_textForegroundColour.GetPixel() != lOldForeGround) ||
1559                (m_textBackgroundColour.GetPixel() != lOldBackGround)))
1560            {
1561                DEVOPENSTRUC        vDop  = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1562                SIZEL               vSize = {0, 0};
1563                HDC                 hDC   = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1564                HPS                 hPS   = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
1565
1566                int                 nBytesPerLine = rBmp.GetWidth() * 3;
1567                int                 i, j;
1568                LONG                lForeGround = m_textForegroundColour.GetPixel();
1569                LONG                lBackGround = m_textBackgroundColour.GetPixel();
1570                LONG                lScans;
1571                HBITMAP             hOldBitmap = NULLHANDLE;
1572                BITMAPINFO2         vInfo;
1573                ERRORID             vError;
1574                wxString            sError;
1575
1576
1577                memset(&vInfo, '\0', 16);
1578                vInfo.cbFix           = 16;
1579                vInfo.cx              = (ULONG)rBmp.GetWidth();
1580                vInfo.cy              = (ULONG)rBmp.GetHeight();
1581                vInfo.cPlanes         = 1;
1582                vInfo.cBitCount       = 24;
1583
1584                unsigned char*          pucBits;     // buffer that will contain the bitmap data
1585                unsigned char*          pucData;     // pointer to use to traverse bitmap data
1586
1587                pucBits = new unsigned char[nBytesPerLine * rBmp.GetHeight()];
1588                memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
1589
1590                if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
1591                {
1592                    vError = ::WinGetLastError(vHabmain);
1593                    sError = wxPMErrorToStr(vError);
1594                    return;
1595                }
1596                if ((lScans = ::GpiQueryBitmapBits( hPS
1597                                                   ,0L
1598                                                   ,(LONG)rBmp.GetHeight()
1599                                                   ,(PBYTE)pucBits
1600                                                   ,&vInfo
1601                                                  )) == GPI_ALTERROR)
1602                {
1603                    vError = ::WinGetLastError(vHabmain);
1604                    sError = wxPMErrorToStr(vError);
1605                    return;
1606                }
1607                unsigned char           cOldRedFore   = (unsigned char)(lOldForeGround >> 16);
1608                unsigned char           cOldGreenFore = (unsigned char)(lOldForeGround >> 8);
1609                unsigned char           cOldBlueFore  = (unsigned char)lOldForeGround;
1610
1611                unsigned char           cRedFore   = (unsigned char)(lForeGround >> 16);
1612                unsigned char           cGreenFore = (unsigned char)(lForeGround >> 8);
1613                unsigned char           cBlueFore  = (unsigned char)lForeGround;
1614
1615                unsigned char           cRedBack   = (unsigned char)(lBackGround >> 16);
1616                unsigned char           cGreenBack = (unsigned char)(lBackGround >> 8);
1617                unsigned char           cBlueBack  = (unsigned char)lBackGround;
1618
1619                pucData = pucBits;
1620                for (i = 0; i < rBmp.GetHeight(); i++)
1621                {
1622                    for (j = 0; j < rBmp.GetWidth(); j++)
1623                    {
1624                        unsigned char    cBmpRed   = *pucData;
1625                        unsigned char    cBmpGreen = *(pucData + 1);
1626                        unsigned char    cBmpBlue  = *(pucData + 2);
1627
1628                        if ((cBmpRed == cOldRedFore) &&
1629                            (cBmpGreen == cOldGreenFore) &&
1630                            (cBmpBlue == cOldBlueFore))
1631                        {
1632                            *pucData = cBlueFore;
1633                            pucData++;
1634                            *pucData = cGreenFore;
1635                            pucData++;
1636                            *pucData = cRedFore;
1637                            pucData++;
1638                        }
1639                        else
1640                        {
1641                            *pucData = cBlueBack;
1642                            pucData++;
1643                            *pucData = cGreenBack;
1644                            pucData++;
1645                            *pucData = cRedBack;
1646                            pucData++;
1647                        }
1648                    }
1649                }
1650                if ((lScans = ::GpiSetBitmapBits( hPS
1651                                                 ,0L
1652                                                 ,(LONG)rBmp.GetHeight()
1653                                                 ,(PBYTE)pucBits
1654                                                 ,&vInfo
1655                                                )) == GPI_ALTERROR)
1656                {
1657                    vError = ::WinGetLastError(vHabmain);
1658                    sError = wxPMErrorToStr(vError);
1659                    return;
1660                }
1661                delete [] pucBits;
1662                ::GpiSetBitmap(hPS, NULLHANDLE);
1663                ::GpiDestroyPS(hPS);
1664                ::DevCloseDC(hDC);
1665            }
1666            ::GpiWCBitBlt( (HPS)GetHPS()
1667                          ,hBitmap
1668                          ,4
1669                          ,vPoint
1670                          ,ROP_SRCCOPY
1671                          ,BBO_IGNORE
1672                         );
1673            ::GpiSetBitmap((HPS)GetHPS(), hBitmapOld);
1674            ::GpiSetColor((HPS)GetHPS(), lOldForeGround);
1675            ::GpiSetBackColor((HPS)GetHPS(), lOldBackGround);
1676        }
1677    }
1678} // end of wxDC::DoDrawBitmap
1679
1680void wxDC::DoDrawText(
1681  const wxString&                   rsText
1682, wxCoord                           vX
1683, wxCoord                           vY
1684)
1685{
1686    wxCoord                         vWidth;
1687    wxCoord                         vHeight;
1688
1689    DrawAnyText( rsText
1690                ,vX
1691                ,vY
1692               );
1693
1694    CalcBoundingBox(vX, vY);
1695    GetTextExtent(rsText, &vWidth, &vHeight);
1696    CalcBoundingBox((vX + vWidth), (vY + vHeight));
1697} // end of wxDC::DoDrawText
1698
1699void wxDC::DrawAnyText( const wxString& rsText,
1700                        wxCoord vX,
1701                        wxCoord vY )
1702{
1703    int                             nOldBackground = 0;
1704    POINTL                          vPtlStart;
1705    LONG                            lHits;
1706    wxCoord                         vTextX = 0;
1707    wxCoord                         vTextY = 0;
1708
1709    //
1710    // prepare for drawing the text
1711    //
1712
1713    //
1714    // Set text color attributes
1715    //
1716    if (m_textForegroundColour.Ok())
1717    {
1718        SetTextColor( m_hPS
1719                     ,(int)m_textForegroundColour.GetPixel()
1720                    );
1721    }
1722
1723    if (m_textBackgroundColour.Ok())
1724    {
1725        nOldBackground = SetTextBkColor( m_hPS
1726                                        ,(int)m_textBackgroundColour.GetPixel()
1727                                       );
1728    }
1729    SetBkMode( m_hPS
1730              ,m_backgroundMode
1731             );
1732    GetTextExtent( rsText
1733                  ,&vTextX
1734                  ,&vTextY
1735                 );
1736    vPtlStart.x = vX;
1737    if (!(m_vRclPaint.yTop == 0 &&
1738          m_vRclPaint.yBottom == 0 &&
1739          m_vRclPaint.xRight == 0 &&
1740          m_vRclPaint.xLeft == 0))
1741    {
1742        vPtlStart.y = OS2Y(vY,vTextY);
1743    }
1744    else
1745    {
1746        if (m_vSelectedBitmap.Ok())
1747        {
1748            m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
1749            m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
1750            vPtlStart.y = OS2Y(vY,vTextY);
1751        }
1752        else
1753            vPtlStart.y = vY;
1754    }
1755
1756    PCH pzStr = (PCH)rsText.c_str();
1757
1758    ::GpiMove(m_hPS, &vPtlStart);
1759    lHits = ::GpiCharString( m_hPS
1760                            ,rsText.length()
1761                            ,pzStr
1762                           );
1763    if (lHits != GPI_OK)
1764    {
1765        wxLogLastError(wxT("TextOut"));
1766    }
1767
1768    //
1769    // Restore the old parameters (text foreground colour may be left because
1770    // it never is set to anything else, but background should remain
1771    // transparent even if we just drew an opaque string)
1772    //
1773    if (m_textBackgroundColour.Ok())
1774            SetTextBkColor( m_hPS
1775                           ,nOldBackground
1776                          );
1777    SetBkMode( m_hPS
1778              ,wxTRANSPARENT
1779             );
1780}
1781
1782void wxDC::DoDrawRotatedText(
1783  const wxString&                   rsText
1784, wxCoord                           vX
1785, wxCoord                           vY
1786, double                            dAngle
1787)
1788{
1789    if (dAngle == 0.0)
1790    {
1791        DoDrawText( rsText
1792                   ,vX
1793                   ,vY
1794                  );
1795    }
1796
1797   // TODO:
1798   /*
1799    if ( angle == 0.0 )
1800    {
1801        DoDrawText(text, x, y);
1802    }
1803    else
1804    {
1805        LOGFONT lf;
1806        wxFillLogFont(&lf, &m_font);
1807
1808        // GDI wants the angle in tenth of degree
1809        long angle10 = (long)(angle * 10);
1810        lf.lfEscapement = angle10;
1811        lf. lfOrientation = angle10;
1812
1813        HFONT hfont = ::CreateFontIndirect(&lf);
1814        if ( !hfont )
1815        {
1816            wxLogLastError("CreateFont");
1817        }
1818        else
1819        {
1820            HFONT hfontOld = ::SelectObject(GetHdc(), hfont);
1821
1822            DrawAnyText(text, x, y);
1823
1824            (void)::SelectObject(GetHdc(), hfontOld);
1825        }
1826
1827        // call the bounding box by adding all four vertices of the rectangle
1828        // containing the text to it (simpler and probably not slower than
1829        // determining which of them is really topmost/leftmost/...)
1830        wxCoord w, h;
1831        GetTextExtent(text, &w, &h);
1832
1833        double rad = DegToRad(angle);
1834
1835        // "upper left" and "upper right"
1836        CalcBoundingBox(x, y);
1837        CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
1838        CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
1839
1840        // "bottom left" and "bottom right"
1841        x += (wxCoord)(h*sin(rad));
1842        y += (wxCoord)(h*cos(rad));
1843        CalcBoundingBox(x, y);
1844        CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
1845    }
1846*/
1847}
1848
1849// ---------------------------------------------------------------------------
1850// set GDI objects
1851// ---------------------------------------------------------------------------
1852
1853void wxDC::DoSelectPalette( bool WXUNUSED(bRealize) )
1854{
1855    //
1856    // Set the old object temporarily, in case the assignment deletes an object
1857    // that's not yet selected out.
1858    //
1859    if (m_hOldPalette)
1860    {
1861        m_hOldPalette = 0;
1862    }
1863
1864    if (m_palette.Ok())
1865    {
1866        HPALETTE                    hOldPal;
1867
1868        hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
1869        if (!m_hOldPalette)
1870            m_hOldPalette = (WXHPALETTE)hOldPal;
1871    }
1872} // end of wxDC::DoSelectPalette
1873
1874void wxDC::InitializePalette()
1875{
1876    if (wxDisplayDepth() <= 8 )
1877    {
1878        //
1879        // Look for any window or parent that has a custom palette. If any has
1880        // one then we need to use it in drawing operations
1881        //
1882        wxWindow*                   pWin = m_pCanvas->GetAncestorWithCustomPalette();
1883
1884        m_hasCustomPalette = pWin && pWin->HasCustomPalette();
1885        if (m_hasCustomPalette)
1886        {
1887            m_palette = pWin->GetPalette();
1888
1889            //
1890            // turn on PM translation for this palette
1891            //
1892            DoSelectPalette();
1893        }
1894    }
1895} // end of wxDC::InitializePalette
1896
1897void wxDC::SetPalette(
1898  const wxPalette&                  rPalette
1899)
1900{
1901    if (m_hOldFont)
1902    {
1903        m_hOldFont = 0;
1904    }
1905    m_palette = rPalette;
1906    if (!rPalette.Ok())
1907    {
1908        if (m_hOldFont)
1909        {
1910            m_hOldFont = 0;
1911        }
1912    }
1913    HPALETTE                    hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
1914    if (!m_hOldPalette)
1915        m_hOldPalette = (WXHPALETTE)hOldPal;
1916} // end of wxDC::SetPalette
1917
1918void wxDC::SetFont(
1919  const wxFont&                     rFont
1920)
1921{
1922    //
1923    // Set the old object temporarily, in case the assignment deletes an object
1924    // that's not yet selected out.
1925    //
1926    if (m_hOldFont)
1927    {
1928        m_hOldFont = 0;
1929    }
1930    m_font = rFont;
1931    if (!rFont.Ok())
1932    {
1933        m_hOldFont = 0;
1934    }
1935
1936    m_font.SetPS(m_hPS); // this will realize the font
1937
1938    if (m_font.Ok())
1939    {
1940        HFONT                       hFont = m_font.GetResourceHandle();
1941        if (hFont == (HFONT) NULL)
1942        {
1943            wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1944        }
1945        if (!m_hOldFont)
1946            m_hOldFont = (WXHFONT) hFont;
1947    }
1948} // end of wxDC::SetFont
1949
1950void wxDC::SetPen(
1951  const wxPen&                      rPen
1952)
1953{
1954    wxCHECK_RET( Ok(), wxT("invalid window dc") );
1955
1956    if (m_pen == rPen)
1957        return;
1958    m_pen = rPen;
1959    if (!m_pen.Ok())
1960        return;
1961
1962    if (m_hOldPen)
1963        m_hOldPen = 0L;
1964    m_pen = rPen;
1965
1966    if (!m_pen.Ok())
1967    {
1968        if (m_hOldPen)
1969        {
1970            m_pen.SetPS((HPS)m_hOldPen);
1971        }
1972        m_hOldPen = 0L;
1973    }
1974
1975    if (m_pen.Ok())
1976    {
1977        if (m_pen.GetResourceHandle())
1978        {
1979            m_pen.SetPS(m_hPS);
1980            if (!m_hOldPen)
1981                m_hOldPen = m_pen.GetPS();
1982        }
1983        ::GpiSetColor(m_hPS, m_pen.GetColour().GetPixel());
1984    }
1985}
1986
1987void wxDC::SetBrush(
1988  const wxBrush&                    rBrush
1989)
1990{
1991    wxCHECK_RET( Ok(), wxT("invalid window dc") );
1992
1993    if (m_hOldBrush)
1994        m_hOldBrush = 0L;
1995    m_brush = rBrush;
1996    if (!m_brush.Ok())
1997    if (m_brush == rBrush)
1998        return;
1999    if (!m_brush.Ok())
2000        if (m_hOldBrush)
2001            m_hOldBrush = 0L;
2002
2003    if (!m_brush.Ok())
2004    {
2005        if (m_hOldBrush)
2006        {
2007            m_brush.SetPS((HPS)m_hOldBrush);
2008        }
2009        m_hOldBrush = 0L;
2010    }
2011
2012    if (m_brush.Ok())
2013    {
2014        if (m_brush.GetResourceHandle())
2015        {
2016            m_brush.SetPS(m_hPS);
2017            if (!m_hOldBrush)
2018                m_hOldBrush = (WXHWND)m_brush.GetPS();
2019        }
2020    }
2021} // end of wxDC::SetBrush
2022
2023void wxDC::SetBackground(const wxBrush& rBrush)
2024{
2025    m_backgroundBrush = rBrush;
2026
2027    if (m_backgroundBrush.Ok())
2028    {
2029        (void)::GpiSetBackColor((HPS)m_hPS, m_backgroundBrush.GetColour().GetPixel());
2030    }
2031} // end of wxDC::SetBackground
2032
2033void wxDC::SetBackgroundMode(int nMode)
2034{
2035    m_backgroundMode = nMode;
2036} // end of wxDC::SetBackgroundMode
2037
2038void wxDC::SetLogicalFunction(int nFunction)
2039{
2040    m_logicalFunction = nFunction;
2041    SetRop((WXHDC)m_hDC);
2042} // wxDC::SetLogicalFunction
2043
2044void wxDC::SetRop(WXHDC hDC)
2045{
2046    if (!hDC || m_logicalFunction < 0)
2047        return;
2048
2049    LONG lCRop;
2050    switch (m_logicalFunction)
2051    {
2052        case wxXOR:
2053            lCRop = FM_XOR;
2054            break;
2055
2056        case wxINVERT:
2057            lCRop = FM_INVERT;
2058            break;
2059
2060        case wxOR_REVERSE:
2061            lCRop = FM_MERGESRCNOT;
2062            break;
2063
2064        case wxAND_REVERSE:
2065            lCRop = FM_NOTMASKSRC;
2066            break;
2067
2068        case wxCLEAR:
2069            lCRop = FM_ONE;
2070            break;
2071
2072        case wxSET:
2073            lCRop = FM_ZERO;
2074            break;
2075
2076        case wxSRC_INVERT:
2077            lCRop = FM_MERGENOTSRC;
2078            break;
2079
2080        case wxOR_INVERT:
2081            lCRop = FM_MERGESRCNOT;
2082            break;
2083
2084        case wxAND:
2085            lCRop = FM_AND;
2086            break;
2087
2088        case wxOR:
2089            lCRop = FM_OR;
2090            break;
2091
2092        case wxAND_INVERT:
2093            lCRop = FM_SUBTRACT;
2094            break;
2095
2096        case wxEQUIV:
2097        case wxNAND:
2098        case wxCOPY:
2099        default:
2100            lCRop = FM_OVERPAINT;
2101            break;
2102    }
2103    ::GpiSetMix((HPS)hDC, lCRop);
2104} // end of wxDC::SetRop
2105
2106bool wxDC::StartDoc( const wxString& WXUNUSED(rsMessage) )
2107{
2108    // We might be previewing, so return true to let it continue.
2109    return true;
2110} // end of wxDC::StartDoc
2111
2112void wxDC::EndDoc()
2113{
2114} // end of wxDC::EndDoc
2115
2116void wxDC::StartPage()
2117{
2118} // end of wxDC::StartPage
2119
2120void wxDC::EndPage()
2121{
2122} // end of wxDC::EndPage
2123
2124// ---------------------------------------------------------------------------
2125// text metrics
2126// ---------------------------------------------------------------------------
2127
2128wxCoord wxDC::GetCharHeight() const
2129{
2130    FONTMETRICS                     vFM; // metrics structure
2131
2132    ::GpiQueryFontMetrics( m_hPS
2133                          ,sizeof(FONTMETRICS)
2134                          ,&vFM
2135                         );
2136    return YDEV2LOGREL(vFM.lXHeight);
2137}
2138
2139wxCoord wxDC::GetCharWidth() const
2140{
2141    FONTMETRICS                     vFM; // metrics structure
2142
2143    ::GpiQueryFontMetrics( m_hPS
2144                          ,sizeof(FONTMETRICS)
2145                          ,&vFM
2146                         );
2147    return XDEV2LOGREL(vFM.lAveCharWidth);
2148}
2149
2150void wxDC::DoGetTextExtent(
2151  const wxString&                   rsString
2152, wxCoord*                          pvX
2153, wxCoord*                          pvY
2154, wxCoord*                          pvDescent
2155, wxCoord*                          pvExternalLeading
2156, wxFont*                           pTheFont
2157) const
2158{
2159    POINTL                          avPoint[TXTBOX_COUNT];
2160    POINTL                          vPtMin;
2161    POINTL                          vPtMax;
2162    int                             i;
2163    int                             l;
2164    FONTMETRICS                     vFM; // metrics structure
2165    BOOL                            bRc;
2166    ERRORID                         vErrorCode; // last error id code
2167    wxFont*                         pFontToUse = (wxFont*)pTheFont;
2168
2169    wxChar                          zMsg[128]; // DEBUG
2170    wxString                        sError;
2171
2172    if (!pFontToUse)
2173        pFontToUse = (wxFont*)&m_font;
2174    l = rsString.length();
2175
2176    //
2177    // In world coordinates.
2178    //
2179    bRc = ::GpiQueryTextBox( m_hPS
2180                            ,l
2181                            ,(PCH)rsString.c_str()
2182                            ,TXTBOX_COUNT // return maximum information
2183                            ,avPoint      // array of coordinates points
2184                           );
2185    if(!bRc)
2186    {
2187       vErrorCode = ::WinGetLastError(wxGetInstance());
2188       sError = wxPMErrorToStr(vErrorCode);
2189       // DEBUG
2190       wxSprintf(zMsg, _T("GpiQueryTextBox for %s: failed with Error: %lx - %s"), rsString.c_str(), vErrorCode, sError.c_str());
2191       (void)wxMessageBox( _T("wxWidgets Menu sample")
2192                          ,zMsg
2193                          ,wxICON_INFORMATION
2194                         );
2195    }
2196
2197    vPtMin.x = avPoint[0].x;
2198    vPtMax.x = avPoint[0].x;
2199    vPtMin.y = avPoint[0].y;
2200    vPtMax.y = avPoint[0].y;
2201    for (i = 1; i < 4; i++)
2202    {
2203        if(vPtMin.x > avPoint[i].x) vPtMin.x = avPoint[i].x;
2204        if(vPtMin.y > avPoint[i].y) vPtMin.y = avPoint[i].y;
2205        if(vPtMax.x < avPoint[i].x) vPtMax.x = avPoint[i].x;
2206        if(vPtMax.y < avPoint[i].y) vPtMax.y = avPoint[i].y;
2207    }
2208    ::GpiQueryFontMetrics( m_hPS
2209                          ,sizeof(FONTMETRICS)
2210                          ,&vFM
2211                         );
2212
2213    if (pvX)
2214        *pvX = (wxCoord)(vPtMax.x - vPtMin.x + 1);
2215    if (pvY)
2216        *pvY = (wxCoord)(vPtMax.y - vPtMin.y + 1);
2217    if (pvDescent)
2218        *pvDescent = vFM.lMaxDescender;
2219    if (pvExternalLeading)
2220        *pvExternalLeading = vFM.lExternalLeading;
2221}
2222
2223void wxDC::SetMapMode(
2224  int                               nMode
2225)
2226{
2227    int                             nPixelWidth = 0;
2228    int                             nPixelHeight = 0;
2229    int                             nMmWidth = 1;
2230    int                             nMmHeight = 1;
2231    LONG                            lArray[CAPS_VERTICAL_RESOLUTION+1];
2232
2233    m_mappingMode = nMode;
2234
2235    if(::DevQueryCaps( m_hDC
2236                      ,CAPS_FAMILY                  // id of first item
2237                      ,CAPS_VERTICAL_RESOLUTION+1   // number of items wanted
2238                      ,lArray
2239                     ))
2240    {
2241        LONG                        lHorzRes;
2242        LONG                        lVertRes;
2243
2244        nPixelWidth    = lArray[CAPS_WIDTH];
2245        nPixelHeight   = lArray[CAPS_HEIGHT];
2246        lHorzRes  = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
2247        lVertRes  = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
2248        nMmWidth  = (lHorzRes/1000) * nPixelWidth;
2249        nMmHeight = (lVertRes/1000) * nPixelHeight;
2250    }
2251    if ((nPixelWidth == 0) || (nPixelHeight == 0) || (nMmWidth == 0) || (nMmHeight == 0))
2252    {
2253        return;
2254    }
2255
2256    double dMm2pixelsX = nPixelWidth/(double)nMmWidth;
2257    double dMm2pixelsY = nPixelHeight/(double)nMmHeight;
2258
2259    switch (nMode)
2260    {
2261        case wxMM_TWIPS:
2262            m_logicalScaleX = (twips2mm * dMm2pixelsX);
2263            m_logicalScaleY = (twips2mm * dMm2pixelsY);
2264            break;
2265
2266        case wxMM_POINTS:
2267            m_logicalScaleX = (pt2mm * dMm2pixelsX);
2268            m_logicalScaleY = (pt2mm * dMm2pixelsY);
2269            break;
2270
2271        case wxMM_METRIC:
2272            m_logicalScaleX = dMm2pixelsX;
2273            m_logicalScaleY = dMm2pixelsY;
2274            break;
2275
2276        case wxMM_LOMETRIC:
2277            m_logicalScaleX = (dMm2pixelsX/10.0);
2278            m_logicalScaleY = (dMm2pixelsY/10.0);
2279            break;
2280
2281        case wxMM_TEXT:
2282        default:
2283            m_logicalScaleX = 1.0;
2284            m_logicalScaleY = 1.0;
2285            break;
2286    }
2287
2288    SIZEL                           vSize;
2289    ULONG                           ulOptions;
2290
2291    ulOptions = ::GpiQueryPS(m_hPS, &vSize);
2292    if (!ulOptions & PU_ARBITRARY)
2293    {
2294        ulOptions = PU_ARBITRARY | GPIF_DEFAULT;
2295        ::GpiSetPS(m_hPS, &vSize, ulOptions);
2296    }
2297}; // end of wxDC::SetMapMode
2298
2299void wxDC::SetUserScale( double dX,
2300                         double dY )
2301{
2302    m_userScaleX = dX;
2303    m_userScaleY = dY;
2304
2305    SetMapMode(m_mappingMode);
2306} // end of wxDC::SetUserScale
2307
2308void wxDC::SetAxisOrientation( bool bXLeftRight,
2309                               bool bYBottomUp )
2310{
2311    m_signX = bXLeftRight ? 1 : -1;
2312    m_signY = bYBottomUp ? -1 : 1;
2313
2314    SetMapMode(m_mappingMode);
2315} // end of wxDC::SetAxisOrientation
2316
2317void wxDC::SetSystemScale(
2318  double                            dX
2319, double                            dY
2320)
2321{
2322    m_scaleX = dX;
2323    m_scaleY = dY;
2324
2325    SetMapMode(m_mappingMode);
2326} // end of wxDC::SetSystemScale
2327
2328void wxDC::SetLogicalOrigin(
2329  wxCoord                           vX
2330, wxCoord                           vY
2331)
2332{
2333    RECTL                           vRect;
2334
2335    ::GpiQueryPageViewport( m_hPS
2336                           ,&vRect
2337                          );
2338    vRect.xRight -= vX;
2339    vRect.yTop += vY;
2340    vRect.xLeft = vX;
2341    vRect.yBottom = vY;
2342    ::GpiSetPageViewport( m_hPS
2343                         ,&vRect
2344                        );
2345}; // end of wxDC::SetLogicalOrigin
2346
2347void wxDC::SetDeviceOrigin(
2348  wxCoord                           vX
2349, wxCoord                           vY
2350)
2351{
2352    RECTL                           vRect;
2353
2354    m_deviceOriginX = vX;
2355    m_deviceOriginY = vY;
2356    ::GpiQueryPageViewport( m_hPS
2357                           ,&vRect
2358                          );
2359    vRect.xLeft += vX;
2360    vRect.xRight += vX;
2361    vRect.yBottom -= vY;
2362    vRect.yTop -= vY;
2363    ::GpiSetPageViewport( m_hPS
2364                         ,&vRect
2365                        );
2366}; // end of wxDC::SetDeviceOrigin
2367
2368// ---------------------------------------------------------------------------
2369// coordinates transformations
2370// ---------------------------------------------------------------------------
2371
2372wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2373{
2374    return (wxCoord) (((x) - m_deviceOriginX)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX) - m_logicalOriginX);
2375}
2376
2377wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2378{
2379    // axis orientation is not taken into account for conversion of a distance
2380    return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_scaleX));
2381}
2382
2383wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2384{
2385    return (wxCoord) (((y) - m_deviceOriginY)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY) - m_logicalOriginY);
2386}
2387
2388wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2389{
2390    // axis orientation is not taken into account for conversion of a distance
2391    return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_scaleY));
2392}
2393
2394wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2395{
2396    return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
2397}
2398
2399wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2400{
2401    // axis orientation is not taken into account for conversion of a distance
2402    return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX);
2403}
2404
2405wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2406{
2407    return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
2408}
2409
2410wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2411{
2412    // axis orientation is not taken into account for conversion of a distance
2413    return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY);
2414}
2415
2416// ---------------------------------------------------------------------------
2417// bit blit
2418// ---------------------------------------------------------------------------
2419
2420bool wxDC::DoBlit( wxCoord vXdest,
2421                   wxCoord vYdest,
2422                   wxCoord vWidth,
2423                   wxCoord vHeight,
2424                   wxDC*   pSource,
2425                   wxCoord vXsrc,
2426                   wxCoord vYsrc,
2427                   int     nRop,
2428                   bool    bUseMask,
2429                   wxCoord WXUNUSED(vXsrcMask),
2430                   wxCoord WXUNUSED(vYsrcMask) )
2431{
2432    wxMask*                         pMask = NULL;
2433    CHARBUNDLE                      vCbnd;
2434    COLORREF                        vOldTextColor;
2435    COLORREF                        vOldBackground = ::GpiQueryBackColor(m_hPS);
2436
2437    if (bUseMask)
2438    {
2439        const wxBitmap&             rBmp = pSource->m_vSelectedBitmap;
2440
2441        pMask = rBmp.GetMask();
2442        if (!(rBmp.Ok() && pMask && pMask->GetMaskBitmap()))
2443        {
2444            bUseMask = false;
2445        }
2446    }
2447
2448    ::GpiQueryAttrs( m_hPS
2449                    ,PRIM_CHAR
2450                    ,CBB_COLOR
2451                    ,&vCbnd
2452                   );
2453    vOldTextColor = (COLORREF)vCbnd.lColor;
2454
2455    if (m_textForegroundColour.Ok())
2456    {
2457        vCbnd.lColor = (LONG)m_textForegroundColour.GetPixel();
2458        ::GpiSetAttrs( m_hPS           // presentation-space handle
2459                      ,PRIM_CHAR       // Char primitive.
2460                      ,CBB_COLOR       // sets color.
2461                      ,0
2462                      ,&vCbnd          // buffer for attributes.
2463                     );
2464    }
2465    if (m_textBackgroundColour.Ok())
2466    {
2467        ::GpiSetBackColor(m_hPS, (LONG)m_textBackgroundColour.GetPixel());
2468    }
2469
2470    LONG                            lRop = ROP_SRCCOPY;
2471
2472    switch (nRop)
2473    {
2474        case wxXOR:          lRop = ROP_SRCINVERT;        break;
2475        case wxINVERT:       lRop = ROP_DSTINVERT;        break;
2476        case wxOR_REVERSE:   lRop = 0x00DD0228;           break;
2477        case wxAND_REVERSE:  lRop = ROP_SRCERASE;         break;
2478        case wxCLEAR:        lRop = ROP_ZERO;             break;
2479        case wxSET:          lRop = ROP_ONE;              break;
2480        case wxOR_INVERT:    lRop = ROP_MERGEPAINT;       break;
2481        case wxAND:          lRop = ROP_SRCAND;           break;
2482        case wxOR:           lRop = ROP_SRCPAINT;         break;
2483        case wxEQUIV:        lRop = 0x00990066;           break;
2484        case wxNAND:         lRop = 0x007700E6;           break;
2485        case wxAND_INVERT:   lRop = 0x00220326;           break;
2486        case wxCOPY:         lRop = ROP_SRCCOPY;          break;
2487        case wxNO_OP:        lRop = ROP_NOTSRCERASE;      break;
2488        case wxSRC_INVERT:   lRop = ROP_SRCINVERT;        break;
2489        case wxNOR:          lRop = ROP_NOTSRCCOPY;       break;
2490        default:
2491           wxFAIL_MSG( wxT("unsupported logical function") );
2492           return false;
2493    }
2494
2495    bool                            bSuccess;
2496
2497    if (bUseMask)
2498    {
2499        //
2500        // Blit bitmap with mask
2501        //
2502
2503        //
2504        // Create a temp buffer bitmap and DCs/PSs to access it and the mask
2505        //
2506        HDC                             hDCMask;
2507        HDC                             hDCBuffer;
2508        HPS                             hPSMask;
2509        HPS                             hPSBuffer;
2510        DEVOPENSTRUC                    vDOP = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
2511        BITMAPINFOHEADER2               vBmpHdr;
2512        HBITMAP                         hBufBitmap;
2513        SIZEL                           vSize = {0, 0};
2514        LONG                            rc;
2515
2516        memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
2517        vBmpHdr.cbFix     = sizeof(BITMAPINFOHEADER2);
2518        vBmpHdr.cx        = vWidth;
2519        vBmpHdr.cy        = vHeight;
2520        vBmpHdr.cPlanes   = 1;
2521        vBmpHdr.cBitCount = 24;
2522
2523#if wxUSE_DC_CACHEING
2524        {
2525            //
2526            // create a temp buffer bitmap and DCs to access it and the mask
2527            //
2528            wxDCCacheEntry*         pDCCacheEntry1    = FindDCInCache( NULL
2529                                                                      ,pSource->GetHPS()
2530                                                                     );
2531            wxDCCacheEntry*         pDCCacheEntry2    = FindDCInCache( pDCCacheEntry1
2532                                                                      ,GetHPS()
2533                                                                     );
2534            wxDCCacheEntry*         pBitmapCacheEntry = FindBitmapInCache( GetHPS()
2535                                                                          ,vWidth
2536                                                                          ,vHeight
2537                                                                         );
2538
2539            hPSMask = pDCCacheEntry1->m_hPS;
2540            hDCBuffer = (HDC)pDCCacheEntry2->m_hPS;
2541            hBufBitmap = (HBITMAP)pBitmapCacheEntry->m_hBitmap;
2542            wxUnusedVar(hDCMask);
2543        }
2544#else
2545        {
2546            hDCMask = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
2547            hDCBuffer = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
2548            hPSMask = ::GpiCreatePS(vHabmain, hDCMask, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
2549            hPSBuffer = ::GpiCreatePS(vHabmain, hDCBuffer, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
2550            hBufBitmap = ::GpiCreateBitmap(GetHPS(), &vBmpHdr, 0L, NULL, NULL);
2551        }
2552#endif
2553
2554        POINTL                          aPoint1[4] = { {0, 0}
2555                              ,{vWidth, vHeight}
2556                              ,{vXdest, vYdest}
2557                              ,{vXdest + vWidth, vYdest + vHeight}
2558                                                     };
2559        POINTL                          aPoint2[4] = { {0, 0}
2560                              ,{vWidth, vHeight}
2561                              ,{vXsrc, vYsrc}
2562                              ,{vXsrc + vWidth, vYsrc + vHeight}
2563                                                     };
2564        POINTL                          aPoint3[4] = { {vXdest, vYdest}
2565                              ,{vXdest + vWidth, vYdest + vHeight}
2566                              ,{vXsrc, vYsrc}
2567                              ,{vXsrc + vWidth, vYsrc + vHeight}
2568                                                     };
2569        POINTL                          aPoint4[4] = { {vXdest, vYdest}
2570                              ,{vXdest + vWidth, vYdest + vHeight}
2571                              ,{0, 0}
2572                              ,{vWidth, vHeight}
2573                                                     };
2574        ::GpiSetBitmap(hPSMask, (HBITMAP) pMask->GetMaskBitmap());
2575        ::GpiSetBitmap(hPSBuffer, (HBITMAP) hBufBitmap);
2576
2577        //
2578        // Copy dest to buffer
2579        //
2580        rc = ::GpiBitBlt( hPSBuffer
2581                         ,GetHPS()
2582                         ,4L
2583                         ,aPoint1
2584                         ,ROP_SRCCOPY
2585                         ,BBO_IGNORE
2586                        );
2587        if (rc == GPI_ERROR)
2588        {
2589            wxLogLastError(wxT("BitBlt"));
2590        }
2591
2592        //
2593        // Copy src to buffer using selected raster op
2594        //
2595        rc = ::GpiBitBlt( hPSBuffer
2596                         ,GetHPS()
2597                         ,4L
2598                         ,aPoint2
2599                         ,lRop
2600                         ,BBO_IGNORE
2601                        );
2602        if (rc == GPI_ERROR)
2603        {
2604            wxLogLastError(wxT("BitBlt"));
2605        }
2606
2607        //
2608        // Set masked area in buffer to BLACK (pixel value 0)
2609        //
2610        COLORREF                        vPrevBkCol = ::GpiQueryBackColor(GetHPS());
2611        COLORREF                        vPrevCol = ::GpiQueryColor(GetHPS());
2612
2613        ::GpiSetBackColor(GetHPS(), OS2RGB(255, 255, 255));
2614        ::GpiSetColor(GetHPS(), OS2RGB(0, 0, 0));
2615
2616        rc = ::GpiBitBlt( hPSBuffer
2617                         ,hPSMask
2618                         ,4L
2619                         ,aPoint2
2620                         ,ROP_SRCAND
2621                         ,BBO_IGNORE
2622                        );
2623        if (rc == GPI_ERROR)
2624        {
2625            wxLogLastError(wxT("BitBlt"));
2626        }
2627
2628        //
2629        // Set unmasked area in dest to BLACK
2630        //
2631        ::GpiSetBackColor(GetHPS(), OS2RGB(0, 0, 0));
2632        ::GpiSetColor(GetHPS(), OS2RGB(255, 255, 255));
2633        rc = ::GpiBitBlt( GetHPS()
2634                         ,hPSMask
2635                         ,4L
2636                         ,aPoint3
2637                         ,ROP_SRCAND
2638                         ,BBO_IGNORE
2639                        );
2640        if (rc == GPI_ERROR)
2641        {
2642            wxLogLastError(wxT("BitBlt"));
2643        }
2644
2645        //
2646        // Restore colours to original values
2647        //
2648        ::GpiSetBackColor(GetHPS(), vPrevBkCol);
2649        ::GpiSetColor(GetHPS(), vPrevCol);
2650
2651        //
2652        // OR buffer to dest
2653        //
2654        rc = ::GpiBitBlt( GetHPS()
2655                         ,hPSMask
2656                         ,4L
2657                         ,aPoint4
2658                         ,ROP_SRCPAINT
2659                         ,BBO_IGNORE
2660                        );
2661        if (rc == GPI_ERROR)
2662        {
2663            bSuccess = false;
2664            wxLogLastError(wxT("BitBlt"));
2665        }
2666
2667        //
2668        // Tidy up temporary DCs and bitmap
2669        //
2670        ::GpiSetBitmap(hPSMask, NULLHANDLE);
2671        ::GpiSetBitmap(hPSBuffer, NULLHANDLE);
2672#if !wxUSE_DC_CACHEING
2673        ::GpiDestroyPS(hPSMask);
2674        ::GpiDestroyPS(hPSBuffer);
2675        ::DevCloseDC(hDCMask);
2676        ::DevCloseDC(hDCBuffer);
2677        ::GpiDeleteBitmap(hBufBitmap);
2678#endif
2679        bSuccess = true;
2680    }
2681    else // no mask, just BitBlt() it
2682    {
2683      POINTL                          aPoint[4] = { {vXdest, vYdest}
2684                           ,{vXdest + vWidth, vYdest + vHeight}
2685                           ,{vXsrc, vYsrc}
2686                           ,{vXsrc + vWidth, vYsrc + vHeight}
2687                                                    };
2688
2689        bSuccess = (::GpiBitBlt( m_hPS
2690                                ,pSource->GetHPS()
2691                                ,4L
2692                                ,aPoint
2693                                ,lRop
2694                                ,BBO_IGNORE
2695                               ) != GPI_ERROR);
2696        if (!bSuccess )
2697        {
2698            wxLogLastError(wxT("BitBlt"));
2699        }
2700    }
2701    vCbnd.lColor = (LONG)vOldTextColor;
2702    ::GpiSetAttrs( m_hPS           // presentation-space handle
2703                  ,PRIM_CHAR       // Char primitive.
2704                  ,CBB_COLOR       // sets color.
2705                  ,0
2706                  ,&vCbnd          // buffer for attributes.
2707                 );
2708    ::GpiSetBackColor(m_hPS, (LONG)vOldBackground);
2709    return bSuccess;
2710}
2711
2712void wxDC::DoGetSize( int* pnWidth,
2713                      int* pnHeight ) const
2714{
2715    LONG lArray[CAPS_HEIGHT+1];
2716
2717    if(::DevQueryCaps( m_hDC
2718                      ,CAPS_FAMILY
2719                      ,CAPS_HEIGHT+1
2720                      ,lArray
2721                     ))
2722    {
2723        if (pnWidth)
2724            *pnWidth  = lArray[CAPS_WIDTH];
2725        if (pnHeight)
2726            *pnHeight = lArray[CAPS_HEIGHT];
2727    }
2728}; // end of wxDC::DoGetSize(
2729
2730void wxDC::DoGetSizeMM( int* pnWidth,
2731                        int* pnHeight ) const
2732{
2733    LONG                            lArray[CAPS_VERTICAL_RESOLUTION+1];
2734
2735    if(::DevQueryCaps( m_hDC
2736                      ,CAPS_FAMILY
2737                      ,CAPS_VERTICAL_RESOLUTION+1
2738                      ,lArray
2739                     ))
2740    {
2741        if(pnWidth)
2742        {
2743            int nWidth   = lArray[CAPS_WIDTH];
2744            int nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
2745            // use fp to avoid returning 0 if nHorzRes < 1000
2746            *pnWidth  = (int)((nHorzRes/1000.0) * nWidth);
2747        }
2748
2749        if(pnHeight)
2750        {
2751            int nHeight  = lArray[CAPS_HEIGHT];
2752            int nVertRes = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
2753            // use fp to avoid returning 0 if nVertRes < 1000
2754            *pnHeight = (int)((nVertRes/1000.0) * nHeight);
2755        }
2756    }
2757}; // end of wxDC::DoGetSizeMM
2758
2759wxSize wxDC::GetPPI() const
2760{
2761    LONG                            lArray[CAPS_VERTICAL_RESOLUTION+1];
2762    int                             nWidth = 0;
2763    int                             nHeight = 0;
2764
2765    if(::DevQueryCaps( m_hDC
2766                      ,CAPS_FAMILY
2767                      ,CAPS_VERTICAL_RESOLUTION+1
2768                      ,lArray
2769                     ))
2770    {
2771        int                         nPelWidth;
2772        int                         nPelHeight;
2773        int                         nHorzRes;
2774        int                         nVertRes;
2775
2776        nPelWidth  = lArray[CAPS_WIDTH];
2777        nPelHeight = lArray[CAPS_HEIGHT];
2778        nHorzRes   = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
2779        nVertRes   = lArray[CAPS_VERTICAL_RESOLUTION];   // returns pel/meter
2780        nWidth   = (int)((nHorzRes/39.3) * nPelWidth);
2781        nHeight  = (int)((nVertRes/39.3) * nPelHeight);
2782    }
2783    wxSize ppisize(nWidth, nHeight);
2784    return ppisize;
2785} // end of wxDC::GetPPI
2786
2787void wxDC::SetLogicalScale( double dX, double dY )
2788{
2789    m_logicalScaleX = dX;
2790    m_logicalScaleY = dY;
2791}; // end of wxDC::SetLogicalScale
2792