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