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