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