]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dc.cpp
check that the version of __sync_sub_and_fetch that returns a value is supported...
[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
VZ
133 int x, int y, int dstWidth, int dstHeight,
134 int srcX, int srcY,
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,
145 int srcX, int srcY,
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
888dde65
RR
336wxMSWDCImpl::wxMSWDCImpl( wxDC *owner, WXHDC hDC ) :
337 wxDCImpl( owner )
338{
339 Init();
340 m_hDC = hDC;
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
5456b916 947 if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
0bafad0c 948 {
7299b1b2 949 RECT rect;
5456b916
RR
950 rect.left = XLOG2DEV(x);
951 rect.top = YLOG2DEV(y);
952 rect.right = XLOG2DEV(x2);
7299b1b2
RD
953 rect.bottom = YLOG2DEV(y2);
954 (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
5456b916
RR
955 }
956 else
957 {
958 // Windows draws the filled rectangles without outline (i.e. drawn with a
959 // transparent pen) one pixel smaller in both directions and we want them
f6bcfd97 960 // to have the same size regardless of which pen is used - adjust
5456b916 961
fea35690 962 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
5456b916
RR
963 if ( m_pen.GetStyle() == wxTRANSPARENT )
964 {
750d64e6
JS
965 // Apparently not needed for WinCE (see e.g. Life! demo)
966#ifndef __WXWINCE__
5456b916
RR
967 x2++;
968 y2++;
750d64e6 969#endif
5456b916
RR
970 }
971
f6bcfd97 972 (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
7bcb11d3 973 }
a23fd0e1 974
a23fd0e1 975
7bcb11d3
JS
976 CalcBoundingBox(x, y);
977 CalcBoundingBox(x2, y2);
2bda0e17
KB
978}
979
888dde65 980void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
2bda0e17 981{
82a306b7 982 WXMICROWIN_CHECK_HDC
d275c7eb 983
f6bcfd97 984 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 985
7bcb11d3
JS
986 // Now, a negative radius value is interpreted to mean
987 // 'the proportion of the smallest X or Y dimension'
a23fd0e1 988
7bcb11d3
JS
989 if (radius < 0.0)
990 {
999836aa 991 double smallest = (width < height) ? width : height;
7bcb11d3
JS
992 radius = (- radius * smallest);
993 }
a23fd0e1 994
72cdf4c9
VZ
995 wxCoord x2 = (x+width);
996 wxCoord y2 = (y+height);
a23fd0e1 997
dfde8cd3
GRG
998 // Windows draws the filled rectangles without outline (i.e. drawn with a
999 // transparent pen) one pixel smaller in both directions and we want them
1000 // to have the same size regardless of which pen is used - adjust
1001 if ( m_pen.GetStyle() == wxTRANSPARENT )
1002 {
1003 x2++;
1004 y2++;
1005 }
1006
a23fd0e1 1007 (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
25889d3c 1008 YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
a23fd0e1 1009
7bcb11d3
JS
1010 CalcBoundingBox(x, y);
1011 CalcBoundingBox(x2, y2);
2bda0e17
KB
1012}
1013
888dde65 1014void wxMSWDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2bda0e17 1015{
82a306b7 1016 WXMICROWIN_CHECK_HDC
d275c7eb 1017
f6bcfd97 1018 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 1019
72cdf4c9
VZ
1020 wxCoord x2 = (x+width);
1021 wxCoord y2 = (y+height);
a23fd0e1
VZ
1022
1023 (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
1024
7bcb11d3
JS
1025 CalcBoundingBox(x, y);
1026 CalcBoundingBox(x2, y2);
2bda0e17
KB
1027}
1028
ad0ac642 1029#if wxUSE_SPLINES
888dde65 1030void wxMSWDCImpl::DoDrawSpline(const wxPointList *points)
ad0ac642
WS
1031{
1032#ifdef __WXWINCE__
1033 // WinCE does not support ::PolyBezier so use generic version
1034 wxDCBase::DoDrawSpline(points);
1035#else
1036 // quadratic b-spline to cubic bezier spline conversion
1037 //
1038 // quadratic spline with control points P0,P1,P2
1039 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1040 //
1041 // bezier spline with control points B0,B1,B2,B3
1042 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1043 //
1044 // control points of bezier spline calculated from b-spline
1045 // B0 = P0
1046 // B1 = (2*P1 + P0)/3
1047 // B2 = (2*P1 + P2)/3
1048 // B3 = P2
1049
1050 WXMICROWIN_CHECK_HDC
1051
1052 wxASSERT_MSG( points, wxT("NULL pointer to spline points?") );
1053
1054 const size_t n_points = points->GetCount();
60e19371 1055 wxASSERT_MSG( n_points > 2 , wxT("incomplete list of spline points?") );
ad0ac642
WS
1056
1057 const size_t n_bezier_points = n_points * 3 + 1;
1058 POINT *lppt = (POINT *)malloc(n_bezier_points*sizeof(POINT));
1059 size_t bezier_pos = 0;
1060 wxCoord x1, y1, x2, y2, cx1, cy1, cx4, cy4;
1061
b0d7707b
RR
1062 wxPointList::compatibility_iterator node = points->GetFirst();
1063 wxPoint *p = node->GetData();
ad0ac642
WS
1064 lppt[ bezier_pos ].x = x1 = p->x;
1065 lppt[ bezier_pos ].y = y1 = p->y;
1066 bezier_pos++;
1067 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1068 bezier_pos++;
1069
1070 node = node->GetNext();
b0d7707b 1071 p = node->GetData();
ad0ac642
WS
1072
1073 x2 = p->x;
1074 y2 = p->y;
1075 cx1 = ( x1 + x2 ) / 2;
1076 cy1 = ( y1 + y2 ) / 2;
1077 lppt[ bezier_pos ].x = XLOG2DEV(cx1);
1078 lppt[ bezier_pos ].y = YLOG2DEV(cy1);
1079 bezier_pos++;
1080 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1081 bezier_pos++;
1082
1083#if !wxUSE_STL
1084 while ((node = node->GetNext()) != NULL)
1085#else
1086 while ((node = node->GetNext()))
1087#endif // !wxUSE_STL
1088 {
1089 p = (wxPoint *)node->GetData();
1090 x1 = x2;
1091 y1 = y2;
1092 x2 = p->x;
1093 y2 = p->y;
1094 cx4 = (x1 + x2) / 2;
1095 cy4 = (y1 + y2) / 2;
1096 // B0 is B3 of previous segment
1097 // B1:
1098 lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx1)/3);
1099 lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy1)/3);
1100 bezier_pos++;
1101 // B2:
1102 lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx4)/3);
1103 lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy4)/3);
1104 bezier_pos++;
1105 // B3:
1106 lppt[ bezier_pos ].x = XLOG2DEV(cx4);
1107 lppt[ bezier_pos ].y = YLOG2DEV(cy4);
1108 bezier_pos++;
1109 cx1 = cx4;
1110 cy1 = cy4;
1111 }
1112
1113 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1114 bezier_pos++;
1115 lppt[ bezier_pos ].x = XLOG2DEV(x2);
1116 lppt[ bezier_pos ].y = YLOG2DEV(y2);
1117 bezier_pos++;
1118 lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
1119 bezier_pos++;
1120
1121 ::PolyBezier( GetHdc(), lppt, bezier_pos );
1122
1123 free(lppt);
1124#endif
1125}
1126#endif
1127
6f65e337 1128// Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
888dde65 1129void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
6f65e337 1130{
4676948b 1131#ifdef __WXWINCE__
4f10962b 1132 DoDrawEllipticArcRot( x, y, w, h, sa, ea );
4676948b
JS
1133#else
1134
82a306b7 1135 WXMICROWIN_CHECK_HDC
d275c7eb 1136
f6bcfd97 1137 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
2d8a5cb1 1138
f6bcfd97
BP
1139 wxCoord x2 = x + w;
1140 wxCoord y2 = y + h;
a23fd0e1 1141
7bcb11d3
JS
1142 int rx1 = XLOG2DEV(x+w/2);
1143 int ry1 = YLOG2DEV(y+h/2);
1144 int rx2 = rx1;
1145 int ry2 = ry1;
4314ec48
VZ
1146
1147 sa = DegToRad(sa);
1148 ea = DegToRad(ea);
1149
1150 rx1 += (int)(100.0 * abs(w) * cos(sa));
1151 ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa));
1152 rx2 += (int)(100.0 * abs(w) * cos(ea));
1153 ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea));
a23fd0e1 1154
e6d18909
RD
1155 // Swap start and end positions if the end angle is less than the start angle.
1156 if (ea < sa) {
1157 int temp;
1158 temp = rx2;
1159 rx2 = rx1;
1160 rx1 = temp;
1161 temp = ry2;
1162 ry2 = ry1;
1163 ry1 = temp;
1164 }
1165
7bcb11d3
JS
1166 // draw pie with NULL_PEN first and then outline otherwise a line is
1167 // drawn from the start and end points to the centre
f6bcfd97 1168 HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
7bcb11d3
JS
1169 if (m_signY > 0)
1170 {
a23fd0e1 1171 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
f6bcfd97 1172 rx1, ry1, rx2, ry2);
7bcb11d3
JS
1173 }
1174 else
1175 {
a23fd0e1 1176 (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
f6bcfd97 1177 rx1, ry1-1, rx2, ry2-1);
7bcb11d3 1178 }
f6bcfd97
BP
1179
1180 ::SelectObject(GetHdc(), hpenOld);
1181
a23fd0e1 1182 (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
f6bcfd97 1183 rx1, ry1, rx2, ry2);
a23fd0e1 1184
7bcb11d3
JS
1185 CalcBoundingBox(x, y);
1186 CalcBoundingBox(x2, y2);
4676948b 1187#endif
6f65e337
JS
1188}
1189
888dde65 1190void wxMSWDCImpl::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
2bda0e17 1191{
82a306b7 1192 WXMICROWIN_CHECK_HDC
d275c7eb 1193
4b7f2165
VZ
1194 wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") );
1195
f6bcfd97
BP
1196#ifdef __WIN32__
1197 ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL);
1198#else
4b7f2165 1199 ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon));
f6bcfd97 1200#endif
a23fd0e1 1201
7bcb11d3 1202 CalcBoundingBox(x, y);
4b7f2165 1203 CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight());
2bda0e17
KB
1204}
1205
888dde65 1206void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
f5419957 1207{
82a306b7 1208 WXMICROWIN_CHECK_HDC
d275c7eb 1209
888dde65 1210 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") );
4b7f2165
VZ
1211
1212 int width = bmp.GetWidth(),
1213 height = bmp.GetHeight();
1214
91b4c08d 1215 HBITMAP hbmpMask = 0;
e22c13fe
VZ
1216
1217#if wxUSE_PALETTE
19193a2c 1218 HPALETTE oldPal = 0;
e22c13fe 1219#endif // wxUSE_PALETTE
91b4c08d 1220
acf8e3d2
VZ
1221 if ( bmp.HasAlpha() )
1222 {
275a63e3
VZ
1223 MemoryHDC hdcMem;
1224 SelectInHDC select(hdcMem, GetHbitmapOf(bmp));
878711c0 1225
e3b81044 1226 if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, width, height, hdcMem, bmp) )
275a63e3 1227 return;
acf8e3d2 1228 }
acf8e3d2 1229
91b4c08d
VZ
1230 if ( useMask )
1231 {
1232 wxMask *mask = bmp.GetMask();
1233 if ( mask )
1234 hbmpMask = (HBITMAP)mask->GetMaskBitmap();
1235
1236 if ( !hbmpMask )
1237 {
1238 // don't give assert here because this would break existing
1239 // programs - just silently ignore useMask parameter
beb966c5 1240 useMask = false;
91b4c08d
VZ
1241 }
1242 }
91b4c08d
VZ
1243 if ( useMask )
1244 {
1245#ifdef __WIN32__
4aff28fc
VZ
1246 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1247 // points
d3211838 1248 // On some systems, MaskBlt succeeds yet is much much slower
77ffb593 1249 // than the wxWidgets fall-back implementation. So we need
d3211838 1250 // to be able to switch this on and off at runtime.
beb966c5 1251 bool ok = false;
0cbff120
JS
1252#if wxUSE_SYSTEM_OPTIONS
1253 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1254#endif
d3211838 1255 {
19193a2c 1256 HDC cdc = GetHdc();
d3211838 1257 HDC hdcMem = ::CreateCompatibleDC(GetHdc());
a230101e 1258 HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp));
e22c13fe
VZ
1259#if wxUSE_PALETTE
1260 wxPalette *pal = bmp.GetPalette();
1261 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1262 {
b95edd47 1263 oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE);
19193a2c 1264 ::RealizePalette(hdcMem);
e22c13fe
VZ
1265 }
1266#endif // wxUSE_PALETTE
1267
19193a2c 1268 ok = ::MaskBlt(cdc, x, y, width, height,
91b4c08d
VZ
1269 hdcMem, 0, 0,
1270 hbmpMask, 0, 0,
4aff28fc 1271 MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
e22c13fe
VZ
1272
1273#if wxUSE_PALETTE
19193a2c
KB
1274 if (oldPal)
1275 ::SelectPalette(hdcMem, oldPal, FALSE);
e22c13fe
VZ
1276#endif // wxUSE_PALETTE
1277
a230101e 1278 ::SelectObject(hdcMem, hOldBitmap);
d3211838
JS
1279 ::DeleteDC(hdcMem);
1280 }
91b4c08d
VZ
1281
1282 if ( !ok )
1283#endif // Win32
1284 {
888dde65 1285 // Rather than reproduce wxMSWDCImpl::Blit, let's do it at the wxWin API
4aff28fc 1286 // level
91b4c08d 1287 wxMemoryDC memDC;
fea35690
VZ
1288
1289 memDC.SelectObjectAsSource(bmp);
91b4c08d 1290
888dde65 1291 GetOwner()->Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
91b4c08d
VZ
1292
1293 memDC.SelectObject(wxNullBitmap);
1294 }
1295 }
1296 else // no mask, just use BitBlt()
f5419957 1297 {
4b7f2165
VZ
1298 HDC cdc = GetHdc();
1299 HDC memdc = ::CreateCompatibleDC( cdc );
1300 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
1301
1302 wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
1303
1304 COLORREF old_textground = ::GetTextColor(GetHdc());
1305 COLORREF old_background = ::GetBkColor(GetHdc());
1306 if (m_textForegroundColour.Ok())
8caa4ed1 1307 {
4b7f2165 1308 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
8caa4ed1 1309 }
4b7f2165 1310 if (m_textBackgroundColour.Ok())
8caa4ed1 1311 {
4b7f2165
VZ
1312 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1313 }
392f4b1b 1314
e22c13fe 1315#if wxUSE_PALETTE
62e1ba75
JS
1316 wxPalette *pal = bmp.GetPalette();
1317 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1318 {
b95edd47 1319 oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE);
62e1ba75
JS
1320 ::RealizePalette(memdc);
1321 }
e22c13fe
VZ
1322#endif // wxUSE_PALETTE
1323
a230101e 1324 HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap );
4b7f2165 1325 ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
e22c13fe
VZ
1326
1327#if wxUSE_PALETTE
19193a2c
KB
1328 if (oldPal)
1329 ::SelectPalette(memdc, oldPal, FALSE);
e22c13fe
VZ
1330#endif // wxUSE_PALETTE
1331
62e1ba75 1332 ::SelectObject( memdc, hOldBitmap );
4b7f2165 1333 ::DeleteDC( memdc );
392f4b1b 1334
4b7f2165
VZ
1335 ::SetTextColor(GetHdc(), old_textground);
1336 ::SetBkColor(GetHdc(), old_background);
f5419957 1337 }
f5419957
JS
1338}
1339
888dde65 1340void wxMSWDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
a23fd0e1 1341{
82a306b7 1342 WXMICROWIN_CHECK_HDC
d275c7eb 1343
4314ec48
VZ
1344 DrawAnyText(text, x, y);
1345
1346 // update the bounding box
1347 CalcBoundingBox(x, y);
1348
1349 wxCoord w, h;
888dde65 1350 GetOwner()->GetTextExtent(text, &w, &h);
4314ec48
VZ
1351 CalcBoundingBox(x + w, y + h);
1352}
1353
888dde65 1354void wxMSWDCImpl::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
4314ec48 1355{
82a306b7 1356 WXMICROWIN_CHECK_HDC
d275c7eb 1357
4314ec48
VZ
1358 // prepare for drawing the text
1359 if ( m_textForegroundColour.Ok() )
1360 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
a23fd0e1
VZ
1361
1362 DWORD old_background = 0;
4314ec48 1363 if ( m_textBackgroundColour.Ok() )
a23fd0e1
VZ
1364 {
1365 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1366 }
1367
4314ec48
VZ
1368 SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
1369 : OPAQUE);
a23fd0e1 1370
4676948b
JS
1371#ifdef __WXWINCE__
1372 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL,
1373 text.c_str(), text.length(), NULL) == 0 )
1374 {
1375 wxLogLastError(wxT("TextOut"));
1376 }
1377#else
4314ec48 1378 if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
696e1ea0 1379 text.c_str(), text.length()) == 0 )
4314ec48 1380 {
f6bcfd97 1381 wxLogLastError(wxT("TextOut"));
4314ec48 1382 }
4676948b 1383#endif
a23fd0e1 1384
4314ec48
VZ
1385 // restore the old parameters (text foreground colour may be left because
1386 // it never is set to anything else, but background should remain
1387 // transparent even if we just drew an opaque string)
1388 if ( m_textBackgroundColour.Ok() )
a23fd0e1
VZ
1389 (void)SetBkColor(GetHdc(), old_background);
1390
c45a644e 1391 SetBkMode(GetHdc(), TRANSPARENT);
a23fd0e1
VZ
1392}
1393
888dde65 1394void wxMSWDCImpl::DoDrawRotatedText(const wxString& text,
95724b1a
VZ
1395 wxCoord x, wxCoord y,
1396 double angle)
1397{
82a306b7 1398 WXMICROWIN_CHECK_HDC
d275c7eb 1399
696e1ea0
VZ
1400 // we test that we have some font because otherwise we should still use the
1401 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1402 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1403 // font for drawing rotated fonts unfortunately)
1404 if ( (angle == 0.0) && m_font.Ok() )
4314ec48
VZ
1405 {
1406 DoDrawText(text, x, y);
1407 }
04ef50df 1408#ifndef __WXMICROWIN__
4314ec48
VZ
1409 else
1410 {
4770df95
VZ
1411 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1412 // because it's not TrueType and so can't have non zero
1413 // orientation/escapement under Win9x
1414 wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT;
696e1ea0 1415 HFONT hfont = (HFONT)font.GetResourceHandle();
4314ec48 1416 LOGFONT lf;
696e1ea0
VZ
1417 if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
1418 {
f6bcfd97 1419 wxLogLastError(wxT("GetObject(hfont)"));
696e1ea0 1420 }
4314ec48
VZ
1421
1422 // GDI wants the angle in tenth of degree
1423 long angle10 = (long)(angle * 10);
1424 lf.lfEscapement = angle10;
1425 lf. lfOrientation = angle10;
1426
696e1ea0 1427 hfont = ::CreateFontIndirect(&lf);
4314ec48
VZ
1428 if ( !hfont )
1429 {
f6bcfd97 1430 wxLogLastError(wxT("CreateFont"));
4314ec48
VZ
1431 }
1432 else
1433 {
696e1ea0 1434 HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
4314ec48
VZ
1435
1436 DrawAnyText(text, x, y);
1437
1438 (void)::SelectObject(GetHdc(), hfontOld);
a3a1ceae 1439 (void)::DeleteObject(hfont);
4314ec48
VZ
1440 }
1441
1442 // call the bounding box by adding all four vertices of the rectangle
1443 // containing the text to it (simpler and probably not slower than
1444 // determining which of them is really topmost/leftmost/...)
1445 wxCoord w, h;
888dde65 1446 GetOwner()->GetTextExtent(text, &w, &h);
4314ec48
VZ
1447
1448 double rad = DegToRad(angle);
1449
1450 // "upper left" and "upper right"
1451 CalcBoundingBox(x, y);
a98ca1ae 1452 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
4314ec48
VZ
1453
1454 // "bottom left" and "bottom right"
1455 x += (wxCoord)(h*sin(rad));
1456 y += (wxCoord)(h*cos(rad));
1457 CalcBoundingBox(x, y);
a98ca1ae 1458 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
4314ec48 1459 }
04ef50df 1460#endif
95724b1a
VZ
1461}
1462
a23fd0e1
VZ
1463// ---------------------------------------------------------------------------
1464// set GDI objects
1465// ---------------------------------------------------------------------------
1466
d275c7eb
VZ
1467#if wxUSE_PALETTE
1468
888dde65 1469void wxMSWDCImpl::DoSelectPalette(bool realize)
a23fd0e1 1470{
82a306b7 1471 WXMICROWIN_CHECK_HDC
d275c7eb 1472
a23fd0e1
VZ
1473 // Set the old object temporarily, in case the assignment deletes an object
1474 // that's not yet selected out.
1475 if (m_oldPalette)
1476 {
19193a2c 1477 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE);
a23fd0e1
VZ
1478 m_oldPalette = 0;
1479 }
1480
b95edd47 1481 if ( m_palette.Ok() )
a23fd0e1 1482 {
b95edd47
VZ
1483 HPALETTE oldPal = ::SelectPalette(GetHdc(),
1484 GetHpaletteOf(m_palette),
beb966c5 1485 false);
a23fd0e1
VZ
1486 if (!m_oldPalette)
1487 m_oldPalette = (WXHPALETTE) oldPal;
1488
574c939e
KB
1489 if (realize)
1490 ::RealizePalette(GetHdc());
a23fd0e1 1491 }
574c939e
KB
1492}
1493
888dde65 1494void wxMSWDCImpl::SetPalette(const wxPalette& palette)
574c939e 1495{
b95edd47
VZ
1496 if ( palette.Ok() )
1497 {
574c939e 1498 m_palette = palette;
beb966c5 1499 DoSelectPalette(true);
b95edd47 1500 }
a23fd0e1
VZ
1501}
1502
888dde65 1503void wxMSWDCImpl::InitializePalette()
574c939e 1504{
b95edd47
VZ
1505 if ( wxDisplayDepth() <= 8 )
1506 {
574c939e
KB
1507 // look for any window or parent that has a custom palette. If any has
1508 // one then we need to use it in drawing operations
888dde65 1509 wxWindow *win = m_window->GetAncestorWithCustomPalette();
b95edd47
VZ
1510
1511 m_hasCustomPalette = win && win->HasCustomPalette();
1512 if ( m_hasCustomPalette )
1513 {
574c939e 1514 m_palette = win->GetPalette();
b95edd47 1515
574c939e
KB
1516 // turn on MSW translation for this palette
1517 DoSelectPalette();
574c939e 1518 }
b95edd47 1519 }
574c939e 1520}
b95edd47 1521
d275c7eb
VZ
1522#endif // wxUSE_PALETTE
1523
9f7948af
VZ
1524// SetFont/Pen/Brush() really ask to be implemented as a single template
1525// function... but doing it is not worth breaking OpenWatcom build <sigh>
1526
888dde65 1527void wxMSWDCImpl::SetFont(const wxFont& font)
2bda0e17 1528{
82a306b7 1529 WXMICROWIN_CHECK_HDC
d275c7eb 1530
9f7948af
VZ
1531 if ( font == m_font )
1532 return;
a23fd0e1 1533
9f7948af 1534 if ( font.Ok() )
7bcb11d3 1535 {
9f7948af
VZ
1536 HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font));
1537 if ( hfont == HGDI_ERROR )
1538 {
1539 wxLogLastError(_T("SelectObject(font)"));
1540 }
1541 else // selected ok
1542 {
1543 if ( !m_oldFont )
658ff7f1 1544 m_oldFont = (WXHFONT)hfont;
a23fd0e1 1545
9f7948af
VZ
1546 m_font = font;
1547 }
1548 }
1549 else // invalid font, reset the current font
7bcb11d3 1550 {
9f7948af 1551 if ( m_oldFont )
7bcb11d3 1552 {
9f7948af
VZ
1553 if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR )
1554 {
1555 wxLogLastError(_T("SelectObject(old font)"));
1556 }
1557
beb966c5 1558 m_oldFont = 0;
7bcb11d3 1559 }
9f7948af
VZ
1560
1561 m_font = wxNullFont;
34da0970 1562 }
2bda0e17
KB
1563}
1564
888dde65 1565void wxMSWDCImpl::SetPen(const wxPen& pen)
2bda0e17 1566{
82a306b7 1567 WXMICROWIN_CHECK_HDC
d275c7eb 1568
b5371ab8
VZ
1569 if ( pen == m_pen )
1570 return;
a23fd0e1 1571
b5371ab8 1572 if ( pen.Ok() )
7bcb11d3 1573 {
b5371ab8
VZ
1574 HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen));
1575 if ( hpen == HGDI_ERROR )
1576 {
1577 wxLogLastError(_T("SelectObject(pen)"));
1578 }
1579 else // selected ok
1580 {
1581 if ( !m_oldPen )
1582 m_oldPen = (WXHPEN)hpen;
a23fd0e1 1583
b5371ab8
VZ
1584 m_pen = pen;
1585 }
1586 }
1587 else // invalid pen, reset the current pen
7bcb11d3 1588 {
b5371ab8 1589 if ( m_oldPen )
7bcb11d3 1590 {
b5371ab8
VZ
1591 if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR )
1592 {
1593 wxLogLastError(_T("SelectObject(old pen)"));
1594 }
1595
beb966c5 1596 m_oldPen = 0;
7bcb11d3 1597 }
b5371ab8
VZ
1598
1599 m_pen = wxNullPen;
2bda0e17 1600 }
2bda0e17
KB
1601}
1602
888dde65 1603void wxMSWDCImpl::SetBrush(const wxBrush& brush)
2bda0e17 1604{
82a306b7 1605 WXMICROWIN_CHECK_HDC
d275c7eb 1606
9f7948af
VZ
1607 if ( brush == m_brush )
1608 return;
a23fd0e1 1609
9f7948af 1610 if ( brush.Ok() )
7bcb11d3 1611 {
9f7948af
VZ
1612 // we must make sure the brush is aligned with the logical coordinates
1613 // before selecting it
1614 wxBitmap *stipple = brush.GetStipple();
2d8a5cb1
VZ
1615 if ( stipple && stipple->Ok() )
1616 {
9f7948af
VZ
1617 if ( !::SetBrushOrgEx
1618 (
1619 GetHdc(),
1620 m_deviceOriginX % stipple->GetWidth(),
1621 m_deviceOriginY % stipple->GetHeight(),
1622 NULL // [out] previous brush origin
1623 ) )
1624 {
1625 wxLogLastError(_T("SetBrushOrgEx()"));
1626 }
2d8a5cb1
VZ
1627 }
1628
9f7948af
VZ
1629 HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush));
1630 if ( hbrush == HGDI_ERROR )
7bcb11d3 1631 {
9f7948af 1632 wxLogLastError(_T("SelectObject(brush)"));
7bcb11d3 1633 }
9f7948af
VZ
1634 else // selected ok
1635 {
1636 if ( !m_oldBrush )
658ff7f1 1637 m_oldBrush = (WXHBRUSH)hbrush;
9f7948af
VZ
1638
1639 m_brush = brush;
1640 }
1641 }
1642 else // invalid brush, reset the current brush
1643 {
1644 if ( m_oldBrush )
1645 {
1646 if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR )
1647 {
1648 wxLogLastError(_T("SelectObject(old brush)"));
1649 }
1650
beb966c5 1651 m_oldBrush = 0;
9f7948af
VZ
1652 }
1653
1654 m_brush = wxNullBrush;
2bda0e17 1655 }
2bda0e17
KB
1656}
1657
888dde65 1658void wxMSWDCImpl::SetBackground(const wxBrush& brush)
2bda0e17 1659{
82a306b7 1660 WXMICROWIN_CHECK_HDC
d275c7eb 1661
7bcb11d3 1662 m_backgroundBrush = brush;
a23fd0e1 1663
44383ef7 1664 if ( m_backgroundBrush.Ok() )
7bcb11d3 1665 {
44383ef7 1666 (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel());
2bda0e17 1667 }
2bda0e17
KB
1668}
1669
888dde65 1670void wxMSWDCImpl::SetBackgroundMode(int mode)
2bda0e17 1671{
82a306b7 1672 WXMICROWIN_CHECK_HDC
d275c7eb 1673
7bcb11d3 1674 m_backgroundMode = mode;
a23fd0e1 1675
c45a644e
RR
1676 // SetBackgroundColour now only refers to text background
1677 // and m_backgroundMode is used there
2bda0e17
KB
1678}
1679
888dde65 1680void wxMSWDCImpl::SetLogicalFunction(int function)
2bda0e17 1681{
82a306b7 1682 WXMICROWIN_CHECK_HDC
d275c7eb 1683
7bcb11d3 1684 m_logicalFunction = function;
a23fd0e1 1685
ed791986 1686 SetRop(m_hDC);
2bda0e17
KB
1687}
1688
888dde65 1689void wxMSWDCImpl::SetRop(WXHDC dc)
2bda0e17 1690{
ed791986 1691 if ( !dc || m_logicalFunction < 0 )
7bcb11d3 1692 return;
a23fd0e1 1693
ed791986
VZ
1694 int rop;
1695
7bcb11d3
JS
1696 switch (m_logicalFunction)
1697 {
4aff28fc 1698 case wxCLEAR: rop = R2_BLACK; break;
ed791986
VZ
1699 case wxXOR: rop = R2_XORPEN; break;
1700 case wxINVERT: rop = R2_NOT; break;
1701 case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
1702 case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
4aff28fc 1703 case wxCOPY: rop = R2_COPYPEN; break;
ed791986 1704 case wxAND: rop = R2_MASKPEN; break;
ed791986 1705 case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
ed791986 1706 case wxNO_OP: rop = R2_NOP; break;
ed791986 1707 case wxNOR: rop = R2_NOTMERGEPEN; break;
4aff28fc
VZ
1708 case wxEQUIV: rop = R2_NOTXORPEN; break;
1709 case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
1710 case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
1711 case wxNAND: rop = R2_NOTMASKPEN; break;
1712 case wxOR: rop = R2_MERGEPEN; break;
1713 case wxSET: rop = R2_WHITE; break;
1714
71fe5c01 1715 default:
71fe5c01 1716 wxFAIL_MSG( wxT("unsupported logical function") );
ed791986 1717 return;
7bcb11d3 1718 }
ed791986
VZ
1719
1720 SetROP2(GetHdc(), rop);
2bda0e17
KB
1721}
1722
888dde65 1723bool wxMSWDCImpl::StartDoc(const wxString& WXUNUSED(message))
2bda0e17 1724{
beb966c5
DS
1725 // We might be previewing, so return true to let it continue.
1726 return true;
2bda0e17
KB
1727}
1728
888dde65 1729void wxMSWDCImpl::EndDoc()
2bda0e17 1730{
2bda0e17
KB
1731}
1732
888dde65 1733void wxMSWDCImpl::StartPage()
2bda0e17 1734{
2bda0e17
KB
1735}
1736
888dde65 1737void wxMSWDCImpl::EndPage()
2bda0e17 1738{
2bda0e17
KB
1739}
1740
a23fd0e1
VZ
1741// ---------------------------------------------------------------------------
1742// text metrics
1743// ---------------------------------------------------------------------------
1744
888dde65 1745wxCoord wxMSWDCImpl::GetCharHeight() const
2bda0e17 1746{
82a306b7 1747 WXMICROWIN_CHECK_HDC_RET(0)
d275c7eb 1748
7bcb11d3 1749 TEXTMETRIC lpTextMetric;
a23fd0e1
VZ
1750
1751 GetTextMetrics(GetHdc(), &lpTextMetric);
1752
1e2081a1 1753 return lpTextMetric.tmHeight;
2bda0e17
KB
1754}
1755
888dde65 1756wxCoord wxMSWDCImpl::GetCharWidth() const
2bda0e17 1757{
82a306b7 1758 WXMICROWIN_CHECK_HDC_RET(0)
d275c7eb 1759
7bcb11d3 1760 TEXTMETRIC lpTextMetric;
a23fd0e1
VZ
1761
1762 GetTextMetrics(GetHdc(), &lpTextMetric);
1763
1e2081a1 1764 return lpTextMetric.tmAveCharWidth;
2bda0e17
KB
1765}
1766
888dde65 1767void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
72cdf4c9 1768 wxCoord *descent, wxCoord *externalLeading,
c94f845b 1769 const wxFont *font) const
2bda0e17 1770{
5adad466
JS
1771#ifdef __WXMICROWIN__
1772 if (!GetHDC())
1773 {
a230101e
VZ
1774 if (x) *x = 0;
1775 if (y) *y = 0;
1776 if (descent) *descent = 0;
1777 if (externalLeading) *externalLeading = 0;
1778 return;
5adad466 1779 }
a230101e 1780#endif // __WXMICROWIN__
d275c7eb 1781
8bf30fe9
VZ
1782 HFONT hfontOld;
1783 if ( font )
1784 {
888dde65 1785 wxASSERT_MSG( font->Ok(), _T("invalid font in wxMSWDCImpl::GetTextExtent") );
8bf30fe9
VZ
1786
1787 hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
1788 }
1789 else // don't change the font
1790 {
1791 hfontOld = 0;
1792 }
a23fd0e1 1793
7bcb11d3 1794 SIZE sizeRect;
481203cb 1795 const size_t len = string.length();
e0a050e3 1796 if ( !::GetTextExtentPoint32(GetHdc(), string.wx_str(), len, &sizeRect) )
481203cb
VZ
1797 {
1798 wxLogLastError(_T("GetTextExtentPoint32()"));
1799 }
a23fd0e1 1800
3cdcf4d4 1801#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
481203cb
VZ
1802 // the result computed by GetTextExtentPoint32() may be too small as it
1803 // accounts for under/overhang of the first/last character while we want
1804 // just the bounding rect for this string so adjust the width as needed
3cdcf4d4 1805 // (using API not available in 2002 SDKs of WinCE)
481203cb
VZ
1806 if ( len > 0 )
1807 {
1808 ABC width;
1809 const wxChar chFirst = *string.begin();
1810 if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) )
1811 {
1812 if ( width.abcA < 0 )
1813 sizeRect.cx -= width.abcA;
1814
1815 if ( len > 1 )
1816 {
1817 const wxChar chLast = *string.rbegin();
1818 ::GetCharABCWidths(GetHdc(), chLast, chLast, &width);
1819 }
1820 //else: we already have the width of the last character
1821
1822 if ( width.abcC < 0 )
1823 sizeRect.cx -= width.abcC;
1824 }
1825 //else: GetCharABCWidths() failed, not a TrueType font?
1826 }
3cdcf4d4 1827#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
481203cb
VZ
1828
1829 TEXTMETRIC tm;
1830 ::GetTextMetrics(GetHdc(), &tm);
a23fd0e1 1831
1e2081a1
VZ
1832 if (x)
1833 *x = sizeRect.cx;
1834 if (y)
1835 *y = sizeRect.cy;
1836 if (descent)
1837 *descent = tm.tmDescent;
1838 if (externalLeading)
1839 *externalLeading = tm.tmExternalLeading;
8bf30fe9
VZ
1840
1841 if ( hfontOld )
1842 {
1843 ::SelectObject(GetHdc(), hfontOld);
1844 }
2bda0e17
KB
1845}
1846
553aa032
RD
1847
1848// Each element of the array will be the width of the string up to and
5c2ddebe 1849// including the coresoponding character in text.
553aa032 1850
888dde65 1851bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
553aa032
RD
1852{
1853 static int maxLenText = -1;
1854 static int maxWidth = -1;
1855 int fit = 0;
1856 SIZE sz = {0,0};
41e155b4 1857 int stlen = text.length();
553aa032
RD
1858
1859 if (maxLenText == -1)
1860 {
1861 // Win9x and WinNT+ have different limits
1862 int version = wxGetOsVersion();
406d283a
PC
1863 maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
1864 maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
553aa032 1865 }
5c2ddebe 1866
553aa032
RD
1867 widths.Empty();
1868 widths.Add(0, stlen); // fill the array with zeros
f9daf953
JS
1869 if (stlen == 0)
1870 return true;
5c2ddebe 1871
553aa032
RD
1872 if (!::GetTextExtentExPoint(GetHdc(),
1873 text.c_str(), // string to check
1874 wxMin(stlen, maxLenText),
5c2ddebe
VZ
1875 maxWidth,
1876 &fit, // [out] count of chars
553aa032 1877 // that will fit
5c2ddebe
VZ
1878 &widths[0], // array to fill
1879 &sz))
1880 {
553aa032
RD
1881 // API failed
1882 wxLogLastError(wxT("GetTextExtentExPoint"));
5c2ddebe
VZ
1883 return false;
1884 }
1885
553aa032
RD
1886 return true;
1887}
1888
888dde65 1889void wxMSWDCImpl::RealizeScaleAndOrigin()
04ab8b6d
RR
1890{
1891 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1892 // cases we could do with MM_TEXT and in the remaining 0.9% with
1893 // MM_ISOTROPIC (TODO!)
1894#ifndef __WXWINCE__
1895 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
553aa032 1896
04ab8b6d
RR
1897 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
1898 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
553aa032 1899
04ab8b6d
RR
1900 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1901 ::SetWindowExtEx(GetHdc(), width, height, NULL);
1902
1903 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
1904 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);
1905#endif
1906
1907}
553aa032 1908
888dde65 1909void wxMSWDCImpl::SetMapMode(int mode)
2bda0e17 1910{
82a306b7 1911 WXMICROWIN_CHECK_HDC
d275c7eb 1912
7bcb11d3 1913 m_mappingMode = mode;
a23fd0e1 1914
1e2081a1 1915 if ( mode == wxMM_TEXT )
2bda0e17 1916 {
1e2081a1
VZ
1917 m_logicalScaleX =
1918 m_logicalScaleY = 1.0;
2bda0e17 1919 }
1e2081a1 1920 else // need to do some calculations
2bda0e17 1921 {
1e2081a1
VZ
1922 int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES),
1923 pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES),
1924 mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE),
1925 mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1926
1927 if ( (mm_width == 0) || (mm_height == 0) )
7bcb11d3 1928 {
1e2081a1
VZ
1929 // we can't calculate mm2pixels[XY] then!
1930 return;
7bcb11d3 1931 }
1e2081a1 1932
82922a02
VZ
1933 double mm2pixelsX = (double)pixel_width / mm_width,
1934 mm2pixelsY = (double)pixel_height / mm_height;
1e2081a1
VZ
1935
1936 switch (mode)
7bcb11d3 1937 {
1e2081a1
VZ
1938 case wxMM_TWIPS:
1939 m_logicalScaleX = twips2mm * mm2pixelsX;
1940 m_logicalScaleY = twips2mm * mm2pixelsY;
1941 break;
1942
1943 case wxMM_POINTS:
1944 m_logicalScaleX = pt2mm * mm2pixelsX;
1945 m_logicalScaleY = pt2mm * mm2pixelsY;
1946 break;
1947
1948 case wxMM_METRIC:
1949 m_logicalScaleX = mm2pixelsX;
1950 m_logicalScaleY = mm2pixelsY;
1951 break;
1952
1953 case wxMM_LOMETRIC:
1954 m_logicalScaleX = mm2pixelsX / 10.0;
1955 m_logicalScaleY = mm2pixelsY / 10.0;
1956 break;
1957
1958 default:
1959 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
7bcb11d3 1960 }
2bda0e17 1961 }
04ab8b6d
RR
1962
1963 ComputeScaleAndOrigin();
1964
1965 RealizeScaleAndOrigin();
2bda0e17
KB
1966}
1967
888dde65 1968void wxMSWDCImpl::SetUserScale(double x, double y)
2bda0e17 1969{
82a306b7 1970 WXMICROWIN_CHECK_HDC
d275c7eb 1971
1e2081a1
VZ
1972 if ( x == m_userScaleX && y == m_userScaleY )
1973 return;
1974
888dde65 1975 wxDCImpl::SetUserScale(x,y);
04ab8b6d
RR
1976
1977 RealizeScaleAndOrigin();
2bda0e17
KB
1978}
1979
888dde65 1980void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight,
04ab8b6d 1981 bool yBottomUp)
6f65e337 1982{
82a306b7 1983 WXMICROWIN_CHECK_HDC
d275c7eb 1984
1e2081a1
VZ
1985 int signX = xLeftRight ? 1 : -1,
1986 signY = yBottomUp ? -1 : 1;
04ab8b6d
RR
1987
1988 if (signX == m_signX && signY == m_signY)
1e2081a1 1989 return;
04ab8b6d 1990
888dde65 1991 wxDCImpl::SetAxisOrientation( xLeftRight, yBottomUp );
1e2081a1 1992
04ab8b6d 1993 RealizeScaleAndOrigin();
2bda0e17
KB
1994}
1995
888dde65 1996void wxMSWDCImpl::SetLogicalOrigin(wxCoord x, wxCoord y)
2bda0e17 1997{
82a306b7 1998 WXMICROWIN_CHECK_HDC
d275c7eb 1999
1e2081a1
VZ
2000 if ( x == m_logicalOriginX && y == m_logicalOriginY )
2001 return;
2002
888dde65 2003 wxDCImpl::SetLogicalOrigin( x, y );
a23fd0e1 2004
1a4b50d2 2005#ifndef __WXWINCE__
a23fd0e1 2006 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
4676948b 2007#endif
2bda0e17
KB
2008}
2009
888dde65 2010void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y)
2bda0e17 2011{
82a306b7 2012 WXMICROWIN_CHECK_HDC
d275c7eb 2013
1e2081a1
VZ
2014 if ( x == m_deviceOriginX && y == m_deviceOriginY )
2015 return;
04ab8b6d 2016
888dde65 2017 wxDCImpl::SetDeviceOrigin( x, y );
2bda0e17 2018
a23fd0e1 2019 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
2bda0e17
KB
2020}
2021
a23fd0e1
VZ
2022// ---------------------------------------------------------------------------
2023// bit blit
2024// ---------------------------------------------------------------------------
04ab8b6d 2025
888dde65 2026bool wxMSWDCImpl::DoBlit(wxCoord dstX, wxCoord dstY,
e3b81044
VZ
2027 wxCoord dstWidth, wxCoord dstHeight,
2028 wxDC *source,
2029 wxCoord srcX, wxCoord srcY,
0cbff120 2030 int rop, bool useMask,
e3b81044
VZ
2031 wxCoord srcMaskX, wxCoord srcMaskY)
2032{
2033 return DoStretchBlit(dstX, dstY, dstWidth, dstHeight, source, srcX, srcY, dstWidth, dstHeight, rop, useMask, srcMaskX, srcMaskY);
2034}
2035
888dde65 2036bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
e3b81044
VZ
2037 wxCoord dstWidth, wxCoord dstHeight,
2038 wxDC *source,
2039 wxCoord xsrc, wxCoord ysrc,
2040 wxCoord srcWidth, wxCoord srcHeight,
2041 int rop, bool useMask,
2042 wxCoord xsrcMask, wxCoord ysrcMask)
2bda0e17 2043{
888dde65 2044 wxCHECK_MSG( source, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
275a63e3 2045
beb966c5 2046 WXMICROWIN_CHECK_HDC_RET(false)
d275c7eb 2047
888dde65
RR
2048 wxDCImpl *impl = source->GetImpl();
2049 wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl );
2050 if (!msw_impl)
2051 {
2052 // TODO: Do we want to be able to blit
2053 // from other DCs too?
2054 return false;
2055 }
2056
57c26f82
VZ
2057 // if either the source or destination has alpha channel, we must use
2058 // AlphaBlt() as other function don't handle it correctly
888dde65 2059 const wxBitmap& bmpSrc = msw_impl->GetSelectedBitmap();
57c26f82
VZ
2060 if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() ||
2061 (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) )
275a63e3 2062 {
e3b81044 2063 if ( AlphaBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight,
888dde65 2064 xsrc, ysrc, srcWidth, srcHeight, GetHdcOf(*msw_impl), bmpSrc) )
beb966c5 2065 return true;
275a63e3 2066 }
d80f416f 2067
4b7f2165
VZ
2068 wxMask *mask = NULL;
2069 if ( useMask )
2070 {
d80f416f 2071 mask = bmpSrc.GetMask();
4b7f2165 2072
d80f416f 2073 if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) )
d5536ade
VZ
2074 {
2075 // don't give assert here because this would break existing
2076 // programs - just silently ignore useMask parameter
beb966c5 2077 useMask = false;
d5536ade 2078 }
4b7f2165 2079 }
a23fd0e1 2080
0cbff120
JS
2081 if (xsrcMask == -1 && ysrcMask == -1)
2082 {
2083 xsrcMask = xsrc; ysrcMask = ysrc;
2084 }
2085
a23fd0e1
VZ
2086 COLORREF old_textground = ::GetTextColor(GetHdc());
2087 COLORREF old_background = ::GetBkColor(GetHdc());
7bcb11d3
JS
2088 if (m_textForegroundColour.Ok())
2089 {
a23fd0e1 2090 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
7bcb11d3
JS
2091 }
2092 if (m_textBackgroundColour.Ok())
2093 {
a23fd0e1 2094 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
7bcb11d3 2095 }
a23fd0e1 2096
999836aa 2097 DWORD dwRop;
71fe5c01
RR
2098 switch (rop)
2099 {
ed791986
VZ
2100 case wxXOR: dwRop = SRCINVERT; break;
2101 case wxINVERT: dwRop = DSTINVERT; break;
2102 case wxOR_REVERSE: dwRop = 0x00DD0228; break;
2103 case wxAND_REVERSE: dwRop = SRCERASE; break;
2104 case wxCLEAR: dwRop = BLACKNESS; break;
2105 case wxSET: dwRop = WHITENESS; break;
2106 case wxOR_INVERT: dwRop = MERGEPAINT; break;
2107 case wxAND: dwRop = SRCAND; break;
2108 case wxOR: dwRop = SRCPAINT; break;
2109 case wxEQUIV: dwRop = 0x00990066; break;
2110 case wxNAND: dwRop = 0x007700E6; break;
2111 case wxAND_INVERT: dwRop = 0x00220326; break;
2112 case wxCOPY: dwRop = SRCCOPY; break;
4aff28fc 2113 case wxNO_OP: dwRop = DSTCOPY; break;
ed791986 2114 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
71fe5c01
RR
2115 case wxNOR: dwRop = NOTSRCCOPY; break;
2116 default:
71fe5c01 2117 wxFAIL_MSG( wxT("unsupported logical function") );
beb966c5 2118 return false;
71fe5c01
RR
2119 }
2120
beb966c5 2121 bool success = false;
730bc726
JS
2122
2123 if (useMask)
7bcb11d3 2124 {
4b7f2165 2125#ifdef __WIN32__
a58a12e9 2126 // we want the part of the image corresponding to the mask to be
4aff28fc
VZ
2127 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2128 // meaning of fg and bg is inverted which corresponds to wxWin notion
2129 // of the mask which is also contrary to the Windows one)
d3211838
JS
2130
2131 // On some systems, MaskBlt succeeds yet is much much slower
77ffb593 2132 // than the wxWidgets fall-back implementation. So we need
d3211838 2133 // to be able to switch this on and off at runtime.
0cbff120
JS
2134#if wxUSE_SYSTEM_OPTIONS
2135 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2136#endif
d3211838 2137 {
e3b81044
VZ
2138 if ( dstWidth == srcWidth && dstHeight == srcHeight )
2139 {
2140 success = ::MaskBlt
2141 (
f178ab7e 2142 GetHdc(),
e3b81044 2143 xdest, ydest, dstWidth, dstHeight,
888dde65 2144 GetHdcOf(*msw_impl),
f178ab7e
VZ
2145 xsrc, ysrc,
2146 (HBITMAP)mask->GetMaskBitmap(),
2147 xsrcMask, ysrcMask,
2148 MAKEROP4(dwRop, DSTCOPY)
e3b81044
VZ
2149 ) != 0;
2150 }
d3211838 2151 }
a58a12e9
VZ
2152
2153 if ( !success )
4b7f2165 2154#endif // Win32
7bcb11d3 2155 {
7bcb11d3 2156 // Blit bitmap with mask
0cbff120
JS
2157 HDC dc_mask ;
2158 HDC dc_buffer ;
2159 HBITMAP buffer_bmap ;
a23fd0e1 2160
0cbff120 2161#if wxUSE_DC_CACHEING
2b96d0fb 2162 // create a temp buffer bitmap and DCs to access it and the mask
888dde65 2163 wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, msw_impl->GetHDC());
2b96d0fb
VZ
2164 dc_mask = (HDC) dcCacheEntry1->m_dc;
2165
2166 wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
2167 dc_buffer = (HDC) dcCacheEntry2->m_dc;
2168
2169 wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
e3b81044 2170 dstWidth, dstHeight);
2b96d0fb
VZ
2171
2172 buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
2173#else // !wxUSE_DC_CACHEING
2174 // create a temp buffer bitmap and DCs to access it and the mask
2175 dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
2176 dc_buffer = ::CreateCompatibleDC(GetHdc());
e3b81044 2177 buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), dstWidth, dstHeight);
619e52bf 2178#endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
a230101e
VZ
2179 HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
2180 HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
4b7f2165
VZ
2181
2182 // copy dest to buffer
e3b81044 2183 if ( !::BitBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight,
4b7f2165 2184 GetHdc(), xdest, ydest, SRCCOPY) )
7bcb11d3 2185 {
f6bcfd97 2186 wxLogLastError(wxT("BitBlt"));
7bcb11d3 2187 }
4b7f2165 2188
e3b81044
VZ
2189#ifndef __WXWINCE__
2190 StretchBltModeChanger changeMode(dc_buffer, COLORONCOLOR);
2191#endif
2192
4b7f2165 2193 // copy src to buffer using selected raster op
e3b81044 2194 if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight,
888dde65 2195 GetHdcOf(*msw_impl), xsrc, ysrc, srcWidth, srcHeight, dwRop) )
7bcb11d3 2196 {
e3b81044 2197 wxLogLastError(wxT("StretchBlt"));
7bcb11d3 2198 }
4b7f2165
VZ
2199
2200 // set masked area in buffer to BLACK (pixel value 0)
2201 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2202 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
e3b81044
VZ
2203 if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight,
2204 dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) )
4b7f2165 2205 {
e3b81044 2206 wxLogLastError(wxT("StretchBlt"));
4b7f2165
VZ
2207 }
2208
2209 // set unmasked area in dest to BLACK
2210 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2211 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
e3b81044
VZ
2212 if ( !::StretchBlt(GetHdc(), xdest, ydest, (int)dstWidth, (int)dstHeight,
2213 dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) )
4b7f2165 2214 {
e3b81044 2215 wxLogLastError(wxT("StretchBlt"));
4b7f2165
VZ
2216 }
2217 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
2218 ::SetTextColor(GetHdc(), prevCol);
2219
2220 // OR buffer to dest
2221 success = ::BitBlt(GetHdc(), xdest, ydest,
e3b81044 2222 (int)dstWidth, (int)dstHeight,
4b7f2165
VZ
2223 dc_buffer, 0, 0, SRCPAINT) != 0;
2224 if ( !success )
2225 {
f6bcfd97 2226 wxLogLastError(wxT("BitBlt"));
4b7f2165
VZ
2227 }
2228
2229 // tidy up temporary DCs and bitmap
62e1ba75
JS
2230 ::SelectObject(dc_mask, hOldMaskBitmap);
2231 ::SelectObject(dc_buffer, hOldBufferBitmap);
0cbff120 2232
27748047 2233#if !wxUSE_DC_CACHEING
0cbff120
JS
2234 {
2235 ::DeleteDC(dc_mask);
2236 ::DeleteDC(dc_buffer);
2237 ::DeleteObject(buffer_bmap);
2238 }
27748047 2239#endif
7bcb11d3
JS
2240 }
2241 }
4b7f2165 2242 else // no mask, just BitBlt() it
730bc726 2243 {
d80f416f
VZ
2244 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2245 // use StretchBlt() if available and finally fall back to BitBlt()
4676948b
JS
2246
2247 // FIXME: use appropriate WinCE functions
2248#ifndef __WXWINCE__
d80f416f
VZ
2249 const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS);
2250 if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) )
f178ab7e 2251 {
d80f416f
VZ
2252 DIBSECTION ds;
2253 wxZeroMemory(ds);
f178ab7e 2254
d80f416f
VZ
2255 if ( ::GetObject(GetHbitmapOf(bmpSrc),
2256 sizeof(ds),
2257 &ds) == sizeof(ds) )
2258 {
2259 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
2260
b9b1f368
VZ
2261 // Figure out what co-ordinate system we're supposed to specify
2262 // ysrc in.
2263 const LONG hDIB = ds.dsBmih.biHeight;
2264 if ( hDIB > 0 )
2265 {
2266 // reflect ysrc
e3b81044 2267 ysrc = hDIB - (ysrc + dstHeight);
b9b1f368
VZ
2268 }
2269
d80f416f
VZ
2270 if ( ::StretchDIBits(GetHdc(),
2271 xdest, ydest,
e3b81044 2272 dstWidth, dstHeight,
b9b1f368 2273 xsrc, ysrc,
e3b81044 2274 srcWidth, srcHeight,
d80f416f
VZ
2275 ds.dsBm.bmBits,
2276 (LPBITMAPINFO)&ds.dsBmih,
2277 DIB_RGB_COLORS,
b7a0abc7 2278 dwRop
d80f416f
VZ
2279 ) == (int)GDI_ERROR )
2280 {
85e7fb12
RD
2281 // On Win9x this API fails most (all?) of the time, so
2282 // logging it becomes quite distracting. Since it falls
2283 // back to the code below this is not really serious, so
35bbb0c6 2284 // don't log it.
85e7fb12 2285 //wxLogLastError(wxT("StretchDIBits"));
d80f416f
VZ
2286 }
2287 else
2288 {
beb966c5 2289 success = true;
d80f416f
VZ
2290 }
2291 }
f178ab7e 2292 }
d80f416f
VZ
2293
2294 if ( !success && (caps & RC_STRETCHBLT) )
419430a0
JS
2295#endif
2296 // __WXWINCE__
f178ab7e 2297 {
419430a0 2298#ifndef __WXWINCE__
d80f416f 2299 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
419430a0 2300#endif
d80f416f
VZ
2301
2302 if ( !::StretchBlt
2303 (
2304 GetHdc(),
e3b81044 2305 xdest, ydest, dstWidth, dstHeight,
888dde65 2306 GetHdcOf(*msw_impl),
e3b81044 2307 xsrc, ysrc, srcWidth, srcHeight,
d80f416f
VZ
2308 dwRop
2309 ) )
2310 {
2311 wxLogLastError(_T("StretchBlt"));
2312 }
2313 else
2314 {
beb966c5 2315 success = true;
d80f416f 2316 }
f178ab7e
VZ
2317 }
2318
4b7f2165 2319 if ( !success )
730bc726 2320 {
d80f416f
VZ
2321 if ( !::BitBlt
2322 (
2323 GetHdc(),
2324 xdest, ydest,
e3b81044 2325 (int)dstWidth, (int)dstHeight,
888dde65 2326 GetHdcOf(*msw_impl),
d80f416f
VZ
2327 xsrc, ysrc,
2328 dwRop
2329 ) )
2330 {
2331 wxLogLastError(_T("BitBlt"));
2332 }
2333 else
2334 {
beb966c5 2335 success = true;
d80f416f 2336 }
730bc726 2337 }
730bc726 2338 }
f178ab7e 2339
a23fd0e1
VZ
2340 ::SetTextColor(GetHdc(), old_textground);
2341 ::SetBkColor(GetHdc(), old_background);
2bda0e17 2342
a23fd0e1 2343 return success;
2bda0e17
KB
2344}
2345
888dde65 2346void wxMSWDCImpl::GetDeviceSize(int *width, int *height) const
2bda0e17 2347{
82a306b7 2348 WXMICROWIN_CHECK_HDC
d275c7eb 2349
7d09b97f
VZ
2350 if ( width )
2351 *width = ::GetDeviceCaps(GetHdc(), HORZRES);
2352 if ( height )
2353 *height = ::GetDeviceCaps(GetHdc(), VERTRES);
2bda0e17
KB
2354}
2355
888dde65 2356void wxMSWDCImpl::DoGetSizeMM(int *w, int *h) const
2bda0e17 2357{
82a306b7 2358 WXMICROWIN_CHECK_HDC
d275c7eb 2359
994a3786
VZ
2360 // if we implement it in terms of DoGetSize() instead of directly using the
2361 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2362 // will also work for wxWindowDC and wxClientDC even though their size is
2363 // not the same as the total size of the screen
2364 int wPixels, hPixels;
2365 DoGetSize(&wPixels, &hPixels);
2366
2367 if ( w )
2368 {
2369 int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES);
2370
2371 wxCHECK_RET( wTotal, _T("0 width device?") );
2372
2373 *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal;
2374 }
2375
2376 if ( h )
2377 {
2378 int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES);
2379
2380 wxCHECK_RET( hTotal, _T("0 height device?") );
2381
2382 *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal;
2383 }
7bcb11d3 2384}
2bda0e17 2385
888dde65 2386wxSize wxMSWDCImpl::GetPPI() const
7bcb11d3 2387{
c47addef 2388 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
d275c7eb 2389
a23fd0e1
VZ
2390 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
2391 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
2bda0e17 2392
a23fd0e1 2393 return wxSize(x, y);
2bda0e17
KB
2394}
2395
77ffb593 2396// For use by wxWidgets only, unless custom units are required.
888dde65 2397void wxMSWDCImpl::SetLogicalScale(double x, double y)
2bda0e17 2398{
82a306b7 2399 WXMICROWIN_CHECK_HDC
d275c7eb 2400
888dde65 2401 wxDCImpl::SetLogicalScale(x,y);
2bda0e17
KB
2402}
2403
878711c0
VZ
2404// ----------------------------------------------------------------------------
2405// DC caching
2406// ----------------------------------------------------------------------------
2407
0cbff120
JS
2408#if wxUSE_DC_CACHEING
2409
2410/*
2411 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2412 * improve it in due course, either using arrays, or simply storing pointers to one
2413 * entry for the bitmap, and two for the DCs. -- JACS
2414 */
2415
888dde65
RR
2416wxObjectList wxMSWDCImpl::sm_bitmapCache;
2417wxObjectList wxMSWDCImpl::sm_dcCache;
0cbff120
JS
2418
2419wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth)
2420{
2421 m_bitmap = hBitmap;
2422 m_dc = 0;
2423 m_width = w;
2424 m_height = h;
2425 m_depth = depth;
2426}
2427
2428wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
2429{
2430 m_bitmap = 0;
2431 m_dc = hDC;
2432 m_width = 0;
2433 m_height = 0;
2434 m_depth = depth;
2435}
2436
2437wxDCCacheEntry::~wxDCCacheEntry()
2438{
2439 if (m_bitmap)
2440 ::DeleteObject((HBITMAP) m_bitmap);
2441 if (m_dc)
2442 ::DeleteDC((HDC) m_dc);
2443}
2444
888dde65 2445wxDCCacheEntry* wxMSWDCImpl::FindBitmapInCache(WXHDC dc, int w, int h)
0cbff120
JS
2446{
2447 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
fc10daf3 2448 wxList::compatibility_iterator node = sm_bitmapCache.GetFirst();
0cbff120
JS
2449 while (node)
2450 {
4a9dba0e 2451 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
0cbff120
JS
2452
2453 if (entry->m_depth == depth)
2454 {
2455 if (entry->m_width < w || entry->m_height < h)
2456 {
2457 ::DeleteObject((HBITMAP) entry->m_bitmap);
2458 entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2459 if ( !entry->m_bitmap)
2460 {
2461 wxLogLastError(wxT("CreateCompatibleBitmap"));
2462 }
2463 entry->m_width = w; entry->m_height = h;
2464 return entry;
2465 }
2466 return entry;
2467 }
2468
4a9dba0e 2469 node = node->GetNext();
0cbff120
JS
2470 }
2471 WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2472 if ( !hBitmap)
2473 {
2474 wxLogLastError(wxT("CreateCompatibleBitmap"));
2475 }
2476 wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
2477 AddToBitmapCache(entry);
2478 return entry;
2479}
2480
888dde65 2481wxDCCacheEntry* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
0cbff120
JS
2482{
2483 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
fc10daf3 2484 wxList::compatibility_iterator node = sm_dcCache.GetFirst();
0cbff120
JS
2485 while (node)
2486 {
4a9dba0e 2487 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
0cbff120
JS
2488
2489 // Don't return the same one as we already have
2490 if (!notThis || (notThis != entry))
2491 {
2492 if (entry->m_depth == depth)
2493 {
2494 return entry;
2495 }
2496 }
2497
4a9dba0e 2498 node = node->GetNext();
0cbff120
JS
2499 }
2500 WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
2501 if ( !hDC)
2502 {
2503 wxLogLastError(wxT("CreateCompatibleDC"));
2504 }
2505 wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
2506 AddToDCCache(entry);
2507 return entry;
2508}
2509
888dde65 2510void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry* entry)
0cbff120
JS
2511{
2512 sm_bitmapCache.Append(entry);
2513}
2514
888dde65 2515void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry* entry)
0cbff120
JS
2516{
2517 sm_dcCache.Append(entry);
2518}
2519
888dde65 2520void wxMSWDCImpl::ClearCache()
0cbff120 2521{
fc10daf3
MB
2522 WX_CLEAR_LIST(wxList, sm_dcCache);
2523 WX_CLEAR_LIST(wxList, sm_bitmapCache);
0cbff120
JS
2524}
2525
aef94d68
JS
2526// Clean up cache at app exit
2527class wxDCModule : public wxModule
2528{
2529public:
beb966c5 2530 virtual bool OnInit() { return true; }
888dde65 2531 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
aef94d68
JS
2532
2533private:
2534 DECLARE_DYNAMIC_CLASS(wxDCModule)
2535};
2536
2537IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2538
878711c0
VZ
2539#endif // wxUSE_DC_CACHEING
2540
2541// ----------------------------------------------------------------------------
275a63e3 2542// alpha channel support
878711c0
VZ
2543// ----------------------------------------------------------------------------
2544
275a63e3 2545static bool AlphaBlt(HDC hdcDst,
e3b81044
VZ
2546 int x, int y, int dstWidth, int dstHeight,
2547 int srcX, int srcY,
2548 int srcWidth, int srcHeight,
2549 HDC hdcSrc,
275a63e3
VZ
2550 const wxBitmap& bmp)
2551{
2552 wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2553 wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") );
2554
2555 // do we have AlphaBlend() and company in the headers?
3080bf59 2556#if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
275a63e3
VZ
2557 // yes, now try to see if we have it during run-time
2558 typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
2559 HDC,int,int,int,int,
2560 BLENDFUNCTION);
2561
6ae7410f
VZ
2562 static AlphaBlend_t
2563 pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend"));
275a63e3
VZ
2564 if ( pfnAlphaBlend )
2565 {
2566 BLENDFUNCTION bf;
2567 bf.BlendOp = AC_SRC_OVER;
2568 bf.BlendFlags = 0;
2569 bf.SourceConstantAlpha = 0xff;
2570 bf.AlphaFormat = AC_SRC_ALPHA;
2571
e3b81044
VZ
2572 if ( pfnAlphaBlend(hdcDst, x, y, dstWidth, dstHeight,
2573 hdcSrc, srcX, srcY, srcWidth, srcHeight,
275a63e3
VZ
2574 bf) )
2575 {
2576 // skip wxAlphaBlend() call below
beb966c5 2577 return true;
275a63e3
VZ
2578 }
2579
2580 wxLogLastError(_T("AlphaBlend"));
2581 }
41e155b4
WS
2582#else
2583 wxUnusedVar(hdcSrc);
275a63e3
VZ
2584#endif // defined(AC_SRC_OVER)
2585
2586 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2587 // implementation
2588#ifdef wxHAVE_RAW_BITMAP
e3b81044 2589 wxAlphaBlend(hdcDst, x, y, dstWidth, dstHeight, srcX, srcY, srcWidth, srcHeight, bmp);
275a63e3 2590
beb966c5 2591 return true;
275a63e3
VZ
2592#else // !wxHAVE_RAW_BITMAP
2593 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2594 // alpha but at least something will be shown like this)
907173e5 2595 wxUnusedVar(bmp);
beb966c5 2596 return false;
275a63e3
VZ
2597#endif // wxHAVE_RAW_BITMAP
2598}
2599
2600
2601// wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
1e3c12d7 2602#ifdef wxHAVE_RAW_BITMAP
275a63e3 2603
878711c0 2604static void
761598d4 2605wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
e3b81044
VZ
2606 int dstWidth, int dstHeight,
2607 int srcX, int srcY,
2608 int srcWidth, int srcHeight,
2609 const wxBitmap& bmpSrc)
878711c0
VZ
2610{
2611 // get the destination DC pixels
e3b81044 2612 wxBitmap bmpDst(dstWidth, dstHeight, 32 /* force creating RGBA DIB */);
878711c0
VZ
2613 MemoryHDC hdcMem;
2614 SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
2615
e3b81044 2616 if ( !::BitBlt(hdcMem, 0, 0, dstWidth, dstHeight, hdcDst, xDst, yDst, SRCCOPY) )
878711c0
VZ
2617 {
2618 wxLogLastError(_T("BitBlt"));
2619 }
2620
2621 // combine them with the source bitmap using alpha
b9bcaf11 2622 wxAlphaPixelData dataDst(bmpDst),
a452af5e 2623 dataSrc((wxBitmap &)bmpSrc);
878711c0 2624
8ffc8f1f
VZ
2625 wxCHECK_RET( dataDst && dataSrc,
2626 _T("failed to get raw data in wxAlphaBlend") );
2627
b9bcaf11
VZ
2628 wxAlphaPixelData::Iterator pDst(dataDst),
2629 pSrc(dataSrc);
878711c0 2630
3db79902 2631
e3b81044 2632 for ( int y = 0; y < dstHeight; y++ )
878711c0 2633 {
e3b81044 2634 wxAlphaPixelData::Iterator pDstRowStart = pDst;
0c0d1521 2635
e3b81044 2636 for ( int x = 0; x < dstWidth; x++ )
878711c0 2637 {
e3b81044
VZ
2638 // source is point sampled, Alpha StretchBlit is ugly on Win95
2639 // (but does not impact performance)
2640 pSrc.MoveTo(dataSrc, srcX + (srcWidth*x/dstWidth), srcY + (srcHeight*y/dstHeight));
2641
878711c0
VZ
2642 // note that source bitmap uses premultiplied alpha (as required by
2643 // the real AlphaBlend)
2644 const unsigned beta = 255 - pSrc.Alpha();
2645
2646 pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255;
2647 pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255;
2648 pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255;
2649
2650 ++pDst;
878711c0
VZ
2651 }
2652
2653 pDst = pDstRowStart;
b9bcaf11 2654 pDst.OffsetY(dataDst, 1);
878711c0
VZ
2655 }
2656
2657 // and finally blit them back to the destination DC
e3b81044 2658 if ( !::BitBlt(hdcDst, xDst, yDst, dstWidth, dstHeight, hdcMem, 0, 0, SRCCOPY) )
878711c0
VZ
2659 {
2660 wxLogLastError(_T("BitBlt"));
2661 }
2662}
7b46ecac 2663
1e3c12d7 2664#endif // #ifdef wxHAVE_RAW_BITMAP
213ad8e7 2665
888dde65 2666void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
213ad8e7
VZ
2667 const wxColour& initialColour,
2668 const wxColour& destColour,
2669 wxDirection nDirection)
2670{
2671 // use native function if we have compile-time support it and can load it
2672 // during run-time (linking to it statically would make the program
2673 // unusable on earlier Windows versions)
2674#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2675 typedef BOOL
2676 (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
6ae7410f
VZ
2677 static GradientFill_t pfnGradientFill =
2678 (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill"));
213ad8e7
VZ
2679
2680 if ( pfnGradientFill )
2681 {
2682 GRADIENT_RECT grect;
2683 grect.UpperLeft = 0;
2684 grect.LowerRight = 1;
2685
2686 // invert colours direction if not filling from left-to-right or
2687 // top-to-bottom
2688 int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
2689
2690 // one vertex for upper left and one for upper-right
2691 TRIVERTEX vertices[2];
2692
2693 vertices[0].x = rect.GetLeft();
2694 vertices[0].y = rect.GetTop();
e6c46ffe
BW
2695 vertices[1].x = rect.GetRight()+1;
2696 vertices[1].y = rect.GetBottom()+1;
213ad8e7 2697
2e98a222
WS
2698 vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8);
2699 vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8);
2700 vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8);
213ad8e7 2701 vertices[firstVertex].Alpha = 0;
2e98a222
WS
2702 vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8);
2703 vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8);
2704 vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
213ad8e7
VZ
2705 vertices[1 - firstVertex].Alpha = 0;
2706
213ad8e7
VZ
2707 if ( (*pfnGradientFill)
2708 (
2709 GetHdc(),
2710 vertices,
2711 WXSIZEOF(vertices),
2712 &grect,
2713 1,
2714 nDirection == wxWEST || nDirection == wxEAST
2715 ? GRADIENT_FILL_RECT_H
2716 : GRADIENT_FILL_RECT_V
2717 ) )
2718 {
2719 // skip call of the base class version below
2720 return;
2721 }
2722
2723 wxLogLastError(_T("GradientFill"));
2724 }
2725#endif // wxUSE_DYNLIB_CLASS
2726
888dde65 2727 wxDCImpl::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
213ad8e7 2728}
6ae7410f 2729
a8ff046b
VZ
2730#if wxUSE_DYNLIB_CLASS
2731
6ae7410f
VZ
2732static DWORD wxGetDCLayout(HDC hdc)
2733{
2734 typedef DWORD (WINAPI *GetLayout_t)(HDC);
2735 static GetLayout_t
60b0c3b4 2736 wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(_T("gdi32.dll")));
6ae7410f 2737
60b0c3b4 2738 return s_pfnGetLayout ? s_pfnGetLayout(hdc) : (DWORD)-1;
6ae7410f
VZ
2739}
2740
888dde65 2741wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
6ae7410f
VZ
2742{
2743 DWORD layout = wxGetDCLayout(GetHdc());
2744
2745 if ( layout == (DWORD)-1 )
2746 return wxLayout_Default;
2747
2748 return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight;
2749}
2750
888dde65 2751void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
6ae7410f
VZ
2752{
2753 typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
2754 static SetLayout_t
60b0c3b4
VZ
2755 wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(_T("gdi32.dll")));
2756 if ( !s_pfnSetLayout )
6ae7410f
VZ
2757 return;
2758
2759 if ( dir == wxLayout_Default )
2760 {
2761 dir = wxTheApp->GetLayoutDirection();
2762 if ( dir == wxLayout_Default )
2763 return;
2764 }
2765
2766 DWORD layout = wxGetDCLayout(GetHdc());
2767 if ( dir == wxLayout_RightToLeft )
2768 layout |= LAYOUT_RTL;
2769 else
2770 layout &= ~LAYOUT_RTL;
2771
60b0c3b4 2772 s_pfnSetLayout(GetHdc(), layout);
6ae7410f 2773}
a8ff046b
VZ
2774
2775#else // !wxUSE_DYNLIB_CLASS
2776
2777// we can't provide RTL support without dynamic loading, so stub it out
888dde65 2778wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
a8ff046b
VZ
2779{
2780 return wxLayout_Default;
2781}
2782
888dde65 2783void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection WXUNUSED(dir))
a8ff046b
VZ
2784{
2785}
2786
2787#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS