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