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