1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/dcprint.cpp
3 // Purpose:     wxPrinterDC class
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     01/02/97
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #if wxUSE_PRINTING_ARCHITECTURE
27 
28 #include "wx/dcprint.h"
29 #include "wx/msw/dcprint.h"
30 
31 #ifndef WX_PRECOMP
32     #include "wx/msw/wrapcdlg.h"
33     #include "wx/string.h"
34     #include "wx/log.h"
35     #include "wx/window.h"
36     #include "wx/dcmemory.h"
37     #include "wx/math.h"
38 #endif
39 
40 #include "wx/msw/private.h"
41 
42 #if wxUSE_WXDIB
43     #include "wx/msw/dib.h"
44 #endif
45 
46 #include "wx/printdlg.h"
47 #include "wx/msw/printdlg.h"
48 
49 #ifndef __WIN32__
50     #include <print.h>
51 #endif
52 
53 // mingw32 defines GDI_ERROR incorrectly
54 #if defined(__GNUWIN32__) || !defined(GDI_ERROR)
55     #undef GDI_ERROR
56     #define GDI_ERROR ((int)-1)
57 #endif
58 
59 #if defined(__WXUNIVERSAL__) && wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW
60     #define wxUSE_PS_PRINTING 1
61 #else
62     #define wxUSE_PS_PRINTING 0
63 #endif
64 
65 // ----------------------------------------------------------------------------
66 // wxWin macros
67 // ----------------------------------------------------------------------------
68 
IMPLEMENT_ABSTRACT_CLASS(wxPrinterDCImpl,wxMSWDCImpl)69 IMPLEMENT_ABSTRACT_CLASS(wxPrinterDCImpl, wxMSWDCImpl)
70 
71 // ============================================================================
72 // implementation
73 // ============================================================================
74 
75 // ----------------------------------------------------------------------------
76 // wxPrinterDC construction
77 // ----------------------------------------------------------------------------
78 
79 #if 0
80 // This form is deprecated
81 wxPrinterDC::wxPrinterDC(const wxString& driver_name,
82                          const wxString& device_name,
83                          const wxString& file,
84                          bool interactive,
85                          wxPrintOrientation orientation)
86 {
87     m_isInteractive = interactive;
88 
89     if ( !file.empty() )
90         m_printData.SetFilename(file);
91 
92 #if wxUSE_COMMON_DIALOGS
93     if ( interactive )
94     {
95         PRINTDLG pd;
96 
97         pd.lStructSize = sizeof( PRINTDLG );
98         pd.hwndOwner = (HWND) NULL;
99         pd.hDevMode = (HANDLE)NULL;
100         pd.hDevNames = (HANDLE)NULL;
101         pd.Flags = PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
102         pd.nFromPage = 0;
103         pd.nToPage = 0;
104         pd.nMinPage = 0;
105         pd.nMaxPage = 0;
106         pd.nCopies = 1;
107         pd.hInstance = (HINSTANCE)NULL;
108 
109         m_ok = PrintDlg( &pd ) != 0;
110         if ( m_ok )
111         {
112             m_hDC = (WXHDC) pd.hDC;
113         }
114     }
115     else
116 #endif // wxUSE_COMMON_DIALOGS
117     {
118         if ( !driver_name.empty() && !device_name.empty() && !file.empty() )
119         {
120             m_hDC = (WXHDC) CreateDC(driver_name.t_str(),
121                                      device_name.t_str(),
122                                      file.fn_str(),
123                                      NULL);
124         }
125         else // we don't have all parameters, ask the user
126         {
127             wxPrintData printData;
128             printData.SetOrientation(orientation);
129             m_hDC = wxGetPrinterDC(printData);
130         }
131 
132         m_ok = m_hDC ? true: false;
133 
134         // as we created it, we must delete it as well
135         m_bOwnsDC = true;
136     }
137 
138     Init();
139 }
140 #endif
141 
142 wxPrinterDCImpl::wxPrinterDCImpl( wxPrinterDC *owner, const wxPrintData& printData ) :
143     wxMSWDCImpl( owner )
144 {
145     m_printData = printData;
146 
147     m_isInteractive = false;
148 
149     m_hDC = wxGetPrinterDC(printData);
150     m_ok = m_hDC != 0;
151     m_bOwnsDC = true;
152 
153     Init();
154 }
155 
156 
wxPrinterDCImpl(wxPrinterDC * owner,WXHDC dc)157 wxPrinterDCImpl::wxPrinterDCImpl( wxPrinterDC *owner, WXHDC dc ) :
158     wxMSWDCImpl( owner )
159 {
160     m_isInteractive = false;
161 
162     m_hDC = dc;
163     m_bOwnsDC = true;
164     m_ok = true;
165 }
166 
Init()167 void wxPrinterDCImpl::Init()
168 {
169     if ( m_hDC )
170     {
171         //     int width = GetDeviceCaps(m_hDC, VERTRES);
172         //     int height = GetDeviceCaps(m_hDC, HORZRES);
173         SetMapMode(wxMM_TEXT);
174 
175         SetBrush(*wxBLACK_BRUSH);
176         SetPen(*wxBLACK_PEN);
177     }
178 }
179 
180 // ----------------------------------------------------------------------------
181 // wxPrinterDCImpl {Start/End}{Page/Doc} methods
182 // ----------------------------------------------------------------------------
183 
StartDoc(const wxString & message)184 bool wxPrinterDCImpl::StartDoc(const wxString& message)
185 {
186     DOCINFO docinfo;
187     docinfo.cbSize = sizeof(DOCINFO);
188     docinfo.lpszDocName = message.t_str();
189 
190     wxString filename(m_printData.GetFilename());
191 
192     if (filename.empty())
193         docinfo.lpszOutput = NULL;
194     else
195         docinfo.lpszOutput = filename.t_str();
196 
197     docinfo.lpszDatatype = NULL;
198     docinfo.fwType = 0;
199 
200     if (!m_hDC)
201         return false;
202 
203     if ( ::StartDoc(GetHdc(), &docinfo) <= 0 )
204     {
205         wxLogLastError(wxT("StartDoc"));
206         return false;
207     }
208 
209     return true;
210 }
211 
EndDoc()212 void wxPrinterDCImpl::EndDoc()
213 {
214     if (m_hDC) ::EndDoc((HDC) m_hDC);
215 }
216 
StartPage()217 void wxPrinterDCImpl::StartPage()
218 {
219     if (m_hDC)
220         ::StartPage((HDC) m_hDC);
221 }
222 
EndPage()223 void wxPrinterDCImpl::EndPage()
224 {
225     if (m_hDC)
226         ::EndPage((HDC) m_hDC);
227 }
228 
229 
GetPaperRect() const230 wxRect wxPrinterDCImpl::GetPaperRect() const
231 
232 {
233     if (!IsOk()) return wxRect(0, 0, 0, 0);
234     int w = ::GetDeviceCaps((HDC) m_hDC, PHYSICALWIDTH);
235     int h = ::GetDeviceCaps((HDC) m_hDC, PHYSICALHEIGHT);
236     int x = -::GetDeviceCaps((HDC) m_hDC, PHYSICALOFFSETX);
237     int y = -::GetDeviceCaps((HDC) m_hDC, PHYSICALOFFSETY);
238     return wxRect(x, y, w, h);
239 }
240 
241 
242 #if !wxUSE_PS_PRINTING
243 
244 // Returns default device and port names
wxGetDefaultDeviceName(wxString & deviceName,wxString & portName)245 static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
246 {
247     deviceName.clear();
248 
249     LPDEVNAMES  lpDevNames;
250     LPTSTR      lpszDeviceName;
251     LPTSTR      lpszPortName;
252 
253     PRINTDLG    pd;
254     memset(&pd, 0, sizeof(PRINTDLG));
255     pd.lStructSize    = sizeof(PRINTDLG);
256     pd.hwndOwner      = (HWND)NULL;
257     pd.hDevMode       = NULL; // Will be created by PrintDlg
258     pd.hDevNames      = NULL; // Ditto
259     pd.Flags          = PD_RETURNDEFAULT;
260     pd.nCopies        = 1;
261 
262     if (!PrintDlg((LPPRINTDLG)&pd))
263     {
264         if ( pd.hDevMode )
265             GlobalFree(pd.hDevMode);
266         if (pd.hDevNames)
267             GlobalFree(pd.hDevNames);
268 
269         return false;
270     }
271 
272     if (pd.hDevNames)
273     {
274         lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
275         lpszDeviceName = (LPTSTR)lpDevNames + lpDevNames->wDeviceOffset;
276         lpszPortName   = (LPTSTR)lpDevNames + lpDevNames->wOutputOffset;
277 
278         deviceName = lpszDeviceName;
279         portName = lpszPortName;
280 
281         GlobalUnlock(pd.hDevNames);
282         GlobalFree(pd.hDevNames);
283         pd.hDevNames=NULL;
284     }
285 
286     if (pd.hDevMode)
287     {
288         GlobalFree(pd.hDevMode);
289         pd.hDevMode=NULL;
290     }
291     return ( !deviceName.empty() );
292 }
293 
294 #endif // !wxUSE_PS_PRINTING
295 
296 // Gets an HDC for the specified printer configuration
wxGetPrinterDC(const wxPrintData & printDataConst)297 WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
298 {
299 #if wxUSE_PS_PRINTING
300     // TODO
301     wxUnusedVar(printDataConst);
302     return 0;
303 #else // native Windows printing
304     wxWindowsPrintNativeData *data =
305         (wxWindowsPrintNativeData *) printDataConst.GetNativeData();
306 
307     data->TransferFrom( printDataConst );
308 
309     wxString deviceName = printDataConst.GetPrinterName();
310     if ( deviceName.empty() )
311     {
312         // Retrieve the default device name
313         wxString portName;
314         if ( !wxGetDefaultDeviceName(deviceName, portName) )
315         {
316             return 0; // Could not get default device name
317         }
318     }
319 
320 
321     GlobalPtrLock lockDevMode;
322     const HGLOBAL devMode = data->GetDevMode();
323     if ( devMode )
324         lockDevMode.Init(devMode);
325 
326     HDC hDC = ::CreateDC
327                 (
328                     NULL,               // no driver name as we use device name
329                     deviceName.t_str(),
330                     NULL,               // unused
331                     static_cast<DEVMODE *>(lockDevMode.Get())
332                 );
333     if ( !hDC )
334     {
335         wxLogLastError(wxT("CreateDC(printer)"));
336     }
337 
338     return (WXHDC) hDC;
339 #endif // PostScript/Windows printing
340 }
341 
342 // ----------------------------------------------------------------------------
343 // wxPrinterDCImpl bit blitting/bitmap drawing
344 // ----------------------------------------------------------------------------
345 
346 // helper of DoDrawBitmap() and DoBlit()
347 static
DrawBitmapUsingStretchDIBits(HDC hdc,const wxBitmap & bmp,wxCoord x,wxCoord y)348 bool DrawBitmapUsingStretchDIBits(HDC hdc,
349                                   const wxBitmap& bmp,
350                                   wxCoord x, wxCoord y)
351 {
352 #if wxUSE_WXDIB
353     wxDIB dib(bmp);
354     bool ok = dib.IsOk();
355     if ( !ok )
356         return false;
357 
358     DIBSECTION ds;
359     if ( !::GetObject(dib.GetHandle(), sizeof(ds), &ds) )
360     {
361         wxLogLastError(wxT("GetObject(DIBSECTION)"));
362 
363         return false;
364     }
365 
366     // ok, we've got all data we need, do blit it
367     if ( ::StretchDIBits
368             (
369                 hdc,
370                 x, y,
371                 ds.dsBmih.biWidth, ds.dsBmih.biHeight,
372                 0, 0,
373                 ds.dsBmih.biWidth, ds.dsBmih.biHeight,
374                 ds.dsBm.bmBits,
375                 (LPBITMAPINFO)&ds.dsBmih,
376                 DIB_RGB_COLORS,
377                 SRCCOPY
378             ) == GDI_ERROR )
379     {
380         wxLogLastError(wxT("StretchDIBits"));
381 
382         return false;
383     }
384 
385     return true;
386 #else
387     return false;
388 #endif
389 }
390 
DoDrawBitmap(const wxBitmap & bmp,wxCoord x,wxCoord y,bool useMask)391 void wxPrinterDCImpl::DoDrawBitmap(const wxBitmap& bmp,
392                                wxCoord x, wxCoord y,
393                                bool useMask)
394 {
395     wxCHECK_RET( bmp.IsOk(), wxT("invalid bitmap in wxPrinterDC::DrawBitmap") );
396 
397     int width = bmp.GetWidth(),
398         height = bmp.GetHeight();
399 
400     if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB) ||
401             !DrawBitmapUsingStretchDIBits(GetHdc(), bmp, x, y) )
402     {
403         // no support for StretchDIBits() or an error occurred if we got here
404         wxMemoryDC memDC;
405 
406         memDC.SelectObjectAsSource(bmp);
407 
408         GetOwner()->Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
409 
410         memDC.SelectObject(wxNullBitmap);
411     }
412 }
413 
DoBlit(wxCoord xdest,wxCoord ydest,wxCoord width,wxCoord height,wxDC * source,wxCoord WXUNUSED (xsrc),wxCoord WXUNUSED (ysrc),wxRasterOperationMode WXUNUSED (rop),bool useMask,wxCoord WXUNUSED (xsrcMask),wxCoord WXUNUSED (ysrcMask))414 bool wxPrinterDCImpl::DoBlit(wxCoord xdest, wxCoord ydest,
415                          wxCoord width, wxCoord height,
416                          wxDC *source,
417                          wxCoord WXUNUSED(xsrc), wxCoord WXUNUSED(ysrc),
418                          wxRasterOperationMode WXUNUSED(rop), bool useMask,
419                          wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask))
420 {
421     wxDCImpl *impl = source->GetImpl();
422     wxMSWDCImpl *msw_impl = wxDynamicCast(impl, wxMSWDCImpl);
423     if (!msw_impl)
424         return false;
425 
426     wxBitmap& bmp = msw_impl->GetSelectedBitmap();
427     wxMask *mask = useMask ? bmp.GetMask() : NULL;
428     if ( mask )
429     {
430         // If we are printing source colours are screen colours not printer
431         // colours and so we need copy the bitmap pixel by pixel.
432         RECT rect;
433         HDC dcSrc = GetHdcOf(*msw_impl);
434         MemoryHDC dcMask(dcSrc);
435         SelectInHDC selectMask(dcMask, (HBITMAP)mask->GetMaskBitmap());
436 
437         for (int x = 0; x < width; x++)
438         {
439             for (int y = 0; y < height; y++)
440             {
441                 COLORREF cref = ::GetPixel(dcMask, x, y);
442                 if (cref)
443                 {
444                     HBRUSH brush = ::CreateSolidBrush(::GetPixel(dcSrc, x, y));
445                     rect.left = xdest + x;
446                     rect.right = rect.left + 1;
447                     rect.top = ydest + y;
448                     rect.bottom = rect.top + 1;
449                     ::FillRect(GetHdc(), &rect, brush);
450                     ::DeleteObject(brush);
451                 }
452             }
453         }
454     }
455     else // no mask
456     {
457         if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB) ||
458                 !DrawBitmapUsingStretchDIBits(GetHdc(), bmp, xdest, ydest) )
459         {
460             // no support for StretchDIBits
461 
462             // as we are printing, source colours are screen colours not
463             // printer colours and so we need copy the bitmap pixel by pixel.
464             HDC dcSrc = GetHdcOf(*msw_impl);
465             RECT rect;
466             for (int y = 0; y < height; y++)
467             {
468                 // optimization: draw identical adjacent pixels together.
469                 for (int x = 0; x < width; x++)
470                 {
471                     COLORREF col = ::GetPixel(dcSrc, x, y);
472                     HBRUSH brush = ::CreateSolidBrush( col );
473 
474                     rect.left = xdest + x;
475                     rect.top = ydest + y;
476                     while( (x + 1 < width) &&
477                                 (::GetPixel(dcSrc, x + 1, y) == col ) )
478                     {
479                         ++x;
480                     }
481                     rect.right = xdest + x + 1;
482                     rect.bottom = rect.top + 1;
483                     ::FillRect((HDC) m_hDC, &rect, brush);
484                     ::DeleteObject(brush);
485                 }
486             }
487         }
488     }
489 
490     return true;
491 }
492 
493 #endif
494     // wxUSE_PRINTING_ARCHITECTURE
495