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