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