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