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