source: trunk/src/gui/painting/qprintengine_win.cpp@ 508

Last change on this file since 508 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 63.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QT_NO_PRINTER
43
44#include "qprinter_p.h"
45#include "qprintengine_win_p.h"
46
47#include <limits.h>
48
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 <private/qpicture_p.h>
58
59QT_BEGIN_NAMESPACE
60
61extern QPainterPath qt_regionToPath(const QRegion &region);
62
63// #define QT_DEBUG_DRAW
64
65static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
66 bool convertToText, const QTransform &xform, const QPointF &topLeft);
67
68static const struct {
69 int winSizeName;
70 QPrinter::PaperSize qtSizeName;
71} dmMapping[] = {
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 }
108};
109
110QPrinter::PaperSize mapDevmodePaperSize(int s)
111{
112 int i = 0;
113 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
114 i++;
115 return dmMapping[i].qtSizeName;
116}
117
118static int mapPaperSizeDevmode(QPrinter::PaperSize s)
119{
120 int i = 0;
121 while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
122 i++;
123 return dmMapping[i].winSizeName;
124}
125
126static const struct {
127 int winSourceName;
128 QPrinter::PaperSource qtSourceName;
129} sources[] = {
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 }
144};
145
146static QPrinter::PaperSource mapDevmodePaperSource(int s)
147{
148 int i = 0;
149 while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
150 i++;
151 return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
152}
153
154static int mapPaperSourceDevmode(QPrinter::PaperSource s)
155{
156 int i = 0;
157 while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
158 i++;
159 return sources[i].winSourceName ? sources[i].winSourceName : s;
160}
161
162QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
163 : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
164 PaintEngineFeatures(PrimitiveTransform
165 | PixmapTransform
166 | PerspectiveTransform
167 | PainterPaths
168 | Antialiasing
169 | PaintOutsidePaintEvent))
170{
171 Q_D(QWin32PrintEngine);
172 d->docName = QLatin1String("document1");
173 d->mode = mode;
174 d->queryDefault();
175 d->initialize();
176}
177
178bool QWin32PrintEngine::begin(QPaintDevice *pdev)
179{
180 Q_D(QWin32PrintEngine);
181
182 QAlphaPaintEngine::begin(pdev);
183 if (!continueCall())
184 return true;
185
186 if (d->reinit) {
187 d->resetDC();
188 d->reinit = false;
189 }
190
191 // ### set default colors and stuff...
192
193 bool ok = d->state == QPrinter::Idle;
194
195 if (!d->hdc)
196 return false;
197
198 // Assign the FILE: to get the query...
199 if (d->printToFile && d->fileName.isEmpty())
200 d->fileName = d->port;
201
202 QT_WA({
203 d->devModeW()->dmCopies = d->num_copies;
204 DOCINFO di;
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");
212 ok = false;
213 }
214 } , {
215 d->devModeA()->dmCopies = d->num_copies;
216 DOCINFOA di;
217 memset(&di, 0, sizeof(DOCINFOA));
218 di.cbSize = sizeof(DOCINFOA);
219 QByteArray docNameA = d->docName.toLocal8Bit();
220 di.lpszDocName = docNameA.data();
221 QByteArray outfileA = d->fileName.toLocal8Bit();
222 if (d->printToFile && !d->fileName.isEmpty())
223 di.lpszOutput = outfileA;
224 if (ok && StartDocA(d->hdc, &di) == SP_ERROR) {
225 qErrnoWarning("QWin32PrintEngine::begin: StartDoc failed");
226 ok = false;
227 }
228 });
229
230 if (StartPage(d->hdc) <= 0) {
231 qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
232 ok = false;
233 }
234
235 if (!ok) {
236 d->state = QPrinter::Idle;
237 } else {
238 d->state = QPrinter::Active;
239 }
240
241 d->matrix = QTransform();
242 d->has_pen = true;
243 d->pen = QColor(Qt::black);
244 d->has_brush = false;
245
246 d->complex_xform = false;
247
248 updateMatrix(d->matrix);
249
250 if (!ok)
251 cleanUp();
252
253 return ok;
254}
255
256bool QWin32PrintEngine::end()
257{
258 Q_D(QWin32PrintEngine);
259
260 if (d->hdc) {
261 if (d->state == QPrinter::Aborted) {
262 cleanUp();
263 AbortDoc(d->hdc);
264 return true;
265 }
266 }
267
268 QAlphaPaintEngine::end();
269 if (!continueCall())
270 return true;
271
272 if (d->hdc) {
273 EndPage(d->hdc); // end; printing done
274 EndDoc(d->hdc);
275 }
276
277 d->state = QPrinter::Idle;
278 d->reinit = true;
279 return true;
280}
281
282bool QWin32PrintEngine::newPage()
283{
284 Q_D(QWin32PrintEngine);
285 Q_ASSERT(isActive());
286
287 Q_ASSERT(d->hdc);
288
289 flushAndInit();
290
291 bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
292
293 if (!EndPage(d->hdc)) {
294 qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
295 return false;
296 }
297
298 if (d->reinit) {
299 if (!d->resetDC()) {
300 qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
301 return false;
302 }
303 d->reinit = false;
304 }
305
306 if (!StartPage(d->hdc)) {
307 qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
308 return false;
309 }
310
311 SetTextAlign(d->hdc, TA_BASELINE);
312 if (transparent)
313 SetBkMode(d->hdc, TRANSPARENT);
314
315 // ###
316 return true;
317
318 bool success = false;
319 if (d->hdc && d->state == QPrinter::Active) {
320// bool restorePainter = false;
321// if ((qWinVersion()& Qt::WV_DOS_based) && painter && painter->isActive()) {
322// painter->save(); // EndPage/StartPage ruins the DC
323// restorePainter = true;
324// }
325 if (EndPage(d->hdc) != SP_ERROR) {
326 // reinitialize the DC before StartPage if needed,
327 // because resetdc is disabled between calls to the StartPage and EndPage functions
328 // (see StartPage documentation in the Platform SDK:Windows GDI)
329// state = PST_ACTIVEDOC;
330// reinit();
331// state = PST_ACTIVE;
332 // start the new page now
333 if (d->reinit) {
334 if (!d->resetDC())
335 qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
336 d->reinit = false;
337 }
338 success = (StartPage(d->hdc) != SP_ERROR);
339 }
340 if (!success)
341 d->state = QPrinter::Aborted;
342
343// if (qWinVersion() & Qt::WV_DOS_based)
344// if (restorePainter) {
345// painter->restore();
346// }
347
348 if (!success)
349 return false;
350 }
351 return true;
352}
353
354bool QWin32PrintEngine::abort()
355{
356 // do nothing loop.
357 return false;
358}
359
360void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
361{
362 Q_D(const QWin32PrintEngine);
363
364 QAlphaPaintEngine::drawTextItem(p, textItem);
365 if (!continueCall())
366 return;
367
368 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
369 QRgb brushColor = state->pen().brush().color().rgb();
370 bool fallBack = state->pen().brush().style() != Qt::SolidPattern
371 || qAlpha(brushColor) != 0xff
372 || QT_WA_INLINE(d->txop >= QTransform::TxProject, d->txop >= QTransform::TxScale)
373 || ti.fontEngine->type() != QFontEngine::Win;
374
375
376 if (!fallBack) {
377 QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
378
379 // Try selecting the font to see if we get a substitution font
380 SelectObject(d->hdc, fe->hfont);
381
382 if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
383 QT_WA({
384 TCHAR n[64];
385 GetTextFaceW(d->hdc, 64, n);
386 fallBack = QString::fromUtf16((ushort *)n)
387 != QString::fromUtf16((ushort *)fe->logfont.lfFaceName);
388 } , {
389 char an[64];
390 GetTextFaceA(d->hdc, 64, an);
391 fallBack = QString::fromLocal8Bit(an)
392 != QString::fromLocal8Bit(((LOGFONTA*)(&fe->logfont))->lfFaceName);
393 });
394 }
395 }
396
397
398 if (fallBack) {
399 QPaintEngine::drawTextItem(p, textItem);
400 return ;
401 }
402
403 // We only want to convert the glyphs to text if the entire string is latin1
404 bool latin1String = true;
405 for (int i=0; i < ti.num_chars; ++i) {
406 if (ti.chars[i].unicode() >= 0x100) {
407 latin1String = false;
408 break;
409 }
410 }
411
412 COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
413 SelectObject(d->hdc, CreateSolidBrush(cf));
414 SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
415 SetTextColor(d->hdc, cf);
416
417 draw_text_item_win(p, ti, d->hdc, latin1String, d->matrix, d->devPaperRect.topLeft());
418 DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
419 DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
420}
421
422static inline qreal mmToInches(double mm)
423{
424 return mm*0.039370147;
425}
426
427static inline qreal inchesToMM(double in)
428{
429 return in/0.039370147;
430}
431
432int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
433{
434 Q_D(const QWin32PrintEngine);
435
436 if (!d->hdc)
437 return 0;
438
439 int val;
440 int res = d->resolution;
441
442 switch (m) {
443 case QPaintDevice::PdmWidth:
444 if (d->has_custom_paper_size) {
445 val = qRound(d->paper_size.width() * res / 72.0);
446 } else {
447 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
448 if (logPixelsX == 0) {
449 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
450 "might be a driver problem");
451 logPixelsX = 600; // Reasonable default
452 }
453 val = res
454 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
455 / logPixelsX;
456 }
457 if (d->pageMarginsSet)
458 val -= int(mmToInches((d->previousDialogMargins.left() +
459 d->previousDialogMargins.width()) / 100.0) * res);
460 break;
461 case QPaintDevice::PdmHeight:
462 if (d->has_custom_paper_size) {
463 val = qRound(d->paper_size.height() * res / 72.0);
464 } else {
465 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
466 if (logPixelsY == 0) {
467 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
468 "might be a driver problem");
469 logPixelsY = 600; // Reasonable default
470 }
471 val = res
472 * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
473 / logPixelsY;
474 }
475 if (d->pageMarginsSet)
476 val -= int(mmToInches((d->previousDialogMargins.top() +
477 d->previousDialogMargins.height()) / 100.0) * res);
478 break;
479 case QPaintDevice::PdmDpiX:
480 val = res;
481 break;
482 case QPaintDevice::PdmDpiY:
483 val = res;
484 break;
485 case QPaintDevice::PdmPhysicalDpiX:
486 val = GetDeviceCaps(d->hdc, LOGPIXELSX);
487 break;
488 case QPaintDevice::PdmPhysicalDpiY:
489 val = GetDeviceCaps(d->hdc, LOGPIXELSY);
490 break;
491 case QPaintDevice::PdmWidthMM:
492 if (d->has_custom_paper_size) {
493 val = qRound(d->paper_size.width()*25.4/72);
494 } else {
495 if (!d->fullPage) {
496 val = GetDeviceCaps(d->hdc, HORZSIZE);
497 } else {
498 float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
499 int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
500 if (logPixelsX == 0) {
501 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
502 "might be a driver problem");
503 logPixelsX = 600; // Reasonable default
504 }
505 val = qRound(wi / logPixelsX);
506 }
507 }
508 if (d->pageMarginsSet)
509 val -= (d->previousDialogMargins.left() +
510 d->previousDialogMargins.width()) / 100.0;
511 break;
512 case QPaintDevice::PdmHeightMM:
513 if (d->has_custom_paper_size) {
514 val = qRound(d->paper_size.height()*25.4/72);
515 } else {
516 if (!d->fullPage) {
517 val = GetDeviceCaps(d->hdc, VERTSIZE);
518 } else {
519 float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
520 int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
521 if (logPixelsY == 0) {
522 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
523 "might be a driver problem");
524 logPixelsY = 600; // Reasonable default
525 }
526 val = qRound(hi / logPixelsY);
527 }
528 }
529 if (d->pageMarginsSet)
530 val -= (d->previousDialogMargins.top() +
531 d->previousDialogMargins.height()) / 100.0;
532 break;
533 case QPaintDevice::PdmNumColors:
534 {
535 int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
536 if(bpp==32)
537 val = INT_MAX;
538 else if(bpp<=8)
539 val = GetDeviceCaps(d->hdc, NUMCOLORS);
540 else
541 val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
542 }
543 break;
544 case QPaintDevice::PdmDepth:
545 val = GetDeviceCaps(d->hdc, PLANES);
546 break;
547 default:
548 qWarning("QPrinter::metric: Invalid metric command");
549 return 0;
550 }
551 return val;
552}
553
554void QWin32PrintEngine::updateState(const QPaintEngineState &state)
555{
556 Q_D(QWin32PrintEngine);
557
558 QAlphaPaintEngine::updateState(state);
559 if (!continueCall())
560 return;
561
562 if (state.state() & DirtyTransform) {
563 updateMatrix(state.transform());
564 }
565
566 if (state.state() & DirtyPen) {
567 d->pen = state.pen();
568 d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
569 }
570
571 if (state.state() & DirtyBrush) {
572 QBrush brush = state.brush();
573 d->has_brush = brush.style() == Qt::SolidPattern;
574 d->brush_color = brush.color();
575 }
576
577 if (state.state() & DirtyClipEnabled) {
578 if (state.isClipEnabled())
579 updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
580 else
581 updateClipPath(QPainterPath(), Qt::NoClip);
582 }
583
584 if (state.state() & DirtyClipPath) {
585 updateClipPath(state.clipPath(), state.clipOperation());
586 }
587
588 if (state.state() & DirtyClipRegion) {
589 QRegion clipRegion = state.clipRegion();
590 QPainterPath clipPath = qt_regionToPath(clipRegion);
591 updateClipPath(clipPath, state.clipOperation());
592 }
593}
594
595void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
596{
597 Q_D(QWin32PrintEngine);
598
599 bool doclip = true;
600 if (op == Qt::NoClip) {
601 SelectClipRgn(d->hdc, 0);
602 doclip = false;
603 }
604
605 if (doclip) {
606 QPainterPath xformed = clipPath * d->matrix;
607
608 if (xformed.isEmpty()) {
609 QRegion empty(-0x1000000, -0x1000000, 1, 1);
610 SelectClipRgn(d->hdc, empty.handle());
611 } else {
612 d->composeGdiPath(xformed);
613 const int ops[] = {
614 -1, // Qt::NoClip, covered above
615 RGN_COPY, // Qt::ReplaceClip
616 RGN_AND, // Qt::IntersectClip
617 RGN_OR // Qt::UniteClip
618 };
619 Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
620 SelectClipPath(d->hdc, ops[op]);
621 }
622 }
623
624 QPainterPath aclip = qt_regionToPath(alphaClipping());
625 if (!aclip.isEmpty()) {
626 QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
627 d->composeGdiPath(tx.map(aclip));
628 SelectClipPath(d->hdc, RGN_DIFF);
629 }
630}
631
632void QWin32PrintEngine::updateMatrix(const QTransform &m)
633{
634 Q_D(QWin32PrintEngine);
635
636 QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
637 d->painterMatrix = m;
638 d->matrix = d->painterMatrix * stretch;
639 d->txop = d->matrix.type();
640 d->complex_xform = (d->txop > QTransform::TxScale);
641}
642
643void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
644 const QPixmap &originalPixmap,
645 const QRectF &sourceRect)
646{
647 Q_D(QWin32PrintEngine);
648
649 QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
650 if (!continueCall())
651 return;
652
653 const int tileSize = 2048;
654
655 QRectF r = targetRect;
656 QRectF sr = sourceRect;
657
658 QPixmap pixmap = originalPixmap;
659 if (sr.size() != pixmap.size()) {
660 pixmap = pixmap.copy(sr.toRect());
661 }
662
663 qreal scaleX = 1.0f;
664 qreal scaleY = 1.0f;
665
666 QTransform scaleMatrix;
667 scaleMatrix.scale(r.width() / pixmap.width(), r.height() / pixmap.height());
668 QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
669 pixmap.width(), pixmap.height());
670
671 qreal xform_offset_x = adapted.dx();
672 qreal xform_offset_y = adapted.dy();
673
674 if (d->complex_xform) {
675 pixmap = pixmap.transformed(adapted);
676 scaleX = d->stretch_x;
677 scaleY = d->stretch_y;
678 } else {
679 scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
680 scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
681 }
682
683 QPointF topLeft = r.topLeft() * d->painterMatrix;
684 int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
685 int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
686 int tw = qAbs(int(pixmap.width() * scaleX));
687 int th = qAbs(int(pixmap.height() * scaleY));
688
689 xform_offset_x *= d->stretch_x;
690 xform_offset_y *= d->stretch_y;
691
692 int dc_state = SaveDC(d->hdc);
693
694 int tilesw = pixmap.width() / tileSize;
695 int tilesh = pixmap.height() / tileSize;
696 ++tilesw;
697 ++tilesh;
698
699 int txinc = tileSize*scaleX;
700 int tyinc = tileSize*scaleY;
701
702 for (int y = 0; y < tilesh; ++y) {
703 int tposy = ty + (y * tyinc);
704 int imgh = tileSize;
705 int height = tyinc;
706 if (y == (tilesh - 1)) {
707 imgh = pixmap.height() - (y * tileSize);
708 height = (th - (y * tyinc));
709 }
710 for (int x = 0; x < tilesw; ++x) {
711 int tposx = tx + (x * txinc);
712 int imgw = tileSize;
713 int width = txinc;
714 if (x == (tilesw - 1)) {
715 imgw = pixmap.width() - (x * tileSize);
716 width = (tw - (x * txinc));
717 }
718
719 QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
720 HBITMAP hbitmap = p.toWinHBITMAP(QPixmap::NoAlpha);
721 HDC display_dc = GetDC(0);
722 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
723 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
724
725 ReleaseDC(0, display_dc);
726
727 if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
728 hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
729 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
730
731 SelectObject(hbitmap_hdc, null_bitmap);
732 DeleteObject(hbitmap);
733 DeleteDC(hbitmap_hdc);
734 }
735 }
736
737 RestoreDC(d->hdc, dc_state);
738}
739
740
741void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
742{
743 Q_D(QWin32PrintEngine);
744
745 QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
746 if (!continueCall())
747 return;
748
749 if (d->complex_xform || !pos.isNull()) {
750 QPaintEngine::drawTiledPixmap(r, pm, pos);
751 } else {
752 int dc_state = SaveDC(d->hdc);
753
754 HDC display_dc = GetDC(0);
755 HBITMAP hbitmap = pm.toWinHBITMAP(QPixmap::NoAlpha);
756 HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
757 HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
758
759 ReleaseDC(0, display_dc);
760
761 QRectF trect = d->painterMatrix.mapRect(r);
762 int tx = int(trect.left() * d->stretch_x + d->origin_x);
763 int ty = int(trect.top() * d->stretch_y + d->origin_y);
764
765 int xtiles = int(trect.width() / pm.width()) + 1;
766 int ytiles = int(trect.height() / pm.height()) + 1;
767 int xinc = int(pm.width() * d->stretch_x);
768 int yinc = int(pm.height() * d->stretch_y);
769
770 for (int y = 0; y < ytiles; ++y) {
771 int ity = ty + (yinc * y);
772 int ith = pm.height();
773 if (y == (ytiles - 1)) {
774 ith = int(trect.height() - (pm.height() * y));
775 }
776
777 for (int x = 0; x < xtiles; ++x) {
778 int itx = tx + (xinc * x);
779 int itw = pm.width();
780 if (x == (xtiles - 1)) {
781 itw = int(trect.width() - (pm.width() * x));
782 }
783
784 if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
785 hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
786 qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
787
788 }
789 }
790
791 SelectObject(hbitmap_hdc, null_bitmap);
792 DeleteObject(hbitmap);
793 DeleteDC(hbitmap_hdc);
794
795 RestoreDC(d->hdc, dc_state);
796 }
797}
798
799
800void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
801{
802 if (!BeginPath(hdc))
803 qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
804
805 // Drawing the subpaths
806 int start = -1;
807 for (int i=0; i<path.elementCount(); ++i) {
808 const QPainterPath::Element &elm = path.elementAt(i);
809 switch (elm.type) {
810 case QPainterPath::MoveToElement:
811 if (start >= 0
812 && path.elementAt(start).x == path.elementAt(i-1).x
813 && path.elementAt(start).y == path.elementAt(i-1).y)
814 CloseFigure(hdc);
815 start = i;
816 MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
817 break;
818 case QPainterPath::LineToElement:
819 LineTo(hdc, qRound(elm.x), qRound(elm.y));
820 break;
821 case QPainterPath::CurveToElement: {
822 POINT pts[3] = {
823 { qRound(elm.x), qRound(elm.y) },
824 { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
825 { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
826 };
827 i+=2;
828 PolyBezierTo(hdc, pts, 3);
829 break;
830 }
831 default:
832 qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
833 }
834 }
835
836 if (start >= 0
837 && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
838 && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
839 CloseFigure(hdc);
840
841 if (!EndPath(hdc))
842 qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
843
844 SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
845}
846
847
848void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
849{
850#ifdef QT_DEBUG_DRAW
851 qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
852#endif
853
854 composeGdiPath(path);
855
856 HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
857 HGDIOBJ old_brush = SelectObject(hdc, brush);
858 FillPath(hdc);
859 DeleteObject(SelectObject(hdc, old_brush));
860}
861
862void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
863{
864 composeGdiPath(path);
865 HPEN pen = CreatePen(PS_SOLID, qRound(penWidth), RGB(color.red(), color.green(), color.blue()));
866 HGDIOBJ old_pen = SelectObject(hdc, pen);
867 StrokePath(hdc);
868 DeleteObject(SelectObject(hdc, old_pen));
869}
870
871
872void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
873{
874 fillPath_dev(path * matrix, color);
875}
876
877void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
878{
879 QPainterPathStroker stroker;
880 if (pen.style() == Qt::CustomDashLine) {
881 stroker.setDashPattern(pen.dashPattern());
882 stroker.setDashOffset(pen.dashOffset());
883 } else {
884 stroker.setDashPattern(pen.style());
885 }
886 stroker.setCapStyle(pen.capStyle());
887 stroker.setJoinStyle(pen.joinStyle());
888 stroker.setMiterLimit(pen.miterLimit());
889
890 QPainterPath stroke;
891 qreal width = pen.widthF();
892 if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
893 strokePath_dev(path * matrix, color, width);
894 } else {
895 stroker.setWidth(width);
896 if (pen.isCosmetic()) {
897 stroke = stroker.createStroke(path * matrix);
898 } else {
899 stroke = stroker.createStroke(path) * painterMatrix;
900 QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
901 stroke = stroke * stretch;
902 }
903
904 if (stroke.isEmpty())
905 return;
906
907 fillPath_dev(stroke, color);
908 }
909}
910
911
912void QWin32PrintEngine::drawPath(const QPainterPath &path)
913{
914#ifdef QT_DEBUG_DRAW
915 qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
916#endif
917
918 Q_D(QWin32PrintEngine);
919
920 QAlphaPaintEngine::drawPath(path);
921 if (!continueCall())
922 return;
923
924 if (d->has_brush)
925 d->fillPath(path, d->brush_color);
926
927 if (d->has_pen)
928 d->strokePath(path, d->pen.color());
929}
930
931
932void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
933{
934#ifdef QT_DEBUG_DRAW
935 qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
936#endif
937
938 QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
939 if (!continueCall())
940 return;
941
942 Q_ASSERT(pointCount > 1);
943
944 QPainterPath path(points[0]);
945
946 for (int i=1; i<pointCount; ++i) {
947 path.lineTo(points[i]);
948 }
949
950 Q_D(QWin32PrintEngine);
951
952 bool has_brush = d->has_brush;
953
954 if (mode == PolylineMode)
955 d->has_brush = false; // No brush for polylines
956 else
957 path.closeSubpath(); // polygons are should always be closed.
958
959 drawPath(path);
960 d->has_brush = has_brush;
961}
962
963void QWin32PrintEnginePrivate::queryDefault()
964{
965 /* Read the default printer name, driver and port with the intuitive function
966 * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
967 */
968 QString noPrinters(QLatin1String("qt_no_printers"));
969 QString output;
970 QT_WA({
971 ushort buffer[256];
972 GetProfileStringW(L"windows", L"device",
973 reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
974 reinterpret_cast<wchar_t *>(buffer), 256);
975 output = QString::fromUtf16(buffer);
976 if (output.isEmpty() || output == noPrinters) // no printers
977 return;
978 }, {
979 char buffer[256];
980 GetProfileStringA("windows", "device", noPrinters.toLatin1(), buffer, 256);
981 output = QString::fromLocal8Bit(buffer);
982 if (output.isEmpty() || output == noPrinters) // no printers
983 return;
984 });
985 QStringList info = output.split(QLatin1Char(','));
986 if (info.size() > 0) {
987 if (name.isEmpty())
988 name = info.at(0);
989 if (program.isEmpty())
990 program = info.at(1);
991 if (port.isEmpty())
992 port = info.at(2);
993 }
994}
995
996QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
997{
998 if (hdc)
999 release();
1000}
1001
1002void QWin32PrintEnginePrivate::initialize()
1003{
1004 if (hdc)
1005 release();
1006 Q_ASSERT(!hPrinter);
1007 Q_ASSERT(!hdc);
1008 Q_ASSERT(!devMode);
1009 Q_ASSERT(!pInfo);
1010
1011 if (name.isEmpty())
1012 return;
1013
1014 txop = QTransform::TxNone;
1015
1016 bool ok;
1017 QT_WA( {
1018 ok = OpenPrinterW((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
1019 }, {
1020 ok = OpenPrinterA((LPSTR)name.toLatin1().data(), (LPHANDLE)&hPrinter, 0);
1021 } );
1022
1023 if (!ok) {
1024 qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
1025 return;
1026 }
1027
1028 // Fetch the PRINTER_INFO_2 with DEVMODE data containing the
1029 // printer settings.
1030 DWORD infoSize, numBytes;
1031 ok = true;
1032 QT_WA( {
1033 GetPrinterW(hPrinter, 2, NULL, 0, &infoSize);
1034 hMem = GlobalAlloc(GHND, infoSize);
1035 pInfo = GlobalLock(hMem);
1036 if (!GetPrinterW(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes)) {
1037 ok = false;
1038 }
1039 }, {
1040 GetPrinterA(hPrinter, 2, NULL, 0, &infoSize);
1041 hMem = GlobalAlloc(GHND, infoSize);
1042 pInfo = GlobalLock(hMem);
1043 if (!GetPrinterA(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes)) {
1044 ok = false;
1045 }
1046 });
1047
1048 if (!ok) {
1049 qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
1050 GlobalUnlock(pInfo);
1051 GlobalFree(hMem);
1052 ClosePrinter(hPrinter);
1053 pInfo = 0;
1054 hMem = 0;
1055 hPrinter = 0;
1056 return;
1057 }
1058
1059 QT_WA( {
1060 devMode = pInfoW()->pDevMode;
1061 }, {
1062 devMode = pInfoA()->pDevMode;
1063 } );
1064
1065 QT_WA( {
1066 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1067 reinterpret_cast<const wchar_t *>(name.utf16()), 0, devModeW());
1068 }, {
1069 hdc = CreateDCA(program.toLatin1(), name.toLatin1(), 0, devModeA());
1070 } );
1071
1072 Q_ASSERT(hPrinter);
1073 Q_ASSERT(pInfo);
1074
1075 if (devMode) {
1076 QT_WA( {
1077 num_copies = devModeW()->dmCopies;
1078 }, {
1079 num_copies = devModeA()->dmCopies;
1080 } );
1081 }
1082
1083 initHDC();
1084
1085#ifdef QT_DEBUG_DRAW
1086 qDebug() << "QWin32PrintEngine::initialize()" << endl
1087 << " - paperRect" << devPaperRect << endl
1088 << " - pageRect" << devPageRect << endl
1089 << " - stretch_x" << stretch_x << endl
1090 << " - stretch_y" << stretch_y << endl
1091 << " - origin_x" << origin_x << endl
1092 << " - origin_y" << origin_y << endl;
1093#endif
1094}
1095
1096void QWin32PrintEnginePrivate::initHDC()
1097{
1098 Q_ASSERT(hdc);
1099
1100 HDC display_dc = GetDC(0);
1101 dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1102 dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1103 dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
1104 ReleaseDC(0, display_dc);
1105 if (dpi_display == 0) {
1106 qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
1107 "might be a driver problem");
1108 dpi_display = 96; // Reasonable default
1109 }
1110
1111 switch(mode) {
1112 case QPrinter::ScreenResolution:
1113 resolution = dpi_display;
1114 stretch_x = dpi_x / double(dpi_display);
1115 stretch_y = dpi_y / double(dpi_display);
1116 break;
1117 case QPrinter::PrinterResolution:
1118 case QPrinter::HighResolution:
1119 resolution = dpi_y;
1120 stretch_x = 1;
1121 stretch_y = 1;
1122 break;
1123 default:
1124 break;
1125 }
1126
1127 initDevRects();
1128}
1129
1130void QWin32PrintEnginePrivate::initDevRects()
1131{
1132 devPaperRect = QRect(0, 0,
1133 GetDeviceCaps(hdc, PHYSICALWIDTH),
1134 GetDeviceCaps(hdc, PHYSICALHEIGHT));
1135 devPhysicalPageRect = QRect(GetDeviceCaps(hdc, PHYSICALOFFSETX),
1136 GetDeviceCaps(hdc, PHYSICALOFFSETY),
1137 GetDeviceCaps(hdc, HORZRES),
1138 GetDeviceCaps(hdc, VERTRES));
1139 if (!pageMarginsSet)
1140 devPageRect = devPhysicalPageRect;
1141 else
1142 devPageRect = devPaperRect.adjusted(qRound(mmToInches(previousDialogMargins.left() / 100.0) * dpi_x),
1143 qRound(mmToInches(previousDialogMargins.top() / 100.0) * dpi_y),
1144 -qRound(mmToInches(previousDialogMargins.width() / 100.0) * dpi_x),
1145 -qRound(mmToInches(previousDialogMargins.height() / 100.0) * dpi_y));
1146 updateOrigin();
1147}
1148
1149void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
1150{
1151 pageMarginsSet = true;
1152 previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
1153
1154 devPageRect = devPaperRect.adjusted(qRound(mmToInches(marginLeft / 100.0) * dpi_x),
1155 qRound(mmToInches(marginTop / 100.0) * dpi_y),
1156 - qRound(mmToInches(marginRight / 100.0) * dpi_x),
1157 - qRound(mmToInches(marginBottom / 100.0) * dpi_y));
1158 updateOrigin();
1159}
1160
1161QRect QWin32PrintEnginePrivate::getPageMargins() const
1162{
1163 if (pageMarginsSet)
1164 return previousDialogMargins;
1165 else
1166 return QRect(qRound(inchesToMM(devPhysicalPageRect.left()) * 100.0 / dpi_x),
1167 qRound(inchesToMM(devPhysicalPageRect.top()) * 100.0 / dpi_y),
1168 qRound(inchesToMM(devPaperRect.right() - devPhysicalPageRect.right()) * 100.0 / dpi_x),
1169 qRound(inchesToMM(devPaperRect.bottom() - devPhysicalPageRect.bottom()) * 100.0 / dpi_y));
1170}
1171
1172void QWin32PrintEnginePrivate::release()
1173{
1174 if (hdc == 0)
1175 return;
1176
1177 if (globalDevMode) { // Devmode comes from print dialog
1178 GlobalUnlock(globalDevMode);
1179 } else { // Devmode comes from initialize...
1180 // devMode is a part of the same memory block as pInfo so one free is enough...
1181 GlobalUnlock(hMem);
1182 GlobalFree(hMem);
1183 }
1184 if (hPrinter)
1185 ClosePrinter(hPrinter);
1186 DeleteDC(hdc);
1187
1188 hdc = 0;
1189 hPrinter = 0;
1190 pInfo = 0;
1191 hMem = 0;
1192 devMode = 0;
1193}
1194
1195QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
1196{
1197 // Read the supported resolutions of the printer.
1198 DWORD numRes;
1199 LONG *enumRes;
1200 DWORD errRes;
1201 QList<QVariant> list;
1202
1203 QT_WA({
1204 numRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1205 reinterpret_cast<const wchar_t *>(port.utf16()),
1206 DC_ENUMRESOLUTIONS, 0, 0);
1207 if (numRes == (DWORD)-1)
1208 return list;
1209 enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
1210 errRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
1211 reinterpret_cast<const wchar_t *>(port.utf16()),
1212 DC_ENUMRESOLUTIONS, (LPWSTR)enumRes, 0);
1213 }, {
1214 numRes = DeviceCapabilitiesA(name.toLocal8Bit(), port.toLocal8Bit(), DC_ENUMRESOLUTIONS, 0, 0);
1215 if (numRes == (DWORD)-1)
1216 return list;
1217 enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
1218 errRes = DeviceCapabilitiesA(name.toLocal8Bit(), port.toLocal8Bit(), DC_ENUMRESOLUTIONS, (LPSTR)enumRes, 0);
1219 });
1220
1221 if (errRes == (DWORD)-1) {
1222 qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
1223 return list;
1224 }
1225
1226 for (uint i=0; i<numRes; ++i)
1227 list.append(int(enumRes[i*2]));
1228 return list;
1229}
1230
1231void QWin32PrintEnginePrivate::doReinit()
1232{
1233 if (state == QPrinter::Active) {
1234 reinit = true;
1235 } else {
1236 resetDC();
1237 initDevRects();
1238 reinit = false;
1239 }
1240}
1241
1242void QWin32PrintEnginePrivate::updateOrigin()
1243{
1244 if (fullPage) {
1245 // subtract physical margins to make (0,0) absolute top corner of paper
1246 // then add user defined margins
1247 origin_x = -devPhysicalPageRect.x();
1248 origin_y = -devPhysicalPageRect.y();
1249 if (pageMarginsSet) {
1250 origin_x += devPageRect.left();
1251 origin_y += devPageRect.top();
1252 }
1253 } else {
1254 origin_x = 0;
1255 origin_y = 0;
1256 if (pageMarginsSet) {
1257 origin_x = devPageRect.left() - devPhysicalPageRect.x();
1258 origin_y = devPageRect.top() - devPhysicalPageRect.y();
1259 }
1260 }
1261}
1262
1263void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
1264{
1265 Q_D(QWin32PrintEngine);
1266 switch (key) {
1267 case PPK_CollateCopies:
1268 {
1269 if (!d->devMode)
1270 break;
1271 short collate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
1272 QT_WA( { d->devModeW()->dmCollate = collate; },
1273 { d->devModeA()->dmCollate = collate; } );
1274 d->doReinit();
1275 }
1276 break;
1277
1278 case PPK_ColorMode:
1279 {
1280 if (!d->devMode)
1281 break;
1282 int cm = value.toInt() == QPrinter::Color ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
1283 QT_WA( { d->devModeW()->dmColor = cm; }, { d->devModeA()->dmColor = cm; } );
1284 d->doReinit();
1285 }
1286 break;
1287
1288 case PPK_Creator:
1289
1290 break;
1291
1292 case PPK_DocumentName:
1293 if (isActive()) {
1294 qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
1295 return;
1296 }
1297 d->docName = value.toString();
1298 break;
1299
1300 case PPK_FullPage:
1301 d->fullPage = value.toBool();
1302 d->updateOrigin();
1303 break;
1304
1305 case PPK_NumberOfCopies:
1306 if (!d->devMode)
1307 break;
1308 d->num_copies = value.toInt();
1309 QT_WA( { d->devModeW()->dmCopies = d->num_copies; },
1310 { d->devModeA()->dmCopies = d->num_copies; });
1311 d->doReinit();
1312 break;
1313
1314 case PPK_Orientation:
1315 {
1316 if (!d->devMode)
1317 break;
1318 int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
1319 int old_orientation;
1320 QT_WA( {
1321 old_orientation = d->devModeW()->dmOrientation;
1322 d->devModeW()->dmOrientation = orientation;
1323 }, {
1324 old_orientation = d->devModeA()->dmOrientation;
1325 d->devModeA()->dmOrientation = orientation;
1326 } );
1327 if (d->has_custom_paper_size && old_orientation != orientation)
1328 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1329 d->doReinit();
1330 }
1331 break;
1332
1333 case PPK_OutputFileName:
1334 if (isActive()) {
1335 qWarning("QWin32PrintEngine: Cannot change filename while printing");
1336 } else {
1337 d->fileName = value.toString();
1338 d->printToFile = !value.toString().isEmpty();
1339 }
1340 break;
1341
1342 case PPK_PaperSize:
1343 if (!d->devMode)
1344 break;
1345 QT_WA( {
1346 d->devModeW()->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1347 }, {
1348 d->devModeA()->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
1349 } );
1350 d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
1351 d->doReinit();
1352 break;
1353
1354 case PPK_PaperSource:
1355 {
1356 if (!d->devMode)
1357 break;
1358 int dmMapped = DMBIN_AUTO;
1359
1360 QList<QVariant> v = property(PPK_PaperSources).toList();
1361 if (v.contains(value))
1362 dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
1363
1364 QT_WA( {
1365 d->devModeW()->dmDefaultSource = dmMapped;
1366 }, {
1367 d->devModeA()->dmDefaultSource = dmMapped;
1368 } );
1369 d->doReinit();
1370 }
1371 break;
1372
1373 case PPK_PrinterName:
1374 d->name = value.toString();
1375 if(d->name.isEmpty())
1376 d->queryDefault();
1377 d->initialize();
1378 break;
1379
1380 case PPK_Resolution:
1381 {
1382 d->resolution = value.toInt();
1383
1384 d->stretch_x = d->dpi_x / double(d->resolution);
1385 d->stretch_y = d->dpi_y / double(d->resolution);
1386 }
1387 break;
1388
1389 case PPK_SelectionOption:
1390
1391 break;
1392
1393 case PPK_SupportedResolutions:
1394
1395 break;
1396
1397
1398 case PPK_WindowsPageSize:
1399 if (!d->devMode)
1400 break;
1401 d->has_custom_paper_size = false;
1402 QT_WA( {
1403 d->devModeW()->dmPaperSize = value.toInt();
1404 }, {
1405 d->devModeA()->dmPaperSize = value.toInt();
1406 } );
1407 d->doReinit();
1408 break;
1409
1410 case PPK_CustomPaperSize:
1411 {
1412 d->has_custom_paper_size = true;
1413 d->paper_size = value.toSizeF();
1414 if (!d->devMode)
1415 break;
1416 int orientation;
1417 QT_WA( {
1418 orientation = d->devModeW()->dmOrientation;
1419 DWORD needed = 0;
1420 DWORD returned = 0;
1421 if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
1422 BYTE *forms = (BYTE *) malloc(needed);
1423 if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
1424 for (DWORD i=0; i< returned; ++i) {
1425 FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
1426 // the form sizes are specified in 1000th of a mm,
1427 // convert the size to Points
1428 QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
1429 (formArray[i].Size.cy * 72/25.4)/1000.0);
1430 if (qAbs(d->paper_size.width() - size.width()) <= 2
1431 && qAbs(d->paper_size.height() - size.height()) <= 2)
1432 {
1433 d->devModeW()->dmPaperSize = i+1;
1434 break;
1435 }
1436 }
1437 }
1438 free(forms);
1439 }
1440 }, {
1441 orientation = d->devModeA()->dmOrientation;
1442 } );
1443 if (orientation != DMORIENT_PORTRAIT)
1444 d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
1445 break;
1446 }
1447
1448 case PPK_PageMargins:
1449 {
1450 QList<QVariant> margins(value.toList());
1451 Q_ASSERT(margins.size() == 4);
1452 int left, top, right, bottom;
1453 // specified in 1/100 mm
1454 left = (margins.at(0).toDouble()*25.4/72.0) * 100;
1455 top = (margins.at(1).toDouble()*25.4/72.0) * 100;
1456 right = (margins.at(2).toDouble()*25.4/72.0) * 100;
1457 bottom = (margins.at(3).toDouble()*25.4/72.0) * 100;
1458 d->setPageMargins(left, top, right, bottom);
1459 break;
1460 }
1461 default:
1462 // Do nothing
1463 break;
1464 }
1465}
1466
1467QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
1468{
1469 Q_D(const QWin32PrintEngine);
1470 QVariant value;
1471 switch (key) {
1472
1473 case PPK_CollateCopies:
1474 value = false;
1475 break;
1476
1477 case PPK_ColorMode:
1478 {
1479 if (!d->devMode) {
1480 value = QPrinter::Color;
1481 } else {
1482 int mode;
1483 QT_WA( {
1484 mode = d->devModeW()->dmColor;
1485 }, {
1486 mode = d->devModeA()->dmColor;
1487 } );
1488 value = mode == DMCOLOR_COLOR ? QPrinter::Color : QPrinter::GrayScale;
1489 }
1490 }
1491 break;
1492
1493 case PPK_DocumentName:
1494 value = d->docName;
1495 break;
1496
1497 case PPK_FullPage:
1498 value = d->fullPage;
1499 break;
1500
1501 case PPK_NumberOfCopies:
1502 value = 1;
1503 break;
1504
1505 case PPK_Orientation:
1506 {
1507 if (!d->devMode) {
1508 value = QPrinter::Portrait;
1509 } else {
1510 int o;
1511 QT_WA( { o = d->devModeW()->dmOrientation; }, { o = d->devModeA()->dmOrientation; } );
1512 value = o == DMORIENT_LANDSCAPE ? QPrinter::Landscape : QPrinter::Portrait;
1513 }
1514 }
1515 break;
1516
1517 case PPK_OutputFileName:
1518 value = d->fileName;
1519 break;
1520
1521 case PPK_PageRect:
1522 if (d->has_custom_paper_size) {
1523 QRect rect(0, 0,
1524 qRound(d->paper_size.width() * d->resolution / 72.0),
1525 qRound(d->paper_size.height() * d->resolution / 72.0));
1526 if (d->pageMarginsSet) {
1527 rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
1528 qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
1529 -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
1530 -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
1531 }
1532 value = rect;
1533 } else {
1534 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
1535 .mapRect(d->fullPage ? d->devPaperRect : d->devPageRect);
1536 }
1537 break;
1538
1539 case PPK_PaperSize:
1540 if (d->has_custom_paper_size) {
1541 value = QPrinter::Custom;
1542 } else {
1543 if (!d->devMode) {
1544 value = QPrinter::A4;
1545 } else {
1546 QT_WA( {
1547 value = mapDevmodePaperSize(d->devModeW()->dmPaperSize);
1548 }, {
1549 value = mapDevmodePaperSize(d->devModeA()->dmPaperSize);
1550 } );
1551 }
1552 }
1553 break;
1554
1555 case PPK_PaperRect:
1556 if (d->has_custom_paper_size) {
1557 value = QRect(0, 0,
1558 qRound(d->paper_size.width() * d->resolution / 72.0),
1559 qRound(d->paper_size.height() * d->resolution / 72.0));
1560 } else {
1561 value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
1562 }
1563 break;
1564
1565 case PPK_PaperSource:
1566 if (!d->devMode) {
1567 value = QPrinter::Auto;
1568 } else {
1569 QT_WA( {
1570 value = mapDevmodePaperSource(d->devModeW()->dmDefaultSource);
1571 }, {
1572 value = mapDevmodePaperSource(d->devModeA()->dmDefaultSource);
1573 } );
1574 }
1575 break;
1576
1577 case PPK_PrinterName:
1578 value = d->name;
1579 break;
1580
1581 case PPK_Resolution:
1582 if (d->resolution || !d->name.isEmpty())
1583 value = d->resolution;
1584 break;
1585
1586 case PPK_SupportedResolutions:
1587 value = d->queryResolutions();
1588 break;
1589
1590 case PPK_WindowsPageSize:
1591 if (!d->devMode) {
1592 value = -1;
1593 } else {
1594 QT_WA( {
1595 value = d->devModeW()->dmPaperSize;
1596 }, {
1597 value = d->devModeA()->dmPaperSize;
1598 } );
1599 }
1600 break;
1601
1602 case PPK_PaperSources:
1603 {
1604 int available, count;
1605 WORD *data;
1606
1607 QT_WA({
1608 available = DeviceCapabilitiesW((const WCHAR *)d->name.utf16(), (const WCHAR *)d->port.utf16(), DC_BINS, 0,
1609 d->devModeW());
1610 }, {
1611 available = DeviceCapabilitiesA(d->name.toLatin1(), d->port.toLatin1(), DC_BINS, 0,
1612 d->devModeA());
1613 });
1614
1615 if (available <= 0)
1616 break;
1617 data = (WORD *) malloc(available * sizeof(WORD));
1618
1619 QT_WA({
1620 count = DeviceCapabilitiesW((const WCHAR *)d->name.utf16(), (const WCHAR *)d->port.utf16(), DC_BINS, (WCHAR *)data,
1621 d->devModeW());
1622 }, {
1623 count = DeviceCapabilitiesA(d->name.toLatin1(), d->port.toLatin1(), DC_BINS,
1624 (char *) data, d->devModeA());
1625 });
1626
1627 QList<QVariant> out;
1628 for (int i=0; i<count; ++i) {
1629 QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
1630 if (src != -1)
1631 out << (int) src;
1632 }
1633 value = out;
1634 free(data);
1635 }
1636 break;
1637
1638 case PPK_CustomPaperSize:
1639 value = d->paper_size;
1640 break;
1641
1642 case PPK_PageMargins:
1643 {
1644 QList<QVariant> margins;
1645 QRect pageMargins(d->getPageMargins());
1646
1647 // specified in 1/100 mm
1648 margins << (mmToInches(pageMargins.left()/100.0) * 72)
1649 << (mmToInches(pageMargins.top()/100.0) * 72)
1650 << (mmToInches(pageMargins.width()/100.0) * 72)
1651 << (mmToInches(pageMargins.height()/100.0) * 72);
1652 value = margins;
1653 break;
1654 }
1655 default:
1656 // Do nothing
1657 break;
1658 }
1659 return value;
1660}
1661
1662QPrinter::PrinterState QWin32PrintEngine::printerState() const
1663{
1664 return d_func()->state;
1665}
1666
1667HDC QWin32PrintEngine::getDC() const
1668{
1669 return d_func()->hdc;
1670}
1671
1672void QWin32PrintEngine::releaseDC(HDC) const
1673{
1674
1675}
1676
1677HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
1678{
1679 QT_WA( {
1680 int size = sizeof(DEVNAMES)
1681 + program.length() * 2 + 2
1682 + name.length() * 2 + 2
1683 + port.length() * 2 + 2;
1684 HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
1685 DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
1686
1687 dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
1688 dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1689 dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1690
1691 memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
1692 memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
1693 memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
1694 dn->wDefault = 0;
1695
1696 GlobalUnlock(hGlobal);
1697
1698// printf("QPrintDialogWinPrivate::createDevNames()\n"
1699// " -> wDriverOffset: %d\n"
1700// " -> wDeviceOffset: %d\n"
1701// " -> wOutputOffset: %d\n",
1702// dn->wDriverOffset,
1703// dn->wDeviceOffset,
1704// dn->wOutputOffset);
1705
1706// printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
1707// QString::fromUtf16((ushort*)(dn) + dn->wDriverOffset).latin1(),
1708// QString::fromUtf16((ushort*)(dn) + dn->wDeviceOffset).latin1(),
1709// QString::fromUtf16((ushort*)(dn) + dn->wOutputOffset).latin1());
1710
1711 return hGlobal;
1712 }, {
1713 int size = sizeof(DEVNAMES)
1714 + program.length() + 2
1715 + name.length() + 2
1716 + port.length() + 2;
1717 HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
1718 DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
1719
1720 dn->wDriverOffset = sizeof(DEVNAMES);
1721 dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
1722 dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
1723
1724 memcpy((char*)dn + dn->wDriverOffset, program.toLatin1(), program.length() + 2);
1725 memcpy((char*)dn + dn->wDeviceOffset, name.toLatin1(), name.length() + 2);
1726 memcpy((char*)dn + dn->wOutputOffset, port.toLatin1(), port.length() + 2);
1727 dn->wDefault = 0;
1728
1729 GlobalUnlock(hGlobal);
1730 return hGlobal;
1731 } );
1732}
1733
1734void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
1735{
1736 if (globalDevnames) {
1737 QT_WA( {
1738 DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
1739 name = QString::fromUtf16((ushort*)(dn) + dn->wDeviceOffset);
1740 port = QString::fromUtf16((ushort*)(dn) + dn->wOutputOffset);
1741 program = QString::fromUtf16((ushort*)(dn) + dn->wDriverOffset);
1742 GlobalUnlock(globalDevnames);
1743 }, {
1744 DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
1745 name = QString::fromLatin1((char*)(dn) + dn->wDeviceOffset);
1746 port = QString::fromLatin1((char*)(dn) + dn->wOutputOffset);
1747 program = QString::fromLatin1((char*)(dn) + dn->wDriverOffset);
1748 GlobalUnlock(globalDevnames);
1749 } );
1750 }
1751}
1752
1753void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
1754{
1755 if (globalDevmode) {
1756 QT_WA( {
1757 DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
1758 release();
1759 globalDevMode = globalDevmode;
1760 devMode = dm;
1761 hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
1762 reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
1763
1764 num_copies = devModeW()->dmCopies;
1765 if (!OpenPrinterW((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0))
1766 qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1767 }, {
1768 DEVMODEA *dm = (DEVMODEA*) GlobalLock(globalDevmode);
1769 release();
1770 globalDevMode = globalDevmode;
1771 devMode = dm;
1772 hdc = CreateDCA(program.toLatin1(), name.toLatin1(), 0, dm);
1773
1774 num_copies = devModeA()->dmCopies;
1775 if (!OpenPrinterA((LPSTR)name.toLatin1().data(), (LPHANDLE)&hPrinter, 0))
1776 qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
1777 } );
1778 }
1779
1780 if (hdc)
1781 initHDC();
1782}
1783
1784static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
1785 bool convertToText, const QTransform &xform, const QPointF &topLeft)
1786{
1787
1788 // Make sure we translate for systems that can't handle world transforms
1789 QPointF pos(QT_WA_INLINE(_pos, _pos + QPointF(xform.dx(), xform.dy())));
1790 QFontEngine *fe = ti.fontEngine;
1791 QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
1792
1793 SetTextAlign(hdc, TA_BASELINE);
1794 SetBkMode(hdc, TRANSPARENT);
1795
1796 bool has_kerning = ti.f && ti.f->kerning();
1797 QFontEngineWin *winfe = (fe->type() == QFontEngine::Win) ? static_cast<QFontEngineWin *>(fe) : 0;
1798
1799 HFONT hfont;
1800 bool ttf = false;
1801 bool useTextOutA = false;
1802
1803 if (winfe) {
1804 hfont = winfe->hfont;
1805 ttf = winfe->ttf;
1806 useTextOutA = winfe->useTextOutA;
1807 } else {
1808 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1809 }
1810
1811 HGDIOBJ old_font = SelectObject(hdc, hfont);
1812 unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
1813 wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
1814 QGlyphLayout glyphs = ti.glyphs;
1815
1816 if (!(ti.flags & QTextItem::RightToLeft) && useTextOutA) {
1817 qreal x = pos.x();
1818 qreal y = pos.y();
1819
1820 // hack to get symbol fonts working on Win95. See also QFontEngine constructor
1821 // can only happen if !ttf
1822 for(int i = 0; i < glyphs.numGlyphs; i++) {
1823 QString str(QChar(glyphs.glyphs[i]));
1824 QT_WA({
1825 TextOutW(hdc, qRound(x + glyphs.offsets[i].x.toReal()),
1826 qRound(y + glyphs.offsets[i].y.toReal()),
1827 (LPWSTR)str.utf16(), str.length());
1828 } , {
1829 QByteArray cstr = str.toLocal8Bit();
1830 TextOutA(hdc, qRound(x + glyphs.offsets[i].x.toReal()),
1831 qRound(y + glyphs.offsets[i].y.toReal()),
1832 cstr.data(), cstr.length());
1833 });
1834 x += glyphs.effectiveAdvance(i).toReal();
1835 }
1836 } else {
1837 bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
1838 for(int i = 0; fast && i < glyphs.numGlyphs; i++) {
1839 if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
1840 || glyphs.attributes[i].dontPrint) {
1841 fast = false;
1842 break;
1843 }
1844 }
1845
1846#if !defined(Q_OS_WINCE)
1847 // Scale, rotate and translate here. This is only valid for systems > Windows Me.
1848 // We should never get here on Windows Me or lower if the transformation specifies
1849 // scaling or rotation.
1850 QT_WA({
1851 XFORM win_xform;
1852 win_xform.eM11 = xform.m11();
1853 win_xform.eM12 = xform.m12();
1854 win_xform.eM21 = xform.m21();
1855 win_xform.eM22 = xform.m22();
1856 win_xform.eDx = xform.dx();
1857 win_xform.eDy = xform.dy();
1858 SetGraphicsMode(hdc, GM_ADVANCED);
1859 SetWorldTransform(hdc, &win_xform);
1860 }, {
1861 // nothing
1862 });
1863#endif
1864
1865 if (fast) {
1866 // fast path
1867 QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
1868 for (int i = 0; i < glyphs.numGlyphs; ++i)
1869 g[i] = glyphs.glyphs[i];
1870 ExtTextOutW(hdc,
1871 qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
1872 qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
1873 options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
1874 } else {
1875 QVarLengthArray<QFixedPoint> positions;
1876 QVarLengthArray<glyph_t> _glyphs;
1877
1878 QTransform matrix;
1879 matrix.translate(baseline_pos.x(), baseline_pos.y());
1880 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
1881 _glyphs, positions);
1882 if (_glyphs.size() == 0) {
1883 SelectObject(hdc, old_font);
1884 return;
1885 }
1886
1887 convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
1888
1889 bool outputEntireItem = (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
1890 && QSysInfo::WindowsVersion != QSysInfo::WV_NT
1891 && _glyphs.size() > 0;
1892
1893 if (outputEntireItem) {
1894 options |= ETO_PDY;
1895 QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
1896 QVarLengthArray<wchar_t> g(_glyphs.size());
1897 for (int i=0; i<_glyphs.size() - 1; ++i) {
1898 glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
1899 glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
1900 g[i] = _glyphs[i];
1901 }
1902 glyphDistances[(_glyphs.size() - 1) * 2] = 0;
1903 glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
1904 g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
1905 ExtTextOutW(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
1906 convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
1907 glyphDistances.data());
1908 } else {
1909 int i = 0;
1910 while(i < _glyphs.size()) {
1911 wchar_t g = _glyphs[i];
1912
1913 ExtTextOutW(hdc, qRound(positions[i].x),
1914 qRound(positions[i].y), options, 0,
1915 convertToText ? convertedGlyphs + i : &g, 1, 0);
1916 ++i;
1917 }
1918 }
1919 }
1920
1921#if !defined(Q_OS_WINCE)
1922 QT_WA({
1923 XFORM win_xform;
1924 win_xform.eM11 = win_xform.eM22 = 1.0;
1925 win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
1926 SetWorldTransform(hdc, &win_xform);
1927 }, {
1928 // nothing
1929 });
1930#endif
1931 }
1932 SelectObject(hdc, old_font);
1933}
1934
1935
1936void QWin32PrintEnginePrivate::updateCustomPaperSize()
1937{
1938 QT_WA( {
1939 uint paperSize = devModeW()->dmPaperSize;
1940 if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
1941 has_custom_paper_size = true;
1942 DWORD needed = 0;
1943 DWORD returned = 0;
1944 if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
1945 BYTE *forms = (BYTE *) malloc(needed);
1946 if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
1947 if (paperSize <= returned) {
1948 FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
1949 int width = formArray[paperSize-1].Size.cx; // 1/1000 of a mm
1950 int height = formArray[paperSize-1].Size.cy; // 1/1000 of a mm
1951 paper_size = QSizeF((width*72/25.4)/1000.0, (height*72/25.4)/1000.0);
1952 } else {
1953 has_custom_paper_size = false;
1954 }
1955 }
1956 free(forms);
1957 }
1958 } else {
1959 has_custom_paper_size = false;
1960 }
1961 }, {
1962 // Not supported under Win98
1963 } );
1964}
1965
1966QT_END_NAMESPACE
1967
1968#endif // QT_NO_PRINTER
Note: See TracBrowser for help on using the repository browser.