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