1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include "qprintengine_win_p.h"
48 #include <private/qprinter_p.h>
49 #include <private/qfont_p.h>
50 #include <private/qfontengine_p.h>
51 #include <private/qpainter_p.h>
57 #include <qpa/qplatformpixmap.h>
58 #include <private/qpicture_p.h>
59 #include <private/qpixmap_raster_p.h>
60 #include <QtCore/QMetaType>
61 #include <QtCore/qt_windows.h>
63 Q_DECLARE_METATYPE(HFONT)
64 Q_DECLARE_METATYPE(LOGFONT)
68 Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
69 extern QPainterPath qt_regionToPath(const QRegion ®ion);
71 // #define QT_DEBUG_DRAW
73 static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
74 bool convertToText, const QTransform &xform, const QPointF &topLeft);
78 QPrinter::PaperSize qtSizeName;
80 { DMPAPER_LETTER, QPrinter::Letter },
81 { DMPAPER_LETTERSMALL, QPrinter::Letter },
82 { DMPAPER_TABLOID, QPrinter::Tabloid },
83 { DMPAPER_LEDGER, QPrinter::Ledger },
84 { DMPAPER_LEGAL, QPrinter::Legal },
85 { DMPAPER_EXECUTIVE, QPrinter::Executive },
86 { DMPAPER_A3, QPrinter::A3 },
87 { DMPAPER_A4, QPrinter::A4 },
88 { DMPAPER_A4SMALL, QPrinter::A4 },
89 { DMPAPER_A5, QPrinter::A5 },
90 { DMPAPER_B4, QPrinter::B4 },
91 { DMPAPER_B5, QPrinter::B5 },
92 { DMPAPER_FOLIO, QPrinter::Folio },
93 { DMPAPER_ENV_10, QPrinter::Comm10E },
94 { DMPAPER_ENV_DL, QPrinter::DLE },
95 { DMPAPER_ENV_C3, QPrinter::C5E },
96 { DMPAPER_LETTER_EXTRA, QPrinter::Letter },
97 { DMPAPER_LEGAL_EXTRA, QPrinter::Legal },
98 { DMPAPER_TABLOID_EXTRA, QPrinter::Tabloid },
99 { DMPAPER_A4_EXTRA, QPrinter::A4},
100 { DMPAPER_LETTER_TRANSVERSE, QPrinter::Letter},
101 { DMPAPER_A4_TRANSVERSE, QPrinter::A4},
102 { DMPAPER_LETTER_EXTRA_TRANSVERSE, QPrinter::Letter },
103 { DMPAPER_A_PLUS, QPrinter::A4 },
104 { DMPAPER_B_PLUS, QPrinter::A3 },
105 { DMPAPER_LETTER_PLUS, QPrinter::Letter },
106 { DMPAPER_A4_PLUS, QPrinter::A4 },
107 { DMPAPER_A5_TRANSVERSE, QPrinter::A5 },
108 { DMPAPER_B5_TRANSVERSE, QPrinter::B5 },
109 { DMPAPER_A3_EXTRA, QPrinter::A3 },
110 { DMPAPER_A5_EXTRA, QPrinter::A5 },
111 { DMPAPER_B5_EXTRA, QPrinter::B5 },
112 { DMPAPER_A2, QPrinter::A2 },
113 { DMPAPER_A3_TRANSVERSE, QPrinter::A3 },
114 { DMPAPER_A3_EXTRA_TRANSVERSE,QPrinter::A3 },
115 { 0, QPrinter::Custom }
118 QPrinter::PaperSize mapDevmodePaperSize(int s)
121 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
123 return dmMapping[i].qtSizeName;
126 static int mapPaperSizeDevmode(QPrinter::PaperSize s)
129 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
131 return dmMapping[i].winSizeName;
134 static const struct {
136 QPrinter::PaperSource qtSourceName;
138 { DMBIN_ONLYONE, QPrinter::OnlyOne },
139 { DMBIN_LOWER, QPrinter::Lower },
140 { DMBIN_MIDDLE, QPrinter::Middle },
141 { DMBIN_MANUAL, QPrinter::Manual },
142 { DMBIN_ENVELOPE, QPrinter::Envelope },
143 { DMBIN_ENVMANUAL, QPrinter::EnvelopeManual },
144 { DMBIN_AUTO, QPrinter::Auto },
145 { DMBIN_TRACTOR, QPrinter::Tractor },
146 { DMBIN_SMALLFMT, QPrinter::SmallFormat },
147 { DMBIN_LARGEFMT, QPrinter::LargeFormat },
148 { DMBIN_LARGECAPACITY, QPrinter::LargeCapacity },
149 { DMBIN_CASSETTE, QPrinter::Cassette },
150 { DMBIN_FORMSOURCE, QPrinter::FormSource },
151 { 0, (QPrinter::PaperSource) -1 }
154 static QPrinter::PaperSource mapDevmodePaperSource(int s)
157 while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
159 return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
162 static int mapPaperSourceDevmode(QPrinter::PaperSource s)
165 while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
167 return sources[i].winSourceName ? sources[i].winSourceName : s;
170 QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
171 : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
172 PaintEngineFeatures(PrimitiveTransform
174 | PerspectiveTransform
177 | PaintOutsidePaintEvent))
179 Q_D(QWin32PrintEngine);
180 d->docName = QLatin1String("document1");
186 bool QWin32PrintEngine::begin(QPaintDevice *pdev)
188 Q_D(QWin32PrintEngine);
190 QAlphaPaintEngine::begin(pdev);
199 // ### set default colors and stuff...
201 bool ok = d->state == QPrinter::Idle;
206 // Assign the FILE: to get the query...
207 if (d->printToFile && d->fileName.isEmpty())
208 d->fileName = d->port;
210 d->devMode->dmCopies = d->num_copies;
213 memset(&di, 0, sizeof(DOCINFO));
214 di.cbSize = sizeof(DOCINFO);
215 di.lpszDocName = reinterpret_cast<const wchar_t *>(d->docName.utf16());
216 if (d->printToFile && !d->fileName.isEmpty())
217 di.lpszOutput = reinterpret_cast<const wchar_t *>(d->fileName.utf16());
218 if (ok && StartDoc(d->hdc, &di) == SP_ERROR) {
219 qErrnoWarning("QWin32PrintEngine::begin: StartDoc failed");
223 if (StartPage(d->hdc) <= 0) {
224 qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
229 d->state = QPrinter::Idle;
231 d->state = QPrinter::Active;
234 d->matrix = QTransform();
236 d->pen = QColor(Qt::black);
237 d->has_brush = false;
239 d->complex_xform = false;
241 updateMatrix(d->matrix);
249 bool QWin32PrintEngine::end()
251 Q_D(QWin32PrintEngine);
254 if (d->state == QPrinter::Aborted) {
261 QAlphaPaintEngine::end();
266 EndPage(d->hdc); // end; printing done
270 d->state = QPrinter::Idle;
275 bool QWin32PrintEngine::newPage()
277 Q_D(QWin32PrintEngine);
278 Q_ASSERT(isActive());
284 bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
286 if (!EndPage(d->hdc)) {
287 qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
293 qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
299 if (!StartPage(d->hdc)) {
300 qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
304 SetTextAlign(d->hdc, TA_BASELINE);
306 SetBkMode(d->hdc, TRANSPARENT);
311 bool success = false;
312 if (d->hdc && d->state == QPrinter::Active) {
313 if (EndPage(d->hdc) != SP_ERROR) {
314 // reinitialize the DC before StartPage if needed,
315 // because resetdc is disabled between calls to the StartPage and EndPage functions
316 // (see StartPage documentation in the Platform SDK:Windows GDI)
317 // state = PST_ACTIVEDOC;
319 // state = PST_ACTIVE;
320 // start the new page now
323 qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
326 success = (StartPage(d->hdc) != SP_ERROR);
329 d->state = QPrinter::Aborted;
336 bool QWin32PrintEngine::abort()
342 void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
344 Q_D(const QWin32PrintEngine);
346 QAlphaPaintEngine::drawTextItem(p, textItem);
350 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
351 QRgb brushColor = state->pen().brush().color().rgb();
352 bool fallBack = state->pen().brush().style() != Qt::SolidPattern
353 || qAlpha(brushColor) != 0xff
354 || d->txop >= QTransform::TxProject
355 || ti.fontEngine->type() != QFontEngine::Win;
358 const QVariant hFontV = ti.fontEngine->property("hFont");
359 const QVariant logFontV = ti.fontEngine->property("logFont");
360 if (hFontV.canConvert<HFONT>() && logFontV.canConvert<LOGFONT>()) {
361 const HFONT hfont = hFontV.value<HFONT>();
362 const LOGFONT logFont = logFontV.value<LOGFONT>();
363 // Try selecting the font to see if we get a substitution font
364 SelectObject(d->hdc, hfont);
365 if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
367 GetTextFace(d->hdc, 64, n);
368 fallBack = QString::fromWCharArray(n)
369 != QString::fromWCharArray(logFont.lfFaceName);
376 QPaintEngine::drawTextItem(p, textItem);
380 // We only want to convert the glyphs to text if the entire string is compatible with ASCII
381 // and if we actually have access to the chars.
382 bool convertToText = ti.chars != 0;
383 for (int i=0; i < ti.num_chars; ++i) {
384 if (ti.chars[i].unicode() >= 0x80) {
385 convertToText = false;
389 if (ti.logClusters[i] != i) {
390 convertToText = false;
395 COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
396 SelectObject(d->hdc, CreateSolidBrush(cf));
397 SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
398 SetTextColor(d->hdc, cf);
400 draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, d->devPaperRect.topLeft());
401 DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
402 DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
405 static inline qreal mmToInches(double mm)
407 return mm*0.039370147;
410 static inline qreal inchesToMM(double in)
412 return in/0.039370147;
415 int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
417 Q_D(const QWin32PrintEngine);
423 int res = d->resolution;
426 case QPaintDevice::PdmWidth:
427 if (d->has_custom_paper_size) {
428 val = qRound(d->paper_size.width() * res / 72.0);
430 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
431 if (logPixelsX == 0) {
432 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
433 "might be a driver problem");
434 logPixelsX = 600; // Reasonable default
437 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
440 if (d->pageMarginsSet)
441 val -= int(mmToInches((d->previousDialogMargins.left() +
442 d->previousDialogMargins.width()) / 100.0) * res);
444 case QPaintDevice::PdmHeight:
445 if (d->has_custom_paper_size) {
446 val = qRound(d->paper_size.height() * res / 72.0);
448 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
449 if (logPixelsY == 0) {
450 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
451 "might be a driver problem");
452 logPixelsY = 600; // Reasonable default
455 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
458 if (d->pageMarginsSet)
459 val -= int(mmToInches((d->previousDialogMargins.top() +
460 d->previousDialogMargins.height()) / 100.0) * res);
462 case QPaintDevice::PdmDpiX:
465 case QPaintDevice::PdmDpiY:
468 case QPaintDevice::PdmPhysicalDpiX:
469 val = GetDeviceCaps(d->hdc, LOGPIXELSX);
471 case QPaintDevice::PdmPhysicalDpiY:
472 val = GetDeviceCaps(d->hdc, LOGPIXELSY);
474 case QPaintDevice::PdmWidthMM:
475 if (d->has_custom_paper_size) {
476 val = qRound(d->paper_size.width()*25.4/72);
479 val = GetDeviceCaps(d->hdc, HORZSIZE);
481 float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
482 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
483 if (logPixelsX == 0) {
484 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
485 "might be a driver problem");
486 logPixelsX = 600; // Reasonable default
488 val = qRound(wi / logPixelsX);
491 if (d->pageMarginsSet)
492 val -= (d->previousDialogMargins.left() +
493 d->previousDialogMargins.width()) / 100.0;
495 case QPaintDevice::PdmHeightMM:
496 if (d->has_custom_paper_size) {
497 val = qRound(d->paper_size.height()*25.4/72);
500 val = GetDeviceCaps(d->hdc, VERTSIZE);
502 float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
503 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
504 if (logPixelsY == 0) {
505 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
506 "might be a driver problem");
507 logPixelsY = 600; // Reasonable default
509 val = qRound(hi / logPixelsY);
512 if (d->pageMarginsSet)
513 val -= (d->previousDialogMargins.top() +
514 d->previousDialogMargins.height()) / 100.0;
516 case QPaintDevice::PdmNumColors:
518 int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
522 val = GetDeviceCaps(d->hdc, NUMCOLORS);
524 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
527 case QPaintDevice::PdmDepth:
528 val = GetDeviceCaps(d->hdc, PLANES);
531 qWarning("QPrinter::metric: Invalid metric command");
537 void QWin32PrintEngine::updateState(const QPaintEngineState &state)
539 Q_D(QWin32PrintEngine);
541 QAlphaPaintEngine::updateState(state);
545 if (state.state() & DirtyTransform) {
546 updateMatrix(state.transform());
549 if (state.state() & DirtyPen) {
550 d->pen = state.pen();
551 d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
554 if (state.state() & DirtyBrush) {
555 QBrush brush = state.brush();
556 d->has_brush = brush.style() == Qt::SolidPattern;
557 d->brush_color = brush.color();
560 if (state.state() & DirtyClipEnabled) {
561 if (state.isClipEnabled())
562 updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
564 updateClipPath(QPainterPath(), Qt::NoClip);
567 if (state.state() & DirtyClipPath) {
568 updateClipPath(state.clipPath(), state.clipOperation());
571 if (state.state() & DirtyClipRegion) {
572 QRegion clipRegion = state.clipRegion();
573 QPainterPath clipPath = qt_regionToPath(clipRegion);
574 updateClipPath(clipPath, state.clipOperation());
578 void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
580 Q_D(QWin32PrintEngine);
583 if (op == Qt::NoClip) {
584 SelectClipRgn(d->hdc, 0);
589 QPainterPath xformed = clipPath * d->matrix;
591 if (xformed.isEmpty()) {
592 // QRegion empty(-0x1000000, -0x1000000, 1, 1);
593 HRGN empty = CreateRectRgn(-0x1000000, -0x1000000, -0x0fffffff, -0x0ffffff);
594 SelectClipRgn(d->hdc, empty);
597 d->composeGdiPath(xformed);
599 -1, // Qt::NoClip, covered above
600 RGN_COPY, // Qt::ReplaceClip
601 RGN_AND, // Qt::IntersectClip
602 RGN_OR // Qt::UniteClip
604 Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
605 SelectClipPath(d->hdc, ops[op]);
609 QPainterPath aclip = qt_regionToPath(alphaClipping());
610 if (!aclip.isEmpty()) {
611 QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
612 d->composeGdiPath(tx.map(aclip));
613 SelectClipPath(d->hdc, RGN_DIFF);
617 void QWin32PrintEngine::updateMatrix(const QTransform &m)
619 Q_D(QWin32PrintEngine);
621 QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
622 d->painterMatrix = m;
623 d->matrix = d->painterMatrix * stretch;
624 d->txop = d->matrix.type();
625 d->complex_xform = (d->txop > QTransform::TxScale);
631 HBitmapPremultipliedAlpha,
635 void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
636 const QPixmap &originalPixmap,
637 const QRectF &sourceRect)
639 Q_D(QWin32PrintEngine);
641 QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
645 const int tileSize = 2048;
647 QRectF r = targetRect;
648 QRectF sr = sourceRect;
650 QPixmap pixmap = originalPixmap;
651 if (sr.size() != pixmap.size()) {
652 pixmap = pixmap.copy(sr.toRect());
658 QTransform scaleMatrix = QTransform::fromScale(r.width() / pixmap.width(), r.height() / pixmap.height());
659 QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
660 pixmap.width(), pixmap.height());
662 qreal xform_offset_x = adapted.dx();
663 qreal xform_offset_y = adapted.dy();
665 if (d->complex_xform) {
666 pixmap = pixmap.transformed(adapted);
667 scaleX = d->stretch_x;
668 scaleY = d->stretch_y;
670 scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
671 scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
674 QPointF topLeft = r.topLeft() * d->painterMatrix;
675 int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
676 int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
677 int tw = qAbs(int(pixmap.width() * scaleX));
678 int th = qAbs(int(pixmap.height() * scaleY));
680 xform_offset_x *= d->stretch_x;
681 xform_offset_y *= d->stretch_y;
683 int dc_state = SaveDC(d->hdc);
685 int tilesw = pixmap.width() / tileSize;
686 int tilesh = pixmap.height() / tileSize;
690 int txinc = tileSize*scaleX;
691 int tyinc = tileSize*scaleY;
693 for (int y = 0; y < tilesh; ++y) {
694 int tposy = ty + (y * tyinc);
697 if (y == (tilesh - 1)) {
698 imgh = pixmap.height() - (y * tileSize);
699 height = (th - (y * tyinc));
701 for (int x = 0; x < tilesw; ++x) {
702 int tposx = tx + (x * txinc);
705 if (x == (tilesw - 1)) {
706 imgw = pixmap.width() - (x * tileSize);
707 width = (tw - (x * txinc));
710 QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
711 HBITMAP hbitmap = qt_pixmapToWinHBITMAP(p, HBitmapNoAlpha);
712 HDC display_dc = GetDC(0);
713 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
714 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
716 ReleaseDC(0, display_dc);
718 if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
719 hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
720 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
722 SelectObject(hbitmap_hdc, null_bitmap);
723 DeleteObject(hbitmap);
724 DeleteDC(hbitmap_hdc);
728 RestoreDC(d->hdc, dc_state);
732 void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
734 Q_D(QWin32PrintEngine);
736 QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
740 if (d->complex_xform || !pos.isNull()) {
741 QPaintEngine::drawTiledPixmap(r, pm, pos);
743 int dc_state = SaveDC(d->hdc);
745 HDC display_dc = GetDC(0);
746 HBITMAP hbitmap = qt_pixmapToWinHBITMAP(pm, HBitmapNoAlpha);
747 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
748 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
750 ReleaseDC(0, display_dc);
752 QRectF trect = d->painterMatrix.mapRect(r);
753 int tx = int(trect.left() * d->stretch_x + d->origin_x);
754 int ty = int(trect.top() * d->stretch_y + d->origin_y);
756 int xtiles = int(trect.width() / pm.width()) + 1;
757 int ytiles = int(trect.height() / pm.height()) + 1;
758 int xinc = int(pm.width() * d->stretch_x);
759 int yinc = int(pm.height() * d->stretch_y);
761 for (int y = 0; y < ytiles; ++y) {
762 int ity = ty + (yinc * y);
763 int ith = pm.height();
764 if (y == (ytiles - 1)) {
765 ith = int(trect.height() - (pm.height() * y));
768 for (int x = 0; x < xtiles; ++x) {
769 int itx = tx + (xinc * x);
770 int itw = pm.width();
771 if (x == (xtiles - 1)) {
772 itw = int(trect.width() - (pm.width() * x));
775 if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
776 hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
777 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
782 SelectObject(hbitmap_hdc, null_bitmap);
783 DeleteObject(hbitmap);
784 DeleteDC(hbitmap_hdc);
786 RestoreDC(d->hdc, dc_state);
791 void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
794 qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
796 // Drawing the subpaths
798 for (int i=0; i<path.elementCount(); ++i) {
799 const QPainterPath::Element &elm = path.elementAt(i);
801 case QPainterPath::MoveToElement:
803 && path.elementAt(start).x == path.elementAt(i-1).x
804 && path.elementAt(start).y == path.elementAt(i-1).y)
807 MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
809 case QPainterPath::LineToElement:
810 LineTo(hdc, qRound(elm.x), qRound(elm.y));
812 case QPainterPath::CurveToElement: {
814 { qRound(elm.x), qRound(elm.y) },
815 { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
816 { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
819 PolyBezierTo(hdc, pts, 3);
823 qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
828 && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
829 && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
833 qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
835 SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
839 void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
842 qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
845 composeGdiPath(path);
847 HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
848 HGDIOBJ old_brush = SelectObject(hdc, brush);
850 DeleteObject(SelectObject(hdc, old_brush));
853 void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
855 composeGdiPath(path);
857 brush.lbStyle = BS_SOLID;
858 brush.lbColor = RGB(color.red(), color.green(), color.blue());
859 DWORD capStyle = PS_ENDCAP_SQUARE;
860 DWORD joinStyle = PS_JOIN_BEVEL;
861 if (pen.capStyle() == Qt::FlatCap)
862 capStyle = PS_ENDCAP_FLAT;
863 else if (pen.capStyle() == Qt::RoundCap)
864 capStyle = PS_ENDCAP_ROUND;
866 if (pen.joinStyle() == Qt::MiterJoin)
867 joinStyle = PS_JOIN_MITER;
868 else if (pen.joinStyle() == Qt::RoundJoin)
869 joinStyle = PS_JOIN_ROUND;
871 HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
872 | PS_SOLID | capStyle | joinStyle,
873 (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
875 HGDIOBJ old_pen = SelectObject(hdc, pen);
877 DeleteObject(SelectObject(hdc, old_pen));
881 void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
883 fillPath_dev(path * matrix, color);
886 void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
888 QPainterPathStroker stroker;
889 if (pen.style() == Qt::CustomDashLine) {
890 stroker.setDashPattern(pen.dashPattern());
891 stroker.setDashOffset(pen.dashOffset());
893 stroker.setDashPattern(pen.style());
895 stroker.setCapStyle(pen.capStyle());
896 stroker.setJoinStyle(pen.joinStyle());
897 stroker.setMiterLimit(pen.miterLimit());
900 qreal width = pen.widthF();
901 if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
902 strokePath_dev(path * matrix, color, width);
904 stroker.setWidth(width);
905 if (pen.isCosmetic()) {
906 stroke = stroker.createStroke(path * matrix);
908 stroke = stroker.createStroke(path) * painterMatrix;
909 QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
910 stroke = stroke * stretch;
913 if (stroke.isEmpty())
916 fillPath_dev(stroke, color);
921 void QWin32PrintEngine::drawPath(const QPainterPath &path)
924 qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
927 Q_D(QWin32PrintEngine);
929 QAlphaPaintEngine::drawPath(path);
934 d->fillPath(path, d->brush_color);
937 d->strokePath(path, d->pen.color());
941 void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
944 qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
947 QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
951 Q_ASSERT(pointCount > 1);
953 QPainterPath path(points[0]);
955 for (int i=1; i<pointCount; ++i) {
956 path.lineTo(points[i]);
959 Q_D(QWin32PrintEngine);
961 bool has_brush = d->has_brush;
963 if (mode == PolylineMode)
964 d->has_brush = false; // No brush for polylines
966 path.closeSubpath(); // polygons are should always be closed.
969 d->has_brush = has_brush;
972 void QWin32PrintEnginePrivate::queryDefault()
974 QWin32PrintEngine::queryDefaultPrinter(name, program, port);
977 QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
983 void QWin32PrintEnginePrivate::initialize()
995 txop = QTransform::TxNone;
997 bool ok = OpenPrinter((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
999 qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
1003 // Fetch the PRINTER_INFO_2 with DEVMODE data containing the
1004 // printer settings.
1005 DWORD infoSize, numBytes;
1006 GetPrinter(hPrinter, 2, NULL, 0, &infoSize);
1007 hMem = GlobalAlloc(GHND, infoSize);
1008 pInfo = (PRINTER_INFO_2*) GlobalLock(hMem);
1009 ok = GetPrinter(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes);
1012 qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
1013 GlobalUnlock(pInfo);
1015 ClosePrinter(hPrinter);
1022 devMode = pInfo->pDevMode;
1023 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1024 reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
1030 num_copies = devMode->dmCopies;
1035 #ifdef QT_DEBUG_DRAW
1036 qDebug() << "QWin32PrintEngine::initialize()" << endl
1037 << " - paperRect" << devPaperRect << endl
1038 << " - pageRect" << devPageRect << endl
1039 << " - stretch_x" << stretch_x << endl
1040 << " - stretch_y" << stretch_y << endl
1041 << " - origin_x" << origin_x << endl
1042 << " - origin_y" << origin_y << endl;
1046 void QWin32PrintEnginePrivate::initHDC()
1050 HDC display_dc = GetDC(0);
1051 dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1052 dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1053 dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
1054 ReleaseDC(0, display_dc);
1055 if (dpi_display == 0) {
1056 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
1057 "might be a driver problem");
1058 dpi_display = 96; // Reasonable default
1062 case QPrinter::ScreenResolution:
1063 resolution = dpi_display;
1064 stretch_x = dpi_x / double(dpi_display);
1065 stretch_y = dpi_y / double(dpi_display);
1067 case QPrinter::PrinterResolution:
1068 case QPrinter::HighResolution:
1080 void QWin32PrintEnginePrivate::initDevRects()
1082 devPaperRect = QRect(0, 0,
1083 GetDeviceCaps(hdc, PHYSICALWIDTH),
1084 GetDeviceCaps(hdc, PHYSICALHEIGHT));
1085 devPhysicalPageRect = QRect(GetDeviceCaps(hdc, PHYSICALOFFSETX),
1086 GetDeviceCaps(hdc, PHYSICALOFFSETY),
1087 GetDeviceCaps(hdc, HORZRES),
1088 GetDeviceCaps(hdc, VERTRES));
1089 if (!pageMarginsSet)
1090 devPageRect = devPhysicalPageRect;
1092 devPageRect = devPaperRect.adjusted(qRound(mmToInches(previousDialogMargins.left() / 100.0) * dpi_x),
1093 qRound(mmToInches(previousDialogMargins.top() / 100.0) * dpi_y),
1094 -qRound(mmToInches(previousDialogMargins.width() / 100.0) * dpi_x),
1095 -qRound(mmToInches(previousDialogMargins.height() / 100.0) * dpi_y));
1099 void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
1101 pageMarginsSet = true;
1102 previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
1104 devPageRect = devPaperRect.adjusted(qRound(mmToInches(marginLeft / 100.0) * dpi_x),
1105 qRound(mmToInches(marginTop / 100.0) * dpi_y),
1106 - qRound(mmToInches(marginRight / 100.0) * dpi_x),
1107 - qRound(mmToInches(marginBottom / 100.0) * dpi_y));
1111 QRect QWin32PrintEnginePrivate::getPageMargins() const
1114 return previousDialogMargins;
1116 return QRect(qRound(inchesToMM(devPhysicalPageRect.left()) * 100.0 / dpi_x),
1117 qRound(inchesToMM(devPhysicalPageRect.top()) * 100.0 / dpi_y),
1118 qRound(inchesToMM(devPaperRect.right() - devPhysicalPageRect.right()) * 100.0 / dpi_x),
1119 qRound(inchesToMM(devPaperRect.bottom() - devPhysicalPageRect.bottom()) * 100.0 / dpi_y));
1122 void QWin32PrintEnginePrivate::release()
1127 if (globalDevMode) { // Devmode comes from print dialog
1128 GlobalUnlock(globalDevMode);
1129 } else { // Devmode comes from initialize...
1130 // devMode is a part of the same memory block as pInfo so one free is enough...
1135 ClosePrinter(hPrinter);
1145 QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
1147 // Read the supported resolutions of the printer.
1148 QList<QVariant> list;
1150 DWORD numRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1151 reinterpret_cast<const wchar_t *>(port.utf16()),
1152 DC_ENUMRESOLUTIONS, 0, 0);
1153 if (numRes == (DWORD)-1)
1156 LONG *enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
1157 DWORD errRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1158 reinterpret_cast<const wchar_t *>(port.utf16()),
1159 DC_ENUMRESOLUTIONS, (LPWSTR)enumRes, 0);
1161 if (errRes == (DWORD)-1) {
1162 qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
1166 for (uint i=0; i<numRes; ++i)
1167 list.append(int(enumRes[i * 2]));
1172 void QWin32PrintEnginePrivate::doReinit()
1174 if (state == QPrinter::Active) {
1183 void QWin32PrintEnginePrivate::updateOrigin()
1186 // subtract physical margins to make (0,0) absolute top corner of paper
1187 // then add user defined margins
1188 origin_x = -devPhysicalPageRect.x();
1189 origin_y = -devPhysicalPageRect.y();
1190 if (pageMarginsSet) {
1191 origin_x += devPageRect.left();
1192 origin_y += devPageRect.top();
1197 if (pageMarginsSet) {
1198 origin_x = devPageRect.left() - devPhysicalPageRect.x();
1199 origin_y = devPageRect.top() - devPhysicalPageRect.y();
1204 void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
1206 Q_D(QWin32PrintEngine);
1208 case PPK_CollateCopies:
1212 d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
1221 d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
1230 case PPK_DocumentName:
1232 qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
1235 d->docName = value.toString();
1239 d->fullPage = value.toBool();
1243 case PPK_CopyCount: // fallthrough
1244 case PPK_NumberOfCopies:
1247 d->num_copies = value.toInt();
1248 d->devMode->dmCopies = d->num_copies;
1252 case PPK_Orientation:
1256 int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
1257 int old_orientation = d->devMode->dmOrientation;
1258 d->devMode->dmOrientation = orientation;
1259 if (d->has_custom_paper_size && old_orientation != orientation)
1260 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1265 case PPK_OutputFileName:
1267 qWarning("QWin32PrintEngine: Cannot change filename while printing");
1269 d->fileName = value.toString();
1270 d->printToFile = !value.toString().isEmpty();
1277 d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1278 d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
1282 case PPK_PaperSource:
1286 int dmMapped = DMBIN_AUTO;
1288 QList<QVariant> v = property(PPK_PaperSources).toList();
1289 if (v.contains(value))
1290 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
1292 d->devMode->dmDefaultSource = dmMapped;
1297 case PPK_PrinterName:
1298 d->name = value.toString();
1299 if(d->name.isEmpty())
1304 case PPK_Resolution:
1306 d->resolution = value.toInt();
1308 d->stretch_x = d->dpi_x / double(d->resolution);
1309 d->stretch_y = d->dpi_y / double(d->resolution);
1313 case PPK_SelectionOption:
1317 case PPK_SupportedResolutions:
1322 case PPK_WindowsPageSize:
1325 d->has_custom_paper_size = false;
1326 d->devMode->dmPaperSize = value.toInt();
1330 case PPK_CustomPaperSize:
1332 d->has_custom_paper_size = true;
1333 d->paper_size = value.toSizeF();
1336 int orientation = d->devMode->dmOrientation;
1339 if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
1340 BYTE *forms = (BYTE *) malloc(needed);
1341 if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
1342 for (DWORD i=0; i< returned; ++i) {
1343 FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
1344 // the form sizes are specified in 1000th of a mm,
1345 // convert the size to Points
1346 QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
1347 (formArray[i].Size.cy * 72/25.4)/1000.0);
1348 if (qAbs(d->paper_size.width() - size.width()) <= 2
1349 && qAbs(d->paper_size.height() - size.height()) <= 2)
1351 d->devMode->dmPaperSize = i + 1;
1358 if (orientation != DMORIENT_PORTRAIT)
1359 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1363 case PPK_PageMargins:
1365 QList<QVariant> margins(value.toList());
1366 Q_ASSERT(margins.size() == 4);
1367 int left, top, right, bottom;
1368 // specified in 1/100 mm
1369 left = (margins.at(0).toReal()*25.4/72.0) * 100;
1370 top = (margins.at(1).toReal()*25.4/72.0) * 100;
1371 right = (margins.at(2).toReal()*25.4/72.0) * 100;
1372 bottom = (margins.at(3).toReal()*25.4/72.0) * 100;
1373 d->setPageMargins(left, top, right, bottom);
1382 QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
1384 Q_D(const QWin32PrintEngine);
1388 case PPK_CollateCopies:
1395 value = QPrinter::Color;
1397 value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
1402 case PPK_DocumentName:
1407 value = d->fullPage;
1411 value = d->num_copies;
1414 case PPK_SupportsMultipleCopies:
1418 case PPK_NumberOfCopies:
1422 case PPK_Orientation:
1425 value = QPrinter::Portrait;
1427 value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
1432 case PPK_OutputFileName:
1433 value = d->fileName;
1437 if (d->has_custom_paper_size) {
1439 qRound(d->paper_size.width() * d->resolution / 72.0),
1440 qRound(d->paper_size.height() * d->resolution / 72.0));
1441 if (d->pageMarginsSet) {
1442 rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
1443 qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
1444 -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
1445 -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
1449 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
1450 .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
1455 if (d->has_custom_paper_size) {
1456 value = QPrinter::Custom;
1459 value = QPrinter::A4;
1461 value = mapDevmodePaperSize(d->devMode->dmPaperSize);
1467 if (d->has_custom_paper_size) {
1469 qRound(d->paper_size.width() * d->resolution / 72.0),
1470 qRound(d->paper_size.height() * d->resolution / 72.0));
1472 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
1476 case PPK_PaperSource:
1478 value = QPrinter::Auto;
1480 value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
1484 case PPK_PrinterName:
1488 case PPK_Resolution:
1489 if (d->resolution || !d->name.isEmpty())
1490 value = d->resolution;
1493 case PPK_SupportedResolutions:
1494 value = d->queryResolutions();
1497 case PPK_WindowsPageSize:
1501 value = d->devMode->dmPaperSize;
1505 case PPK_PaperSources:
1507 int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1508 (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
1513 wchar_t *data = new wchar_t[available];
1514 int count = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1515 (const wchar_t *)d->port.utf16(), DC_BINS, data, d->devMode);
1517 QList<QVariant> out;
1518 for (int i=0; i<count; ++i) {
1519 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
1529 case PPK_CustomPaperSize:
1530 value = d->paper_size;
1533 case PPK_PageMargins:
1535 QList<QVariant> margins;
1536 QRect pageMargins(d->getPageMargins());
1538 // specified in 1/100 mm
1539 margins << (mmToInches(pageMargins.left()/100.0) * 72)
1540 << (mmToInches(pageMargins.top()/100.0) * 72)
1541 << (mmToInches(pageMargins.width()/100.0) * 72)
1542 << (mmToInches(pageMargins.height()/100.0) * 72);
1553 QPrinter::PrinterState QWin32PrintEngine::printerState() const
1555 return d_func()->state;
1558 HDC QWin32PrintEngine::getDC() const
1560 return d_func()->hdc;
1563 void QWin32PrintEngine::releaseDC(HDC) const
1568 QList<QPrinter::PaperSize> QWin32PrintEngine::supportedPaperSizes(const QPrinterInfo &printerInfo)
1570 QList<QPrinter::PaperSize> returnList;
1572 if (printerInfo.isNull())
1575 DWORD size = DeviceCapabilities(reinterpret_cast<const wchar_t *>(printerInfo.printerName().utf16()),
1576 NULL, DC_PAPERS, NULL, NULL);
1577 if ((int)size != -1) {
1578 wchar_t *papers = new wchar_t[size];
1579 size = DeviceCapabilities(reinterpret_cast<const wchar_t *>(printerInfo.printerName().utf16()),
1580 NULL, DC_PAPERS, papers, NULL);
1581 for (int c = 0; c < (int)size; ++c)
1582 returnList.append(mapDevmodePaperSize(papers[c]));
1588 void QWin32PrintEngine::queryDefaultPrinter(QString &name, QString &program, QString &port)
1590 /* Read the default printer name, driver and port with the intuitive function
1591 * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
1593 QString noPrinters(QLatin1String("qt_no_printers"));
1594 wchar_t buffer[256];
1595 GetProfileString(L"windows", L"device",
1596 reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
1598 QString output = QString::fromWCharArray(buffer);
1599 if (output.isEmpty() || output == noPrinters) // no printers
1602 QStringList info = output.split(QLatin1Char(','));
1603 int infoSize = info.size();
1607 if (program.isEmpty() && infoSize > 1)
1608 program = info.at(1);
1609 if (port.isEmpty() && infoSize > 2)
1614 HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
1616 int size = sizeof(DEVNAMES)
1617 + program.length() * 2 + 2
1618 + name.length() * 2 + 2
1619 + port.length() * 2 + 2;
1620 HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
1621 DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
1623 dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
1624 dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1625 dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1627 memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
1628 memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
1629 memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
1632 GlobalUnlock(hGlobal);
1634 // printf("QPrintDialogWinPrivate::createDevNames()\n"
1635 // " -> wDriverOffset: %d\n"
1636 // " -> wDeviceOffset: %d\n"
1637 // " -> wOutputOffset: %d\n",
1638 // dn->wDriverOffset,
1639 // dn->wDeviceOffset,
1640 // dn->wOutputOffset);
1642 // printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
1643 // QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset).latin1(),
1644 // QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset).latin1(),
1645 // QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset).latin1());
1650 void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
1652 if (globalDevnames) {
1653 DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
1654 name = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
1655 port = QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset);
1656 program = QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset);
1657 GlobalUnlock(globalDevnames);
1661 void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
1663 if (globalDevmode) {
1664 DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
1666 globalDevMode = globalDevmode;
1668 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1669 reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
1671 num_copies = devMode->dmCopies;
1672 if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
1673 qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1680 static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
1681 bool convertToText, const QTransform &xform, const QPointF &topLeft)
1683 QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
1685 SetTextAlign(hdc, TA_BASELINE);
1686 SetBkMode(hdc, TRANSPARENT);
1688 const bool has_kerning = ti.f && ti.f->kerning();
1693 if (ti.fontEngine->type() == QFontEngine::Win) {
1694 const QVariant hfontV = ti.fontEngine->property("hFont");
1695 const QVariant ttfV = ti.fontEngine->property("trueType");
1696 if (ttfV.type() == QVariant::Bool && hfontV.canConvert<HFONT>()) {
1697 hfont = hfontV.value<HFONT>();
1698 ttf = ttfV.toBool();
1703 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1705 HGDIOBJ old_font = SelectObject(hdc, hfont);
1706 unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
1707 wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
1708 QGlyphLayout glyphs = ti.glyphs;
1710 bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
1711 for (int i = 0; fast && i < glyphs.numGlyphs; i++) {
1712 if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
1713 || glyphs.attributes[i].dontPrint) {
1719 #if !defined(Q_OS_WINCE)
1720 // Scale, rotate and translate here.
1722 win_xform.eM11 = xform.m11();
1723 win_xform.eM12 = xform.m12();
1724 win_xform.eM21 = xform.m21();
1725 win_xform.eM22 = xform.m22();
1726 win_xform.eDx = xform.dx();
1727 win_xform.eDy = xform.dy();
1729 SetGraphicsMode(hdc, GM_ADVANCED);
1730 SetWorldTransform(hdc, &win_xform);
1735 QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
1736 for (int i = 0; i < glyphs.numGlyphs; ++i)
1737 g[i] = glyphs.glyphs[i];
1739 qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
1740 qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
1741 options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
1743 QVarLengthArray<QFixedPoint> positions;
1744 QVarLengthArray<glyph_t> _glyphs;
1746 QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y());
1747 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
1748 _glyphs, positions);
1749 if (_glyphs.size() == 0) {
1750 SelectObject(hdc, old_font);
1754 convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
1755 bool outputEntireItem = _glyphs.size() > 0;
1757 if (outputEntireItem) {
1759 QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
1760 QVarLengthArray<wchar_t> g(_glyphs.size());
1761 for (int i=0; i<_glyphs.size() - 1; ++i) {
1762 glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
1763 glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
1766 glyphDistances[(_glyphs.size() - 1) * 2] = 0;
1767 glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
1768 g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
1769 ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
1770 convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
1771 glyphDistances.data());
1774 while(i < _glyphs.size()) {
1775 wchar_t g = _glyphs[i];
1777 ExtTextOut(hdc, qRound(positions[i].x),
1778 qRound(positions[i].y), options, 0,
1779 convertToText ? convertedGlyphs + i : &g, 1, 0);
1785 #if !defined(Q_OS_WINCE)
1786 win_xform.eM11 = win_xform.eM22 = 1.0;
1787 win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
1788 SetWorldTransform(hdc, &win_xform);
1791 SelectObject(hdc, old_font);
1795 void QWin32PrintEnginePrivate::updateCustomPaperSize()
1797 uint paperSize = devMode->dmPaperSize;
1798 if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
1799 has_custom_paper_size = true;
1802 if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
1803 BYTE *forms = (BYTE *) malloc(needed);
1804 if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
1805 if (paperSize <= returned) {
1806 FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
1807 int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
1808 int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
1809 paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
1811 has_custom_paper_size = false;
1817 has_custom_paper_size = false;
1823 #endif // QT_NO_PRINTER