Fix font printing on Windows using the native engine.
[profile/ivi/qtbase.git] / src / printsupport / kernel / qprintengine_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QT_NO_PRINTER
43
44 #include "qprintengine_win_p.h"
45
46 #include <limits.h>
47
48 #include <private/qprinter_p.h>
49 #include <private/qfont_p.h>
50 #include <private/qfontengine_p.h>
51 #include <private/qpainter_p.h>
52
53 #include <qbitmap.h>
54 #include <qdebug.h>
55 #include <qvector.h>
56 #include <qpicture.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>
62
63 Q_DECLARE_METATYPE(HFONT)
64 Q_DECLARE_METATYPE(LOGFONT)
65
66 QT_BEGIN_NAMESPACE
67
68 Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
69 extern QPainterPath qt_regionToPath(const QRegion &region);
70
71 // #define QT_DEBUG_DRAW
72
73 static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
74                                bool convertToText, const QTransform &xform, const QPointF &topLeft);
75
76 static const struct {
77     int winSizeName;
78     QPrinter::PaperSize qtSizeName;
79 } dmMapping[] = {
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 }
116 };
117
118 QPrinter::PaperSize mapDevmodePaperSize(int s)
119 {
120     int i = 0;
121     while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
122         i++;
123     return dmMapping[i].qtSizeName;
124 }
125
126 static int mapPaperSizeDevmode(QPrinter::PaperSize s)
127 {
128     int i = 0;
129  while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
130         i++;
131     return dmMapping[i].winSizeName;
132 }
133
134 static const struct {
135     int winSourceName;
136     QPrinter::PaperSource qtSourceName;
137 }  sources[] = {
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 }
152 };
153
154 static QPrinter::PaperSource mapDevmodePaperSource(int s)
155 {
156     int i = 0;
157     while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
158         i++;
159     return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
160 }
161
162 static int mapPaperSourceDevmode(QPrinter::PaperSource s)
163 {
164     int i = 0;
165     while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
166         i++;
167     return sources[i].winSourceName ? sources[i].winSourceName : s;
168 }
169
170 QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
171     : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
172                    PaintEngineFeatures(PrimitiveTransform
173                                        | PixmapTransform
174                                        | PerspectiveTransform
175                                        | PainterPaths
176                                        | Antialiasing
177                                        | PaintOutsidePaintEvent))
178 {
179     Q_D(QWin32PrintEngine);
180     d->docName = QLatin1String("document1");
181     d->mode = mode;
182     d->queryDefault();
183     d->initialize();
184 }
185
186 bool QWin32PrintEngine::begin(QPaintDevice *pdev)
187 {
188     Q_D(QWin32PrintEngine);
189
190     QAlphaPaintEngine::begin(pdev);
191     if (!continueCall())
192         return true;
193
194     if (d->reinit) {
195        d->resetDC();
196        d->reinit = false;
197     }
198
199     // ### set default colors and stuff...
200
201     bool ok = d->state == QPrinter::Idle;
202
203     if (!d->hdc)
204         return false;
205
206     // Assign the FILE: to get the query...
207     if (d->printToFile && d->fileName.isEmpty())
208         d->fileName = d->port;
209
210     d->devMode->dmCopies = d->num_copies;
211
212     DOCINFO di;
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");
220         ok = false;
221     }
222
223     if (StartPage(d->hdc) <= 0) {
224         qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
225         ok = false;
226     }
227
228     if (!ok) {
229         d->state = QPrinter::Idle;
230     } else {
231         d->state = QPrinter::Active;
232     }
233
234     d->matrix = QTransform();
235     d->has_pen = true;
236     d->pen = QColor(Qt::black);
237     d->has_brush = false;
238
239     d->complex_xform = false;
240
241     updateMatrix(d->matrix);
242
243     if (!ok)
244         cleanUp();
245
246     return ok;
247 }
248
249 bool QWin32PrintEngine::end()
250 {
251     Q_D(QWin32PrintEngine);
252
253     if (d->hdc) {
254         if (d->state == QPrinter::Aborted) {
255             cleanUp();
256             AbortDoc(d->hdc);
257             return true;
258         }
259     }
260
261     QAlphaPaintEngine::end();
262     if (!continueCall())
263         return true;
264
265     if (d->hdc) {
266         EndPage(d->hdc);                 // end; printing done
267         EndDoc(d->hdc);
268     }
269
270     d->state = QPrinter::Idle;
271     d->reinit = true;
272     return true;
273 }
274
275 bool QWin32PrintEngine::newPage()
276 {
277     Q_D(QWin32PrintEngine);
278     Q_ASSERT(isActive());
279
280     Q_ASSERT(d->hdc);
281
282     flushAndInit();
283
284     bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
285
286     if (!EndPage(d->hdc)) {
287         qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
288         return false;
289     }
290
291     if (d->reinit) {
292         if (!d->resetDC()) {
293             qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
294             return false;
295         }
296         d->reinit = false;
297     }
298
299     if (!StartPage(d->hdc)) {
300         qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
301         return false;
302     }
303
304     SetTextAlign(d->hdc, TA_BASELINE);
305     if (transparent)
306         SetBkMode(d->hdc, TRANSPARENT);
307
308     // ###
309     return true;
310
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;
318 //          reinit();
319 //          state = PST_ACTIVE;
320             // start the new page now
321             if (d->reinit) {
322                 if (!d->resetDC())
323                     qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
324                 d->reinit = false;
325             }
326             success = (StartPage(d->hdc) != SP_ERROR);
327         }
328         if (!success) {
329             d->state = QPrinter::Aborted;
330             return false;
331         }
332     }
333     return true;
334 }
335
336 bool QWin32PrintEngine::abort()
337 {
338     // do nothing loop.
339     return false;
340 }
341
342 void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
343 {
344     Q_D(const QWin32PrintEngine);
345
346     QAlphaPaintEngine::drawTextItem(p, textItem);
347     if (!continueCall())
348         return;
349
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;
356
357     if (!fallBack) {
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) {
366                 wchar_t n[64];
367                 GetTextFace(d->hdc, 64, n);
368                 fallBack = QString::fromWCharArray(n)
369                     != QString::fromWCharArray(logFont.lfFaceName);
370             }
371         }
372     }
373
374
375     if (fallBack) {
376         QPaintEngine::drawTextItem(p, textItem);
377         return ;
378     }
379
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;
386             break;
387         }
388
389         if (ti.logClusters[i] != i) {
390             convertToText = false;
391             break;
392         }
393     }
394
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);
399
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)));
403 }
404
405 static inline qreal mmToInches(double mm)
406 {
407     return mm*0.039370147;
408 }
409
410 static inline qreal inchesToMM(double in)
411 {
412     return in/0.039370147;
413 }
414
415 int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
416 {
417     Q_D(const QWin32PrintEngine);
418
419     if (!d->hdc)
420         return 0;
421
422     int val;
423     int res = d->resolution;
424
425     switch (m) {
426     case QPaintDevice::PdmWidth:
427         if (d->has_custom_paper_size) {
428             val =  qRound(d->paper_size.width() * res / 72.0);
429         } else {
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
435             }
436             val = res
437                   * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
438                   / logPixelsX;
439         }
440         if (d->pageMarginsSet)
441             val -= int(mmToInches((d->previousDialogMargins.left() +
442                                    d->previousDialogMargins.width()) / 100.0) * res);
443         break;
444     case QPaintDevice::PdmHeight:
445         if (d->has_custom_paper_size) {
446             val = qRound(d->paper_size.height() * res / 72.0);
447         } else {
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
453             }
454             val = res
455                   * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
456                   / logPixelsY;
457         }
458         if (d->pageMarginsSet)
459             val -= int(mmToInches((d->previousDialogMargins.top() +
460                                    d->previousDialogMargins.height()) / 100.0) * res);
461         break;
462     case QPaintDevice::PdmDpiX:
463         val = res;
464         break;
465     case QPaintDevice::PdmDpiY:
466         val = res;
467         break;
468     case QPaintDevice::PdmPhysicalDpiX:
469         val = GetDeviceCaps(d->hdc, LOGPIXELSX);
470         break;
471     case QPaintDevice::PdmPhysicalDpiY:
472         val = GetDeviceCaps(d->hdc, LOGPIXELSY);
473         break;
474     case QPaintDevice::PdmWidthMM:
475         if (d->has_custom_paper_size) {
476             val = qRound(d->paper_size.width()*25.4/72);
477         } else {
478             if (!d->fullPage) {
479                 val = GetDeviceCaps(d->hdc, HORZSIZE);
480             } else {
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
487                 }
488                 val = qRound(wi / logPixelsX);
489             }
490         }
491         if (d->pageMarginsSet)
492             val -= (d->previousDialogMargins.left() +
493                     d->previousDialogMargins.width()) / 100.0;
494         break;
495     case QPaintDevice::PdmHeightMM:
496         if (d->has_custom_paper_size) {
497             val = qRound(d->paper_size.height()*25.4/72);
498         } else {
499             if (!d->fullPage) {
500                 val = GetDeviceCaps(d->hdc, VERTSIZE);
501             } else {
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
508                 }
509                 val = qRound(hi / logPixelsY);
510             }
511         }
512         if (d->pageMarginsSet)
513             val -= (d->previousDialogMargins.top() +
514                     d->previousDialogMargins.height()) / 100.0;
515         break;
516     case QPaintDevice::PdmNumColors:
517         {
518             int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
519             if(bpp==32)
520                 val = INT_MAX;
521             else if(bpp<=8)
522                 val = GetDeviceCaps(d->hdc, NUMCOLORS);
523             else
524                 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
525         }
526         break;
527     case QPaintDevice::PdmDepth:
528         val = GetDeviceCaps(d->hdc, PLANES);
529         break;
530     default:
531         qWarning("QPrinter::metric: Invalid metric command");
532         return 0;
533     }
534     return val;
535 }
536
537 void QWin32PrintEngine::updateState(const QPaintEngineState &state)
538 {
539     Q_D(QWin32PrintEngine);
540
541     QAlphaPaintEngine::updateState(state);
542     if (!continueCall())
543         return;
544
545     if (state.state() & DirtyTransform) {
546         updateMatrix(state.transform());
547     }
548
549     if (state.state() & DirtyPen) {
550         d->pen = state.pen();
551         d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
552     }
553
554     if (state.state() & DirtyBrush) {
555         QBrush brush = state.brush();
556         d->has_brush = brush.style() == Qt::SolidPattern;
557         d->brush_color = brush.color();
558     }
559
560     if (state.state() & DirtyClipEnabled) {
561         if (state.isClipEnabled())
562             updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
563         else
564             updateClipPath(QPainterPath(), Qt::NoClip);
565     }
566
567     if (state.state() & DirtyClipPath) {
568         updateClipPath(state.clipPath(), state.clipOperation());
569     }
570
571     if (state.state() & DirtyClipRegion) {
572         QRegion clipRegion = state.clipRegion();
573         QPainterPath clipPath = qt_regionToPath(clipRegion);
574         updateClipPath(clipPath, state.clipOperation());
575     }
576 }
577
578 void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
579 {
580     Q_D(QWin32PrintEngine);
581
582     bool doclip = true;
583     if (op == Qt::NoClip) {
584         SelectClipRgn(d->hdc, 0);
585         doclip = false;
586     }
587
588     if (doclip) {
589         QPainterPath xformed = clipPath * d->matrix;
590
591         if (xformed.isEmpty()) {
592 //            QRegion empty(-0x1000000, -0x1000000, 1, 1);
593             HRGN empty = CreateRectRgn(-0x1000000, -0x1000000, -0x0fffffff, -0x0ffffff);
594             SelectClipRgn(d->hdc, empty);
595             DeleteObject(empty);
596         } else {
597             d->composeGdiPath(xformed);
598             const int ops[] = {
599                 -1,         // Qt::NoClip, covered above
600                 RGN_COPY,   // Qt::ReplaceClip
601                 RGN_AND,    // Qt::IntersectClip
602                 RGN_OR      // Qt::UniteClip
603             };
604             Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
605             SelectClipPath(d->hdc, ops[op]);
606         }
607     }
608
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);
614     }
615 }
616
617 void QWin32PrintEngine::updateMatrix(const QTransform &m)
618 {
619     Q_D(QWin32PrintEngine);
620
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);
626 }
627
628 enum HBitmapFormat
629 {
630     HBitmapNoAlpha,
631     HBitmapPremultipliedAlpha,
632     HBitmapAlpha
633 };
634
635 void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
636                                    const QPixmap &originalPixmap,
637                                    const QRectF &sourceRect)
638 {
639     Q_D(QWin32PrintEngine);
640
641     QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
642     if (!continueCall())
643         return;
644
645     const int tileSize = 2048;
646
647     QRectF r = targetRect;
648     QRectF sr = sourceRect;
649
650     QPixmap pixmap = originalPixmap;
651     if (sr.size() != pixmap.size()) {
652         pixmap = pixmap.copy(sr.toRect());
653     }
654
655     qreal scaleX = 1.0f;
656     qreal scaleY = 1.0f;
657
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());
661
662     qreal xform_offset_x = adapted.dx();
663     qreal xform_offset_y = adapted.dy();
664
665     if (d->complex_xform) {
666         pixmap = pixmap.transformed(adapted);
667         scaleX = d->stretch_x;
668         scaleY = d->stretch_y;
669     } else {
670         scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
671         scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
672     }
673
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));
679
680     xform_offset_x *= d->stretch_x;
681     xform_offset_y *= d->stretch_y;
682
683     int dc_state = SaveDC(d->hdc);
684
685     int tilesw = pixmap.width() / tileSize;
686     int tilesh = pixmap.height() / tileSize;
687     ++tilesw;
688     ++tilesh;
689
690     int txinc = tileSize*scaleX;
691     int tyinc = tileSize*scaleY;
692
693     for (int y = 0; y < tilesh; ++y) {
694         int tposy = ty + (y * tyinc);
695         int imgh = tileSize;
696         int height = tyinc;
697         if (y == (tilesh - 1)) {
698             imgh = pixmap.height() - (y * tileSize);
699             height = (th - (y * tyinc));
700         }
701         for (int x = 0; x < tilesw; ++x) {
702             int tposx = tx + (x * txinc);
703             int imgw = tileSize;
704             int width = txinc;
705             if (x == (tilesw - 1)) {
706                 imgw = pixmap.width() - (x * tileSize);
707                 width = (tw - (x * txinc));
708             }
709
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);
715
716             ReleaseDC(0, display_dc);
717
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");
721
722             SelectObject(hbitmap_hdc, null_bitmap);
723             DeleteObject(hbitmap);
724             DeleteDC(hbitmap_hdc);
725         }
726     }
727
728     RestoreDC(d->hdc, dc_state);
729 }
730
731
732 void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
733 {
734     Q_D(QWin32PrintEngine);
735
736     QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
737     if (!continueCall())
738         return;
739
740     if (d->complex_xform || !pos.isNull()) {
741         QPaintEngine::drawTiledPixmap(r, pm, pos);
742     } else {
743         int dc_state = SaveDC(d->hdc);
744
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);
749
750         ReleaseDC(0, display_dc);
751
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);
755
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);
760
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));
766             }
767
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));
773                 }
774
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");
778
779             }
780         }
781
782         SelectObject(hbitmap_hdc, null_bitmap);
783         DeleteObject(hbitmap);
784         DeleteDC(hbitmap_hdc);
785
786         RestoreDC(d->hdc, dc_state);
787     }
788 }
789
790
791 void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
792 {
793     if (!BeginPath(hdc))
794         qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
795
796     // Drawing the subpaths
797     int start = -1;
798     for (int i=0; i<path.elementCount(); ++i) {
799         const QPainterPath::Element &elm = path.elementAt(i);
800         switch (elm.type) {
801         case QPainterPath::MoveToElement:
802             if (start >= 0
803                 && path.elementAt(start).x == path.elementAt(i-1).x
804                 && path.elementAt(start).y == path.elementAt(i-1).y)
805                 CloseFigure(hdc);
806             start = i;
807             MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
808             break;
809         case QPainterPath::LineToElement:
810             LineTo(hdc, qRound(elm.x), qRound(elm.y));
811             break;
812         case QPainterPath::CurveToElement: {
813             POINT pts[3] = {
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) }
817             };
818             i+=2;
819             PolyBezierTo(hdc, pts, 3);
820             break;
821         }
822         default:
823             qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
824         }
825     }
826
827     if (start >= 0
828         && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
829         && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
830         CloseFigure(hdc);
831
832     if (!EndPath(hdc))
833         qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
834
835     SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
836 }
837
838
839 void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
840 {
841 #ifdef QT_DEBUG_DRAW
842     qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
843 #endif
844
845     composeGdiPath(path);
846
847     HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
848     HGDIOBJ old_brush = SelectObject(hdc, brush);
849     FillPath(hdc);
850     DeleteObject(SelectObject(hdc, old_brush));
851 }
852
853 void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
854 {
855     composeGdiPath(path);
856     LOGBRUSH brush;
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;
865
866     if (pen.joinStyle() == Qt::MiterJoin)
867         joinStyle = PS_JOIN_MITER;
868     else if (pen.joinStyle() == Qt::RoundJoin)
869         joinStyle = PS_JOIN_ROUND;
870
871     HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
872                             | PS_SOLID | capStyle | joinStyle,
873                             (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
874
875     HGDIOBJ old_pen = SelectObject(hdc, pen);
876     StrokePath(hdc);
877     DeleteObject(SelectObject(hdc, old_pen));
878 }
879
880
881 void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
882 {
883     fillPath_dev(path * matrix, color);
884 }
885
886 void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
887 {
888     QPainterPathStroker stroker;
889     if (pen.style() == Qt::CustomDashLine) {
890         stroker.setDashPattern(pen.dashPattern());
891         stroker.setDashOffset(pen.dashOffset());
892     } else {
893         stroker.setDashPattern(pen.style());
894     }
895     stroker.setCapStyle(pen.capStyle());
896     stroker.setJoinStyle(pen.joinStyle());
897     stroker.setMiterLimit(pen.miterLimit());
898
899     QPainterPath stroke;
900     qreal width = pen.widthF();
901     if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
902         strokePath_dev(path * matrix, color, width);
903     } else {
904         stroker.setWidth(width);
905         if (pen.isCosmetic()) {
906             stroke = stroker.createStroke(path * matrix);
907         } else {
908             stroke = stroker.createStroke(path) * painterMatrix;
909             QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
910             stroke = stroke * stretch;
911         }
912
913         if (stroke.isEmpty())
914             return;
915
916         fillPath_dev(stroke, color);
917     }
918 }
919
920
921 void QWin32PrintEngine::drawPath(const QPainterPath &path)
922 {
923 #ifdef QT_DEBUG_DRAW
924     qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
925 #endif
926
927     Q_D(QWin32PrintEngine);
928
929     QAlphaPaintEngine::drawPath(path);
930     if (!continueCall())
931         return;
932
933     if (d->has_brush)
934         d->fillPath(path, d->brush_color);
935
936     if (d->has_pen)
937         d->strokePath(path, d->pen.color());
938 }
939
940
941 void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
942 {
943 #ifdef QT_DEBUG_DRAW
944     qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
945 #endif
946
947     QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
948     if (!continueCall())
949         return;
950
951     Q_ASSERT(pointCount > 1);
952
953     QPainterPath path(points[0]);
954
955     for (int i=1; i<pointCount; ++i) {
956         path.lineTo(points[i]);
957     }
958
959     Q_D(QWin32PrintEngine);
960
961     bool has_brush = d->has_brush;
962
963     if (mode == PolylineMode)
964         d->has_brush = false; // No brush for polylines
965     else
966         path.closeSubpath(); // polygons are should always be closed.
967
968     drawPath(path);
969     d->has_brush = has_brush;
970 }
971
972 void QWin32PrintEnginePrivate::queryDefault()
973 {
974     QWin32PrintEngine::queryDefaultPrinter(name, program, port);
975 }
976
977 QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
978 {
979     if (hdc)
980         release();
981 }
982
983 void QWin32PrintEnginePrivate::initialize()
984 {
985     if (hdc)
986         release();
987     Q_ASSERT(!hPrinter);
988     Q_ASSERT(!hdc);
989     Q_ASSERT(!devMode);
990     Q_ASSERT(!pInfo);
991
992     if (name.isEmpty())
993         return;
994
995     txop = QTransform::TxNone;
996
997     bool ok = OpenPrinter((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
998     if (!ok) {
999         qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
1000         return;
1001     }
1002
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);
1010
1011     if (!ok) {
1012         qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
1013         GlobalUnlock(pInfo);
1014         GlobalFree(hMem);
1015         ClosePrinter(hPrinter);
1016         pInfo = 0;
1017         hMem = 0;
1018         hPrinter = 0;
1019         return;
1020     }
1021
1022     devMode = pInfo->pDevMode;
1023     hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1024                    reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
1025
1026     Q_ASSERT(hPrinter);
1027     Q_ASSERT(pInfo);
1028
1029     if (devMode) {
1030         num_copies = devMode->dmCopies;
1031     }
1032
1033     initHDC();
1034
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;
1043 #endif
1044 }
1045
1046 void QWin32PrintEnginePrivate::initHDC()
1047 {
1048     Q_ASSERT(hdc);
1049
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
1059     }
1060
1061     switch(mode) {
1062     case QPrinter::ScreenResolution:
1063         resolution = dpi_display;
1064         stretch_x = dpi_x / double(dpi_display);
1065         stretch_y = dpi_y / double(dpi_display);
1066         break;
1067     case QPrinter::PrinterResolution:
1068     case QPrinter::HighResolution:
1069         resolution = dpi_y;
1070         stretch_x = 1;
1071         stretch_y = 1;
1072         break;
1073     default:
1074         break;
1075     }
1076
1077     initDevRects();
1078 }
1079
1080 void QWin32PrintEnginePrivate::initDevRects()
1081 {
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;
1091     else
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));
1096     updateOrigin();
1097 }
1098
1099 void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
1100 {
1101     pageMarginsSet = true;
1102     previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
1103
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));
1108     updateOrigin();
1109 }
1110
1111 QRect QWin32PrintEnginePrivate::getPageMargins() const
1112 {
1113     if (pageMarginsSet)
1114         return previousDialogMargins;
1115     else
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));
1120 }
1121
1122 void QWin32PrintEnginePrivate::release()
1123 {
1124     if (hdc == 0)
1125         return;
1126
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...
1131         GlobalUnlock(hMem);
1132         GlobalFree(hMem);
1133     }
1134     if (hPrinter)
1135         ClosePrinter(hPrinter);
1136     DeleteDC(hdc);
1137
1138     hdc = 0;
1139     hPrinter = 0;
1140     pInfo = 0;
1141     hMem = 0;
1142     devMode = 0;
1143 }
1144
1145 QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
1146 {
1147     // Read the supported resolutions of the printer.
1148     QList<QVariant> list;
1149
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)
1154         return list;
1155
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);
1160
1161     if (errRes == (DWORD)-1) {
1162         qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
1163         return list;
1164     }
1165
1166     for (uint i=0; i<numRes; ++i)
1167         list.append(int(enumRes[i * 2]));
1168
1169     return list;
1170 }
1171
1172 void QWin32PrintEnginePrivate::doReinit()
1173 {
1174     if (state == QPrinter::Active) {
1175         reinit = true;
1176     } else {
1177         resetDC();
1178         initDevRects();
1179         reinit = false;
1180     }
1181 }
1182
1183 void QWin32PrintEnginePrivate::updateOrigin()
1184 {
1185     if (fullPage) {
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();
1193         }
1194     } else {
1195         origin_x = 0;
1196         origin_y = 0;
1197         if (pageMarginsSet) {
1198             origin_x = devPageRect.left() - devPhysicalPageRect.x();
1199             origin_y = devPageRect.top() - devPhysicalPageRect.y();
1200         }
1201     }
1202 }
1203
1204 void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
1205 {
1206     Q_D(QWin32PrintEngine);
1207     switch (key) {
1208     case PPK_CollateCopies:
1209         {
1210             if (!d->devMode)
1211                 break;
1212             d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
1213             d->doReinit();
1214         }
1215         break;
1216
1217     case PPK_ColorMode:
1218         {
1219             if (!d->devMode)
1220                 break;
1221             d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
1222             d->doReinit();
1223         }
1224         break;
1225
1226     case PPK_Creator:
1227
1228         break;
1229
1230     case PPK_DocumentName:
1231         if (isActive()) {
1232             qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
1233             return;
1234         }
1235         d->docName = value.toString();
1236         break;
1237
1238     case PPK_FullPage:
1239         d->fullPage = value.toBool();
1240         d->updateOrigin();
1241         break;
1242
1243     case PPK_CopyCount: // fallthrough
1244     case PPK_NumberOfCopies:
1245         if (!d->devMode)
1246             break;
1247         d->num_copies = value.toInt();
1248         d->devMode->dmCopies = d->num_copies;
1249         d->doReinit();
1250         break;
1251
1252     case PPK_Orientation:
1253         {
1254             if (!d->devMode)
1255                 break;
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());
1261             d->doReinit();
1262         }
1263         break;
1264
1265     case PPK_OutputFileName:
1266         if (isActive()) {
1267             qWarning("QWin32PrintEngine: Cannot change filename while printing");
1268         } else {
1269             d->fileName = value.toString();
1270             d->printToFile = !value.toString().isEmpty();
1271         }
1272         break;
1273
1274     case PPK_PaperSize:
1275         if (!d->devMode)
1276             break;
1277         d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1278         d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
1279         d->doReinit();
1280         break;
1281
1282     case PPK_PaperSource:
1283         {
1284             if (!d->devMode)
1285                 break;
1286             int dmMapped = DMBIN_AUTO;
1287
1288             QList<QVariant> v = property(PPK_PaperSources).toList();
1289             if (v.contains(value))
1290                 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
1291
1292             d->devMode->dmDefaultSource = dmMapped;
1293             d->doReinit();
1294         }
1295         break;
1296
1297     case PPK_PrinterName:
1298         d->name = value.toString();
1299         if(d->name.isEmpty())
1300             d->queryDefault();
1301         d->initialize();
1302         break;
1303
1304     case PPK_Resolution:
1305         {
1306             d->resolution = value.toInt();
1307
1308             d->stretch_x = d->dpi_x / double(d->resolution);
1309             d->stretch_y = d->dpi_y / double(d->resolution);
1310         }
1311         break;
1312
1313     case PPK_SelectionOption:
1314
1315         break;
1316
1317     case PPK_SupportedResolutions:
1318
1319         break;
1320
1321
1322     case PPK_WindowsPageSize:
1323         if (!d->devMode)
1324             break;
1325         d->has_custom_paper_size = false;
1326         d->devMode->dmPaperSize = value.toInt();
1327         d->doReinit();
1328         break;
1329
1330     case PPK_CustomPaperSize:
1331     {
1332         d->has_custom_paper_size = true;
1333         d->paper_size = value.toSizeF();
1334         if (!d->devMode)
1335             break;
1336         int orientation = d->devMode->dmOrientation;
1337         DWORD needed = 0;
1338         DWORD returned = 0;
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)
1350                     {
1351                         d->devMode->dmPaperSize = i + 1;
1352                         break;
1353                     }
1354                 }
1355             }
1356             free(forms);
1357         }
1358         if (orientation != DMORIENT_PORTRAIT)
1359             d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1360         break;
1361     }
1362
1363     case PPK_PageMargins:
1364     {
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);
1374         break;
1375     }
1376     default:
1377         // Do nothing
1378         break;
1379     }
1380 }
1381
1382 QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
1383 {
1384     Q_D(const QWin32PrintEngine);
1385     QVariant value;
1386     switch (key) {
1387
1388     case PPK_CollateCopies:
1389         value = false;
1390         break;
1391
1392     case PPK_ColorMode:
1393         {
1394             if (!d->devMode) {
1395                 value = QPrinter::Color;
1396             } else {
1397                 value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
1398             }
1399         }
1400         break;
1401
1402     case PPK_DocumentName:
1403         value = d->docName;
1404         break;
1405
1406     case PPK_FullPage:
1407         value = d->fullPage;
1408         break;
1409
1410     case PPK_CopyCount:
1411         value = d->num_copies;
1412         break;
1413
1414     case PPK_SupportsMultipleCopies:
1415         value = true;
1416         break;
1417
1418     case PPK_NumberOfCopies:
1419         value = 1;
1420         break;
1421
1422     case PPK_Orientation:
1423         {
1424             if (!d->devMode) {
1425                 value = QPrinter::Portrait;
1426             } else {
1427                 value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
1428             }
1429         }
1430         break;
1431
1432     case PPK_OutputFileName:
1433         value = d->fileName;
1434         break;
1435
1436     case PPK_PageRect:
1437         if (d->has_custom_paper_size) {
1438             QRect rect(0, 0,
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));
1446             }
1447             value = rect;
1448         } else {
1449             value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
1450                     .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
1451         }
1452         break;
1453
1454     case PPK_PaperSize:
1455         if (d->has_custom_paper_size) {
1456             value = QPrinter::Custom;
1457         } else {
1458             if (!d->devMode) {
1459                 value = QPrinter::A4;
1460             } else {
1461                 value = mapDevmodePaperSize(d->devMode->dmPaperSize);
1462             }
1463         }
1464         break;
1465
1466     case PPK_PaperRect:
1467         if (d->has_custom_paper_size) {
1468             value = QRect(0, 0,
1469                           qRound(d->paper_size.width() * d->resolution / 72.0),
1470                           qRound(d->paper_size.height() * d->resolution / 72.0));
1471         } else {
1472             value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
1473         }
1474         break;
1475
1476     case PPK_PaperSource:
1477         if (!d->devMode) {
1478             value = QPrinter::Auto;
1479         } else {
1480             value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
1481         }
1482         break;
1483
1484     case PPK_PrinterName:
1485         value = d->name;
1486         break;
1487
1488     case PPK_Resolution:
1489         if (d->resolution || !d->name.isEmpty())
1490             value = d->resolution;
1491         break;
1492
1493     case PPK_SupportedResolutions:
1494         value = d->queryResolutions();
1495         break;
1496
1497     case PPK_WindowsPageSize:
1498         if (!d->devMode) {
1499             value = -1;
1500         } else {
1501             value = d->devMode->dmPaperSize;
1502         }
1503         break;
1504
1505     case PPK_PaperSources:
1506         {
1507             int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
1508                                                (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
1509
1510             if (available <= 0)
1511                 break;
1512
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);
1516
1517             QList<QVariant> out;
1518             for (int i=0; i<count; ++i) {
1519                 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
1520                 if (src != -1)
1521                     out << (int) src;
1522             }
1523             value = out;
1524
1525             delete [] data;
1526         }
1527         break;
1528
1529     case PPK_CustomPaperSize:
1530         value = d->paper_size;
1531         break;
1532
1533     case PPK_PageMargins:
1534     {
1535         QList<QVariant> margins;
1536         QRect pageMargins(d->getPageMargins());
1537
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);
1543         value = margins;
1544         break;
1545     }
1546     default:
1547         // Do nothing
1548         break;
1549     }
1550     return value;
1551 }
1552
1553 QPrinter::PrinterState QWin32PrintEngine::printerState() const
1554 {
1555     return d_func()->state;
1556 }
1557
1558 HDC QWin32PrintEngine::getDC() const
1559 {
1560     return d_func()->hdc;
1561 }
1562
1563 void QWin32PrintEngine::releaseDC(HDC) const
1564 {
1565
1566 }
1567
1568 QList<QPrinter::PaperSize> QWin32PrintEngine::supportedPaperSizes(const QPrinterInfo &printerInfo)
1569 {
1570     QList<QPrinter::PaperSize> returnList;
1571
1572     if (printerInfo.isNull())
1573         return returnList;
1574
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]));
1583         delete [] papers;
1584     }
1585     return returnList;
1586 }
1587
1588 void QWin32PrintEngine::queryDefaultPrinter(QString &name, QString &program, QString &port)
1589 {
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()
1592      */
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()),
1597                      buffer, 256);
1598     QString output = QString::fromWCharArray(buffer);
1599     if (output.isEmpty() || output == noPrinters) // no printers
1600         return;
1601
1602     QStringList info = output.split(QLatin1Char(','));
1603     int infoSize = info.size();
1604     if (infoSize > 0) {
1605         if (name.isEmpty())
1606             name = info.at(0);
1607         if (program.isEmpty() && infoSize > 1)
1608             program = info.at(1);
1609         if (port.isEmpty() && infoSize > 2)
1610             port = info.at(2);
1611     }
1612 }
1613
1614 HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
1615 {
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);
1622
1623     dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
1624     dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1625     dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1626
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);
1630     dn->wDefault = 0;
1631
1632     GlobalUnlock(hGlobal);
1633
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);
1641
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());
1646
1647     return hGlobal;
1648 }
1649
1650 void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
1651 {
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);
1658     }
1659 }
1660
1661 void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
1662 {
1663     if (globalDevmode) {
1664         DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
1665         release();
1666         globalDevMode = globalDevmode;
1667         devMode = dm;
1668         hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1669                        reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
1670
1671         num_copies = devMode->dmCopies;
1672         if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
1673             qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1674     }
1675
1676     if (hdc)
1677         initHDC();
1678 }
1679
1680 static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
1681                                bool convertToText, const QTransform &xform, const QPointF &topLeft)
1682 {
1683     QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
1684
1685     SetTextAlign(hdc, TA_BASELINE);
1686     SetBkMode(hdc, TRANSPARENT);
1687
1688     const bool has_kerning = ti.f && ti.f->kerning();
1689
1690     HFONT hfont = 0;
1691     bool ttf = false;
1692
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();
1699         }
1700     }
1701
1702     if (!hfont)
1703         hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1704
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;
1709
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) {
1714             fast = false;
1715             break;
1716         }
1717     }
1718
1719 #if !defined(Q_OS_WINCE)
1720     // Scale, rotate and translate here.
1721     XFORM win_xform;
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();
1728
1729     SetGraphicsMode(hdc, GM_ADVANCED);
1730     SetWorldTransform(hdc, &win_xform);
1731 #endif
1732
1733     if (fast) {
1734         // fast path
1735         QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
1736         for (int i = 0; i < glyphs.numGlyphs; ++i)
1737             g[i] = glyphs.glyphs[i];
1738         ExtTextOut(hdc,
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);
1742     } else {
1743         QVarLengthArray<QFixedPoint> positions;
1744         QVarLengthArray<glyph_t> _glyphs;
1745
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);
1751             return;
1752         }
1753
1754         convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
1755         bool outputEntireItem = _glyphs.size() > 0;
1756
1757         if (outputEntireItem) {
1758             options |= ETO_PDY;
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);
1764                 g[i] = _glyphs[i];
1765             }
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());
1772         } else {
1773             int i = 0;
1774             while(i < _glyphs.size()) {
1775                 wchar_t g = _glyphs[i];
1776
1777                 ExtTextOut(hdc, qRound(positions[i].x),
1778                            qRound(positions[i].y), options, 0,
1779                            convertToText ? convertedGlyphs + i : &g, 1, 0);
1780                 ++i;
1781             }
1782         }
1783     }
1784
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);
1789 #endif
1790
1791     SelectObject(hdc, old_font);
1792 }
1793
1794
1795 void QWin32PrintEnginePrivate::updateCustomPaperSize()
1796 {
1797     uint paperSize = devMode->dmPaperSize;
1798     if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
1799         has_custom_paper_size = true;
1800         DWORD needed = 0;
1801         DWORD returned = 0;
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);
1810                 } else {
1811                     has_custom_paper_size = false;
1812                 }
1813             }
1814             free(forms);
1815         }
1816     } else {
1817         has_custom_paper_size = false;
1818     }
1819 }
1820
1821 QT_END_NAMESPACE
1822
1823 #endif // QT_NO_PRINTER