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