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