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