/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/dc.cpp
ViewVC logotype

Annotation of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/dc.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (10 years ago) by william
File size: 80284 byte(s)
branching from upstream revision (http://pcsx2.googlecode.com/svn/trunk
): r3113 to
https://svn.netsolutions.dnsalias.com/websvn/ps2/pcsx2/pcsx2_0.9.7/branch/r3113_0.9.7_beta
1 william 31 /////////////////////////////////////////////////////////////////////////////
2     // Name: src/msw/dc.cpp
3     // Purpose: wxDC class for MSW port
4     // Author: Julian Smart
5     // Modified by:
6     // Created: 01/02/97
7     // RCS-ID: $Id: dc.cpp 49338 2007-10-22 18:07:45Z RD $
8     // Copyright: (c) Julian Smart
9     // Licence: wxWindows licence
10     /////////////////////////////////////////////////////////////////////////////
11    
12     // ===========================================================================
13     // declarations
14     // ===========================================================================
15    
16     // ---------------------------------------------------------------------------
17     // headers
18     // ---------------------------------------------------------------------------
19    
20     // For compilers that support precompilation, includes "wx.h".
21     #include "wx/wxprec.h"
22    
23     #ifdef __BORLANDC__
24     #pragma hdrstop
25     #endif
26    
27     #ifndef WX_PRECOMP
28     #include "wx/msw/wrapcdlg.h"
29     #include "wx/image.h"
30     #include "wx/window.h"
31     #include "wx/dc.h"
32     #include "wx/utils.h"
33     #include "wx/dialog.h"
34     #include "wx/app.h"
35     #include "wx/bitmap.h"
36     #include "wx/dcmemory.h"
37     #include "wx/log.h"
38     #include "wx/icon.h"
39     #include "wx/dcprint.h"
40     #include "wx/module.h"
41     #endif
42    
43     #include "wx/sysopt.h"
44     #include "wx/dynlib.h"
45    
46     #ifdef wxHAVE_RAW_BITMAP
47     #include "wx/rawbmp.h"
48     #endif
49    
50     #include <string.h>
51    
52     #ifndef __WIN32__
53     #include <print.h>
54     #endif
55    
56     #ifndef AC_SRC_ALPHA
57     #define AC_SRC_ALPHA 1
58     #endif
59    
60     #ifndef LAYOUT_RTL
61     #define LAYOUT_RTL 1
62     #endif
63    
64     /* Quaternary raster codes */
65     #ifndef MAKEROP4
66     #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
67     #endif
68    
69     // apparently with MicroWindows it is possible that HDC is 0 so we have to
70     // check for this ourselves
71     #ifdef __WXMICROWIN__
72     #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73     #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
74     #else
75     #define WXMICROWIN_CHECK_HDC
76     #define WXMICROWIN_CHECK_HDC_RET(x)
77     #endif
78    
79     IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
80    
81     // ---------------------------------------------------------------------------
82     // constants
83     // ---------------------------------------------------------------------------
84    
85     static const int VIEWPORT_EXTENT = 1000;
86    
87     static const int MM_POINTS = 9;
88     static const int MM_METRIC = 10;
89    
90     // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91     // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92     #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
93    
94     // ----------------------------------------------------------------------------
95     // macros for logical <-> device coords conversion
96     // ----------------------------------------------------------------------------
97    
98     /*
99     We currently let Windows do all the translations itself so these macros are
100     not really needed (any more) but keep them to enhance readability of the
101     code by allowing to see where are the logical and where are the device
102     coordinates used.
103     */
104    
105     #ifdef __WXWINCE__
106     #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
107     #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
108     #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
109     #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
110     #else
111     #define XLOG2DEV(x) (x)
112     #define YLOG2DEV(y) (y)
113     #define XDEV2LOG(x) (x)
114     #define YDEV2LOG(y) (y)
115     #endif
116    
117     // ---------------------------------------------------------------------------
118     // private functions
119     // ---------------------------------------------------------------------------
120    
121     // convert degrees to radians
122     static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
123    
124     // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
125     //
126     // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127     // to pass it to this function but as we already have it at the point
128     // of call anyhow we do
129     //
130     // return true if we could draw the bitmap in one way or the other, false
131     // otherwise
132     static bool AlphaBlt(HDC hdcDst,
133     int x, int y, int w, int h,
134     int srcX, int srcY, HDC hdcSrc,
135     const wxBitmap& bmpSrc);
136    
137     #ifdef wxHAVE_RAW_BITMAP
138    
139     // our (limited) AlphaBlend() replacement for Windows versions not providing it
140     static void
141     wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h,
142     int srcX, int srcY, const wxBitmap& bmp);
143    
144     #endif // wxHAVE_RAW_BITMAP
145    
146     // ----------------------------------------------------------------------------
147     // private classes
148     // ----------------------------------------------------------------------------
149    
150     // instead of duplicating the same code which sets and then restores text
151     // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
152     // encapsulate this in a small helper class
153    
154     // wxColourChanger: changes the text colours in the ctor if required and
155     // restores them in the dtor
156     class wxColourChanger
157     {
158     public:
159     wxColourChanger(wxDC& dc);
160     ~wxColourChanger();
161    
162     private:
163     wxDC& m_dc;
164    
165     COLORREF m_colFgOld, m_colBgOld;
166    
167     bool m_changed;
168    
169     DECLARE_NO_COPY_CLASS(wxColourChanger)
170     };
171    
172     // this class saves the old stretch blit mode during its life time
173     class StretchBltModeChanger
174     {
175     public:
176     StretchBltModeChanger(HDC hdc,
177     int WXUNUSED_IN_WINCE(mode))
178     : m_hdc(hdc)
179     {
180     #ifndef __WXWINCE__
181     m_modeOld = ::SetStretchBltMode(m_hdc, mode);
182     if ( !m_modeOld )
183     wxLogLastError(_T("SetStretchBltMode"));
184     #endif
185     }
186    
187     ~StretchBltModeChanger()
188     {
189     #ifndef __WXWINCE__
190     if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
191     wxLogLastError(_T("SetStretchBltMode"));
192     #endif
193     }
194    
195     private:
196     const HDC m_hdc;
197    
198     int m_modeOld;
199    
200     DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
201     };
202    
203     // helper class to cache dynamically loaded libraries and not attempt reloading
204     // them if it fails
205     class wxOnceOnlyDLLLoader
206     {
207     public:
208     // ctor argument must be a literal string as we don't make a copy of it!
209     wxOnceOnlyDLLLoader(const wxChar *dllName)
210     : m_dllName(dllName)
211     {
212     }
213    
214    
215     // return the symbol with the given name or NULL if the DLL not loaded
216     // or symbol not present
217     void *GetSymbol(const wxChar *name)
218     {
219     // we're prepared to handle errors here
220     wxLogNull noLog;
221    
222     if ( m_dllName )
223     {
224     m_dll.Load(m_dllName);
225    
226     // reset the name whether we succeeded or failed so that we don't
227     // try again the next time
228     m_dllName = NULL;
229     }
230    
231     return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL;
232     }
233    
234     private:
235     wxDynamicLibrary m_dll;
236     const wxChar *m_dllName;
237     };
238    
239     static wxOnceOnlyDLLLoader wxGDI32DLL(_T("gdi32"));
240     static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32"));
241    
242     // ===========================================================================
243     // implementation
244     // ===========================================================================
245    
246     // ----------------------------------------------------------------------------
247     // wxColourChanger
248     // ----------------------------------------------------------------------------
249    
250     wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
251     {
252     const wxBrush& brush = dc.GetBrush();
253     if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
254     {
255     HDC hdc = GetHdcOf(dc);
256     m_colFgOld = ::GetTextColor(hdc);
257     m_colBgOld = ::GetBkColor(hdc);
258    
259     // note that Windows convention is opposite to wxWidgets one, this is
260     // why text colour becomes the background one and vice versa
261     const wxColour& colFg = dc.GetTextForeground();
262     if ( colFg.Ok() )
263     {
264     ::SetBkColor(hdc, colFg.GetPixel());
265     }
266    
267     const wxColour& colBg = dc.GetTextBackground();
268     if ( colBg.Ok() )
269     {
270     ::SetTextColor(hdc, colBg.GetPixel());
271     }
272    
273     SetBkMode(hdc,
274     dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
275     : OPAQUE);
276    
277     // flag which telsl us to undo changes in the dtor
278     m_changed = true;
279     }
280     else
281     {
282     // nothing done, nothing to undo
283     m_changed = false;
284     }
285     }
286    
287     wxColourChanger::~wxColourChanger()
288     {
289     if ( m_changed )
290     {
291     // restore the colours we changed
292     HDC hdc = GetHdcOf(m_dc);
293    
294     ::SetBkMode(hdc, TRANSPARENT);
295     ::SetTextColor(hdc, m_colFgOld);
296     ::SetBkColor(hdc, m_colBgOld);
297     }
298     }
299    
300     // ---------------------------------------------------------------------------
301     // wxDC
302     // ---------------------------------------------------------------------------
303    
304     wxDC::~wxDC()
305     {
306     if ( m_hDC != 0 )
307     {
308     SelectOldObjects(m_hDC);
309    
310     // if we own the HDC, we delete it, otherwise we just release it
311    
312     if ( m_bOwnsDC )
313     {
314     ::DeleteDC(GetHdc());
315     }
316     else // we don't own our HDC
317     {
318     if (m_canvas)
319     {
320     ::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
321     }
322     else
323     {
324     // Must have been a wxScreenDC
325     ::ReleaseDC((HWND) NULL, GetHdc());
326     }
327     }
328     }
329     }
330    
331     // This will select current objects out of the DC,
332     // which is what you have to do before deleting the
333     // DC.
334     void wxDC::SelectOldObjects(WXHDC dc)
335     {
336     if (dc)
337     {
338     if (m_oldBitmap)
339     {
340     ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
341     #ifdef __WXDEBUG__
342     if (m_selectedBitmap.Ok())
343     {
344     m_selectedBitmap.SetSelectedInto(NULL);
345     }
346     #endif
347     }
348     m_oldBitmap = 0;
349     if (m_oldPen)
350     {
351     ::SelectObject((HDC) dc, (HPEN) m_oldPen);
352     }
353     m_oldPen = 0;
354     if (m_oldBrush)
355     {
356     ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
357     }
358     m_oldBrush = 0;
359     if (m_oldFont)
360     {
361     ::SelectObject((HDC) dc, (HFONT) m_oldFont);
362     }
363     m_oldFont = 0;
364    
365     #if wxUSE_PALETTE
366     if (m_oldPalette)
367     {
368     ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
369     }
370     m_oldPalette = 0;
371     #endif // wxUSE_PALETTE
372     }
373    
374     m_brush = wxNullBrush;
375     m_pen = wxNullPen;
376     #if wxUSE_PALETTE
377     m_palette = wxNullPalette;
378     #endif // wxUSE_PALETTE
379     m_font = wxNullFont;
380     m_backgroundBrush = wxNullBrush;
381     m_selectedBitmap = wxNullBitmap;
382     }
383    
384     // ---------------------------------------------------------------------------
385     // clipping
386     // ---------------------------------------------------------------------------
387    
388     void wxDC::UpdateClipBox()
389     {
390     WXMICROWIN_CHECK_HDC
391    
392     RECT rect;
393     ::GetClipBox(GetHdc(), &rect);
394    
395     m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
396     m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
397     m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
398     m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
399     }
400    
401     void
402     wxDC::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const
403     {
404     // check if we should try to retrieve the clipping region possibly not set
405     // by our SetClippingRegion() but preset by Windows:this can only happen
406     // when we're associated with an existing HDC usign SetHDC(), see there
407     if ( m_clipping && !m_clipX1 && !m_clipX2 )
408     {
409     wxDC *self = wxConstCast(this, wxDC);
410     self->UpdateClipBox();
411    
412     if ( !m_clipX1 && !m_clipX2 )
413     self->m_clipping = false;
414     }
415    
416     wxDCBase::DoGetClippingBox(x, y, w, h);
417     }
418    
419     // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
420     void wxDC::SetClippingHrgn(WXHRGN hrgn)
421     {
422     wxCHECK_RET( hrgn, wxT("invalid clipping region") );
423    
424     WXMICROWIN_CHECK_HDC
425    
426     // note that we combine the new clipping region with the existing one: this
427     // is compatible with what the other ports do and is the documented
428     // behaviour now (starting with 2.3.3)
429     #if defined(__WXWINCE__)
430     RECT rectClip;
431     if ( !::GetClipBox(GetHdc(), &rectClip) )
432     return;
433    
434     // GetClipBox returns logical coordinates, so transform to device
435     rectClip.left = LogicalToDeviceX(rectClip.left);
436     rectClip.top = LogicalToDeviceY(rectClip.top);
437     rectClip.right = LogicalToDeviceX(rectClip.right);
438     rectClip.bottom = LogicalToDeviceY(rectClip.bottom);
439    
440     HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
441     HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
442     rectClip.right, rectClip.bottom);
443    
444     if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
445     {
446     ::SelectClipRgn(GetHdc(), hrgnDest);
447     }
448    
449     ::DeleteObject(hrgnClipOld);
450     ::DeleteObject(hrgnDest);
451     #else // !WinCE
452     if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
453     {
454     wxLogLastError(_T("ExtSelectClipRgn"));
455    
456     return;
457     }
458     #endif // WinCE/!WinCE
459    
460     m_clipping = true;
461    
462     UpdateClipBox();
463     }
464    
465     void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
466     {
467     // the region coords are always the device ones, so do the translation
468     // manually
469     //
470     // FIXME: possible +/-1 error here, to check!
471     HRGN hrgn = ::CreateRectRgn(LogicalToDeviceX(x),
472     LogicalToDeviceY(y),
473     LogicalToDeviceX(x + w),
474     LogicalToDeviceY(y + h));
475     if ( !hrgn )
476     {
477     wxLogLastError(_T("CreateRectRgn"));
478     }
479     else
480     {
481     SetClippingHrgn((WXHRGN)hrgn);
482    
483     ::DeleteObject(hrgn);
484     }
485     }
486    
487     void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
488     {
489     SetClippingHrgn(region.GetHRGN());
490     }
491    
492     void wxDC::DestroyClippingRegion()
493     {
494     WXMICROWIN_CHECK_HDC
495    
496     if (m_clipping && m_hDC)
497     {
498     #if 1
499     // On a PocketPC device (not necessarily emulator), resetting
500     // the clip region as per the old method causes bad display
501     // problems. In fact setting a null region is probably OK
502     // on desktop WIN32 also, since the WIN32 docs imply that the user
503     // clipping region is independent from the paint clipping region.
504     ::SelectClipRgn(GetHdc(), 0);
505     #else
506     // TODO: this should restore the previous clipping region,
507     // so that OnPaint processing works correctly, and the update
508     // clipping region doesn't get destroyed after the first
509     // DestroyClippingRegion.
510     HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
511     ::SelectClipRgn(GetHdc(), rgn);
512     ::DeleteObject(rgn);
513     #endif
514     }
515    
516     wxDCBase::DestroyClippingRegion();
517     }
518    
519     // ---------------------------------------------------------------------------
520     // query capabilities
521     // ---------------------------------------------------------------------------
522    
523     bool wxDC::CanDrawBitmap() const
524     {
525     return true;
526     }
527    
528     bool wxDC::CanGetTextExtent() const
529     {
530     #ifdef __WXMICROWIN__
531     // TODO Extend MicroWindows' GetDeviceCaps function
532     return true;
533     #else
534     // What sort of display is it?
535     int technology = ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
536    
537     return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
538     #endif
539     }
540    
541     int wxDC::GetDepth() const
542     {
543     WXMICROWIN_CHECK_HDC_RET(16)
544    
545     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL);
546     }
547    
548     // ---------------------------------------------------------------------------
549     // drawing
550     // ---------------------------------------------------------------------------
551    
552     void wxDC::Clear()
553     {
554     WXMICROWIN_CHECK_HDC
555    
556     RECT rect;
557     if ( m_canvas )
558     {
559     GetClientRect((HWND) m_canvas->GetHWND(), &rect);
560     }
561     else
562     {
563     // No, I think we should simply ignore this if printing on e.g.
564     // a printer DC.
565     // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
566     if (!m_selectedBitmap.Ok())
567     return;
568    
569     rect.left = -m_deviceOriginX; rect.top = -m_deviceOriginY;
570     rect.right = m_selectedBitmap.GetWidth()-m_deviceOriginX;
571     rect.bottom = m_selectedBitmap.GetHeight()-m_deviceOriginY;
572     }
573    
574     #ifndef __WXWINCE__
575     (void) ::SetMapMode(GetHdc(), MM_TEXT);
576     #endif
577    
578     DWORD colour = ::GetBkColor(GetHdc());
579     HBRUSH brush = ::CreateSolidBrush(colour);
580     ::FillRect(GetHdc(), &rect, brush);
581     ::DeleteObject(brush);
582    
583     #ifndef __WXWINCE__
584     int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
585     height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
586    
587     ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
588    
589     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
590     ::SetWindowExtEx(GetHdc(), width, height, NULL);
591     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
592     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
593     #endif
594     }
595    
596     bool wxDC::DoFloodFill(wxCoord WXUNUSED_IN_WINCE(x),
597     wxCoord WXUNUSED_IN_WINCE(y),
598     const wxColour& WXUNUSED_IN_WINCE(col),
599     int WXUNUSED_IN_WINCE(style))
600     {
601     #ifdef __WXWINCE__
602     return false;
603     #else
604     WXMICROWIN_CHECK_HDC_RET(false)
605    
606     bool success = (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
607     col.GetPixel(),
608     style == wxFLOOD_SURFACE ? FLOODFILLSURFACE
609     : FLOODFILLBORDER) ) ;
610     if (!success)
611     {
612     // quoting from the MSDN docs:
613     //
614     // Following are some of the reasons this function might fail:
615     //
616     // * The filling could not be completed.
617     // * The specified point has the boundary color specified by the
618     // crColor parameter (if FLOODFILLBORDER was requested).
619     // * The specified point does not have the color specified by
620     // crColor (if FLOODFILLSURFACE was requested)
621     // * The point is outside the clipping region that is, it is not
622     // visible on the device.
623     //
624     wxLogLastError(wxT("ExtFloodFill"));
625     }
626    
627     CalcBoundingBox(x, y);
628    
629     return success;
630     #endif
631     }
632    
633     bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
634     {
635     WXMICROWIN_CHECK_HDC_RET(false)
636    
637     wxCHECK_MSG( col, false, _T("NULL colour parameter in wxDC::GetPixel") );
638    
639     // get the color of the pixel
640     COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
641    
642     wxRGBToColour(*col, pixelcolor);
643    
644     return true;
645     }
646    
647     void wxDC::DoCrossHair(wxCoord x, wxCoord y)
648     {
649     WXMICROWIN_CHECK_HDC
650    
651     wxCoord x1 = x-VIEWPORT_EXTENT;
652     wxCoord y1 = y-VIEWPORT_EXTENT;
653     wxCoord x2 = x+VIEWPORT_EXTENT;
654     wxCoord y2 = y+VIEWPORT_EXTENT;
655    
656     wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y));
657     wxDrawLine(GetHdc(), XLOG2DEV(x), YLOG2DEV(y1), XLOG2DEV(x), YLOG2DEV(y2));
658    
659     CalcBoundingBox(x1, y1);
660     CalcBoundingBox(x2, y2);
661     }
662    
663     void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
664     {
665     WXMICROWIN_CHECK_HDC
666    
667     wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
668    
669     CalcBoundingBox(x1, y1);
670     CalcBoundingBox(x2, y2);
671     }
672    
673     // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
674     // and ending at (x2, y2)
675     void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
676     wxCoord x2, wxCoord y2,
677     wxCoord xc, wxCoord yc)
678     {
679     #ifdef __WXWINCE__
680     // Slower emulation since WinCE doesn't support Pie and Arc
681     double r = sqrt( (x1-xc)*(x1-xc) + (y1-yc)*(y1-yc) );
682     double sa = acos((x1-xc)/r)/M_PI*180; // between 0 and 180
683     if( y1>yc ) sa = -sa; // below center
684     double ea = atan2(yc-y2, x2-xc)/M_PI*180;
685     DoDrawEllipticArcRot( xc-r, yc-r, 2*r, 2*r, sa, ea );
686     #else
687    
688     WXMICROWIN_CHECK_HDC
689    
690     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
691    
692     double dx = xc - x1;
693     double dy = yc - y1;
694     double radius = (double)sqrt(dx*dx+dy*dy);
695     wxCoord r = (wxCoord)radius;
696    
697     // treat the special case of full circle separately
698     if ( x1 == x2 && y1 == y2 )
699     {
700     DrawEllipse(xc - r, yc - r, 2*r, 2*r);
701     return;
702     }
703    
704     wxCoord xx1 = XLOG2DEV(x1);
705     wxCoord yy1 = YLOG2DEV(y1);
706     wxCoord xx2 = XLOG2DEV(x2);
707     wxCoord yy2 = YLOG2DEV(y2);
708     wxCoord xxc = XLOG2DEV(xc);
709     wxCoord yyc = YLOG2DEV(yc);
710     wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
711    
712     wxCoord xxx1 = (wxCoord) (xxc-ray);
713     wxCoord yyy1 = (wxCoord) (yyc-ray);
714     wxCoord xxx2 = (wxCoord) (xxc+ray);
715     wxCoord yyy2 = (wxCoord) (yyc+ray);
716    
717     if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT )
718     {
719     // Have to add 1 to bottom-right corner of rectangle
720     // to make semi-circles look right (crooked line otherwise).
721     // Unfortunately this is not a reliable method, depends
722     // on the size of shape.
723     // TODO: figure out why this happens!
724     Pie(GetHdc(),xxx1,yyy1,xxx2+1,yyy2+1, xx1,yy1,xx2,yy2);
725     }
726     else
727     {
728     Arc(GetHdc(),xxx1,yyy1,xxx2,yyy2, xx1,yy1,xx2,yy2);
729     }
730    
731     CalcBoundingBox(xc - r, yc - r);
732     CalcBoundingBox(xc + r, yc + r);
733     #endif
734     }
735    
736     void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
737     wxCoord width, wxCoord height)
738     {
739     // cases when we don't have DrawFrameControl()
740     #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
741     return wxDCBase::DoDrawCheckMark(x1, y1, width, height);
742     #else // normal case
743     wxCoord x2 = x1 + width,
744     y2 = y1 + height;
745    
746     RECT rect;
747     rect.left = x1;
748     rect.top = y1;
749     rect.right = x2;
750     rect.bottom = y2;
751    
752     #ifdef __WXWINCE__
753     DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK);
754     #else
755     DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
756     #endif
757    
758     CalcBoundingBox(x1, y1);
759     CalcBoundingBox(x2, y2);
760     #endif // Microwin/Normal
761     }
762    
763     void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
764     {
765     WXMICROWIN_CHECK_HDC
766    
767     COLORREF color = 0x00ffffff;
768     if (m_pen.Ok())
769     {
770     color = m_pen.GetColour().GetPixel();
771     }
772    
773     SetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), color);
774    
775     CalcBoundingBox(x, y);
776     }
777    
778     void wxDC::DoDrawPolygon(int n,
779     wxPoint points[],
780     wxCoord xoffset,
781     wxCoord yoffset,
782     int WXUNUSED_IN_WINCE(fillStyle))
783     {
784     WXMICROWIN_CHECK_HDC
785    
786     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
787    
788     // Do things less efficiently if we have offsets
789     if (xoffset != 0 || yoffset != 0)
790     {
791     POINT *cpoints = new POINT[n];
792     int i;
793     for (i = 0; i < n; i++)
794     {
795     cpoints[i].x = (int)(points[i].x + xoffset);
796     cpoints[i].y = (int)(points[i].y + yoffset);
797    
798     CalcBoundingBox(cpoints[i].x, cpoints[i].y);
799     }
800     #ifndef __WXWINCE__
801     int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
802     #endif
803     (void)Polygon(GetHdc(), cpoints, n);
804     #ifndef __WXWINCE__
805     SetPolyFillMode(GetHdc(),prev);
806     #endif
807     delete[] cpoints;
808     }
809     else
810     {
811     int i;
812     for (i = 0; i < n; i++)
813     CalcBoundingBox(points[i].x, points[i].y);
814    
815     #ifndef __WXWINCE__
816     int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
817     #endif
818     (void)Polygon(GetHdc(), (POINT*) points, n);
819     #ifndef __WXWINCE__
820     SetPolyFillMode(GetHdc(),prev);
821     #endif
822     }
823     }
824    
825     void
826     wxDC::DoDrawPolyPolygon(int n,
827     int count[],
828     wxPoint points[],
829     wxCoord xoffset,
830     wxCoord yoffset,
831     int fillStyle)
832     {
833     #ifdef __WXWINCE__
834     wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle);
835     #else
836     WXMICROWIN_CHECK_HDC
837    
838     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
839     int i, cnt;
840     for (i = cnt = 0; i < n; i++)
841     cnt += count[i];
842    
843     // Do things less efficiently if we have offsets
844     if (xoffset != 0 || yoffset != 0)
845     {
846     POINT *cpoints = new POINT[cnt];
847     for (i = 0; i < cnt; i++)
848     {
849     cpoints[i].x = (int)(points[i].x + xoffset);
850     cpoints[i].y = (int)(points[i].y + yoffset);
851    
852     CalcBoundingBox(cpoints[i].x, cpoints[i].y);
853     }
854     #ifndef __WXWINCE__
855     int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
856     #endif
857     (void)PolyPolygon(GetHdc(), cpoints, count, n);
858     #ifndef __WXWINCE__
859     SetPolyFillMode(GetHdc(),prev);
860     #endif
861     delete[] cpoints;
862     }
863     else
864     {
865     for (i = 0; i < cnt; i++)
866     CalcBoundingBox(points[i].x, points[i].y);
867    
868     #ifndef __WXWINCE__
869     int prev = SetPolyFillMode(GetHdc(),fillStyle==wxODDEVEN_RULE?ALTERNATE:WINDING);
870     #endif
871     (void)PolyPolygon(GetHdc(), (POINT*) points, count, n);
872     #ifndef __WXWINCE__
873     SetPolyFillMode(GetHdc(),prev);
874     #endif
875     }
876     #endif
877     // __WXWINCE__
878     }
879    
880     void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
881     {
882     WXMICROWIN_CHECK_HDC
883    
884     // Do things less efficiently if we have offsets
885     if (xoffset != 0 || yoffset != 0)
886     {
887     POINT *cpoints = new POINT[n];
888     int i;
889     for (i = 0; i < n; i++)
890     {
891     cpoints[i].x = (int)(points[i].x + xoffset);
892     cpoints[i].y = (int)(points[i].y + yoffset);
893    
894     CalcBoundingBox(cpoints[i].x, cpoints[i].y);
895     }
896     (void)Polyline(GetHdc(), cpoints, n);
897     delete[] cpoints;
898     }
899     else
900     {
901     int i;
902     for (i = 0; i < n; i++)
903     CalcBoundingBox(points[i].x, points[i].y);
904    
905     (void)Polyline(GetHdc(), (POINT*) points, n);
906     }
907     }
908    
909     void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
910     {
911     WXMICROWIN_CHECK_HDC
912    
913     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
914    
915     wxCoord x2 = x + width;
916     wxCoord y2 = y + height;
917    
918     if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
919     {
920     RECT rect;
921     rect.left = XLOG2DEV(x);
922     rect.top = YLOG2DEV(y);
923     rect.right = XLOG2DEV(x2);
924     rect.bottom = YLOG2DEV(y2);
925     (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
926     }
927     else
928     {
929     // Windows draws the filled rectangles without outline (i.e. drawn with a
930     // transparent pen) one pixel smaller in both directions and we want them
931     // to have the same size regardless of which pen is used - adjust
932    
933     // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
934     if ( m_pen.GetStyle() == wxTRANSPARENT )
935     {
936     // Apparently not needed for WinCE (see e.g. Life! demo)
937     #ifndef __WXWINCE__
938     x2++;
939     y2++;
940     #endif
941     }
942    
943     (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
944     }
945    
946    
947     CalcBoundingBox(x, y);
948     CalcBoundingBox(x2, y2);
949     }
950    
951     void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
952     {
953     WXMICROWIN_CHECK_HDC
954    
955     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
956    
957     // Now, a negative radius value is interpreted to mean
958     // 'the proportion of the smallest X or Y dimension'
959    
960     if (radius < 0.0)
961     {
962     double smallest = (width < height) ? width : height;
963     radius = (- radius * smallest);
964     }
965    
966     wxCoord x2 = (x+width);
967     wxCoord y2 = (y+height);
968    
969     // Windows draws the filled rectangles without outline (i.e. drawn with a
970     // transparent pen) one pixel smaller in both directions and we want them
971     // to have the same size regardless of which pen is used - adjust
972     if ( m_pen.GetStyle() == wxTRANSPARENT )
973     {
974     x2++;
975     y2++;
976     }
977    
978     (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
979     YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
980    
981     CalcBoundingBox(x, y);
982     CalcBoundingBox(x2, y2);
983     }
984    
985     void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
986     {
987     WXMICROWIN_CHECK_HDC
988    
989     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
990    
991     wxCoord x2 = (x+width);
992     wxCoord y2 = (y+height);
993    
994     (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
995    
996     CalcBoundingBox(x, y);
997     CalcBoundingBox(x2, y2);
998     }
999    
1000     #if wxUSE_SPLINES
1001     void wxDC::DoDrawSpline(wxList *points)
1002     {
1003     #ifdef __WXWINCE__
1004     // WinCE does not support ::PolyBezier so use generic version
1005     wxDCBase::DoDrawSpline(points);
1006     #else
1007     // quadratic b-spline to cubic bezier spline conversion
1008     //
1009     // quadratic spline with control points P0,P1,P2
1010     // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1011     //
1012     // bezier spline with control points B0,B1,B2,B3
1013     // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1014     //
1015     // control points of bezier spline calculated from b-spline
1016     // B0 = P0
1017     // B1 = (2*P1 + P0)/3
1018     // B2 = (2*P1 + P2)/3
1019     // B3 = P2
1020    
1021     WXMICROWIN_CHECK_HDC
1022    
1023     wxASSERT_MSG( points, wxT("NULL pointer to spline points?") );
1024    
1025     const size_t n_points = points->GetCount();
1026     wxASSERT_MSG( n_points > 2 , wxT("incomplete list of spline points?") );
1027    
1028     const size_t n_bezier_points = n_points * 3 + 1;
1029     POINT *lppt = (POINT *)malloc(n_bezier_points*sizeof(POINT));
1030     size_t bezier_pos = 0;
1031     wxCoord x1, y1, x2, y2, cx1, cy1, cx4, cy4;
1032    
1033     wxList::compatibility_iterator node = points->GetFirst();
1034     wxPoint *p = (wxPoint *)node->GetData();
1035     lppt[ bezier_pos ].x = x1 = p->x;
1036     lppt[ bezier_pos ].y = y1 = p->y;
1037     bezier_pos++;
1038     lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1039     bezier_pos++;
1040    
1041     node = node->GetNext();
1042     p = (wxPoint *)node->GetData();
1043    
1044     x2 = p->x;
1045     y2 = p->y;
1046     cx1 = ( x1 + x2 ) / 2;
1047     cy1 = ( y1 + y2 ) / 2;
1048     lppt[ bezier_pos ].x = XLOG2DEV(cx1);
1049     lppt[ bezier_pos ].y = YLOG2DEV(cy1);
1050     bezier_pos++;
1051     lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1052     bezier_pos++;
1053    
1054     #if !wxUSE_STL
1055     while ((node = node->GetNext()) != NULL)
1056     #else
1057     while ((node = node->GetNext()))
1058     #endif // !wxUSE_STL
1059     {
1060     p = (wxPoint *)node->GetData();
1061     x1 = x2;
1062     y1 = y2;
1063     x2 = p->x;
1064     y2 = p->y;
1065     cx4 = (x1 + x2) / 2;
1066     cy4 = (y1 + y2) / 2;
1067     // B0 is B3 of previous segment
1068     // B1:
1069     lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx1)/3);
1070     lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy1)/3);
1071     bezier_pos++;
1072     // B2:
1073     lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx4)/3);
1074     lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy4)/3);
1075     bezier_pos++;
1076     // B3:
1077     lppt[ bezier_pos ].x = XLOG2DEV(cx4);
1078     lppt[ bezier_pos ].y = YLOG2DEV(cy4);
1079     bezier_pos++;
1080     cx1 = cx4;
1081     cy1 = cy4;
1082     }
1083    
1084     lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1085     bezier_pos++;
1086     lppt[ bezier_pos ].x = XLOG2DEV(x2);
1087     lppt[ bezier_pos ].y = YLOG2DEV(y2);
1088     bezier_pos++;
1089     lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1090     bezier_pos++;
1091    
1092     ::PolyBezier( GetHdc(), lppt, bezier_pos );
1093    
1094     free(lppt);
1095     #endif
1096     }
1097     #endif
1098    
1099     // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1100     void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
1101     {
1102     #ifdef __WXWINCE__
1103     DoDrawEllipticArcRot( x, y, w, h, sa, ea );
1104     #else
1105    
1106     WXMICROWIN_CHECK_HDC
1107    
1108     wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1109    
1110     wxCoord x2 = x + w;
1111     wxCoord y2 = y + h;
1112    
1113     int rx1 = XLOG2DEV(x+w/2);
1114     int ry1 = YLOG2DEV(y+h/2);
1115     int rx2 = rx1;
1116     int ry2 = ry1;
1117    
1118     sa = DegToRad(sa);
1119     ea = DegToRad(ea);
1120    
1121     rx1 += (int)(100.0 * abs(w) * cos(sa));
1122     ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa));
1123     rx2 += (int)(100.0 * abs(w) * cos(ea));
1124     ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea));
1125    
1126     // Swap start and end positions if the end angle is less than the start angle.
1127     if (ea < sa) {
1128     int temp;
1129     temp = rx2;
1130     rx2 = rx1;
1131     rx1 = temp;
1132     temp = ry2;
1133     ry2 = ry1;
1134     ry1 = temp;
1135     }
1136    
1137     // draw pie with NULL_PEN first and then outline otherwise a line is
1138     // drawn from the start and end points to the centre
1139     HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
1140     if (m_signY > 0)
1141     {
1142     (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
1143     rx1, ry1, rx2, ry2);
1144     }
1145     else
1146     {
1147     (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
1148     rx1, ry1-1, rx2, ry2-1);
1149     }
1150    
1151     ::SelectObject(GetHdc(), hpenOld);
1152    
1153     (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
1154     rx1, ry1, rx2, ry2);
1155    
1156     CalcBoundingBox(x, y);
1157     CalcBoundingBox(x2, y2);
1158     #endif
1159     }
1160    
1161     void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
1162     {
1163     WXMICROWIN_CHECK_HDC
1164    
1165     wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") );
1166    
1167     #ifdef __WIN32__
1168     ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL);
1169     #else
1170     ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon));
1171     #endif
1172    
1173     CalcBoundingBox(x, y);
1174     CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight());
1175     }
1176    
1177     void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
1178     {
1179     WXMICROWIN_CHECK_HDC
1180    
1181     wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1182    
1183     int width = bmp.GetWidth(),
1184     height = bmp.GetHeight();
1185    
1186     HBITMAP hbmpMask = 0;
1187    
1188     #if wxUSE_PALETTE
1189     HPALETTE oldPal = 0;
1190     #endif // wxUSE_PALETTE
1191    
1192     if ( bmp.HasAlpha() )
1193     {
1194     MemoryHDC hdcMem;
1195     SelectInHDC select(hdcMem, GetHbitmapOf(bmp));
1196    
1197     if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, hdcMem, bmp) )
1198     return;
1199     }
1200    
1201     if ( useMask )
1202     {
1203     wxMask *mask = bmp.GetMask();
1204     if ( mask )
1205     hbmpMask = (HBITMAP)mask->GetMaskBitmap();
1206    
1207     if ( !hbmpMask )
1208     {
1209     // don't give assert here because this would break existing
1210     // programs - just silently ignore useMask parameter
1211     useMask = false;
1212     }
1213     }
1214     if ( useMask )
1215     {
1216     #ifdef __WIN32__
1217     // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1218     // points
1219     // On some systems, MaskBlt succeeds yet is much much slower
1220     // than the wxWidgets fall-back implementation. So we need
1221     // to be able to switch this on and off at runtime.
1222     bool ok = false;
1223     #if wxUSE_SYSTEM_OPTIONS
1224     if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1225     #endif
1226     {
1227     HDC cdc = GetHdc();
1228     HDC hdcMem = ::CreateCompatibleDC(GetHdc());
1229     HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp));
1230     #if wxUSE_PALETTE
1231     wxPalette *pal = bmp.GetPalette();
1232     if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1233     {
1234     oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE);
1235     ::RealizePalette(hdcMem);
1236     }
1237     #endif // wxUSE_PALETTE
1238    
1239     ok = ::MaskBlt(cdc, x, y, width, height,
1240     hdcMem, 0, 0,
1241     hbmpMask, 0, 0,
1242     MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
1243    
1244     #if wxUSE_PALETTE
1245     if (oldPal)
1246     ::SelectPalette(hdcMem, oldPal, FALSE);
1247     #endif // wxUSE_PALETTE
1248    
1249     ::SelectObject(hdcMem, hOldBitmap);
1250     ::DeleteDC(hdcMem);
1251     }
1252    
1253     if ( !ok )
1254     #endif // Win32
1255     {
1256     // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1257     // level
1258     wxMemoryDC memDC;
1259    
1260     memDC.SelectObjectAsSource(bmp);
1261    
1262     Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
1263    
1264     memDC.SelectObject(wxNullBitmap);
1265     }
1266     }
1267     else // no mask, just use BitBlt()
1268     {
1269     HDC cdc = GetHdc();
1270     HDC memdc = ::CreateCompatibleDC( cdc );
1271     HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
1272    
1273     wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
1274    
1275     COLORREF old_textground = ::GetTextColor(GetHdc());
1276     COLORREF old_background = ::GetBkColor(GetHdc());
1277     if (m_textForegroundColour.Ok())
1278     {
1279     ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
1280     }
1281     if (m_textBackgroundColour.Ok())
1282     {
1283     ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1284     }
1285    
1286     #if wxUSE_PALETTE
1287     wxPalette *pal = bmp.GetPalette();
1288     if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1289     {
1290     oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE);
1291     ::RealizePalette(memdc);
1292     }
1293     #endif // wxUSE_PALETTE
1294    
1295     HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap );
1296     ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
1297    
1298     #if wxUSE_PALETTE
1299     if (oldPal)
1300     ::SelectPalette(memdc, oldPal, FALSE);
1301     #endif // wxUSE_PALETTE
1302    
1303     ::SelectObject( memdc, hOldBitmap );
1304     ::DeleteDC( memdc );
1305    
1306     ::SetTextColor(GetHdc(), old_textground);
1307     ::SetBkColor(GetHdc(), old_background);
1308     }
1309     }
1310    
1311     void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
1312     {
1313     WXMICROWIN_CHECK_HDC
1314    
1315     DrawAnyText(text, x, y);
1316    
1317     // update the bounding box
1318     CalcBoundingBox(x, y);
1319    
1320     wxCoord w, h;
1321     GetTextExtent(text, &w, &h);
1322     CalcBoundingBox(x + w, y + h);
1323     }
1324    
1325     void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
1326     {
1327     WXMICROWIN_CHECK_HDC
1328    
1329     // prepare for drawing the text
1330     if ( m_textForegroundColour.Ok() )
1331     SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
1332    
1333     DWORD old_background = 0;
1334     if ( m_textBackgroundColour.Ok() )
1335     {
1336     old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1337     }
1338    
1339     SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
1340     : OPAQUE);
1341    
1342     #ifdef __WXWINCE__
1343     if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL,
1344     text.c_str(), text.length(), NULL) == 0 )
1345     {
1346     wxLogLastError(wxT("TextOut"));
1347     }
1348     #else
1349     if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
1350     text.c_str(), text.length()) == 0 )
1351     {
1352     wxLogLastError(wxT("TextOut"));
1353     }
1354     #endif
1355    
1356     // restore the old parameters (text foreground colour may be left because
1357     // it never is set to anything else, but background should remain
1358     // transparent even if we just drew an opaque string)
1359     if ( m_textBackgroundColour.Ok() )
1360     (void)SetBkColor(GetHdc(), old_background);
1361    
1362     SetBkMode(GetHdc(), TRANSPARENT);
1363     }
1364    
1365     void wxDC::DoDrawRotatedText(const wxString& text,
1366     wxCoord x, wxCoord y,
1367     double angle)
1368     {
1369     WXMICROWIN_CHECK_HDC
1370    
1371     // we test that we have some font because otherwise we should still use the
1372     // "else" part below to avoid that DrawRotatedText(angle = 180) and
1373     // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1374     // font for drawing rotated fonts unfortunately)
1375     if ( (angle == 0.0) && m_font.Ok() )
1376     {
1377     DoDrawText(text, x, y);
1378     }
1379     #ifndef __WXMICROWIN__
1380     else
1381     {
1382     // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1383     // because it's not TrueType and so can't have non zero
1384     // orientation/escapement under Win9x
1385     wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT;
1386     HFONT hfont = (HFONT)font.GetResourceHandle();
1387     LOGFONT lf;
1388     if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
1389     {
1390     wxLogLastError(wxT("GetObject(hfont)"));
1391     }
1392    
1393     // GDI wants the angle in tenth of degree
1394     long angle10 = (long)(angle * 10);
1395     lf.lfEscapement = angle10;
1396     lf. lfOrientation = angle10;
1397    
1398     hfont = ::CreateFontIndirect(&lf);
1399     if ( !hfont )
1400     {
1401     wxLogLastError(wxT("CreateFont"));
1402     }
1403     else
1404     {
1405     HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
1406    
1407     DrawAnyText(text, x, y);
1408    
1409     (void)::SelectObject(GetHdc(), hfontOld);
1410     (void)::DeleteObject(hfont);
1411     }
1412    
1413     // call the bounding box by adding all four vertices of the rectangle
1414     // containing the text to it (simpler and probably not slower than
1415     // determining which of them is really topmost/leftmost/...)
1416     wxCoord w, h;
1417     GetTextExtent(text, &w, &h);
1418    
1419     double rad = DegToRad(angle);
1420    
1421     // "upper left" and "upper right"
1422     CalcBoundingBox(x, y);
1423     CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
1424    
1425     // "bottom left" and "bottom right"
1426     x += (wxCoord)(h*sin(rad));
1427     y += (wxCoord)(h*cos(rad));
1428     CalcBoundingBox(x, y);
1429     CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
1430     }
1431     #endif
1432     }
1433    
1434     // ---------------------------------------------------------------------------
1435     // set GDI objects
1436     // ---------------------------------------------------------------------------
1437    
1438     #if wxUSE_PALETTE
1439    
1440     void wxDC::DoSelectPalette(bool realize)
1441     {
1442     WXMICROWIN_CHECK_HDC
1443    
1444     // Set the old object temporarily, in case the assignment deletes an object
1445     // that's not yet selected out.
1446     if (m_oldPalette)
1447     {
1448     ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE);
1449     m_oldPalette = 0;
1450     }
1451    
1452     if ( m_palette.Ok() )
1453     {
1454     HPALETTE oldPal = ::SelectPalette(GetHdc(),
1455     GetHpaletteOf(m_palette),
1456     false);
1457     if (!m_oldPalette)
1458     m_oldPalette = (WXHPALETTE) oldPal;
1459    
1460     if (realize)
1461     ::RealizePalette(GetHdc());
1462     }
1463     }
1464    
1465     void wxDC::SetPalette(const wxPalette& palette)
1466     {
1467     if ( palette.Ok() )
1468     {
1469     m_palette = palette;
1470     DoSelectPalette(true);
1471     }
1472     }
1473    
1474     void wxDC::InitializePalette()
1475     {
1476     if ( wxDisplayDepth() <= 8 )
1477     {
1478     // look for any window or parent that has a custom palette. If any has
1479     // one then we need to use it in drawing operations
1480     wxWindow *win = m_canvas->GetAncestorWithCustomPalette();
1481    
1482     m_hasCustomPalette = win && win->HasCustomPalette();
1483     if ( m_hasCustomPalette )
1484     {
1485     m_palette = win->GetPalette();
1486    
1487     // turn on MSW translation for this palette
1488     DoSelectPalette();
1489     }
1490     }
1491     }
1492    
1493     #endif // wxUSE_PALETTE
1494    
1495     // SetFont/Pen/Brush() really ask to be implemented as a single template
1496     // function... but doing it is not worth breaking OpenWatcom build <sigh>
1497    
1498     void wxDC::SetFont(const wxFont& font)
1499     {
1500     WXMICROWIN_CHECK_HDC
1501    
1502     if ( font == m_font )
1503     return;
1504    
1505     if ( font.Ok() )
1506     {
1507     HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font));
1508     if ( hfont == HGDI_ERROR )
1509     {
1510     wxLogLastError(_T("SelectObject(font)"));
1511     }
1512     else // selected ok
1513     {
1514     if ( !m_oldFont )
1515     m_oldFont = (WXHFONT)hfont;
1516    
1517     m_font = font;
1518     }
1519     }
1520     else // invalid font, reset the current font
1521     {
1522     if ( m_oldFont )
1523     {
1524     if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR )
1525     {
1526     wxLogLastError(_T("SelectObject(old font)"));
1527     }
1528    
1529     m_oldFont = 0;
1530     }
1531    
1532     m_font = wxNullFont;
1533     }
1534     }
1535    
1536     void wxDC::SetPen(const wxPen& pen)
1537     {
1538     WXMICROWIN_CHECK_HDC
1539    
1540     if ( pen == m_pen )
1541     return;
1542    
1543     if ( pen.Ok() )
1544     {
1545     HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen));
1546     if ( hpen == HGDI_ERROR )
1547     {
1548     wxLogLastError(_T("SelectObject(pen)"));
1549     }
1550     else // selected ok
1551     {
1552     if ( !m_oldPen )
1553     m_oldPen = (WXHPEN)hpen;
1554    
1555     m_pen = pen;
1556     }
1557     }
1558     else // invalid pen, reset the current pen
1559     {
1560     if ( m_oldPen )
1561     {
1562     if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR )
1563     {
1564     wxLogLastError(_T("SelectObject(old pen)"));
1565     }
1566    
1567     m_oldPen = 0;
1568     }
1569    
1570     m_pen = wxNullPen;
1571     }
1572     }
1573    
1574     void wxDC::SetBrush(const wxBrush& brush)
1575     {
1576     WXMICROWIN_CHECK_HDC
1577    
1578     if ( brush == m_brush )
1579     return;
1580    
1581     if ( brush.Ok() )
1582     {
1583     // we must make sure the brush is aligned with the logical coordinates
1584     // before selecting it
1585     wxBitmap *stipple = brush.GetStipple();
1586     if ( stipple && stipple->Ok() )
1587     {
1588     if ( !::SetBrushOrgEx
1589     (
1590     GetHdc(),
1591     m_deviceOriginX % stipple->GetWidth(),
1592     m_deviceOriginY % stipple->GetHeight(),
1593     NULL // [out] previous brush origin
1594     ) )
1595     {
1596     wxLogLastError(_T("SetBrushOrgEx()"));
1597     }
1598     }
1599    
1600     HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush));
1601     if ( hbrush == HGDI_ERROR )
1602     {
1603     wxLogLastError(_T("SelectObject(brush)"));
1604     }
1605     else // selected ok
1606     {
1607     if ( !m_oldBrush )
1608     m_oldBrush = (WXHBRUSH)hbrush;
1609    
1610     m_brush = brush;
1611     }
1612     }
1613     else // invalid brush, reset the current brush
1614     {
1615     if ( m_oldBrush )
1616     {
1617     if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR )
1618     {
1619     wxLogLastError(_T("SelectObject(old brush)"));
1620     }
1621    
1622     m_oldBrush = 0;
1623     }
1624    
1625     m_brush = wxNullBrush;
1626     }
1627     }
1628    
1629     void wxDC::SetBackground(const wxBrush& brush)
1630     {
1631     WXMICROWIN_CHECK_HDC
1632    
1633     m_backgroundBrush = brush;
1634    
1635     if ( m_backgroundBrush.Ok() )
1636     {
1637     (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel());
1638     }
1639     }
1640    
1641     void wxDC::SetBackgroundMode(int mode)
1642     {
1643     WXMICROWIN_CHECK_HDC
1644    
1645     m_backgroundMode = mode;
1646    
1647     // SetBackgroundColour now only refers to text background
1648     // and m_backgroundMode is used there
1649     }
1650    
1651     void wxDC::SetLogicalFunction(int function)
1652     {
1653     WXMICROWIN_CHECK_HDC
1654    
1655     m_logicalFunction = function;
1656    
1657     SetRop(m_hDC);
1658     }
1659    
1660     void wxDC::SetRop(WXHDC dc)
1661     {
1662     if ( !dc || m_logicalFunction < 0 )
1663     return;
1664    
1665     int rop;
1666    
1667     switch (m_logicalFunction)
1668     {
1669     case wxCLEAR: rop = R2_BLACK; break;
1670     case wxXOR: rop = R2_XORPEN; break;
1671     case wxINVERT: rop = R2_NOT; break;
1672     case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
1673     case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
1674     case wxCOPY: rop = R2_COPYPEN; break;
1675     case wxAND: rop = R2_MASKPEN; break;
1676     case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
1677     case wxNO_OP: rop = R2_NOP; break;
1678     case wxNOR: rop = R2_NOTMERGEPEN; break;
1679     case wxEQUIV: rop = R2_NOTXORPEN; break;
1680     case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
1681     case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
1682     case wxNAND: rop = R2_NOTMASKPEN; break;
1683     case wxOR: rop = R2_MERGEPEN; break;
1684     case wxSET: rop = R2_WHITE; break;
1685    
1686     default:
1687     wxFAIL_MSG( wxT("unsupported logical function") );
1688     return;
1689     }
1690    
1691     SetROP2(GetHdc(), rop);
1692     }
1693    
1694     bool wxDC::StartDoc(const wxString& WXUNUSED(message))
1695     {
1696     // We might be previewing, so return true to let it continue.
1697     return true;
1698     }
1699    
1700     void wxDC::EndDoc()
1701     {
1702     }
1703    
1704     void wxDC::StartPage()
1705     {
1706     }
1707    
1708     void wxDC::EndPage()
1709     {
1710     }
1711    
1712     // ---------------------------------------------------------------------------
1713     // text metrics
1714     // ---------------------------------------------------------------------------
1715    
1716     wxCoord wxDC::GetCharHeight() const
1717     {
1718     WXMICROWIN_CHECK_HDC_RET(0)
1719    
1720     TEXTMETRIC lpTextMetric;
1721    
1722     GetTextMetrics(GetHdc(), &lpTextMetric);
1723    
1724     return lpTextMetric.tmHeight;
1725     }
1726    
1727     wxCoord wxDC::GetCharWidth() const
1728     {
1729     WXMICROWIN_CHECK_HDC_RET(0)
1730    
1731     TEXTMETRIC lpTextMetric;
1732    
1733     GetTextMetrics(GetHdc(), &lpTextMetric);
1734    
1735     return lpTextMetric.tmAveCharWidth;
1736     }
1737    
1738     void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
1739     wxCoord *descent, wxCoord *externalLeading,
1740     wxFont *font) const
1741     {
1742     #ifdef __WXMICROWIN__
1743     if (!GetHDC())
1744     {
1745     if (x) *x = 0;
1746     if (y) *y = 0;
1747     if (descent) *descent = 0;
1748     if (externalLeading) *externalLeading = 0;
1749     return;
1750     }
1751     #endif // __WXMICROWIN__
1752    
1753     HFONT hfontOld;
1754     if ( font )
1755     {
1756     wxASSERT_MSG( font->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1757    
1758     hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
1759     }
1760     else // don't change the font
1761     {
1762     hfontOld = 0;
1763     }
1764    
1765     SIZE sizeRect;
1766     const size_t len = string.length();
1767     if ( !::GetTextExtentPoint32(GetHdc(), string, len, &sizeRect) )
1768     {
1769     wxLogLastError(_T("GetTextExtentPoint32()"));
1770     }
1771    
1772     #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1773     // the result computed by GetTextExtentPoint32() may be too small as it
1774     // accounts for under/overhang of the first/last character while we want
1775     // just the bounding rect for this string so adjust the width as needed
1776     // (using API not available in 2002 SDKs of WinCE)
1777     if ( len > 0 )
1778     {
1779     ABC width;
1780     const wxChar chFirst = *string.begin();
1781     if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) )
1782     {
1783     if ( width.abcA < 0 )
1784     sizeRect.cx -= width.abcA;
1785    
1786     if ( len > 1 )
1787     {
1788     const wxChar chLast = *string.rbegin();
1789     ::GetCharABCWidths(GetHdc(), chLast, chLast, &width);
1790     }
1791     //else: we already have the width of the last character
1792    
1793     if ( width.abcC < 0 )
1794     sizeRect.cx -= width.abcC;
1795     }
1796     //else: GetCharABCWidths() failed, not a TrueType font?
1797     }
1798     #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1799    
1800     TEXTMETRIC tm;
1801     ::GetTextMetrics(GetHdc(), &tm);
1802    
1803     if (x)
1804     *x = sizeRect.cx;
1805     if (y)
1806     *y = sizeRect.cy;
1807     if (descent)
1808     *descent = tm.tmDescent;
1809     if (externalLeading)
1810     *externalLeading = tm.tmExternalLeading;
1811    
1812     if ( hfontOld )
1813     {
1814     ::SelectObject(GetHdc(), hfontOld);
1815     }
1816     }
1817    
1818    
1819     // Each element of the array will be the width of the string up to and
1820     // including the coresoponding character in text.
1821    
1822     bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1823     {
1824     static int maxLenText = -1;
1825     static int maxWidth = -1;
1826     int fit = 0;
1827     SIZE sz = {0,0};
1828     int stlen = text.length();
1829    
1830     if (maxLenText == -1)
1831     {
1832     // Win9x and WinNT+ have different limits
1833     int version = wxGetOsVersion();
1834     maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
1835     maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
1836     }
1837    
1838     widths.Empty();
1839     widths.Add(0, stlen); // fill the array with zeros
1840     if (stlen == 0)
1841     return true;
1842    
1843     if (!::GetTextExtentExPoint(GetHdc(),
1844     text.c_str(), // string to check
1845     wxMin(stlen, maxLenText),
1846     maxWidth,
1847     &fit, // [out] count of chars
1848     // that will fit
1849     &widths[0], // array to fill
1850     &sz))
1851     {
1852     // API failed
1853     wxLogLastError(wxT("GetTextExtentExPoint"));
1854     return false;
1855     }
1856    
1857     return true;
1858     }
1859    
1860    
1861    
1862    
1863     void wxDC::SetMapMode(int mode)
1864     {
1865     WXMICROWIN_CHECK_HDC
1866    
1867     m_mappingMode = mode;
1868    
1869     if ( mode == wxMM_TEXT )
1870     {
1871     m_logicalScaleX =
1872     m_logicalScaleY = 1.0;
1873     }
1874     else // need to do some calculations
1875     {
1876     int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES),
1877     pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES),
1878     mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE),
1879     mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1880    
1881     if ( (mm_width == 0) || (mm_height == 0) )
1882     {
1883     // we can't calculate mm2pixels[XY] then!
1884     return;
1885     }
1886    
1887     double mm2pixelsX = (double)pixel_width / mm_width,
1888     mm2pixelsY = (double)pixel_height / mm_height;
1889    
1890     switch (mode)
1891     {
1892     case wxMM_TWIPS:
1893     m_logicalScaleX = twips2mm * mm2pixelsX;
1894     m_logicalScaleY = twips2mm * mm2pixelsY;
1895     break;
1896    
1897     case wxMM_POINTS:
1898     m_logicalScaleX = pt2mm * mm2pixelsX;
1899     m_logicalScaleY = pt2mm * mm2pixelsY;
1900     break;
1901    
1902     case wxMM_METRIC:
1903     m_logicalScaleX = mm2pixelsX;
1904     m_logicalScaleY = mm2pixelsY;
1905     break;
1906    
1907     case wxMM_LOMETRIC:
1908     m_logicalScaleX = mm2pixelsX / 10.0;
1909     m_logicalScaleY = mm2pixelsY / 10.0;
1910     break;
1911    
1912     default:
1913     wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1914     }
1915     }
1916    
1917     // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1918     // cases we could do with MM_TEXT and in the remaining 0.9% with
1919     // MM_ISOTROPIC (TODO!)
1920     #ifndef __WXWINCE__
1921     ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
1922    
1923     int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
1924     height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
1925    
1926     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1927     ::SetWindowExtEx(GetHdc(), width, height, NULL);
1928    
1929     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
1930     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);
1931     #endif
1932     }
1933    
1934     void wxDC::SetUserScale(double x, double y)
1935     {
1936     WXMICROWIN_CHECK_HDC
1937    
1938     if ( x == m_userScaleX && y == m_userScaleY )
1939     return;
1940    
1941     m_userScaleX = x;
1942     m_userScaleY = y;
1943    
1944     this->SetMapMode(m_mappingMode);
1945     }
1946    
1947     void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight),
1948     bool WXUNUSED_IN_WINCE(yBottomUp))
1949     {
1950     WXMICROWIN_CHECK_HDC
1951    
1952     #ifndef __WXWINCE__
1953     int signX = xLeftRight ? 1 : -1,
1954     signY = yBottomUp ? -1 : 1;
1955    
1956     if ( signX != m_signX || signY != m_signY )
1957     {
1958     m_signX = signX;
1959     m_signY = signY;
1960    
1961     SetMapMode(m_mappingMode);
1962     }
1963     #endif
1964     }
1965    
1966     void wxDC::SetSystemScale(double x, double y)
1967     {
1968     WXMICROWIN_CHECK_HDC
1969    
1970     if ( x == m_scaleX && y == m_scaleY )
1971     return;
1972    
1973     m_scaleX = x;
1974     m_scaleY = y;
1975    
1976     #ifndef __WXWINCE__
1977     SetMapMode(m_mappingMode);
1978     #endif
1979     }
1980    
1981     void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y)
1982     {
1983     WXMICROWIN_CHECK_HDC
1984    
1985     if ( x == m_logicalOriginX && y == m_logicalOriginY )
1986     return;
1987    
1988     m_logicalOriginX = x;
1989     m_logicalOriginY = y;
1990    
1991     #ifndef __WXWINCE__
1992     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1993     #endif
1994     }
1995    
1996     void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y)
1997     {
1998     WXMICROWIN_CHECK_HDC
1999    
2000     if ( x == m_deviceOriginX && y == m_deviceOriginY )
2001     return;
2002    
2003     m_deviceOriginX = x;
2004     m_deviceOriginY = y;
2005    
2006     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
2007     }
2008    
2009     // ---------------------------------------------------------------------------
2010     // coordinates transformations
2011     // ---------------------------------------------------------------------------
2012    
2013     wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2014     {
2015     return DeviceToLogicalXRel(x - m_deviceOriginX)*m_signX + m_logicalOriginX;
2016     }
2017    
2018     wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2019     {
2020     // axis orientation is not taken into account for conversion of a distance
2021     return (wxCoord)(x / (m_logicalScaleX*m_userScaleX*m_scaleX));
2022     }
2023    
2024     wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2025     {
2026     return DeviceToLogicalYRel(y - m_deviceOriginY)*m_signY + m_logicalOriginY;
2027     }
2028    
2029     wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2030     {
2031     // axis orientation is not taken into account for conversion of a distance
2032     return (wxCoord)( y / (m_logicalScaleY*m_userScaleY*m_scaleY));
2033     }
2034    
2035     wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2036     {
2037     return LogicalToDeviceXRel(x - m_logicalOriginX)*m_signX + m_deviceOriginX;
2038     }
2039    
2040     wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2041     {
2042     // axis orientation is not taken into account for conversion of a distance
2043     return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX);
2044     }
2045    
2046     wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2047     {
2048     return LogicalToDeviceYRel(y - m_logicalOriginY)*m_signY + m_deviceOriginY;
2049     }
2050    
2051     wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2052     {
2053     // axis orientation is not taken into account for conversion of a distance
2054     return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY);
2055     }
2056    
2057     // ---------------------------------------------------------------------------
2058     // bit blit
2059     // ---------------------------------------------------------------------------
2060    
2061     bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
2062     wxCoord width, wxCoord height,
2063     wxDC *source, wxCoord xsrc, wxCoord ysrc,
2064     int rop, bool useMask,
2065     wxCoord xsrcMask, wxCoord ysrcMask)
2066     {
2067     wxCHECK_MSG( source, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2068    
2069     WXMICROWIN_CHECK_HDC_RET(false)
2070    
2071     // if either the source or destination has alpha channel, we must use
2072     // AlphaBlt() as other function don't handle it correctly
2073     const wxBitmap& bmpSrc = source->m_selectedBitmap;
2074     if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() ||
2075     (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) )
2076     {
2077     if ( AlphaBlt(GetHdc(), xdest, ydest, width, height,
2078     xsrc, ysrc, GetHdcOf(*source), bmpSrc) )
2079     return true;
2080     }
2081    
2082     wxMask *mask = NULL;
2083     if ( useMask )
2084     {
2085     mask = bmpSrc.GetMask();
2086    
2087     if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) )
2088     {
2089     // don't give assert here because this would break existing
2090     // programs - just silently ignore useMask parameter
2091     useMask = false;
2092     }
2093     }
2094    
2095     if (xsrcMask == -1 && ysrcMask == -1)
2096     {
2097     xsrcMask = xsrc; ysrcMask = ysrc;
2098     }
2099    
2100     COLORREF old_textground = ::GetTextColor(GetHdc());
2101     COLORREF old_background = ::GetBkColor(GetHdc());
2102     if (m_textForegroundColour.Ok())
2103     {
2104     ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
2105     }
2106     if (m_textBackgroundColour.Ok())
2107     {
2108     ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
2109     }
2110    
2111     DWORD dwRop;
2112     switch (rop)
2113     {
2114     case wxXOR: dwRop = SRCINVERT; break;
2115     case wxINVERT: dwRop = DSTINVERT; break;
2116     case wxOR_REVERSE: dwRop = 0x00DD0228; break;
2117     case wxAND_REVERSE: dwRop = SRCERASE; break;
2118     case wxCLEAR: dwRop = BLACKNESS; break;
2119     case wxSET: dwRop = WHITENESS; break;
2120     case wxOR_INVERT: dwRop = MERGEPAINT; break;
2121     case wxAND: dwRop = SRCAND; break;
2122     case wxOR: dwRop = SRCPAINT; break;
2123     case wxEQUIV: dwRop = 0x00990066; break;
2124     case wxNAND: dwRop = 0x007700E6; break;
2125     case wxAND_INVERT: dwRop = 0x00220326; break;
2126     case wxCOPY: dwRop = SRCCOPY; break;
2127     case wxNO_OP: dwRop = DSTCOPY; break;
2128     case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
2129     case wxNOR: dwRop = NOTSRCCOPY; break;
2130     default:
2131     wxFAIL_MSG( wxT("unsupported logical function") );
2132     return false;
2133     }
2134    
2135     bool success = false;
2136    
2137     if (useMask)
2138     {
2139     #ifdef __WIN32__
2140     // we want the part of the image corresponding to the mask to be
2141     // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2142     // meaning of fg and bg is inverted which corresponds to wxWin notion
2143     // of the mask which is also contrary to the Windows one)
2144    
2145     // On some systems, MaskBlt succeeds yet is much much slower
2146     // than the wxWidgets fall-back implementation. So we need
2147     // to be able to switch this on and off at runtime.
2148     #if wxUSE_SYSTEM_OPTIONS
2149     if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2150     #endif
2151     {
2152     success = ::MaskBlt
2153     (
2154     GetHdc(),
2155     xdest, ydest, width, height,
2156     GetHdcOf(*source),
2157     xsrc, ysrc,
2158     (HBITMAP)mask->GetMaskBitmap(),
2159     xsrcMask, ysrcMask,
2160     MAKEROP4(dwRop, DSTCOPY)
2161     ) != 0;
2162     }
2163    
2164     if ( !success )
2165     #endif // Win32
2166     {
2167     // Blit bitmap with mask
2168     HDC dc_mask ;
2169     HDC dc_buffer ;
2170     HBITMAP buffer_bmap ;
2171    
2172     #if wxUSE_DC_CACHEING
2173     // create a temp buffer bitmap and DCs to access it and the mask
2174     wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, source->GetHDC());
2175     dc_mask = (HDC) dcCacheEntry1->m_dc;
2176    
2177     wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
2178     dc_buffer = (HDC) dcCacheEntry2->m_dc;
2179    
2180     wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
2181     width, height);
2182    
2183     buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
2184     #else // !wxUSE_DC_CACHEING
2185     // create a temp buffer bitmap and DCs to access it and the mask
2186     dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
2187     dc_buffer = ::CreateCompatibleDC(GetHdc());
2188     buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
2189     #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2190     HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
2191     HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
2192    
2193     // copy dest to buffer
2194     if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2195     GetHdc(), xdest, ydest, SRCCOPY) )
2196     {
2197     wxLogLastError(wxT("BitBlt"));
2198     }
2199    
2200     // copy src to buffer using selected raster op
2201     if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2202     GetHdcOf(*source), xsrc, ysrc, dwRop) )
2203     {
2204     wxLogLastError(wxT("BitBlt"));
2205     }
2206    
2207     // set masked area in buffer to BLACK (pixel value 0)
2208     COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2209     COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2210     if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2211     dc_mask, xsrcMask, ysrcMask, SRCAND) )
2212     {
2213     wxLogLastError(wxT("BitBlt"));
2214     }
2215    
2216     // set unmasked area in dest to BLACK
2217     ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2218     ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2219     if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height,
2220     dc_mask, xsrcMask, ysrcMask, SRCAND) )
2221     {
2222     wxLogLastError(wxT("BitBlt"));
2223     }
2224     ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
2225     ::SetTextColor(GetHdc(), prevCol);
2226    
2227     // OR buffer to dest
2228     success = ::BitBlt(GetHdc(), xdest, ydest,
2229     (int)width, (int)height,
2230     dc_buffer, 0, 0, SRCPAINT) != 0;
2231     if ( !success )
2232     {
2233     wxLogLastError(wxT("BitBlt"));
2234     }
2235    
2236     // tidy up temporary DCs and bitmap
2237     ::SelectObject(dc_mask, hOldMaskBitmap);
2238     ::SelectObject(dc_buffer, hOldBufferBitmap);
2239    
2240     #if !wxUSE_DC_CACHEING
2241     {
2242     ::DeleteDC(dc_mask);
2243     ::DeleteDC(dc_buffer);
2244     ::DeleteObject(buffer_bmap);
2245     }
2246     #endif
2247     }
2248     }
2249     else // no mask, just BitBlt() it
2250     {
2251     // if we already have a DIB, draw it using StretchDIBits(), otherwise
2252     // use StretchBlt() if available and finally fall back to BitBlt()
2253    
2254     // FIXME: use appropriate WinCE functions
2255     #ifndef __WXWINCE__
2256     const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS);
2257     if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) )
2258     {
2259     DIBSECTION ds;
2260     wxZeroMemory(ds);
2261    
2262     if ( ::GetObject(GetHbitmapOf(bmpSrc),
2263     sizeof(ds),
2264     &ds) == sizeof(ds) )
2265     {
2266     StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
2267    
2268     // Figure out what co-ordinate system we're supposed to specify
2269     // ysrc in.
2270     const LONG hDIB = ds.dsBmih.biHeight;
2271     if ( hDIB > 0 )
2272     {
2273     // reflect ysrc
2274     ysrc = hDIB - (ysrc + height);
2275     }
2276    
2277     if ( ::StretchDIBits(GetHdc(),
2278     xdest, ydest,
2279     width, height,
2280     xsrc, ysrc,
2281     width, height,
2282     ds.dsBm.bmBits,
2283     (LPBITMAPINFO)&ds.dsBmih,
2284     DIB_RGB_COLORS,
2285     dwRop
2286     ) == (int)GDI_ERROR )
2287     {
2288     // On Win9x this API fails most (all?) of the time, so
2289     // logging it becomes quite distracting. Since it falls
2290     // back to the code below this is not really serious, so
2291     // don't log it.
2292     //wxLogLastError(wxT("StretchDIBits"));
2293     }
2294     else
2295     {
2296     success = true;
2297     }
2298     }
2299     }
2300    
2301     if ( !success && (caps & RC_STRETCHBLT) )
2302     #endif
2303     // __WXWINCE__
2304     {
2305     #ifndef __WXWINCE__
2306     StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
2307     #endif
2308    
2309     if ( !::StretchBlt
2310     (
2311     GetHdc(),
2312     xdest, ydest, width, height,
2313     GetHdcOf(*source),
2314     xsrc, ysrc, width, height,
2315     dwRop
2316     ) )
2317     {
2318     wxLogLastError(_T("StretchBlt"));
2319     }
2320     else
2321     {
2322     success = true;
2323     }
2324     }
2325    
2326     if ( !success )
2327     {
2328     if ( !::BitBlt
2329     (
2330     GetHdc(),
2331     xdest, ydest,
2332     (int)width, (int)height,
2333     GetHdcOf(*source),
2334     xsrc, ysrc,
2335     dwRop
2336     ) )
2337     {
2338     wxLogLastError(_T("BitBlt"));
2339     }
2340     else
2341     {
2342     success = true;
2343     }
2344     }
2345     }
2346    
2347     ::SetTextColor(GetHdc(), old_textground);
2348     ::SetBkColor(GetHdc(), old_background);
2349    
2350     return success;
2351     }
2352    
2353     void wxDC::GetDeviceSize(int *width, int *height) const
2354     {
2355     WXMICROWIN_CHECK_HDC
2356    
2357     if ( width )
2358     *width = ::GetDeviceCaps(GetHdc(), HORZRES);
2359     if ( height )
2360     *height = ::GetDeviceCaps(GetHdc(), VERTRES);
2361     }
2362    
2363     void wxDC::DoGetSizeMM(int *w, int *h) const
2364     {
2365     WXMICROWIN_CHECK_HDC
2366    
2367     // if we implement it in terms of DoGetSize() instead of directly using the
2368     // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2369     // will also work for wxWindowDC and wxClientDC even though their size is
2370     // not the same as the total size of the screen
2371     int wPixels, hPixels;
2372     DoGetSize(&wPixels, &hPixels);
2373    
2374     if ( w )
2375     {
2376     int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES);
2377    
2378     wxCHECK_RET( wTotal, _T("0 width device?") );
2379    
2380     *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal;
2381     }
2382    
2383     if ( h )
2384     {
2385     int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES);
2386    
2387     wxCHECK_RET( hTotal, _T("0 height device?") );
2388    
2389     *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal;
2390     }
2391     }
2392    
2393     wxSize wxDC::GetPPI() const
2394     {
2395     WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2396    
2397     int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
2398     int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
2399    
2400     return wxSize(x, y);
2401     }
2402    
2403     // For use by wxWidgets only, unless custom units are required.
2404     void wxDC::SetLogicalScale(double x, double y)
2405     {
2406     WXMICROWIN_CHECK_HDC
2407    
2408     m_logicalScaleX = x;
2409     m_logicalScaleY = y;
2410     }
2411    
2412     // ----------------------------------------------------------------------------
2413     // DC caching
2414     // ----------------------------------------------------------------------------
2415    
2416     #if wxUSE_DC_CACHEING
2417    
2418     /*
2419     * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2420     * improve it in due course, either using arrays, or simply storing pointers to one
2421     * entry for the bitmap, and two for the DCs. -- JACS
2422     */
2423    
2424     wxList wxDC::sm_bitmapCache;
2425     wxList wxDC::sm_dcCache;
2426    
2427     wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth)
2428     {
2429     m_bitmap = hBitmap;
2430     m_dc = 0;
2431     m_width = w;
2432     m_height = h;
2433     m_depth = depth;
2434     }
2435    
2436     wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
2437     {
2438     m_bitmap = 0;
2439     m_dc = hDC;
2440     m_width = 0;
2441     m_height = 0;
2442     m_depth = depth;
2443     }
2444    
2445     wxDCCacheEntry::~wxDCCacheEntry()
2446     {
2447     if (m_bitmap)
2448     ::DeleteObject((HBITMAP) m_bitmap);
2449     if (m_dc)
2450     ::DeleteDC((HDC) m_dc);
2451     }
2452    
2453     wxDCCacheEntry* wxDC::FindBitmapInCache(WXHDC dc, int w, int h)
2454     {
2455     int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2456     wxList::compatibility_iterator node = sm_bitmapCache.GetFirst();
2457     while (node)
2458     {
2459     wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
2460    
2461     if (entry->m_depth == depth)
2462     {
2463     if (entry->m_width < w || entry->m_height < h)
2464     {
2465     ::DeleteObject((HBITMAP) entry->m_bitmap);
2466     entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2467     if ( !entry->m_bitmap)
2468     {
2469     wxLogLastError(wxT("CreateCompatibleBitmap"));
2470     }
2471     entry->m_width = w; entry->m_height = h;
2472     return entry;
2473     }
2474     return entry;
2475     }
2476    
2477     node = node->GetNext();
2478     }
2479     WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2480     if ( !hBitmap)
2481     {
2482     wxLogLastError(wxT("CreateCompatibleBitmap"));
2483     }
2484     wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
2485     AddToBitmapCache(entry);
2486     return entry;
2487     }
2488    
2489     wxDCCacheEntry* wxDC::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
2490     {
2491     int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2492     wxList::compatibility_iterator node = sm_dcCache.GetFirst();
2493     while (node)
2494     {
2495     wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
2496    
2497     // Don't return the same one as we already have
2498     if (!notThis || (notThis != entry))
2499     {
2500     if (entry->m_depth == depth)
2501     {
2502     return entry;
2503     }
2504     }
2505    
2506     node = node->GetNext();
2507     }
2508     WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
2509     if ( !hDC)
2510     {
2511     wxLogLastError(wxT("CreateCompatibleDC"));
2512     }
2513     wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
2514     AddToDCCache(entry);
2515     return entry;
2516     }
2517    
2518     void wxDC::AddToBitmapCache(wxDCCacheEntry* entry)
2519     {
2520     sm_bitmapCache.Append(entry);
2521     }
2522    
2523     void wxDC::AddToDCCache(wxDCCacheEntry* entry)
2524     {
2525     sm_dcCache.Append(entry);
2526     }
2527    
2528     void wxDC::ClearCache()
2529     {
2530     WX_CLEAR_LIST(wxList, sm_dcCache);
2531     WX_CLEAR_LIST(wxList, sm_bitmapCache);
2532     }
2533    
2534     // Clean up cache at app exit
2535     class wxDCModule : public wxModule
2536     {
2537     public:
2538     virtual bool OnInit() { return true; }
2539     virtual void OnExit() { wxDC::ClearCache(); }
2540    
2541     private:
2542     DECLARE_DYNAMIC_CLASS(wxDCModule)
2543     };
2544    
2545     IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2546    
2547     #endif // wxUSE_DC_CACHEING
2548    
2549     // ----------------------------------------------------------------------------
2550     // alpha channel support
2551     // ----------------------------------------------------------------------------
2552    
2553     static bool AlphaBlt(HDC hdcDst,
2554     int x, int y, int width, int height,
2555     int srcX, int srcY, HDC hdcSrc,
2556     const wxBitmap& bmp)
2557     {
2558     wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2559     wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") );
2560    
2561     // do we have AlphaBlend() and company in the headers?
2562     #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2563     // yes, now try to see if we have it during run-time
2564     typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
2565     HDC,int,int,int,int,
2566     BLENDFUNCTION);
2567    
2568     static AlphaBlend_t
2569     pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend"));
2570     if ( pfnAlphaBlend )
2571     {
2572     BLENDFUNCTION bf;
2573     bf.BlendOp = AC_SRC_OVER;
2574     bf.BlendFlags = 0;
2575     bf.SourceConstantAlpha = 0xff;
2576     bf.AlphaFormat = AC_SRC_ALPHA;
2577    
2578     if ( pfnAlphaBlend(hdcDst, x, y, width, height,
2579     hdcSrc, srcX, srcY, width, height,
2580     bf) )
2581     {
2582     // skip wxAlphaBlend() call below
2583     return true;
2584     }
2585    
2586     wxLogLastError(_T("AlphaBlend"));
2587     }
2588     #else
2589     wxUnusedVar(hdcSrc);
2590     #endif // defined(AC_SRC_OVER)
2591    
2592     // AlphaBlend() unavailable of failed: use our own (probably much slower)
2593     // implementation
2594     #ifdef wxHAVE_RAW_BITMAP
2595     wxAlphaBlend(hdcDst, x, y, width, height, srcX, srcY, bmp);
2596    
2597     return true;
2598     #else // !wxHAVE_RAW_BITMAP
2599     // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2600     // alpha but at least something will be shown like this)
2601     wxUnusedVar(bmp);
2602     return false;
2603     #endif // wxHAVE_RAW_BITMAP
2604     }
2605    
2606    
2607     // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2608     #ifdef wxHAVE_RAW_BITMAP
2609    
2610     static void
2611     wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
2612     int w, int h,
2613     int srcX, int srcY, const wxBitmap& bmpSrc)
2614     {
2615     // get the destination DC pixels
2616     wxBitmap bmpDst(w, h, 32 /* force creating RGBA DIB */);
2617     MemoryHDC hdcMem;
2618     SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
2619    
2620     if ( !::BitBlt(hdcMem, 0, 0, w, h, hdcDst, xDst, yDst, SRCCOPY) )
2621     {
2622     wxLogLastError(_T("BitBlt"));
2623     }
2624    
2625     // combine them with the source bitmap using alpha
2626     wxAlphaPixelData dataDst(bmpDst),
2627     dataSrc((wxBitmap &)bmpSrc);
2628    
2629     wxCHECK_RET( dataDst && dataSrc,
2630     _T("failed to get raw data in wxAlphaBlend") );
2631    
2632     wxAlphaPixelData::Iterator pDst(dataDst),
2633     pSrc(dataSrc);
2634    
2635     pSrc.Offset(dataSrc, srcX, srcY);
2636    
2637     for ( int y = 0; y < h; y++ )
2638     {
2639     wxAlphaPixelData::Iterator pDstRowStart = pDst,
2640     pSrcRowStart = pSrc;
2641    
2642     for ( int x = 0; x < w; x++ )
2643     {
2644     // note that source bitmap uses premultiplied alpha (as required by
2645     // the real AlphaBlend)
2646     const unsigned beta = 255 - pSrc.Alpha();
2647    
2648     pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255;
2649     pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255;
2650     pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255;
2651    
2652     ++pDst;
2653     ++pSrc;
2654     }
2655    
2656     pDst = pDstRowStart;
2657     pSrc = pSrcRowStart;
2658     pDst.OffsetY(dataDst, 1);
2659     pSrc.OffsetY(dataSrc, 1);
2660     }
2661    
2662     // and finally blit them back to the destination DC
2663     if ( !::BitBlt(hdcDst, xDst, yDst, w, h, hdcMem, 0, 0, SRCCOPY) )
2664     {
2665     wxLogLastError(_T("BitBlt"));
2666     }
2667     }
2668    
2669     #endif // #ifdef wxHAVE_RAW_BITMAP
2670    
2671     void wxDC::DoGradientFillLinear (const wxRect& rect,
2672     const wxColour& initialColour,
2673     const wxColour& destColour,
2674     wxDirection nDirection)
2675     {
2676     // use native function if we have compile-time support it and can load it
2677     // during run-time (linking to it statically would make the program
2678     // unusable on earlier Windows versions)
2679     #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2680     typedef BOOL
2681     (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
2682     static GradientFill_t pfnGradientFill =
2683     (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill"));
2684    
2685     if ( pfnGradientFill )
2686     {
2687     GRADIENT_RECT grect;
2688     grect.UpperLeft = 0;
2689     grect.LowerRight = 1;
2690    
2691     // invert colours direction if not filling from left-to-right or
2692     // top-to-bottom
2693     int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
2694    
2695     // one vertex for upper left and one for upper-right
2696     TRIVERTEX vertices[2];
2697    
2698     vertices[0].x = rect.GetLeft();
2699     vertices[0].y = rect.GetTop();
2700     vertices[1].x = rect.GetRight()+1;
2701     vertices[1].y = rect.GetBottom()+1;
2702    
2703     vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8);
2704     vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8);
2705     vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8);
2706     vertices[firstVertex].Alpha = 0;
2707     vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8);
2708     vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8);
2709     vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
2710     vertices[1 - firstVertex].