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