]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
Add support for IEC and SI size units to wxFileName::GetHumanReadableSize().
[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 1774
1e2081a1
VZ
1775 if (x)
1776 *x = sizeRect.cx;
1777 if (y)
1778 *y = sizeRect.cy;
247afab5
VZ
1779
1780 if ( descent || externalLeading )
1781 {
1782 TEXTMETRIC tm;
1783 ::GetTextMetrics(GetHdc(), &tm);
1784
1785 if (descent)
1786 *descent = tm.tmDescent;
1787 if (externalLeading)
1788 *externalLeading = tm.tmExternalLeading;
1789 }
8bf30fe9
VZ
1790
1791 if ( hfontOld )
1792 {
1793 ::SelectObject(GetHdc(), hfontOld);
1794 }
2bda0e17
KB
1795}
1796
553aa032
RD
1797
1798// Each element of the array will be the width of the string up to and
5c2ddebe 1799// including the coresoponding character in text.
553aa032 1800
888dde65 1801bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
553aa032
RD
1802{
1803 static int maxLenText = -1;
1804 static int maxWidth = -1;
1805 int fit = 0;
1806 SIZE sz = {0,0};
41e155b4 1807 int stlen = text.length();
553aa032
RD
1808
1809 if (maxLenText == -1)
1810 {
1811 // Win9x and WinNT+ have different limits
1812 int version = wxGetOsVersion();
406d283a
PC
1813 maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
1814 maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
553aa032 1815 }
5c2ddebe 1816
553aa032
RD
1817 widths.Empty();
1818 widths.Add(0, stlen); // fill the array with zeros
f9daf953
JS
1819 if (stlen == 0)
1820 return true;
5c2ddebe 1821
553aa032
RD
1822 if (!::GetTextExtentExPoint(GetHdc(),
1823 text.c_str(), // string to check
1824 wxMin(stlen, maxLenText),
5c2ddebe
VZ
1825 maxWidth,
1826 &fit, // [out] count of chars
553aa032 1827 // that will fit
5c2ddebe
VZ
1828 &widths[0], // array to fill
1829 &sz))
1830 {
553aa032
RD
1831 // API failed
1832 wxLogLastError(wxT("GetTextExtentExPoint"));
5c2ddebe
VZ
1833 return false;
1834 }
1835
553aa032
RD
1836 return true;
1837}
1838
888dde65 1839void wxMSWDCImpl::RealizeScaleAndOrigin()
04ab8b6d 1840{
9effb77d
VZ
1841 // although it may seem wasteful to always use MM_ANISOTROPIC here instead
1842 // of using MM_TEXT if there is no scaling, benchmarking doesn't detect any
1843 // noticeable difference between these mapping modes
04ab8b6d
RR
1844#ifndef __WXWINCE__
1845 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
553aa032 1846
04ab8b6d
RR
1847 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
1848 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
553aa032 1849
04ab8b6d
RR
1850 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1851 ::SetWindowExtEx(GetHdc(), width, height, NULL);
1852
1853 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
1854 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);
1855#endif
04ab8b6d 1856}
553aa032 1857
89efaf2b 1858void wxMSWDCImpl::SetMapMode(wxMappingMode mode)
2bda0e17 1859{
82a306b7 1860 WXMICROWIN_CHECK_HDC
d275c7eb 1861
7bcb11d3 1862 m_mappingMode = mode;
a23fd0e1 1863
1e2081a1 1864 if ( mode == wxMM_TEXT )
2bda0e17 1865 {
1e2081a1
VZ
1866 m_logicalScaleX =
1867 m_logicalScaleY = 1.0;
2bda0e17 1868 }
1e2081a1 1869 else // need to do some calculations
2bda0e17 1870 {
1e2081a1
VZ
1871 int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES),
1872 pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES),
1873 mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE),
1874 mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1875
1876 if ( (mm_width == 0) || (mm_height == 0) )
7bcb11d3 1877 {
1e2081a1
VZ
1878 // we can't calculate mm2pixels[XY] then!
1879 return;
7bcb11d3 1880 }
1e2081a1 1881
82922a02
VZ
1882 double mm2pixelsX = (double)pixel_width / mm_width,
1883 mm2pixelsY = (double)pixel_height / mm_height;
1e2081a1
VZ
1884
1885 switch (mode)
7bcb11d3 1886 {
1e2081a1
VZ
1887 case wxMM_TWIPS:
1888 m_logicalScaleX = twips2mm * mm2pixelsX;
1889 m_logicalScaleY = twips2mm * mm2pixelsY;
1890 break;
1891
1892 case wxMM_POINTS:
1893 m_logicalScaleX = pt2mm * mm2pixelsX;
1894 m_logicalScaleY = pt2mm * mm2pixelsY;
1895 break;
1896
1897 case wxMM_METRIC:
1898 m_logicalScaleX = mm2pixelsX;
1899 m_logicalScaleY = mm2pixelsY;
1900 break;
1901
1902 case wxMM_LOMETRIC:
1903 m_logicalScaleX = mm2pixelsX / 10.0;
1904 m_logicalScaleY = mm2pixelsY / 10.0;
1905 break;
1906
1907 default:
9a83f860 1908 wxFAIL_MSG( wxT("unknown mapping mode in SetMapMode") );
7bcb11d3 1909 }
2bda0e17 1910 }
1ee280b7 1911
04ab8b6d 1912 ComputeScaleAndOrigin();
1ee280b7 1913
04ab8b6d 1914 RealizeScaleAndOrigin();
2bda0e17
KB
1915}
1916
888dde65 1917void wxMSWDCImpl::SetUserScale(double x, double y)
2bda0e17 1918{
82a306b7 1919 WXMICROWIN_CHECK_HDC
d275c7eb 1920
1e2081a1
VZ
1921 if ( x == m_userScaleX && y == m_userScaleY )
1922 return;
1923
888dde65 1924 wxDCImpl::SetUserScale(x,y);
1ee280b7 1925
04ab8b6d 1926 RealizeScaleAndOrigin();
2bda0e17
KB
1927}
1928
888dde65 1929void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight,
04ab8b6d 1930 bool yBottomUp)
6f65e337 1931{
82a306b7 1932 WXMICROWIN_CHECK_HDC
d275c7eb 1933
1e2081a1
VZ
1934 int signX = xLeftRight ? 1 : -1,
1935 signY = yBottomUp ? -1 : 1;
1ee280b7 1936
04ab8b6d 1937 if (signX == m_signX && signY == m_signY)
1e2081a1 1938 return;
1ee280b7 1939
888dde65 1940 wxDCImpl::SetAxisOrientation( xLeftRight, yBottomUp );
1e2081a1 1941
04ab8b6d 1942 RealizeScaleAndOrigin();
2bda0e17
KB
1943}
1944
888dde65 1945void wxMSWDCImpl::SetLogicalOrigin(wxCoord x, wxCoord y)
2bda0e17 1946{
82a306b7 1947 WXMICROWIN_CHECK_HDC
d275c7eb 1948
1e2081a1
VZ
1949 if ( x == m_logicalOriginX && y == m_logicalOriginY )
1950 return;
1951
888dde65 1952 wxDCImpl::SetLogicalOrigin( x, y );
a23fd0e1 1953
d225267e
RR
1954 RealizeScaleAndOrigin();
1955}
1956
1957// For use by wxWidgets only, unless custom units are required.
1958void wxMSWDCImpl::SetLogicalScale(double x, double y)
1959{
1960 WXMICROWIN_CHECK_HDC
1961
1962 wxDCImpl::SetLogicalScale(x,y);
2bda0e17
KB
1963}
1964
888dde65 1965void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y)
2bda0e17 1966{
82a306b7 1967 WXMICROWIN_CHECK_HDC
d275c7eb 1968
1e2081a1
VZ
1969 if ( x == m_deviceOriginX && y == m_deviceOriginY )
1970 return;
1ee280b7 1971
888dde65 1972 wxDCImpl::SetDeviceOrigin( x, y );
2bda0e17 1973
a23fd0e1 1974 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
2bda0e17
KB
1975}
1976
a23fd0e1
VZ
1977// ---------------------------------------------------------------------------
1978// bit blit
1979// ---------------------------------------------------------------------------
04ab8b6d 1980
888dde65 1981bool wxMSWDCImpl::DoBlit(wxCoord dstX, wxCoord dstY,
e3b81044
VZ
1982 wxCoord dstWidth, wxCoord dstHeight,
1983 wxDC *source,
1984 wxCoord srcX, wxCoord srcY,
89efaf2b 1985 wxRasterOperationMode rop, bool useMask,
e3b81044
VZ
1986 wxCoord srcMaskX, wxCoord srcMaskY)
1987{
1988 return DoStretchBlit(dstX, dstY, dstWidth, dstHeight, source, srcX, srcY, dstWidth, dstHeight, rop, useMask, srcMaskX, srcMaskY);
1989}
1990
888dde65 1991bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
e3b81044
VZ
1992 wxCoord dstWidth, wxCoord dstHeight,
1993 wxDC *source,
1994 wxCoord xsrc, wxCoord ysrc,
1995 wxCoord srcWidth, wxCoord srcHeight,
89efaf2b 1996 wxRasterOperationMode rop, bool useMask,
e3b81044 1997 wxCoord xsrcMask, wxCoord ysrcMask)
2bda0e17 1998{
9a83f860 1999 wxCHECK_MSG( source, false, wxT("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
275a63e3 2000
beb966c5 2001 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 2002
a619d8c9
VZ
2003 wxMSWDCImpl *implSrc = wxDynamicCast( source->GetImpl(), wxMSWDCImpl );
2004 if ( !implSrc )
888dde65 2005 {
a619d8c9 2006 // TODO: Do we want to be able to blit from other DCs too?
888dde65
RR
2007 return false;
2008 }
2009
a619d8c9
VZ
2010 const HDC hdcSrc = GetHdcOf(*implSrc);
2011
57c26f82
VZ
2012 // if either the source or destination has alpha channel, we must use
2013 // AlphaBlt() as other function don't handle it correctly
a619d8c9 2014 const wxBitmap& bmpSrc = implSrc->GetSelectedBitmap();
87d3576f
RR
2015 if ( bmpSrc.IsOk() && (bmpSrc.HasAlpha() ||
2016 (m_selectedBitmap.IsOk() && m_selectedBitmap.HasAlpha())) )
275a63e3 2017 {
e3b81044 2018 if ( AlphaBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight,
a619d8c9 2019 xsrc, ysrc, srcWidth, srcHeight, hdcSrc, bmpSrc) )
beb966c5 2020 return true;
275a63e3 2021 }
d80f416f 2022
4b7f2165
VZ
2023 wxMask *mask = NULL;
2024 if ( useMask )
2025 {
d80f416f 2026 mask = bmpSrc.GetMask();
4b7f2165 2027
87d3576f 2028 if ( !(bmpSrc.IsOk() && mask && mask->GetMaskBitmap()) )
d5536ade
VZ
2029 {
2030 // don't give assert here because this would break existing
2031 // programs - just silently ignore useMask parameter
beb966c5 2032 useMask = false;
d5536ade 2033 }
4b7f2165 2034 }
a23fd0e1 2035
0cbff120
JS
2036 if (xsrcMask == -1 && ysrcMask == -1)
2037 {
2038 xsrcMask = xsrc; ysrcMask = ysrc;
2039 }
2040
76f91e77 2041 wxTextColoursChanger textCol(GetHdc(), *this);
a23fd0e1 2042
999836aa 2043 DWORD dwRop;
71fe5c01
RR
2044 switch (rop)
2045 {
ed791986
VZ
2046 case wxXOR: dwRop = SRCINVERT; break;
2047 case wxINVERT: dwRop = DSTINVERT; break;
2048 case wxOR_REVERSE: dwRop = 0x00DD0228; break;
2049 case wxAND_REVERSE: dwRop = SRCERASE; break;
2050 case wxCLEAR: dwRop = BLACKNESS; break;
2051 case wxSET: dwRop = WHITENESS; break;
2052 case wxOR_INVERT: dwRop = MERGEPAINT; break;
2053 case wxAND: dwRop = SRCAND; break;
2054 case wxOR: dwRop = SRCPAINT; break;
2055 case wxEQUIV: dwRop = 0x00990066; break;
2056 case wxNAND: dwRop = 0x007700E6; break;
2057 case wxAND_INVERT: dwRop = 0x00220326; break;
2058 case wxCOPY: dwRop = SRCCOPY; break;
4aff28fc 2059 case wxNO_OP: dwRop = DSTCOPY; break;
ed791986 2060 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
71fe5c01
RR
2061 case wxNOR: dwRop = NOTSRCCOPY; break;
2062 default:
71fe5c01 2063 wxFAIL_MSG( wxT("unsupported logical function") );
beb966c5 2064 return false;
71fe5c01
RR
2065 }
2066
beb966c5 2067 bool success = false;
730bc726
JS
2068
2069 if (useMask)
7bcb11d3 2070 {
4b7f2165 2071#ifdef __WIN32__
a58a12e9 2072 // we want the part of the image corresponding to the mask to be
4aff28fc
VZ
2073 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2074 // meaning of fg and bg is inverted which corresponds to wxWin notion
2075 // of the mask which is also contrary to the Windows one)
d3211838
JS
2076
2077 // On some systems, MaskBlt succeeds yet is much much slower
77ffb593 2078 // than the wxWidgets fall-back implementation. So we need
d3211838 2079 // to be able to switch this on and off at runtime.
0cbff120
JS
2080#if wxUSE_SYSTEM_OPTIONS
2081 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2082#endif
d3211838 2083 {
e3b81044
VZ
2084 if ( dstWidth == srcWidth && dstHeight == srcHeight )
2085 {
2086 success = ::MaskBlt
2087 (
f178ab7e 2088 GetHdc(),
e3b81044 2089 xdest, ydest, dstWidth, dstHeight,
a619d8c9 2090 hdcSrc,
f178ab7e
VZ
2091 xsrc, ysrc,
2092 (HBITMAP)mask->GetMaskBitmap(),
2093 xsrcMask, ysrcMask,
2094 MAKEROP4(dwRop, DSTCOPY)
e3b81044
VZ
2095 ) != 0;
2096 }
d3211838 2097 }
a58a12e9
VZ
2098
2099 if ( !success )
4b7f2165 2100#endif // Win32
7bcb11d3 2101 {
7bcb11d3 2102 // Blit bitmap with mask
0cbff120
JS
2103 HDC dc_mask ;
2104 HDC dc_buffer ;
2105 HBITMAP buffer_bmap ;
a23fd0e1 2106
0cbff120 2107#if wxUSE_DC_CACHEING
2b96d0fb 2108 // create a temp buffer bitmap and DCs to access it and the mask
a619d8c9 2109 wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, hdcSrc);
2b96d0fb
VZ
2110 dc_mask = (HDC) dcCacheEntry1->m_dc;
2111
2112 wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
2113 dc_buffer = (HDC) dcCacheEntry2->m_dc;
2114
2115 wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
e3b81044 2116 dstWidth, dstHeight);
2b96d0fb
VZ
2117
2118 buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
2119#else // !wxUSE_DC_CACHEING
2120 // create a temp buffer bitmap and DCs to access it and the mask
a619d8c9 2121 dc_mask = ::CreateCompatibleDC(hdcSrc);
2b96d0fb 2122 dc_buffer = ::CreateCompatibleDC(GetHdc());
e3b81044 2123 buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), dstWidth, dstHeight);
619e52bf 2124#endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
a230101e
VZ
2125 HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
2126 HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
4b7f2165
VZ
2127
2128 // copy dest to buffer
76f91e77 2129 if ( !::BitBlt(dc_buffer, 0, 0, dstWidth, dstHeight,
4b7f2165 2130 GetHdc(), xdest, ydest, SRCCOPY) )
7bcb11d3 2131 {
f6bcfd97 2132 wxLogLastError(wxT("BitBlt"));
7bcb11d3 2133 }
4b7f2165 2134
4f64fde7 2135 SET_STRETCH_BLT_MODE(GetHdc());
e3b81044 2136
4b7f2165 2137 // copy src to buffer using selected raster op
76f91e77 2138 if ( !::StretchBlt(dc_buffer, 0, 0, dstWidth, dstHeight,
a619d8c9 2139 hdcSrc, xsrc, ysrc, srcWidth, srcHeight, dwRop) )
7bcb11d3 2140 {
e3b81044 2141 wxLogLastError(wxT("StretchBlt"));
7bcb11d3 2142 }
4b7f2165 2143
76f91e77 2144 // set masked area in buffer to BLACK
4b7f2165 2145 {
76f91e77
VZ
2146 wxTextColoursChanger textCol2(GetHdc(), *wxBLACK, *wxWHITE);
2147 if ( !::StretchBlt(dc_buffer, 0, 0, dstWidth, dstHeight,
2148 dc_mask, xsrcMask, ysrcMask,
2149 srcWidth, srcHeight, SRCAND) )
2150 {
2151 wxLogLastError(wxT("StretchBlt"));
2152 }
4b7f2165 2153
76f91e77
VZ
2154 // set unmasked area in dest to BLACK
2155 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2156 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2157 if ( !::StretchBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight,
2158 dc_mask, xsrcMask, ysrcMask,
2159 srcWidth, srcHeight, SRCAND) )
2160 {
2161 wxLogLastError(wxT("StretchBlt"));
2162 }
2163 } // restore the original text and background colours
4b7f2165
VZ
2164
2165 // OR buffer to dest
76f91e77 2166 success = ::BitBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight,
4b7f2165
VZ
2167 dc_buffer, 0, 0, SRCPAINT) != 0;
2168 if ( !success )
2169 {
f6bcfd97 2170 wxLogLastError(wxT("BitBlt"));
4b7f2165
VZ
2171 }
2172
2173 // tidy up temporary DCs and bitmap
62e1ba75
JS
2174 ::SelectObject(dc_mask, hOldMaskBitmap);
2175 ::SelectObject(dc_buffer, hOldBufferBitmap);
0cbff120 2176
27748047 2177#if !wxUSE_DC_CACHEING
0cbff120
JS
2178 {
2179 ::DeleteDC(dc_mask);
2180 ::DeleteDC(dc_buffer);
2181 ::DeleteObject(buffer_bmap);
2182 }
27748047 2183#endif
7bcb11d3
JS
2184 }
2185 }
4b7f2165 2186 else // no mask, just BitBlt() it
730bc726 2187 {
d80f416f
VZ
2188 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2189 // use StretchBlt() if available and finally fall back to BitBlt()
4676948b
JS
2190
2191 // FIXME: use appropriate WinCE functions
2192#ifndef __WXWINCE__
d80f416f 2193 const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS);
87d3576f 2194 if ( bmpSrc.IsOk() && (caps & RC_STRETCHDIB) )
f178ab7e 2195 {
d80f416f
VZ
2196 DIBSECTION ds;
2197 wxZeroMemory(ds);
f178ab7e 2198
d80f416f
VZ
2199 if ( ::GetObject(GetHbitmapOf(bmpSrc),
2200 sizeof(ds),
2201 &ds) == sizeof(ds) )
2202 {
4f64fde7 2203 SET_STRETCH_BLT_MODE(GetHdc());
d80f416f 2204
b9b1f368
VZ
2205 // Figure out what co-ordinate system we're supposed to specify
2206 // ysrc in.
2207 const LONG hDIB = ds.dsBmih.biHeight;
2208 if ( hDIB > 0 )
2209 {
2210 // reflect ysrc
4b871421 2211 ysrc = hDIB - (ysrc + srcHeight);
b9b1f368
VZ
2212 }
2213
d80f416f
VZ
2214 if ( ::StretchDIBits(GetHdc(),
2215 xdest, ydest,
e3b81044 2216 dstWidth, dstHeight,
b9b1f368 2217 xsrc, ysrc,
e3b81044 2218 srcWidth, srcHeight,
d80f416f
VZ
2219 ds.dsBm.bmBits,
2220 (LPBITMAPINFO)&ds.dsBmih,
2221 DIB_RGB_COLORS,
b7a0abc7 2222 dwRop
d80f416f
VZ
2223 ) == (int)GDI_ERROR )
2224 {
85e7fb12
RD
2225 // On Win9x this API fails most (all?) of the time, so
2226 // logging it becomes quite distracting. Since it falls
2227 // back to the code below this is not really serious, so
35bbb0c6 2228 // don't log it.
85e7fb12 2229 //wxLogLastError(wxT("StretchDIBits"));
d80f416f
VZ
2230 }
2231 else
2232 {
beb966c5 2233 success = true;
d80f416f
VZ
2234 }
2235 }
f178ab7e 2236 }
d80f416f
VZ
2237
2238 if ( !success && (caps & RC_STRETCHBLT) )
419430a0
JS
2239#endif
2240 // __WXWINCE__
f178ab7e 2241 {
4f64fde7 2242 SET_STRETCH_BLT_MODE(GetHdc());
d80f416f
VZ
2243
2244 if ( !::StretchBlt
2245 (
2246 GetHdc(),
e3b81044 2247 xdest, ydest, dstWidth, dstHeight,
a619d8c9 2248 hdcSrc,
e3b81044 2249 xsrc, ysrc, srcWidth, srcHeight,
d80f416f
VZ
2250 dwRop
2251 ) )
2252 {
9a83f860 2253 wxLogLastError(wxT("StretchBlt"));
d80f416f
VZ
2254 }
2255 else
2256 {
beb966c5 2257 success = true;
d80f416f 2258 }
f178ab7e
VZ
2259 }
2260
4b7f2165 2261 if ( !success )
730bc726 2262 {
76f91e77
VZ
2263 if ( !::BitBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight,
2264 hdcSrc, xsrc, ysrc, dwRop) )
d80f416f 2265 {
9a83f860 2266 wxLogLastError(wxT("BitBlt"));
d80f416f
VZ
2267 }
2268 else
2269 {
beb966c5 2270 success = true;
d80f416f 2271 }
730bc726 2272 }
730bc726 2273 }
f178ab7e 2274
a23fd0e1 2275 return success;
2bda0e17
KB
2276}
2277
888dde65 2278void wxMSWDCImpl::GetDeviceSize(int *width, int *height) const
2bda0e17 2279{
82a306b7 2280 WXMICROWIN_CHECK_HDC
d275c7eb 2281
7d09b97f
VZ
2282 if ( width )
2283 *width = ::GetDeviceCaps(GetHdc(), HORZRES);
2284 if ( height )
2285 *height = ::GetDeviceCaps(GetHdc(), VERTRES);
2bda0e17
KB
2286}
2287
888dde65 2288void wxMSWDCImpl::DoGetSizeMM(int *w, int *h) const
2bda0e17 2289{
82a306b7 2290 WXMICROWIN_CHECK_HDC
d275c7eb 2291
994a3786
VZ
2292 // if we implement it in terms of DoGetSize() instead of directly using the
2293 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2294 // will also work for wxWindowDC and wxClientDC even though their size is
2295 // not the same as the total size of the screen
2296 int wPixels, hPixels;
2297 DoGetSize(&wPixels, &hPixels);
2298
2299 if ( w )
2300 {
2301 int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES);
2302
9a83f860 2303 wxCHECK_RET( wTotal, wxT("0 width device?") );
994a3786
VZ
2304
2305 *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal;
2306 }
2307
2308 if ( h )
2309 {
2310 int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES);
2311
9a83f860 2312 wxCHECK_RET( hTotal, wxT("0 height device?") );
994a3786
VZ
2313
2314 *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal;
2315 }
7bcb11d3 2316}
2bda0e17 2317
888dde65 2318wxSize wxMSWDCImpl::GetPPI() const
7bcb11d3 2319{
c47addef 2320 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
d275c7eb 2321
a23fd0e1
VZ
2322 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
2323 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
2bda0e17 2324
a23fd0e1 2325 return wxSize(x, y);
2bda0e17
KB
2326}
2327
878711c0
VZ
2328// ----------------------------------------------------------------------------
2329// DC caching
2330// ----------------------------------------------------------------------------
2331
0cbff120
JS
2332#if wxUSE_DC_CACHEING
2333
2334/*
2335 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2336 * improve it in due course, either using arrays, or simply storing pointers to one
2337 * entry for the bitmap, and two for the DCs. -- JACS
2338 */
2339
888dde65
RR
2340wxObjectList wxMSWDCImpl::sm_bitmapCache;
2341wxObjectList wxMSWDCImpl::sm_dcCache;
0cbff120
JS
2342
2343wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth)
2344{
2345 m_bitmap = hBitmap;
2346 m_dc = 0;
2347 m_width = w;
2348 m_height = h;
2349 m_depth = depth;
2350}
2351
2352wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
2353{
2354 m_bitmap = 0;
2355 m_dc = hDC;
2356 m_width = 0;
2357 m_height = 0;
2358 m_depth = depth;
2359}
2360
2361wxDCCacheEntry::~wxDCCacheEntry()
2362{
2363 if (m_bitmap)
2364 ::DeleteObject((HBITMAP) m_bitmap);
2365 if (m_dc)
2366 ::DeleteDC((HDC) m_dc);
2367}
2368
888dde65 2369wxDCCacheEntry* wxMSWDCImpl::FindBitmapInCache(WXHDC dc, int w, int h)
0cbff120
JS
2370{
2371 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
fc10daf3 2372 wxList::compatibility_iterator node = sm_bitmapCache.GetFirst();
0cbff120
JS
2373 while (node)
2374 {
4a9dba0e 2375 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
0cbff120
JS
2376
2377 if (entry->m_depth == depth)
2378 {
2379 if (entry->m_width < w || entry->m_height < h)
2380 {
2381 ::DeleteObject((HBITMAP) entry->m_bitmap);
2382 entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2383 if ( !entry->m_bitmap)
2384 {
2385 wxLogLastError(wxT("CreateCompatibleBitmap"));
2386 }
2387 entry->m_width = w; entry->m_height = h;
2388 return entry;
2389 }
2390 return entry;
2391 }
2392
4a9dba0e 2393 node = node->GetNext();
0cbff120
JS
2394 }
2395 WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2396 if ( !hBitmap)
2397 {
2398 wxLogLastError(wxT("CreateCompatibleBitmap"));
2399 }
2400 wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
2401 AddToBitmapCache(entry);
2402 return entry;
2403}
2404
888dde65 2405wxDCCacheEntry* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
0cbff120
JS
2406{
2407 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
fc10daf3 2408 wxList::compatibility_iterator node = sm_dcCache.GetFirst();
0cbff120
JS
2409 while (node)
2410 {
4a9dba0e 2411 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
0cbff120
JS
2412
2413 // Don't return the same one as we already have
2414 if (!notThis || (notThis != entry))
2415 {
2416 if (entry->m_depth == depth)
2417 {
2418 return entry;
2419 }
2420 }
2421
4a9dba0e 2422 node = node->GetNext();
0cbff120
JS
2423 }
2424 WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
2425 if ( !hDC)
2426 {
2427 wxLogLastError(wxT("CreateCompatibleDC"));
2428 }
2429 wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
2430 AddToDCCache(entry);
2431 return entry;
2432}
2433
888dde65 2434void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry* entry)
0cbff120
JS
2435{
2436 sm_bitmapCache.Append(entry);
2437}
2438
888dde65 2439void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry* entry)
0cbff120
JS
2440{
2441 sm_dcCache.Append(entry);
2442}
2443
888dde65 2444void wxMSWDCImpl::ClearCache()
0cbff120 2445{
fc10daf3
MB
2446 WX_CLEAR_LIST(wxList, sm_dcCache);
2447 WX_CLEAR_LIST(wxList, sm_bitmapCache);
0cbff120
JS
2448}
2449
aef94d68
JS
2450// Clean up cache at app exit
2451class wxDCModule : public wxModule
2452{
2453public:
beb966c5 2454 virtual bool OnInit() { return true; }
888dde65 2455 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
aef94d68
JS
2456
2457private:
2458 DECLARE_DYNAMIC_CLASS(wxDCModule)
2459};
2460
2461IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2462
878711c0
VZ
2463#endif // wxUSE_DC_CACHEING
2464
2465// ----------------------------------------------------------------------------
275a63e3 2466// alpha channel support
878711c0
VZ
2467// ----------------------------------------------------------------------------
2468
275a63e3 2469static bool AlphaBlt(HDC hdcDst,
e3b81044 2470 int x, int y, int dstWidth, int dstHeight,
1ee280b7 2471 int srcX, int srcY,
e3b81044
VZ
2472 int srcWidth, int srcHeight,
2473 HDC hdcSrc,
275a63e3
VZ
2474 const wxBitmap& bmp)
2475{
9a83f860
VZ
2476 wxASSERT_MSG( bmp.IsOk() && bmp.HasAlpha(), wxT("AlphaBlt(): invalid bitmap") );
2477 wxASSERT_MSG( hdcDst && hdcSrc, wxT("AlphaBlt(): invalid HDC") );
275a63e3
VZ
2478
2479 // do we have AlphaBlend() and company in the headers?
3080bf59 2480#if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
275a63e3
VZ
2481 // yes, now try to see if we have it during run-time
2482 typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
2483 HDC,int,int,int,int,
2484 BLENDFUNCTION);
2485
6ae7410f 2486 static AlphaBlend_t
9a83f860 2487 pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(wxT("AlphaBlend"));
275a63e3
VZ
2488 if ( pfnAlphaBlend )
2489 {
2490 BLENDFUNCTION bf;
2491 bf.BlendOp = AC_SRC_OVER;
2492 bf.BlendFlags = 0;
2493 bf.SourceConstantAlpha = 0xff;
2494 bf.AlphaFormat = AC_SRC_ALPHA;
2495
e3b81044
VZ
2496 if ( pfnAlphaBlend(hdcDst, x, y, dstWidth, dstHeight,
2497 hdcSrc, srcX, srcY, srcWidth, srcHeight,
275a63e3
VZ
2498 bf) )
2499 {
2500 // skip wxAlphaBlend() call below
beb966c5 2501 return true;
275a63e3
VZ
2502 }
2503
9a83f860 2504 wxLogLastError(wxT("AlphaBlend"));
275a63e3 2505 }
41e155b4
WS
2506#else
2507 wxUnusedVar(hdcSrc);
275a63e3
VZ
2508#endif // defined(AC_SRC_OVER)
2509
2510 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2511 // implementation
3fb1e059 2512#ifdef wxHAS_RAW_BITMAP
e3b81044 2513 wxAlphaBlend(hdcDst, x, y, dstWidth, dstHeight, srcX, srcY, srcWidth, srcHeight, bmp);
275a63e3 2514
beb966c5 2515 return true;
3fb1e059 2516#else // !wxHAS_RAW_BITMAP
275a63e3
VZ
2517 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2518 // alpha but at least something will be shown like this)
907173e5 2519 wxUnusedVar(bmp);
beb966c5 2520 return false;
3fb1e059 2521#endif // wxHAS_RAW_BITMAP/!wxHAS_RAW_BITMAP
275a63e3
VZ
2522}
2523
2524
2525// wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
3fb1e059 2526#ifdef wxHAS_RAW_BITMAP
275a63e3 2527
878711c0 2528static void
761598d4 2529wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
e3b81044 2530 int dstWidth, int dstHeight,
1ee280b7 2531 int srcX, int srcY,
e3b81044
VZ
2532 int srcWidth, int srcHeight,
2533 const wxBitmap& bmpSrc)
878711c0
VZ
2534{
2535 // get the destination DC pixels
e3b81044 2536 wxBitmap bmpDst(dstWidth, dstHeight, 32 /* force creating RGBA DIB */);
878711c0
VZ
2537 MemoryHDC hdcMem;
2538 SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
2539
e3b81044 2540 if ( !::BitBlt(hdcMem, 0, 0, dstWidth, dstHeight, hdcDst, xDst, yDst, SRCCOPY) )
878711c0 2541 {
9a83f860 2542 wxLogLastError(wxT("BitBlt"));
878711c0
VZ
2543 }
2544
2545 // combine them with the source bitmap using alpha
b9bcaf11 2546 wxAlphaPixelData dataDst(bmpDst),
a452af5e 2547 dataSrc((wxBitmap &)bmpSrc);
878711c0 2548
8ffc8f1f 2549 wxCHECK_RET( dataDst && dataSrc,
9a83f860 2550 wxT("failed to get raw data in wxAlphaBlend") );
8ffc8f1f 2551
b9bcaf11
VZ
2552 wxAlphaPixelData::Iterator pDst(dataDst),
2553 pSrc(dataSrc);
878711c0 2554
3db79902 2555
e3b81044 2556 for ( int y = 0; y < dstHeight; y++ )
878711c0 2557 {
e3b81044 2558 wxAlphaPixelData::Iterator pDstRowStart = pDst;
0c0d1521 2559
e3b81044 2560 for ( int x = 0; x < dstWidth; x++ )
878711c0 2561 {
e3b81044
VZ
2562 // source is point sampled, Alpha StretchBlit is ugly on Win95
2563 // (but does not impact performance)
2564 pSrc.MoveTo(dataSrc, srcX + (srcWidth*x/dstWidth), srcY + (srcHeight*y/dstHeight));
2565
878711c0
VZ
2566 // note that source bitmap uses premultiplied alpha (as required by
2567 // the real AlphaBlend)
2568 const unsigned beta = 255 - pSrc.Alpha();
2569
2570 pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255;
2571 pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255;
2572 pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255;
2573
2574 ++pDst;
878711c0
VZ
2575 }
2576
2577 pDst = pDstRowStart;
b9bcaf11 2578 pDst.OffsetY(dataDst, 1);
878711c0
VZ
2579 }
2580
2581 // and finally blit them back to the destination DC
e3b81044 2582 if ( !::BitBlt(hdcDst, xDst, yDst, dstWidth, dstHeight, hdcMem, 0, 0, SRCCOPY) )
878711c0 2583 {
9a83f860 2584 wxLogLastError(wxT("BitBlt"));
878711c0
VZ
2585 }
2586}
7b46ecac 2587
3fb1e059 2588#endif // wxHAS_RAW_BITMAP
213ad8e7 2589
888dde65 2590void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
213ad8e7
VZ
2591 const wxColour& initialColour,
2592 const wxColour& destColour,
2593 wxDirection nDirection)
2594{
2595 // use native function if we have compile-time support it and can load it
2596 // during run-time (linking to it statically would make the program
2597 // unusable on earlier Windows versions)
2598#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2599 typedef BOOL
2600 (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
6ae7410f 2601 static GradientFill_t pfnGradientFill =
9a83f860 2602 (GradientFill_t)wxMSIMG32DLL.GetSymbol(wxT("GradientFill"));
213ad8e7
VZ
2603
2604 if ( pfnGradientFill )
2605 {
2606 GRADIENT_RECT grect;
2607 grect.UpperLeft = 0;
2608 grect.LowerRight = 1;
2609
2610 // invert colours direction if not filling from left-to-right or
2611 // top-to-bottom
2612 int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
2613
2614 // one vertex for upper left and one for upper-right
2615 TRIVERTEX vertices[2];
2616
2617 vertices[0].x = rect.GetLeft();
2618 vertices[0].y = rect.GetTop();
e6c46ffe
BW
2619 vertices[1].x = rect.GetRight()+1;
2620 vertices[1].y = rect.GetBottom()+1;
213ad8e7 2621
2e98a222
WS
2622 vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8);
2623 vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8);
2624 vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8);
213ad8e7 2625 vertices[firstVertex].Alpha = 0;
2e98a222
WS
2626 vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8);
2627 vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8);
2628 vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
213ad8e7
VZ
2629 vertices[1 - firstVertex].Alpha = 0;
2630
213ad8e7
VZ
2631 if ( (*pfnGradientFill)
2632 (
2633 GetHdc(),
2634 vertices,
2635 WXSIZEOF(vertices),
2636 &grect,
2637 1,
2638 nDirection == wxWEST || nDirection == wxEAST
2639 ? GRADIENT_FILL_RECT_H
2640 : GRADIENT_FILL_RECT_V
2641 ) )
2642 {
2643 // skip call of the base class version below
2644 return;
2645 }
2646
9a83f860 2647 wxLogLastError(wxT("GradientFill"));
213ad8e7
VZ
2648 }
2649#endif // wxUSE_DYNLIB_CLASS
2650
888dde65 2651 wxDCImpl::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
213ad8e7 2652}
6ae7410f 2653
a8ff046b
VZ
2654#if wxUSE_DYNLIB_CLASS
2655
6ae7410f
VZ
2656static DWORD wxGetDCLayout(HDC hdc)
2657{
2658 typedef DWORD (WINAPI *GetLayout_t)(HDC);
2659 static GetLayout_t
9a83f860 2660 wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(wxT("gdi32.dll")));
6ae7410f 2661
60b0c3b4 2662 return s_pfnGetLayout ? s_pfnGetLayout(hdc) : (DWORD)-1;
6ae7410f
VZ
2663}
2664
888dde65 2665wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
6ae7410f
VZ
2666{
2667 DWORD layout = wxGetDCLayout(GetHdc());
2668
2669 if ( layout == (DWORD)-1 )
2670 return wxLayout_Default;
2671
2672 return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight;
2673}
2674
888dde65 2675void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
6ae7410f
VZ
2676{
2677 typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
2678 static SetLayout_t
9a83f860 2679 wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(wxT("gdi32.dll")));
60b0c3b4 2680 if ( !s_pfnSetLayout )
6ae7410f
VZ
2681 return;
2682
2683 if ( dir == wxLayout_Default )
2684 {
2685 dir = wxTheApp->GetLayoutDirection();
2686 if ( dir == wxLayout_Default )
2687 return;
2688 }
2689
2690 DWORD layout = wxGetDCLayout(GetHdc());
2691 if ( dir == wxLayout_RightToLeft )
2692 layout |= LAYOUT_RTL;
2693 else
2694 layout &= ~LAYOUT_RTL;
2695
60b0c3b4 2696 s_pfnSetLayout(GetHdc(), layout);
6ae7410f 2697}
a8ff046b
VZ
2698
2699#else // !wxUSE_DYNLIB_CLASS
2700
2701// we can't provide RTL support without dynamic loading, so stub it out
888dde65 2702wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
a8ff046b
VZ
2703{
2704 return wxLayout_Default;
2705}
2706
888dde65 2707void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection WXUNUSED(dir))
a8ff046b
VZ
2708{
2709}
2710
2711#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS