1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include "qprinter_p.h"
45 #include "qprintengine_win_p.h"
49 #include <private/qfont_p.h>
50 #include <private/qfontengine_p.h>
51 #include <private/qpainter_p.h>
57 #include <private/qpicture_p.h>
61 extern QPainterPath qt_regionToPath(const QRegion ®ion);
63 // #define QT_DEBUG_DRAW
65 static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
66 bool convertToText, const QTransform &xform, const QPointF &topLeft);
70 QPrinter::PaperSize qtSizeName;
72 { DMPAPER_LETTER, QPrinter::Letter },
73 { DMPAPER_LETTERSMALL, QPrinter::Letter },
74 { DMPAPER_TABLOID, QPrinter::Tabloid },
75 { DMPAPER_LEDGER, QPrinter::Ledger },
76 { DMPAPER_LEGAL, QPrinter::Legal },
77 { DMPAPER_EXECUTIVE, QPrinter::Executive },
78 { DMPAPER_A3, QPrinter::A3 },
79 { DMPAPER_A4, QPrinter::A4 },
80 { DMPAPER_A4SMALL, QPrinter::A4 },
81 { DMPAPER_A5, QPrinter::A5 },
82 { DMPAPER_B4, QPrinter::B4 },
83 { DMPAPER_B5, QPrinter::B5 },
84 { DMPAPER_FOLIO, QPrinter::Folio },
85 { DMPAPER_ENV_10, QPrinter::Comm10E },
86 { DMPAPER_ENV_DL, QPrinter::DLE },
87 { DMPAPER_ENV_C3, QPrinter::C5E },
88 { DMPAPER_LETTER_EXTRA, QPrinter::Letter },
89 { DMPAPER_LEGAL_EXTRA, QPrinter::Legal },
90 { DMPAPER_TABLOID_EXTRA, QPrinter::Tabloid },
91 { DMPAPER_A4_EXTRA, QPrinter::A4},
92 { DMPAPER_LETTER_TRANSVERSE, QPrinter::Letter},
93 { DMPAPER_A4_TRANSVERSE, QPrinter::A4},
94 { DMPAPER_LETTER_EXTRA_TRANSVERSE, QPrinter::Letter },
95 { DMPAPER_A_PLUS, QPrinter::A4 },
96 { DMPAPER_B_PLUS, QPrinter::A3 },
97 { DMPAPER_LETTER_PLUS, QPrinter::Letter },
98 { DMPAPER_A4_PLUS, QPrinter::A4 },
99 { DMPAPER_A5_TRANSVERSE, QPrinter::A5 },
100 { DMPAPER_B5_TRANSVERSE, QPrinter::B5 },
101 { DMPAPER_A3_EXTRA, QPrinter::A3 },
102 { DMPAPER_A5_EXTRA, QPrinter::A5 },
103 { DMPAPER_B5_EXTRA, QPrinter::B5 },
104 { DMPAPER_A2, QPrinter::A2 },
105 { DMPAPER_A3_TRANSVERSE, QPrinter::A3 },
106 { DMPAPER_A3_EXTRA_TRANSVERSE,QPrinter::A3 },
107 { 0, QPrinter::Custom }
110 QPrinter::PaperSize mapDevmodePaperSize(int s)
113 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
115 return dmMapping[i].qtSizeName;
118 static int mapPaperSizeDevmode(QPrinter::PaperSize s)
121 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
123 return dmMapping[i].winSizeName;
126 static const struct {
128 QPrinter::PaperSource qtSourceName;
130 { DMBIN_ONLYONE, QPrinter::OnlyOne },
131 { DMBIN_LOWER, QPrinter::Lower },
132 { DMBIN_MIDDLE, QPrinter::Middle },
133 { DMBIN_MANUAL, QPrinter::Manual },
134 { DMBIN_ENVELOPE, QPrinter::Envelope },
135 { DMBIN_ENVMANUAL, QPrinter::EnvelopeManual },
136 { DMBIN_AUTO, QPrinter::Auto },
137 { DMBIN_TRACTOR, QPrinter::Tractor },
138 { DMBIN_SMALLFMT, QPrinter::SmallFormat },
139 { DMBIN_LARGEFMT, QPrinter::LargeFormat },
140 { DMBIN_LARGECAPACITY, QPrinter::LargeCapacity },
141 { DMBIN_CASSETTE, QPrinter::Cassette },
142 { DMBIN_FORMSOURCE, QPrinter::FormSource },
143 { 0, (QPrinter::PaperSource) -1 }
146 static QPrinter::PaperSource mapDevmodePaperSource(int s)
149 while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
151 return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
154 static int mapPaperSourceDevmode(QPrinter::PaperSource s)
157 while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
159 return sources[i].winSourceName ? sources[i].winSourceName : s;
162 QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
163 : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
164 PaintEngineFeatures(PrimitiveTransform
166 | PerspectiveTransform
169 | PaintOutsidePaintEvent))
171 Q_D(QWin32PrintEngine);
172 d->docName = QLatin1String("document1");
178 bool QWin32PrintEngine::begin(QPaintDevice *pdev)
180 Q_D(QWin32PrintEngine);
182 QAlphaPaintEngine::begin(pdev);
191 // ### set default colors and stuff...
193 bool ok = d->state == QPrinter::Idle;
198 // Assign the FILE: to get the query...
199 if (d->printToFile && d->fileName.isEmpty())
200 d->fileName = d->port;
202 d->devMode->dmCopies = d->num_copies;
205 memset(&di, 0, sizeof(DOCINFO));
206 di.cbSize = sizeof(DOCINFO);
207 di.lpszDocName = reinterpret_cast<const wchar_t *>(d->docName.utf16());
208 if (d->printToFile && !d->fileName.isEmpty())
209 di.lpszOutput = reinterpret_cast<const wchar_t *>(d->fileName.utf16());
210 if (ok && StartDoc(d->hdc, &di) == SP_ERROR) {
211 qErrnoWarning("QWin32PrintEngine::begin: StartDoc failed");
215 if (StartPage(d->hdc) <= 0) {
216 qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
221 d->state = QPrinter::Idle;
223 d->state = QPrinter::Active;
226 d->matrix = QTransform();
228 d->pen = QColor(Qt::black);
229 d->has_brush = false;
231 d->complex_xform = false;
233 updateMatrix(d->matrix);
241 bool QWin32PrintEngine::end()
243 Q_D(QWin32PrintEngine);
246 if (d->state == QPrinter::Aborted) {
253 QAlphaPaintEngine::end();
258 EndPage(d->hdc); // end; printing done
262 d->state = QPrinter::Idle;
267 bool QWin32PrintEngine::newPage()
269 Q_D(QWin32PrintEngine);
270 Q_ASSERT(isActive());
276 bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
278 if (!EndPage(d->hdc)) {
279 qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
285 qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
291 if (!StartPage(d->hdc)) {
292 qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
296 SetTextAlign(d->hdc, TA_BASELINE);
298 SetBkMode(d->hdc, TRANSPARENT);
303 bool success = false;
304 if (d->hdc && d->state == QPrinter::Active) {
305 if (EndPage(d->hdc) != SP_ERROR) {
306 // reinitialize the DC before StartPage if needed,
307 // because resetdc is disabled between calls to the StartPage and EndPage functions
308 // (see StartPage documentation in the Platform SDK:Windows GDI)
309 // state = PST_ACTIVEDOC;
311 // state = PST_ACTIVE;
312 // start the new page now
315 qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
318 success = (StartPage(d->hdc) != SP_ERROR);
321 d->state = QPrinter::Aborted;
328 bool QWin32PrintEngine::abort()
334 void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
336 Q_D(const QWin32PrintEngine);
338 QAlphaPaintEngine::drawTextItem(p, textItem);
342 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
343 QRgb brushColor = state->pen().brush().color().rgb();
344 bool fallBack = state->pen().brush().style() != Qt::SolidPattern
345 || qAlpha(brushColor) != 0xff
346 || d->txop >= QTransform::TxProject
347 || ti.fontEngine->type() != QFontEngine::Win;
351 QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
353 // Try selecting the font to see if we get a substitution font
354 SelectObject(d->hdc, fe->hfont);
356 if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
358 GetTextFace(d->hdc, 64, n);
359 fallBack = QString::fromWCharArray(n)
360 != QString::fromWCharArray(fe->logfont.lfFaceName);
366 QPaintEngine::drawTextItem(p, textItem);
370 // We only want to convert the glyphs to text if the entire string is compatible with ASCII
371 // and if we actually have access to the chars.
372 bool convertToText = ti.chars != 0;
373 for (int i=0; i < ti.num_chars; ++i) {
374 if (ti.chars[i].unicode() >= 0x80) {
375 convertToText = false;
379 if (ti.logClusters[i] != i) {
380 convertToText = false;
385 COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
386 SelectObject(d->hdc, CreateSolidBrush(cf));
387 SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
388 SetTextColor(d->hdc, cf);
390 draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, d->devPaperRect.topLeft());
391 DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
392 DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
395 static inline qreal mmToInches(double mm)
397 return mm*0.039370147;
400 static inline qreal inchesToMM(double in)
402 return in/0.039370147;
405 int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
407 Q_D(const QWin32PrintEngine);
413 int res = d->resolution;
416 case QPaintDevice::PdmWidth:
417 if (d->has_custom_paper_size) {
418 val = qRound(d->paper_size.width() * res / 72.0);
420 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
421 if (logPixelsX == 0) {
422 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
423 "might be a driver problem");
424 logPixelsX = 600; // Reasonable default
427 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
430 if (d->pageMarginsSet)
431 val -= int(mmToInches((d->previousDialogMargins.left() +
432 d->previousDialogMargins.width()) / 100.0) * res);
434 case QPaintDevice::PdmHeight:
435 if (d->has_custom_paper_size) {
436 val = qRound(d->paper_size.height() * res / 72.0);
438 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
439 if (logPixelsY == 0) {
440 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
441 "might be a driver problem");
442 logPixelsY = 600; // Reasonable default
445 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
448 if (d->pageMarginsSet)
449 val -= int(mmToInches((d->previousDialogMargins.top() +
450 d->previousDialogMargins.height()) / 100.0) * res);
452 case QPaintDevice::PdmDpiX:
455 case QPaintDevice::PdmDpiY:
458 case QPaintDevice::PdmPhysicalDpiX:
459 val = GetDeviceCaps(d->hdc, LOGPIXELSX);
461 case QPaintDevice::PdmPhysicalDpiY:
462 val = GetDeviceCaps(d->hdc, LOGPIXELSY);
464 case QPaintDevice::PdmWidthMM:
465 if (d->has_custom_paper_size) {
466 val = qRound(d->paper_size.width()*25.4/72);
469 val = GetDeviceCaps(d->hdc, HORZSIZE);
471 float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
472 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
473 if (logPixelsX == 0) {
474 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
475 "might be a driver problem");
476 logPixelsX = 600; // Reasonable default
478 val = qRound(wi / logPixelsX);
481 if (d->pageMarginsSet)
482 val -= (d->previousDialogMargins.left() +
483 d->previousDialogMargins.width()) / 100.0;
485 case QPaintDevice::PdmHeightMM:
486 if (d->has_custom_paper_size) {
487 val = qRound(d->paper_size.height()*25.4/72);
490 val = GetDeviceCaps(d->hdc, VERTSIZE);
492 float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
493 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
494 if (logPixelsY == 0) {
495 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
496 "might be a driver problem");
497 logPixelsY = 600; // Reasonable default
499 val = qRound(hi / logPixelsY);
502 if (d->pageMarginsSet)
503 val -= (d->previousDialogMargins.top() +
504 d->previousDialogMargins.height()) / 100.0;
506 case QPaintDevice::PdmNumColors:
508 int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
512 val = GetDeviceCaps(d->hdc, NUMCOLORS);
514 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
517 case QPaintDevice::PdmDepth:
518 val = GetDeviceCaps(d->hdc, PLANES);
521 qWarning("QPrinter::metric: Invalid metric command");
527 void QWin32PrintEngine::updateState(const QPaintEngineState &state)
529 Q_D(QWin32PrintEngine);
531 QAlphaPaintEngine::updateState(state);
535 if (state.state() & DirtyTransform) {
536 updateMatrix(state.transform());
539 if (state.state() & DirtyPen) {
540 d->pen = state.pen();
541 d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
544 if (state.state() & DirtyBrush) {
545 QBrush brush = state.brush();
546 d->has_brush = brush.style() == Qt::SolidPattern;
547 d->brush_color = brush.color();
550 if (state.state() & DirtyClipEnabled) {
551 if (state.isClipEnabled())
552 updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
554 updateClipPath(QPainterPath(), Qt::NoClip);
557 if (state.state() & DirtyClipPath) {
558 updateClipPath(state.clipPath(), state.clipOperation());
561 if (state.state() & DirtyClipRegion) {
562 QRegion clipRegion = state.clipRegion();
563 QPainterPath clipPath = qt_regionToPath(clipRegion);
564 updateClipPath(clipPath, state.clipOperation());
568 void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
570 Q_D(QWin32PrintEngine);
573 if (op == Qt::NoClip) {
574 SelectClipRgn(d->hdc, 0);
579 QPainterPath xformed = clipPath * d->matrix;
581 if (xformed.isEmpty()) {
582 QRegion empty(-0x1000000, -0x1000000, 1, 1);
583 SelectClipRgn(d->hdc, empty.handle());
585 d->composeGdiPath(xformed);
587 -1, // Qt::NoClip, covered above
588 RGN_COPY, // Qt::ReplaceClip
589 RGN_AND // Qt::IntersectClip
591 Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
592 SelectClipPath(d->hdc, ops[op]);
596 QPainterPath aclip = qt_regionToPath(alphaClipping());
597 if (!aclip.isEmpty()) {
598 QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
599 d->composeGdiPath(tx.map(aclip));
600 SelectClipPath(d->hdc, RGN_DIFF);
604 void QWin32PrintEngine::updateMatrix(const QTransform &m)
606 Q_D(QWin32PrintEngine);
608 QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
609 d->painterMatrix = m;
610 d->matrix = d->painterMatrix * stretch;
611 d->txop = d->matrix.type();
612 d->complex_xform = (d->txop > QTransform::TxScale);
615 void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
616 const QPixmap &originalPixmap,
617 const QRectF &sourceRect)
619 Q_D(QWin32PrintEngine);
621 QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
625 const int tileSize = 2048;
627 QRectF r = targetRect;
628 QRectF sr = sourceRect;
630 QPixmap pixmap = originalPixmap;
631 if (sr.size() != pixmap.size()) {
632 pixmap = pixmap.copy(sr.toRect());
638 QTransform scaleMatrix = QTransform::fromScale(r.width() / pixmap.width(), r.height() / pixmap.height());
639 QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
640 pixmap.width(), pixmap.height());
642 qreal xform_offset_x = adapted.dx();
643 qreal xform_offset_y = adapted.dy();
645 if (d->complex_xform) {
646 pixmap = pixmap.transformed(adapted);
647 scaleX = d->stretch_x;
648 scaleY = d->stretch_y;
650 scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
651 scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
654 QPointF topLeft = r.topLeft() * d->painterMatrix;
655 int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
656 int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
657 int tw = qAbs(int(pixmap.width() * scaleX));
658 int th = qAbs(int(pixmap.height() * scaleY));
660 xform_offset_x *= d->stretch_x;
661 xform_offset_y *= d->stretch_y;
663 int dc_state = SaveDC(d->hdc);
665 int tilesw = pixmap.width() / tileSize;
666 int tilesh = pixmap.height() / tileSize;
670 int txinc = tileSize*scaleX;
671 int tyinc = tileSize*scaleY;
673 for (int y = 0; y < tilesh; ++y) {
674 int tposy = ty + (y * tyinc);
677 if (y == (tilesh - 1)) {
678 imgh = pixmap.height() - (y * tileSize);
679 height = (th - (y * tyinc));
681 for (int x = 0; x < tilesw; ++x) {
682 int tposx = tx + (x * txinc);
685 if (x == (tilesw - 1)) {
686 imgw = pixmap.width() - (x * tileSize);
687 width = (tw - (x * txinc));
690 QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
691 HBITMAP hbitmap = p.toWinHBITMAP(QPixmap::NoAlpha);
692 HDC display_dc = GetDC(0);
693 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
694 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
696 ReleaseDC(0, display_dc);
698 if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
699 hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
700 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
702 SelectObject(hbitmap_hdc, null_bitmap);
703 DeleteObject(hbitmap);
704 DeleteDC(hbitmap_hdc);
708 RestoreDC(d->hdc, dc_state);
712 void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
714 Q_D(QWin32PrintEngine);
716 QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
720 if (d->complex_xform || !pos.isNull()) {
721 QPaintEngine::drawTiledPixmap(r, pm, pos);
723 int dc_state = SaveDC(d->hdc);
725 HDC display_dc = GetDC(0);
726 HBITMAP hbitmap = pm.toWinHBITMAP(QPixmap::NoAlpha);
727 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
728 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
730 ReleaseDC(0, display_dc);
732 QRectF trect = d->painterMatrix.mapRect(r);
733 int tx = int(trect.left() * d->stretch_x + d->origin_x);
734 int ty = int(trect.top() * d->stretch_y + d->origin_y);
736 int xtiles = int(trect.width() / pm.width()) + 1;
737 int ytiles = int(trect.height() / pm.height()) + 1;
738 int xinc = int(pm.width() * d->stretch_x);
739 int yinc = int(pm.height() * d->stretch_y);
741 for (int y = 0; y < ytiles; ++y) {
742 int ity = ty + (yinc * y);
743 int ith = pm.height();
744 if (y == (ytiles - 1)) {
745 ith = int(trect.height() - (pm.height() * y));
748 for (int x = 0; x < xtiles; ++x) {
749 int itx = tx + (xinc * x);
750 int itw = pm.width();
751 if (x == (xtiles - 1)) {
752 itw = int(trect.width() - (pm.width() * x));
755 if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
756 hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
757 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
762 SelectObject(hbitmap_hdc, null_bitmap);
763 DeleteObject(hbitmap);
764 DeleteDC(hbitmap_hdc);
766 RestoreDC(d->hdc, dc_state);
771 void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
774 qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
776 // Drawing the subpaths
778 for (int i=0; i<path.elementCount(); ++i) {
779 const QPainterPath::Element &elm = path.elementAt(i);
781 case QPainterPath::MoveToElement:
783 && path.elementAt(start).x == path.elementAt(i-1).x
784 && path.elementAt(start).y == path.elementAt(i-1).y)
787 MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
789 case QPainterPath::LineToElement:
790 LineTo(hdc, qRound(elm.x), qRound(elm.y));
792 case QPainterPath::CurveToElement: {
794 { qRound(elm.x), qRound(elm.y) },
795 { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
796 { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
799 PolyBezierTo(hdc, pts, 3);
803 qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
808 && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
809 && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
813 qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
815 SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
819 void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
822 qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
825 composeGdiPath(path);
827 HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
828 HGDIOBJ old_brush = SelectObject(hdc, brush);
830 DeleteObject(SelectObject(hdc, old_brush));
833 void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
835 composeGdiPath(path);
837 brush.lbStyle = BS_SOLID;
838 brush.lbColor = RGB(color.red(), color.green(), color.blue());
839 DWORD capStyle = PS_ENDCAP_SQUARE;
840 DWORD joinStyle = PS_JOIN_BEVEL;
841 if (pen.capStyle() == Qt::FlatCap)
842 capStyle = PS_ENDCAP_FLAT;
843 else if (pen.capStyle() == Qt::RoundCap)
844 capStyle = PS_ENDCAP_ROUND;
846 if (pen.joinStyle() == Qt::MiterJoin)
847 joinStyle = PS_JOIN_MITER;
848 else if (pen.joinStyle() == Qt::RoundJoin)
849 joinStyle = PS_JOIN_ROUND;
851 HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
852 | PS_SOLID | capStyle | joinStyle,
853 (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
855 HGDIOBJ old_pen = SelectObject(hdc, pen);
857 DeleteObject(SelectObject(hdc, old_pen));
861 void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
863 fillPath_dev(path * matrix, color);
866 void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
868 QPainterPathStroker stroker;
869 if (pen.style() == Qt::CustomDashLine) {
870 stroker.setDashPattern(pen.dashPattern());
871 stroker.setDashOffset(pen.dashOffset());
873 stroker.setDashPattern(pen.style());
875 stroker.setCapStyle(pen.capStyle());
876 stroker.setJoinStyle(pen.joinStyle());
877 stroker.setMiterLimit(pen.miterLimit());
880 qreal width = pen.widthF();
881 if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
882 strokePath_dev(path * matrix, color, width);
884 stroker.setWidth(width);
885 if (pen.isCosmetic()) {
886 stroke = stroker.createStroke(path * matrix);
888 stroke = stroker.createStroke(path) * painterMatrix;
889 QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
890 stroke = stroke * stretch;
893 if (stroke.isEmpty())
896 fillPath_dev(stroke, color);
901 void QWin32PrintEngine::drawPath(const QPainterPath &path)
904 qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
907 Q_D(QWin32PrintEngine);
909 QAlphaPaintEngine::drawPath(path);
914 d->fillPath(path, d->brush_color);
917 d->strokePath(path, d->pen.color());
921 void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
924 qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
927 QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
931 Q_ASSERT(pointCount > 1);
933 QPainterPath path(points[0]);
935 for (int i=1; i<pointCount; ++i) {
936 path.lineTo(points[i]);
939 Q_D(QWin32PrintEngine);
941 bool has_brush = d->has_brush;
943 if (mode == PolylineMode)
944 d->has_brush = false; // No brush for polylines
946 path.closeSubpath(); // polygons are should always be closed.
949 d->has_brush = has_brush;
952 void QWin32PrintEnginePrivate::queryDefault()
954 /* Read the default printer name, driver and port with the intuitive function
955 * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
957 QString noPrinters(QLatin1String("qt_no_printers"));
959 GetProfileString(L"windows", L"device",
960 reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
962 QString output = QString::fromWCharArray(buffer);
963 if (output.isEmpty() || output == noPrinters) // no printers
966 QStringList info = output.split(QLatin1Char(','));
967 int infoSize = info.size();
971 if (program.isEmpty() && infoSize > 1)
972 program = info.at(1);
973 if (port.isEmpty() && infoSize > 2)
978 QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
984 void QWin32PrintEnginePrivate::initialize()
996 txop = QTransform::TxNone;
998 bool ok = OpenPrinter((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
1000 qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
1004 // Fetch the PRINTER_INFO_2 with DEVMODE data containing the
1005 // printer settings.
1006 DWORD infoSize, numBytes;
1007 GetPrinter(hPrinter, 2, NULL, 0, &infoSize);
1008 hMem = GlobalAlloc(GHND, infoSize);
1009 pInfo = (PRINTER_INFO_2*) GlobalLock(hMem);
1010 ok = GetPrinter(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes);
1013 qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
1014 GlobalUnlock(pInfo);
1016 ClosePrinter(hPrinter);
1023 devMode = pInfo->pDevMode;
1024 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1025 reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
1031 num_copies = devMode->dmCopies;
1036 #ifdef QT_DEBUG_DRAW
1037 qDebug() << "QWin32PrintEngine::initialize()" << endl
1038 << " - paperRect" << devPaperRect << endl
1039 << " - pageRect" << devPageRect << endl
1040 << " - stretch_x" << stretch_x << endl
1041 << " - stretch_y" << stretch_y << endl
1042 << " - origin_x" << origin_x << endl
1043 << " - origin_y" << origin_y << endl;
1047 void QWin32PrintEnginePrivate::initHDC()
1051 HDC display_dc = GetDC(0);
1052 dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1053 dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1054 dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
1055 ReleaseDC(0, display_dc);
1056 if (dpi_display == 0) {
1057 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
1058 "might be a driver problem");
1059 dpi_display = 96; // Reasonable default
1063 case QPrinter::ScreenResolution:
1064 resolution = dpi_display;
1065 stretch_x = dpi_x / double(dpi_display);
1066 stretch_y = dpi_y / double(dpi_display);
1068 case QPrinter::PrinterResolution:
1069 case QPrinter::HighResolution:
1081 void QWin32PrintEnginePrivate::initDevRects()
1083 devPaperRect = QRect(0, 0,
1084 GetDeviceCaps(hdc, PHYSICALWIDTH),
1085 GetDeviceCaps(hdc, PHYSICALHEIGHT));
1086 devPhysicalPageRect = QRect(GetDeviceCaps(hdc, PHYSICALOFFSETX),
1087 GetDeviceCaps(hdc, PHYSICALOFFSETY),
1088 GetDeviceCaps(hdc, HORZRES),
1089 GetDeviceCaps(hdc, VERTRES));
1090 if (!pageMarginsSet)
1091 devPageRect = devPhysicalPageRect;
1093 devPageRect = devPaperRect.adjusted(qRound(mmToInches(previousDialogMargins.left() / 100.0) * dpi_x),
1094 qRound(mmToInches(previousDialogMargins.top() / 100.0) * dpi_y),
1095 -qRound(mmToInches(previousDialogMargins.width() / 100.0) * dpi_x),
1096 -qRound(mmToInches(previousDialogMargins.height() / 100.0) * dpi_y));
1100 void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
1102 pageMarginsSet = true;
1103 previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
1105 devPageRect = devPaperRect.adjusted(qRound(mmToInches(marginLeft / 100.0) * dpi_x),
1106 qRound(mmToInches(marginTop / 100.0) * dpi_y),
1107 - qRound(mmToInches(marginRight / 100.0) * dpi_x),
1108 - qRound(mmToInches(marginBottom / 100.0) * dpi_y));
1112 QRect QWin32PrintEnginePrivate::getPageMargins() const
1115 return previousDialogMargins;
1117 return QRect(qRound(inchesToMM(devPhysicalPageRect.left()) * 100.0 / dpi_x),
1118 qRound(inchesToMM(devPhysicalPageRect.top()) * 100.0 / dpi_y),
1119 qRound(inchesToMM(devPaperRect.right() - devPhysicalPageRect.right()) * 100.0 / dpi_x),
1120 qRound(inchesToMM(devPaperRect.bottom() - devPhysicalPageRect.bottom()) * 100.0 / dpi_y));
1123 void QWin32PrintEnginePrivate::release()
1128 if (globalDevMode) { // Devmode comes from print dialog
1129 GlobalUnlock(globalDevMode);
1130 } else { // Devmode comes from initialize...
1131 // devMode is a part of the same memory block as pInfo so one free is enough...
1136 ClosePrinter(hPrinter);
1146 QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
1148 // Read the supported resolutions of the printer.
1149 QList<QVariant> list;
1151 DWORD numRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1152 reinterpret_cast<const wchar_t *>(port.utf16()),
1153 DC_ENUMRESOLUTIONS, 0, 0);
1154 if (numRes == (DWORD)-1)
1157 LONG *enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
1158 DWORD errRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1159 reinterpret_cast<const wchar_t *>(port.utf16()),
1160 DC_ENUMRESOLUTIONS, (LPWSTR)enumRes, 0);
1162 if (errRes == (DWORD)-1) {
1163 qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
1167 for (uint i=0; i<numRes; ++i)
1168 list.append(int(enumRes[i * 2]));
1173 void QWin32PrintEnginePrivate::doReinit()
1175 if (state == QPrinter::Active) {
1184 void QWin32PrintEnginePrivate::updateOrigin()
1187 // subtract physical margins to make (0,0) absolute top corner of paper
1188 // then add user defined margins
1189 origin_x = -devPhysicalPageRect.x();
1190 origin_y = -devPhysicalPageRect.y();
1191 if (pageMarginsSet) {
1192 origin_x += devPageRect.left();
1193 origin_y += devPageRect.top();
1198 if (pageMarginsSet) {
1199 origin_x = devPageRect.left() - devPhysicalPageRect.x();
1200 origin_y = devPageRect.top() - devPhysicalPageRect.y();
1205 void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
1207 Q_D(QWin32PrintEngine);
1209 case PPK_CollateCopies:
1213 d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
1222 d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
1231 case PPK_DocumentName:
1233 qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
1236 d->docName = value.toString();
1240 d->fullPage = value.toBool();
1244 case PPK_CopyCount: // fallthrough
1245 case PPK_NumberOfCopies:
1248 d->num_copies = value.toInt();
1249 d->devMode->dmCopies = d->num_copies;
1253 case PPK_Orientation:
1257 int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
1258 int old_orientation = d->devMode->dmOrientation;
1259 d->devMode->dmOrientation = orientation;
1260 if (d->has_custom_paper_size && old_orientation != orientation)
1261 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1266 case PPK_OutputFileName:
1268 qWarning("QWin32PrintEngine: Cannot change filename while printing");
1270 d->fileName = value.toString();
1271 d->printToFile = !value.toString().isEmpty();
1278 d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1279 d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
1283 case PPK_PaperSource:
1287 int dmMapped = DMBIN_AUTO;
1289 QList<QVariant> v = property(PPK_PaperSources).toList();
1290 if (v.contains(value))
1291 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
1293 d->devMode->dmDefaultSource = dmMapped;
1298 case PPK_PrinterName:
1299 d->name = value.toString();
1300 if(d->name.isEmpty())
1305 case PPK_Resolution:
1307 d->resolution = value.toInt();
1309 d->stretch_x = d->dpi_x / double(d->resolution);
1310 d->stretch_y = d->dpi_y / double(d->resolution);
1314 case PPK_SelectionOption:
1318 case PPK_SupportedResolutions:
1323 case PPK_WindowsPageSize:
1326 d->has_custom_paper_size = false;
1327 d->devMode->dmPaperSize = value.toInt();
1331 case PPK_CustomPaperSize:
1333 d->has_custom_paper_size = true;
1334 d->paper_size = value.toSizeF();
1337 int orientation = d->devMode->dmOrientation;
1340 if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
1341 BYTE *forms = (BYTE *) malloc(needed);
1342 if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
1343 for (DWORD i=0; i< returned; ++i) {
1344 FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
1345 // the form sizes are specified in 1000th of a mm,
1346 // convert the size to Points
1347 QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
1348 (formArray[i].Size.cy * 72/25.4)/1000.0);
1349 if (qAbs(d->paper_size.width() - size.width()) <= 2
1350 && qAbs(d->paper_size.height() - size.height()) <= 2)
1352 d->devMode->dmPaperSize = i + 1;
1359 if (orientation != DMORIENT_PORTRAIT)
1360 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1364 case PPK_PageMargins:
1366 QList<QVariant> margins(value.toList());
1367 Q_ASSERT(margins.size() == 4);
1368 int left, top, right, bottom;
1369 // specified in 1/100 mm
1370 left = (margins.at(0).toReal()*25.4/72.0) * 100;
1371 top = (margins.at(1).toReal()*25.4/72.0) * 100;
1372 right = (margins.at(2).toReal()*25.4/72.0) * 100;
1373 bottom = (margins.at(3).toReal()*25.4/72.0) * 100;
1374 d->setPageMargins(left, top, right, bottom);
1383 QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
1385 Q_D(const QWin32PrintEngine);
1389 case PPK_CollateCopies:
1396 value = QPrinter::Color;
1398 value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
1403 case PPK_DocumentName:
1408 value = d->fullPage;
1412 value = d->num_copies;
1415 case PPK_SupportsMultipleCopies:
1419 case PPK_NumberOfCopies:
1423 case PPK_Orientation:
1426 value = QPrinter::Portrait;
1428 value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
1433 case PPK_OutputFileName:
1434 value = d->fileName;
1438 if (d->has_custom_paper_size) {
1440 qRound(d->paper_size.width() * d->resolution / 72.0),
1441 qRound(d->paper_size.height() * d->resolution / 72.0));
1442 if (d->pageMarginsSet) {
1443 rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
1444 qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
1445 -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
1446 -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
1450 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
1451 .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
1456 if (d->has_custom_paper_size) {
1457 value = QPrinter::Custom;
1460 value = QPrinter::A4;
1462 value = mapDevmodePaperSize(d->devMode->dmPaperSize);
1468 if (d->has_custom_paper_size) {
1470 qRound(d->paper_size.width() * d->resolution / 72.0),
1471 qRound(d->paper_size.height() * d->resolution / 72.0));
1473 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
1477 case PPK_PaperSource:
1479 value = QPrinter::Auto;
1481 value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
1485 case PPK_PrinterName:
1489 case PPK_Resolution:
1490 if (d->resolution || !d->name.isEmpty())
1491 value = d->resolution;
1494 case PPK_SupportedResolutions:
1495 value = d->queryResolutions();
1498 case PPK_WindowsPageSize:
1502 value = d->devMode->dmPaperSize;
1506 case PPK_PaperSources:
1508 int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1509 (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
1514 wchar_t *data = new wchar_t[available];
1515 int count = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1516 (const wchar_t *)d->port.utf16(), DC_BINS, data, d->devMode);
1518 QList<QVariant> out;
1519 for (int i=0; i<count; ++i) {
1520 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
1530 case PPK_CustomPaperSize:
1531 value = d->paper_size;
1534 case PPK_PageMargins:
1536 QList<QVariant> margins;
1537 QRect pageMargins(d->getPageMargins());
1539 // specified in 1/100 mm
1540 margins << (mmToInches(pageMargins.left()/100.0) * 72)
1541 << (mmToInches(pageMargins.top()/100.0) * 72)
1542 << (mmToInches(pageMargins.width()/100.0) * 72)
1543 << (mmToInches(pageMargins.height()/100.0) * 72);
1554 QPrinter::PrinterState QWin32PrintEngine::printerState() const
1556 return d_func()->state;
1559 HDC QWin32PrintEngine::getDC() const
1561 return d_func()->hdc;
1564 void QWin32PrintEngine::releaseDC(HDC) const
1569 HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
1571 int size = sizeof(DEVNAMES)
1572 + program.length() * 2 + 2
1573 + name.length() * 2 + 2
1574 + port.length() * 2 + 2;
1575 HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
1576 DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
1578 dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
1579 dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1580 dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1582 memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
1583 memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
1584 memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
1587 GlobalUnlock(hGlobal);
1589 // printf("QPrintDialogWinPrivate::createDevNames()\n"
1590 // " -> wDriverOffset: %d\n"
1591 // " -> wDeviceOffset: %d\n"
1592 // " -> wOutputOffset: %d\n",
1593 // dn->wDriverOffset,
1594 // dn->wDeviceOffset,
1595 // dn->wOutputOffset);
1597 // printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
1598 // QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset).latin1(),
1599 // QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset).latin1(),
1600 // QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset).latin1());
1605 void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
1607 if (globalDevnames) {
1608 DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
1609 name = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
1610 port = QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset);
1611 program = QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset);
1612 GlobalUnlock(globalDevnames);
1616 void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
1618 if (globalDevmode) {
1619 DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
1621 globalDevMode = globalDevmode;
1623 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1624 reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
1626 num_copies = devMode->dmCopies;
1627 if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
1628 qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1635 static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
1636 bool convertToText, const QTransform &xform, const QPointF &topLeft)
1638 QFontEngine *fe = ti.fontEngine;
1639 QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
1641 SetTextAlign(hdc, TA_BASELINE);
1642 SetBkMode(hdc, TRANSPARENT);
1644 bool has_kerning = ti.f && ti.f->kerning();
1645 QFontEngineWin *winfe = (fe->type() == QFontEngine::Win) ? static_cast<QFontEngineWin *>(fe) : 0;
1651 hfont = winfe->hfont;
1654 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1657 HGDIOBJ old_font = SelectObject(hdc, hfont);
1658 unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
1659 wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
1660 QGlyphLayout glyphs = ti.glyphs;
1662 bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
1663 for (int i = 0; fast && i < glyphs.numGlyphs; i++) {
1664 if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
1665 || glyphs.attributes[i].dontPrint) {
1671 #if !defined(Q_OS_WINCE)
1672 // Scale, rotate and translate here.
1674 win_xform.eM11 = xform.m11();
1675 win_xform.eM12 = xform.m12();
1676 win_xform.eM21 = xform.m21();
1677 win_xform.eM22 = xform.m22();
1678 win_xform.eDx = xform.dx();
1679 win_xform.eDy = xform.dy();
1681 SetGraphicsMode(hdc, GM_ADVANCED);
1682 SetWorldTransform(hdc, &win_xform);
1687 QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
1688 for (int i = 0; i < glyphs.numGlyphs; ++i)
1689 g[i] = glyphs.glyphs[i];
1691 qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
1692 qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
1693 options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
1695 QVarLengthArray<QFixedPoint> positions;
1696 QVarLengthArray<glyph_t> _glyphs;
1698 QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y());
1699 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
1700 _glyphs, positions);
1701 if (_glyphs.size() == 0) {
1702 SelectObject(hdc, old_font);
1706 convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
1707 bool outputEntireItem = _glyphs.size() > 0;
1709 if (outputEntireItem) {
1711 QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
1712 QVarLengthArray<wchar_t> g(_glyphs.size());
1713 for (int i=0; i<_glyphs.size() - 1; ++i) {
1714 glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
1715 glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
1718 glyphDistances[(_glyphs.size() - 1) * 2] = 0;
1719 glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
1720 g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
1721 ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
1722 convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
1723 glyphDistances.data());
1726 while(i < _glyphs.size()) {
1727 wchar_t g = _glyphs[i];
1729 ExtTextOut(hdc, qRound(positions[i].x),
1730 qRound(positions[i].y), options, 0,
1731 convertToText ? convertedGlyphs + i : &g, 1, 0);
1737 #if !defined(Q_OS_WINCE)
1738 win_xform.eM11 = win_xform.eM22 = 1.0;
1739 win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
1740 SetWorldTransform(hdc, &win_xform);
1743 SelectObject(hdc, old_font);
1747 void QWin32PrintEnginePrivate::updateCustomPaperSize()
1749 uint paperSize = devMode->dmPaperSize;
1750 if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
1751 has_custom_paper_size = true;
1754 if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
1755 BYTE *forms = (BYTE *) malloc(needed);
1756 if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
1757 if (paperSize <= returned) {
1758 FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
1759 int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
1760 int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
1761 paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
1763 has_custom_paper_size = false;
1769 has_custom_paper_size = false;
1775 #endif // QT_NO_PRINTER