]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dcprint.cpp
patches for wxSTIPPLE_MASK_OPAQUE from Klass Holwerda
[wxWidgets.git] / src / msw / dcprint.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
4b7f2165 2// Name: src/msw/dcprint.cpp
2bda0e17
KB
3// Purpose: wxPrinterDC class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
4b7f2165 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
4b7f2165
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17 20#ifdef __GNUG__
4b7f2165 21 #pragma implementation "dcprint.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
4b7f2165 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
4b7f2165
VZ
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/window.h"
475f6e7a 35 #include "wx/dcmemory.h"
2bda0e17
KB
36#endif
37
42e69d6b 38#include "wx/msw/private.h"
0c589ad0
BM
39#include "wx/dcprint.h"
40#include "math.h"
2bda0e17 41
c455ab93 42#if wxUSE_COMMON_DIALOGS || defined(__WXWINE__)
4b7f2165 43 #include <commdlg.h>
2bda0e17
KB
44#endif
45
46#ifndef __WIN32__
4b7f2165 47 #include <print.h>
2bda0e17
KB
48#endif
49
4b7f2165
VZ
50// ----------------------------------------------------------------------------
51// wxWin macros
52// ----------------------------------------------------------------------------
2bda0e17 53IMPLEMENT_CLASS(wxPrinterDC, wxDC)
2bda0e17 54
4b7f2165
VZ
55// ============================================================================
56// implementation
57// ============================================================================
58
59// ----------------------------------------------------------------------------
60// wxPrinterDC construction
61// ----------------------------------------------------------------------------
62
7bcb11d3 63// This form is deprecated
debe6624 64wxPrinterDC::wxPrinterDC(const wxString& driver_name, const wxString& device_name, const wxString& file, bool interactive, int orientation)
2bda0e17 65{
7bcb11d3 66 m_isInteractive = interactive;
a17e237f 67
4b7f2165 68 if ( !!file )
7bcb11d3 69 m_printData.SetFilename(file);
a17e237f 70
47d67540 71#if wxUSE_COMMON_DIALOGS
7bcb11d3
JS
72 if (interactive)
73 {
74 PRINTDLG pd;
a17e237f 75
7bcb11d3
JS
76 pd.lStructSize = sizeof( PRINTDLG );
77 pd.hwndOwner=(HWND) NULL;
78 pd.hDevMode=(HANDLE)NULL;
79 pd.hDevNames=(HANDLE)NULL;
80 pd.Flags=PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
81 pd.nFromPage=0;
82 pd.nToPage=0;
83 pd.nMinPage=0;
84 pd.nMaxPage=0;
85 pd.nCopies=1;
86 pd.hInstance=(HINSTANCE)NULL;
a17e237f 87
7bcb11d3
JS
88 if ( PrintDlg( &pd ) != 0 )
89 {
90 m_hDC = (WXHDC) pd.hDC;
91 m_ok = TRUE;
92 }
93 else
94 {
95 m_ok = FALSE;
96 return;
97 }
a17e237f 98
7bcb11d3
JS
99 // m_dontDelete = TRUE;
100 }
101 else
4b7f2165 102#endif // wxUSE_COMMON_DIALOGS
223d09f6
KB
103 if ((!driver_name.IsNull() && driver_name != wxT("")) &&
104 (!device_name.IsNull() && device_name != wxT("")) &&
105 (!file.IsNull() && file != wxT("")))
7bcb11d3 106 {
837e5743 107 m_hDC = (WXHDC) CreateDC(WXSTRINGCAST driver_name, WXSTRINGCAST device_name, WXSTRINGCAST file, NULL);
7bcb11d3
JS
108 m_ok = m_hDC ? TRUE: FALSE;
109 }
110 else
111 {
112 wxPrintData printData;
113 printData.SetOrientation(orientation);
114 m_hDC = wxGetPrinterDC(printData);
115 m_ok = m_hDC ? TRUE: FALSE;
116 }
a17e237f 117
7bcb11d3
JS
118 if (m_hDC)
119 {
120 // int width = GetDeviceCaps(m_hDC, VERTRES);
121 // int height = GetDeviceCaps(m_hDC, HORZRES);
122 SetMapMode(wxMM_TEXT);
123 }
124 SetBrush(*wxBLACK_BRUSH);
125 SetPen(*wxBLACK_PEN);
126}
127
128wxPrinterDC::wxPrinterDC(const wxPrintData& printData)
129{
130 m_printData = printData;
131
132 m_isInteractive = FALSE;
133
134 m_hDC = wxGetPrinterDC(printData);
135 m_ok = (m_hDC != 0);
a17e237f 136
7bcb11d3
JS
137 if (m_hDC)
138 SetMapMode(wxMM_TEXT);
a17e237f 139
7bcb11d3
JS
140 SetBrush(*wxBLACK_BRUSH);
141 SetPen(*wxBLACK_PEN);
2bda0e17
KB
142}
143
7bcb11d3 144
2bda0e17
KB
145wxPrinterDC::wxPrinterDC(WXHDC theDC)
146{
7bcb11d3 147 m_isInteractive = FALSE;
a17e237f 148
7bcb11d3
JS
149 m_hDC = theDC;
150 m_ok = TRUE;
151 if (m_hDC)
152 {
153 // int width = GetDeviceCaps(m_hDC, VERTRES);
154 // int height = GetDeviceCaps(m_hDC, HORZRES);
155 SetMapMode(wxMM_TEXT);
156 }
157 SetBrush(*wxBLACK_BRUSH);
158 SetPen(*wxBLACK_PEN);
2bda0e17
KB
159}
160
4b7f2165 161wxPrinterDC::~wxPrinterDC()
2bda0e17
KB
162{
163}
164
4b7f2165
VZ
165// ----------------------------------------------------------------------------
166// wxPrinterDC {Start/End}{Page/Doc} methods
167// ----------------------------------------------------------------------------
168
7bcb11d3
JS
169bool wxPrinterDC::StartDoc(const wxString& message)
170{
171 DOCINFO docinfo;
172 docinfo.cbSize = sizeof(DOCINFO);
837e5743 173 docinfo.lpszDocName = (const wxChar*)message;
7bcb11d3
JS
174
175 wxString filename(m_printData.GetFilename());
176
177 if (filename.IsEmpty())
178 docinfo.lpszOutput = NULL;
179 else
837e5743 180 docinfo.lpszOutput = (const wxChar *) filename;
7bcb11d3
JS
181
182#if defined(__WIN95__)
183 docinfo.lpszDatatype = NULL;
184 docinfo.fwType = 0;
185#endif
a17e237f 186
7bcb11d3
JS
187 if (!m_hDC)
188 return FALSE;
a17e237f 189
4b7f2165 190 int ret = ::StartDoc(GetHdc(), &docinfo);
a17e237f 191
7bcb11d3
JS
192#ifndef __WIN16__
193 if (ret <= 0)
194 {
195 DWORD lastError = GetLastError();
223d09f6 196 wxLogDebug(wxT("wxDC::StartDoc failed with error: %d\n"), lastError);
7bcb11d3
JS
197 }
198#endif
a17e237f 199
7bcb11d3
JS
200 return (ret > 0);
201}
202
4b7f2165 203void wxPrinterDC::EndDoc()
7bcb11d3
JS
204{
205 if (m_hDC) ::EndDoc((HDC) m_hDC);
206}
207
4b7f2165 208void wxPrinterDC::StartPage()
7bcb11d3
JS
209{
210 if (m_hDC)
211 ::StartPage((HDC) m_hDC);
212}
213
4b7f2165 214void wxPrinterDC::EndPage()
7bcb11d3
JS
215{
216 if (m_hDC)
217 ::EndPage((HDC) m_hDC);
218}
219
220// Returns default device and port names
221static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
222{
223 deviceName = "";
224
225 LPDEVNAMES lpDevNames;
226 LPSTR lpszDriverName;
227 LPSTR lpszDeviceName;
228 LPSTR lpszPortName;
a17e237f 229
7bcb11d3
JS
230 PRINTDLG pd;
231
232 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
233#ifdef __GNUWIN32__
234 pd.lStructSize = 66; // sizeof(PRINTDLG);
235#else
236 pd.lStructSize = sizeof(PRINTDLG);
237#endif
238
239 pd.hwndOwner = (HWND)NULL;
240 pd.hDevMode = NULL; // Will be created by PrintDlg
241 pd.hDevNames = NULL; // Ditto
242 pd.Flags = PD_RETURNDEFAULT;
243 pd.nCopies = 1;
a17e237f 244
7bcb11d3
JS
245 if (!PrintDlg((LPPRINTDLG)&pd))
246 {
247 if ( pd.hDevMode )
248 GlobalFree(pd.hDevMode);
249 if (pd.hDevNames)
250 GlobalFree(pd.hDevNames);
a17e237f 251
7bcb11d3
JS
252 return FALSE;
253 }
a17e237f 254
7bcb11d3
JS
255 if (pd.hDevNames)
256 {
257 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
258 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
259 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
260 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
7bcb11d3
JS
261
262 deviceName = lpszDeviceName;
263 portName = lpszPortName;
60fe7303
JS
264
265 GlobalUnlock(pd.hDevNames);
266 GlobalFree(pd.hDevNames);
267 pd.hDevNames=NULL;
7bcb11d3 268 }
a17e237f 269
7bcb11d3
JS
270 if (pd.hDevMode)
271 {
272 GlobalFree(pd.hDevMode);
273 pd.hDevMode=NULL;
274 }
223d09f6 275 return ( deviceName != wxT("") );
7bcb11d3
JS
276}
277
278#if 0
279// This uses defaults, except for orientation, so we should eliminate this function
280// and use the 2nd form (passing wxPrintData) instead.
2bda0e17
KB
281WXHDC wxGetPrinterDC(int orientation)
282{
283 HDC hDC;
284 LPDEVMODE lpDevMode = NULL;
285 LPDEVNAMES lpDevNames;
286 LPSTR lpszDriverName;
287 LPSTR lpszDeviceName;
288 LPSTR lpszPortName;
a17e237f 289
2bda0e17
KB
290 PRINTDLG pd;
291 // __GNUWIN32__ has trouble believing PRINTDLG is 66 bytes - thinks it is 68
7bcb11d3 292#ifdef __GNUWIN32__
2bda0e17 293 pd.lStructSize = 66; // sizeof(PRINTDLG);
7bcb11d3
JS
294#else
295 pd.lStructSize = sizeof(PRINTDLG);
296#endif
2bda0e17
KB
297 pd.hwndOwner = (HWND)NULL;
298 pd.hDevMode = NULL; // Will be created by PrintDlg
299 pd.hDevNames = NULL; // Ditto
300 pd.Flags = PD_RETURNDEFAULT;
301 pd.nCopies = 1;
a17e237f 302
2bda0e17
KB
303 if (!PrintDlg((LPPRINTDLG)&pd))
304 {
305 if ( pd.hDevMode )
306 GlobalFree(pd.hDevMode);
307 if (pd.hDevNames)
308 GlobalFree(pd.hDevNames);
a17e237f 309
2bda0e17
KB
310 return(0);
311 }
a17e237f 312
2bda0e17
KB
313 if (!pd.hDevNames)
314 {
315 if ( pd.hDevMode )
316 GlobalFree(pd.hDevMode);
317 }
a17e237f 318
2bda0e17
KB
319 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
320 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
321 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
322 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
323 GlobalUnlock(pd.hDevNames);
a17e237f 324
2bda0e17
KB
325 if ( pd.hDevMode )
326 {
327 lpDevMode = (DEVMODE*) GlobalLock(pd.hDevMode);
328 lpDevMode->dmOrientation = orientation;
329 lpDevMode->dmFields |= DM_ORIENTATION;
330 }
a17e237f 331
2bda0e17
KB
332#ifdef __WIN32__
333 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (DEVMODE *)lpDevMode);
334#else
335 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (LPSTR)lpDevMode);
336#endif
a17e237f 337
2bda0e17
KB
338 if (pd.hDevMode && lpDevMode)
339 GlobalUnlock(pd.hDevMode);
a17e237f 340
2bda0e17
KB
341 if (pd.hDevNames)
342 {
7bcb11d3
JS
343 GlobalFree(pd.hDevNames);
344 pd.hDevNames=NULL;
2bda0e17
KB
345 }
346 if (pd.hDevMode)
347 {
348 GlobalFree(pd.hDevMode);
349 pd.hDevMode=NULL;
350 }
351 return (WXHDC) hDC;
352}
7bcb11d3
JS
353#endif
354
355// Gets an HDC for the specified printer configuration
356WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
357{
358 wxPrintData printData = printDataConst;
359 printData.ConvertToNative();
a17e237f 360
837e5743 361 wxChar* driverName = (wxChar*) NULL;
a17e237f 362
7bcb11d3 363 wxString devNameStr = printData.GetPrinterName();
837e5743 364 wxChar* portName = (wxChar*) NULL; // Obsolete in WIN32
a17e237f 365
4b7f2165
VZ
366 const wxChar* deviceName;
367 if ( !devNameStr )
837e5743 368 deviceName = (wxChar*) NULL;
7bcb11d3 369 else
4b7f2165 370 deviceName = devNameStr.c_str();
7bcb11d3
JS
371
372 LPDEVMODE lpDevMode = (LPDEVMODE) NULL;
373
48c12cb1 374 HGLOBAL hDevMode = (HGLOBAL)(DWORD) printData.GetNativeData();
7bcb11d3
JS
375
376 if ( hDevMode )
377 lpDevMode = (DEVMODE*) GlobalLock(hDevMode);
378
4b7f2165 379 if ( !devNameStr )
7bcb11d3
JS
380 {
381 // Retrieve the default device name
382 wxString portName;
a17e237f
VZ
383#ifdef __WXDEBUG__
384 bool ret =
385#else // !Debug
386 (void)
387#endif // Debug/Release
388 wxGetDefaultDeviceName(devNameStr, portName);
7bcb11d3 389
223d09f6 390 wxASSERT_MSG( ret, wxT("Could not get default device name.") );
2bda0e17 391
4b7f2165 392 deviceName = devNameStr.c_str();
7bcb11d3 393 }
a17e237f 394
7bcb11d3
JS
395#ifdef __WIN32__
396 HDC hDC = CreateDC(driverName, deviceName, portName, (DEVMODE *) lpDevMode);
397#else
398 HDC hDC = CreateDC(driverName, deviceName, portName, (LPSTR) lpDevMode);
399#endif
a17e237f 400
7bcb11d3
JS
401 if (hDevMode && lpDevMode)
402 GlobalUnlock(hDevMode);
a17e237f 403
7bcb11d3
JS
404 return (WXHDC) hDC;
405}
2bda0e17 406
4b7f2165
VZ
407// ----------------------------------------------------------------------------
408// wxPrinterDC bit blitting/bitmap drawing
409// ----------------------------------------------------------------------------
410
411void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
412 wxCoord x, wxCoord y,
413 bool useMask)
414{
415 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
416
417 int width = bmp.GetWidth(),
418 height = bmp.GetHeight();
419
420 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
421 {
422 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
423 memset( info, 0, sizeof( BITMAPINFOHEADER ) );
424
425 int iBitsSize = ((width + 3 ) & ~3 ) * height;
426
427 void* bits = malloc( iBitsSize );
428
429 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
430 info->bmiHeader.biWidth = width;
431 info->bmiHeader.biHeight = height;
432 info->bmiHeader.biPlanes = 1;
433 info->bmiHeader.biBitCount = 8;
434 info->bmiHeader.biCompression = BI_RGB;
435
436 ScreenHDC display;
437 if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
438 bmp.GetHeight(), bits, info,
439 DIB_RGB_COLORS) )
440 {
441 if ( ::StretchDIBits(GetHdc(), x, y,
442 width, height,
443 0 , 0, width, height,
444 bits, info,
445 DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
446 {
447 wxLogLastError("StretchDIBits");
448 }
449 }
450
451 free(bits);
452 free(info);
453 }
454 else // no support for StretchDIBits()
455 {
456 wxMemoryDC memDC;
457 memDC.SelectObject(bmp);
458
459 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
460
461 memDC.SelectObject(wxNullBitmap);
462 }
463}
464
465bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
466 wxCoord width, wxCoord height,
467 wxDC *source,
468 wxCoord xsrc, wxCoord ysrc,
469 int rop, bool useMask)
470{
471 bool success = TRUE;
472
473 if ( useMask )
474 {
475 // If we are printing source colours are screen colours
476 // not printer colours and so we need copy the bitmap
477 // pixel by pixel.
478 RECT rect;
479 HDC dc_src = GetHdcOf(*source);
480 HDC dc_mask = ::CreateCompatibleDC(dc_src);
481
482 ::SelectObject(dc_mask, (HBITMAP) source->GetSelectedBitmap().GetMask()->GetMaskBitmap());
483 for (int x = 0; x < width; x++)
484 {
485 for (int y = 0; y < height; y++)
486 {
487 COLORREF cref = ::GetPixel(dc_mask, x, y);
488 if (cref)
489 {
490 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
491 rect.left = xdest + x;
492 rect.right = rect.left + 1;
493 rect.top = ydest + y;
494 rect.bottom = rect.top + 1;
495 ::FillRect(GetHdc(), &rect, brush);
496 ::DeleteObject(brush);
497 }
498 }
499 }
500 ::SelectObject(dc_mask, 0);
501 ::DeleteDC(dc_mask);
502 }
503 else // no mask
504 {
505 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
506 {
507 wxBitmap& bmp = source->GetSelectedBitmap();
508 int width = bmp.GetWidth(),
509 height = bmp.GetHeight();
510
511 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
512 int iBitsSize = ((width + 3 ) & ~3 ) * height;
513
514 void* bits = malloc( iBitsSize );
515
516 memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
517
518 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
519 info->bmiHeader.biWidth = width;
520 info->bmiHeader.biHeight = height;
521 info->bmiHeader.biPlanes = 1;
522 info->bmiHeader.biBitCount = 8;
523 info->bmiHeader.biCompression = BI_RGB;
524
525 ScreenHDC display;
526 if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
527 height, bits, info, DIB_RGB_COLORS) )
528 {
529 wxLogLastError("GetDIBits");
530
531 success = FALSE;
532 }
533
534 if ( success )
535 {
536 success = ::StretchDIBits(GetHdc(), xdest, ydest,
537 width, height,
538 xsrc, ysrc,
539 width, height,
540 bits, info ,
541 DIB_RGB_COLORS,
542 SRCCOPY) != GDI_ERROR;
543 if ( !success )
544 {
545 wxLogLastError("StretchDIBits");
546 }
547 }
548
549 free(bits);
550 free(info);
551 }
552 else // no support for StretchDIBits
553 {
554 // as we are printing, source colours are screen colours not printer
555 // colours and so we need copy the bitmap pixel by pixel.
556 HDC dc_src = GetHdcOf(*source);
557 RECT rect;
558 for (int y = 0; y < height; y++)
559 {
560 // This is Stefan Csomor's optimisation, where identical adjacent
561 // pixels are drawn together.
562 for (int x = 0; x < width; x++)
563 {
564 COLORREF col = ::GetPixel(dc_src, x, y);
565 HBRUSH brush = ::CreateSolidBrush( col );
566
567 rect.left = xdest + x;
568 rect.top = ydest + y;
569 while( (x + 1 < width) && (::GetPixel(dc_src, x + 1, y) == col ) )
570 {
571 ++x;
572 }
573 rect.right = xdest + x + 1;
574 rect.bottom = rect.top + 1;
575 ::FillRect((HDC) m_hDC, &rect, brush);
576 ::DeleteObject(brush);
577 }
578 }
579 }
580 }
581
582 return success;
583}