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