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