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