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