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