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