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