/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/dc.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/dc.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (9 years, 11 months ago) by william
File size: 80284 byte(s)
branching from upstream revision (http://pcsx2.googlecode.com/svn/trunk
): r3113 to
https://svn.netsolutions.dnsalias.com/websvn/ps2/pcsx2/pcsx2_0.9.7/branch/r3113_0.9.7_beta
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 49338 2007-10-22 18:07:45Z RD $
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
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:
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
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!
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
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
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
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
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.
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
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
402 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()
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
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
487 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
488 {
489 SetClippingHrgn(region.GetHRGN());
490 }
491
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
523 bool wxDC::CanDrawBitmap() const
524 {
525 return true;
526 }
527
528 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
541 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
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
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
633 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
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
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)
675 void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
676 wxCoord x2, wxCoord y2,
677 wxCoord xc, wxCoord yc)
678 {
679 #ifdef __WXWINCE__
680 // Slower emulation since WinCE doesn't support Pie and Arc
681 double r = sqrt( (x1-xc)*(x1-xc) + (y1-yc)*(y1-yc) );
682 double sa = acos((x1-xc)/r)/M_PI*180; // between 0 and 180
683 if( y1>yc ) sa = -sa; // below center
684 double ea = atan2(yc-y2, x2-xc)/M_PI*180;
685 DoDrawEllipticArcRot( xc-r, yc-r, 2*r, 2*r, sa, ea );
686 #else
687
688 WXMICROWIN_CHECK_HDC
689
690 wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
691
692 double dx = xc - x1;
693 double dy = yc - y1;
694 double radius = (double)sqrt(dx*dx+dy*dy);
695 wxCoord r = (wxCoord)radius;
696
697 // treat the special case of full circle separately
698 if ( x1 == x2 && y1 == y2 )
699 {
700 DrawEllipse(xc - r, yc - r, 2*r, 2*r);
701 return;
702 }
703
704 wxCoord xx1 = XLOG2DEV(x1);
705 wxCoord yy1 = YLOG2DEV(y1);
706 wxCoord xx2 = XLOG2DEV(x2);
707 wxCoord yy2 = YLOG2DEV(y2);
708 wxCoord xxc = XLOG2DEV(xc);
709 wxCoord yyc = YLOG2DEV(yc);
710 wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1)));
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
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
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
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
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
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
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
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
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
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
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
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
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 if ( useMask )
1202 {
1203 wxMask *mask = bmp.GetMask();
1204 if ( mask )
1205 hbmpMask = (HBITMAP)mask->GetMaskBitmap();
1206
1207 if ( !hbmpMask )
1208 {
1209 // don't give assert here because this would break existing
1210 // programs - just silently ignore useMask parameter
1211 useMask = false;
1212 }
1213 }
1214 if ( useMask )
1215 {
1216 #ifdef __WIN32__
1217 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1218 // points
1219 // On some systems, MaskBlt succeeds yet is much much slower
1220 // than the wxWidgets fall-back implementation. So we need
1221 // to be able to switch this on and off at runtime.
1222 bool ok = false;
1223 #if wxUSE_SYSTEM_OPTIONS
1224 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1225 #endif
1226 {
1227 HDC cdc = GetHdc();
1228 HDC hdcMem = ::CreateCompatibleDC(GetHdc());
1229 HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp));
1230 #if wxUSE_PALETTE
1231 wxPalette *pal = bmp.GetPalette();
1232 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1233 {
1234 oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE);
1235 ::RealizePalette(hdcMem);
1236 }
1237 #endif // wxUSE_PALETTE
1238
1239 ok = ::MaskBlt(cdc, x, y, width, height,
1240 hdcMem, 0, 0,
1241 hbmpMask, 0, 0,
1242 MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
1243
1244 #if wxUSE_PALETTE
1245 if (oldPal)
1246 ::SelectPalette(hdcMem, oldPal, FALSE);
1247 #endif // wxUSE_PALETTE
1248
1249 ::SelectObject(hdcMem, hOldBitmap);
1250 ::DeleteDC(hdcMem);
1251 }
1252
1253 if ( !ok )
1254 #endif // Win32
1255 {
1256 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1257 // level
1258 wxMemoryDC memDC;
1259
1260 memDC.SelectObjectAsSource(bmp);
1261
1262 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
1263
1264 memDC.SelectObject(wxNullBitmap);
1265 }
1266 }
1267 else // no mask, just use BitBlt()
1268 {
1269 HDC cdc = GetHdc();
1270 HDC memdc = ::CreateCompatibleDC( cdc );
1271 HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
1272
1273 wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
1274
1275 COLORREF old_textground = ::GetTextColor(GetHdc());
1276 COLORREF old_background = ::GetBkColor(GetHdc());
1277 if (m_textForegroundColour.Ok())
1278 {
1279 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
1280 }
1281 if (m_textBackgroundColour.Ok())
1282 {
1283 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1284 }
1285
1286 #if wxUSE_PALETTE
1287 wxPalette *pal = bmp.GetPalette();
1288 if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
1289 {
1290 oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE);
1291 ::RealizePalette(memdc);
1292 }
1293 #endif // wxUSE_PALETTE
1294
1295 HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap );
1296 ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
1297
1298 #if wxUSE_PALETTE
1299 if (oldPal)
1300 ::SelectPalette(memdc, oldPal, FALSE);
1301 #endif // wxUSE_PALETTE
1302
1303 ::SelectObject( memdc, hOldBitmap );
1304 ::DeleteDC( memdc );
1305
1306 ::SetTextColor(GetHdc(), old_textground);
1307 ::SetBkColor(GetHdc(), old_background);
1308 }
1309 }
1310
1311 void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
1312 {
1313 WXMICROWIN_CHECK_HDC
1314
1315 DrawAnyText(text, x, y);
1316
1317 // update the bounding box
1318 CalcBoundingBox(x, y);
1319
1320 wxCoord w, h;
1321 GetTextExtent(text, &w, &h);
1322 CalcBoundingBox(x + w, y + h);
1323 }
1324
1325 void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
1326 {
1327 WXMICROWIN_CHECK_HDC
1328
1329 // prepare for drawing the text
1330 if ( m_textForegroundColour.Ok() )
1331 SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
1332
1333 DWORD old_background = 0;
1334 if ( m_textBackgroundColour.Ok() )
1335 {
1336 old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
1337 }
1338
1339 SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
1340 : OPAQUE);
1341
1342 #ifdef __WXWINCE__
1343 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL,
1344 text.c_str(), text.length(), NULL) == 0 )
1345 {
1346 wxLogLastError(wxT("TextOut"));
1347 }
1348 #else
1349 if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
1350 text.c_str(), text.length()) == 0 )
1351 {
1352 wxLogLastError(wxT("TextOut"));
1353 }
1354 #endif
1355
1356 // restore the old parameters (text foreground colour may be left because
1357 // it never is set to anything else, but background should remain
1358 // transparent even if we just drew an opaque string)
1359 if ( m_textBackgroundColour.Ok() )
1360 (void)SetBkColor(GetHdc(), old_background);
1361
1362 SetBkMode(GetHdc(), TRANSPARENT);
1363 }
1364
1365 void wxDC::DoDrawRotatedText(const wxString& text,
1366 wxCoord x, wxCoord y,
1367 double angle)
1368 {
1369 WXMICROWIN_CHECK_HDC
1370
1371 // we test that we have some font because otherwise we should still use the
1372 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1373 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1374 // font for drawing rotated fonts unfortunately)
1375 if ( (angle == 0.0) && m_font.Ok() )
1376 {
1377 DoDrawText(text, x, y);
1378 }
1379 #ifndef __WXMICROWIN__
1380 else
1381 {
1382 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1383 // because it's not TrueType and so can't have non zero
1384 // orientation/escapement under Win9x
1385 wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT;
1386 HFONT hfont = (HFONT)font.GetResourceHandle();
1387 LOGFONT lf;
1388 if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
1389 {
1390 wxLogLastError(wxT("GetObject(hfont)"));
1391 }
1392
1393 // GDI wants the angle in tenth of degree
1394 long angle10 = (long)(angle * 10);
1395 lf.lfEscapement = angle10;
1396 lf. lfOrientation = angle10;
1397
1398 hfont = ::CreateFontIndirect(&lf);
1399 if ( !hfont )
1400 {
1401 wxLogLastError(wxT("CreateFont"));
1402 }
1403 else
1404 {
1405 HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
1406
1407 DrawAnyText(text, x, y);
1408
1409 (void)::SelectObject(GetHdc(), hfontOld);
1410 (void)::DeleteObject(hfont);
1411 }
1412
1413 // call the bounding box by adding all four vertices of the rectangle
1414 // containing the text to it (simpler and probably not slower than
1415 // determining which of them is really topmost/leftmost/...)
1416 wxCoord w, h;
1417 GetTextExtent(text, &w, &h);
1418
1419 double rad = DegToRad(angle);
1420
1421 // "upper left" and "upper right"
1422 CalcBoundingBox(x, y);
1423 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
1424
1425 // "bottom left" and "bottom right"
1426 x += (wxCoord)(h*sin(rad));
1427 y += (wxCoord)(h*cos(rad));
1428 CalcBoundingBox(x, y);
1429 CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
1430 }
1431 #endif
1432 }
1433
1434 // ---------------------------------------------------------------------------
1435 // set GDI objects
1436 // ---------------------------------------------------------------------------
1437
1438 #if wxUSE_PALETTE
1439
1440 void wxDC::DoSelectPalette(bool realize)
1441 {
1442 WXMICROWIN_CHECK_HDC
1443
1444 // Set the old object temporarily, in case the assignment deletes an object
1445 // that's not yet selected out.
1446 if (m_oldPalette)
1447 {
1448 ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE);
1449 m_oldPalette = 0;
1450 }
1451
1452 if ( m_palette.Ok() )
1453 {
1454 HPALETTE oldPal = ::SelectPalette(GetHdc(),
1455 GetHpaletteOf(m_palette),
1456 false);
1457 if (!m_oldPalette)
1458 m_oldPalette = (WXHPALETTE) oldPal;
1459
1460 if (realize)
1461 ::RealizePalette(GetHdc());
1462 }
1463 }
1464
1465 void wxDC::SetPalette(const wxPalette& palette)
1466 {
1467 if ( palette.Ok() )
1468 {
1469 m_palette = palette;
1470 DoSelectPalette(true);
1471 }
1472 }
1473
1474 void wxDC::InitializePalette()
1475 {
1476 if ( wxDisplayDepth() <= 8 )
1477 {
1478 // look for any window or parent that has a custom palette. If any has
1479 // one then we need to use it in drawing operations
1480 wxWindow *win = m_canvas->GetAncestorWithCustomPalette();
1481
1482 m_hasCustomPalette = win && win->HasCustomPalette();
1483 if ( m_hasCustomPalette )
1484 {
1485 m_palette = win->GetPalette();
1486
1487 // turn on MSW translation for this palette
1488 DoSelectPalette();
1489 }
1490 }
1491 }
1492
1493 #endif // wxUSE_PALETTE
1494
1495 // SetFont/Pen/Brush() really ask to be implemented as a single template
1496 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1497
1498 void wxDC::SetFont(const wxFont& font)
1499 {
1500 WXMICROWIN_CHECK_HDC
1501
1502 if ( font == m_font )
1503 return;
1504
1505 if ( font.Ok() )
1506 {
1507 HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font));
1508 if ( hfont == HGDI_ERROR )
1509 {
1510 wxLogLastError(_T("SelectObject(font)"));
1511 }
1512 else // selected ok
1513 {
1514 if ( !m_oldFont )
1515 m_oldFont = (WXHFONT)hfont;
1516
1517 m_font = font;
1518 }
1519 }
1520 else // invalid font, reset the current font
1521 {
1522 if ( m_oldFont )
1523 {
1524 if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR )
1525 {
1526 wxLogLastError(_T("SelectObject(old font)"));
1527 }
1528
1529 m_oldFont = 0;
1530 }
1531
1532 m_font = wxNullFont;
1533 }
1534 }
1535
1536 void wxDC::SetPen(const wxPen& pen)
1537 {
1538 WXMICROWIN_CHECK_HDC
1539
1540 if ( pen == m_pen )
1541 return;
1542
1543 if ( pen.Ok() )
1544 {
1545 HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen));
1546 if ( hpen == HGDI_ERROR )
1547 {
1548 wxLogLastError(_T("SelectObject(pen)"));
1549 }
1550 else // selected ok
1551 {
1552 if ( !m_oldPen )
1553 m_oldPen = (WXHPEN)hpen;
1554
1555 m_pen = pen;
1556 }
1557 }
1558 else // invalid pen, reset the current pen
1559 {
1560 if ( m_oldPen )
1561 {
1562 if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR )
1563 {
1564 wxLogLastError(_T("SelectObject(old pen)"));
1565 }
1566
1567 m_oldPen = 0;
1568 }
1569
1570 m_pen = wxNullPen;
1571 }
1572 }
1573
1574 void wxDC::SetBrush(const wxBrush& brush)
1575 {
1576 WXMICROWIN_CHECK_HDC
1577
1578 if ( brush == m_brush )
1579 return;
1580
1581 if ( brush.Ok() )
1582 {
1583 // we must make sure the brush is aligned with the logical coordinates
1584 // before selecting it
1585 wxBitmap *stipple = brush.GetStipple();
1586 if ( stipple && stipple->Ok() )
1587 {
1588 if ( !::SetBrushOrgEx
1589 (
1590 GetHdc(),
1591 m_deviceOriginX % stipple->GetWidth(),
1592 m_deviceOriginY % stipple->GetHeight(),
1593 NULL // [out] previous brush origin
1594 ) )
1595 {
1596 wxLogLastError(_T("SetBrushOrgEx()"));
1597 }
1598 }
1599
1600 HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush));
1601 if ( hbrush == HGDI_ERROR )
1602 {
1603 wxLogLastError(_T("SelectObject(brush)"));
1604 }
1605 else // selected ok
1606 {
1607 if ( !m_oldBrush )
1608 m_oldBrush = (WXHBRUSH)hbrush;
1609
1610 m_brush = brush;
1611 }
1612 }
1613 else // invalid brush, reset the current brush
1614 {
1615 if ( m_oldBrush )
1616 {
1617 if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR )
1618 {
1619 wxLogLastError(_T("SelectObject(old brush)"));
1620 }
1621
1622 m_oldBrush = 0;
1623 }
1624
1625 m_brush = wxNullBrush;
1626 }
1627 }
1628
1629 void wxDC::SetBackground(const wxBrush& brush)
1630 {
1631 WXMICROWIN_CHECK_HDC
1632
1633 m_backgroundBrush = brush;
1634
1635 if ( m_backgroundBrush.Ok() )
1636 {
1637 (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel());
1638 }
1639 }
1640
1641 void wxDC::SetBackgroundMode(int mode)
1642 {
1643 WXMICROWIN_CHECK_HDC
1644
1645 m_backgroundMode = mode;
1646
1647 // SetBackgroundColour now only refers to text background
1648 // and m_backgroundMode is used there
1649 }
1650
1651 void wxDC::SetLogicalFunction(int function)
1652 {
1653 WXMICROWIN_CHECK_HDC
1654
1655 m_logicalFunction = function;
1656
1657 SetRop(m_hDC);
1658 }
1659
1660 void wxDC::SetRop(WXHDC dc)
1661 {
1662 if ( !dc || m_logicalFunction < 0 )
1663 return;
1664
1665 int rop;
1666
1667 switch (m_logicalFunction)
1668 {
1669 case wxCLEAR: rop = R2_BLACK; break;
1670 case wxXOR: rop = R2_XORPEN; break;
1671 case wxINVERT: rop = R2_NOT; break;
1672 case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
1673 case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
1674 case wxCOPY: rop = R2_COPYPEN; break;
1675 case wxAND: rop = R2_MASKPEN; break;
1676 case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
1677 case wxNO_OP: rop = R2_NOP; break;
1678 case wxNOR: rop = R2_NOTMERGEPEN; break;
1679 case wxEQUIV: rop = R2_NOTXORPEN; break;
1680 case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
1681 case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
1682 case wxNAND: rop = R2_NOTMASKPEN; break;
1683 case wxOR: rop = R2_MERGEPEN; break;
1684 case wxSET: rop = R2_WHITE; break;
1685
1686 default:
1687 wxFAIL_MSG( wxT("unsupported logical function") );
1688 return;
1689 }
1690
1691 SetROP2(GetHdc(), rop);
1692 }
1693
1694 bool wxDC::StartDoc(const wxString& WXUNUSED(message))
1695 {
1696 // We might be previewing, so return true to let it continue.
1697 return true;
1698 }
1699
1700 void wxDC::EndDoc()
1701 {
1702 }
1703
1704 void wxDC::StartPage()
1705 {
1706 }
1707
1708 void wxDC::EndPage()
1709 {
1710 }
1711
1712 // ---------------------------------------------------------------------------
1713 // text metrics
1714 // ---------------------------------------------------------------------------
1715
1716 wxCoord wxDC::GetCharHeight() const
1717 {
1718 WXMICROWIN_CHECK_HDC_RET(0)
1719
1720 TEXTMETRIC lpTextMetric;
1721
1722 GetTextMetrics(GetHdc(), &lpTextMetric);
1723
1724 return lpTextMetric.tmHeight;
1725 }
1726
1727 wxCoord wxDC::GetCharWidth() const
1728 {
1729 WXMICROWIN_CHECK_HDC_RET(0)
1730
1731 TEXTMETRIC lpTextMetric;
1732
1733 GetTextMetrics(GetHdc(), &lpTextMetric);
1734
1735 return lpTextMetric.tmAveCharWidth;
1736 }
1737
1738 void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
1739 wxCoord *descent, wxCoord *externalLeading,
1740 wxFont *font) const
1741 {
1742 #ifdef __WXMICROWIN__
1743 if (!GetHDC())
1744 {
1745 if (x) *x = 0;
1746 if (y) *y = 0;
1747 if (descent) *descent = 0;
1748 if (externalLeading) *externalLeading = 0;
1749 return;
1750 }
1751 #endif // __WXMICROWIN__
1752
1753 HFONT hfontOld;
1754 if ( font )
1755 {
1756 wxASSERT_MSG( font->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1757
1758 hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
1759 }
1760 else // don't change the font
1761 {
1762 hfontOld = 0;
1763 }
1764
1765 SIZE sizeRect;
1766 const size_t len = string.length();
1767 if ( !::GetTextExtentPoint32(GetHdc(), string, len, &sizeRect) )
1768 {
1769 wxLogLastError(_T("GetTextExtentPoint32()"));
1770 }
1771
1772 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1773 // the result computed by GetTextExtentPoint32() may be too small as it
1774 // accounts for under/overhang of the first/last character while we want
1775 // just the bounding rect for this string so adjust the width as needed
1776 // (using API not available in 2002 SDKs of WinCE)
1777 if ( len > 0 )
1778 {
1779 ABC width;
1780 const wxChar chFirst = *string.begin();
1781 if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) )
1782 {
1783 if ( width.abcA < 0 )
1784 sizeRect.cx -= width.abcA;
1785
1786 if ( len > 1 )
1787 {
1788 const wxChar chLast = *string.rbegin();
1789 ::GetCharABCWidths(GetHdc(), chLast, chLast, &width);
1790 }
1791 //else: we already have the width of the last character
1792
1793 if ( width.abcC < 0 )
1794 sizeRect.cx -= width.abcC;
1795 }
1796 //else: GetCharABCWidths() failed, not a TrueType font?
1797 }
1798 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1799
1800 TEXTMETRIC tm;
1801 ::GetTextMetrics(GetHdc(), &tm);
1802
1803 if (x)
1804 *x = sizeRect.cx;
1805 if (y)
1806 *y = sizeRect.cy;
1807 if (descent)
1808 *descent = tm.tmDescent;
1809 if (externalLeading)
1810 *externalLeading = tm.tmExternalLeading;
1811
1812 if ( hfontOld )
1813 {
1814 ::SelectObject(GetHdc(), hfontOld);
1815 }
1816 }
1817
1818
1819 // Each element of the array will be the width of the string up to and
1820 // including the coresoponding character in text.
1821
1822 bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1823 {
1824 static int maxLenText = -1;
1825 static int maxWidth = -1;
1826 int fit = 0;
1827 SIZE sz = {0,0};
1828 int stlen = text.length();
1829
1830 if (maxLenText == -1)
1831 {
1832 // Win9x and WinNT+ have different limits
1833 int version = wxGetOsVersion();
1834 maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
1835 maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
1836 }
1837
1838 widths.Empty();
1839 widths.Add(0, stlen); // fill the array with zeros
1840 if (stlen == 0)
1841 return true;
1842
1843 if (!::GetTextExtentExPoint(GetHdc(),
1844 text.c_str(), // string to check
1845 wxMin(stlen, maxLenText),
1846 maxWidth,
1847 &fit, // [out] count of chars
1848 // that will fit
1849 &widths[0], // array to fill
1850 &sz))
1851 {
1852 // API failed
1853 wxLogLastError(wxT("GetTextExtentExPoint"));
1854 return false;
1855 }
1856
1857 return true;
1858 }
1859
1860
1861
1862
1863 void wxDC::SetMapMode(int mode)
1864 {
1865 WXMICROWIN_CHECK_HDC
1866
1867 m_mappingMode = mode;
1868
1869 if ( mode == wxMM_TEXT )
1870 {
1871 m_logicalScaleX =
1872 m_logicalScaleY = 1.0;
1873 }
1874 else // need to do some calculations
1875 {
1876 int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES),
1877 pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES),
1878 mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE),
1879 mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE);
1880
1881 if ( (mm_width == 0) || (mm_height == 0) )
1882 {
1883 // we can't calculate mm2pixels[XY] then!
1884 return;
1885 }
1886
1887 double mm2pixelsX = (double)pixel_width / mm_width,
1888 mm2pixelsY = (double)pixel_height / mm_height;
1889
1890 switch (mode)
1891 {
1892 case wxMM_TWIPS:
1893 m_logicalScaleX = twips2mm * mm2pixelsX;
1894 m_logicalScaleY = twips2mm * mm2pixelsY;
1895 break;
1896
1897 case wxMM_POINTS:
1898 m_logicalScaleX = pt2mm * mm2pixelsX;
1899 m_logicalScaleY = pt2mm * mm2pixelsY;
1900 break;
1901
1902 case wxMM_METRIC:
1903 m_logicalScaleX = mm2pixelsX;
1904 m_logicalScaleY = mm2pixelsY;
1905 break;
1906
1907 case wxMM_LOMETRIC:
1908 m_logicalScaleX = mm2pixelsX / 10.0;
1909 m_logicalScaleY = mm2pixelsY / 10.0;
1910 break;
1911
1912 default:
1913 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1914 }
1915 }
1916
1917 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1918 // cases we could do with MM_TEXT and in the remaining 0.9% with
1919 // MM_ISOTROPIC (TODO!)
1920 #ifndef __WXWINCE__
1921 ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
1922
1923 int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
1924 height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
1925
1926 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
1927 ::SetWindowExtEx(GetHdc(), width, height, NULL);
1928
1929 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
1930 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);
1931 #endif
1932 }
1933
1934 void wxDC::SetUserScale(double x, double y)
1935 {
1936 WXMICROWIN_CHECK_HDC
1937
1938 if ( x == m_userScaleX && y == m_userScaleY )
1939 return;
1940
1941 m_userScaleX = x;
1942 m_userScaleY = y;
1943
1944 this->SetMapMode(m_mappingMode);
1945 }
1946
1947 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight),
1948 bool WXUNUSED_IN_WINCE(yBottomUp))
1949 {
1950 WXMICROWIN_CHECK_HDC
1951
1952 #ifndef __WXWINCE__
1953 int signX = xLeftRight ? 1 : -1,
1954 signY = yBottomUp ? -1 : 1;
1955
1956 if ( signX != m_signX || signY != m_signY )
1957 {
1958 m_signX = signX;
1959 m_signY = signY;
1960
1961 SetMapMode(m_mappingMode);
1962 }
1963 #endif
1964 }
1965
1966 void wxDC::SetSystemScale(double x, double y)
1967 {
1968 WXMICROWIN_CHECK_HDC
1969
1970 if ( x == m_scaleX && y == m_scaleY )
1971 return;
1972
1973 m_scaleX = x;
1974 m_scaleY = y;
1975
1976 #ifndef __WXWINCE__
1977 SetMapMode(m_mappingMode);
1978 #endif
1979 }
1980
1981 void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y)
1982 {
1983 WXMICROWIN_CHECK_HDC
1984
1985 if ( x == m_logicalOriginX && y == m_logicalOriginY )
1986 return;
1987
1988 m_logicalOriginX = x;
1989 m_logicalOriginY = y;
1990
1991 #ifndef __WXWINCE__
1992 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL);
1993 #endif
1994 }
1995
1996 void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y)
1997 {
1998 WXMICROWIN_CHECK_HDC
1999
2000 if ( x == m_deviceOriginX && y == m_deviceOriginY )
2001 return;
2002
2003 m_deviceOriginX = x;
2004 m_deviceOriginY = y;
2005
2006 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL);
2007 }
2008
2009 // ---------------------------------------------------------------------------
2010 // coordinates transformations
2011 // ---------------------------------------------------------------------------
2012
2013 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
2014 {
2015 return DeviceToLogicalXRel(x - m_deviceOriginX)*m_signX + m_logicalOriginX;
2016 }
2017
2018 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
2019 {
2020 // axis orientation is not taken into account for conversion of a distance
2021 return (wxCoord)(x / (m_logicalScaleX*m_userScaleX*m_scaleX));
2022 }
2023
2024 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
2025 {
2026 return DeviceToLogicalYRel(y - m_deviceOriginY)*m_signY + m_logicalOriginY;
2027 }
2028
2029 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
2030 {
2031 // axis orientation is not taken into account for conversion of a distance
2032 return (wxCoord)( y / (m_logicalScaleY*m_userScaleY*m_scaleY));
2033 }
2034
2035 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
2036 {
2037 return LogicalToDeviceXRel(x - m_logicalOriginX)*m_signX + m_deviceOriginX;
2038 }
2039
2040 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
2041 {
2042 // axis orientation is not taken into account for conversion of a distance
2043 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX);
2044 }
2045
2046 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
2047 {
2048 return LogicalToDeviceYRel(y - m_logicalOriginY)*m_signY + m_deviceOriginY;
2049 }
2050
2051 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
2052 {
2053 // axis orientation is not taken into account for conversion of a distance
2054 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY);
2055 }
2056
2057 // ---------------------------------------------------------------------------
2058 // bit blit
2059 // ---------------------------------------------------------------------------
2060
2061 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
2062 wxCoord width, wxCoord height,
2063 wxDC *source, wxCoord xsrc, wxCoord ysrc,
2064 int rop, bool useMask,
2065 wxCoord xsrcMask, wxCoord ysrcMask)
2066 {
2067 wxCHECK_MSG( source, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2068
2069 WXMICROWIN_CHECK_HDC_RET(false)
2070
2071 // if either the source or destination has alpha channel, we must use
2072 // AlphaBlt() as other function don't handle it correctly
2073 const wxBitmap& bmpSrc = source->m_selectedBitmap;
2074 if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() ||
2075 (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) )
2076 {
2077 if ( AlphaBlt(GetHdc(), xdest, ydest, width, height,
2078 xsrc, ysrc, GetHdcOf(*source), bmpSrc) )
2079 return true;
2080 }
2081
2082 wxMask *mask = NULL;
2083 if ( useMask )
2084 {
2085 mask = bmpSrc.GetMask();
2086
2087 if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) )
2088 {
2089 // don't give assert here because this would break existing
2090 // programs - just silently ignore useMask parameter
2091 useMask = false;
2092 }
2093 }
2094
2095 if (xsrcMask == -1 && ysrcMask == -1)
2096 {
2097 xsrcMask = xsrc; ysrcMask = ysrc;
2098 }
2099
2100 COLORREF old_textground = ::GetTextColor(GetHdc());
2101 COLORREF old_background = ::GetBkColor(GetHdc());
2102 if (m_textForegroundColour.Ok())
2103 {
2104 ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
2105 }
2106 if (m_textBackgroundColour.Ok())
2107 {
2108 ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
2109 }
2110
2111 DWORD dwRop;
2112 switch (rop)
2113 {
2114 case wxXOR: dwRop = SRCINVERT; break;
2115 case wxINVERT: dwRop = DSTINVERT; break;
2116 case wxOR_REVERSE: dwRop = 0x00DD0228; break;
2117 case wxAND_REVERSE: dwRop = SRCERASE; break;
2118 case wxCLEAR: dwRop = BLACKNESS; break;
2119 case wxSET: dwRop = WHITENESS; break;
2120 case wxOR_INVERT: dwRop = MERGEPAINT; break;
2121 case wxAND: dwRop = SRCAND; break;
2122 case wxOR: dwRop = SRCPAINT; break;
2123 case wxEQUIV: dwRop = 0x00990066; break;
2124 case wxNAND: dwRop = 0x007700E6; break;
2125 case wxAND_INVERT: dwRop = 0x00220326; break;
2126 case wxCOPY: dwRop = SRCCOPY; break;
2127 case wxNO_OP: dwRop = DSTCOPY; break;
2128 case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
2129 case wxNOR: dwRop = NOTSRCCOPY; break;
2130 default:
2131 wxFAIL_MSG( wxT("unsupported logical function") );
2132 return false;
2133 }
2134
2135 bool success = false;
2136
2137 if (useMask)
2138 {
2139 #ifdef __WIN32__
2140 // we want the part of the image corresponding to the mask to be
2141 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2142 // meaning of fg and bg is inverted which corresponds to wxWin notion
2143 // of the mask which is also contrary to the Windows one)
2144
2145 // On some systems, MaskBlt succeeds yet is much much slower
2146 // than the wxWidgets fall-back implementation. So we need
2147 // to be able to switch this on and off at runtime.
2148 #if wxUSE_SYSTEM_OPTIONS
2149 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2150 #endif
2151 {
2152 success = ::MaskBlt
2153 (
2154 GetHdc(),
2155 xdest, ydest, width, height,
2156 GetHdcOf(*source),
2157 xsrc, ysrc,
2158 (HBITMAP)mask->GetMaskBitmap(),
2159 xsrcMask, ysrcMask,
2160 MAKEROP4(dwRop, DSTCOPY)
2161 ) != 0;
2162 }
2163
2164 if ( !success )
2165 #endif // Win32
2166 {
2167 // Blit bitmap with mask
2168 HDC dc_mask ;
2169 HDC dc_buffer ;
2170 HBITMAP buffer_bmap ;
2171
2172 #if wxUSE_DC_CACHEING
2173 // create a temp buffer bitmap and DCs to access it and the mask
2174 wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, source->GetHDC());
2175 dc_mask = (HDC) dcCacheEntry1->m_dc;
2176
2177 wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
2178 dc_buffer = (HDC) dcCacheEntry2->m_dc;
2179
2180 wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
2181 width, height);
2182
2183 buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
2184 #else // !wxUSE_DC_CACHEING
2185 // create a temp buffer bitmap and DCs to access it and the mask
2186 dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
2187 dc_buffer = ::CreateCompatibleDC(GetHdc());
2188 buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
2189 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2190 HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
2191 HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
2192
2193 // copy dest to buffer
2194 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2195 GetHdc(), xdest, ydest, SRCCOPY) )
2196 {
2197 wxLogLastError(wxT("BitBlt"));
2198 }
2199
2200 // copy src to buffer using selected raster op
2201 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2202 GetHdcOf(*source), xsrc, ysrc, dwRop) )
2203 {
2204 wxLogLastError(wxT("BitBlt"));
2205 }
2206
2207 // set masked area in buffer to BLACK (pixel value 0)
2208 COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2209 COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2210 if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
2211 dc_mask, xsrcMask, ysrcMask, SRCAND) )
2212 {
2213 wxLogLastError(wxT("BitBlt"));
2214 }
2215
2216 // set unmasked area in dest to BLACK
2217 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2218 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2219 if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height,
2220 dc_mask, xsrcMask, ysrcMask, SRCAND) )
2221 {
2222 wxLogLastError(wxT("BitBlt"));
2223 }
2224 ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
2225 ::SetTextColor(GetHdc(), prevCol);
2226
2227 // OR buffer to dest
2228 success = ::BitBlt(GetHdc(), xdest, ydest,
2229 (int)width, (int)height,
2230 dc_buffer, 0, 0, SRCPAINT) != 0;
2231 if ( !success )
2232 {
2233 wxLogLastError(wxT("BitBlt"));
2234 }
2235
2236 // tidy up temporary DCs and bitmap
2237 ::SelectObject(dc_mask, hOldMaskBitmap);
2238 ::SelectObject(dc_buffer, hOldBufferBitmap);
2239
2240 #if !wxUSE_DC_CACHEING
2241 {
2242 ::DeleteDC(dc_mask);
2243 ::DeleteDC(dc_buffer);
2244 ::DeleteObject(buffer_bmap);
2245 }
2246 #endif
2247 }
2248 }
2249 else // no mask, just BitBlt() it
2250 {
2251 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2252 // use StretchBlt() if available and finally fall back to BitBlt()
2253
2254 // FIXME: use appropriate WinCE functions
2255 #ifndef __WXWINCE__
2256 const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS);
2257 if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) )
2258 {
2259 DIBSECTION ds;
2260 wxZeroMemory(ds);
2261
2262 if ( ::GetObject(GetHbitmapOf(bmpSrc),
2263 sizeof(ds),
2264 &ds) == sizeof(ds) )
2265 {
2266 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
2267
2268 // Figure out what co-ordinate system we're supposed to specify
2269 // ysrc in.
2270 const LONG hDIB = ds.dsBmih.biHeight;
2271 if ( hDIB > 0 )
2272 {
2273 // reflect ysrc
2274 ysrc = hDIB - (ysrc + height);
2275 }
2276
2277 if ( ::StretchDIBits(GetHdc(),
2278 xdest, ydest,
2279 width, height,
2280 xsrc, ysrc,
2281 width, height,
2282 ds.dsBm.bmBits,
2283 (LPBITMAPINFO)&ds.dsBmih,
2284 DIB_RGB_COLORS,
2285 dwRop
2286 ) == (int)GDI_ERROR )
2287 {
2288 // On Win9x this API fails most (all?) of the time, so
2289 // logging it becomes quite distracting. Since it falls
2290 // back to the code below this is not really serious, so
2291 // don't log it.
2292 //wxLogLastError(wxT("StretchDIBits"));
2293 }
2294 else
2295 {
2296 success = true;
2297 }
2298 }
2299 }
2300
2301 if ( !success && (caps & RC_STRETCHBLT) )
2302 #endif
2303 // __WXWINCE__
2304 {
2305 #ifndef __WXWINCE__
2306 StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
2307 #endif
2308
2309 if ( !::StretchBlt
2310 (
2311 GetHdc(),
2312 xdest, ydest, width, height,
2313 GetHdcOf(*source),
2314 xsrc, ysrc, width, height,
2315 dwRop
2316 ) )
2317 {
2318 wxLogLastError(_T("StretchBlt"));
2319 }
2320 else
2321 {
2322 success = true;
2323 }
2324 }
2325
2326 if ( !success )
2327 {
2328 if ( !::BitBlt
2329 (
2330 GetHdc(),
2331 xdest, ydest,
2332 (int)width, (int)height,
2333 GetHdcOf(*source),
2334 xsrc, ysrc,
2335 dwRop
2336 ) )
2337 {
2338 wxLogLastError(_T("BitBlt"));
2339 }
2340 else
2341 {
2342 success = true;
2343 }
2344 }
2345 }
2346
2347 ::SetTextColor(GetHdc(), old_textground);
2348 ::SetBkColor(GetHdc(), old_background);
2349
2350 return success;
2351 }
2352
2353 void wxDC::GetDeviceSize(int *width, int *height) const
2354 {
2355 WXMICROWIN_CHECK_HDC
2356
2357 if ( width )
2358 *width = ::GetDeviceCaps(GetHdc(), HORZRES);
2359 if ( height )
2360 *height = ::GetDeviceCaps(GetHdc(), VERTRES);
2361 }
2362
2363 void wxDC::DoGetSizeMM(int *w, int *h) const
2364 {
2365 WXMICROWIN_CHECK_HDC
2366
2367 // if we implement it in terms of DoGetSize() instead of directly using the
2368 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2369 // will also work for wxWindowDC and wxClientDC even though their size is
2370 // not the same as the total size of the screen
2371 int wPixels, hPixels;
2372 DoGetSize(&wPixels, &hPixels);
2373
2374 if ( w )
2375 {
2376 int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES);
2377
2378 wxCHECK_RET( wTotal, _T("0 width device?") );
2379
2380 *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal;
2381 }
2382
2383 if ( h )
2384 {
2385 int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES);
2386
2387 wxCHECK_RET( hTotal, _T("0 height device?") );
2388
2389 *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal;
2390 }
2391 }
2392
2393 wxSize wxDC::GetPPI() const
2394 {
2395 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2396
2397 int x = ::GetDeviceCaps(GetHdc(), LOGPIXELSX);
2398 int y = ::GetDeviceCaps(GetHdc(), LOGPIXELSY);
2399
2400 return wxSize(x, y);
2401 }
2402
2403 // For use by wxWidgets only, unless custom units are required.
2404 void wxDC::SetLogicalScale(double x, double y)
2405 {
2406 WXMICROWIN_CHECK_HDC
2407
2408 m_logicalScaleX = x;
2409 m_logicalScaleY = y;
2410 }
2411
2412 // ----------------------------------------------------------------------------
2413 // DC caching
2414 // ----------------------------------------------------------------------------
2415
2416 #if wxUSE_DC_CACHEING
2417
2418 /*
2419 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2420 * improve it in due course, either using arrays, or simply storing pointers to one
2421 * entry for the bitmap, and two for the DCs. -- JACS
2422 */
2423
2424 wxList wxDC::sm_bitmapCache;
2425 wxList wxDC::sm_dcCache;
2426
2427 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap, int w, int h, int depth)
2428 {
2429 m_bitmap = hBitmap;
2430 m_dc = 0;
2431 m_width = w;
2432 m_height = h;
2433 m_depth = depth;
2434 }
2435
2436 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
2437 {
2438 m_bitmap = 0;
2439 m_dc = hDC;
2440 m_width = 0;
2441 m_height = 0;
2442 m_depth = depth;
2443 }
2444
2445 wxDCCacheEntry::~wxDCCacheEntry()
2446 {
2447 if (m_bitmap)
2448 ::DeleteObject((HBITMAP) m_bitmap);
2449 if (m_dc)
2450 ::DeleteDC((HDC) m_dc);
2451 }
2452
2453 wxDCCacheEntry* wxDC::FindBitmapInCache(WXHDC dc, int w, int h)
2454 {
2455 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2456 wxList::compatibility_iterator node = sm_bitmapCache.GetFirst();
2457 while (node)
2458 {
2459 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
2460
2461 if (entry->m_depth == depth)
2462 {
2463 if (entry->m_width < w || entry->m_height < h)
2464 {
2465 ::DeleteObject((HBITMAP) entry->m_bitmap);
2466 entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2467 if ( !entry->m_bitmap)
2468 {
2469 wxLogLastError(wxT("CreateCompatibleBitmap"));
2470 }
2471 entry->m_width = w; entry->m_height = h;
2472 return entry;
2473 }
2474 return entry;
2475 }
2476
2477 node = node->GetNext();
2478 }
2479 WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
2480 if ( !hBitmap)
2481 {
2482 wxLogLastError(wxT("CreateCompatibleBitmap"));
2483 }
2484 wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
2485 AddToBitmapCache(entry);
2486 return entry;
2487 }
2488
2489 wxDCCacheEntry* wxDC::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
2490 {
2491 int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
2492 wxList::compatibility_iterator node = sm_dcCache.GetFirst();
2493 while (node)
2494 {
2495 wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
2496
2497 // Don't return the same one as we already have
2498 if (!notThis || (notThis != entry))
2499 {
2500 if (entry->m_depth == depth)
2501 {
2502 return entry;
2503 }
2504 }
2505
2506 node = node->GetNext();
2507 }
2508 WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
2509 if ( !hDC)
2510 {
2511 wxLogLastError(wxT("CreateCompatibleDC"));
2512 }
2513 wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
2514 AddToDCCache(entry);
2515 return entry;
2516 }
2517
2518 void wxDC::AddToBitmapCache(wxDCCacheEntry* entry)
2519 {
2520 sm_bitmapCache.Append(entry);
2521 }
2522
2523 void wxDC::AddToDCCache(wxDCCacheEntry* entry)
2524 {
2525 sm_dcCache.Append(entry);
2526 }
2527
2528 void wxDC::ClearCache()
2529 {
2530 WX_CLEAR_LIST(wxList, sm_dcCache);
2531 WX_CLEAR_LIST(wxList, sm_bitmapCache);
2532 }
2533
2534 // Clean up cache at app exit
2535 class wxDCModule : public wxModule
2536 {
2537 public:
2538 virtual bool OnInit() { return true; }
2539 virtual void OnExit() { wxDC::ClearCache(); }
2540
2541 private:
2542 DECLARE_DYNAMIC_CLASS(wxDCModule)
2543 };
2544
2545 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2546
2547 #endif // wxUSE_DC_CACHEING
2548
2549 // ----------------------------------------------------------------------------
2550 // alpha channel support
2551 // ----------------------------------------------------------------------------
2552
2553 static bool AlphaBlt(HDC hdcDst,
2554 int x, int y, int width, int height,
2555 int srcX, int srcY, HDC hdcSrc,
2556 const wxBitmap& bmp)
2557 {
2558 wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2559 wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") );
2560
2561 // do we have AlphaBlend() and company in the headers?
2562 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2563 // yes, now try to see if we have it during run-time
2564 typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
2565 HDC,int,int,int,int,
2566 BLENDFUNCTION);
2567
2568 static AlphaBlend_t
2569 pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend"));
2570 if ( pfnAlphaBlend )
2571 {
2572 BLENDFUNCTION bf;
2573 bf.BlendOp = AC_SRC_OVER;
2574 bf.BlendFlags = 0;
2575 bf.SourceConstantAlpha = 0xff;
2576 bf.AlphaFormat = AC_SRC_ALPHA;
2577
2578 if ( pfnAlphaBlend(hdcDst, x, y, width, height,
2579 hdcSrc, srcX, srcY, width, height,
2580 bf) )
2581 {
2582 // skip wxAlphaBlend() call below
2583 return true;
2584 }
2585
2586 wxLogLastError(_T("AlphaBlend"));
2587 }
2588 #else
2589 wxUnusedVar(hdcSrc);
2590 #endif // defined(AC_SRC_OVER)
2591
2592 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2593 // implementation
2594 #ifdef wxHAVE_RAW_BITMAP
2595 wxAlphaBlend(hdcDst, x, y, width, height, srcX, srcY, bmp);
2596
2597 return true;
2598 #else // !wxHAVE_RAW_BITMAP
2599 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2600 // alpha but at least something will be shown like this)
2601 wxUnusedVar(bmp);
2602 return false;
2603 #endif // wxHAVE_RAW_BITMAP
2604 }
2605
2606
2607 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2608 #ifdef wxHAVE_RAW_BITMAP
2609
2610 static void
2611 wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
2612 int w, int h,
2613 int srcX, int srcY, const wxBitmap& bmpSrc)
2614 {
2615 // get the destination DC pixels
2616 wxBitmap bmpDst(w, h, 32 /* force creating RGBA DIB */);
2617 MemoryHDC hdcMem;
2618 SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
2619
2620 if ( !::BitBlt(hdcMem, 0, 0, w, h, hdcDst, xDst, yDst, SRCCOPY) )
2621 {
2622 wxLogLastError(_T("BitBlt"));
2623 }
2624
2625 // combine them with the source bitmap using alpha
2626 wxAlphaPixelData dataDst(bmpDst),
2627 dataSrc((wxBitmap &)bmpSrc);
2628
2629 wxCHECK_RET( dataDst && dataSrc,
2630 _T("failed to get raw data in wxAlphaBlend") );
2631
2632 wxAlphaPixelData::Iterator pDst(dataDst),
2633 pSrc(dataSrc);
2634
2635 pSrc.Offset(dataSrc, srcX, srcY);
2636
2637 for ( int y = 0; y < h; y++ )
2638 {
2639 wxAlphaPixelData::Iterator pDstRowStart = pDst,
2640 pSrcRowStart = pSrc;
2641
2642 for ( int x = 0; x < w; x++ )
2643 {
2644 // note that source bitmap uses premultiplied alpha (as required by
2645 // the real AlphaBlend)
2646 const unsigned beta = 255 - pSrc.Alpha();
2647
2648 pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255;
2649 pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255;
2650 pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255;
2651
2652 ++pDst;
2653 ++pSrc;
2654 }
2655
2656 pDst = pDstRowStart;
2657 pSrc = pSrcRowStart;
2658 pDst.OffsetY(dataDst, 1);
2659 pSrc.OffsetY(dataSrc, 1);
2660 }
2661
2662 // and finally blit them back to the destination DC
2663 if ( !::BitBlt(hdcDst, xDst, yDst, w, h, hdcMem, 0, 0, SRCCOPY) )
2664 {
2665 wxLogLastError(_T("BitBlt"));
2666 }
2667 }
2668
2669 #endif // #ifdef wxHAVE_RAW_BITMAP
2670
2671 void wxDC::DoGradientFillLinear (const wxRect& rect,
2672 const wxColour& initialColour,
2673 const wxColour& destColour,
2674 wxDirection nDirection)
2675 {
2676 // use native function if we have compile-time support it and can load it
2677 // during run-time (linking to it statically would make the program
2678 // unusable on earlier Windows versions)
2679 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2680 typedef BOOL
2681 (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
2682 static GradientFill_t pfnGradientFill =
2683 (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill"));
2684
2685 if ( pfnGradientFill )
2686 {
2687 GRADIENT_RECT grect;
2688 grect.UpperLeft = 0;
2689 grect.LowerRight = 1;
2690
2691 // invert colours direction if not filling from left-to-right or
2692 // top-to-bottom
2693 int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
2694
2695 // one vertex for upper left and one for upper-right
2696 TRIVERTEX vertices[2];
2697
2698 vertices[0].x = rect.GetLeft();
2699 vertices[0].y = rect.GetTop();
2700 vertices[1].x = rect.GetRight()+1;
2701 vertices[1].y = rect.GetBottom()+1;
2702
2703 vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8);
2704 vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8);
2705 vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8);
2706 vertices[firstVertex].Alpha = 0;
2707 vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8);
2708 vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8);
2709 vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
2710 vertices[1 - firstVertex].Alpha = 0;
2711
2712 if ( (*pfnGradientFill)
2713 (
2714 GetHdc(),
2715 vertices,
2716 WXSIZEOF(vertices),
2717 &grect,
2718 1,
2719 nDirection == wxWEST || nDirection == wxEAST
2720 ? GRADIENT_FILL_RECT_H
2721 : GRADIENT_FILL_RECT_V
2722 ) )
2723 {
2724 // skip call of the base class version below
2725 return;
2726 }
2727
2728 wxLogLastError(_T("GradientFill"));
2729 }
2730 #endif // wxUSE_DYNLIB_CLASS
2731
2732 wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
2733 }
2734
2735 static DWORD wxGetDCLayout(HDC hdc)
2736 {
2737 typedef DWORD (WINAPI *GetLayout_t)(HDC);
2738 static GetLayout_t
2739 pfnGetLayout = (GetLayout_t)wxGDI32DLL.GetSymbol(_T("GetLayout"));
2740
2741 return pfnGetLayout ? pfnGetLayout(hdc) : (DWORD)-1;
2742 }
2743
2744 wxLayoutDirection wxDC::GetLayoutDirection() const
2745 {
2746 DWORD layout = wxGetDCLayout(GetHdc());
2747
2748 if ( layout == (DWORD)-1 )
2749 return wxLayout_Default;
2750
2751 return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight;
2752 }
2753
2754 void wxDC::SetLayoutDirection(wxLayoutDirection dir)
2755 {
2756 typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
2757 static SetLayout_t
2758 pfnSetLayout = (SetLayout_t)wxGDI32DLL.GetSymbol(_T("SetLayout"));
2759 if ( !pfnSetLayout )
2760 return;
2761
2762 if ( dir == wxLayout_Default )
2763 {
2764 dir = wxTheApp->GetLayoutDirection();
2765 if ( dir == wxLayout_Default )
2766 return;
2767 }
2768
2769 DWORD layout = wxGetDCLayout(GetHdc());
2770 if ( dir == wxLayout_RightToLeft )
2771 layout |= LAYOUT_RTL;
2772 else
2773 layout &= ~LAYOUT_RTL;
2774
2775 pfnSetLayout(GetHdc(), layout);
2776 }

  ViewVC Help
Powered by ViewVC 1.1.22