1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/sysopt.h"
45 #include "wx/dcprint.h"
46 #include "wx/module.h"
47 #include "wx/dynload.h"
49 #ifdef wxHAVE_RAW_BITMAP
50 #include "wx/rawbmp.h"
55 #include "wx/msw/wrapcdlg.h"
61 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
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
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
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
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)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
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
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int w
, int h
,
134 int srcX
, int srcY
, HDC hdcSrc
,
135 const wxBitmap
& bmpSrc
);
137 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement
140 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmp
);
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 // instead of duplicating the same code which sets and then restores text
148 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
149 // encapsulate this in a small helper class
151 // wxColourChanger: changes the text colours in the ctor if required and
152 // restores them in the dtor
153 class wxColourChanger
156 wxColourChanger(wxDC
& dc
);
162 COLORREF m_colFgOld
, m_colBgOld
;
166 DECLARE_NO_COPY_CLASS(wxColourChanger
)
169 // this class saves the old stretch blit mode during its life time
170 class StretchBltModeChanger
173 StretchBltModeChanger(HDC hdc
,
174 int WXUNUSED_IN_WINCE(mode
))
178 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
180 wxLogLastError(_T("SetStretchBltMode"));
184 ~StretchBltModeChanger()
187 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
188 wxLogLastError(_T("SetStretchBltMode"));
197 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
200 // ===========================================================================
202 // ===========================================================================
204 // ----------------------------------------------------------------------------
206 // ----------------------------------------------------------------------------
208 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
210 const wxBrush
& brush
= dc
.GetBrush();
211 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
213 HDC hdc
= GetHdcOf(dc
);
214 m_colFgOld
= ::GetTextColor(hdc
);
215 m_colBgOld
= ::GetBkColor(hdc
);
217 // note that Windows convention is opposite to wxWidgets one, this is
218 // why text colour becomes the background one and vice versa
219 const wxColour
& colFg
= dc
.GetTextForeground();
222 ::SetBkColor(hdc
, colFg
.GetPixel());
225 const wxColour
& colBg
= dc
.GetTextBackground();
228 ::SetTextColor(hdc
, colBg
.GetPixel());
232 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
235 // flag which telsl us to undo changes in the dtor
240 // nothing done, nothing to undo
245 wxColourChanger::~wxColourChanger()
249 // restore the colours we changed
250 HDC hdc
= GetHdcOf(m_dc
);
252 ::SetBkMode(hdc
, TRANSPARENT
);
253 ::SetTextColor(hdc
, m_colFgOld
);
254 ::SetBkColor(hdc
, m_colBgOld
);
258 // ---------------------------------------------------------------------------
260 // ---------------------------------------------------------------------------
262 // Default constructor
273 #endif // wxUSE_PALETTE
283 SelectOldObjects(m_hDC
);
285 // if we own the HDC, we delete it, otherwise we just release it
289 ::DeleteDC(GetHdc());
291 else // we don't own our HDC
295 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
299 // Must have been a wxScreenDC
300 ::ReleaseDC((HWND
) NULL
, GetHdc());
306 // This will select current objects out of the DC,
307 // which is what you have to do before deleting the
309 void wxDC::SelectOldObjects(WXHDC dc
)
315 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
317 if (m_selectedBitmap
.Ok())
319 m_selectedBitmap
.SetSelectedInto(NULL
);
326 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
331 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
336 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
343 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
346 #endif // wxUSE_PALETTE
349 m_brush
= wxNullBrush
;
352 m_palette
= wxNullPalette
;
353 #endif // wxUSE_PALETTE
355 m_backgroundBrush
= wxNullBrush
;
356 m_selectedBitmap
= wxNullBitmap
;
359 // ---------------------------------------------------------------------------
361 // ---------------------------------------------------------------------------
363 void wxDC::UpdateClipBox()
368 ::GetClipBox(GetHdc(), &rect
);
370 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
371 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
372 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
373 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
377 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
379 // check if we should try to retrieve the clipping region possibly not set
380 // by our SetClippingRegion() but preset by Windows:this can only happen
381 // when we're associated with an existing HDC usign SetHDC(), see there
382 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
384 wxDC
*self
= wxConstCast(this, wxDC
);
385 self
->UpdateClipBox();
387 if ( !m_clipX1
&& !m_clipX2
)
388 self
->m_clipping
= false;
391 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
394 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
395 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
397 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
401 // note that we combine the new clipping region with the existing one: this
402 // is compatible with what the other ports do and is the documented
403 // behaviour now (starting with 2.3.3)
404 #if defined(__WXWINCE__)
406 if ( !::GetClipBox(GetHdc(), &rectClip
) )
409 // GetClipBox returns logical coordinates, so transform to device
410 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
411 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
412 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
413 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
415 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
416 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
417 rectClip
.right
, rectClip
.bottom
);
419 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
421 ::SelectClipRgn(GetHdc(), hrgnDest
);
424 ::DeleteObject(hrgnClipOld
);
425 ::DeleteObject(hrgnDest
);
427 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
429 wxLogLastError(_T("ExtSelectClipRgn"));
433 #endif // WinCE/!WinCE
440 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
442 // the region coords are always the device ones, so do the translation
445 // FIXME: possible +/-1 error here, to check!
446 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
448 LogicalToDeviceX(x
+ w
),
449 LogicalToDeviceY(y
+ h
));
452 wxLogLastError(_T("CreateRectRgn"));
456 SetClippingHrgn((WXHRGN
)hrgn
);
458 ::DeleteObject(hrgn
);
462 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
464 SetClippingHrgn(region
.GetHRGN());
467 void wxDC::DestroyClippingRegion()
471 if (m_clipping
&& m_hDC
)
473 // TODO: this should restore the previous clipping region,
474 // so that OnPaint processing works correctly, and the update
475 // clipping region doesn't get destroyed after the first
476 // DestroyClippingRegion.
477 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
478 ::SelectClipRgn(GetHdc(), rgn
);
482 wxDCBase::DestroyClippingRegion();
485 // ---------------------------------------------------------------------------
486 // query capabilities
487 // ---------------------------------------------------------------------------
489 bool wxDC::CanDrawBitmap() const
494 bool wxDC::CanGetTextExtent() const
496 #ifdef __WXMICROWIN__
497 // TODO Extend MicroWindows' GetDeviceCaps function
500 // What sort of display is it?
501 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
503 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
507 int wxDC::GetDepth() const
509 WXMICROWIN_CHECK_HDC_RET(16)
511 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
514 // ---------------------------------------------------------------------------
516 // ---------------------------------------------------------------------------
525 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
529 // No, I think we should simply ignore this if printing on e.g.
531 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
532 if (!m_selectedBitmap
.Ok())
535 rect
.left
= 0; rect
.top
= 0;
536 rect
.right
= m_selectedBitmap
.GetWidth();
537 rect
.bottom
= m_selectedBitmap
.GetHeight();
541 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
544 DWORD colour
= ::GetBkColor(GetHdc());
545 HBRUSH brush
= ::CreateSolidBrush(colour
);
546 ::FillRect(GetHdc(), &rect
, brush
);
547 ::DeleteObject(brush
);
550 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
551 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
553 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
555 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
556 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
557 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
558 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
562 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
563 wxCoord
WXUNUSED_IN_WINCE(y
),
564 const wxColour
& WXUNUSED_IN_WINCE(col
),
565 int WXUNUSED_IN_WINCE(style
))
570 WXMICROWIN_CHECK_HDC_RET(false)
572 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
574 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
575 : FLOODFILLBORDER
) ) ;
578 // quoting from the MSDN docs:
580 // Following are some of the reasons this function might fail:
582 // * The filling could not be completed.
583 // * The specified point has the boundary color specified by the
584 // crColor parameter (if FLOODFILLBORDER was requested).
585 // * The specified point does not have the color specified by
586 // crColor (if FLOODFILLSURFACE was requested)
587 // * The point is outside the clipping region that is, it is not
588 // visible on the device.
590 wxLogLastError(wxT("ExtFloodFill"));
593 CalcBoundingBox(x
, y
);
599 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
601 WXMICROWIN_CHECK_HDC_RET(false)
603 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
605 // get the color of the pixel
606 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
608 wxRGBToColour(*col
, pixelcolor
);
613 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
617 wxCoord x1
= x
-VIEWPORT_EXTENT
;
618 wxCoord y1
= y
-VIEWPORT_EXTENT
;
619 wxCoord x2
= x
+VIEWPORT_EXTENT
;
620 wxCoord y2
= y
+VIEWPORT_EXTENT
;
622 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
623 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
625 CalcBoundingBox(x1
, y1
);
626 CalcBoundingBox(x2
, y2
);
629 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
633 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
635 CalcBoundingBox(x1
, y1
);
636 CalcBoundingBox(x2
, y2
);
639 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
640 // and ending at (x2, y2)
641 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
642 wxCoord x2
, wxCoord y2
,
643 wxCoord xc
, wxCoord yc
)
646 // Slower emulation since WinCE doesn't support Pie and Arc
647 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
648 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
649 if( y1
>yc
) sa
= -sa
; // below center
650 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
651 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
656 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
660 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
661 wxCoord r
= (wxCoord
)radius
;
663 // treat the special case of full circle separately
664 if ( x1
== x2
&& y1
== y2
)
666 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
670 wxCoord xx1
= XLOG2DEV(x1
);
671 wxCoord yy1
= YLOG2DEV(y1
);
672 wxCoord xx2
= XLOG2DEV(x2
);
673 wxCoord yy2
= YLOG2DEV(y2
);
674 wxCoord xxc
= XLOG2DEV(xc
);
675 wxCoord yyc
= YLOG2DEV(yc
);
676 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
678 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
679 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
680 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
681 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
683 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
685 // Have to add 1 to bottom-right corner of rectangle
686 // to make semi-circles look right (crooked line otherwise).
687 // Unfortunately this is not a reliable method, depends
688 // on the size of shape.
689 // TODO: figure out why this happens!
690 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
694 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
697 CalcBoundingBox(xc
- r
, yc
- r
);
698 CalcBoundingBox(xc
+ r
, yc
+ r
);
702 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
703 wxCoord width
, wxCoord height
)
707 wxCoord x2
= x1
+ width
,
710 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
718 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
720 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
722 #else // Symantec-MicroWin
724 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
725 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
726 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
727 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
728 ::SetROP2(GetHdc(), R2_COPYPEN
);
729 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
730 MoveToEx(GetHdc(), x1
, y1
, NULL
);
731 LineTo(GetHdc(), x2
, y2
);
732 MoveToEx(GetHdc(), x2
, y1
, NULL
);
733 LineTo(GetHdc(), x1
, y2
);
734 ::SelectObject(GetHdc(), hPenOld
);
735 ::SelectObject(GetHdc(), hBrushOld
);
736 ::DeleteObject(blackPen
);
737 #endif // Win32/Symantec-MicroWin
739 CalcBoundingBox(x1
, y1
);
740 CalcBoundingBox(x2
, y2
);
743 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
747 COLORREF color
= 0x00ffffff;
750 color
= m_pen
.GetColour().GetPixel();
753 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
755 CalcBoundingBox(x
, y
);
758 void wxDC::DoDrawPolygon(int n
,
762 int WXUNUSED_IN_WINCE(fillStyle
))
766 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
768 // Do things less efficiently if we have offsets
769 if (xoffset
!= 0 || yoffset
!= 0)
771 POINT
*cpoints
= new POINT
[n
];
773 for (i
= 0; i
< n
; i
++)
775 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
776 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
778 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
781 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
783 (void)Polygon(GetHdc(), cpoints
, n
);
785 SetPolyFillMode(GetHdc(),prev
);
792 for (i
= 0; i
< n
; i
++)
793 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
796 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
798 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
800 SetPolyFillMode(GetHdc(),prev
);
806 wxDC::DoDrawPolyPolygon(int n
,
814 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
818 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
820 for (i
= cnt
= 0; i
< n
; i
++)
823 // Do things less efficiently if we have offsets
824 if (xoffset
!= 0 || yoffset
!= 0)
826 POINT
*cpoints
= new POINT
[cnt
];
827 for (i
= 0; i
< cnt
; i
++)
829 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
830 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
832 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
835 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
837 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
839 SetPolyFillMode(GetHdc(),prev
);
845 for (i
= 0; i
< cnt
; i
++)
846 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
849 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
851 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
853 SetPolyFillMode(GetHdc(),prev
);
860 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
864 // Do things less efficiently if we have offsets
865 if (xoffset
!= 0 || yoffset
!= 0)
867 POINT
*cpoints
= new POINT
[n
];
869 for (i
= 0; i
< n
; i
++)
871 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
872 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
874 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
876 (void)Polyline(GetHdc(), cpoints
, n
);
882 for (i
= 0; i
< n
; i
++)
883 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
885 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
889 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
893 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
895 wxCoord x2
= x
+ width
;
896 wxCoord y2
= y
+ height
;
898 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
901 rect
.left
= XLOG2DEV(x
);
902 rect
.top
= YLOG2DEV(y
);
903 rect
.right
= XLOG2DEV(x2
);
904 rect
.bottom
= YLOG2DEV(y2
);
905 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
909 // Windows draws the filled rectangles without outline (i.e. drawn with a
910 // transparent pen) one pixel smaller in both directions and we want them
911 // to have the same size regardless of which pen is used - adjust
913 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
914 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
916 // Apparently not needed for WinCE (see e.g. Life! demo)
923 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
927 CalcBoundingBox(x
, y
);
928 CalcBoundingBox(x2
, y2
);
931 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
935 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
937 // Now, a negative radius value is interpreted to mean
938 // 'the proportion of the smallest X or Y dimension'
942 double smallest
= (width
< height
) ? width
: height
;
943 radius
= (- radius
* smallest
);
946 wxCoord x2
= (x
+width
);
947 wxCoord y2
= (y
+height
);
949 // Windows draws the filled rectangles without outline (i.e. drawn with a
950 // transparent pen) one pixel smaller in both directions and we want them
951 // to have the same size regardless of which pen is used - adjust
952 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
958 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
959 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
961 CalcBoundingBox(x
, y
);
962 CalcBoundingBox(x2
, y2
);
965 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
969 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
971 wxCoord x2
= (x
+width
);
972 wxCoord y2
= (y
+height
);
974 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
976 CalcBoundingBox(x
, y
);
977 CalcBoundingBox(x2
, y2
);
980 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
981 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
984 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
989 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
994 int rx1
= XLOG2DEV(x
+w
/2);
995 int ry1
= YLOG2DEV(y
+h
/2);
1002 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1003 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1004 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1005 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1007 // draw pie with NULL_PEN first and then outline otherwise a line is
1008 // drawn from the start and end points to the centre
1009 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1012 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1013 rx1
, ry1
, rx2
, ry2
);
1017 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1018 rx1
, ry1
-1, rx2
, ry2
-1);
1021 ::SelectObject(GetHdc(), hpenOld
);
1023 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1024 rx1
, ry1
, rx2
, ry2
);
1026 CalcBoundingBox(x
, y
);
1027 CalcBoundingBox(x2
, y2
);
1031 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1033 WXMICROWIN_CHECK_HDC
1035 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1038 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1040 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1043 CalcBoundingBox(x
, y
);
1044 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1047 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1049 WXMICROWIN_CHECK_HDC
1051 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1053 int width
= bmp
.GetWidth(),
1054 height
= bmp
.GetHeight();
1056 HBITMAP hbmpMask
= 0;
1059 HPALETTE oldPal
= 0;
1060 #endif // wxUSE_PALETTE
1062 if ( bmp
.HasAlpha() )
1065 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1067 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1073 wxMask
*mask
= bmp
.GetMask();
1075 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1079 // don't give assert here because this would break existing
1080 // programs - just silently ignore useMask parameter
1087 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1089 // On some systems, MaskBlt succeeds yet is much much slower
1090 // than the wxWidgets fall-back implementation. So we need
1091 // to be able to switch this on and off at runtime.
1093 #if wxUSE_SYSTEM_OPTIONS
1094 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1098 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1099 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1101 wxPalette
*pal
= bmp
.GetPalette();
1102 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1104 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1105 ::RealizePalette(hdcMem
);
1107 #endif // wxUSE_PALETTE
1109 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1112 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1116 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1117 #endif // wxUSE_PALETTE
1119 ::SelectObject(hdcMem
, hOldBitmap
);
1126 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1129 memDC
.SelectObject(bmp
);
1131 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1133 memDC
.SelectObject(wxNullBitmap
);
1136 else // no mask, just use BitBlt()
1139 HDC memdc
= ::CreateCompatibleDC( cdc
);
1140 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1142 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1144 COLORREF old_textground
= ::GetTextColor(GetHdc());
1145 COLORREF old_background
= ::GetBkColor(GetHdc());
1146 if (m_textForegroundColour
.Ok())
1148 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1150 if (m_textBackgroundColour
.Ok())
1152 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1156 wxPalette
*pal
= bmp
.GetPalette();
1157 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1159 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1160 ::RealizePalette(memdc
);
1162 #endif // wxUSE_PALETTE
1164 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1165 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1169 ::SelectPalette(memdc
, oldPal
, FALSE
);
1170 #endif // wxUSE_PALETTE
1172 ::SelectObject( memdc
, hOldBitmap
);
1173 ::DeleteDC( memdc
);
1175 ::SetTextColor(GetHdc(), old_textground
);
1176 ::SetBkColor(GetHdc(), old_background
);
1180 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1182 WXMICROWIN_CHECK_HDC
1184 DrawAnyText(text
, x
, y
);
1186 // update the bounding box
1187 CalcBoundingBox(x
, y
);
1190 GetTextExtent(text
, &w
, &h
);
1191 CalcBoundingBox(x
+ w
, y
+ h
);
1194 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1196 WXMICROWIN_CHECK_HDC
1198 // prepare for drawing the text
1199 if ( m_textForegroundColour
.Ok() )
1200 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1202 DWORD old_background
= 0;
1203 if ( m_textBackgroundColour
.Ok() )
1205 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1208 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1212 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1213 text
.c_str(), text
.length(), NULL
) == 0 )
1215 wxLogLastError(wxT("TextOut"));
1218 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1219 text
.c_str(), text
.length()) == 0 )
1221 wxLogLastError(wxT("TextOut"));
1225 // restore the old parameters (text foreground colour may be left because
1226 // it never is set to anything else, but background should remain
1227 // transparent even if we just drew an opaque string)
1228 if ( m_textBackgroundColour
.Ok() )
1229 (void)SetBkColor(GetHdc(), old_background
);
1231 SetBkMode(GetHdc(), TRANSPARENT
);
1234 void wxDC::DoDrawRotatedText(const wxString
& text
,
1235 wxCoord x
, wxCoord y
,
1238 WXMICROWIN_CHECK_HDC
1240 // we test that we have some font because otherwise we should still use the
1241 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1242 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1243 // font for drawing rotated fonts unfortunately)
1244 if ( (angle
== 0.0) && m_font
.Ok() )
1246 DoDrawText(text
, x
, y
);
1248 #ifndef __WXMICROWIN__
1251 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1252 // because it's not TrueType and so can't have non zero
1253 // orientation/escapement under Win9x
1254 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1255 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1257 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1259 wxLogLastError(wxT("GetObject(hfont)"));
1262 // GDI wants the angle in tenth of degree
1263 long angle10
= (long)(angle
* 10);
1264 lf
.lfEscapement
= angle10
;
1265 lf
. lfOrientation
= angle10
;
1267 hfont
= ::CreateFontIndirect(&lf
);
1270 wxLogLastError(wxT("CreateFont"));
1274 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1276 DrawAnyText(text
, x
, y
);
1278 (void)::SelectObject(GetHdc(), hfontOld
);
1279 (void)::DeleteObject(hfont
);
1282 // call the bounding box by adding all four vertices of the rectangle
1283 // containing the text to it (simpler and probably not slower than
1284 // determining which of them is really topmost/leftmost/...)
1286 GetTextExtent(text
, &w
, &h
);
1288 double rad
= DegToRad(angle
);
1290 // "upper left" and "upper right"
1291 CalcBoundingBox(x
, y
);
1292 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1294 // "bottom left" and "bottom right"
1295 x
+= (wxCoord
)(h
*sin(rad
));
1296 y
+= (wxCoord
)(h
*cos(rad
));
1297 CalcBoundingBox(x
, y
);
1298 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1303 // ---------------------------------------------------------------------------
1305 // ---------------------------------------------------------------------------
1309 void wxDC::DoSelectPalette(bool realize
)
1311 WXMICROWIN_CHECK_HDC
1313 // Set the old object temporarily, in case the assignment deletes an object
1314 // that's not yet selected out.
1317 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1321 if ( m_palette
.Ok() )
1323 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1324 GetHpaletteOf(m_palette
),
1327 m_oldPalette
= (WXHPALETTE
) oldPal
;
1330 ::RealizePalette(GetHdc());
1334 void wxDC::SetPalette(const wxPalette
& palette
)
1338 m_palette
= palette
;
1339 DoSelectPalette(true);
1343 void wxDC::InitializePalette()
1345 if ( wxDisplayDepth() <= 8 )
1347 // look for any window or parent that has a custom palette. If any has
1348 // one then we need to use it in drawing operations
1349 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1351 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1352 if ( m_hasCustomPalette
)
1354 m_palette
= win
->GetPalette();
1356 // turn on MSW translation for this palette
1362 #endif // wxUSE_PALETTE
1364 // SetFont/Pen/Brush() really ask to be implemented as a single template
1365 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1367 void wxDC::SetFont(const wxFont
& font
)
1369 WXMICROWIN_CHECK_HDC
1371 if ( font
== m_font
)
1376 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1377 if ( hfont
== HGDI_ERROR
)
1379 wxLogLastError(_T("SelectObject(font)"));
1384 m_oldFont
= (WXHPEN
)hfont
;
1389 else // invalid font, reset the current font
1393 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1395 wxLogLastError(_T("SelectObject(old font)"));
1401 m_font
= wxNullFont
;
1405 void wxDC::SetPen(const wxPen
& pen
)
1407 WXMICROWIN_CHECK_HDC
1414 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1415 if ( hpen
== HGDI_ERROR
)
1417 wxLogLastError(_T("SelectObject(pen)"));
1422 m_oldPen
= (WXHPEN
)hpen
;
1427 else // invalid pen, reset the current pen
1431 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1433 wxLogLastError(_T("SelectObject(old pen)"));
1443 void wxDC::SetBrush(const wxBrush
& brush
)
1445 WXMICROWIN_CHECK_HDC
1447 if ( brush
== m_brush
)
1452 // we must make sure the brush is aligned with the logical coordinates
1453 // before selecting it
1454 wxBitmap
*stipple
= brush
.GetStipple();
1455 if ( stipple
&& stipple
->Ok() )
1457 if ( !::SetBrushOrgEx
1460 m_deviceOriginX
% stipple
->GetWidth(),
1461 m_deviceOriginY
% stipple
->GetHeight(),
1462 NULL
// [out] previous brush origin
1465 wxLogLastError(_T("SetBrushOrgEx()"));
1469 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1470 if ( hbrush
== HGDI_ERROR
)
1472 wxLogLastError(_T("SelectObject(brush)"));
1477 m_oldBrush
= (WXHPEN
)hbrush
;
1482 else // invalid brush, reset the current brush
1486 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1488 wxLogLastError(_T("SelectObject(old brush)"));
1494 m_brush
= wxNullBrush
;
1498 void wxDC::SetBackground(const wxBrush
& brush
)
1500 WXMICROWIN_CHECK_HDC
1502 m_backgroundBrush
= brush
;
1504 if ( m_backgroundBrush
.Ok() )
1506 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1510 void wxDC::SetBackgroundMode(int mode
)
1512 WXMICROWIN_CHECK_HDC
1514 m_backgroundMode
= mode
;
1516 // SetBackgroundColour now only refers to text background
1517 // and m_backgroundMode is used there
1520 void wxDC::SetLogicalFunction(int function
)
1522 WXMICROWIN_CHECK_HDC
1524 m_logicalFunction
= function
;
1529 void wxDC::SetRop(WXHDC dc
)
1531 if ( !dc
|| m_logicalFunction
< 0 )
1536 switch (m_logicalFunction
)
1538 case wxCLEAR
: rop
= R2_BLACK
; break;
1539 case wxXOR
: rop
= R2_XORPEN
; break;
1540 case wxINVERT
: rop
= R2_NOT
; break;
1541 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1542 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1543 case wxCOPY
: rop
= R2_COPYPEN
; break;
1544 case wxAND
: rop
= R2_MASKPEN
; break;
1545 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1546 case wxNO_OP
: rop
= R2_NOP
; break;
1547 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1548 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1549 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1550 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1551 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1552 case wxOR
: rop
= R2_MERGEPEN
; break;
1553 case wxSET
: rop
= R2_WHITE
; break;
1556 wxFAIL_MSG( wxT("unsupported logical function") );
1560 SetROP2(GetHdc(), rop
);
1563 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1565 // We might be previewing, so return true to let it continue.
1573 void wxDC::StartPage()
1577 void wxDC::EndPage()
1581 // ---------------------------------------------------------------------------
1583 // ---------------------------------------------------------------------------
1585 wxCoord
wxDC::GetCharHeight() const
1587 WXMICROWIN_CHECK_HDC_RET(0)
1589 TEXTMETRIC lpTextMetric
;
1591 GetTextMetrics(GetHdc(), &lpTextMetric
);
1593 return lpTextMetric
.tmHeight
;
1596 wxCoord
wxDC::GetCharWidth() const
1598 WXMICROWIN_CHECK_HDC_RET(0)
1600 TEXTMETRIC lpTextMetric
;
1602 GetTextMetrics(GetHdc(), &lpTextMetric
);
1604 return lpTextMetric
.tmAveCharWidth
;
1607 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1608 wxCoord
*descent
, wxCoord
*externalLeading
,
1611 #ifdef __WXMICROWIN__
1616 if (descent
) *descent
= 0;
1617 if (externalLeading
) *externalLeading
= 0;
1620 #endif // __WXMICROWIN__
1625 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1627 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1629 else // don't change the font
1637 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1638 GetTextMetrics(GetHdc(), &tm
);
1645 *descent
= tm
.tmDescent
;
1646 if (externalLeading
)
1647 *externalLeading
= tm
.tmExternalLeading
;
1651 ::SelectObject(GetHdc(), hfontOld
);
1656 // Each element of the array will be the width of the string up to and
1657 // including the coresoponding character in text.
1659 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1661 static int maxLenText
= -1;
1662 static int maxWidth
= -1;
1665 int stlen
= text
.Length();
1667 if (maxLenText
== -1)
1669 // Win9x and WinNT+ have different limits
1670 int version
= wxGetOsVersion();
1671 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1672 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1676 widths
.Add(0, stlen
); // fill the array with zeros
1678 if (!::GetTextExtentExPoint(GetHdc(),
1679 text
.c_str(), // string to check
1680 wxMin(stlen
, maxLenText
),
1682 &fit
, // [out] count of chars
1684 &widths
[0], // array to fill
1688 wxLogLastError(wxT("GetTextExtentExPoint"));
1698 void wxDC::SetMapMode(int mode
)
1700 WXMICROWIN_CHECK_HDC
1702 m_mappingMode
= mode
;
1704 if ( mode
== wxMM_TEXT
)
1707 m_logicalScaleY
= 1.0;
1709 else // need to do some calculations
1711 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1712 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1713 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1714 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1716 if ( (mm_width
== 0) || (mm_height
== 0) )
1718 // we can't calculate mm2pixels[XY] then!
1722 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1723 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1728 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1729 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1733 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1734 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1738 m_logicalScaleX
= mm2pixelsX
;
1739 m_logicalScaleY
= mm2pixelsY
;
1743 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1744 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1748 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1752 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1753 // cases we could do with MM_TEXT and in the remaining 0.9% with
1754 // MM_ISOTROPIC (TODO!)
1756 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1758 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1759 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1761 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1762 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1764 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1765 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1769 void wxDC::SetUserScale(double x
, double y
)
1771 WXMICROWIN_CHECK_HDC
1773 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1779 this->SetMapMode(m_mappingMode
);
1782 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1783 bool WXUNUSED_IN_WINCE(yBottomUp
))
1785 WXMICROWIN_CHECK_HDC
1788 int signX
= xLeftRight
? 1 : -1,
1789 signY
= yBottomUp
? -1 : 1;
1791 if ( signX
!= m_signX
|| signY
!= m_signY
)
1796 SetMapMode(m_mappingMode
);
1801 void wxDC::SetSystemScale(double x
, double y
)
1803 WXMICROWIN_CHECK_HDC
1805 if ( x
== m_scaleX
&& y
== m_scaleY
)
1812 SetMapMode(m_mappingMode
);
1816 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1818 WXMICROWIN_CHECK_HDC
1820 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1823 m_logicalOriginX
= x
;
1824 m_logicalOriginY
= y
;
1827 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1831 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1833 WXMICROWIN_CHECK_HDC
1835 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1838 m_deviceOriginX
= x
;
1839 m_deviceOriginY
= y
;
1841 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1844 // ---------------------------------------------------------------------------
1845 // coordinates transformations
1846 // ---------------------------------------------------------------------------
1848 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1850 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1853 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1855 // axis orientation is not taken into account for conversion of a distance
1856 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1859 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1861 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1864 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1866 // axis orientation is not taken into account for conversion of a distance
1867 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1870 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1872 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1875 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1877 // axis orientation is not taken into account for conversion of a distance
1878 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1881 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1883 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1886 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1888 // axis orientation is not taken into account for conversion of a distance
1889 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1892 // ---------------------------------------------------------------------------
1894 // ---------------------------------------------------------------------------
1896 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1897 wxCoord width
, wxCoord height
,
1898 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1899 int rop
, bool useMask
,
1900 wxCoord xsrcMask
, wxCoord ysrcMask
)
1902 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1904 WXMICROWIN_CHECK_HDC_RET(false)
1906 // if either the source or destination has alpha channel, we must use
1907 // AlphaBlt() as other function don't handle it correctly
1908 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1909 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1910 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1912 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1913 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
1917 wxMask
*mask
= NULL
;
1920 mask
= bmpSrc
.GetMask();
1922 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1924 // don't give assert here because this would break existing
1925 // programs - just silently ignore useMask parameter
1930 if (xsrcMask
== -1 && ysrcMask
== -1)
1932 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1935 COLORREF old_textground
= ::GetTextColor(GetHdc());
1936 COLORREF old_background
= ::GetBkColor(GetHdc());
1937 if (m_textForegroundColour
.Ok())
1939 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1941 if (m_textBackgroundColour
.Ok())
1943 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1949 case wxXOR
: dwRop
= SRCINVERT
; break;
1950 case wxINVERT
: dwRop
= DSTINVERT
; break;
1951 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1952 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1953 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1954 case wxSET
: dwRop
= WHITENESS
; break;
1955 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1956 case wxAND
: dwRop
= SRCAND
; break;
1957 case wxOR
: dwRop
= SRCPAINT
; break;
1958 case wxEQUIV
: dwRop
= 0x00990066; break;
1959 case wxNAND
: dwRop
= 0x007700E6; break;
1960 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1961 case wxCOPY
: dwRop
= SRCCOPY
; break;
1962 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1963 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1964 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1966 wxFAIL_MSG( wxT("unsupported logical function") );
1970 bool success
= false;
1975 // we want the part of the image corresponding to the mask to be
1976 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1977 // meaning of fg and bg is inverted which corresponds to wxWin notion
1978 // of the mask which is also contrary to the Windows one)
1980 // On some systems, MaskBlt succeeds yet is much much slower
1981 // than the wxWidgets fall-back implementation. So we need
1982 // to be able to switch this on and off at runtime.
1983 #if wxUSE_SYSTEM_OPTIONS
1984 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1990 xdest
, ydest
, width
, height
,
1993 (HBITMAP
)mask
->GetMaskBitmap(),
1995 MAKEROP4(dwRop
, DSTCOPY
)
2002 // Blit bitmap with mask
2005 HBITMAP buffer_bmap
;
2007 #if wxUSE_DC_CACHEING
2008 // create a temp buffer bitmap and DCs to access it and the mask
2009 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2010 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2012 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2013 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2015 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2018 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2019 #else // !wxUSE_DC_CACHEING
2020 // create a temp buffer bitmap and DCs to access it and the mask
2021 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2022 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2023 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2024 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2025 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2026 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2028 // copy dest to buffer
2029 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2030 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2032 wxLogLastError(wxT("BitBlt"));
2035 // copy src to buffer using selected raster op
2036 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2037 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2039 wxLogLastError(wxT("BitBlt"));
2042 // set masked area in buffer to BLACK (pixel value 0)
2043 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2044 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2045 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2046 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2048 wxLogLastError(wxT("BitBlt"));
2051 // set unmasked area in dest to BLACK
2052 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2053 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2054 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2055 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2057 wxLogLastError(wxT("BitBlt"));
2059 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2060 ::SetTextColor(GetHdc(), prevCol
);
2062 // OR buffer to dest
2063 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2064 (int)width
, (int)height
,
2065 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2068 wxLogLastError(wxT("BitBlt"));
2071 // tidy up temporary DCs and bitmap
2072 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2073 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2075 #if !wxUSE_DC_CACHEING
2077 ::DeleteDC(dc_mask
);
2078 ::DeleteDC(dc_buffer
);
2079 ::DeleteObject(buffer_bmap
);
2084 else // no mask, just BitBlt() it
2086 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2087 // use StretchBlt() if available and finally fall back to BitBlt()
2089 // FIXME: use appropriate WinCE functions
2091 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2092 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2097 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2099 &ds
) == sizeof(ds
) )
2101 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2103 // Figure out what co-ordinate system we're supposed to specify
2105 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2109 ysrc
= hDIB
- (ysrc
+ height
);
2112 if ( ::StretchDIBits(GetHdc(),
2118 (LPBITMAPINFO
)&ds
.dsBmih
,
2121 ) == (int)GDI_ERROR
)
2123 // On Win9x this API fails most (all?) of the time, so
2124 // logging it becomes quite distracting. Since it falls
2125 // back to the code below this is not really serious, so
2127 //wxLogLastError(wxT("StretchDIBits"));
2136 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2141 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2147 xdest
, ydest
, width
, height
,
2149 xsrc
, ysrc
, width
, height
,
2153 wxLogLastError(_T("StretchBlt"));
2167 (int)width
, (int)height
,
2173 wxLogLastError(_T("BitBlt"));
2182 ::SetTextColor(GetHdc(), old_textground
);
2183 ::SetBkColor(GetHdc(), old_background
);
2188 void wxDC::DoGetSize(int *w
, int *h
) const
2190 WXMICROWIN_CHECK_HDC
2192 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2193 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2196 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2198 WXMICROWIN_CHECK_HDC
2200 // if we implement it in terms of DoGetSize() instead of directly using the
2201 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2202 // will also work for wxWindowDC and wxClientDC even though their size is
2203 // not the same as the total size of the screen
2204 int wPixels
, hPixels
;
2205 DoGetSize(&wPixels
, &hPixels
);
2209 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2211 wxCHECK_RET( wTotal
, _T("0 width device?") );
2213 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2218 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2220 wxCHECK_RET( hTotal
, _T("0 height device?") );
2222 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2226 wxSize
wxDC::GetPPI() const
2228 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2230 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2231 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2233 return wxSize(x
, y
);
2236 // For use by wxWidgets only, unless custom units are required.
2237 void wxDC::SetLogicalScale(double x
, double y
)
2239 WXMICROWIN_CHECK_HDC
2241 m_logicalScaleX
= x
;
2242 m_logicalScaleY
= y
;
2245 // ----------------------------------------------------------------------------
2247 // ----------------------------------------------------------------------------
2249 #if wxUSE_DC_CACHEING
2252 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2253 * improve it in due course, either using arrays, or simply storing pointers to one
2254 * entry for the bitmap, and two for the DCs. -- JACS
2257 wxList
wxDC::sm_bitmapCache
;
2258 wxList
wxDC::sm_dcCache
;
2260 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2269 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2278 wxDCCacheEntry::~wxDCCacheEntry()
2281 ::DeleteObject((HBITMAP
) m_bitmap
);
2283 ::DeleteDC((HDC
) m_dc
);
2286 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2288 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2289 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2292 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2294 if (entry
->m_depth
== depth
)
2296 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2298 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2299 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2300 if ( !entry
->m_bitmap
)
2302 wxLogLastError(wxT("CreateCompatibleBitmap"));
2304 entry
->m_width
= w
; entry
->m_height
= h
;
2310 node
= node
->GetNext();
2312 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2315 wxLogLastError(wxT("CreateCompatibleBitmap"));
2317 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2318 AddToBitmapCache(entry
);
2322 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2324 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2325 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2328 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2330 // Don't return the same one as we already have
2331 if (!notThis
|| (notThis
!= entry
))
2333 if (entry
->m_depth
== depth
)
2339 node
= node
->GetNext();
2341 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2344 wxLogLastError(wxT("CreateCompatibleDC"));
2346 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2347 AddToDCCache(entry
);
2351 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2353 sm_bitmapCache
.Append(entry
);
2356 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2358 sm_dcCache
.Append(entry
);
2361 void wxDC::ClearCache()
2363 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2364 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2367 // Clean up cache at app exit
2368 class wxDCModule
: public wxModule
2371 virtual bool OnInit() { return true; }
2372 virtual void OnExit() { wxDC::ClearCache(); }
2375 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2378 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2380 #endif // wxUSE_DC_CACHEING
2382 // ----------------------------------------------------------------------------
2383 // alpha channel support
2384 // ----------------------------------------------------------------------------
2386 static bool AlphaBlt(HDC hdcDst
,
2387 int x
, int y
, int width
, int height
,
2388 int srcX
, int srcY
, HDC hdcSrc
,
2389 const wxBitmap
& bmp
)
2391 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2392 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2394 // do we have AlphaBlend() and company in the headers?
2395 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2396 // yes, now try to see if we have it during run-time
2397 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2398 HDC
,int,int,int,int,
2401 // bitmaps can be drawn only from GUI thread so there is no need to
2402 // protect this static variable from multiple threads
2403 static bool s_triedToLoad
= false;
2404 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2405 if ( !s_triedToLoad
)
2407 s_triedToLoad
= true;
2409 // don't give errors about the DLL being unavailable, we're
2410 // prepared to handle this
2413 wxDynamicLibrary
dll(_T("msimg32.dll"));
2414 if ( dll
.IsLoaded() )
2416 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2417 if ( pfnAlphaBlend
)
2419 // we must keep the DLL loaded if we want to be able to
2420 // call AlphaBlend() so just never unload it at all, not a
2427 if ( pfnAlphaBlend
)
2430 bf
.BlendOp
= AC_SRC_OVER
;
2432 bf
.SourceConstantAlpha
= 0xff;
2433 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2435 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2436 hdcSrc
, srcX
, srcY
, width
, height
,
2439 // skip wxAlphaBlend() call below
2443 wxLogLastError(_T("AlphaBlend"));
2445 #endif // defined(AC_SRC_OVER)
2447 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2449 #ifdef wxHAVE_RAW_BITMAP
2450 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2453 #else // !wxHAVE_RAW_BITMAP
2454 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2455 // alpha but at least something will be shown like this)
2458 #endif // wxHAVE_RAW_BITMAP
2462 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2463 #ifdef wxHAVE_RAW_BITMAP
2466 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2468 // get the destination DC pixels
2469 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2471 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2473 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2475 wxLogLastError(_T("BitBlt"));
2478 // combine them with the source bitmap using alpha
2479 wxAlphaPixelData
dataDst(bmpDst
),
2480 dataSrc((wxBitmap
&)bmpSrc
);
2482 wxCHECK_RET( dataDst
&& dataSrc
,
2483 _T("failed to get raw data in wxAlphaBlend") );
2485 wxAlphaPixelData::Iterator
pDst(dataDst
),
2488 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2490 for ( int y
= 0; y
< h
; y
++ )
2492 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2493 pSrcRowStart
= pSrc
;
2495 for ( int x
= 0; x
< w
; x
++ )
2497 // note that source bitmap uses premultiplied alpha (as required by
2498 // the real AlphaBlend)
2499 const unsigned beta
= 255 - pSrc
.Alpha();
2501 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2502 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2503 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2509 pDst
= pDstRowStart
;
2510 pSrc
= pSrcRowStart
;
2511 pDst
.OffsetY(dataDst
, 1);
2512 pSrc
.OffsetY(dataSrc
, 1);
2515 // and finally blit them back to the destination DC
2516 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2518 wxLogLastError(_T("BitBlt"));
2522 #endif // #ifdef wxHAVE_RAW_BITMAP